xref: /freebsd/sys/netinet/libalias/alias_util.c (revision fe267a559009cbf34f9341666fe4d88a92c02d5e)
1f987e1bdSBrian Somers /*-
2*fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*fe267a55SPedro F. Giffuni  *
4e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5f987e1bdSBrian Somers  * All rights reserved.
6f987e1bdSBrian Somers  *
7f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
8f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
9f987e1bdSBrian Somers  * are met:
10f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
12f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
13f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
14f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
15f987e1bdSBrian Somers  *
16f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f987e1bdSBrian Somers  * SUCH DAMAGE.
27f987e1bdSBrian Somers  */
28f987e1bdSBrian Somers 
29e2505aa6SMatthew Dillon #include <sys/cdefs.h>
30e2505aa6SMatthew Dillon __FBSDID("$FreeBSD$");
31e2505aa6SMatthew Dillon 
32e2505aa6SMatthew Dillon 
333b160b8bSBrian Somers /*
3491cc2995SRuslan Ermilov     Alias_util.c contains general utilities used by other functions
353b160b8bSBrian Somers     in the packet aliasing module.  At the moment, there are functions
363b160b8bSBrian Somers     for computing IP header and TCP packet checksums.
373b160b8bSBrian Somers 
383b160b8bSBrian Somers     The checksum routines are based upon example code in a Unix networking
393b160b8bSBrian Somers     text written by Stevens (sorry, I can't remember the title -- but
403b160b8bSBrian Somers     at least this is a good author).
413b160b8bSBrian Somers 
423b160b8bSBrian Somers     Initial Version:  August, 1996  (cjm)
433b160b8bSBrian Somers 
443b160b8bSBrian Somers     Version 1.7:  January 9, 1997
453b160b8bSBrian Somers 	 Added differential checksum update function.
463b160b8bSBrian Somers */
473b160b8bSBrian Somers 
48c649a2e0SGleb Smirnoff #ifdef _KERNEL
49c649a2e0SGleb Smirnoff #include <sys/param.h>
50be4f3cd0SPaolo Pisati #include <sys/proc.h>
51c649a2e0SGleb Smirnoff #else
523b160b8bSBrian Somers #include <sys/types.h>
53c649a2e0SGleb Smirnoff #include <stdio.h>
54c649a2e0SGleb Smirnoff #endif
55c649a2e0SGleb Smirnoff 
563b160b8bSBrian Somers #include <netinet/in_systm.h>
573b160b8bSBrian Somers #include <netinet/in.h>
583b160b8bSBrian Somers #include <netinet/ip.h>
593b160b8bSBrian Somers #include <netinet/tcp.h>
603b160b8bSBrian Somers 
61c649a2e0SGleb Smirnoff #ifdef _KERNEL
62c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
63c649a2e0SGleb Smirnoff #include <netinet/libalias/alias_local.h>
64c649a2e0SGleb Smirnoff #else
653efa11bbSBrian Somers #include "alias.h"
663b160b8bSBrian Somers #include "alias_local.h"
67c649a2e0SGleb Smirnoff #endif
683b160b8bSBrian Somers 
6959dde15eSGleb Smirnoff /*
7059dde15eSGleb Smirnoff  * Note: the checksum routines assume that the actual checksum word has
7159dde15eSGleb Smirnoff  * been zeroed out.  If the checksum word is filled with the proper value,
7259dde15eSGleb Smirnoff  * then these routines will give a result of zero (useful for testing
7359dde15eSGleb Smirnoff  * purposes);
7459dde15eSGleb Smirnoff  */
753b160b8bSBrian Somers u_short
7672f2d657SGleb Smirnoff LibAliasInternetChecksum(struct libalias *la __unused, u_short * ptr,
7772f2d657SGleb Smirnoff 	int nbytes)
783b160b8bSBrian Somers {
793b160b8bSBrian Somers 	int sum, oddbyte;
803b160b8bSBrian Somers 
81ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
823b160b8bSBrian Somers 	sum = 0;
83f0f93429SDag-Erling Smørgrav 	while (nbytes > 1) {
843b160b8bSBrian Somers 		sum += *ptr++;
853b160b8bSBrian Somers 		nbytes -= 2;
863b160b8bSBrian Somers 	}
87f0f93429SDag-Erling Smørgrav 	if (nbytes == 1) {
883b160b8bSBrian Somers 		oddbyte = 0;
8946d28b44SLuoqi Chen 		((u_char *) & oddbyte)[0] = *(u_char *) ptr;
9046d28b44SLuoqi Chen 		((u_char *) & oddbyte)[1] = 0;
913b160b8bSBrian Somers 		sum += oddbyte;
923b160b8bSBrian Somers 	}
933b160b8bSBrian Somers 	sum = (sum >> 16) + (sum & 0xffff);
943b160b8bSBrian Somers 	sum += (sum >> 16);
95ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
963b160b8bSBrian Somers 	return (~sum);
973b160b8bSBrian Somers }
983b160b8bSBrian Somers 
9959dde15eSGleb Smirnoff #ifndef	_KERNEL
1003b160b8bSBrian Somers u_short
1013b160b8bSBrian Somers IpChecksum(struct ip *pip)
1023b160b8bSBrian Somers {
10372f2d657SGleb Smirnoff 	return (LibAliasInternetChecksum(NULL, (u_short *) pip,
1043efa11bbSBrian Somers 	    (pip->ip_hl << 2)));
1053b160b8bSBrian Somers 
1063b160b8bSBrian Somers }
1073b160b8bSBrian Somers 
1083b160b8bSBrian Somers u_short
1093b160b8bSBrian Somers TcpChecksum(struct ip *pip)
1103b160b8bSBrian Somers {
1113b160b8bSBrian Somers 	u_short *ptr;
1123b160b8bSBrian Somers 	struct tcphdr *tc;
1133b160b8bSBrian Somers 	int nhdr, ntcp, nbytes;
1143b160b8bSBrian Somers 	int sum, oddbyte;
1153b160b8bSBrian Somers 
1163b160b8bSBrian Somers 	nhdr = pip->ip_hl << 2;
1173b160b8bSBrian Somers 	ntcp = ntohs(pip->ip_len) - nhdr;
1183b160b8bSBrian Somers 
1199fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
1203b160b8bSBrian Somers 	ptr = (u_short *) tc;
1213b160b8bSBrian Somers 
1223b160b8bSBrian Somers /* Add up TCP header and data */
1233b160b8bSBrian Somers 	nbytes = ntcp;
1243b160b8bSBrian Somers 	sum = 0;
125f0f93429SDag-Erling Smørgrav 	while (nbytes > 1) {
1263b160b8bSBrian Somers 		sum += *ptr++;
1273b160b8bSBrian Somers 		nbytes -= 2;
1283b160b8bSBrian Somers 	}
129f0f93429SDag-Erling Smørgrav 	if (nbytes == 1) {
1303b160b8bSBrian Somers 		oddbyte = 0;
13146d28b44SLuoqi Chen 		((u_char *) & oddbyte)[0] = *(u_char *) ptr;
13246d28b44SLuoqi Chen 		((u_char *) & oddbyte)[1] = 0;
1333b160b8bSBrian Somers 		sum += oddbyte;
1343b160b8bSBrian Somers 	}
1353b160b8bSBrian Somers /* "Pseudo-header" data */
1366c7faee2SDag-Erling Smørgrav 	ptr = (void *)&pip->ip_dst;
1373b160b8bSBrian Somers 	sum += *ptr++;
1383b160b8bSBrian Somers 	sum += *ptr;
1396c7faee2SDag-Erling Smørgrav 	ptr = (void *)&pip->ip_src;
1403b160b8bSBrian Somers 	sum += *ptr++;
1413b160b8bSBrian Somers 	sum += *ptr;
1423b160b8bSBrian Somers 	sum += htons((u_short) ntcp);
1433b160b8bSBrian Somers 	sum += htons((u_short) pip->ip_p);
1443b160b8bSBrian Somers 
1453b160b8bSBrian Somers /* Roll over carry bits */
1463b160b8bSBrian Somers 	sum = (sum >> 16) + (sum & 0xffff);
1473b160b8bSBrian Somers 	sum += (sum >> 16);
1483b160b8bSBrian Somers 
1493b160b8bSBrian Somers /* Return checksum */
1503b160b8bSBrian Somers 	return ((u_short) ~ sum);
1513b160b8bSBrian Somers }
15259dde15eSGleb Smirnoff #endif	/* not _KERNEL */
1533b160b8bSBrian Somers 
1543b160b8bSBrian Somers void
1552871c501SDag-Erling Smørgrav DifferentialChecksum(u_short * cksum, void *newp, void *oldp, int n)
1563b160b8bSBrian Somers {
1573b160b8bSBrian Somers 	int i;
1583b160b8bSBrian Somers 	int accumulate;
1592871c501SDag-Erling Smørgrav 	u_short *new = newp;
1602871c501SDag-Erling Smørgrav 	u_short *old = oldp;
1613b160b8bSBrian Somers 
1623b160b8bSBrian Somers 	accumulate = *cksum;
163f0f93429SDag-Erling Smørgrav 	for (i = 0; i < n; i++) {
1643b160b8bSBrian Somers 		accumulate -= *new++;
1653b160b8bSBrian Somers 		accumulate += *old++;
1663b160b8bSBrian Somers 	}
1673b160b8bSBrian Somers 
168f0f93429SDag-Erling Smørgrav 	if (accumulate < 0) {
1693b160b8bSBrian Somers 		accumulate = -accumulate;
1703b160b8bSBrian Somers 		accumulate = (accumulate >> 16) + (accumulate & 0xffff);
1713b160b8bSBrian Somers 		accumulate += accumulate >> 16;
1723b160b8bSBrian Somers 		*cksum = (u_short) ~ accumulate;
173f0f93429SDag-Erling Smørgrav 	} else {
1743b160b8bSBrian Somers 		accumulate = (accumulate >> 16) + (accumulate & 0xffff);
1753b160b8bSBrian Somers 		accumulate += accumulate >> 16;
1763b160b8bSBrian Somers 		*cksum = (u_short) accumulate;
1773b160b8bSBrian Somers 	}
1783b160b8bSBrian Somers }
179