diff options
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/libalias/HISTORY | 129 | ||||
-rw-r--r-- | sys/netinet/libalias/Makefile | 15 | ||||
-rw-r--r-- | sys/netinet/libalias/alias.c | 1165 | ||||
-rw-r--r-- | sys/netinet/libalias/alias.h | 173 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_cuseeme.c | 120 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_db.c | 2241 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_ftp.c | 227 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_irc.c | 316 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_local.h | 107 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_nbt.c | 713 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_old.c | 77 | ||||
-rw-r--r-- | sys/netinet/libalias/alias_util.c | 137 | ||||
-rw-r--r-- | sys/netinet/libalias/libalias.3 | 768 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 2231 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 751 |
15 files changed, 0 insertions, 9170 deletions
diff --git a/sys/netinet/libalias/HISTORY b/sys/netinet/libalias/HISTORY deleted file mode 100644 index 3d97fd0803b1..000000000000 --- a/sys/netinet/libalias/HISTORY +++ /dev/null @@ -1,129 +0,0 @@ -Version 1.0: August 11, 1996 (cjm) - -Version 1.1: August 20, 1996 (cjm) - - Host accepts incoming connections for ports 0 to 1023. - -Version 1.2: September 7, 1996 (cjm) - - Fragment handling error in alias_db.c corrected. - -Version 1.3: September 15, 1996 (cjm) - - Generalized mechanism for handling incoming - connections (no more 0 to 1023 restriction). - - - Increased ICMP support (will handle traceroute now). - - - Improved TCP close connection logic. - -Version 1.4: September 16, 1996 (cjm) - -Version 1.5: September 17, 1996 (cjm) - - Corrected error in handling incoming UDP packets - with zero checksum. - -Version 1.6: September 18, 1996 - - Simplified ICMP data storage. Will now handle - tracert from Win95 and NT as well as FreeBSD - traceroute, which uses UDP packets to non-existent - ports. - -Verstion 1.7: January 9, 1997 (cjm) - - Reduced malloc() activity for ICMP echo and - timestamp requests. - - - Added handling for out-of-order IP fragments. - - - Switched to differential checksum computation - for IP headers (TCP, UDP and ICMP checksums - were already differential). - - - Accepts FTP data connections from other than - port 20. This allows one ftp connections - from two hosts which are both running packet - aliasing. - - - Checksum error on FTP transfers. Problem - in code located by Martin Renters and - Brian Somers. - -Version 1.8: January 14, 1997 (cjm) - - Fixed data type error in function StartPoint() - in alias_db.c (this bug did not exist before v1.7) - Problem in code located by Ari Suutari. - -Version 1.9: February 1, 1997 (Eivind Eklund <perhaps@yes.no>) - - Added support for IRC DCC (ee) - - - Changed the aliasing routines to use ANSI style - throughout (ee) - - - Minor API changes for integration with other - programs than PPP (ee) - - - Fixed minor security hole in alias_ftp.c for - other applications of the aliasing software. - Hole could _not_ manifest in ppp+pktAlias, but - could potentially manifest in other applications - of the aliasing. (ee) - - - Connections initiated from packet aliasing - host machine will not have their port number - aliased unless it conflicts with an aliasing - port already being used. (There is an option - to disable this for debugging) (cjm) - - - Sockets will be allocated in cases where - there might be port interference with the - host machine. This can be disabled in cases - where the ppp host will be acting purely as a - masquerading router and not generate any - traffic of its own. - (cjm) - -Version 2.0: March, 1997 (cjm) - - Aliasing links are cleared only when a host interface address - changes. - - - PacketAliasPermanentLink() API added. - - - Option for only aliasing private, unregistered - IP addresses added. - - - Substantial rework to the aliasing lookup engine. - -Version 2.1: May, 1997 (cjm) - - Continuing rework to the aliasing lookup engine - to support multiple incoming addresses and static - NAT. PacketAliasRedirectPort() and - PacketAliasRedirectAddr() added to API. - - - Now supports outgoing as well as incoming ICMP - error messges. - -Version 2.2: July, 1997 (cjm) - - Rationalized API function names to all begin with - "PacketAlias..." Old function names are retained - for backwards compatitibility. - - - Packet aliasing engine will now free memory of - fragments which are never resolved after a timeout - period. Once a fragment is resolved, it becomes - the users responsibility to free the memory. - -Version 2.3: August 11, 1997 (cjm) - - Problem associated with socket file descriptor - accumulation in alias_db.c corrected. The sockets - had to be closed when a binding failed. Problem - in code located by Gordon Burditt. - -Version 2.4: September 1, 1997 (cjm) - - PKT_ALIAS_UNREGISTERED_ONLY option repaired. - This part of the code was incorrectly re-implemented - in version 2.1. - -Version 2.5: December, 1997 (ee) - - Added PKT_ALIAS_PUNCH_FW mode for firewall - bypass of FTP/IRC DCC data connections. Also added - improved TCP connection monitoring. - -Version 2.6: May, 1998 (amurai) - - Added supporting routine for NetBios over TCP/IP. diff --git a/sys/netinet/libalias/Makefile b/sys/netinet/libalias/Makefile deleted file mode 100644 index 665d14e10b3d..000000000000 --- a/sys/netinet/libalias/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# $Id$ - -LIB= alias -SHLIB_MAJOR= 2 -SHLIB_MINOR= 5 -CFLAGS+= -Wall -I${.CURDIR} -SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \ - alias_nbt.c alias_old.c alias_util.c -MAN3= libalias.3 - -beforeinstall: - ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/alias.h \ - ${DESTDIR}/usr/include - -.include <bsd.lib.mk> diff --git a/sys/netinet/libalias/alias.c b/sys/netinet/libalias/alias.c deleted file mode 100644 index 50e597f4364a..000000000000 --- a/sys/netinet/libalias/alias.c +++ /dev/null @@ -1,1165 +0,0 @@ -/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */ -/* - Alias.c provides supervisory control for the functions of the - packet aliasing software. It consists of routines to monitor - TCP connection state, protocol-specific aliasing routines, - fragment handling and the following outside world functional - interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn, - PacketAliasIn and PacketAliasOut. - - The other C program files are briefly described. The data - structure framework which holds information needed to translate - packets is encapsulated in alias_db.c. Data is accessed by - function calls, so other segments of the program need not know - about the underlying data structures. Alias_ftp.c contains - special code for modifying the ftp PORT command used to establish - data connections, while alias_irc.c do the same for IRC - DCC. Alias_util.c contains a few utility routines. - - This software is placed into the public domain with no restrictions - on its distribution. - - Version 1.0 August, 1996 (cjm) - - Version 1.1 August 20, 1996 (cjm) - PPP host accepts incoming connections for ports 0 to 1023. - (Gary Roberts pointed out the need to handle incoming - connections.) - - Version 1.2 September 7, 1996 (cjm) - Fragment handling error in alias_db.c corrected. - (Tom Torrance helped fix this problem.) - - Version 1.4 September 16, 1996 (cjm) - - A more generalized method for handling incoming - connections, without the 0-1023 restriction, is - implemented in alias_db.c - - Improved ICMP support in alias.c. Traceroute - packet streams can now be correctly aliased. - - TCP connection closing logic simplified in - alias.c and now allows for additional 1 minute - "grace period" after FIN or RST is observed. - - Version 1.5 September 17, 1996 (cjm) - Corrected error in handling incoming UDP packets with 0 checksum. - (Tom Torrance helped fix this problem.) - - Version 1.6 September 18, 1996 (cjm) - Simplified ICMP aliasing scheme. Should now support - traceroute from Win95 as well as FreeBSD. - - Version 1.7 January 9, 1997 (cjm) - - Out-of-order fragment handling. - - IP checksum error fixed for ftp transfers - from aliasing host. - - Integer return codes added to all - aliasing/de-aliasing functions. - - Some obsolete comments cleaned up. - - Differential checksum computations for - IP header (TCP, UDP and ICMP were already - differential). - - Version 2.1 May 1997 (cjm) - - Added support for outgoing ICMP error - messages. - - Added two functions PacketAliasIn2() - and PacketAliasOut2() for dynamic address - control (e.g. round-robin allocation of - incoming packets). - - Version 2.2 July 1997 (cjm) - - Rationalized API function names to begin - with "PacketAlias..." - - Eliminated PacketAliasIn2() and - PacketAliasOut2() as poorly conceived. - - Version 2.3 Dec 1998 (dillon) - - Major bounds checking additions, see FreeBSD/CVS - - See HISTORY file for additional revisions. - -*/ - -#include <stdio.h> -#include <unistd.h> - -#include <sys/param.h> -#include <sys/types.h> - -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> - -#include "alias_local.h" -#include "alias.h" - -#define NETBIOS_NS_PORT_NUMBER 137 -#define NETBIOS_DGM_PORT_NUMBER 138 -#define FTP_CONTROL_PORT_NUMBER 21 -#define FTP_CONTROL_PORT_NUMBER 21 -#define IRC_CONTROL_PORT_NUMBER_1 6667 -#define IRC_CONTROL_PORT_NUMBER_2 6668 -#define CUSEEME_PORT_NUMBER 7648 - -/* - The following macro is used to update an - internet checksum. "delta" is a 32-bit - accumulation of all the changes to the - checksum (adding in new 16-bit words and - subtracting out old words), and "cksum" - is the checksum value to be updated. -*/ -#define ADJUST_CHECKSUM(acc, cksum) { \ - acc += cksum; \ - if (acc < 0) \ - { \ - acc = -acc; \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) ~acc; \ - } \ - else \ - { \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) acc; \ - } \ -} - - - - -/* TCP Handling Routines - - TcpMonitorIn() -- These routines monitor TCP connections, and - TcpMonitorOut() -- delete a link node when a connection is closed. - -These routines look for SYN, ACK and RST flags to determine when TCP -connections open and close. When a TCP connection closes, the data -structure containing packet aliasing information is deleted after -a timeout period. -*/ - -/* Local prototypes */ -static void TcpMonitorIn(struct ip *, struct alias_link *); - -static void TcpMonitorOut(struct ip *, struct alias_link *); - - -static void -TcpMonitorIn(struct ip *pip, struct alias_link *link) -{ - struct tcphdr *tc; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - - switch (GetStateIn(link)) - { - case ALIAS_TCP_STATE_NOT_CONNECTED: - if (tc->th_flags & TH_SYN) - SetStateIn(link, ALIAS_TCP_STATE_CONNECTED); - break; - case ALIAS_TCP_STATE_CONNECTED: - if (tc->th_flags & TH_FIN - || tc->th_flags & TH_RST) - SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED); - break; - } -} - -static void -TcpMonitorOut(struct ip *pip, struct alias_link *link) -{ - struct tcphdr *tc; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - - switch (GetStateOut(link)) - { - case ALIAS_TCP_STATE_NOT_CONNECTED: - if (tc->th_flags & TH_SYN) - SetStateOut(link, ALIAS_TCP_STATE_CONNECTED); - break; - case ALIAS_TCP_STATE_CONNECTED: - if (tc->th_flags & TH_FIN - || tc->th_flags & TH_RST) - SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED); - break; - } -} - - - - - -/* Protocol Specific Packet Aliasing Routines - - IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3() - IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3() - UdpAliasIn(), UdpAliasOut() - TcpAliasIn(), TcpAliasOut() - -These routines handle protocol specific details of packet aliasing. -One may observe a certain amount of repetitive arithmetic in these -functions, the purpose of which is to compute a revised checksum -without actually summing over the entire data packet, which could be -unnecessarily time consuming. - -The purpose of the packet aliasing routines is to replace the source -address of the outgoing packet and then correctly put it back for -any incoming packets. For TCP and UDP, ports are also re-mapped. - -For ICMP echo/timestamp requests and replies, the following scheme -is used: the id number is replaced by an alias for the outgoing -packet. - -ICMP error messages are handled by looking at the IP fragment -in the data section of the message. - -For TCP and UDP protocols, a port number is chosen for an outgoing -packet, and then incoming packets are identified by IP address and -port numbers. For TCP packets, there is additional logic in the event -that sequence and ack numbers have been altered (as is the case for -FTP data port commands). - -The port numbers used by the packet aliasing module are not true -ports in the Unix sense. No sockets are actually bound to ports. -They are more correctly thought of as placeholders. - -All packets go through the aliasing mechanism, whether they come from -the gateway machine or other machines on a local area network. -*/ - - -/* Local prototypes */ -static int IcmpAliasIn1(struct ip *); -static int IcmpAliasIn2(struct ip *); -static int IcmpAliasIn3(struct ip *); -static int IcmpAliasIn (struct ip *); - -static int IcmpAliasOut1(struct ip *); -static int IcmpAliasOut2(struct ip *); -static int IcmpAliasOut3(struct ip *); -static int IcmpAliasOut (struct ip *); - -static int UdpAliasOut(struct ip *); -static int UdpAliasIn (struct ip *); - -static int TcpAliasOut(struct ip *, int); -static int TcpAliasIn (struct ip *); - - -static int -IcmpAliasIn1(struct ip *pip) -{ -/* - De-alias incoming echo and timestamp replies -*/ - struct alias_link *link; - struct icmp *ic; - - ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - -/* Get source address from ICMP data field and restore original data */ - link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id); - if (link != NULL) - { - u_short original_id; - int accumulate; - - original_id = GetOriginalPort(link); - -/* Adjust ICMP checksum */ - accumulate = ic->icmp_id; - accumulate -= original_id; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) - -/* Put original sequence number back in */ - ic->icmp_id = original_id; - -/* Put original address back into IP header */ - { - struct in_addr original_address; - - original_address = GetOriginalAddress(link); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - } - - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - -static int -IcmpAliasIn2(struct ip *pip) -{ -/* - Alias incoming ICMP error messages containing - IP header and first 64 bits of datagram. -*/ - struct ip *ip; - struct icmp *ic, *ic2; - struct udphdr *ud; - struct tcphdr *tc; - struct alias_link *link; - - ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - ip = (struct ip *) ic->icmp_data; - - ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2)); - tc = (struct tcphdr *) ud; - ic2 = (struct icmp *) ud; - - if (ip->ip_p == IPPROTO_UDP) - link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, - ud->uh_dport, ud->uh_sport, - IPPROTO_UDP); - else if (ip->ip_p == IPPROTO_TCP) - link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, - tc->th_dport, tc->th_sport, - IPPROTO_TCP); - else if (ip->ip_p == IPPROTO_ICMP) { - if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) - link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id); - else - link = NULL; - } else - link = NULL; - - if (link != NULL) - { - if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) - { - u_short *sptr; - int accumulate; - struct in_addr original_address; - u_short original_port; - - original_address = GetOriginalAddress(link); - original_port = GetOriginalPort(link); - -/* Adjust ICMP checksum */ - sptr = (u_short *) &(ip->ip_src); - accumulate = *sptr++; - accumulate += *sptr; - sptr = (u_short *) &original_address; - accumulate -= *sptr++; - accumulate -= *sptr; - accumulate += ud->uh_sport; - accumulate -= original_port; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) - -/* Un-alias address in IP header */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - -/* Un-alias address and port number of original IP packet -fragment contained in ICMP data section */ - ip->ip_src = original_address; - ud->uh_sport = original_port; - } - else if (pip->ip_p == IPPROTO_ICMP) - { - u_short *sptr; - int accumulate; - struct in_addr original_address; - u_short original_id; - - original_address = GetOriginalAddress(link); - original_id = GetOriginalPort(link); - -/* Adjust ICMP checksum */ - sptr = (u_short *) &(ip->ip_src); - accumulate = *sptr++; - accumulate += *sptr; - sptr = (u_short *) &original_address; - accumulate -= *sptr++; - accumulate -= *sptr; - accumulate += ic2->icmp_id; - accumulate -= original_id; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) - -/* Un-alias address in IP header */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - -/* Un-alias address of original IP packet and seqence number of - embedded icmp datagram */ - ip->ip_src = original_address; - ic2->icmp_id = original_id; - } - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - - -static int -IcmpAliasIn3(struct ip *pip) -{ - struct in_addr original_address; - - original_address = FindOriginalAddress(pip->ip_dst); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - - return PKT_ALIAS_OK; -} - - -static int -IcmpAliasIn(struct ip *pip) -{ - int iresult; - struct icmp *ic; - - ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - - iresult = PKT_ALIAS_IGNORED; - switch (ic->icmp_type) - { - case ICMP_ECHOREPLY: - case ICMP_TSTAMPREPLY: - if (ic->icmp_code == 0) - { - iresult = IcmpAliasIn1(pip); - } - break; - case ICMP_UNREACH: - case ICMP_SOURCEQUENCH: - case ICMP_TIMXCEED: - case ICMP_PARAMPROB: - iresult = IcmpAliasIn2(pip); - break; - case ICMP_ECHO: - case ICMP_TSTAMP: - iresult = IcmpAliasIn3(pip); - break; - } - return(iresult); -} - - -static int -IcmpAliasOut1(struct ip *pip) -{ -/* - Alias ICMP echo and timestamp packets -*/ - struct alias_link *link; - struct icmp *ic; - - ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - -/* Save overwritten data for when echo packet returns */ - link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id); - if (link != NULL) - { - u_short alias_id; - int accumulate; - - alias_id = GetAliasPort(link); - -/* Since data field is being modified, adjust ICMP checksum */ - accumulate = ic->icmp_id; - accumulate -= alias_id; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) - -/* Alias sequence number */ - ic->icmp_id = alias_id; - -/* Change source address */ - { - struct in_addr alias_address; - - alias_address = GetAliasAddress(link); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_address, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_address; - } - - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - - -static int -IcmpAliasOut2(struct ip *pip) -{ -/* - Alias outgoing ICMP error messages containing - IP header and first 64 bits of datagram. -*/ - struct in_addr alias_addr; - struct ip *ip; - struct icmp *ic; - - ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - ip = (struct ip *) ic->icmp_data; - - alias_addr = FindAliasAddress(ip->ip_src); - -/* Alias destination address in IP fragment */ - DifferentialChecksum(&ic->icmp_cksum, - (u_short *) &alias_addr, - (u_short *) &ip->ip_dst, - 2); - ip->ip_dst = alias_addr; - -/* alias source address in IP header */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_addr, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_addr; - - return PKT_ALIAS_OK; -} - - -static int -IcmpAliasOut3(struct ip *pip) -{ -/* - Handle outgoing echo and timestamp replies. The - only thing which is done in this case is to alias - the source IP address of the packet. -*/ - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(pip->ip_src); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_addr, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_addr; - - return PKT_ALIAS_OK; -} - - -static int -IcmpAliasOut(struct ip *pip) -{ - int iresult; - struct icmp *ic; - - ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - - iresult = PKT_ALIAS_IGNORED; - switch (ic->icmp_type) - { - case ICMP_ECHO: - case ICMP_TSTAMP: - if (ic->icmp_code == 0) - { - iresult = IcmpAliasOut1(pip); - } - break; - case ICMP_UNREACH: - case ICMP_SOURCEQUENCH: - case ICMP_TIMXCEED: - case ICMP_PARAMPROB: - iresult = IcmpAliasOut2(pip); - break; - case ICMP_ECHOREPLY: - case ICMP_TSTAMPREPLY: - iresult = IcmpAliasOut3(pip); - } - return(iresult); -} - -static int -UdpAliasIn(struct ip *pip) -{ - struct udphdr *ud; - struct alias_link *link; - - ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); - - link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, - ud->uh_sport, ud->uh_dport, - IPPROTO_UDP); - if (link != NULL) - { - struct in_addr alias_address; - struct in_addr original_address; - u_short alias_port; - int accumulate; - u_short *sptr; - int r = 0; - - alias_address = GetAliasAddress(link); - original_address = GetOriginalAddress(link); - alias_port = ud->uh_dport; - ud->uh_dport = GetOriginalPort(link); - -/* If NETBIOS Datagram, It should be alias address in UDP Data, too */ - if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) - { - r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport); - } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) - { - r = AliasHandleUdpNbtNS(pip, link, - &alias_address, - &alias_port, - &original_address, - &ud->uh_dport ); - } - - if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) - AliasHandleCUSeeMeIn(pip, original_address); - -/* If UDP checksum is not zero, then adjust since destination port */ -/* is being unaliased and destination port is being altered. */ - if (ud->uh_sum != 0) - { - accumulate = alias_port; - accumulate -= ud->uh_dport; - sptr = (u_short *) &alias_address; - accumulate += *sptr++; - accumulate += *sptr; - sptr = (u_short *) &original_address; - accumulate -= *sptr++; - accumulate -= *sptr; - ADJUST_CHECKSUM(accumulate, ud->uh_sum) - } - -/* Restore original IP address */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - - /* - * If we cannot figure out the packet, ignore it. - */ - if (r < 0) - return(PKT_ALIAS_IGNORED); - else - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - -static int -UdpAliasOut(struct ip *pip) -{ - struct udphdr *ud; - struct alias_link *link; - - ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); - - link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, - ud->uh_sport, ud->uh_dport, - IPPROTO_UDP); - if (link != NULL) - { - u_short alias_port; - struct in_addr alias_address; - - alias_address = GetAliasAddress(link); - alias_port = GetAliasPort(link); - - if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) - AliasHandleCUSeeMeOut(pip, link); - -/* If NETBIOS Datagram, It should be alias address in UDP Data, too */ - if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) - { - AliasHandleUdpNbt(pip, link, &alias_address, alias_port); - } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) - { - AliasHandleUdpNbtNS(pip, link, - &pip->ip_src, - &ud->uh_sport, - &alias_address, - &alias_port); - } - -/* If UDP checksum is not zero, adjust since source port is */ -/* being aliased and source address is being altered */ - if (ud->uh_sum != 0) - { - int accumulate; - u_short *sptr; - - accumulate = ud->uh_sport; - accumulate -= alias_port; - sptr = (u_short *) &(pip->ip_src); - accumulate += *sptr++; - accumulate += *sptr; - sptr = (u_short *) &alias_address; - accumulate -= *sptr++; - accumulate -= *sptr; - ADJUST_CHECKSUM(accumulate, ud->uh_sum) - } - -/* Put alias port in UDP header */ - ud->uh_sport = alias_port; - -/* Change source address */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_address, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_address; - - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - - - -static int -TcpAliasIn(struct ip *pip) -{ - struct tcphdr *tc; - struct alias_link *link; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - - link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, - tc->th_sport, tc->th_dport, - IPPROTO_TCP); - if (link != NULL) - { - struct in_addr alias_address; - struct in_addr original_address; - u_short alias_port; - int accumulate; - u_short *sptr; - - alias_address = GetAliasAddress(link); - original_address = GetOriginalAddress(link); - alias_port = tc->th_dport; - tc->th_dport = GetOriginalPort(link); - -/* Adjust TCP checksum since destination port is being unaliased */ -/* and destination port is being altered. */ - accumulate = alias_port; - accumulate -= tc->th_dport; - sptr = (u_short *) &alias_address; - accumulate += *sptr++; - accumulate += *sptr; - sptr = (u_short *) &original_address; - accumulate -= *sptr++; - accumulate -= *sptr; - -/* See if ack number needs to be modified */ - if (GetAckModified(link) == 1) - { - int delta; - - delta = GetDeltaAckIn(pip, link); - if (delta != 0) - { - sptr = (u_short *) &tc->th_ack; - accumulate += *sptr++; - accumulate += *sptr; - tc->th_ack = htonl(ntohl(tc->th_ack) - delta); - sptr = (u_short *) &tc->th_ack; - accumulate -= *sptr++; - accumulate -= *sptr; - } - } - - ADJUST_CHECKSUM(accumulate, tc->th_sum); - -/* Restore original IP address */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - -/* Monitor TCP connection state */ - TcpMonitorIn(pip, link); - - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - -static int -TcpAliasOut(struct ip *pip, int maxpacketsize) -{ - struct tcphdr *tc; - struct alias_link *link; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - - link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, - tc->th_sport, tc->th_dport, - IPPROTO_TCP); - if (link !=NULL) - { - struct in_addr alias_address; - u_short alias_port; - int accumulate; - u_short *sptr; - - alias_port = GetAliasPort(link); - alias_address = GetAliasAddress(link); - -/* Monitor tcp connection state */ - TcpMonitorOut(pip, link); - -/* Special processing for ftp connection */ - if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER - || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER) - AliasHandleFtpOut(pip, link, maxpacketsize); - if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1 - || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2) - AliasHandleIrcOut(pip, link, maxpacketsize); - -/* Adjust TCP checksum since source port is being aliased */ -/* and source address is being altered */ - accumulate = tc->th_sport; - accumulate -= alias_port; - sptr = (u_short *) &(pip->ip_src); - accumulate += *sptr++; - accumulate += *sptr; - sptr = (u_short *) &alias_address; - accumulate -= *sptr++; - accumulate -= *sptr; - -/* Modify sequence number if necessary */ - if (GetAckModified(link) == 1) - { - int delta; - - delta = GetDeltaSeqOut(pip, link); - if (delta != 0) - { - sptr = (u_short *) &tc->th_seq; - accumulate += *sptr++; - accumulate += *sptr; - tc->th_seq = htonl(ntohl(tc->th_seq) + delta); - sptr = (u_short *) &tc->th_seq; - accumulate -= *sptr++; - accumulate -= *sptr; - } - } - - ADJUST_CHECKSUM(accumulate, tc->th_sum) - -/* Put alias address in TCP header */ - tc->th_sport = alias_port; - -/* Change source address */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_address, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_address; - - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_IGNORED); -} - - - - -/* Fragment Handling - - FragmentIn() - FragmentOut() - -The packet aliasing module has a limited ability for handling IP -fragments. If the ICMP, TCP or UDP header is in the first fragment -received, then the id number of the IP packet is saved, and other -fragments are identified according to their ID number and IP address -they were sent from. Pointers to unresolved fragments can also be -saved and recalled when a header fragment is seen. -*/ - -/* Local prototypes */ -static int FragmentIn(struct ip *); -static int FragmentOut(struct ip *); - - -static int -FragmentIn(struct ip *pip) -{ - struct alias_link *link; - - link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id); - if (link != NULL) - { - struct in_addr original_address; - - GetFragmentAddr(link, &original_address); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - - return(PKT_ALIAS_OK); - } - return(PKT_ALIAS_UNRESOLVED_FRAGMENT); -} - - -static int -FragmentOut(struct ip *pip) -{ - struct in_addr alias_address; - - alias_address = FindAliasAddress(pip->ip_src); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_address, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_address; - - return(PKT_ALIAS_OK); -} - - - - - - -/* Outside World Access - - PacketAliasSaveFragment() - PacketAliasGetFragment() - PacketAliasFragmentIn() - PacketAliasIn() - PacketAliasOut() - -(prototypes in alias.h) -*/ - - -int -PacketAliasSaveFragment(char *ptr) -{ - int iresult; - struct alias_link *link; - struct ip *pip; - - pip = (struct ip *) ptr; - link = AddFragmentPtrLink(pip->ip_src, pip->ip_id); - iresult = PKT_ALIAS_ERROR; - if (link != NULL) - { - SetFragmentPtr(link, ptr); - iresult = PKT_ALIAS_OK; - } - return(iresult); -} - - -char * -PacketAliasGetFragment(char *ptr) -{ - struct alias_link *link; - char *fptr; - struct ip *pip; - - pip = (struct ip *) ptr; - link = FindFragmentPtr(pip->ip_src, pip->ip_id); - if (link != NULL) - { - GetFragmentPtr(link, &fptr); - SetFragmentPtr(link, NULL); - SetExpire(link, 0); /* Deletes link */ - - return(fptr); - } - else - { - return(NULL); - } -} - - -void -PacketAliasFragmentIn(char *ptr, /* Points to correctly de-aliased - header fragment */ - char *ptr_fragment /* Points to fragment which must - be de-aliased */ - ) -{ - struct ip *pip; - struct ip *fpip; - - pip = (struct ip *) ptr; - fpip = (struct ip *) ptr_fragment; - - DifferentialChecksum(&fpip->ip_sum, - (u_short *) &pip->ip_dst, - (u_short *) &fpip->ip_dst, - 2); - fpip->ip_dst = pip->ip_dst; -} - - -int -PacketAliasIn(char *ptr, int maxpacketsize) -{ - struct in_addr alias_addr; - struct ip *pip; - int iresult; - - HouseKeeping(); - ClearCheckNewLink(); - pip = (struct ip *) ptr; - alias_addr = pip->ip_dst; - - /* Defense against mangled packets */ - if (ntohs(pip->ip_len) > maxpacketsize - || (pip->ip_hl<<2) > maxpacketsize) - return PKT_ALIAS_IGNORED; - - iresult = PKT_ALIAS_IGNORED; - if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 ) - { - switch (pip->ip_p) - { - case IPPROTO_ICMP: - iresult = IcmpAliasIn(pip); - break; - case IPPROTO_UDP: - iresult = UdpAliasIn(pip); - break; - case IPPROTO_TCP: - iresult = TcpAliasIn(pip); - break; - } - - if (ntohs(pip->ip_off) & IP_MF) - { - struct alias_link *link; - - link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id); - if (link != NULL) - { - iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; - SetFragmentAddr(link, pip->ip_dst); - } - else - { - iresult = PKT_ALIAS_ERROR; - } - } - } - else - { - iresult = FragmentIn(pip); - } - - return(iresult); -} - - - -/* Unregistered address ranges */ - -/* 10.0.0.0 -> 10.255.255.255 */ -#define UNREG_ADDR_A_LOWER 0x0a000000 -#define UNREG_ADDR_A_UPPER 0x0affffff - -/* 172.16.0.0 -> 172.31.255.255 */ -#define UNREG_ADDR_B_LOWER 0xac100000 -#define UNREG_ADDR_B_UPPER 0xac1fffff - -/* 192.168.0.0 -> 192.168.255.255 */ -#define UNREG_ADDR_C_LOWER 0xc0a80000 -#define UNREG_ADDR_C_UPPER 0xc0a8ffff - - - -int -PacketAliasOut(char *ptr, /* valid IP packet */ - int maxpacketsize /* How much the packet data may grow - (FTP and IRC inline changes) */ - ) -{ - int iresult; - struct in_addr addr_save; - struct ip *pip; - - HouseKeeping(); - ClearCheckNewLink(); - pip = (struct ip *) ptr; - - /* Defense against mangled packets */ - if (ntohs(pip->ip_len) > maxpacketsize - || (pip->ip_hl<<2) > maxpacketsize) - return PKT_ALIAS_IGNORED; - - addr_save = GetDefaultAliasAddress(); - if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) - { - unsigned int addr; - int iclass; - - iclass = 0; - addr = ntohl(pip->ip_src.s_addr); - if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) - iclass = 3; - else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) - iclass = 2; - else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) - iclass = 1; - - if (iclass == 0) - { - SetDefaultAliasAddress(pip->ip_src); - } - } - - iresult = PKT_ALIAS_IGNORED; - if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) - { - switch (pip->ip_p) - { - case IPPROTO_ICMP: - iresult = IcmpAliasOut(pip); - break; - case IPPROTO_UDP: - iresult = UdpAliasOut(pip); - break; - case IPPROTO_TCP: - iresult = TcpAliasOut(pip, maxpacketsize); - break; - } - } - else - { - iresult = FragmentOut(pip); - } - - SetDefaultAliasAddress(addr_save); - return(iresult); -} diff --git a/sys/netinet/libalias/alias.h b/sys/netinet/libalias/alias.h deleted file mode 100644 index 010db9885a5a..000000000000 --- a/sys/netinet/libalias/alias.h +++ /dev/null @@ -1,173 +0,0 @@ -/*lint -save -library Flexelint comment for external headers */ - -/* - Alias.h defines the outside world interfaces for the packet - aliasing software. - - This software is placed into the public domain with no restrictions - on its distribution. - - $Id: alias.h,v 1.7 1998/01/16 12:56:07 bde Exp $ -*/ - - -#ifndef _ALIAS_H_ -#define _ALIAS_H_ - -#ifndef NULL -#define NULL 0 -#endif - -/* Alias link representative (incomplete struct) */ -struct alias_link; - -/* External interfaces (API) to packet aliasing engine */ - -/* Initialization and Control */ - extern void - PacketAliasInit(void); - - extern void - PacketAliasUninit(void); - - extern void - PacketAliasSetAddress(struct in_addr); - - extern unsigned int - PacketAliasSetMode(unsigned int, unsigned int); - -#ifndef NO_FW_PUNCH - extern void - PacketAliasSetFWBase(unsigned int, unsigned int); -#endif - -/* Packet Handling */ - extern int - PacketAliasIn(char *, int maxpacketsize); - - extern int - PacketAliasOut(char *, int maxpacketsize); - -/* Port and Address Redirection */ - extern struct alias_link * - PacketAliasRedirectPort(struct in_addr, u_short, - struct in_addr, u_short, - struct in_addr, u_short, - u_char); - - extern struct alias_link * - PacketAliasRedirectAddr(struct in_addr, - struct in_addr); - - extern void - PacketAliasRedirectDelete(struct alias_link *); - -/* Fragment Handling */ - extern int - PacketAliasSaveFragment(char *); - - extern char * - PacketAliasGetFragment(char *); - - extern void - PacketAliasFragmentIn(char *, char *); - -/* Miscellaneous Functions */ - extern void - PacketAliasSetTarget(struct in_addr addr); - - extern int - PacketAliasCheckNewLink(void); - - extern u_short - PacketAliasInternetChecksum(u_short *, int); - - -/* - In version 2.2, the function names were rationalized - to all be of the form PacketAlias... These are the - old function names for backwards compatibility -*/ -extern int SaveFragmentPtr(char *); -extern char *GetNextFragmentPtr(char *); -extern void FragmentAliasIn(char *, char *); -extern void SetPacketAliasAddress(struct in_addr); -extern void InitPacketAlias(void); -extern unsigned int SetPacketAliasMode(unsigned int, unsigned int); -extern int PacketAliasIn2(char *, struct in_addr, int maxpacketsize); -extern int PacketAliasOut2(char *, struct in_addr, int maxpacketsize); -extern int -PacketAliasPermanentLink(struct in_addr, u_short, - struct in_addr, u_short, - u_short, u_char); -extern u_short InternetChecksum(u_short *, int); - -/* Obsolete constant */ -#define PKT_ALIAS_NEW_LINK 5 - -/********************** Mode flags ********************/ -/* Set these flags using SetPacketAliasMode() */ - -/* If PKT_ALIAS_LOG is set, a message will be printed to - /var/log/alias.log every time a link is created or deleted. This - is useful for debugging */ -#define PKT_ALIAS_LOG 0x01 - -/* If PKT_ALIAS_DENY_INCOMING is set, then incoming connections (e.g. - to ftp, telnet or web servers will be prevented by the aliasing - mechanism. */ -#define PKT_ALIAS_DENY_INCOMING 0x02 - -/* If PKT_ALIAS_SAME_PORTS is set, packets will be attempted sent from - the same port as they originated on. This allows eg rsh to work - *99% of the time*, but _not_ 100%. (It will be slightly flakey - instead of not working at all.) This mode bit is set by - PacketAliasInit(), so it is a default mode of operation. */ -#define PKT_ALIAS_SAME_PORTS 0x04 - -/* If PKT_ALIAS_USE_SOCKETS is set, then when partially specified - links (e.g. destination port and/or address is zero), the packet - aliasing engine will attempt to allocate a socket for the aliasing - port it chooses. This will avoid interference with the host - machine. Fully specified links do not require this. This bit - is set after a call to PacketAliasInit(), so it is a default - mode of operation.*/ -#define PKT_ALIAS_USE_SOCKETS 0x08 - -/* If PKT_ALIAS_UNREGISTERED_ONLY is set, then only packets with with - unregistered source addresses will be aliased (along with those - of the ppp host maching itself. Private addresses are those - in the following ranges: - - 10.0.0.0 -> 10.255.255.255 - 172.16.0.0 -> 172.31.255.255 - 192.168.0.0 -> 192.168.255.255 */ -#define PKT_ALIAS_UNREGISTERED_ONLY 0x10 - -/* If PKT_ALIAS_RESET_ON_ADDR_CHANGE is set, then the table of dynamic - aliasing links will be reset whenever PacketAliasSetAddress() - changes the default aliasing address. If the default aliasing - address is left unchanged by this functions call, then the - table of dynamic aliasing links will be left intact. This - bit is set after a call to PacketAliasInit(). */ -#define PKT_ALIAS_RESET_ON_ADDR_CHANGE 0x20 - -#ifndef NO_FW_PUNCH -/* If PKT_ALIAS_PUNCH_FW is set, active FTP and IRC DCC connections - will create a 'hole' in the firewall to allow the transfers to - work. Where (IPFW "line-numbers") the hole is created is - controlled by PacketAliasSetFWBase(base, size). The hole will be - attached to that particular alias_link, so when the link goes away - so do the hole. */ -#define PKT_ALIAS_PUNCH_FW 0x40 -#endif - -/* Return Codes */ -#define PKT_ALIAS_ERROR -1 -#define PKT_ALIAS_OK 1 -#define PKT_ALIAS_IGNORED 2 -#define PKT_ALIAS_UNRESOLVED_FRAGMENT 3 -#define PKT_ALIAS_FOUND_HEADER_FRAGMENT 4 - -#endif -/*lint -restore */ diff --git a/sys/netinet/libalias/alias_cuseeme.c b/sys/netinet/libalias/alias_cuseeme.c deleted file mode 100644 index 7cb6d4ea4ee4..000000000000 --- a/sys/netinet/libalias/alias_cuseeme.c +++ /dev/null @@ -1,120 +0,0 @@ -/*- - * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> - * with the aid of code written by - * Junichi SATOH <junichi@astec.co.jp> 1996, 1997. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ - -#include <sys/types.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/udp.h> - -#include "alias_local.h" - -/* CU-SeeMe Data Header */ -struct cu_header { - u_int16_t dest_family; - u_int16_t dest_port; - u_int32_t dest_addr; - int16_t family; - u_int16_t port; - u_int32_t addr; - u_int32_t seq; - u_int16_t msg; - u_int16_t data_type; - u_int16_t packet_len; -}; - -/* Open Continue Header */ -struct oc_header { - u_int16_t client_count; /* Number of client info structs */ - u_int32_t seq_no; - char user_name[20]; - char reserved[4]; /* flags, version stuff, etc */ -}; - -/* client info structures */ -struct client_info { - u_int32_t address; /* Client address */ - char reserved[8]; /* Flags, pruning bitfield, packet counts etc */ -}; - -void -AliasHandleCUSeeMeOut(struct ip *pip, struct alias_link *link) -{ - struct udphdr *ud; - - ud = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); - if(ud->uh_ulen >= sizeof(struct cu_header)) { - struct cu_header *cu; - struct alias_link *cu_link; - - cu = (struct cu_header *)(ud + 1); - if (cu->addr) - cu->addr = (u_int32_t)GetAliasAddress(link).s_addr; - - cu_link = FindUdpTcpOut(pip->ip_src, GetDestAddress(link), - ud->uh_dport, 0, IPPROTO_UDP); - -#ifndef NO_FW_PUNCH - if (cu_link) - PunchFWHole(cu_link); -#endif - } -} - -void -AliasHandleCUSeeMeIn(struct ip *pip, struct in_addr original_addr) -{ - struct in_addr alias_addr; - struct udphdr *ud; - struct cu_header *cu; - struct oc_header *oc; - struct client_info *ci; - char *end; - int i; - - alias_addr.s_addr = pip->ip_dst.s_addr; - ud = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); - cu = (struct cu_header *)(ud + 1); - oc = (struct oc_header *)(cu + 1); - ci = (struct client_info *)(oc + 1); - end = (char *)cu + ud->uh_ulen; - - if ((char *)oc <= end) { - if(cu->dest_addr) - cu->dest_addr = (u_int32_t)original_addr.s_addr; - if(ntohs(cu->data_type) == 101) - /* Find and change our address */ - for(i = 0; (char *)(ci + 1) <= end && i < oc->client_count; i++, ci++) - if(ci->address == (u_int32_t)alias_addr.s_addr) { - ci->address = (u_int32_t)original_addr.s_addr; - break; - } - } -} diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c deleted file mode 100644 index dc9d020bd858..000000000000 --- a/sys/netinet/libalias/alias_db.c +++ /dev/null @@ -1,2241 +0,0 @@ -/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- - Alias_db.c encapsulates all data structures used for storing - packet aliasing data. Other parts of the aliasing software - access data through functions provided in this file. - - Data storage is based on the notion of a "link", which is - established for ICMP echo/reply packets, UDP datagrams and - TCP stream connections. A link stores the original source - and destination addresses. For UDP and TCP, it also stores - source and destination port numbers, as well as an alias - port number. Links are also used to store information about - fragments. - - There is a facility for sweeping through and deleting old - links as new packets are sent through. A simple timeout is - used for ICMP and UDP links. TCP links are left alone unless - there is an incomplete connection, in which case the link - can be deleted after a certain amount of time. - - - This software is placed into the public domain with no restrictions - on its distribution. - - Initial version: August, 1996 (cjm) - - Version 1.4: September 16, 1996 (cjm) - Facility for handling incoming links added. - - Version 1.6: September 18, 1996 (cjm) - ICMP data handling simplified. - - Version 1.7: January 9, 1997 (cjm) - Fragment handling simplified. - Saves pointers for unresolved fragments. - Permits links for unspecied remote ports - or unspecified remote addresses. - Fixed bug which did not properly zero port - table entries after a link was deleted. - Cleaned up some obsolete comments. - - Version 1.8: January 14, 1997 (cjm) - Fixed data type error in StartPoint(). - (This error did not exist prior to v1.7 - and was discovered and fixed by Ari Suutari) - - Version 1.9: February 1, 1997 - Optionally, connections initiated from packet aliasing host - machine will will not have their port number aliased unless it - conflicts with an aliasing port already being used. (cjm) - - All options earlier being #ifdef'ed now are available through - a new interface, SetPacketAliasMode(). This allow run time - control (which is now available in PPP+pktAlias through the - 'alias' keyword). (ee) - - Added ability to create an alias port without - either destination address or port specified. - port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) - - Removed K&R style function headers - and general cleanup. (ee) - - Added packetAliasMode to replace compiler #defines's (ee) - - Allocates sockets for partially specified - ports if ALIAS_USE_SOCKETS defined. (cjm) - - Version 2.0: March, 1997 - SetAliasAddress() will now clean up alias links - if the aliasing address is changed. (cjm) - - PacketAliasPermanentLink() function added to support permanent - links. (J. Fortes suggested the need for this.) - Examples: - - (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port - - (192.168.0.2, port 21) <-> alias port 3604, known dest addr - unknown dest port - - These permament links allow for incoming connections to - machines on the local network. They can be given with a - user-chosen amount of specificity, with increasing specificity - meaning more security. (cjm) - - Quite a bit of rework to the basic engine. The portTable[] - array, which kept track of which ports were in use was replaced - by a table/linked list structure. (cjm) - - SetExpire() function added. (cjm) - - DeleteLink() no longer frees memory association with a pointer - to a fragment (this bug was first recognized by E. Eklund in - v1.9). - - Version 2.1: May, 1997 (cjm) - Packet aliasing engine reworked so that it can handle - multiple external addresses rather than just a single - host address. - - PacketAliasRedirectPort() and PacketAliasRedirectAddr() - added to the API. The first function is a more generalized - version of PacketAliasPermanentLink(). The second function - implements static network address translation. - - See HISTORY file for additional revisions. -*/ - - -/* System include files */ -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include <sys/errno.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/types.h> - -/* BSD network include files */ -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> - -#include "alias.h" -#include "alias_local.h" - - - -/* - Constants (note: constants are also defined - near relevant functions or structs) -*/ - -/* Sizes of input and output link tables */ -#define LINK_TABLE_OUT_SIZE 101 -#define LINK_TABLE_IN_SIZE 4001 - -/* Parameters used for cleanup of expired links */ -#define ALIAS_CLEANUP_INTERVAL_SECS 60 -#define ALIAS_CLEANUP_MAX_SPOKES 30 - -/* Timouts (in seconds) for different link types) */ -#define ICMP_EXPIRE_TIME 60 -#define UDP_EXPIRE_TIME 60 -#define FRAGMENT_ID_EXPIRE_TIME 10 -#define FRAGMENT_PTR_EXPIRE_TIME 30 - -/* TCP link expire time for different cases */ -/* When the link has been used and closed - minimal grace time to - allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ -#ifndef TCP_EXPIRE_DEAD -# define TCP_EXPIRE_DEAD 10 -#endif - -/* When the link has been used and closed on one side - the other side - is allowed to still send data */ -#ifndef TCP_EXPIRE_SINGLEDEAD -# define TCP_EXPIRE_SINGLEDEAD 90 -#endif - -/* When the link isn't yet up */ -#ifndef TCP_EXPIRE_INITIAL -# define TCP_EXPIRE_INITIAL 300 -#endif - -/* When the link is up */ -#ifndef TCP_EXPIRE_CONNECTED -# define TCP_EXPIRE_CONNECTED 86400 -#endif - - -/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). - These constants can be anything except zero, which indicates an - unknown port numbea. */ - -#define NO_DEST_PORT 1 -#define NO_SRC_PORT 1 - - - -/* Data Structures - - The fundamental data structure used in this program is - "struct alias_link". Whenever a TCP connection is made, - a UDP datagram is sent out, or an ICMP echo request is made, - a link record is made (if it has not already been created). - The link record is identified by the source address/port - and the destination address/port. In the case of an ICMP - echo request, the source port is treated as being equivalent - with the 16-bit id number of the ICMP packet. - - The link record also can store some auxiliary data. For - TCP connections that have had sequence and acknowledgment - modifications, data space is available to track these changes. - A state field is used to keep track in changes to the tcp - connection state. Id numbers of fragments can also be - stored in the auxiliary space. Pointers to unresolved - framgents can also be stored. - - The link records support two independent chainings. Lookup - tables for input and out tables hold the initial pointers - the link chains. On input, the lookup table indexes on alias - port and link type. On output, the lookup table indexes on - source addreess, destination address, source port, destination - port and link type. -*/ - -struct ack_data_record /* used to save changes to ack/seq numbers */ -{ - u_long ack_old; - u_long ack_new; - int delta; - int active; -}; - -struct tcp_state /* Information about tcp connection */ -{ - int in; /* State for outside -> inside */ - int out; /* State for inside -> outside */ - int index; /* Index to ack data array */ - int ack_modified; /* Indicates whether ack and seq numbers */ - /* been modified */ -}; - -#define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes - saved for a modified TCP stream */ -struct tcp_dat -{ - struct tcp_state state; - struct ack_data_record ack[N_LINK_TCP_DATA]; - int fwhole; /* Which firewall record is used for this hole? */ -}; - -struct alias_link /* Main data structure */ -{ - struct in_addr src_addr; /* Address and port information */ - struct in_addr dst_addr; /* . */ - struct in_addr alias_addr; /* . */ - u_short src_port; /* . */ - u_short dst_port; /* . */ - u_short alias_port; /* . */ - - int link_type; /* Type of link: tcp, udp, icmp, frag */ - -/* values for link_type */ -#define LINK_ICMP 1 -#define LINK_UDP 2 -#define LINK_TCP 3 -#define LINK_FRAGMENT_ID 4 -#define LINK_FRAGMENT_PTR 5 -#define LINK_ADDR 6 - - int flags; /* indicates special characteristics */ - -/* flag bits */ -#define LINK_UNKNOWN_DEST_PORT 0x01 -#define LINK_UNKNOWN_DEST_ADDR 0x02 -#define LINK_PERMANENT 0x04 -#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ -#define LINK_UNFIREWALLED 0x08 - - int timestamp; /* Time link was last accessed */ - int expire_time; /* Expire time for link */ - - int sockfd; /* socket descriptor */ - - u_int start_point_out; /* Index number in output lookup table */ - u_int start_point_in; - struct alias_link *next_out; /* Linked list pointers for input and */ - struct alias_link *last_out; /* output tables */ - struct alias_link *next_in; /* . */ - struct alias_link *last_in; /* . */ - - union /* Auxiliary data */ - { - char *frag_ptr; - struct in_addr frag_addr; - struct tcp_dat *tcp; - } data; -}; - - - - - -/* Global Variables - - The global variables listed here are only accessed from - within alias_db.c and so are prefixed with the static - designation. -*/ - -int packetAliasMode; /* Mode flags */ - /* - documented in alias.h */ - -static struct in_addr aliasAddress; /* Address written onto source */ - /* field of IP packet. */ - -static struct in_addr targetAddress; /* IP address incoming packets */ - /* are sent to if no aliasing */ - /* link already exists */ - -static struct in_addr nullAddress; /* Used as a dummy parameter for */ - /* some function calls */ -static struct alias_link * -linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ - /* chains of link records. Each */ -static struct alias_link * /* link record is doubly indexed */ -linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ - /* tables. */ - -static int icmpLinkCount; /* Link statistics */ -static int udpLinkCount; -static int tcpLinkCount; -static int fragmentIdLinkCount; -static int fragmentPtrLinkCount; -static int sockCount; - -static int cleanupIndex; /* Index to chain of link table */ - /* being inspected for old links */ - -static int timeStamp; /* System time in seconds for */ - /* current packet */ - -static int lastCleanupTime; /* Last time IncrementalCleanup() */ - /* was called */ - -static int houseKeepingResidual; /* used by HouseKeeping() */ - -static int deleteAllLinks; /* If equal to zero, DeleteLink() */ - /* will not remove permanent links */ - -static FILE *monitorFile; /* File descriptor for link */ - /* statistics monitoring file */ - -static int newDefaultLink; /* Indicates if a new aliasing */ - /* link has been created after a */ - /* call to PacketAliasIn/Out(). */ - -#ifndef NO_FW_PUNCH -static int fireWallFD = -1; /* File descriptor to be able to */ - /* control firewall. Opened by */ - /* PacketAliasSetMode on first */ - /* setting the PKT_ALIAS_PUNCH_FW */ - /* flag. */ -#endif - - - - - - -/* Internal utility routines (used only in alias_db.c) - -Lookup table starting points: - StartPointIn() -- link table initial search point for - outgoing packets - StartPointOut() -- port table initial search point for - incoming packets - -Miscellaneous: - SeqDiff() -- difference between two TCP sequences - ShowAliasStats() -- send alias statistics to a monitor file -*/ - - -/* Local prototypes */ -static u_int StartPointIn(struct in_addr, u_short, int); - -static u_int StartPointOut(struct in_addr, struct in_addr, - u_short, u_short, int); - -static int SeqDiff(u_long, u_long); - -static void ShowAliasStats(void); - -#ifndef NO_FW_PUNCH -/* Firewall control */ -static void InitPunchFW(void); -static void UninitPunchFW(void); -static void ClearFWHole(struct alias_link *link); -#endif - -/* Log file control */ -static void InitPacketAliasLog(void); -static void UninitPacketAliasLog(void); - -static u_int -StartPointIn(struct in_addr alias_addr, - u_short alias_port, - int link_type) -{ - u_int n; - - n = alias_addr.s_addr; - n += alias_port; - n += link_type; - return(n % LINK_TABLE_IN_SIZE); -} - - -static u_int -StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, - u_short src_port, u_short dst_port, int link_type) -{ - u_int n; - - n = src_addr.s_addr; - n += dst_addr.s_addr; - n += src_port; - n += dst_port; - n += link_type; - - return(n % LINK_TABLE_OUT_SIZE); -} - - -static int -SeqDiff(u_long x, u_long y) -{ -/* Return the difference between two TCP sequence numbers */ - -/* - This function is encapsulated in case there are any unusual - arithmetic conditions that need to be considered. -*/ - - return (ntohl(y) - ntohl(x)); -} - - -static void -ShowAliasStats(void) -{ -/* Used for debugging */ - - if (monitorFile) - { - fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", - icmpLinkCount, - udpLinkCount, - tcpLinkCount, - fragmentIdLinkCount, - fragmentPtrLinkCount); - - fprintf(monitorFile, " / tot=%d (sock=%d)\n", - icmpLinkCount + udpLinkCount - + tcpLinkCount - + fragmentIdLinkCount - + fragmentPtrLinkCount, - sockCount); - - fflush(monitorFile); - } -} - - - - - -/* Internal routines for finding, deleting and adding links - -Port Allocation: - GetNewPort() -- find and reserve new alias port number - GetSocket() -- try to allocate a socket for a given port - -Link creation and deletion: - CleanupAliasData() - remove all link chains from lookup table - IncrementalCleanup() - look for stale links in a single chain - DeleteLink() - remove link - AddLink() - add link - ReLink() - change link - -Link search: - FindLinkOut() - find link for outgoing packets - FindLinkIn() - find link for incoming packets -*/ - -/* Local prototypes */ -static int GetNewPort(struct alias_link *, int); - -static u_short GetSocket(u_short, int *, int); - -static void CleanupAliasData(void); - -static void IncrementalCleanup(void); - -static void DeleteLink(struct alias_link *); - -static struct alias_link * -AddLink(struct in_addr, struct in_addr, struct in_addr, - u_short, u_short, int, int); - -static struct alias_link * -ReLink(struct alias_link *, - struct in_addr, struct in_addr, struct in_addr, - u_short, u_short, int, int); - -static struct alias_link * -FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); - -static struct alias_link * -FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); - - -#define ALIAS_PORT_BASE 0x08000 -#define ALIAS_PORT_MASK 0x07fff -#define GET_NEW_PORT_MAX_ATTEMPTS 20 - -#define GET_ALIAS_PORT -1 -#define GET_ALIAS_ID GET_ALIAS_PORT - -/* GetNewPort() allocates port numbers. Note that if a port number - is already in use, that does not mean that it cannot be used by - another link concurrently. This is because GetNewPort() looks for - unused triplets: (dest addr, dest port, alias port). */ - -static int -GetNewPort(struct alias_link *link, int alias_port_param) -{ - int i; - int max_trials; - u_short port_sys; - u_short port_net; - -/* - Description of alias_port_param for GetNewPort(). When - this parameter is zero or positive, it precisely specifies - the port number. GetNewPort() will return this number - without check that it is in use. - - Whis this parameter is -1, it indicates to get a randomly - selected port number. -*/ - - if (alias_port_param == GET_ALIAS_PORT) - { - /* - * The aliasing port is automatically selected - * by one of two methods below: - */ - max_trials = GET_NEW_PORT_MAX_ATTEMPTS; - - if (packetAliasMode & PKT_ALIAS_SAME_PORTS) - { - /* - * When the ALIAS_SAME_PORTS option is - * chosen, the first try will be the - * actual source port. If this is already - * in use, the remainder of the trials - * will be random. - */ - port_net = link->src_port; - port_sys = ntohs(port_net); - } - else - { - /* First trial and all subsequent are random. */ - port_sys = random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); - } - } - else if (alias_port_param >= 0 && alias_port_param < 0x10000) - { - link->alias_port = (u_short) alias_port_param; - return(0); - } - else - { - fprintf(stderr, "PacketAlias/GetNewPort(): "); - fprintf(stderr, "input parameter error\n"); - return(-1); - } - - -/* Port number search */ - for (i=0; i<max_trials; i++) - { - int go_ahead; - struct alias_link *search_result; - - search_result = FindLinkIn(link->dst_addr, link->alias_addr, - link->dst_port, port_net, - link->link_type, 0); - - if (search_result == NULL) - go_ahead = 1; - else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) - && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) - go_ahead = 1; - else - go_ahead = 0; - - if (go_ahead) - { - if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS) - && (link->flags & LINK_PARTIALLY_SPECIFIED)) - { - if (GetSocket(port_net, &link->sockfd, link->link_type)) - { - link->alias_port = port_net; - return(0); - } - } - else - { - link->alias_port = port_net; - return(0); - } - } - - port_sys = random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); - } - - fprintf(stderr, "PacketAlias/GetnewPort(): "); - fprintf(stderr, "could not find free port\n"); - - return(-1); -} - - -static u_short -GetSocket(u_short port_net, int *sockfd, int link_type) -{ - int err; - int sock; - struct sockaddr_in sock_addr; - - if (link_type == LINK_TCP) - sock = socket(AF_INET, SOCK_STREAM, 0); - else if (link_type == LINK_UDP) - sock = socket(AF_INET, SOCK_DGRAM, 0); - else - { - fprintf(stderr, "PacketAlias/GetSocket(): "); - fprintf(stderr, "incorrect link type\n"); - return(0); - } - - if (sock < 0) - { - fprintf(stderr, "PacketAlias/GetSocket(): "); - fprintf(stderr, "socket() error %d\n", *sockfd); - return(0); - } - - sock_addr.sin_family = AF_INET; - sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); - sock_addr.sin_port = port_net; - - err = bind(sock, - (struct sockaddr *) &sock_addr, - sizeof(sock_addr)); - if (err == 0) - { - sockCount++; - *sockfd = sock; - return(1); - } - else - { - close(sock); - return(0); - } -} - - -static void -CleanupAliasData(void) -{ - struct alias_link *link; - int i, icount; - - icount = 0; - for (i=0; i<LINK_TABLE_OUT_SIZE; i++) - { - link = linkTableOut[i]; - while (link != NULL) - { - struct alias_link *link_next; - link_next = link->next_out; - icount++; - DeleteLink(link); - link = link_next; - } - } - - cleanupIndex =0; -} - - -static void -IncrementalCleanup(void) -{ - int icount; - struct alias_link *link; - - icount = 0; - link = linkTableOut[cleanupIndex++]; - while (link != NULL) - { - int idelta; - struct alias_link *link_next; - - link_next = link->next_out; - idelta = timeStamp - link->timestamp; - switch (link->link_type) - { - case LINK_ICMP: - case LINK_UDP: - case LINK_FRAGMENT_ID: - case LINK_FRAGMENT_PTR: - if (idelta > link->expire_time) - { - DeleteLink(link); - icount++; - } - break; - case LINK_TCP: - if (idelta > link->expire_time) - { - struct tcp_dat *tcp_aux; - - tcp_aux = link->data.tcp; - if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED - || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) - { - DeleteLink(link); - icount++; - } - } - break; - } - link = link_next; - } - - if (cleanupIndex == LINK_TABLE_OUT_SIZE) - cleanupIndex = 0; -} - -void -DeleteLink(struct alias_link *link) -{ - struct alias_link *link_last; - struct alias_link *link_next; - -/* Don't do anything if the link is marked permanent */ - if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) - return; - -#ifndef NO_FW_PUNCH -/* Delete associatied firewall hole, if any */ - ClearFWHole(link); -#endif - -/* Adjust output table pointers */ - link_last = link->last_out; - link_next = link->next_out; - - if (link_last != NULL) - link_last->next_out = link_next; - else - linkTableOut[link->start_point_out] = link_next; - - if (link_next != NULL) - link_next->last_out = link_last; - -/* Adjust input table pointers */ - link_last = link->last_in; - link_next = link->next_in; - - if (link_last != NULL) - link_last->next_in = link_next; - else - linkTableIn[link->start_point_in] = link_next; - - if (link_next != NULL) - link_next->last_in = link_last; - -/* Close socket, if one has been allocated */ - if (link->sockfd != -1) - { - sockCount--; - close(link->sockfd); - } - -/* Link-type dependent cleanup */ - switch(link->link_type) - { - case LINK_ICMP: - icmpLinkCount--; - break; - case LINK_UDP: - udpLinkCount--; - break; - case LINK_TCP: - tcpLinkCount--; - if (link->data.tcp != NULL) - free(link->data.tcp); - break; - case LINK_FRAGMENT_ID: - fragmentIdLinkCount--; - break; - case LINK_FRAGMENT_PTR: - fragmentPtrLinkCount--; - if (link->data.frag_ptr != NULL) - free(link->data.frag_ptr); - break; - } - -/* Free memory */ - free(link); - -/* Write statistics, if logging enabled */ - if (packetAliasMode & PKT_ALIAS_LOG) - { - ShowAliasStats(); - } -} - - -static struct alias_link * -AddLink(struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_short src_port, - u_short dst_port, - int alias_port_param, /* if less than zero, alias */ - int link_type) /* port will be automatically */ -{ /* chosen. If greater than */ - u_int start_point; /* zero, equal to alias port */ - struct alias_link *link; - struct alias_link *first_link; - - link = malloc(sizeof(struct alias_link)); - if (link != NULL) - { - /* If either the aliasing address or source address are - equal to the default device address (equal to the - global variable aliasAddress), then set the alias - address field of the link record to zero */ - - if (src_addr.s_addr == aliasAddress.s_addr) - src_addr.s_addr = 0; - - if (alias_addr.s_addr == aliasAddress.s_addr) - alias_addr.s_addr = 0; - - /* Basic initialization */ - link->src_addr = src_addr; - link->dst_addr = dst_addr; - link->src_port = src_port; - link->alias_addr = alias_addr; - link->dst_port = dst_port; - link->link_type = link_type; - link->sockfd = -1; - link->flags = 0; - link->timestamp = timeStamp; - - /* Expiration time */ - switch (link_type) - { - case LINK_ICMP: - link->expire_time = ICMP_EXPIRE_TIME; - break; - case LINK_UDP: - link->expire_time = UDP_EXPIRE_TIME; - break; - case LINK_TCP: - link->expire_time = TCP_EXPIRE_INITIAL; - break; - case LINK_FRAGMENT_ID: - link->expire_time = FRAGMENT_ID_EXPIRE_TIME; - break; - case LINK_FRAGMENT_PTR: - link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; - break; - } - - /* Determine alias flags */ - if (dst_addr.s_addr == 0) - link->flags |= LINK_UNKNOWN_DEST_ADDR; - if (dst_port == 0) - link->flags |= LINK_UNKNOWN_DEST_PORT; - - /* Determine alias port */ - if (GetNewPort(link, alias_port_param) != 0) - { - free(link); - return(NULL); - } - - /* Set up pointers for output lookup table */ - start_point = StartPointOut(src_addr, dst_addr, - src_port, dst_port, link_type); - first_link = linkTableOut[start_point]; - - link->last_out = NULL; - link->next_out = first_link; - link->start_point_out = start_point; - - if (first_link != NULL) - first_link->last_out = link; - - linkTableOut[start_point] = link; - - /* Set up pointers for input lookup table */ - start_point = StartPointIn(alias_addr, link->alias_port, link_type); - first_link = linkTableIn[start_point]; - - link->last_in = NULL; - link->next_in = first_link; - link->start_point_in = start_point; - - if (first_link != NULL) - first_link->last_in = link; - - linkTableIn[start_point] = link; - - /* Link-type dependent initialization */ - switch(link_type) - { - struct tcp_dat *aux_tcp; - - case LINK_ICMP: - icmpLinkCount++; - break; - case LINK_UDP: - udpLinkCount++; - break; - case LINK_TCP: - aux_tcp = malloc(sizeof(struct tcp_dat)); - link->data.tcp = aux_tcp; - if (aux_tcp != NULL) - { - int i; - - tcpLinkCount++; - aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; - aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; - aux_tcp->state.index = 0; - aux_tcp->state.ack_modified = 0; - for (i=0; i<N_LINK_TCP_DATA; i++) - aux_tcp->ack[i].active = 0; - aux_tcp->fwhole = -1; - } - else - { - fprintf(stderr, "PacketAlias/AddLink: "); - fprintf(stderr, " cannot allocate auxiliary TCP data\n"); - } - break; - case LINK_FRAGMENT_ID: - fragmentIdLinkCount++; - break; - case LINK_FRAGMENT_PTR: - fragmentPtrLinkCount++; - break; - } - } - else - { - fprintf(stderr, "PacketAlias/AddLink(): "); - fprintf(stderr, "malloc() call failed.\n"); - } - - if (packetAliasMode & PKT_ALIAS_LOG) - { - ShowAliasStats(); - } - - return(link); -} - -static struct alias_link * -ReLink(struct alias_link *old_link, - struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_short src_port, - u_short dst_port, - int alias_port_param, /* if less than zero, alias */ - int link_type) /* port will be automatically */ -{ /* chosen. If greater than */ - struct alias_link *new_link; /* zero, equal to alias port */ - - new_link = AddLink(src_addr, dst_addr, alias_addr, - src_port, dst_port, alias_port_param, - link_type); -#ifndef NO_FW_PUNCH - if (new_link != NULL && - old_link->link_type == LINK_TCP && - old_link->data.tcp && - old_link->data.tcp->fwhole > 0) { - PunchFWHole(new_link); - } -#endif - DeleteLink(old_link); - return new_link; -} - -static struct alias_link * -FindLinkOut(struct in_addr src_addr, - struct in_addr dst_addr, - u_short src_port, - u_short dst_port, - int link_type) -{ - u_int i; - struct alias_link *link; - - if (src_addr.s_addr == aliasAddress.s_addr) - src_addr.s_addr = 0; - - i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); - link = linkTableOut[i]; - while (link != NULL) - { - if (link->src_addr.s_addr == src_addr.s_addr - && link->dst_addr.s_addr == dst_addr.s_addr - && link->dst_port == dst_port - && link->src_port == src_port - && link->link_type == link_type) - { - link->timestamp = timeStamp; - break; - } - link = link->next_out; - } - - return(link); -} - - -struct alias_link * -FindLinkIn(struct in_addr dst_addr, - struct in_addr alias_addr, - u_short dst_port, - u_short alias_port, - int link_type, - int replace_partial_links) -{ - int flags_in; - u_int start_point; - struct alias_link *link; - struct alias_link *link_fully_specified; - struct alias_link *link_unknown_all; - struct alias_link *link_unknown_dst_addr; - struct alias_link *link_unknown_dst_port; - -/* Initialize pointers */ - link_fully_specified = NULL; - link_unknown_all = NULL; - link_unknown_dst_addr = NULL; - link_unknown_dst_port = NULL; - -/* If either the dest addr or port is unknown, the search - loop will have to know about this. */ - - flags_in = 0; - if (dst_addr.s_addr == 0) - flags_in |= LINK_UNKNOWN_DEST_ADDR; - if (dst_port == 0) - flags_in |= LINK_UNKNOWN_DEST_PORT; - -/* The following allows permanent links to be - be specified as using the default aliasing address - (i.e. device interface address) without knowing - in advance what that address is. */ - - if (alias_addr.s_addr == aliasAddress.s_addr) - alias_addr.s_addr = 0; - -/* Search loop */ - start_point = StartPointIn(alias_addr, alias_port, link_type); - link = linkTableIn[start_point]; - while (link != NULL) - { - int flags; - - flags = flags_in | link->flags; - if (!(flags & LINK_PARTIALLY_SPECIFIED)) - { - if (link->alias_addr.s_addr == alias_addr.s_addr - && link->alias_port == alias_port - && link->dst_addr.s_addr == dst_addr.s_addr - && link->dst_port == dst_port - && link->link_type == link_type) - { - link_fully_specified = link; - break; - } - } - else if ((flags & LINK_UNKNOWN_DEST_ADDR) - && (flags & LINK_UNKNOWN_DEST_PORT)) - { - if (link->alias_addr.s_addr == alias_addr.s_addr - && link->alias_port == alias_port - && link->link_type == link_type) - { - if (link_unknown_all == NULL) - link_unknown_all = link; - } - } - else if (flags & LINK_UNKNOWN_DEST_ADDR) - { - if (link->alias_addr.s_addr == alias_addr.s_addr - && link->alias_port == alias_port - && link->link_type == link_type - && link->dst_port == dst_port) - { - if (link_unknown_dst_addr == NULL) - link_unknown_dst_addr = link; - } - } - else if (flags & LINK_UNKNOWN_DEST_PORT) - { - if (link->alias_addr.s_addr == alias_addr.s_addr - && link->alias_port == alias_port - && link->link_type == link_type - && link->dst_addr.s_addr == dst_addr.s_addr) - { - if (link_unknown_dst_port == NULL) - link_unknown_dst_port = link; - } - } - link = link->next_in; - } - - - - if (link_fully_specified != NULL) - { - return link_fully_specified; - } - else if (link_unknown_dst_port != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_port, - link_unknown_dst_port->src_addr, dst_addr, alias_addr, - link_unknown_dst_port->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_port; - } - else if (link_unknown_dst_addr != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_addr, - link_unknown_dst_addr->src_addr, dst_addr, alias_addr, - link_unknown_dst_addr->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_addr; - } - else if (link_unknown_all != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_all, - link_unknown_all->src_addr, dst_addr, alias_addr, - link_unknown_all->src_port, dst_port, alias_port, - link_type) - : link_unknown_all; - } - else - { - return(NULL); - } -} - - - - -/* External routines for finding/adding links - --- "external" means outside alias_db.c, but within alias*.c -- - - FindIcmpIn(), FindIcmpOut() - FindFragmentIn1(), FindFragmentIn2() - AddFragmentPtrLink(), FindFragmentPtr() - FindUdpTcpIn(), FindUdpTcpOut() - FindOriginalAddress(), FindAliasAddress() - -(prototypes in alias_local.h) -*/ - - -struct alias_link * -FindIcmpIn(struct in_addr dst_addr, - struct in_addr alias_addr, - u_short id_alias) -{ - return FindLinkIn(dst_addr, alias_addr, - NO_DEST_PORT, id_alias, - LINK_ICMP, 0); -} - - -struct alias_link * -FindIcmpOut(struct in_addr src_addr, - struct in_addr dst_addr, - u_short id) -{ - struct alias_link * link; - - link = FindLinkOut(src_addr, dst_addr, - id, NO_DEST_PORT, - LINK_ICMP); - if (link == NULL) - { - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(src_addr); - link = AddLink(src_addr, dst_addr, alias_addr, - id, NO_DEST_PORT, GET_ALIAS_ID, - LINK_ICMP); - } - - return(link); -} - - -struct alias_link * -FindFragmentIn1(struct in_addr dst_addr, - struct in_addr alias_addr, - u_short ip_id) -{ - struct alias_link *link; - - link = FindLinkIn(dst_addr, alias_addr, - NO_DEST_PORT, ip_id, - LINK_FRAGMENT_ID, 0); - - if (link == NULL) - { - link = AddLink(nullAddress, dst_addr, alias_addr, - NO_SRC_PORT, NO_DEST_PORT, ip_id, - LINK_FRAGMENT_ID); - } - - return(link); -} - - -struct alias_link * -FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ - struct in_addr alias_addr, /* is not found. */ - u_short ip_id) -{ - return FindLinkIn(dst_addr, alias_addr, - NO_DEST_PORT, ip_id, - LINK_FRAGMENT_ID, 0); -} - - -struct alias_link * -AddFragmentPtrLink(struct in_addr dst_addr, - u_short ip_id) -{ - return AddLink(nullAddress, dst_addr, nullAddress, - NO_SRC_PORT, NO_DEST_PORT, ip_id, - LINK_FRAGMENT_PTR); -} - - -struct alias_link * -FindFragmentPtr(struct in_addr dst_addr, - u_short ip_id) -{ - return FindLinkIn(dst_addr, nullAddress, - NO_DEST_PORT, ip_id, - LINK_FRAGMENT_PTR, 0); -} - - -struct alias_link * -FindUdpTcpIn(struct in_addr dst_addr, - struct in_addr alias_addr, - u_short dst_port, - u_short alias_port, - u_char proto) -{ - int link_type; - struct alias_link *link; - - switch (proto) - { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: - return NULL; - break; - } - - link = FindLinkIn(dst_addr, alias_addr, - dst_port, alias_port, - link_type, 1); - - if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL) - { - struct in_addr target_addr; - - target_addr = FindOriginalAddress(alias_addr); - link = AddLink(target_addr, dst_addr, alias_addr, - alias_port, dst_port, alias_port, - link_type); - } - - return(link); -} - - -struct alias_link * -FindUdpTcpOut(struct in_addr src_addr, - struct in_addr dst_addr, - u_short src_port, - u_short dst_port, - u_char proto) -{ - int link_type; - struct alias_link *link; - - switch (proto) - { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: - return NULL; - break; - } - - link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); - - if (link == NULL) - { - struct in_addr alias_addr; - - alias_addr = FindAliasAddress(src_addr); - link = AddLink(src_addr, dst_addr, alias_addr, - src_port, dst_port, GET_ALIAS_PORT, - link_type); - } - - return(link); -} - - -struct in_addr -FindOriginalAddress(struct in_addr alias_addr) -{ - struct alias_link *link; - - link = FindLinkIn(nullAddress, alias_addr, - 0, 0, LINK_ADDR, 0); - if (link == NULL) - { - newDefaultLink = 1; - if (targetAddress.s_addr != 0) - return targetAddress; - else - return alias_addr; - } - else - { - if (link->src_addr.s_addr == 0) - return aliasAddress; - else - return link->src_addr; - } -} - - -struct in_addr -FindAliasAddress(struct in_addr original_addr) -{ - struct alias_link *link; - - link = FindLinkOut(original_addr, nullAddress, - 0, 0, LINK_ADDR); - if (link == NULL) - { - return aliasAddress; - } - else - { - if (link->alias_addr.s_addr == 0) - return aliasAddress; - else - return link->alias_addr; - } -} - - -/* External routines for getting or changing link data - (external to alias_db.c, but internal to alias*.c) - - SetFragmentData(), GetFragmentData() - SetFragmentPtr(), GetFragmentPtr() - SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() - GetOriginalAddress(), GetDestAddress(), GetAliasAddress() - GetOriginalPort(), GetAliasPort() - SetAckModified(), GetAckModified() - GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() -*/ - - -void -SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) -{ - link->data.frag_addr = src_addr; -} - - -void -GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) -{ - *src_addr = link->data.frag_addr; -} - - -void -SetFragmentPtr(struct alias_link *link, char *fptr) -{ - link->data.frag_ptr = fptr; -} - - -void -GetFragmentPtr(struct alias_link *link, char **fptr) -{ - *fptr = link->data.frag_ptr; -} - - -void -SetStateIn(struct alias_link *link, int state) -{ - /* TCP input state */ - switch (state) { - case ALIAS_TCP_STATE_DISCONNECTED: - if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { - link->expire_time = TCP_EXPIRE_DEAD; - } else { - link->expire_time = TCP_EXPIRE_SINGLEDEAD; - } - link->data.tcp->state.in = state; - break; - case ALIAS_TCP_STATE_CONNECTED: - link->expire_time = TCP_EXPIRE_CONNECTED; - /*FALLTHROUGH*/ - case ALIAS_TCP_STATE_NOT_CONNECTED: - link->data.tcp->state.in = state; - break; - default: - abort(); - } -} - - -void -SetStateOut(struct alias_link *link, int state) -{ - /* TCP output state */ - switch (state) { - case ALIAS_TCP_STATE_DISCONNECTED: - if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { - link->expire_time = TCP_EXPIRE_DEAD; - } else { - link->expire_time = TCP_EXPIRE_SINGLEDEAD; - } - link->data.tcp->state.out = state; - break; - case ALIAS_TCP_STATE_CONNECTED: - link->expire_time = TCP_EXPIRE_CONNECTED; - /*FALLTHROUGH*/ - case ALIAS_TCP_STATE_NOT_CONNECTED: - link->data.tcp->state.out = state; - break; - default: - abort(); - } -} - - -int -GetStateIn(struct alias_link *link) -{ - /* TCP input state */ - return link->data.tcp->state.in; -} - - -int -GetStateOut(struct alias_link *link) -{ - /* TCP output state */ - return link->data.tcp->state.out; -} - - -struct in_addr -GetOriginalAddress(struct alias_link *link) -{ - if (link->src_addr.s_addr == 0) - return aliasAddress; - else - return(link->src_addr); -} - - -struct in_addr -GetDestAddress(struct alias_link *link) -{ - return(link->dst_addr); -} - - -struct in_addr -GetAliasAddress(struct alias_link *link) -{ - if (link->alias_addr.s_addr == 0) - return aliasAddress; - else - return link->alias_addr; -} - - -struct in_addr -GetDefaultAliasAddress() -{ - return aliasAddress; -} - - -void -SetDefaultAliasAddress(struct in_addr alias_addr) -{ - aliasAddress = alias_addr; -} - - -u_short -GetOriginalPort(struct alias_link *link) -{ - return(link->src_port); -} - - -u_short -GetAliasPort(struct alias_link *link) -{ - return(link->alias_port); -} - -u_short -GetDestPort(struct alias_link *link) -{ - return(link->dst_port); -} - -void -SetAckModified(struct alias_link *link) -{ -/* Indicate that ack numbers have been modified in a TCP connection */ - link->data.tcp->state.ack_modified = 1; -} - - -int -GetAckModified(struct alias_link *link) -{ -/* See if ack numbers have been modified */ - return link->data.tcp->state.ack_modified; -} - - -int -GetDeltaAckIn(struct ip *pip, struct alias_link *link) -{ -/* -Find out how much the ack number has been altered for an incoming -TCP packet. To do this, a circular list is ack numbers where the TCP -packet size was altered is searched. -*/ - - int i; - struct tcphdr *tc; - int delta, ack_diff_min; - u_long ack; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - ack = tc->th_ack; - - delta = 0; - ack_diff_min = -1; - for (i=0; i<N_LINK_TCP_DATA; i++) - { - struct ack_data_record x; - - x = link->data.tcp->ack[i]; - if (x.active == 1) - { - int ack_diff; - - ack_diff = SeqDiff(x.ack_new, ack); - if (ack_diff >= 0) - { - if (ack_diff_min >= 0) - { - if (ack_diff < ack_diff_min) - { - delta = x.delta; - ack_diff_min = ack_diff; - } - } - else - { - delta = x.delta; - ack_diff_min = ack_diff; - } - } - } - } - return (delta); -} - - -int -GetDeltaSeqOut(struct ip *pip, struct alias_link *link) -{ -/* -Find out how much the seq number has been altered for an outgoing -TCP packet. To do this, a circular list is ack numbers where the TCP -packet size was altered is searched. -*/ - - int i; - struct tcphdr *tc; - int delta, seq_diff_min; - u_long seq; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - seq = tc->th_seq; - - delta = 0; - seq_diff_min = -1; - for (i=0; i<N_LINK_TCP_DATA; i++) - { - struct ack_data_record x; - - x = link->data.tcp->ack[i]; - if (x.active == 1) - { - int seq_diff; - - seq_diff = SeqDiff(x.ack_old, seq); - if (seq_diff >= 0) - { - if (seq_diff_min >= 0) - { - if (seq_diff < seq_diff_min) - { - delta = x.delta; - seq_diff_min = seq_diff; - } - } - else - { - delta = x.delta; - seq_diff_min = seq_diff; - } - } - } - } - return (delta); -} - - -void -AddSeq(struct ip *pip, struct alias_link *link, int delta) -{ -/* -When a TCP packet has been altered in length, save this -information in a circular list. If enough packets have -been altered, then this list will begin to overwrite itself. -*/ - - struct tcphdr *tc; - struct ack_data_record x; - int hlen, tlen, dlen; - int i; - - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; - - x.ack_old = htonl(ntohl(tc->th_seq) + dlen); - x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); - x.delta = delta; - x.active = 1; - - i = link->data.tcp->state.index; - link->data.tcp->ack[i] = x; - - i++; - if (i == N_LINK_TCP_DATA) - link->data.tcp->state.index = 0; - else - link->data.tcp->state.index = i; -} - -void -SetExpire(struct alias_link *link, int expire) -{ - if (expire == 0) - { - link->flags &= ~LINK_PERMANENT; - DeleteLink(link); - } - else if (expire == -1) - { - link->flags |= LINK_PERMANENT; - } - else if (expire > 0) - { - link->expire_time = expire; - } - else - { - fprintf(stderr, "PacketAlias/SetExpire(): "); - fprintf(stderr, "error in expire parameter\n"); - } -} - -void -ClearCheckNewLink(void) -{ - newDefaultLink = 0; -} - - -/* Miscellaneous Functions - - HouseKeeping() - InitPacketAliasLog() - UninitPacketAliasLog() -*/ - -/* - Whenever an outgoing or incoming packet is handled, HouseKeeping() - is called to find and remove timed-out aliasing links. Logic exists - to sweep through the entire table and linked list structure - every 60 seconds. - - (prototype in alias_local.h) -*/ - -void -HouseKeeping(void) -{ - int i, n, n100; - struct timeval tv; - struct timezone tz; - - /* - * Save system time (seconds) in global variable timeStamp for - * use by other functions. This is done so as not to unnecessarily - * waste timeline by making system calls. - */ - gettimeofday(&tv, &tz); - timeStamp = tv.tv_sec; - - /* Compute number of spokes (output table link chains) to cover */ - n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; - n100 *= timeStamp - lastCleanupTime; - n100 /= ALIAS_CLEANUP_INTERVAL_SECS; - - n = n100/100; - - /* Handle different cases */ - if (n > ALIAS_CLEANUP_MAX_SPOKES) - { - n = ALIAS_CLEANUP_MAX_SPOKES; - lastCleanupTime = timeStamp; - houseKeepingResidual = 0; - - for (i=0; i<n; i++) - IncrementalCleanup(); - } - else if (n > 0) - { - lastCleanupTime = timeStamp; - houseKeepingResidual = n100 - 100*n; - - for (i=0; i<n; i++) - IncrementalCleanup(); - } - else if (n < 0) - { - fprintf(stderr, "PacketAlias/HouseKeeping(): "); - fprintf(stderr, "something unexpected in time values\n"); - lastCleanupTime = timeStamp; - houseKeepingResidual = 0; - } -} - - -/* Init the log file and enable logging */ -static void -InitPacketAliasLog(void) -{ - if ((~packetAliasMode & PKT_ALIAS_LOG) - && (monitorFile = fopen("/var/log/alias.log", "w"))) - { - packetAliasMode |= PKT_ALIAS_LOG; - fprintf(monitorFile, - "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); - } -} - - -/* Close the log-file and disable logging. */ -static void -UninitPacketAliasLog(void) -{ - if (monitorFile) { - fclose(monitorFile); - monitorFile = NULL; - } - packetAliasMode &= ~PKT_ALIAS_LOG; -} - - - - - - -/* Outside world interfaces - --- "outside world" means other than alias*.c routines -- - - PacketAliasRedirectPort() - PacketAliasRedirectAddr() - PacketAliasRedirectDelete() - PacketAliasSetAddress() - PacketAliasInit() - PacketAliasUninit() - PacketAliasSetMode() - -(prototypes in alias.h) -*/ - -/* Redirection from a specific public addr:port to a - a private addr:port */ -struct alias_link * -PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, - struct in_addr dst_addr, u_short dst_port, - struct in_addr alias_addr, u_short alias_port, - u_char proto) -{ - int link_type; - struct alias_link *link; - - switch(proto) - { - case IPPROTO_UDP: - link_type = LINK_UDP; - break; - case IPPROTO_TCP: - link_type = LINK_TCP; - break; - default: - fprintf(stderr, "PacketAliasRedirectPort(): "); - fprintf(stderr, "only TCP and UDP protocols allowed\n"); - return NULL; - } - - link = AddLink(src_addr, dst_addr, alias_addr, - src_port, dst_port, alias_port, - link_type); - - if (link != NULL) - { - link->flags |= LINK_PERMANENT; - } - else - { - fprintf(stderr, "PacketAliasRedirectPort(): " - "call to AddLink() failed\n"); - } - - return link; -} - - -/* Static address translation */ -struct alias_link * -PacketAliasRedirectAddr(struct in_addr src_addr, - struct in_addr alias_addr) -{ - struct alias_link *link; - - link = AddLink(src_addr, nullAddress, alias_addr, - 0, 0, 0, - LINK_ADDR); - - if (link != NULL) - { - link->flags |= LINK_PERMANENT; - } - else - { - fprintf(stderr, "PacketAliasRedirectAddr(): " - "call to AddLink() failed\n"); - } - - return link; -} - - -void -PacketAliasRedirectDelete(struct alias_link *link) -{ -/* This is a dangerous function to put in the API, - because an invalid pointer can crash the program. */ - - deleteAllLinks = 1; - DeleteLink(link); - deleteAllLinks = 0; -} - - -void -PacketAliasSetAddress(struct in_addr addr) -{ - if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE - && aliasAddress.s_addr != addr.s_addr) - CleanupAliasData(); - - aliasAddress = addr; -} - - -void -PacketAliasSetTarget(struct in_addr target_addr) -{ - targetAddress = target_addr; -} - - -void -PacketAliasInit(void) -{ - int i; - struct timeval tv; - struct timezone tz; - static int firstCall = 1; - - if (firstCall == 1) - { - gettimeofday(&tv, &tz); - timeStamp = tv.tv_sec; - lastCleanupTime = tv.tv_sec; - houseKeepingResidual = 0; - - for (i=0; i<LINK_TABLE_OUT_SIZE; i++) - linkTableOut[i] = NULL; - for (i=0; i<LINK_TABLE_IN_SIZE; i++) - linkTableIn[i] = NULL; - - atexit(PacketAliasUninit); - firstCall = 0; - } - else - { - deleteAllLinks = 1; - CleanupAliasData(); - deleteAllLinks = 0; - } - - aliasAddress.s_addr = 0; - targetAddress.s_addr = 0; - - icmpLinkCount = 0; - udpLinkCount = 0; - tcpLinkCount = 0; - fragmentIdLinkCount = 0; - fragmentPtrLinkCount = 0; - sockCount = 0; - - cleanupIndex =0; - - packetAliasMode = PKT_ALIAS_SAME_PORTS - | PKT_ALIAS_USE_SOCKETS - | PKT_ALIAS_RESET_ON_ADDR_CHANGE; -} - -void -PacketAliasUninit(void) { - deleteAllLinks = 1; - CleanupAliasData(); - deleteAllLinks = 0; - UninitPacketAliasLog(); -#ifndef NO_FW_PUNCH - UninitPunchFW(); -#endif -} - - -/* Change mode for some operations */ -unsigned int -PacketAliasSetMode( - unsigned int flags, /* Which state to bring flags to */ - unsigned int mask /* Mask of which flags to affect (use 0 to do a - probe for flag values) */ -) -{ -/* Enable logging? */ - if (flags & mask & PKT_ALIAS_LOG) - { - InitPacketAliasLog(); /* Do the enable */ - } else -/* _Disable_ logging? */ - if (~flags & mask & PKT_ALIAS_LOG) { - UninitPacketAliasLog(); - } - -#ifndef NO_FW_PUNCH -/* Start punching holes in the firewall? */ - if (flags & mask & PKT_ALIAS_PUNCH_FW) { - InitPunchFW(); - } else -/* Stop punching holes in the firewall? */ - if (~flags & mask & PKT_ALIAS_PUNCH_FW) { - UninitPunchFW(); - } -#endif - -/* Other flags can be set/cleared without special action */ - packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); - return packetAliasMode; -} - - -int -PacketAliasCheckNewLink(void) -{ - return newDefaultLink; -} - - -#ifndef NO_FW_PUNCH - -/***************** - Code to support firewall punching. This shouldn't really be in this - file, but making variables global is evil too. - ****************/ - -/* Firewall include files */ -#include <sys/queue.h> -#include <net/if.h> -#include <netinet/ip_fw.h> -#include <string.h> -#include <err.h> - -static void ClearAllFWHoles(void); - -static int fireWallBaseNum; /* The first firewall entry free for our use */ -static int fireWallNumNums; /* How many entries can we use? */ -static int fireWallActiveNum; /* Which entry did we last use? */ -static char *fireWallField; /* bool array for entries */ - -#define fw_setfield(field, num) \ -do { \ - (field)[num] = 1; \ -} /*lint -save -e717 */ while(0) /*lint -restore */ -#define fw_clrfield(field, num) \ -do { \ - (field)[num] = 0; \ -} /*lint -save -e717 */ while(0) /*lint -restore */ -#define fw_tstfield(field, num) ((field)[num]) - -void -PacketAliasSetFWBase(unsigned int base, unsigned int num) { - fireWallBaseNum = base; - fireWallNumNums = num; -} - -static void -InitPunchFW(void) { - fireWallField = malloc(fireWallNumNums); - if (fireWallField) { - memset(fireWallField, 0, fireWallNumNums); - if (fireWallFD < 0) { - fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - } - ClearAllFWHoles(); - fireWallActiveNum = fireWallBaseNum; - } -} - -static void -UninitPunchFW(void) { - ClearAllFWHoles(); - if (fireWallFD >= 0) - close(fireWallFD); - fireWallFD = -1; - if (fireWallField) - free(fireWallField); - fireWallField = NULL; - packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; -} - -/* Make a certain link go through the firewall */ -void -PunchFWHole(struct alias_link *link) { - int r; /* Result code */ - struct ip_fw rule; /* On-the-fly built rule */ - int fwhole; /* Where to punch hole */ - -/* Don't do anything unless we are asked to */ - if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || - fireWallFD < 0 || - link->link_type != LINK_TCP || - !link->data.tcp) - return; - - memset(&rule, 0, sizeof rule); - -/** Build rule **/ - - /* Find empty slot */ - for (fwhole = fireWallActiveNum; - fwhole < fireWallBaseNum + fireWallNumNums && - fw_tstfield(fireWallField, fwhole); - fwhole++) - ; - if (fwhole >= fireWallBaseNum + fireWallNumNums || - fw_tstfield(fireWallField, fwhole)) { - for (fwhole = fireWallBaseNum; - fwhole < fireWallActiveNum && - fw_tstfield(fireWallField, fwhole); - fwhole++) - ; - if (fwhole == fireWallActiveNum) { - /* No rule point empty - we can't punch more holes. */ - fireWallActiveNum = fireWallBaseNum; - fprintf(stderr, "libalias: Unable to create firewall hole!\n"); - return; - } - } - /* Start next search at next position */ - fireWallActiveNum = fwhole+1; - - /* Build generic part of the two rules */ - rule.fw_number = fwhole; - rule.fw_nports = 1; /* Number of source ports; dest ports follow */ - rule.fw_flg = IP_FW_F_ACCEPT; - rule.fw_prot = IPPROTO_TCP; - rule.fw_smsk.s_addr = INADDR_BROADCAST; - rule.fw_dmsk.s_addr = INADDR_BROADCAST; - - /* Build and apply specific part of the rules */ - rule.fw_src = GetOriginalAddress(link); - rule.fw_dst = GetDestAddress(link); - rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); - rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); - - /* Skip non-bound links - XXX should not be strictly necessary, - but seems to leave hole if not done. Leak of non-bound links? - (Code should be left even if the problem is fixed - it is a - clear optimization) */ - if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { - r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); - if (r) - err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); - rule.fw_src = GetDestAddress(link); - rule.fw_dst = GetOriginalAddress(link); - rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); - rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); - r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); - if (r) - err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); - } -/* Indicate hole applied */ - link->data.tcp->fwhole = fwhole; - fw_setfield(fireWallField, fwhole); -} - -/* Remove a hole in a firewall associated with a particular alias - link. Calling this too often is harmless. */ -static void -ClearFWHole(struct alias_link *link) { - if (link->link_type == LINK_TCP && link->data.tcp) { - int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ - struct ip_fw rule; - - if (fwhole < 0) - return; - - memset(&rule, 0, sizeof rule); - rule.fw_number = fwhole; - while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) - ; - fw_clrfield(fireWallField, fwhole); - link->data.tcp->fwhole = -1; - } -} - -/* Clear out the entire range dedicated to firewall holes. */ -static void -ClearAllFWHoles(void) { - struct ip_fw rule; /* On-the-fly built rule */ - int i; - - if (fireWallFD < 0) - return; - - memset(&rule, 0, sizeof rule); - for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { - rule.fw_number = i; - while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) - ; - } - memset(fireWallField, 0, fireWallNumNums); -} -#endif diff --git a/sys/netinet/libalias/alias_ftp.c b/sys/netinet/libalias/alias_ftp.c deleted file mode 100644 index c6d449d05723..000000000000 --- a/sys/netinet/libalias/alias_ftp.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - Alias_ftp.c performs special processing for FTP sessions under - TCP. Specifically, when a PORT command from the client side - is sent, it is intercepted and modified. The address is changed - to the gateway machine and an aliasing port is used. - - For this routine to work, the PORT command must fit entirely - into a single TCP packet. This is typically the case, but exceptions - can easily be envisioned under the actual specifications. - - Probably the most troubling aspect of the approach taken here is - that the new PORT command will typically be a different length, and - this causes a certain amount of bookkeeping to keep track of the - changes of sequence and acknowledgment numbers, since the client - machine is totally unaware of the modification to the TCP stream. - - - This software is placed into the public domain with no restrictions - on its distribution. - - Initial version: August, 1996 (cjm) - - Version 1.6 - Brian Somers and Martin Renters identified an IP checksum - error for modified IP packets. - - Version 1.7: January 9, 1996 (cjm) - Differental checksum computation for change - in IP packet length. - - Version 2.1: May, 1997 (cjm) - Very minor changes to conform with - local/global/function naming conventions - withing the packet alising module. - - See HISTORY file for record of revisions. -*/ - -/* Includes */ -#include <ctype.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> - -#include "alias_local.h" - -static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int); - - - -void -AliasHandleFtpOut( -struct ip *pip, /* IP packet to examine/patch */ -struct alias_link *link, /* The link to go through (aliased port) */ -int maxpacketsize /* The maximum size this packet can grow to (including headers) */) -{ - int hlen, tlen, dlen; - struct in_addr true_addr; - u_short true_port; - char *sptr; - struct tcphdr *tc; - -/* Calculate data length of TCP packet */ - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; - -/* Return is data length is too long or too short */ - if (dlen<10 || dlen>80) - return; - -/* Place string pointer and beginning of data */ - sptr = (char *) pip; - sptr += hlen; - -/* Parse through string using state diagram method */ - { - char ch, zero; - int i, state; - u_long a1, a2, a3, a4; - u_short p1, p2; - - a1=0; a2=0; a3=0; a4=0; p1=0; p2=0; - zero = '0'; - state=-4; - for (i=0; i<dlen; i++) - { - ch = sptr[i]; - switch (state) - { - case -4: if (ch == 'P') state=-3; else return; break; - case -3: if (ch == 'O') state=-2; else return; break; - case -2: if (ch == 'R') state=-1; else return; break; - case -1: if (ch == 'T') state= 0; else return; break; - - case 0 : - if (isdigit(ch)) {a1=ch-zero; state=1 ;} break; - case 1 : - if (isdigit(ch)) a1=10*a1+ch-zero; else state=2 ; break; - case 2 : - if (isdigit(ch)) {a2=ch-zero; state=3 ;} break; - case 3 : - if (isdigit(ch)) a2=10*a2+ch-zero; else state=4 ; break; - case 4 : - if (isdigit(ch)) {a3=ch-zero; state=5 ;} break; - case 5 : - if (isdigit(ch)) a3=10*a3+ch-zero; else state=6 ; break; - case 6 : - if (isdigit(ch)) {a4=ch-zero; state=7 ;} break; - case 7 : - if (isdigit(ch)) a4=10*a4+ch-zero; else state=8 ; break; - case 8 : - if (isdigit(ch)) {p1=ch-zero; state=9 ;} break; - case 9 : - if (isdigit(ch)) p1=10*p1+ch-zero; else state=10; break; - case 10: - if (isdigit(ch)) {p2=ch-zero; state=11;} break; - case 11: - if (isdigit(ch)) p2=10*p2+ch-zero; break; - } - } - - if (state == 11) - { - true_port = htons((p1<<8) + p2); - true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4); - NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize); - } - } -} - -static void -NewFtpPortCommand(struct ip *pip, - struct alias_link *link, - struct in_addr true_addr, - u_short true_port, - int maxpacketsize) -{ - struct alias_link *ftp_link; - -/* Establish link to address and port found in PORT command */ - ftp_link = FindUdpTcpOut(true_addr, GetDestAddress(link), - true_port, 0, IPPROTO_TCP); - - if (ftp_link != NULL) - { - int slen, hlen, tlen, dlen; - struct tcphdr *tc; - -#ifndef NO_FW_PUNCH -/* Punch hole in firewall */ - PunchFWHole(ftp_link); -#endif - -/* Calculate data length of TCP packet */ - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; - -/* Create new PORT command */ - { - char stemp[80]; - char *sptr; - u_short alias_port; - u_char *ptr; - int a1, a2, a3, a4, p1, p2; - struct in_addr alias_address; - -/* Decompose alias address into quad format */ - alias_address = GetAliasAddress(link); - ptr = (u_char *) &alias_address.s_addr; - a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr; - -/* Decompose alias port into pair format */ - alias_port = GetAliasPort(ftp_link); - ptr = (char *) &alias_port; - p1 = *ptr++; p2=*ptr; - -/* Generate command string */ - sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", - a1,a2,a3,a4,p1,p2); - -/* Save string length for IP header modification */ - slen = strlen(stemp); - -/* Copy into IP packet */ - sptr = (char *) pip; sptr += hlen; - strncpy(sptr, stemp, maxpacketsize-hlen); - } - -/* Save information regarding modified seq and ack numbers */ - { - int delta; - - SetAckModified(link); - delta = GetDeltaSeqOut(pip, link); - AddSeq(pip, link, delta+slen-dlen); - } - -/* Revise IP header */ - { - u_short new_len; - - new_len = htons(hlen + slen); - DifferentialChecksum(&pip->ip_sum, - &new_len, - &pip->ip_len, - 1); - pip->ip_len = new_len; - } - -/* Compute TCP checksum for revised packet */ - tc->th_sum = 0; - tc->th_sum = TcpChecksum(pip); - } - else - { - fprintf(stderr, - "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n"); - } -} diff --git a/sys/netinet/libalias/alias_irc.c b/sys/netinet/libalias/alias_irc.c deleted file mode 100644 index 910e9343404a..000000000000 --- a/sys/netinet/libalias/alias_irc.c +++ /dev/null @@ -1,316 +0,0 @@ -/* Alias_irc.c intercepts packages contain IRC CTCP commands, and - changes DCC commands to export a port on the aliasing host instead - of an aliased host. - - For this routine to work, the DCC command must fit entirely into a - single TCP packet. This will usually happen, but is not - guaranteed. - - The interception is likely to change the length of the packet. - The handling of this is copied more-or-less verbatim from - ftp_alias.c - - This software is placed into the public domain with no restrictions - on its distribution. - - Initial version: Eivind Eklund <perhaps@yes.no> (ee) 97-01-29 - - Version 2.1: May, 1997 (cjm) - Very minor changes to conform with - local/global/function naming conventions - withing the packet alising module. -*/ - -/* Includes */ -#include <ctype.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <limits.h> - -#include "alias_local.h" - -/* Local defines */ -#define DBprintf(a) - - -void -AliasHandleIrcOut(struct ip *pip, /* IP packet to examine */ - struct alias_link *link, /* Which link are we on? */ - int maxsize /* Maximum size of IP packet including headers */ - ) -{ - int hlen, tlen, dlen; - struct in_addr true_addr; - u_short true_port; - char *sptr; - struct tcphdr *tc; - int i; /* Iterator through the source */ - -/* Calculate data length of TCP packet */ - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; - - /* Return if data length is too short - assume an entire PRIVMSG in each packet. */ - if (dlen<sizeof(":A!a@n.n PRIVMSG A :aDCC 1 1a")-1) - return; - -/* Place string pointer at beginning of data */ - sptr = (char *) pip; - sptr += hlen; - maxsize -= hlen; /* We're interested in maximum size of data, not packet */ - - /* Search for a CTCP command [Note 1] */ - for( i=0; i<dlen; i++ ) { - if(sptr[i]=='\001') - goto lFOUND_CTCP; - } - return; /* No CTCP commands in */ - /* Handle CTCP commands - the buffer may have to be copied */ -lFOUND_CTCP: - { - char newpacket[65536]; /* Estimate of maximum packet size :) */ - int copyat = i; /* Same */ - int iCopy = 0; /* How much data have we written to copy-back string? */ - unsigned long org_addr; /* Original IP address */ - unsigned short org_port; /* Original source port address */ - lCTCP_START: - if( i >= dlen || iCopy >= sizeof(newpacket) ) - goto lPACKET_DONE; - newpacket[iCopy++] = sptr[i++]; /* Copy the CTCP start character */ - /* Start of a CTCP */ - if( i+4 >= dlen ) /* Too short for DCC */ - goto lBAD_CTCP; - if( sptr[i+0] != 'D' ) - goto lBAD_CTCP; - if( sptr[i+1] != 'C' ) - goto lBAD_CTCP; - if( sptr[i+2] != 'C' ) - goto lBAD_CTCP; - if( sptr[i+3] != ' ' ) - goto lBAD_CTCP; - /* We have a DCC command - handle it! */ - i+= 4; /* Skip "DCC " */ - if( iCopy+4 > sizeof(newpacket) ) - goto lPACKET_DONE; - newpacket[iCopy++] = 'D'; - newpacket[iCopy++] = 'C'; - newpacket[iCopy++] = 'C'; - newpacket[iCopy++] = ' '; - - DBprintf(("Found DCC\n")); - /* Skip any extra spaces (should not occur according to - protocol, but DCC breaks CTCP protocol anyway */ - while(sptr[i] == ' ') { - if( ++i >= dlen) { - DBprintf(("DCC packet terminated in just spaces\n")); - goto lPACKET_DONE; - } - } - - DBprintf(("Transferring command...\n")); - while(sptr[i] != ' ') { - newpacket[iCopy++] = sptr[i]; - if( ++i >= dlen || iCopy >= sizeof(newpacket) ) { - DBprintf(("DCC packet terminated during command\n")); - goto lPACKET_DONE; - } - } - /* Copy _one_ space */ - if( i+1 < dlen && iCopy < sizeof(newpacket) ) - newpacket[iCopy++] = sptr[i++]; - - DBprintf(("Done command - removing spaces\n")); - /* Skip any extra spaces (should not occur according to - protocol, but DCC breaks CTCP protocol anyway */ - while(sptr[i] == ' ') { - if( ++i >= dlen ) { - DBprintf(("DCC packet terminated in just spaces (post-command)\n")); - goto lPACKET_DONE; - } - } - - DBprintf(("Transferring filename...\n")); - while(sptr[i] != ' ') { - newpacket[iCopy++] = sptr[i]; - if( ++i >= dlen || iCopy >= sizeof(newpacket) ) { - DBprintf(("DCC packet terminated during filename\n")); - goto lPACKET_DONE; - } - } - /* Copy _one_ space */ - if( i+1 < dlen && iCopy < sizeof(newpacket) ) - newpacket[iCopy++] = sptr[i++]; - - DBprintf(("Done filename - removing spaces\n")); - /* Skip any extra spaces (should not occur according to - protocol, but DCC breaks CTCP protocol anyway */ - while(sptr[i] == ' ') { - if( ++i >= dlen ) { - DBprintf(("DCC packet terminated in just spaces (post-filename)\n")); - goto lPACKET_DONE; - } - } - - DBprintf(("Fetching IP address\n")); - /* Fetch IP address */ - org_addr = 0; - while(i<dlen && isdigit(sptr[i])) { - if( org_addr > ULONG_MAX/10UL ) { /* Terminate on overflow */ - DBprintf(("DCC Address overflow (org_addr == 0x%08lx, next char %c\n", org_addr, sptr[i])); - goto lBAD_CTCP; - } - org_addr *= 10; - org_addr += sptr[i++]-'0'; - } - DBprintf(("Skipping space\n")); - if( i+1 >= dlen || sptr[i] != ' ' ) { - DBprintf(("Overflow (%d >= %d) or bad character (%02x) terminating IP address\n", i+1, dlen, sptr[i])); - goto lBAD_CTCP; - } - /* Skip any extra spaces (should not occur according to - protocol, but DCC breaks CTCP protocol anyway, so we might - as well play it safe */ - while(sptr[i] == ' ') { - if( ++i >= dlen ) { - DBprintf(("Packet failure - space overflow.\n")); - goto lPACKET_DONE; - } - } - DBprintf(("Fetching port number\n")); - /* Fetch source port */ - org_port = 0; - while(i<dlen && isdigit(sptr[i])) { - if( org_port > 6554 ) { /* Terminate on overflow (65536/10 rounded up*/ - DBprintf(("DCC: port number overflow\n")); - goto lBAD_CTCP; - } - org_port *= 10; - org_port += sptr[i++]-'0'; - } - /* Skip illegal addresses (or early termination) */ - if( i >= dlen || (sptr[i] != '\001' && sptr[i] != ' ') ) { - DBprintf(("Bad port termination\n")); - goto lBAD_CTCP; - } - DBprintf(("Got IP %lu and port %u\n", org_addr, (unsigned)org_port)); - - /* We've got the address and port - now alias it */ - { - struct alias_link *dcc_link; - struct in_addr destaddr; - - - true_port = htons(org_port); - true_addr.s_addr = htonl(org_addr); - destaddr.s_addr = 0; - - /* Steal the FTP_DATA_PORT - it doesn't really matter, and this - would probably allow it through at least _some_ - firewalls. */ - dcc_link = FindUdpTcpOut (true_addr, - destaddr, - true_port, - 0, IPPROTO_TCP); - DBprintf(("Got a DCC link\n")); - if ( dcc_link ) { - struct in_addr alias_address; /* Address from aliasing */ - u_short alias_port; /* Port given by aliasing */ - -#ifndef NO_FW_PUNCH - /* Generate firewall hole as appropriate */ - PunchFWHole(dcc_link); -#endif - - alias_address = GetAliasAddress(link); - iCopy += snprintf(&newpacket[iCopy], - sizeof(newpacket)-iCopy, - "%lu ", (u_long)htonl(alias_address.s_addr)); - if( iCopy >= sizeof(newpacket) ) { /* Truncated/fit exactly - bad news */ - DBprintf(("DCC constructed packet overflow.\n")); - goto lBAD_CTCP; - } - alias_port = GetAliasPort(dcc_link); - iCopy += snprintf(&newpacket[iCopy], - sizeof(newpacket)-iCopy, - "%u", htons(alias_port) ); - /* Done - truncated cases will be taken care of by lBAD_CTCP */ - DBprintf(("Aliased IP %lu and port %u\n", alias_address.s_addr, (unsigned)alias_port)); - } - } - /* An uninteresting CTCP - state entered right after '\001' has - been pushed. Also used to copy the rest of a DCC, after IP - address and port has been handled */ - lBAD_CTCP: - for(; i<dlen && iCopy<sizeof(newpacket); i++,iCopy++) { - newpacket[iCopy] = sptr[i]; /* Copy CTCP unchanged */ - if(sptr[i] == '\001') { - goto lNORMAL_TEXT; - } - } - goto lPACKET_DONE; - /* Normal text */ - lNORMAL_TEXT: - for(; i<dlen && iCopy<sizeof(newpacket); i++,iCopy++) { - newpacket[iCopy] = sptr[i]; /* Copy CTCP unchanged */ - if(sptr[i] == '\001') { - goto lCTCP_START; - } - } - /* Handle the end of a packet */ - lPACKET_DONE: - iCopy = iCopy > maxsize-copyat ? maxsize-copyat : iCopy; - memcpy(sptr+copyat, newpacket, iCopy); - -/* Save information regarding modified seq and ack numbers */ - { - int delta; - - SetAckModified(link); - delta = GetDeltaSeqOut(pip, link); - AddSeq(pip, link, delta+copyat+iCopy-dlen); - } - - /* Revise IP header */ - { - u_short new_len; - - new_len = htons(hlen + iCopy + copyat); - DifferentialChecksum(&pip->ip_sum, - &new_len, - &pip->ip_len, - 1); - pip->ip_len = new_len; - } - - /* Compute TCP checksum for revised packet */ - tc->th_sum = 0; - tc->th_sum = TcpChecksum(pip); - return; - } -} - -/* Notes: - [Note 1] - The initial search will most often fail; it could be replaced with a 32-bit specific search. - Such a search would be done for 32-bit unsigned value V: - V ^= 0x01010101; (Search is for null bytes) - if( ((V-0x01010101)^V) & 0x80808080 ) { - (found a null bytes which was a 01 byte) - } - To assert that the processor is 32-bits, do - extern int ircdccar[32]; (32 bits) - extern int ircdccar[CHAR_BIT*sizeof(unsigned int)]; - which will generate a type-error on all but 32-bit machines. - - [Note 2] This routine really ought to be replaced with one that - creates a transparent proxy on the aliasing host, to allow arbitary - changes in the TCP stream. This should not be too difficult given - this base; I (ee) will try to do this some time later. - */ diff --git a/sys/netinet/libalias/alias_local.h b/sys/netinet/libalias/alias_local.h deleted file mode 100644 index 38462810733a..000000000000 --- a/sys/netinet/libalias/alias_local.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- mode: c; tab-width: 3; c-basic-offset: 3; -*- - Alias_local.h contains the function prototypes for alias.c, - alias_db.c, alias_util.c and alias_ftp.c, alias_irc.c (as well - as any future add-ons). It is intended to be used only within - the aliasing software. Outside world interfaces are defined - in alias.h - - This software is placed into the public domain with no restrictions - on its distribution. - - Initial version: August, 1996 (cjm) - - <updated several times by original author and Eivind Eiklund> -*/ -#ifndef ALIAS_LOCAL_H -#define ALIAS_LOCAL_H - -extern int packetAliasMode; - -struct alias_link; - -/* General utilities */ -u_short IpChecksum(struct ip *); -u_short TcpChecksum(struct ip *); -void DifferentialChecksum(u_short *, u_short *, u_short *, int); - -/* Internal data access */ -struct alias_link * -FindIcmpIn(struct in_addr, struct in_addr, u_short); - -struct alias_link * -FindIcmpOut(struct in_addr, struct in_addr, u_short); - -struct alias_link * -FindFragmentIn1(struct in_addr, struct in_addr, u_short); - -struct alias_link * -FindFragmentIn2(struct in_addr, struct in_addr, u_short); - -struct alias_link * -AddFragmentPtrLink(struct in_addr, u_short); - -struct alias_link * -FindFragmentPtr(struct in_addr, u_short); - -struct alias_link * -FindUdpTcpIn (struct in_addr, struct in_addr, u_short, u_short, u_char); - -struct alias_link * -FindUdpTcpOut(struct in_addr, struct in_addr, u_short, u_short, u_char); - -struct in_addr -FindOriginalAddress(struct in_addr); - -struct in_addr -FindAliasAddress(struct in_addr); - -/* External data access/modification */ -void GetFragmentAddr(struct alias_link *, struct in_addr *); -void SetFragmentAddr(struct alias_link *, struct in_addr); -void GetFragmentPtr(struct alias_link *, char **); -void SetFragmentPtr(struct alias_link *, char *); -void SetStateIn(struct alias_link *, int); -void SetStateOut(struct alias_link *, int); -int GetStateIn(struct alias_link *); -int GetStateOut(struct alias_link *); -struct in_addr GetOriginalAddress(struct alias_link *); -struct in_addr GetDestAddress(struct alias_link *); -struct in_addr GetAliasAddress(struct alias_link *); -struct in_addr GetDefaultAliasAddress(void); -void SetDefaultAliasAddress(struct in_addr); -u_short GetOriginalPort(struct alias_link *); -u_short GetAliasPort(struct alias_link *); -void SetAckModified(struct alias_link *); -int GetAckModified(struct alias_link *); -int GetDeltaAckIn(struct ip *, struct alias_link *); -int GetDeltaSeqOut(struct ip *, struct alias_link *); -void AddSeq(struct ip *, struct alias_link *, int); -void SetExpire(struct alias_link *, int); -void ClearCheckNewLink(void); -#ifndef NO_FW_PUNCH -void PunchFWHole(struct alias_link *); -#endif - - -/* Housekeeping function */ -void HouseKeeping(void); - -/* Tcp specfic routines */ -/*lint -save -library Suppress flexelint warnings */ -void AliasHandleFtpOut(struct ip *, struct alias_link *, int); -void AliasHandleIrcOut(struct ip *pip, struct alias_link *link, int maxsize ); -int AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short); -int AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *); -void AliasHandleCUSeeMeOut(struct ip *, struct alias_link *); -void AliasHandleCUSeeMeIn(struct ip *, struct in_addr); - - - -enum alias_tcp_state { - ALIAS_TCP_STATE_NOT_CONNECTED, - ALIAS_TCP_STATE_CONNECTED, - ALIAS_TCP_STATE_DISCONNECTED -}; - -/*lint -restore */ -#endif /* defined(ALIAS_LOCAL_H) */ diff --git a/sys/netinet/libalias/alias_nbt.c b/sys/netinet/libalias/alias_nbt.c deleted file mode 100644 index cd07431f5cbf..000000000000 --- a/sys/netinet/libalias/alias_nbt.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Written by Atsushi Murai <amurai@spec.co.jp> - * - * Copyright (C) 1998, System Planning and Engineering Co. All rights reserverd. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the System Planning and Engineering Co. The name of the - * SPEC may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: alias_nbt.c,v 1.1 1998/05/24 03:03:10 amurai Exp $ - * - * TODO: - * oClean up. - * oConsidering for word alignment for other platform. - */ -/* - alias_nbt.c performs special processing for NetBios over TCP/IP - sessions by UDP. - - Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>) - - See HISTORY file for record of revisions. -*/ - -/* Includes */ -#include <ctype.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netinet/ip.h> -#include <netinet/udp.h> -#include <netinet/tcp.h> - -#include "alias_local.h" - -#define ADJUST_CHECKSUM(acc, cksum) { \ - acc += cksum; \ - if (acc < 0) \ - { \ - acc = -acc; \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) ~acc; \ - } \ - else \ - { \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) acc; \ - } \ -} - -typedef struct { - struct in_addr oldaddr; - u_short oldport; - struct in_addr newaddr; - u_short newport; - u_short *uh_sum; -} NBTArguments; - -typedef struct { - unsigned char type; - unsigned char flags; - u_short id; - struct in_addr source_ip; - u_short source_port; - u_short len; - u_short offset; -} NbtDataHeader; - -#define OpQuery 0 -#define OpUnknown 4 -#define OpRegist 5 -#define OpRelease 6 -#define OpWACK 7 -#define OpRefresh 8 -typedef struct { - u_short nametrid; - u_short dir:1, opcode:4, nmflags:7, rcode:4; - u_short qdcount; - u_short ancount; - u_short nscount; - u_short arcount; -} NbtNSHeader; - -#define FMT_ERR 0x1 -#define SRV_ERR 0x2 -#define IMP_ERR 0x4 -#define RFS_ERR 0x5 -#define ACT_ERR 0x6 -#define CFT_ERR 0x7 - -/******************************************************************* - * copy an IP address from one buffer to another * - *******************************************************************/ -void putip(void *dest,void *src) -{ - memcpy(dest,src,4); -} - -void PrintRcode( u_char rcode ) { - - switch (rcode) { - case FMT_ERR: - printf("\nFormat Error."); - case SRV_ERR: - printf("\nSever failure."); - case IMP_ERR: - printf("\nUnsupported request error.\n"); - case RFS_ERR: - printf("\nRefused error.\n"); - case ACT_ERR: - printf("\nActive error.\n"); - case CFT_ERR: - printf("\nName in conflict error.\n"); - default: - printf("\n???=%0x\n", rcode ); - - } -} - - -/* Handling Name field */ -u_char *AliasHandleName ( u_char *p, char *pmax ) { - - u_char *s; - u_char c; - int compress; - - /* Following length field */ - - if (p == NULL || (char *)p >= pmax) - return(NULL); - - if (*p & 0xc0 ) { - p = p + 2; - if ((char *)p > pmax) - return(NULL); - return ((u_char *)p); - } - while ( ( *p & 0x3f) != 0x00 ) { - s = p + 1; - if ( *p == 0x20 ) - compress = 1; - else - compress = 0; - - /* Get next length field */ - p = (u_char *)(p + (*p & 0x3f) + 1); - if ((char *)p > pmax) { - p = NULL; - break; - } -#ifdef DEBUG - printf(":"); -#endif - while (s < p) { - if ( compress == 1 ) { - c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11)); -#ifdef DEBUG - if (isprint( c ) ) - printf("%c", c ); - else - printf("<0x%02x>", c ); -#endif - s +=2; - } else { -#ifdef DEBUG - printf("%c", *s); -#endif - s++; - } - } -#ifdef DEBUG - printf(":"); -#endif - fflush(stdout); - } - - /* Set up to out of Name field */ - if (p == NULL || (char *)p >= pmax) - p = NULL; - else - p++; - return ((u_char *)p); -} - -/* - * NetBios Datagram Handler (IP/UDP) - */ -#define DGM_DIRECT_UNIQ 0x10 -#define DGM_DIRECT_GROUP 0x11 -#define DGM_BROADCAST 0x12 -#define DGM_ERROR 0x13 -#define DGM_QUERY 0x14 -#define DGM_POSITIVE_RES 0x15 -#define DGM_NEGATIVE_RES 0x16 - -int AliasHandleUdpNbt( - struct ip *pip, /* IP packet to examine/patch */ - struct alias_link *link, - struct in_addr *alias_address, - u_short alias_port -) { - struct udphdr * uh; - NbtDataHeader *ndh; - u_char *p = NULL; - char *pmax; - - /* Calculate data length of UDP packet */ - uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); - pmax = (char *)uh + ntohs( uh->uh_ulen ); - - ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr))); - if ((char *)(ndh + 1) > pmax) - return(-1); -#ifdef DEBUG - printf("\nType=%02x,", ndh->type ); -#endif - switch ( ndh->type ) { - case DGM_DIRECT_UNIQ: - case DGM_DIRECT_GROUP: - case DGM_BROADCAST: - p = (u_char *)ndh + 14; - p = AliasHandleName ( p, pmax ); /* Source Name */ - p = AliasHandleName ( p, pmax ); /* Destination Name */ - break; - case DGM_ERROR: - p = (u_char *)ndh + 11; - break; - case DGM_QUERY: - case DGM_POSITIVE_RES: - case DGM_NEGATIVE_RES: - p = (u_char *)ndh + 10; - p = AliasHandleName ( p, pmax ); /* Destination Name */ - break; - } - if (p == NULL || (char *)p > pmax) - p = NULL; -#ifdef DEBUG - printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); -#endif - /* Doing a IP address and Port number Translation */ - if ( uh->uh_sum != 0 ) { - int acc; - u_short *sptr; - acc = ndh->source_port; - acc -= alias_port; - sptr = (u_short *) &(ndh->source_ip); - acc += *sptr++; - acc += *sptr; - sptr = (u_short *) alias_address; - acc -= *sptr++; - acc -= *sptr; - ADJUST_CHECKSUM(acc, uh->uh_sum) - } - ndh->source_ip = *alias_address; - ndh->source_port = alias_port; -#ifdef DEBUG - printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); - fflush(stdout); -#endif - return((p == NULL) ? -1 : 0); -} -/* Question Section */ -#define QS_TYPE_NB 0x0020 -#define QS_TYPE_NBSTAT 0x0021 -#define QS_CLAS_IN 0x0001 -typedef struct { - u_short type; /* The type of Request */ - u_short class; /* The class of Request */ -} NBTNsQuestion; - -u_char * -AliasHandleQuestion( - u_short count, - NBTNsQuestion *q, - char *pmax, - NBTArguments *nbtarg) -{ - - while ( count != 0 ) { - /* Name Filed */ - q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax); - - if (q == NULL || (char *)(q + 1) > pmax) { - q = NULL; - break; - } - - /* Type and Class filed */ - switch ( ntohs(q->type) ) { - case QS_TYPE_NB: - case QS_TYPE_NBSTAT: - q= q+1; - break; - default: - printf("\nUnknown Type on Question %0x\n", ntohs(q->type) ); - break; - } - count--; - } - - /* Set up to out of Question Section */ - return ((u_char *)q); -} - -/* Resource Record */ -#define RR_TYPE_A 0x0001 -#define RR_TYPE_NS 0x0002 -#define RR_TYPE_NULL 0x000a -#define RR_TYPE_NB 0x0020 -#define RR_TYPE_NBSTAT 0x0021 -#define RR_CLAS_IN 0x0001 -#define SizeOfNsResource 8 -typedef struct { - u_short type; - u_short class; - unsigned int ttl; - u_short rdlen; -} NBTNsResource; - -#define SizeOfNsRNB 6 -typedef struct { - u_short g:1, ont:2, resv:13; - struct in_addr addr; -} NBTNsRNB; - -u_char * -AliasHandleResourceNB( - NBTNsResource *q, - char *pmax, - NBTArguments *nbtarg) -{ - NBTNsRNB *nb; - u_short bcount; - - if (q == NULL || (char *)(q + 1) > pmax) - return(NULL); - /* Check out a length */ - bcount = ntohs(q->rdlen); - - /* Forward to Resource NB position */ - nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource); - - /* Processing all in_addr array */ -#ifdef DEBUG - printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); - printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount); -#endif - while ( nb != NULL && bcount != 0 ) { - if ((char *)(nb + 1) > pmax) { - nb = NULL; - break; - } -#ifdef DEBUG - printf("<%s>", inet_ntoa(nb->addr) ); -#endif - if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) { - if ( *nbtarg->uh_sum != 0 ) { - int acc; - u_short *sptr; - - sptr = (u_short *) &(nb->addr); - acc = *sptr++; - acc += *sptr; - sptr = (u_short *) &(nbtarg->newaddr); - acc -= *sptr++; - acc -= *sptr; - ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) - } - - nb->addr = nbtarg->newaddr; -#ifdef DEBUG - printf("O"); -#endif - } -#ifdef DEBUG - else { - printf("."); - } -#endif - nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB); - bcount -= SizeOfNsRNB; - } - if (nb == NULL || (char *)(nb + 1) > pmax) { - nb = NULL; - } - - return ((u_char *)nb); -} - -#define SizeOfResourceA 6 -typedef struct { - struct in_addr addr; -} NBTNsResourceA; - -u_char * -AliasHandleResourceA( - NBTNsResource *q, - char *pmax, - NBTArguments *nbtarg) -{ - NBTNsResourceA *a; - u_short bcount; - - if (q == NULL || (char *)(q + 1) > pmax) - return(NULL); - - /* Forward to Resource A position */ - a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) ); - - /* Check out of length */ - bcount = ntohs(q->rdlen); - - /* Processing all in_addr array */ -#ifdef DEBUG - printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); - printf("->%s]",inet_ntoa(nbtarg->newaddr )); -#endif - while ( bcount != 0 ) { - if (a == NULL || (char *)(a + 1) > pmax) - return(NULL); -#ifdef DEBUG - printf("..%s", inet_ntoa(a->addr) ); -#endif - if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) { - if ( *nbtarg->uh_sum != 0 ) { - int acc; - u_short *sptr; - - sptr = (u_short *) &(a->addr); /* Old */ - acc = *sptr++; - acc += *sptr; - sptr = (u_short *) &nbtarg->newaddr; /* New */ - acc -= *sptr++; - acc -= *sptr; - ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) - } - - a->addr = nbtarg->newaddr; - } - a++; /*XXXX*/ - bcount -= SizeOfResourceA; - } - if (a == NULL || (char *)(a + 1) > pmax) - a = NULL; - return ((u_char *)a); -} - -typedef struct { - u_short opcode:4, flags:8, resv:4; -} NBTNsResourceNULL; - -u_char * -AliasHandleResourceNULL( - NBTNsResource *q, - char *pmax, - NBTArguments *nbtarg) -{ - NBTNsResourceNULL *n; - u_short bcount; - - if (q == NULL || (char *)(q + 1) > pmax) - return(NULL); - - /* Forward to Resource NULL position */ - n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); - - /* Check out of length */ - bcount = ntohs(q->rdlen); - - /* Processing all in_addr array */ - while ( bcount != 0 ) { - if ((char *)(n + 1) > pmax) { - n = NULL; - break; - } - n++; - bcount -= sizeof(NBTNsResourceNULL); - } - if ((char *)(n + 1) > pmax) - n = NULL; - - return ((u_char *)n); -} - -u_char * -AliasHandleResourceNS( - NBTNsResource *q, - char *pmax, - NBTArguments *nbtarg) -{ - NBTNsResourceNULL *n; - u_short bcount; - - if (q == NULL || (char *)(q + 1) > pmax) - return(NULL); - - /* Forward to Resource NULL position */ - n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); - - /* Check out of length */ - bcount = ntohs(q->rdlen); - - /* Resource Record Name Filed */ - q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */ - - if (q == NULL || (char *)((u_char *)n + bcount) > pmax) - return(NULL); - else - return ((u_char *)n + bcount); -} - -typedef struct { - u_short numnames; -} NBTNsResourceNBSTAT; - -u_char * -AliasHandleResourceNBSTAT( - NBTNsResource *q, - char *pmax, - NBTArguments *nbtarg) -{ - NBTNsResourceNBSTAT *n; - u_short bcount; - - if (q == NULL || (char *)(q + 1) > pmax) - return(NULL); - - /* Forward to Resource NBSTAT position */ - n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) ); - - /* Check out of length */ - bcount = ntohs(q->rdlen); - - if (q == NULL || (char *)((u_char *)n + bcount) > pmax) - return(NULL); - else - return ((u_char *)n + bcount); -} - -u_char * -AliasHandleResource( - u_short count, - NBTNsResource *q, - char *pmax, - NBTArguments - *nbtarg) -{ - while ( count != 0 ) { - /* Resource Record Name Filed */ - q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax ); - - if (q == NULL || (char *)(q + 1) > pmax) - break; -#ifdef DEBUG - printf("type=%02x, count=%d\n", ntohs(q->type), count ); -#endif - - /* Type and Class filed */ - switch ( ntohs(q->type) ) { - case RR_TYPE_NB: - q = (NBTNsResource *)AliasHandleResourceNB( - q, - pmax, - nbtarg - ); - break; - case RR_TYPE_A: - q = (NBTNsResource *)AliasHandleResourceA( - q, - pmax, - nbtarg - ); - break; - case RR_TYPE_NS: - q = (NBTNsResource *)AliasHandleResourceNS( - q, - pmax, - nbtarg - ); - break; - case RR_TYPE_NULL: - q = (NBTNsResource *)AliasHandleResourceNULL( - q, - pmax, - nbtarg - ); - break; - case RR_TYPE_NBSTAT: - q = (NBTNsResource *)AliasHandleResourceNBSTAT( - q, - pmax, - nbtarg - ); - break; - default: - printf( - "\nUnknown Type of Resource %0x\n", - ntohs(q->type) - ); - break; - } - count--; - } - fflush(stdout); - return ((u_char *)q); -} - -int AliasHandleUdpNbtNS( - struct ip *pip, /* IP packet to examine/patch */ - struct alias_link *link, - struct in_addr *alias_address, - u_short *alias_port, - struct in_addr *original_address, - u_short *original_port ) -{ - struct udphdr * uh; - NbtNSHeader * nsh; - u_char * p; - char *pmax; - NBTArguments nbtarg; - - /* Set up Common Parameter */ - nbtarg.oldaddr = *alias_address; - nbtarg.oldport = *alias_port; - nbtarg.newaddr = *original_address; - nbtarg.newport = *original_port; - - /* Calculate data length of UDP packet */ - uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); - nbtarg.uh_sum = &(uh->uh_sum); - nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr))); - p = (u_char *)(nsh + 1); - pmax = (char *)uh + ntohs( uh->uh_ulen ); - - if ((char *)(nsh + 1) > pmax) - return(-1); - -#ifdef DEBUG - printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x" - ", an=%04x, ns=%04x, ar=%04x, [%d]-->", - nsh->dir ? "Response": "Request", - nsh->nametrid, - nsh->opcode, - nsh->nmflags, - nsh->rcode, - ntohs(nsh->qdcount), - ntohs(nsh->ancount), - ntohs(nsh->nscount), - ntohs(nsh->arcount), - (u_char *)p -(u_char *)nsh - ); -#endif - - /* Question Entries */ - if (ntohs(nsh->qdcount) !=0 ) { - p = AliasHandleQuestion( - ntohs(nsh->qdcount), - (NBTNsQuestion *)p, - pmax, - &nbtarg - ); - } - - /* Answer Resource Records */ - if (ntohs(nsh->ancount) !=0 ) { - p = AliasHandleResource( - ntohs(nsh->ancount), - (NBTNsResource *)p, - pmax, - &nbtarg - ); - } - - /* Authority Resource Recodrs */ - if (ntohs(nsh->nscount) !=0 ) { - p = AliasHandleResource( - ntohs(nsh->nscount), - (NBTNsResource *)p, - pmax, - &nbtarg - ); - } - - /* Additional Resource Recodrs */ - if (ntohs(nsh->arcount) !=0 ) { - p = AliasHandleResource( - ntohs(nsh->arcount), - (NBTNsResource *)p, - pmax, - &nbtarg - ); - } - -#ifdef DEBUG - PrintRcode(nsh->rcode); -#endif - return ((p == NULL) ? -1 : 0); -} - diff --git a/sys/netinet/libalias/alias_old.c b/sys/netinet/libalias/alias_old.c deleted file mode 100644 index 3f634d448411..000000000000 --- a/sys/netinet/libalias/alias_old.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - This file can be considered a junk pile of old functions that - are either obsolete or have had their names changed. In the - transition from alias2.1 to alias2.2, all the function names - were rationalized so that they began with "PacketAlias..." - - These functions are included for backwards compatibility. -*/ - -#include <sys/types.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include "alias.h" -#include "alias_local.h" - -void -InitPacketAlias(void) -{ - PacketAliasInit(); -} - -void -SetPacketAliasAddress(struct in_addr addr) -{ - PacketAliasSetAddress(addr); -} - -unsigned int -SetPacketAliasMode(unsigned int flags, unsigned int mask) -{ - return PacketAliasSetMode(flags, mask); -} - -int -PacketAliasPermanentLink(struct in_addr src_addr, u_short src_port, - struct in_addr dst_addr, u_short dst_port, - u_short alias_port, u_char proto) -{ - struct alias_link *link; - struct in_addr null_address; - - null_address.s_addr = 0; - link = PacketAliasRedirectPort(src_addr, src_port, - dst_addr, dst_port, - null_address, alias_port, - proto); - - if (link == NULL) - return -1; - else - return 0; -} - -int -SaveFragmentPtr(char *ptr) -{ - return PacketAliasSaveFragment(ptr); -} - -char * -GetNextFragmentPtr(char *ptr) -{ - return PacketAliasGetFragment(ptr); -} - -void -FragmentAliasIn(char *header, char *fragment) -{ - PacketAliasFragmentIn(header, fragment); -} - -u_short -InternetChecksum(u_short *ptr, int len) -{ - return PacketAliasInternetChecksum(ptr, len); -} diff --git a/sys/netinet/libalias/alias_util.c b/sys/netinet/libalias/alias_util.c deleted file mode 100644 index fe0765312018..000000000000 --- a/sys/netinet/libalias/alias_util.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - Alias_util.h contains general utilities used by other functions - in the packet aliasing module. At the moment, there are functions - for computing IP header and TCP packet checksums. - - The checksum routines are based upon example code in a Unix networking - text written by Stevens (sorry, I can't remember the title -- but - at least this is a good author). - - Initial Version: August, 1996 (cjm) - - Version 1.7: January 9, 1997 - Added differential checksum update function. -*/ - -/* -Note: the checksum routines assume that the actual checksum word has -been zeroed out. If the checksum workd is filled with the proper value, -then these routines will give a result of zero (useful for testing -purposes); -*/ - -#include <sys/types.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> - -#include "alias.h" -#include "alias_local.h" - -u_short -PacketAliasInternetChecksum(u_short *ptr, int nbytes) -{ - int sum, oddbyte; - - sum = 0; - while (nbytes > 1) - { - sum += *ptr++; - nbytes -= 2; - } - if (nbytes == 1) - { - oddbyte = 0; - *((u_char *) &oddbyte) = *(u_char *) ptr; - sum += oddbyte; - } - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return(~sum); -} - -u_short -IpChecksum(struct ip *pip) -{ - return( PacketAliasInternetChecksum((u_short *) pip, - (pip->ip_hl << 2)) ); - -} - -u_short -TcpChecksum(struct ip *pip) -{ - u_short *ptr; - struct tcphdr *tc; - int nhdr, ntcp, nbytes; - int sum, oddbyte; - - nhdr = pip->ip_hl << 2; - ntcp = ntohs(pip->ip_len) - nhdr; - - tc = (struct tcphdr *) ((char *) pip + nhdr); - ptr = (u_short *) tc; - -/* Add up TCP header and data */ - nbytes = ntcp; - sum = 0; - while (nbytes > 1) - { - sum += *ptr++; - nbytes -= 2; - } - if (nbytes == 1) - { - oddbyte = 0; - *((u_char *) &oddbyte) = *(u_char *) ptr; - sum += oddbyte; - } - -/* "Pseudo-header" data */ - ptr = (u_short *) &(pip->ip_dst); - sum += *ptr++; - sum += *ptr; - ptr = (u_short *) &(pip->ip_src); - sum += *ptr++; - sum += *ptr; - sum += htons((u_short) ntcp); - sum += htons((u_short) pip->ip_p); - -/* Roll over carry bits */ - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - -/* Return checksum */ - return((u_short) ~sum); -} - - -void -DifferentialChecksum(u_short *cksum, u_short *new, u_short *old, int n) -{ - int i; - int accumulate; - - accumulate = *cksum; - for (i=0; i<n; i++) - { - accumulate -= *new++; - accumulate += *old++; - } - - if (accumulate < 0) - { - accumulate = -accumulate; - accumulate = (accumulate >> 16) + (accumulate & 0xffff); - accumulate += accumulate >> 16; - *cksum = (u_short) ~accumulate; - } - else - { - accumulate = (accumulate >> 16) + (accumulate & 0xffff); - accumulate += accumulate >> 16; - *cksum = (u_short) accumulate; - } -} - diff --git a/sys/netinet/libalias/libalias.3 b/sys/netinet/libalias/libalias.3 deleted file mode 100644 index f9b36e6c6d71..000000000000 --- a/sys/netinet/libalias/libalias.3 +++ /dev/null @@ -1,768 +0,0 @@ -.Dd July, 1997 -.Dt "libalias" 3 -.Os -.Sh NAME -.Nm "libalias" -Packet Aliasing Library. A collection of -functions for aliasing and de-aliasing -of IP packets, intended for masquerading and -network address translation (NAT). - -.Sh SYNOPSIS -.Fd #include <sys/types.h> -.Fd #include <netinet/in.h> -.Fd #include <alias.h> - -Function prototypes are given in the main body -of the text. - -.Sh CONTENTS -.Bd -literal -offset left -1. Introduction -2. Initialization and Control - 2.1 PacketAliasInit() - 2.2 PacketAliasUninit() - 2.3 PacketAliasSetAddress() - 2.4 PacketAliasSetMode() - 2.5 PacketAliasSetFWBase() -3. Packet Handling - 3.1 PacketAliasIn() - 3.2 PacketAliasOut() -4. Port and Address Redirection - 4.1 PacketAliasRedirectPort() - 4.2 PacketAliasRedirectAddr() - 4.3 PacketAliasRedirectDelete() -5. Fragment Handling - 5.1 PacketAliasSaveFragment() - 5.2 PacketAliasGetFragment() - 5.3 PacketAliasFragmentIn() -6. Miscellaneous Functions - 6.1 PacketAliasSetTarget() - 6.2 PacketAliasCheckNewLink() - 6.3 PacketAliasInternetChecksum() -7. Authors -8. Acknowledgments - -Appendix A: Conceptual Background - A.1 Aliasing Links - A.2 Static and Dynamic Links - A.3 Partially Specified Links - A.4 Dynamic Link Creation -.Ed - -.Sh 1. Introduction -This library is a moderately portable -set of functions designed to assist -in the process of IP masquerading and -network address translation. Outgoing -packets from a local network with -unregistered IP addresses can be aliased -to appear as if they came from an -accessible IP address. Incoming packets -are then de-aliased so that they are sent -to the correct machine on the local network. - -A certain amount of flexibility is built -into the packet aliasing engine. In -the simplest mode of operation, a -many-to-one address mapping takes place -between local network and the packet -aliasing host. This is known as IP -masquerading. In addition, one-to-one -mappings between local and public addresses -can also be implemented, which is known as -static NAT. In between these extremes, -different groups of private addresses -can be linked to different public addresses, -comprising several distinct many-to-one -mappings. Also, a given public address -and port can be statically redirected to -a private address/port. - -The packet aliasing engine was designed -to operate in user space outside of the -kernel, without any access to private -kernel data structure, but the source code -can also be ported to a kernel environment. - -.Sh 2. Initialization and Control -Two specific functions, PacketAliasInit() -and PacketAliasSetAddress(), must always be -called before any packet handling may be -performed. In addition, the operating mode -of the packet aliasing engine can be customized -by calling PacketAliasSetMode(). -.Ss 2.1 PacketAliasInit() - -.Ft void -.Fn PacketAliasInit "void" - -This function has no argument or return -value and is used to initialize internal -data structures. The following mode bits -are always set after calling -PacketAliasInit(). See section 2.3 for -the meaning of these mode bits. -.Bd -literal -offset indent - PKT_ALIAS_USE_SAME_PORTS - PKT_ALIAS_USE_SOCKETS - PKT_ALIAS_RESET_ON_ADDR_CHANGE - -.Ed -This function will always return the packet -aliasing engine to the same initial state. -PacketAliasSetAddress() must be called afterwards, -and any desired changes from the default mode -bits listed above require a call to -PacketAliasSetMode(). - -It is mandatory that this function be called -at the beginning of a program prior to any -packet handling. -.Ss 2.2 PacketAliasUninit() - -.Ft void -.Fn PacketAliasUninit "void" - -This function has no argument or return -value and is used to clear any resources -attached to internal data structures. - -This functions should be called when a -program stop using the aliasing engine; -it do, among other things, clear out any -firewall holes. To provide backwards -compatibility and extra security, it is -added to the atexit() chain by -PacketAliasInit(). Calling it multiple -times is harmless. -.Ss 2.3 PacketAliasSetAddress() - -.Ft void -.Fn PacketAliasSetAddress "struct in_addr addr" - -This function sets the source address to which -outgoing packets from the local area network -are aliased. All outgoing packets are remapped -to this address unless overridden by a static -address mapping established by -PacketAliasRedirectAddr(). - -If the PKT_ALIAS_RESET_ON_ADDR_CHANGE mode bit -is set (the default mode of operation), then -the internal aliasing link tables will be reset -any time the aliasing address changes, as if -PacketAliasReset() were called. This is useful -for interfaces such as ppp where the IP -address may or may not change on successive -dial-up attempts. - -If the PKT_ALIAS_RESET_ON_ADDR_CHANGE mode bit -is set to zero, this function can also be used to -dynamically change the aliasing address on a -packet to packet basis (it is a low overhead -call). - -It is mandatory that this function be called -prior to any packet handling. -.Ss 2.4 PacketAliasSetMode() - -.Ft unsigned int -.Fn PacketAliasSetMode "unsigned int mode" "unsigned int mask" - -This function sets or clears mode bits -according to the value of -.Em mode . -Only bits marked in -.Em mask -are affected. The following mode bits are -defined in alias.h: -.Bl -hang -offset left -.It PKT_ALIAS_LOG. -Enables logging /var/log/alias.log. The log file -shows total numbers of links (icmp, tcp, udp) each -time an aliasing link is created or deleted. Mainly -useful for debugging when the log file is viewed -continuously with "tail -f". -.It PKT_ALIAS_DENY_INCOMING. -If this mode bit is set, all incoming packets -associated with new TCP connections or new -UDP transactions will be marked for being -ignored (PacketAliasIn() return code -PKT_ALIAS_IGNORED) by the calling program. -Response packets to connections or transactions -initiated from the packet aliasing host or -local network will be unaffected. This mode -bit is useful for implementing a one-way firewall. -.It PKT_ALIAS_SAME_PORTS. -If this mode bit is set, the packet aliasing -engine will attempt to leave the alias port -numbers unchanged from the actual local port -number. This can be done as long as the -quintuple (proto, alias addr, alias port, -remote addr, remote port) is unique. If a -conflict exists, an new aliasing port number is -chosen even if this mode bit is set. -.It PKT_ALIAS_USE_SOCKETS. -This bit should be set when the the packet -aliasing host originates network traffic as -well as forwards it. When the packet aliasing -host is waiting for a connection from an -unknown host address or unknown port number -(e.g. an FTP data connection), this mode bit -specifies that a socket be allocated as a place -holder to prevent port conflicts. Once a -connection is established, usually within a -minute or so, the socket is closed. -.It PKT_ALIAS_UNREGISTERED_ONLY. -If this mode bit is set, traffic on the -local network which does not originate from -unregistered address spaces will be ignored. -Standard Class A, B and C unregistered addresses -are: -.Bd -literal -offset indent - 10.0.0.0 -> 10.255.255.255 (Class A subnet) - 172.16.0.0 -> 172.31.255.255 (Class B subnets) - 192.168.0.0 -> 192.168.255.255 (Class C subnets) - -.Ed -This option is useful in the case that -packet aliasing host has both registered and -unregistered subnets on different interfaces. -The registered subnet is fully accessible to -the outside world, so traffic from it doesn't -need to be passed through the packet aliasing -engine. -.It PKT_ALIAS_RESET_ON_ADDR_CHANGE. -When this mode bit is set and -PacketAliasSetAddress() is called to change -the aliasing address, the internal link table -of the packet aliasing engine will be cleared. -This operating mode is useful for ppp links -where the interface address can sometimes -change or remain the same between dial-ups. -If this mode bit is not set, it the link table -will never be reset in the event of an -address change. -.It PKT_ALIAS_PUNCH_FW. -This option make libalias `punch holes' in an -ipfw based firewall for FTP/IRC DCC connections. -The holes punched are bound by from/to IP address -and port; it will not be possible to use a hole -for another connection. A hole is removed when -the connection that use it die. To cater for -unexpected death of a program using libalias (e.g -kill -9), changing the state of the flag will -clear the entire ipfw range allocated for holes. -This will also happen on the initial call to -PacketAliasSetFWBase(). This call must happen -prior to setting this flag. - -.El - -.Ss 2.5 PacketAliasSetFWBase() - -.Ft void -.Fn PacketAliasSetFWBase "unsigned int base" "unsigned int num" - -Set IPFW range allocated for punching firewall holes (with the -PKT_ALIAS_PUNCH_FW flag). The range will be cleared for all rules on -initialization. - -.Sh 3. Packet Handling -The packet handling functions are used to -modify incoming (remote->local) and outgoing -(local->remote) packets. The calling program -is responsible for receiving and sending -packets via network interfaces. - -Along with PacketAliasInit() and PacketAliasSetAddress(), -the two packet handling functions, PacketAliasIn() -and PacketAliasOut(), comprise minimal set of functions -needed for a basic IP masquerading implementation. -.Ss 3.1 PacketAliasIn() - -.Ft int -.Fn PacketAliasIn "char *buffer" "int maxpacketsize" - -An incoming packet coming from a remote machine to -the local network is de-aliased by this function. -The IP packet is pointed to by -.Em buffer , -and -.Em maxpacketsize -indicates the size of the data structure containing -the packet and should be at least as large as the -actual packet size. - -Return codes: -.Bl -hang -offset left -.It PKT_ALIAS_ERROR. -An internal error within the packet aliasing -engine occurred. -.It PKT_ALIAS_OK. -The packet aliasing process was successful. -.It PKT_ALIAS_IGNORED. -The packet was ignored and not de-aliased. -This can happen if the protocal is unrecognized, -possibly an ICMP message type is not handled or -if incoming packets for new connections are being -ignored (see PKT_ALIAS_DENY_INCOMING in section -2.2). -.It PKT_ALIAS_UNRESOLVED_FRAGMENT. -This is returned when a fragment cannot be -resolved because the header fragment has not -been sent yet. In this situation, fragments -must be saved with PacketAliasSaveFragment() -until a header fragment is found. -.It PKT_ALIAS_FOUND_HEADER_FRAGMENT. -The packet aliasing process was successful, -and a header fragment was found. This is a -signal to retrieve any unresolved fragments -with PacketAliasGetFragment() and de-alias -them with PacketAliasFragmentIn(). -.El -.Ss 3.2 PacketAliasOut() - -.Ft int -.Fn PacketAliasOut "char *buffer" "int maxpacketsize" - -An outgoing packet coming from the local network -to a remote machine is aliased by this function. -The IP packet is pointed to by -.Em buffer r, -and -.Em maxpacketsize -indicates the maximum packet size permissible -should the packet length be changed. IP encoding -protocols place address and port information in -the encapsulated data stream which have to be -modified and can account for changes in packet -length. Well known examples of such protocols -are FTP and IRC DCC. - -Return codes: -.Bl -hang -offset left -.It PKT_ALIAS_ERROR. -An internal error within the packet aliasing -engine occurred. -.It PKT_ALIAS_OK. -The packet aliasing process was successful. -.It PKT_ALIAS_IGNORED. -The packet was ignored and not de-aliased. -This can happen if the protocal is unrecognized, -or possibly an ICMP message type is not handled. -.El - -.Sh 4. Port and Address Redirection -The functions described in this section allow machines -on the local network to be accessible in some degree -to new incoming connections from the external network. -Individual ports can be re-mapped or static network -address translations can be designated. -.Ss 4.1 PacketAliasRedirectPort() - -.Ft struct alias_link * -.Fo PacketAliasRedirectPort -.Fa "struct in_addr local_addr" -.Fa "u_short local_port" -.Fa "struct in_addr remote_addr" -.Fa "u_short remote_port" -.Fa "struct in_addr alias_addr" -.Fa "u_short alias_port" -.Fa "u_char proto" -.Fc - -This function specifies that traffic from a -given remote address/port to an alias address/port -be redirected to a specified local address/port. -The parameter -.Em proto -can be either IPPROTO_TCP or IPPROTO_UDP, as -defined in <netinet/in.h>. - -If -.Em local_addr -or -.Em alias_addr -is zero, this indicates that the packet aliasing -address as established by PacketAliasSetAddress() -is to be used. Even if PacketAliasAddress() is -called to change the address after PacketAliasRedirectPort() -is called, a zero reference will track this change. - -If -.Em remote_addr -is zero, this indicates to redirect packets from -any remote address. Likewise, if -.Em remote_port -is zero, this indicates to redirect packets originating -from any remote port number. Almost always, the remote -port specification will be zero, but non-zero remote -addresses can be sometimes be useful for firewalling. -If two calls to PacketAliasRedirectPort() overlap in -their address/port specifications, then the most recent -call will have precedence. - -This function returns a pointer which can subsequently -be used by PacketAliasRedirectDelete(). If NULL is -returned, then the function call did not complete -successfully. - -All port numbers are in network address byte order, -so it is necessary to use htons() to convert these -parameters from internally readable numbers to -network byte order. Addresses are also in network -byte order, which is implicit in the use of the -.Em struct in_addr -data type. -.Ss 4.2 PacketAliasRedirectAddr() - -.Ft struct alias_link * -.Fo PacketAliasRedirectAddr -.Fa "struct in_addr local_addr" -.Fa "struct in_addr alias_addr" -.Fc - -This function desgnates that all incoming -traffic to -.Em alias_addr -be redirected to -.Em local_addr. -Similarly, all outgoing traffic from -.Em local_addr -is aliased to -.Em alias_addr . - -If -.Em local_addr -or -.Em alias_addr -is zero, this indicates that the packet aliasing -address as established by PacketAliasSetAddress() -is to be used. Even if PacketAliasAddress() is -called to change the address after PacketAliasRedirectAddr() -is called, a zero reference will track this change. - -If subsequent calls to PacketAliasRedirectAddr() -use the same aliasing address, all new incoming -traffic to this aliasing address will be redirected -to the local address made in the last function call, -but new traffic all of the local machines designated -in the several function calls will be aliased to -the same address. Consider the following example: -.Bd -literal -offset left - PacketAliasRedirectAddr(inet_aton("192.168.0.2"), - inet_aton("141.221.254.101")); - PacketAliasRedirectAddr(inet_aton("192.168.0.3"), - inet_aton("141.221.254.101")); - PacketAliasRedirectAddr(inet_aton("192.168.0.4"), - inet_aton("141.221.254.101")); -.Ed - -Any outgoing connections such as telnet or ftp -from 192.168.0.2, 102.168.0.3, 192.168.0.4 will -appear to come from 141.221.254.101. Any incoming -connections to 141.221.254.101 will be directed -to 192.168.0.4. - -Any calls to PacketAliasRedirectPort() will -have precedence over address mappings designated -by PacketAliasRedirectAddr(). - -This function returns a pointer which can subsequently -be used by PacketAliasRedirectDelete(). If NULL is -returned, then the function call did not complete -successfully. -.Ss 4.3 PacketAliasRedirectDelete() - -.Ft void -.Fn PacketAliasRedirectDelete "struct alias_link *ptr" - -This function will delete a specific static redirect -rule entered by PacketAliasRedirectPort() or -PacketAliasRedirectAddr(). The parameter -.Em ptr -is the pointer returned by either of the redirection -functions. If an invalid pointer is passed to -PacketAliasRedirectDelete(), then a program crash -or unpredictable operation could result, so it is -necessary to be careful using this function. - -.Sh 5. Fragment Handling -The functions in this section are used to deal with -incoming fragments. - -Outgoing fragments are handled within PacketAliasOut() -by changing the address according to any -applicable mapping set by PacketAliasRedirectAddress(), -or the default aliasing address set by -PacketAliasSetAddress(). - -Incoming fragments are handled in one of two ways. -If the header of a fragmented IP packet has already -been seen, then all subsequent fragments will be -re-mapped in the same manner the header fragment -was. Fragments which arrive before the header -are saved and then retrieved once the header fragment -has been resolved. -.Ss 5.1 PacketAliasSaveFragment() - -.Ft int -.Fn PacketAliasSaveFragment "char *ptr" - -When PacketAliasIn() returns -PKT_ALIAS_UNRESOLVED_FRAGMENT, this -function can be used to save the pointer to -the unresolved fragment. - -It is implicitly assumed that -.Em ptr -points to a block of memory allocated by -malloc(). If the fragment is never -resolved, the packet aliasing engine will -automatically free the memory after a -timeout period. [Eventually this function -should be modified so that a callback -function for freeing memory is passed as -an argument.] - -This function returns PKT_ALIAS_OK if it -was successful and PKT_ALIAS_ERROR if there -was an error. -.Ss 5.2 PacketAliasGetNextFragment() - -.Ft char * -.Fn PacketAliasGetFragment "char *buffer" - -This function can be used to retrieve fragment -pointers saved by PacketAliasSaveFragment(). -The IP header fragment pointed to by -Em buffer -is the header fragment indicated when -PacketAliasIn() returns PKT_ALIAS_FOUND_HEADER_FRAGMENT. -Once a a fragment pointer is retrieved, it -becomes the calling program's responsibility -to free the dynamically allocated memory for -the fragment. - -PacketAliasGetFragment() can be called -sequentially until there are no more fragments -available, at which time it returns NULL. -.Ss 5.3 PacketAliasFragmentIn() - -.Ft void -.Fn PacketAliasFragmentIn "char *header" "char *fragment" - -When a fragment is retrieved with -PacketAliasGetFragment(), it can then be -de-aliased with a call to PacketAliasFragmentIn(). -.Em header -is the pointer to a header fragment used as a -template, and -.Em fragment -is the pointer to the packet to be de-aliased. - -.Sh 6. Miscellaneous Functions - -.Ss 6.1 PacketAliasSetTarget() - -.Ft void -.Fn PacketAliasSetTarget "struct in_addr addr" - -When an incoming packet not associated with -any pre-existing aliasing link arrives at the -host machine, it will be sent to the address -indicated by a call to PacketAliasSetTarget(). - -If this function is not called, or is called -with a zero address argument, then all new -incoming packets go to the address set by -PacketAliasSetAddress. -.Ss 6.2 PacketAliasCheckNewLink() - -.Ft int -.Fn PacketAliasCheckNewLink "void" - -This function returns a non-zero value when -a new aliasing link is created. In circumstances -where incoming traffic is being sequentially -sent to different local servers, this function -can be used to trigger when PacketAliasSetTarget() -is called to change the default target address. -.Ss 6.3 PacketAliasInternetChecksum() - -.Ft u_short -.Fn PacketAliasInternetChecksum "u_short *buffer" "int nbytes" - -This is a utility function that does not seem -to be available elswhere and is included as a -convenience. It computes the internet checksum, -which is used in both IP and protocol-specific -headers (TCP, UDP, ICMP). - -.Em buffer -points to the data block to be checksummed, and -.Em nbytes -is the number of bytes. The 16-bit checksum -field should be zeroed before computing the checksum. - -Checksums can also be verified by operating on a block -of data including its checksum. If the checksum is -valid, PacketAliasInternetChecksum() will return zero. - -.Sh 7. Authors -Charles Mott (cmott@srv.net), versions 1.0 - 1.8, 2.0 - 2.4. - -Eivind Eklund (eivind@freebsd.org), versions 1.8b, 1.9 and -2.5. Added IRC DCC support as well as contributing a number of -architectural improvements; added the firewall bypass -for FTP/IRC DCC. - -.Sh 8. Acknowledgments - -Listed below, in approximate chronological -order, are individuals who have provided -valuable comments and/or debugging assistance. - -.Bl -inset -compact -offset left -.It Gary Roberts -.It Tom Torrance -.It Reto Burkhalter -.It Martin Renters -.It Brian Somers -.It Paul Traina -.It Ari Suutari -.It Dave Remien -.It J. Fortes -.It Andrzej Bialeki -.It Gordon Burditt -.El - -.Sh Appendix: Conceptual Background -This appendix is intended for those who -are planning to modify the source code or want -to create somewhat esoteric applications using -the packet aliasing functions. - -The conceptual framework under which the -packet aliasing engine operates is described here. -Central to the discussion is the idea of an -"aliasing link" which describes the relationship -for a given packet transaction between the local -machine, aliased identity and remote machine. It -is discussed how such links come into existence -and are destroyed. -.Ss A.1 Aliasing Links -There is a notion of an "aliasing link", -which is 7-tuple describing a specific -translation: -.Bd -literal -offset indent -(local addr, local port, alias addr, alias port, - remote addr, remote port, protocol) -.Ed - -Outgoing packets have the local address and -port number replaced with the alias address -and port number. Incoming packets undergo the -reverse process. The packet aliasing engine -attempts to match packets against an internal -table of aliasing links to determine how to -modify a given IP packet. Both the IP -header and protocol dependent headers are -modified as necessary. Aliasing links are -created and deleted as necessary according -to network traffic. - -Protocols can be TCP, UDP or even ICMP in -certain circumstances. (Some types of ICMP -packets can be aliased according to sequence -or id number which acts as an equivalent port -number for identifying how individual packets -should be handled.) - -Each aliasing link must have a unique -combination of the following five quantities: -alias address/port, remote address/port -and protocol. This ensures that several -machines on a local network can share the -same aliased IP address. In cases where -conflicts might arise, the aliasing port -is chosen so that uniqueness is maintained. -.Ss A.2 Static and Dynamic Links -Aliasing links can either be static or dynamic. -Static links persist indefinitely and represent -fixed rules for translating IP packets. Dynamic -links come into existence for a specific TCP -connection or UDP transaction or ICMP echo -sequence. For the case of TCP, the connection -can be monitored to see when the associated -aliasing link should be deleted. Aliasing links -for UDP transactions (and ICMP echo and timestamp -requests) work on a simple timeout rule. When -no activity is observed on a dynamic link for -a certain amount of time it is automatically -deleted. Timeout rules also apply to TCP -connections which do not open or close -properly. -.Ss A.3 Partially Specified Aliasing Links -Aliasing links can be partially specified, -meaning that the remote address and/or remote -ports are unknown. In this case, when a packet -matching the incomplete specification is found, -a fully specified dynamic link is created. If -the original partially specified link is dynamic, -it will be deleted after the fully specified link -is created, otherwise it will persist. - -For instance, a partially specified link might -be -.Bd -literal -offset indent -(192.168.0.4, 23, 204.228.203.215, 8066, 0, 0, tcp) -.Ed - -The zeros denote unspecified components for -the remote address and port. If this link were -static it would have the effect of redirecting -all incoming traffic from port 8066 of -204.228.203.215 to port 23 (telnet) of machine -192.168.0.4 on the local network. Each -individual telnet connection would initiate -the creation of a distinct dynamic link. -.Ss A.4 Dynamic Link Creation -In addition to aliasing links, there are -also address mappings that can be stored -within the internal data table of the packet -aliasing mechanism. -.Bd -literal -offset indent -(local addr, alias addr) -.Ed - -Address mappings are searched when creating -new dynamic links. - -All outgoing packets from the local network -automatically create a dynamic link if -they do not match an already existing fully -specified link. If an address mapping exists -for the the outgoing packet, this determines -the alias address to be used. If no mapping -exists, then a default address, usually the -address of the packet aliasing host, is used. -If necessary, this default address can be -changed as often as each individual packet -arrives. - -The aliasing port number is determined -such that the new dynamic link does not -conflict with any existing links. In the -default operating mode, the packet aliasing -engine attempts to set the aliasing port -equal to the local port number. If this -results in a conflict, then port numbers -are randomly chosen until a unique aliasing -link can be established. In an alternate -operating mode, the first choice of an -aliasing port is also random and unrelated -to the local port number. - diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c deleted file mode 100644 index 97d1983b0078..000000000000 --- a/sys/netinet/tcp_reass.c +++ /dev/null @@ -1,2231 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 - * $Id: tcp_input.c,v 1.81 1998/09/11 16:04:03 wollman Exp $ - */ - -#include "opt_ipfw.h" /* for ipfw_fwd */ -#include "opt_tcpdebug.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/sysctl.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> /* for proc0 declaration */ -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/syslog.h> - -#include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ - -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* for ICMP_BANDLIM */ -#include <netinet/in_pcb.h> -#include <netinet/ip_var.h> -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ -#include <netinet/tcp.h> -#include <netinet/tcp_fsm.h> -#include <netinet/tcp_seq.h> -#include <netinet/tcp_timer.h> -#include <netinet/tcp_var.h> -#include <netinet/tcpip.h> -#ifdef TCPDEBUG -#include <netinet/tcp_debug.h> -static struct tcpiphdr tcp_saveti; -#endif - -static int tcprexmtthresh = 3; -tcp_seq tcp_iss; -tcp_cc tcp_ccgen; - -struct tcpstat tcpstat; -SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, - CTLFLAG_RD, &tcpstat , tcpstat, ""); - -static int log_in_vain = 0; -SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW, - &log_in_vain, 0, ""); - -int tcp_delack_enabled = 1; -SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW, - &tcp_delack_enabled, 0, ""); - -u_long tcp_now; -struct inpcbhead tcb; -struct inpcbinfo tcbinfo; - -static void tcp_dooptions __P((struct tcpcb *, - u_char *, int, struct tcpiphdr *, struct tcpopt *)); -static void tcp_pulloutofband __P((struct socket *, - struct tcpiphdr *, struct mbuf *)); -static int tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *)); -static void tcp_xmit_timer __P((struct tcpcb *, int)); - - -/* - * Insert segment ti into reassembly queue of tcp with - * control block tp. Return TH_FIN if reassembly now includes - * a segment with FIN. The macro form does the common case inline - * (segment is the next to be received on an established connection, - * and the queue is empty), avoiding linkage into and removal - * from the queue and repetition of various conversions. - * Set DELACK for segments received in order, but ack immediately - * when segments are out of order (so fast retransmit can work). - */ -#define TCP_REASS(tp, ti, m, so, flags) { \ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->t_segq == NULL && \ - (tp)->t_state == TCPS_ESTABLISHED) { \ - if (tcp_delack_enabled) \ - tp->t_flags |= TF_DELACK; \ - else \ - tp->t_flags |= TF_ACKNOW; \ - (tp)->rcv_nxt += (ti)->ti_len; \ - flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ - sbappend(&(so)->so_rcv, (m)); \ - sorwakeup(so); \ - } else { \ - (flags) = tcp_reass((tp), (ti), (m)); \ - tp->t_flags |= TF_ACKNOW; \ - } \ -} - -static int -tcp_reass(tp, ti, m) - register struct tcpcb *tp; - register struct tcpiphdr *ti; - struct mbuf *m; -{ - struct mbuf *q; - struct mbuf *p; - struct mbuf *nq; - struct socket *so = tp->t_inpcb->inp_socket; - int flags; - -#define GETTCP(m) ((struct tcpiphdr *)m->m_pkthdr.header) - - /* - * Call with ti==0 after become established to - * force pre-ESTABLISHED data up to user socket. - */ - if (ti == 0) - goto present; - - m->m_pkthdr.header = ti; - - /* - * Find a segment which begins after this one does. - */ - for (q = tp->t_segq, p = NULL; q; p = q, q = q->m_nextpkt) - if (SEQ_GT(GETTCP(q)->ti_seq, ti->ti_seq)) - break; - - /* - * If there is a preceding segment, it may provide some of - * our data already. If so, drop the data from the incoming - * segment. If it provides all of our data, drop us. - */ - if (p != NULL) { - register int i; - /* conversion to int (in i) handles seq wraparound */ - i = GETTCP(p)->ti_seq + GETTCP(p)->ti_len - ti->ti_seq; - if (i > 0) { - if (i >= ti->ti_len) { - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += ti->ti_len; - m_freem(m); - /* - * Try to present any queued data - * at the left window edge to the user. - * This is needed after the 3-WHS - * completes. - */ - goto present; /* ??? */ - } - m_adj(m, i); - ti->ti_len -= i; - ti->ti_seq += i; - } - } - tcpstat.tcps_rcvoopack++; - tcpstat.tcps_rcvoobyte += ti->ti_len; - - /* - * While we overlap succeeding segments trim them or, - * if they are completely covered, dequeue them. - */ - while (q) { - register int i = (ti->ti_seq + ti->ti_len) - GETTCP(q)->ti_seq; - if (i <= 0) - break; - if (i < GETTCP(q)->ti_len) { - GETTCP(q)->ti_seq += i; - GETTCP(q)->ti_len -= i; - m_adj(q, i); - break; - } - - nq = q->m_nextpkt; - if (p) - p->m_nextpkt = nq; - else - tp->t_segq = nq; - m_freem(q); - q = nq; - } - - if (p == NULL) { - m->m_nextpkt = tp->t_segq; - tp->t_segq = m; - } else { - m->m_nextpkt = p->m_nextpkt; - p->m_nextpkt = m; - } - -present: - /* - * Present data to user, advancing rcv_nxt through - * completed sequence space. - */ - if (!TCPS_HAVEESTABLISHED(tp->t_state)) - return (0); - q = tp->t_segq; - if (!q || GETTCP(q)->ti_seq != tp->rcv_nxt) - return (0); - do { - tp->rcv_nxt += GETTCP(q)->ti_len; - flags = GETTCP(q)->ti_flags & TH_FIN; - nq = q->m_nextpkt; - tp->t_segq = nq; - q->m_nextpkt = NULL; - if (so->so_state & SS_CANTRCVMORE) - m_freem(q); - else - sbappend(&so->so_rcv, q); - q = nq; - } while (q && GETTCP(q)->ti_seq == tp->rcv_nxt); - sorwakeup(so); - return (flags); - -#undef GETTCP -} - -/* - * TCP input routine, follows pages 65-76 of the - * protocol specification dated September, 1981 very closely. - */ -void -tcp_input(m, iphlen) - register struct mbuf *m; - int iphlen; -{ - register struct tcpiphdr *ti; - register struct inpcb *inp; - u_char *optp = NULL; - int optlen = 0; - int len, tlen, off; - register struct tcpcb *tp = 0; - register int tiflags; - struct socket *so = 0; - int todrop, acked, ourfinisacked, needoutput = 0; - struct in_addr laddr; - int dropsocket = 0; - int iss = 0; - u_long tiwin; - struct tcpopt to; /* options in this segment */ - struct rmxp_tao *taop; /* pointer to our TAO cache entry */ - struct rmxp_tao tao_noncached; /* in case there's no cached entry */ -#ifdef TCPDEBUG - short ostate = 0; -#endif - - bzero((char *)&to, sizeof(to)); - - tcpstat.tcps_rcvtotal++; - /* - * Get IP and TCP header together in first mbuf. - * Note: IP leaves IP header in first mbuf. - */ - ti = mtod(m, struct tcpiphdr *); - if (iphlen > sizeof (struct ip)) - ip_stripoptions(m, (struct mbuf *)0); - if (m->m_len < sizeof (struct tcpiphdr)) { - if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { - tcpstat.tcps_rcvshort++; - return; - } - ti = mtod(m, struct tcpiphdr *); - } - - /* - * Checksum extended TCP header and data. - */ - tlen = ((struct ip *)ti)->ip_len; - len = sizeof (struct ip) + tlen; - bzero(ti->ti_x1, sizeof(ti->ti_x1)); - ti->ti_len = (u_short)tlen; - HTONS(ti->ti_len); - ti->ti_sum = in_cksum(m, len); - if (ti->ti_sum) { - tcpstat.tcps_rcvbadsum++; - goto drop; - } - - /* - * Check that TCP offset makes sense, - * pull out TCP options and adjust length. XXX - */ - off = ti->ti_off << 2; - if (off < sizeof (struct tcphdr) || off > tlen) { - tcpstat.tcps_rcvbadoff++; - goto drop; - } - tlen -= off; - ti->ti_len = tlen; - if (off > sizeof (struct tcphdr)) { - if (m->m_len < sizeof(struct ip) + off) { - if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { - tcpstat.tcps_rcvshort++; - return; - } - ti = mtod(m, struct tcpiphdr *); - } - optlen = off - sizeof (struct tcphdr); - optp = mtod(m, u_char *) + sizeof (struct tcpiphdr); - } - tiflags = ti->ti_flags; - - /* - * Convert TCP protocol specific fields to host format. - */ - NTOHL(ti->ti_seq); - NTOHL(ti->ti_ack); - NTOHS(ti->ti_win); - NTOHS(ti->ti_urp); - - /* - * Drop TCP, IP headers and TCP options. - */ - m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - - /* - * Locate pcb for segment. - */ -findpcb: -#ifdef IPFIREWALL_FORWARD - if (ip_fw_fwd_addr != NULL) { - /* - * Diverted. Pretend to be the destination. - * already got one like this? - */ - inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, 0); - if (!inp) { - /* - * No, then it's new. Try find the ambushing socket - */ - if (!ip_fw_fwd_addr->sin_port) { - inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, - ti->ti_sport, ip_fw_fwd_addr->sin_addr, - ti->ti_dport, 1); - } else { - inp = in_pcblookup_hash(&tcbinfo, - ti->ti_src, ti->ti_sport, - ip_fw_fwd_addr->sin_addr, - ntohs(ip_fw_fwd_addr->sin_port), 1); - } - } - ip_fw_fwd_addr = NULL; - } else -#endif /* IPFIREWALL_FORWARD */ - - inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, 1); - - /* - * If the state is CLOSED (i.e., TCB does not exist) then - * all data in the incoming segment is discarded. - * If the TCB exists but is in CLOSED state, it is embryonic, - * but should either do a listen or a connect soon. - */ - if (inp == NULL) { - if (log_in_vain && tiflags & TH_SYN) { - char buf[4*sizeof "123"]; - - strcpy(buf, inet_ntoa(ti->ti_dst)); - log(LOG_INFO, - "Connection attempt to TCP %s:%d from %s:%d\n", - buf, ntohs(ti->ti_dport), inet_ntoa(ti->ti_src), - ntohs(ti->ti_sport)); - } -#ifdef ICMP_BANDLIM - if (badport_bandlim(1) < 0) - goto drop; -#endif - goto dropwithreset; - } - tp = intotcpcb(inp); - if (tp == 0) - goto dropwithreset; - if (tp->t_state == TCPS_CLOSED) - goto drop; - - /* Unscale the window into a 32-bit value. */ - if ((tiflags & TH_SYN) == 0) - tiwin = ti->ti_win << tp->snd_scale; - else - tiwin = ti->ti_win; - - so = inp->inp_socket; - if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { -#ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) { - ostate = tp->t_state; - tcp_saveti = *ti; - } -#endif - if (so->so_options & SO_ACCEPTCONN) { - register struct tcpcb *tp0 = tp; - struct socket *so2; - if ((tiflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) { - /* - * Note: dropwithreset makes sure we don't - * send a RST in response to a RST. - */ - if (tiflags & TH_ACK) { - tcpstat.tcps_badsyn++; - goto dropwithreset; - } - goto drop; - } - so2 = sonewconn(so, 0); - if (so2 == 0) { - tcpstat.tcps_listendrop++; - so2 = sodropablereq(so); - if (so2) { - tcp_drop(sototcpcb(so2), ETIMEDOUT); - so2 = sonewconn(so, 0); - } - if (!so2) - goto drop; - } - so = so2; - /* - * This is ugly, but .... - * - * Mark socket as temporary until we're - * committed to keeping it. The code at - * ``drop'' and ``dropwithreset'' check the - * flag dropsocket to see if the temporary - * socket created here should be discarded. - * We mark the socket as discardable until - * we're committed to it below in TCPS_LISTEN. - */ - dropsocket++; - inp = (struct inpcb *)so->so_pcb; - inp->inp_laddr = ti->ti_dst; - inp->inp_lport = ti->ti_dport; - if (in_pcbinshash(inp) != 0) { - /* - * Undo the assignments above if we failed to put - * the PCB on the hash lists. - */ - inp->inp_laddr.s_addr = INADDR_ANY; - inp->inp_lport = 0; - goto drop; - } - inp->inp_options = ip_srcroute(); - tp = intotcpcb(inp); - tp->t_state = TCPS_LISTEN; - tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT); - - /* Compute proper scaling value from buffer space */ - while (tp->request_r_scale < TCP_MAX_WINSHIFT && - TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) - tp->request_r_scale++; - } - } - - /* - * Segment received on connection. - * Reset idle time and keep-alive timer. - */ - tp->t_idle = 0; - if (TCPS_HAVEESTABLISHED(tp->t_state)) - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - - /* - * Process options if not in LISTEN state, - * else do it below (after getting remote address). - */ - if (tp->t_state != TCPS_LISTEN) - tcp_dooptions(tp, optp, optlen, ti, &to); - - /* - * Header prediction: check for the two common cases - * of a uni-directional data xfer. If the packet has - * no control flags, is in-sequence, the window didn't - * change and we're not retransmitting, it's a - * candidate. If the length is zero and the ack moved - * forward, we're the sender side of the xfer. Just - * free the data acked & wake any higher level process - * that was blocked waiting for space. If the length - * is non-zero and the ack didn't move, we're the - * receiver side. If we're getting packets in-order - * (the reassembly queue is empty), add the data to - * the socket buffer and note that we need a delayed ack. - * Make sure that the hidden state-flags are also off. - * Since we check for TCPS_ESTABLISHED above, it can only - * be TH_NEEDSYN. - */ - if (tp->t_state == TCPS_ESTABLISHED && - (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && - ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) && - ((to.to_flag & TOF_TS) == 0 || - TSTMP_GEQ(to.to_tsval, tp->ts_recent)) && - /* - * Using the CC option is compulsory if once started: - * the segment is OK if no T/TCP was negotiated or - * if the segment has a CC option equal to CCrecv - */ - ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) != (TF_REQ_CC|TF_RCVD_CC) || - (to.to_flag & TOF_CC) != 0 && to.to_cc == tp->cc_recv) && - ti->ti_seq == tp->rcv_nxt && - tiwin && tiwin == tp->snd_wnd && - tp->snd_nxt == tp->snd_max) { - - /* - * If last ACK falls within this segment's sequence numbers, - * record the timestamp. - * NOTE that the test is modified according to the latest - * proposal of the tcplw@cray.com list (Braden 1993/04/26). - */ - if ((to.to_flag & TOF_TS) != 0 && - SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) { - tp->ts_recent_age = tcp_now; - tp->ts_recent = to.to_tsval; - } - - if (ti->ti_len == 0) { - if (SEQ_GT(ti->ti_ack, tp->snd_una) && - SEQ_LEQ(ti->ti_ack, tp->snd_max) && - tp->snd_cwnd >= tp->snd_wnd && - tp->t_dupacks < tcprexmtthresh) { - /* - * this is a pure ack for outstanding data. - */ - ++tcpstat.tcps_predack; - if ((to.to_flag & TOF_TS) != 0) - tcp_xmit_timer(tp, - tcp_now - to.to_tsecr + 1); - else if (tp->t_rtt && - SEQ_GT(ti->ti_ack, tp->t_rtseq)) - tcp_xmit_timer(tp, tp->t_rtt); - acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; - sbdrop(&so->so_snd, acked); - tp->snd_una = ti->ti_ack; - m_freem(m); - - /* - * If all outstanding data are acked, stop - * retransmit timer, otherwise restart timer - * using current (possibly backed-off) value. - * If process is waiting for space, - * wakeup/selwakeup/signal. If data - * are ready to send, let tcp_output - * decide between more output or persist. - */ - if (tp->snd_una == tp->snd_max) - tp->t_timer[TCPT_REXMT] = 0; - else if (tp->t_timer[TCPT_PERSIST] == 0) - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - - sowwakeup(so); - if (so->so_snd.sb_cc) - (void) tcp_output(tp); - return; - } - } else if (ti->ti_ack == tp->snd_una && - tp->t_segq == NULL && - ti->ti_len <= sbspace(&so->so_rcv)) { - /* - * this is a pure, in-sequence data packet - * with nothing on the reassembly queue and - * we have enough buffer space to take it. - */ - ++tcpstat.tcps_preddat; - tp->rcv_nxt += ti->ti_len; - tcpstat.tcps_rcvpack++; - tcpstat.tcps_rcvbyte += ti->ti_len; - /* - * Add data to socket buffer. - */ - sbappend(&so->so_rcv, m); - sorwakeup(so); - if (tcp_delack_enabled) { - tp->t_flags |= TF_DELACK; - } else { - tp->t_flags |= TF_ACKNOW; - tcp_output(tp); - } - return; - } - } - - /* - * Calculate amount of space in receive window, - * and then do TCP input processing. - * Receive window is amount of space in rcv queue, - * but not less than advertised window. - */ - { int win; - - win = sbspace(&so->so_rcv); - if (win < 0) - win = 0; - tp->rcv_wnd = imax(win, (int)(tp->rcv_adv - tp->rcv_nxt)); - } - - switch (tp->t_state) { - - /* - * If the state is LISTEN then ignore segment if it contains an RST. - * If the segment contains an ACK then it is bad and send a RST. - * If it does not contain a SYN then it is not interesting; drop it. - * If it is from this socket, drop it, it must be forged. - * Don't bother responding if the destination was a broadcast. - * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial - * tp->iss, and send a segment: - * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> - * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. - * Fill in remote peer address fields if not previously specified. - * Enter SYN_RECEIVED state, and process any other fields of this - * segment in this state. - */ - case TCPS_LISTEN: { - register struct sockaddr_in *sin; - - if (tiflags & TH_RST) - goto drop; - if (tiflags & TH_ACK) - goto dropwithreset; - if ((tiflags & TH_SYN) == 0) - goto drop; - if ((ti->ti_dport == ti->ti_sport) && - (ti->ti_dst.s_addr == ti->ti_src.s_addr)) - goto drop; - /* - * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN - * in_broadcast() should never return true on a received - * packet with M_BCAST not set. - */ - if (m->m_flags & (M_BCAST|M_MCAST) || - IN_MULTICAST(ntohl(ti->ti_dst.s_addr))) - goto drop; - MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, - M_NOWAIT); - if (sin == NULL) - goto drop; - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ti->ti_src; - sin->sin_port = ti->ti_sport; - bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero)); - laddr = inp->inp_laddr; - if (inp->inp_laddr.s_addr == INADDR_ANY) - inp->inp_laddr = ti->ti_dst; - if (in_pcbconnect(inp, (struct sockaddr *)sin, &proc0)) { - inp->inp_laddr = laddr; - FREE(sin, M_SONAME); - goto drop; - } - FREE(sin, M_SONAME); - tp->t_template = tcp_template(tp); - if (tp->t_template == 0) { - tp = tcp_drop(tp, ENOBUFS); - dropsocket = 0; /* socket is already gone */ - goto drop; - } - if ((taop = tcp_gettaocache(inp)) == NULL) { - taop = &tao_noncached; - bzero(taop, sizeof(*taop)); - } - tcp_dooptions(tp, optp, optlen, ti, &to); - if (iss) - tp->iss = iss; - else - tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR/4; - tp->irs = ti->ti_seq; - tcp_sendseqinit(tp); - tcp_rcvseqinit(tp); - /* - * Initialization of the tcpcb for transaction; - * set SND.WND = SEG.WND, - * initialize CCsend and CCrecv. - */ - tp->snd_wnd = tiwin; /* initial send-window */ - tp->cc_send = CC_INC(tcp_ccgen); - tp->cc_recv = to.to_cc; - /* - * Perform TAO test on incoming CC (SEG.CC) option, if any. - * - compare SEG.CC against cached CC from the same host, - * if any. - * - if SEG.CC > chached value, SYN must be new and is accepted - * immediately: save new CC in the cache, mark the socket - * connected, enter ESTABLISHED state, turn on flag to - * send a SYN in the next segment. - * A virtual advertised window is set in rcv_adv to - * initialize SWS prevention. Then enter normal segment - * processing: drop SYN, process data and FIN. - * - otherwise do a normal 3-way handshake. - */ - if ((to.to_flag & TOF_CC) != 0) { - if (((tp->t_flags & TF_NOPUSH) != 0) && - taop->tao_cc != 0 && CC_GT(to.to_cc, taop->tao_cc)) { - - taop->tao_cc = to.to_cc; - tp->t_state = TCPS_ESTABLISHED; - - /* - * If there is a FIN, or if there is data and the - * connection is local, then delay SYN,ACK(SYN) in - * the hope of piggy-backing it on a response - * segment. Otherwise must send ACK now in case - * the other side is slow starting. - */ - if (tcp_delack_enabled && ((tiflags & TH_FIN) || (ti->ti_len != 0 && - in_localaddr(inp->inp_faddr)))) - tp->t_flags |= (TF_DELACK | TF_NEEDSYN); - else - tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); - - /* - * Limit the `virtual advertised window' to TCP_MAXWIN - * here. Even if we requested window scaling, it will - * become effective only later when our SYN is acked. - */ - tp->rcv_adv += min(tp->rcv_wnd, TCP_MAXWIN); - tcpstat.tcps_connects++; - soisconnected(so); - tp->t_timer[TCPT_KEEP] = tcp_keepinit; - dropsocket = 0; /* committed to socket */ - tcpstat.tcps_accepts++; - goto trimthenstep6; - } - /* else do standard 3-way handshake */ - } else { - /* - * No CC option, but maybe CC.NEW: - * invalidate cached value. - */ - taop->tao_cc = 0; - } - /* - * TAO test failed or there was no CC option, - * do a standard 3-way handshake. - */ - tp->t_flags |= TF_ACKNOW; - tp->t_state = TCPS_SYN_RECEIVED; - tp->t_timer[TCPT_KEEP] = tcp_keepinit; - dropsocket = 0; /* committed to socket */ - tcpstat.tcps_accepts++; - goto trimthenstep6; - } - - /* - * If the state is SYN_RECEIVED: - * if seg contains an ACK, but not for our SYN/ACK, send a RST. - */ - case TCPS_SYN_RECEIVED: - if ((tiflags & TH_ACK) && - (SEQ_LEQ(ti->ti_ack, tp->snd_una) || - SEQ_GT(ti->ti_ack, tp->snd_max))) - goto dropwithreset; - break; - - /* - * If the state is SYN_SENT: - * if seg contains an ACK, but not for our SYN, drop the input. - * if seg contains a RST, then drop the connection. - * if seg does not contain SYN, then drop it. - * Otherwise this is an acceptable SYN segment - * initialize tp->rcv_nxt and tp->irs - * if seg contains ack then advance tp->snd_una - * if SYN has been acked change to ESTABLISHED else SYN_RCVD state - * arrange for segment to be acked (eventually) - * continue processing rest of data/controls, beginning with URG - */ - case TCPS_SYN_SENT: - if ((taop = tcp_gettaocache(inp)) == NULL) { - taop = &tao_noncached; - bzero(taop, sizeof(*taop)); - } - - if ((tiflags & TH_ACK) && - (SEQ_LEQ(ti->ti_ack, tp->iss) || - SEQ_GT(ti->ti_ack, tp->snd_max))) { - /* - * If we have a cached CCsent for the remote host, - * hence we haven't just crashed and restarted, - * do not send a RST. This may be a retransmission - * from the other side after our earlier ACK was lost. - * Our new SYN, when it arrives, will serve as the - * needed ACK. - */ - if (taop->tao_ccsent != 0) - goto drop; - else - goto dropwithreset; - } - if (tiflags & TH_RST) { - if (tiflags & TH_ACK) - tp = tcp_drop(tp, ECONNREFUSED); - goto drop; - } - if ((tiflags & TH_SYN) == 0) - goto drop; - tp->snd_wnd = ti->ti_win; /* initial send window */ - tp->cc_recv = to.to_cc; /* foreign CC */ - - tp->irs = ti->ti_seq; - tcp_rcvseqinit(tp); - if (tiflags & TH_ACK) { - /* - * Our SYN was acked. If segment contains CC.ECHO - * option, check it to make sure this segment really - * matches our SYN. If not, just drop it as old - * duplicate, but send an RST if we're still playing - * by the old rules. If no CC.ECHO option, make sure - * we don't get fooled into using T/TCP. - */ - if (to.to_flag & TOF_CCECHO) { - if (tp->cc_send != to.to_ccecho) - if (taop->tao_ccsent != 0) - goto drop; - else - goto dropwithreset; - } else - tp->t_flags &= ~TF_RCVD_CC; - tcpstat.tcps_connects++; - soisconnected(so); - /* Do window scaling on this connection? */ - if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - (TF_RCVD_SCALE|TF_REQ_SCALE)) { - tp->snd_scale = tp->requested_s_scale; - tp->rcv_scale = tp->request_r_scale; - } - /* Segment is acceptable, update cache if undefined. */ - if (taop->tao_ccsent == 0) - taop->tao_ccsent = to.to_ccecho; - - tp->rcv_adv += tp->rcv_wnd; - tp->snd_una++; /* SYN is acked */ - /* - * If there's data, delay ACK; if there's also a FIN - * ACKNOW will be turned on later. - */ - if (tcp_delack_enabled && ti->ti_len != 0) - tp->t_flags |= TF_DELACK; - else - tp->t_flags |= TF_ACKNOW; - /* - * Received <SYN,ACK> in SYN_SENT[*] state. - * Transitions: - * SYN_SENT --> ESTABLISHED - * SYN_SENT* --> FIN_WAIT_1 - */ - if (tp->t_flags & TF_NEEDFIN) { - tp->t_state = TCPS_FIN_WAIT_1; - tp->t_flags &= ~TF_NEEDFIN; - tiflags &= ~TH_SYN; - } else { - tp->t_state = TCPS_ESTABLISHED; - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - } - } else { - /* - * Received initial SYN in SYN-SENT[*] state => simul- - * taneous open. If segment contains CC option and there is - * a cached CC, apply TAO test; if it succeeds, connection is - * half-synchronized. Otherwise, do 3-way handshake: - * SYN-SENT -> SYN-RECEIVED - * SYN-SENT* -> SYN-RECEIVED* - * If there was no CC option, clear cached CC value. - */ - tp->t_flags |= TF_ACKNOW; - tp->t_timer[TCPT_REXMT] = 0; - if (to.to_flag & TOF_CC) { - if (taop->tao_cc != 0 && - CC_GT(to.to_cc, taop->tao_cc)) { - /* - * update cache and make transition: - * SYN-SENT -> ESTABLISHED* - * SYN-SENT* -> FIN-WAIT-1* - */ - taop->tao_cc = to.to_cc; - if (tp->t_flags & TF_NEEDFIN) { - tp->t_state = TCPS_FIN_WAIT_1; - tp->t_flags &= ~TF_NEEDFIN; - } else { - tp->t_state = TCPS_ESTABLISHED; - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - } - tp->t_flags |= TF_NEEDSYN; - } else - tp->t_state = TCPS_SYN_RECEIVED; - } else { - /* CC.NEW or no option => invalidate cache */ - taop->tao_cc = 0; - tp->t_state = TCPS_SYN_RECEIVED; - } - } - -trimthenstep6: - /* - * Advance ti->ti_seq to correspond to first data byte. - * If data, trim to stay within window, - * dropping FIN if necessary. - */ - ti->ti_seq++; - if (ti->ti_len > tp->rcv_wnd) { - todrop = ti->ti_len - tp->rcv_wnd; - m_adj(m, -todrop); - ti->ti_len = tp->rcv_wnd; - tiflags &= ~TH_FIN; - tcpstat.tcps_rcvpackafterwin++; - tcpstat.tcps_rcvbyteafterwin += todrop; - } - tp->snd_wl1 = ti->ti_seq - 1; - tp->rcv_up = ti->ti_seq; - /* - * Client side of transaction: already sent SYN and data. - * If the remote host used T/TCP to validate the SYN, - * our data will be ACK'd; if so, enter normal data segment - * processing in the middle of step 5, ack processing. - * Otherwise, goto step 6. - */ - if (tiflags & TH_ACK) - goto process_ACK; - goto step6; - /* - * If the state is LAST_ACK or CLOSING or TIME_WAIT: - * if segment contains a SYN and CC [not CC.NEW] option: - * if state == TIME_WAIT and connection duration > MSL, - * drop packet and send RST; - * - * if SEG.CC > CCrecv then is new SYN, and can implicitly - * ack the FIN (and data) in retransmission queue. - * Complete close and delete TCPCB. Then reprocess - * segment, hoping to find new TCPCB in LISTEN state; - * - * else must be old SYN; drop it. - * else do normal processing. - */ - case TCPS_LAST_ACK: - case TCPS_CLOSING: - case TCPS_TIME_WAIT: - if ((tiflags & TH_SYN) && - (to.to_flag & TOF_CC) && tp->cc_recv != 0) { - if (tp->t_state == TCPS_TIME_WAIT && - tp->t_duration > TCPTV_MSL) - goto dropwithreset; - if (CC_GT(to.to_cc, tp->cc_recv)) { - tp = tcp_close(tp); - goto findpcb; - } - else - goto drop; - } - break; /* continue normal processing */ - } - - /* - * States other than LISTEN or SYN_SENT. - * First check the RST flag and sequence number since reset segments - * are exempt from the timestamp and connection count tests. This - * fixes a bug introduced by the Stevens, vol. 2, p. 960 bugfix - * below which allowed reset segments in half the sequence space - * to fall though and be processed (which gives forged reset - * segments with a random sequence number a 50 percent chance of - * killing a connection). - * Then check timestamp, if present. - * Then check the connection count, if present. - * Then check that at least some bytes of segment are within - * receive window. If segment begins before rcv_nxt, - * drop leading data (and SYN); if nothing left, just ack. - * - * - * If the RST bit is set, check the sequence number to see - * if this is a valid reset segment. - * RFC 793 page 37: - * In all states except SYN-SENT, all reset (RST) segments - * are validated by checking their SEQ-fields. A reset is - * valid if its sequence number is in the window. - * Note: this does not take into account delayed ACKs, so - * we should test against last_ack_sent instead of rcv_nxt. - * Also, it does not make sense to allow reset segments with - * sequence numbers greater than last_ack_sent to be processed - * since these sequence numbers are just the acknowledgement - * numbers in our outgoing packets being echoed back at us, - * and these acknowledgement numbers are monotonically - * increasing. - * If we have multiple segments in flight, the intial reset - * segment sequence numbers will be to the left of last_ack_sent, - * but they will eventually catch up. - * In any case, it never made sense to trim reset segments to - * fit the receive window since RFC 1122 says: - * 4.2.2.12 RST Segment: RFC-793 Section 3.4 - * - * A TCP SHOULD allow a received RST segment to include data. - * - * DISCUSSION - * It has been suggested that a RST segment could contain - * ASCII text that encoded and explained the cause of the - * RST. No standard has yet been established for such - * data. - * - * If the reset segment passes the sequence number test examine - * the state: - * SYN_RECEIVED STATE: - * If passive open, return to LISTEN state. - * If active open, inform user that connection was refused. - * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: - * Inform user that connection was reset, and close tcb. - * CLOSING, LAST_ACK, TIME_WAIT STATES - * Close the tcb. - * TIME_WAIT state: - * Drop the segment - see Stevens, vol. 2, p. 964 and - * RFC 1337. - */ - if (tiflags & TH_RST) { - if (tp->last_ack_sent == ti->ti_seq) { - switch (tp->t_state) { - - case TCPS_SYN_RECEIVED: - so->so_error = ECONNREFUSED; - goto close; - - case TCPS_ESTABLISHED: - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - case TCPS_CLOSE_WAIT: - so->so_error = ECONNRESET; - close: - tp->t_state = TCPS_CLOSED; - tcpstat.tcps_drops++; - tp = tcp_close(tp); - break; - - case TCPS_CLOSING: - case TCPS_LAST_ACK: - tp = tcp_close(tp); - break; - - case TCPS_TIME_WAIT: - break; - } - } - goto drop; - } - - /* - * RFC 1323 PAWS: If we have a timestamp reply on this segment - * and it's less than ts_recent, drop it. - */ - if ((to.to_flag & TOF_TS) != 0 && tp->ts_recent && - TSTMP_LT(to.to_tsval, tp->ts_recent)) { - - /* Check to see if ts_recent is over 24 days old. */ - if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { - /* - * Invalidate ts_recent. If this segment updates - * ts_recent, the age will be reset later and ts_recent - * will get a valid value. If it does not, setting - * ts_recent to zero will at least satisfy the - * requirement that zero be placed in the timestamp - * echo reply when ts_recent isn't valid. The - * age isn't reset until we get a valid ts_recent - * because we don't want out-of-order segments to be - * dropped when ts_recent is old. - */ - tp->ts_recent = 0; - } else { - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += ti->ti_len; - tcpstat.tcps_pawsdrop++; - goto dropafterack; - } - } - - /* - * T/TCP mechanism - * If T/TCP was negotiated and the segment doesn't have CC, - * or if its CC is wrong then drop the segment. - * RST segments do not have to comply with this. - */ - if ((tp->t_flags & (TF_REQ_CC|TF_RCVD_CC)) == (TF_REQ_CC|TF_RCVD_CC) && - ((to.to_flag & TOF_CC) == 0 || tp->cc_recv != to.to_cc)) - goto dropafterack; - - /* - * In the SYN-RECEIVED state, validate that the packet belongs to - * this connection before trimming the data to fit the receive - * window. Check the sequence number versus IRS since we know - * the sequence numbers haven't wrapped. This is a partial fix - * for the "LAND" DoS attack. - */ - if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(ti->ti_seq, tp->irs)) - goto dropwithreset; - - todrop = tp->rcv_nxt - ti->ti_seq; - if (todrop > 0) { - if (tiflags & TH_SYN) { - tiflags &= ~TH_SYN; - ti->ti_seq++; - if (ti->ti_urp > 1) - ti->ti_urp--; - else - tiflags &= ~TH_URG; - todrop--; - } - /* - * Following if statement from Stevens, vol. 2, p. 960. - */ - if (todrop > ti->ti_len - || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { - /* - * Any valid FIN must be to the left of the window. - * At this point the FIN must be a duplicate or out - * of sequence; drop it. - */ - tiflags &= ~TH_FIN; - - /* - * Send an ACK to resynchronize and drop any data. - * But keep on processing for RST or ACK. - */ - tp->t_flags |= TF_ACKNOW; - todrop = ti->ti_len; - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += todrop; - } else { - tcpstat.tcps_rcvpartduppack++; - tcpstat.tcps_rcvpartdupbyte += todrop; - } - m_adj(m, todrop); - ti->ti_seq += todrop; - ti->ti_len -= todrop; - if (ti->ti_urp > todrop) - ti->ti_urp -= todrop; - else { - tiflags &= ~TH_URG; - ti->ti_urp = 0; - } - } - - /* - * If new data are received on a connection after the - * user processes are gone, then RST the other end. - */ - if ((so->so_state & SS_NOFDREF) && - tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { - tp = tcp_close(tp); - tcpstat.tcps_rcvafterclose++; - goto dropwithreset; - } - - /* - * If segment ends after window, drop trailing data - * (and PUSH and FIN); if nothing left, just ACK. - */ - todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); - if (todrop > 0) { - tcpstat.tcps_rcvpackafterwin++; - if (todrop >= ti->ti_len) { - tcpstat.tcps_rcvbyteafterwin += ti->ti_len; - /* - * If a new connection request is received - * while in TIME_WAIT, drop the old connection - * and start over if the sequence numbers - * are above the previous ones. - */ - if (tiflags & TH_SYN && - tp->t_state == TCPS_TIME_WAIT && - SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { - iss = tp->rcv_nxt + TCP_ISSINCR; - tp = tcp_close(tp); - goto findpcb; - } - /* - * If window is closed can only take segments at - * window edge, and have to drop data and PUSH from - * incoming segments. Continue processing, but - * remember to ack. Otherwise, drop segment - * and ack. - */ - if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { - tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_rcvwinprobe++; - } else - goto dropafterack; - } else - tcpstat.tcps_rcvbyteafterwin += todrop; - m_adj(m, -todrop); - ti->ti_len -= todrop; - tiflags &= ~(TH_PUSH|TH_FIN); - } - - /* - * If last ACK falls within this segment's sequence numbers, - * record its timestamp. - * NOTE that the test is modified according to the latest - * proposal of the tcplw@cray.com list (Braden 1993/04/26). - */ - if ((to.to_flag & TOF_TS) != 0 && - SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) { - tp->ts_recent_age = tcp_now; - tp->ts_recent = to.to_tsval; - } - - /* - * If a SYN is in the window, then this is an - * error and we send an RST and drop the connection. - */ - if (tiflags & TH_SYN) { - tp = tcp_drop(tp, ECONNRESET); - goto dropwithreset; - } - - /* - * If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN - * flag is on (half-synchronized state), then queue data for - * later processing; else drop segment and return. - */ - if ((tiflags & TH_ACK) == 0) { - if (tp->t_state == TCPS_SYN_RECEIVED || - (tp->t_flags & TF_NEEDSYN)) - goto step6; - else - goto drop; - } - - /* - * Ack processing. - */ - switch (tp->t_state) { - - /* - * In SYN_RECEIVED state, the ack ACKs our SYN, so enter - * ESTABLISHED state and continue processing. - * The ACK was checked above. - */ - case TCPS_SYN_RECEIVED: - - tcpstat.tcps_connects++; - soisconnected(so); - /* Do window scaling? */ - if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - (TF_RCVD_SCALE|TF_REQ_SCALE)) { - tp->snd_scale = tp->requested_s_scale; - tp->rcv_scale = tp->request_r_scale; - } - /* - * Upon successful completion of 3-way handshake, - * update cache.CC if it was undefined, pass any queued - * data to the user, and advance state appropriately. - */ - if ((taop = tcp_gettaocache(inp)) != NULL && - taop->tao_cc == 0) - taop->tao_cc = tp->cc_recv; - - /* - * Make transitions: - * SYN-RECEIVED -> ESTABLISHED - * SYN-RECEIVED* -> FIN-WAIT-1 - */ - if (tp->t_flags & TF_NEEDFIN) { - tp->t_state = TCPS_FIN_WAIT_1; - tp->t_flags &= ~TF_NEEDFIN; - } else { - tp->t_state = TCPS_ESTABLISHED; - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - } - /* - * If segment contains data or ACK, will call tcp_reass() - * later; if not, do so now to pass queued data to user. - */ - if (ti->ti_len == 0 && (tiflags & TH_FIN) == 0) - (void) tcp_reass(tp, (struct tcpiphdr *)0, - (struct mbuf *)0); - tp->snd_wl1 = ti->ti_seq - 1; - /* fall into ... */ - - /* - * In ESTABLISHED state: drop duplicate ACKs; ACK out of range - * ACKs. If the ack is in the range - * tp->snd_una < ti->ti_ack <= tp->snd_max - * then advance tp->snd_una to ti->ti_ack and drop - * data from the retransmission queue. If this ACK reflects - * more up to date window information we update our window information. - */ - case TCPS_ESTABLISHED: - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - case TCPS_CLOSE_WAIT: - case TCPS_CLOSING: - case TCPS_LAST_ACK: - case TCPS_TIME_WAIT: - - if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { - if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { - tcpstat.tcps_rcvdupack++; - /* - * If we have outstanding data (other than - * a window probe), this is a completely - * duplicate ack (ie, window info didn't - * change), the ack is the biggest we've - * seen and we've seen exactly our rexmt - * threshhold of them, assume a packet - * has been dropped and retransmit it. - * Kludge snd_nxt & the congestion - * window so we send only this one - * packet. - * - * We know we're losing at the current - * window size so do congestion avoidance - * (set ssthresh to half the current window - * and pull our congestion window back to - * the new ssthresh). - * - * Dup acks mean that packets have left the - * network (they're now cached at the receiver) - * so bump cwnd by the amount in the receiver - * to keep a constant cwnd packets in the - * network. - */ - if (tp->t_timer[TCPT_REXMT] == 0 || - ti->ti_ack != tp->snd_una) - tp->t_dupacks = 0; - else if (++tp->t_dupacks == tcprexmtthresh) { - tcp_seq onxt = tp->snd_nxt; - u_int win = - min(tp->snd_wnd, tp->snd_cwnd) / 2 / - tp->t_maxseg; - - if (win < 2) - win = 2; - tp->snd_ssthresh = win * tp->t_maxseg; - tp->t_timer[TCPT_REXMT] = 0; - tp->t_rtt = 0; - tp->snd_nxt = ti->ti_ack; - tp->snd_cwnd = tp->t_maxseg; - (void) tcp_output(tp); - tp->snd_cwnd = tp->snd_ssthresh + - tp->t_maxseg * tp->t_dupacks; - if (SEQ_GT(onxt, tp->snd_nxt)) - tp->snd_nxt = onxt; - goto drop; - } else if (tp->t_dupacks > tcprexmtthresh) { - tp->snd_cwnd += tp->t_maxseg; - (void) tcp_output(tp); - goto drop; - } - } else - tp->t_dupacks = 0; - break; - } - /* - * If the congestion window was inflated to account - * for the other side's cached packets, retract it. - */ - if (tp->t_dupacks >= tcprexmtthresh && - tp->snd_cwnd > tp->snd_ssthresh) - tp->snd_cwnd = tp->snd_ssthresh; - tp->t_dupacks = 0; - if (SEQ_GT(ti->ti_ack, tp->snd_max)) { - tcpstat.tcps_rcvacktoomuch++; - goto dropafterack; - } - /* - * If we reach this point, ACK is not a duplicate, - * i.e., it ACKs something we sent. - */ - if (tp->t_flags & TF_NEEDSYN) { - /* - * T/TCP: Connection was half-synchronized, and our - * SYN has been ACK'd (so connection is now fully - * synchronized). Go to non-starred state, - * increment snd_una for ACK of SYN, and check if - * we can do window scaling. - */ - tp->t_flags &= ~TF_NEEDSYN; - tp->snd_una++; - /* Do window scaling? */ - if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - (TF_RCVD_SCALE|TF_REQ_SCALE)) { - tp->snd_scale = tp->requested_s_scale; - tp->rcv_scale = tp->request_r_scale; - } - } - -process_ACK: - acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; - - /* - * If we have a timestamp reply, update smoothed - * round trip time. If no timestamp is present but - * transmit timer is running and timed sequence - * number was acked, update smoothed round trip time. - * Since we now have an rtt measurement, cancel the - * timer backoff (cf., Phil Karn's retransmit alg.). - * Recompute the initial retransmit timer. - */ - if (to.to_flag & TOF_TS) - tcp_xmit_timer(tp, tcp_now - to.to_tsecr + 1); - else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) - tcp_xmit_timer(tp,tp->t_rtt); - - /* - * If all outstanding data is acked, stop retransmit - * timer and remember to restart (more output or persist). - * If there is more data to be acked, restart retransmit - * timer, using current (possibly backed-off) value. - */ - if (ti->ti_ack == tp->snd_max) { - tp->t_timer[TCPT_REXMT] = 0; - needoutput = 1; - } else if (tp->t_timer[TCPT_PERSIST] == 0) - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - - /* - * If no data (only SYN) was ACK'd, - * skip rest of ACK processing. - */ - if (acked == 0) - goto step6; - - /* - * When new data is acked, open the congestion window. - * If the window gives us less than ssthresh packets - * in flight, open exponentially (maxseg per packet). - * Otherwise open linearly: maxseg per window - * (maxseg^2 / cwnd per packet). - */ - { - register u_int cw = tp->snd_cwnd; - register u_int incr = tp->t_maxseg; - - if (cw > tp->snd_ssthresh) - incr = incr * incr / cw; - tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale); - } - if (acked > so->so_snd.sb_cc) { - tp->snd_wnd -= so->so_snd.sb_cc; - sbdrop(&so->so_snd, (int)so->so_snd.sb_cc); - ourfinisacked = 1; - } else { - sbdrop(&so->so_snd, acked); - tp->snd_wnd -= acked; - ourfinisacked = 0; - } - sowwakeup(so); - tp->snd_una = ti->ti_ack; - if (SEQ_LT(tp->snd_nxt, tp->snd_una)) - tp->snd_nxt = tp->snd_una; - - switch (tp->t_state) { - - /* - * In FIN_WAIT_1 STATE in addition to the processing - * for the ESTABLISHED state if our FIN is now acknowledged - * then enter FIN_WAIT_2. - */ - case TCPS_FIN_WAIT_1: - if (ourfinisacked) { - /* - * If we can't receive any more - * data, then closing user can proceed. - * Starting the timer is contrary to the - * specification, but if we don't get a FIN - * we'll hang forever. - */ - if (so->so_state & SS_CANTRCVMORE) { - soisdisconnected(so); - tp->t_timer[TCPT_2MSL] = tcp_maxidle; - } - tp->t_state = TCPS_FIN_WAIT_2; - } - break; - - /* - * In CLOSING STATE in addition to the processing for - * the ESTABLISHED state if the ACK acknowledges our FIN - * then enter the TIME-WAIT state, otherwise ignore - * the segment. - */ - case TCPS_CLOSING: - if (ourfinisacked) { - tp->t_state = TCPS_TIME_WAIT; - tcp_canceltimers(tp); - /* Shorten TIME_WAIT [RFC-1644, p.28] */ - if (tp->cc_recv != 0 && - tp->t_duration < TCPTV_MSL) - tp->t_timer[TCPT_2MSL] = - tp->t_rxtcur * TCPTV_TWTRUNC; - else - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - soisdisconnected(so); - } - break; - - /* - * In LAST_ACK, we may still be waiting for data to drain - * and/or to be acked, as well as for the ack of our FIN. - * If our FIN is now acknowledged, delete the TCB, - * enter the closed state and return. - */ - case TCPS_LAST_ACK: - if (ourfinisacked) { - tp = tcp_close(tp); - goto drop; - } - break; - - /* - * In TIME_WAIT state the only thing that should arrive - * is a retransmission of the remote FIN. Acknowledge - * it and restart the finack timer. - */ - case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - goto dropafterack; - } - } - -step6: - /* - * Update window information. - * Don't look at window if no ACK: TAC's send garbage on first SYN. - */ - if ((tiflags & TH_ACK) && - (SEQ_LT(tp->snd_wl1, ti->ti_seq) || - (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || - (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { - /* keep track of pure window updates */ - if (ti->ti_len == 0 && - tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) - tcpstat.tcps_rcvwinupd++; - tp->snd_wnd = tiwin; - tp->snd_wl1 = ti->ti_seq; - tp->snd_wl2 = ti->ti_ack; - if (tp->snd_wnd > tp->max_sndwnd) - tp->max_sndwnd = tp->snd_wnd; - needoutput = 1; - } - - /* - * Process segments with URG. - */ - if ((tiflags & TH_URG) && ti->ti_urp && - TCPS_HAVERCVDFIN(tp->t_state) == 0) { - /* - * This is a kludge, but if we receive and accept - * random urgent pointers, we'll crash in - * soreceive. It's hard to imagine someone - * actually wanting to send this much urgent data. - */ - if (ti->ti_urp + so->so_rcv.sb_cc > sb_max) { - ti->ti_urp = 0; /* XXX */ - tiflags &= ~TH_URG; /* XXX */ - goto dodata; /* XXX */ - } - /* - * If this segment advances the known urgent pointer, - * then mark the data stream. This should not happen - * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since - * a FIN has been received from the remote side. - * In these states we ignore the URG. - * - * According to RFC961 (Assigned Protocols), - * the urgent pointer points to the last octet - * of urgent data. We continue, however, - * to consider it to indicate the first octet - * of data past the urgent section as the original - * spec states (in one of two places). - */ - if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { - tp->rcv_up = ti->ti_seq + ti->ti_urp; - so->so_oobmark = so->so_rcv.sb_cc + - (tp->rcv_up - tp->rcv_nxt) - 1; - if (so->so_oobmark == 0) - so->so_state |= SS_RCVATMARK; - sohasoutofband(so); - tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); - } - /* - * Remove out of band data so doesn't get presented to user. - * This can happen independent of advancing the URG pointer, - * but if two URG's are pending at once, some out-of-band - * data may creep in... ick. - */ - if (ti->ti_urp <= (u_long)ti->ti_len -#ifdef SO_OOBINLINE - && (so->so_options & SO_OOBINLINE) == 0 -#endif - ) - tcp_pulloutofband(so, ti, m); - } else - /* - * If no out of band data is expected, - * pull receive urgent pointer along - * with the receive window. - */ - if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) - tp->rcv_up = tp->rcv_nxt; -dodata: /* XXX */ - - /* - * Process the segment text, merging it into the TCP sequencing queue, - * and arranging for acknowledgment of receipt if necessary. - * This process logically involves adjusting tp->rcv_wnd as data - * is presented to the user (this happens in tcp_usrreq.c, - * case PRU_RCVD). If a FIN has already been received on this - * connection then we just ignore the text. - */ - if ((ti->ti_len || (tiflags&TH_FIN)) && - TCPS_HAVERCVDFIN(tp->t_state) == 0) { - TCP_REASS(tp, ti, m, so, tiflags); - /* - * Note the amount of data that peer has sent into - * our window, in order to estimate the sender's - * buffer size. - */ - len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); - } else { - m_freem(m); - tiflags &= ~TH_FIN; - } - - /* - * If FIN is received ACK the FIN and let the user know - * that the connection is closing. - */ - if (tiflags & TH_FIN) { - if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { - socantrcvmore(so); - /* - * If connection is half-synchronized - * (ie NEEDSYN flag on) then delay ACK, - * so it may be piggybacked when SYN is sent. - * Otherwise, since we received a FIN then no - * more input can be expected, send ACK now. - */ - if (tcp_delack_enabled && (tp->t_flags & TF_NEEDSYN)) - tp->t_flags |= TF_DELACK; - else - tp->t_flags |= TF_ACKNOW; - tp->rcv_nxt++; - } - switch (tp->t_state) { - - /* - * In SYN_RECEIVED and ESTABLISHED STATES - * enter the CLOSE_WAIT state. - */ - case TCPS_SYN_RECEIVED: - case TCPS_ESTABLISHED: - tp->t_state = TCPS_CLOSE_WAIT; - break; - - /* - * If still in FIN_WAIT_1 STATE FIN has not been acked so - * enter the CLOSING state. - */ - case TCPS_FIN_WAIT_1: - tp->t_state = TCPS_CLOSING; - break; - - /* - * In FIN_WAIT_2 state enter the TIME_WAIT state, - * starting the time-wait timer, turning off the other - * standard timers. - */ - case TCPS_FIN_WAIT_2: - tp->t_state = TCPS_TIME_WAIT; - tcp_canceltimers(tp); - /* Shorten TIME_WAIT [RFC-1644, p.28] */ - if (tp->cc_recv != 0 && - tp->t_duration < TCPTV_MSL) { - tp->t_timer[TCPT_2MSL] = - tp->t_rxtcur * TCPTV_TWTRUNC; - /* For transaction client, force ACK now. */ - tp->t_flags |= TF_ACKNOW; - } - else - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - soisdisconnected(so); - break; - - /* - * In TIME_WAIT state restart the 2 MSL time_wait timer. - */ - case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - break; - } - } -#ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) - tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0); -#endif - - /* - * Return any desired output. - */ - if (needoutput || (tp->t_flags & TF_ACKNOW)) - (void) tcp_output(tp); - return; - -dropafterack: - /* - * Generate an ACK dropping incoming segment if it occupies - * sequence space, where the ACK reflects our state. - * - * We can now skip the test for the RST flag since all - * paths to this code happen after packets containing - * RST have been dropped. - * - * In the SYN-RECEIVED state, don't send an ACK unless the - * segment we received passes the SYN-RECEIVED ACK test. - * If it fails send a RST. This breaks the loop in the - * "LAND" DoS attack, and also prevents an ACK storm - * between two listening ports that have been sent forged - * SYN segments, each with the source address of the other. - */ - if (tp->t_state == TCPS_SYN_RECEIVED && (tiflags & TH_ACK) && - (SEQ_GT(tp->snd_una, ti->ti_ack) || - SEQ_GT(ti->ti_ack, tp->snd_max)) ) - goto dropwithreset; -#ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) - tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); -#endif - m_freem(m); - tp->t_flags |= TF_ACKNOW; - (void) tcp_output(tp); - return; - -dropwithreset: - /* - * Generate a RST, dropping incoming segment. - * Make ACK acceptable to originator of segment. - * Don't bother to respond if destination was broadcast/multicast. - */ - if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) || - IN_MULTICAST(ntohl(ti->ti_dst.s_addr))) - goto drop; -#ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); -#endif - if (tiflags & TH_ACK) - tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); - else { - if (tiflags & TH_SYN) - ti->ti_len++; - tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, - TH_RST|TH_ACK); - } - /* destroy temporarily created socket */ - if (dropsocket) - (void) soabort(so); - return; - -drop: - /* - * Drop space held by incoming segment and return. - */ -#ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); -#endif - m_freem(m); - /* destroy temporarily created socket */ - if (dropsocket) - (void) soabort(so); - return; -} - -static void -tcp_dooptions(tp, cp, cnt, ti, to) - struct tcpcb *tp; - u_char *cp; - int cnt; - struct tcpiphdr *ti; - struct tcpopt *to; -{ - u_short mss = 0; - int opt, optlen; - - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[0]; - if (opt == TCPOPT_EOL) - break; - if (opt == TCPOPT_NOP) - optlen = 1; - else { - optlen = cp[1]; - if (optlen <= 0) - break; - } - switch (opt) { - - default: - continue; - - case TCPOPT_MAXSEG: - if (optlen != TCPOLEN_MAXSEG) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - bcopy((char *) cp + 2, (char *) &mss, sizeof(mss)); - NTOHS(mss); - break; - - case TCPOPT_WINDOW: - if (optlen != TCPOLEN_WINDOW) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - tp->t_flags |= TF_RCVD_SCALE; - tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); - break; - - case TCPOPT_TIMESTAMP: - if (optlen != TCPOLEN_TIMESTAMP) - continue; - to->to_flag |= TOF_TS; - bcopy((char *)cp + 2, - (char *)&to->to_tsval, sizeof(to->to_tsval)); - NTOHL(to->to_tsval); - bcopy((char *)cp + 6, - (char *)&to->to_tsecr, sizeof(to->to_tsecr)); - NTOHL(to->to_tsecr); - - /* - * A timestamp received in a SYN makes - * it ok to send timestamp requests and replies. - */ - if (ti->ti_flags & TH_SYN) { - tp->t_flags |= TF_RCVD_TSTMP; - tp->ts_recent = to->to_tsval; - tp->ts_recent_age = tcp_now; - } - break; - case TCPOPT_CC: - if (optlen != TCPOLEN_CC) - continue; - to->to_flag |= TOF_CC; - bcopy((char *)cp + 2, - (char *)&to->to_cc, sizeof(to->to_cc)); - NTOHL(to->to_cc); - /* - * A CC or CC.new option received in a SYN makes - * it ok to send CC in subsequent segments. - */ - if (ti->ti_flags & TH_SYN) - tp->t_flags |= TF_RCVD_CC; - break; - case TCPOPT_CCNEW: - if (optlen != TCPOLEN_CC) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - to->to_flag |= TOF_CCNEW; - bcopy((char *)cp + 2, - (char *)&to->to_cc, sizeof(to->to_cc)); - NTOHL(to->to_cc); - /* - * A CC or CC.new option received in a SYN makes - * it ok to send CC in subsequent segments. - */ - tp->t_flags |= TF_RCVD_CC; - break; - case TCPOPT_CCECHO: - if (optlen != TCPOLEN_CC) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - to->to_flag |= TOF_CCECHO; - bcopy((char *)cp + 2, - (char *)&to->to_ccecho, sizeof(to->to_ccecho)); - NTOHL(to->to_ccecho); - break; - } - } - if (ti->ti_flags & TH_SYN) - tcp_mss(tp, mss); /* sets t_maxseg */ -} - -/* - * Pull out of band byte out of a segment so - * it doesn't appear in the user's data queue. - * It is still reflected in the segment length for - * sequencing purposes. - */ -static void -tcp_pulloutofband(so, ti, m) - struct socket *so; - struct tcpiphdr *ti; - register struct mbuf *m; -{ - int cnt = ti->ti_urp - 1; - - while (cnt >= 0) { - if (m->m_len > cnt) { - char *cp = mtod(m, caddr_t) + cnt; - struct tcpcb *tp = sototcpcb(so); - - tp->t_iobc = *cp; - tp->t_oobflags |= TCPOOB_HAVEDATA; - bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); - m->m_len--; - return; - } - cnt -= m->m_len; - m = m->m_next; - if (m == 0) - break; - } - panic("tcp_pulloutofband"); -} - -/* - * Collect new round-trip time estimate - * and update averages and current timeout. - */ -static void -tcp_xmit_timer(tp, rtt) - register struct tcpcb *tp; - short rtt; -{ - register int delta; - - tcpstat.tcps_rttupdated++; - tp->t_rttupdated++; - if (tp->t_srtt != 0) { - /* - * srtt is stored as fixed point with 5 bits after the - * binary point (i.e., scaled by 8). The following magic - * is equivalent to the smoothing algorithm in rfc793 with - * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed - * point). Adjust rtt to origin 0. - */ - delta = ((rtt - 1) << TCP_DELTA_SHIFT) - - (tp->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT)); - - if ((tp->t_srtt += delta) <= 0) - tp->t_srtt = 1; - - /* - * We accumulate a smoothed rtt variance (actually, a - * smoothed mean difference), then set the retransmit - * timer to smoothed rtt + 4 times the smoothed variance. - * rttvar is stored as fixed point with 4 bits after the - * binary point (scaled by 16). The following is - * equivalent to rfc793 smoothing with an alpha of .75 - * (rttvar = rttvar*3/4 + |delta| / 4). This replaces - * rfc793's wired-in beta. - */ - if (delta < 0) - delta = -delta; - delta -= tp->t_rttvar >> (TCP_RTTVAR_SHIFT - TCP_DELTA_SHIFT); - if ((tp->t_rttvar += delta) <= 0) - tp->t_rttvar = 1; - } else { - /* - * No rtt measurement yet - use the unsmoothed rtt. - * Set the variance to half the rtt (so our first - * retransmit happens at 3*rtt). - */ - tp->t_srtt = rtt << TCP_RTT_SHIFT; - tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); - } - tp->t_rtt = 0; - tp->t_rxtshift = 0; - - /* - * the retransmit should happen at rtt + 4 * rttvar. - * Because of the way we do the smoothing, srtt and rttvar - * will each average +1/2 tick of bias. When we compute - * the retransmit timer, we want 1/2 tick of rounding and - * 1 extra tick because of +-1/2 tick uncertainty in the - * firing of the timer. The bias will give us exactly the - * 1.5 tick we need. But, because the bias is - * statistical, we have to test that we don't drop below - * the minimum feasible timer (which is 2 ticks). - */ - TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), - max(tp->t_rttmin, rtt + 2), TCPTV_REXMTMAX); - - /* - * We received an ack for a packet that wasn't retransmitted; - * it is probably safe to discard any error indications we've - * received recently. This isn't quite right, but close enough - * for now (a route might have failed after we sent a segment, - * and the return path might not be symmetrical). - */ - tp->t_softerror = 0; -} - -/* - * Determine a reasonable value for maxseg size. - * If the route is known, check route for mtu. - * If none, use an mss that can be handled on the outgoing - * interface without forcing IP to fragment; if bigger than - * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES - * to utilize large mbufs. If no route is found, route has no mtu, - * or the destination isn't local, use a default, hopefully conservative - * size (usually 512 or the default IP max size, but no more than the mtu - * of the interface), as we can't discover anything about intervening - * gateways or networks. We also initialize the congestion/slow start - * window to be a single segment if the destination isn't local. - * While looking at the routing entry, we also initialize other path-dependent - * parameters from pre-set or cached values in the routing entry. - * - * Also take into account the space needed for options that we - * send regularly. Make maxseg shorter by that amount to assure - * that we can send maxseg amount of data even when the options - * are present. Store the upper limit of the length of options plus - * data in maxopd. - * - * NOTE that this routine is only called when we process an incoming - * segment, for outgoing segments only tcp_mssopt is called. - * - * In case of T/TCP, we call this routine during implicit connection - * setup as well (offer = -1), to initialize maxseg from the cached - * MSS of our peer. - */ -void -tcp_mss(tp, offer) - struct tcpcb *tp; - int offer; -{ - register struct rtentry *rt; - struct ifnet *ifp; - register int rtt, mss; - u_long bufsize; - struct inpcb *inp; - struct socket *so; - struct rmxp_tao *taop; - int origoffer = offer; - - inp = tp->t_inpcb; - if ((rt = tcp_rtlookup(inp)) == NULL) { - tp->t_maxopd = tp->t_maxseg = tcp_mssdflt; - return; - } - ifp = rt->rt_ifp; - so = inp->inp_socket; - - taop = rmx_taop(rt->rt_rmx); - /* - * Offer == -1 means that we didn't receive SYN yet, - * use cached value in that case; - */ - if (offer == -1) - offer = taop->tao_mssopt; - /* - * Offer == 0 means that there was no MSS on the SYN segment, - * in this case we use tcp_mssdflt. - */ - if (offer == 0) - offer = tcp_mssdflt; - else - /* - * Sanity check: make sure that maxopd will be large - * enough to allow some data on segments even is the - * all the option space is used (40bytes). Otherwise - * funny things may happen in tcp_output. - */ - offer = max(offer, 64); - taop->tao_mssopt = offer; - - /* - * While we're here, check if there's an initial rtt - * or rttvar. Convert from the route-table units - * to scaled multiples of the slow timeout timer. - */ - if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { - /* - * XXX the lock bit for RTT indicates that the value - * is also a minimum value; this is subject to time. - */ - if (rt->rt_rmx.rmx_locks & RTV_RTT) - tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ); - tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); - tcpstat.tcps_usedrtt++; - if (rt->rt_rmx.rmx_rttvar) { - tp->t_rttvar = rt->rt_rmx.rmx_rttvar / - (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); - tcpstat.tcps_usedrttvar++; - } else { - /* default variation is +- 1 rtt */ - tp->t_rttvar = - tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE; - } - TCPT_RANGESET(tp->t_rxtcur, - ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, - tp->t_rttmin, TCPTV_REXMTMAX); - } - /* - * if there's an mtu associated with the route, use it - */ - if (rt->rt_rmx.rmx_mtu) - mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); - else - { - mss = ifp->if_mtu - sizeof(struct tcpiphdr); - if (!in_localaddr(inp->inp_faddr)) - mss = min(mss, tcp_mssdflt); - } - mss = min(mss, offer); - /* - * maxopd stores the maximum length of data AND options - * in a segment; maxseg is the amount of data in a normal - * segment. We need to store this value (maxopd) apart - * from maxseg, because now every segment carries options - * and thus we normally have somewhat less data in segments. - */ - tp->t_maxopd = mss; - - /* - * In case of T/TCP, origoffer==-1 indicates, that no segments - * were received yet. In this case we just guess, otherwise - * we do the same as before T/TCP. - */ - if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && - (origoffer == -1 || - (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)) - mss -= TCPOLEN_TSTAMP_APPA; - if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && - (origoffer == -1 || - (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC)) - mss -= TCPOLEN_CC_APPA; - -#if (MCLBYTES & (MCLBYTES - 1)) == 0 - if (mss > MCLBYTES) - mss &= ~(MCLBYTES-1); -#else - if (mss > MCLBYTES) - mss = mss / MCLBYTES * MCLBYTES; -#endif - /* - * If there's a pipesize, change the socket buffer - * to that size. Make the socket buffers an integral - * number of mss units; if the mss is larger than - * the socket buffer, decrease the mss. - */ -#ifdef RTV_SPIPE - if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0) -#endif - bufsize = so->so_snd.sb_hiwat; - if (bufsize < mss) - mss = bufsize; - else { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - (void)sbreserve(&so->so_snd, bufsize); - } - tp->t_maxseg = mss; - -#ifdef RTV_RPIPE - if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0) -#endif - bufsize = so->so_rcv.sb_hiwat; - if (bufsize > mss) { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - (void)sbreserve(&so->so_rcv, bufsize); - } - /* - * Don't force slow-start on local network. - */ - if (!in_localaddr(inp->inp_faddr)) - tp->snd_cwnd = mss; - - if (rt->rt_rmx.rmx_ssthresh) { - /* - * There's some sort of gateway or interface - * buffer limit on the path. Use this to set - * the slow start threshhold, but set the - * threshold to no less than 2*mss. - */ - tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh); - tcpstat.tcps_usedssthresh++; - } -} - -/* - * Determine the MSS option to send on an outgoing SYN. - */ -int -tcp_mssopt(tp) - struct tcpcb *tp; -{ - struct rtentry *rt; - - rt = tcp_rtlookup(tp->t_inpcb); - if (rt == NULL) - return tcp_mssdflt; - - return rt->rt_ifp->if_mtu - sizeof(struct tcpiphdr); -} diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c deleted file mode 100644 index 12ca0258f12f..000000000000 --- a/sys/netinet/tcp_timewait.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 - * $Id: tcp_subr.c,v 1.48 1998/11/15 21:35:09 guido Exp $ - */ - -#include "opt_compat.h" -#include "opt_tcpdebug.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/sysctl.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/protosw.h> - -#include <vm/vm_zone.h> - -#include <net/route.h> -#include <net/if.h> - -#define _IP_VHL -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/in_pcb.h> -#include <netinet/in_var.h> -#include <netinet/ip_var.h> -#include <netinet/tcp.h> -#include <netinet/tcp_fsm.h> -#include <netinet/tcp_seq.h> -#include <netinet/tcp_timer.h> -#include <netinet/tcp_var.h> -#include <netinet/tcpip.h> -#ifdef TCPDEBUG -#include <netinet/tcp_debug.h> -#endif - -int tcp_mssdflt = TCP_MSS; -SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, - CTLFLAG_RW, &tcp_mssdflt , 0, ""); - -static int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; -SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, - CTLFLAG_RW, &tcp_rttdflt , 0, ""); - -static int tcp_do_rfc1323 = 1; -SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, - CTLFLAG_RW, &tcp_do_rfc1323 , 0, ""); - -static int tcp_do_rfc1644 = 0; -SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1644, rfc1644, - CTLFLAG_RW, &tcp_do_rfc1644 , 0, ""); - -SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD, &tcbinfo.ipi_count, - 0, "Number of active PCBs"); - -static void tcp_cleartaocache __P((void)); -static void tcp_notify __P((struct inpcb *, int)); - -/* - * Target size of TCP PCB hash tables. Must be a power of two. - */ -#ifndef TCBHASHSIZE -#define TCBHASHSIZE 512 -#endif - -/* - * This is the actual shape of what we allocate using the zone - * allocator. Doing it this way allows us to protect both structures - * using the same generation count, and also eliminates the overhead - * of allocating tcpcbs separately. By hiding the structure here, - * we avoid changing most of the rest of the code (although it needs - * to be changed, eventually, for greater efficiency). - */ -#define ALIGNMENT 32 -#define ALIGNM1 (ALIGNMENT - 1) -struct inp_tp { - union { - struct inpcb inp; - char align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1]; - } inp_tp_u; - struct tcpcb tcb; -}; -#undef ALIGNMENT -#undef ALIGNM1 - -/* - * Tcp initialization - */ -void -tcp_init() -{ - - tcp_iss = random(); /* wrong, but better than a constant */ - tcp_ccgen = 1; - tcp_cleartaocache(); - LIST_INIT(&tcb); - tcbinfo.listhead = &tcb; - tcbinfo.hashbase = hashinit(TCBHASHSIZE, M_PCB, &tcbinfo.hashmask); - tcbinfo.porthashbase = hashinit(TCBHASHSIZE, M_PCB, - &tcbinfo.porthashmask); - tcbinfo.ipi_zone = zinit("tcpcb", sizeof(struct inp_tp), maxsockets, - ZONE_INTERRUPT, 0); - if (max_protohdr < sizeof(struct tcpiphdr)) - max_protohdr = sizeof(struct tcpiphdr); - if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN) - panic("tcp_init"); -} - -/* - * Create template to be used to send tcp packets on a connection. - * Call after host entry created, allocates an mbuf and fills - * in a skeletal tcp/ip header, minimizing the amount of work - * necessary when the connection is used. - */ -struct tcpiphdr * -tcp_template(tp) - struct tcpcb *tp; -{ - register struct inpcb *inp = tp->t_inpcb; - register struct mbuf *m; - register struct tcpiphdr *n; - - if ((n = tp->t_template) == 0) { - m = m_get(M_DONTWAIT, MT_HEADER); - if (m == NULL) - return (0); - m->m_len = sizeof (struct tcpiphdr); - n = mtod(m, struct tcpiphdr *); - } - bzero(n->ti_x1, sizeof(n->ti_x1)); - n->ti_pr = IPPROTO_TCP; - n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - n->ti_src = inp->inp_laddr; - n->ti_dst = inp->inp_faddr; - n->ti_sport = inp->inp_lport; - n->ti_dport = inp->inp_fport; - n->ti_seq = 0; - n->ti_ack = 0; - n->ti_x2 = 0; - n->ti_off = 5; - n->ti_flags = 0; - n->ti_win = 0; - n->ti_sum = 0; - n->ti_urp = 0; - return (n); -} - -/* - * Send a single message to the TCP at address specified by - * the given TCP/IP header. If m == 0, then we make a copy - * of the tcpiphdr at ti and send directly to the addressed host. - * This is used to force keep alive messages out using the TCP - * template for a connection tp->t_template. If flags are given - * then we send a message back to the TCP which originated the - * segment ti, and discard the mbuf containing it and any other - * attached mbufs. - * - * In any case the ack and sequence number of the transmitted - * segment are as specified by the parameters. - * - * NOTE: If m != NULL, then ti must point to *inside* the mbuf. - */ -void -tcp_respond(tp, ti, m, ack, seq, flags) - struct tcpcb *tp; - register struct tcpiphdr *ti; - register struct mbuf *m; - tcp_seq ack, seq; - int flags; -{ - register int tlen; - int win = 0; - struct route *ro = 0; - struct route sro; - - if (tp) { - if (!(flags & TH_RST)) - win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); - ro = &tp->t_inpcb->inp_route; - } else { - ro = &sro; - bzero(ro, sizeof *ro); - } - if (m == 0) { - m = m_gethdr(M_DONTWAIT, MT_HEADER); - if (m == NULL) - return; -#ifdef TCP_COMPAT_42 - tlen = 1; -#else - tlen = 0; -#endif - m->m_data += max_linkhdr; - *mtod(m, struct tcpiphdr *) = *ti; - ti = mtod(m, struct tcpiphdr *); - flags = TH_ACK; - } else { - m_freem(m->m_next); - m->m_next = 0; - m->m_data = (caddr_t)ti; - m->m_len = sizeof (struct tcpiphdr); - tlen = 0; -#define xchg(a,b,type) { type t; t=a; a=b; b=t; } - xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, n_long); - xchg(ti->ti_dport, ti->ti_sport, n_short); -#undef xchg - } - ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); - tlen += sizeof (struct tcpiphdr); - m->m_len = tlen; - m->m_pkthdr.len = tlen; - m->m_pkthdr.rcvif = (struct ifnet *) 0; - bzero(ti->ti_x1, sizeof(ti->ti_x1)); - ti->ti_seq = htonl(seq); - ti->ti_ack = htonl(ack); - ti->ti_x2 = 0; - ti->ti_off = sizeof (struct tcphdr) >> 2; - ti->ti_flags = flags; - if (tp) - ti->ti_win = htons((u_short) (win >> tp->rcv_scale)); - else - ti->ti_win = htons((u_short)win); - ti->ti_urp = 0; - ti->ti_sum = 0; - ti->ti_sum = in_cksum(m, tlen); - ((struct ip *)ti)->ip_len = tlen; - ((struct ip *)ti)->ip_ttl = ip_defttl; -#ifdef TCPDEBUG - if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_OUTPUT, 0, tp, ti, 0); -#endif - (void) ip_output(m, NULL, ro, 0, NULL); - if (ro == &sro && ro->ro_rt) { - RTFREE(ro->ro_rt); - } -} - -/* - * Create a new TCP control block, making an - * empty reassembly queue and hooking it to the argument - * protocol control block. The `inp' parameter must have - * come from the zone allocator set up in tcp_init(). - */ -struct tcpcb * -tcp_newtcpcb(inp) - struct inpcb *inp; -{ - struct inp_tp *it; - register struct tcpcb *tp; - - it = (struct inp_tp *)inp; - tp = &it->tcb; - bzero((char *) tp, sizeof(struct tcpcb)); - tp->t_segq = NULL; - tp->t_maxseg = tp->t_maxopd = tcp_mssdflt; - - if (tcp_do_rfc1323) - tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); - if (tcp_do_rfc1644) - tp->t_flags |= TF_REQ_CC; - tp->t_inpcb = inp; /* XXX */ - /* - * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no - * rtt estimate. Set rttvar so that srtt + 4 * rttvar gives - * reasonable initial retransmit time. - */ - tp->t_srtt = TCPTV_SRTTBASE; - tp->t_rttvar = ((TCPTV_RTOBASE - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4; - tp->t_rttmin = TCPTV_MIN; - tp->t_rxtcur = TCPTV_RTOBASE; - tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; - inp->inp_ip_ttl = ip_defttl; - inp->inp_ppcb = (caddr_t)tp; - return (tp); /* XXX */ -} - -/* - * Drop a TCP connection, reporting - * the specified error. If connection is synchronized, - * then send a RST to peer. - */ -struct tcpcb * -tcp_drop(tp, errno) - register struct tcpcb *tp; - int errno; -{ - struct socket *so = tp->t_inpcb->inp_socket; - - if (TCPS_HAVERCVDSYN(tp->t_state)) { - tp->t_state = TCPS_CLOSED; - (void) tcp_output(tp); - tcpstat.tcps_drops++; - } else - tcpstat.tcps_conndrops++; - if (errno == ETIMEDOUT && tp->t_softerror) - errno = tp->t_softerror; - so->so_error = errno; - return (tcp_close(tp)); -} - -/* - * Close a TCP control block: - * discard all space held by the tcp - * discard internet protocol block - * wake up any sleepers - */ -struct tcpcb * -tcp_close(tp) - register struct tcpcb *tp; -{ - register struct mbuf *q; - register struct mbuf *nq; - struct inpcb *inp = tp->t_inpcb; - struct socket *so = inp->inp_socket; - register struct rtentry *rt; - int dosavessthresh; - - /* - * If we got enough samples through the srtt filter, - * save the rtt and rttvar in the routing entry. - * 'Enough' is arbitrarily defined as the 16 samples. - * 16 samples is enough for the srtt filter to converge - * to within 5% of the correct value; fewer samples and - * we could save a very bogus rtt. - * - * Don't update the default route's characteristics and don't - * update anything that the user "locked". - */ - if (tp->t_rttupdated >= 16 && - (rt = inp->inp_route.ro_rt) && - ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { - register u_long i = 0; - - if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { - i = tp->t_srtt * - (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); - if (rt->rt_rmx.rmx_rtt && i) - /* - * filter this update to half the old & half - * the new values, converting scale. - * See route.h and tcp_var.h for a - * description of the scaling constants. - */ - rt->rt_rmx.rmx_rtt = - (rt->rt_rmx.rmx_rtt + i) / 2; - else - rt->rt_rmx.rmx_rtt = i; - tcpstat.tcps_cachedrtt++; - } - if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { - i = tp->t_rttvar * - (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); - if (rt->rt_rmx.rmx_rttvar && i) - rt->rt_rmx.rmx_rttvar = - (rt->rt_rmx.rmx_rttvar + i) / 2; - else - rt->rt_rmx.rmx_rttvar = i; - tcpstat.tcps_cachedrttvar++; - } - /* - * The old comment here said: - * update the pipelimit (ssthresh) if it has been updated - * already or if a pipesize was specified & the threshhold - * got below half the pipesize. I.e., wait for bad news - * before we start updating, then update on both good - * and bad news. - * - * But we want to save the ssthresh even if no pipesize is - * specified explicitly in the route, because such - * connections still have an implicit pipesize specified - * by the global tcp_sendspace. In the absence of a reliable - * way to calculate the pipesize, it will have to do. - */ - i = tp->snd_ssthresh; - if (rt->rt_rmx.rmx_sendpipe != 0) - dosavessthresh = (i < rt->rt_rmx.rmx_sendpipe / 2); - else - dosavessthresh = (i < so->so_snd.sb_hiwat / 2); - if (((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && - i != 0 && rt->rt_rmx.rmx_ssthresh != 0) - || dosavessthresh) { - /* - * convert the limit from user data bytes to - * packets then to packet data bytes. - */ - i = (i + tp->t_maxseg / 2) / tp->t_maxseg; - if (i < 2) - i = 2; - i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); - if (rt->rt_rmx.rmx_ssthresh) - rt->rt_rmx.rmx_ssthresh = - (rt->rt_rmx.rmx_ssthresh + i) / 2; - else - rt->rt_rmx.rmx_ssthresh = i; - tcpstat.tcps_cachedssthresh++; - } - } - /* free the reassembly queue, if any */ - for (q = tp->t_segq; q; q = nq) { - nq = q->m_nextpkt; - tp->t_segq = nq; - m_freem(q); - } - if (tp->t_template) - (void) m_free(dtom(tp->t_template)); - inp->inp_ppcb = NULL; - soisdisconnected(so); - in_pcbdetach(inp); - tcpstat.tcps_closed++; - return ((struct tcpcb *)0); -} - -void -tcp_drain() -{ - -} - -/* - * Notify a tcp user of an asynchronous error; - * store error as soft error, but wake up user - * (for now, won't do anything until can select for soft error). - */ -static void -tcp_notify(inp, error) - struct inpcb *inp; - int error; -{ - register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; - register struct socket *so = inp->inp_socket; - - /* - * Ignore some errors if we are hooked up. - * If connection hasn't completed, has retransmitted several times, - * and receives a second error, give up now. This is better - * than waiting a long time to establish a connection that - * can never complete. - */ - if (tp->t_state == TCPS_ESTABLISHED && - (error == EHOSTUNREACH || error == ENETUNREACH || - error == EHOSTDOWN)) { - return; - } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 && - tp->t_softerror) - so->so_error = error; - else - tp->t_softerror = error; - wakeup((caddr_t) &so->so_timeo); - sorwakeup(so); - sowwakeup(so); -} - -static int -tcp_pcblist SYSCTL_HANDLER_ARGS -{ - int error, i, n, s; - struct inpcb *inp, **inp_list; - inp_gen_t gencnt; - struct xinpgen xig; - - /* - * The process of preparing the TCB list is too time-consuming and - * resource-intensive to repeat twice on every request. - */ - if (req->oldptr == 0) { - n = tcbinfo.ipi_count; - req->oldidx = 2 * (sizeof xig) - + (n + n/8) * sizeof(struct xtcpcb); - return 0; - } - - if (req->newptr != 0) - return EPERM; - - /* - * OK, now we're committed to doing something. - */ - s = splnet(); - gencnt = tcbinfo.ipi_gencnt; - n = tcbinfo.ipi_count; - splx(s); - - xig.xig_len = sizeof xig; - xig.xig_count = n; - xig.xig_gen = gencnt; - xig.xig_sogen = so_gencnt; - error = SYSCTL_OUT(req, &xig, sizeof xig); - if (error) - return error; - - inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); - if (inp_list == 0) - return ENOMEM; - - s = splnet(); - for (inp = tcbinfo.listhead->lh_first, i = 0; inp && i < n; - inp = inp->inp_list.le_next) { - if (inp->inp_gencnt <= gencnt) - inp_list[i++] = inp; - } - splx(s); - n = i; - - error = 0; - for (i = 0; i < n; i++) { - inp = inp_list[i]; - if (inp->inp_gencnt <= gencnt) { - struct xtcpcb xt; - xt.xt_len = sizeof xt; - /* XXX should avoid extra copy */ - bcopy(inp, &xt.xt_inp, sizeof *inp); - bcopy(inp->inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp); - if (inp->inp_socket) - sotoxsocket(inp->inp_socket, &xt.xt_socket); - error = SYSCTL_OUT(req, &xt, sizeof xt); - } - } - if (!error) { - /* - * Give the user an updated idea of our state. - * If the generation differs from what we told - * her before, she knows that something happened - * while we were processing this request, and it - * might be necessary to retry. - */ - s = splnet(); - xig.xig_gen = tcbinfo.ipi_gencnt; - xig.xig_sogen = so_gencnt; - xig.xig_count = tcbinfo.ipi_count; - splx(s); - error = SYSCTL_OUT(req, &xig, sizeof xig); - } - free(inp_list, M_TEMP); - return error; -} - -SYSCTL_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, - tcp_pcblist, "S,xtcpcb", "List of active TCP connections"); - -void -tcp_ctlinput(cmd, sa, vip) - int cmd; - struct sockaddr *sa; - void *vip; -{ - register struct ip *ip = vip; - register struct tcphdr *th; - void (*notify) __P((struct inpcb *, int)) = tcp_notify; - - if (cmd == PRC_QUENCH) - notify = tcp_quench; - else if (cmd == PRC_MSGSIZE) - notify = tcp_mtudisc; - else if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)) - return; - if (ip) { - th = (struct tcphdr *)((caddr_t)ip - + (IP_VHL_HL(ip->ip_vhl) << 2)); - in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, - cmd, notify); - } else - in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); -} - -/* - * When a source quench is received, close congestion window - * to one segment. We will gradually open it again as we proceed. - */ -void -tcp_quench(inp, errno) - struct inpcb *inp; - int errno; -{ - struct tcpcb *tp = intotcpcb(inp); - - if (tp) - tp->snd_cwnd = tp->t_maxseg; -} - -/* - * When `need fragmentation' ICMP is received, update our idea of the MSS - * based on the new value in the route. Also nudge TCP to send something, - * since we know the packet we just sent was dropped. - * This duplicates some code in the tcp_mss() function in tcp_input.c. - */ -void -tcp_mtudisc(inp, errno) - struct inpcb *inp; - int errno; -{ - struct tcpcb *tp = intotcpcb(inp); - struct rtentry *rt; - struct rmxp_tao *taop; - struct socket *so = inp->inp_socket; - int offered; - int mss; - - if (tp) { - rt = tcp_rtlookup(inp); - if (!rt || !rt->rt_rmx.rmx_mtu) { - tp->t_maxopd = tp->t_maxseg = tcp_mssdflt; - return; - } - taop = rmx_taop(rt->rt_rmx); - offered = taop->tao_mssopt; - mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); - if (offered) - mss = min(mss, offered); - /* - * XXX - The above conditional probably violates the TCP - * spec. The problem is that, since we don't know the - * other end's MSS, we are supposed to use a conservative - * default. But, if we do that, then MTU discovery will - * never actually take place, because the conservative - * default is much less than the MTUs typically seen - * on the Internet today. For the moment, we'll sweep - * this under the carpet. - * - * The conservative default might not actually be a problem - * if the only case this occurs is when sending an initial - * SYN with options and data to a host we've never talked - * to before. Then, they will reply with an MSS value which - * will get recorded and the new parameters should get - * recomputed. For Further Study. - */ - if (tp->t_maxopd <= mss) - return; - tp->t_maxopd = mss; - - if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && - (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP) - mss -= TCPOLEN_TSTAMP_APPA; - if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && - (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC) - mss -= TCPOLEN_CC_APPA; -#if (MCLBYTES & (MCLBYTES - 1)) == 0 - if (mss > MCLBYTES) - mss &= ~(MCLBYTES-1); -#else - if (mss > MCLBYTES) - mss = mss / MCLBYTES * MCLBYTES; -#endif - if (so->so_snd.sb_hiwat < mss) - mss = so->so_snd.sb_hiwat; - - tp->t_maxseg = mss; - - tcpstat.tcps_mturesent++; - tp->t_rtt = 0; - tp->snd_nxt = tp->snd_una; - tcp_output(tp); - } -} - -/* - * Look-up the routing entry to the peer of this inpcb. If no route - * is found and it cannot be allocated the return NULL. This routine - * is called by TCP routines that access the rmx structure and by tcp_mss - * to get the interface MTU. - */ -struct rtentry * -tcp_rtlookup(inp) - struct inpcb *inp; -{ - struct route *ro; - struct rtentry *rt; - - ro = &inp->inp_route; - rt = ro->ro_rt; - if (rt == NULL || !(rt->rt_flags & RTF_UP)) { - /* No route yet, so try to acquire one */ - if (inp->inp_faddr.s_addr != INADDR_ANY) { - ro->ro_dst.sa_family = AF_INET; - ro->ro_dst.sa_len = sizeof(ro->ro_dst); - ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = - inp->inp_faddr; - rtalloc(ro); - rt = ro->ro_rt; - } - } - return rt; -} - -/* - * Return a pointer to the cached information about the remote host. - * The cached information is stored in the protocol specific part of - * the route metrics. - */ -struct rmxp_tao * -tcp_gettaocache(inp) - struct inpcb *inp; -{ - struct rtentry *rt = tcp_rtlookup(inp); - - /* Make sure this is a host route and is up. */ - if (rt == NULL || - (rt->rt_flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)) - return NULL; - - return rmx_taop(rt->rt_rmx); -} - -/* - * Clear all the TAO cache entries, called from tcp_init. - * - * XXX - * This routine is just an empty one, because we assume that the routing - * routing tables are initialized at the same time when TCP, so there is - * nothing in the cache left over. - */ -static void -tcp_cleartaocache() -{ -} |