summaryrefslogtreecommitdiffstats
path: root/sys/netinet/libalias
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/libalias')
-rw-r--r--sys/netinet/libalias/HISTORY129
-rw-r--r--sys/netinet/libalias/Makefile14
-rw-r--r--sys/netinet/libalias/alias.c1147
-rw-r--r--sys/netinet/libalias/alias.h173
-rw-r--r--sys/netinet/libalias/alias_db.c2239
-rw-r--r--sys/netinet/libalias/alias_ftp.c227
-rw-r--r--sys/netinet/libalias/alias_irc.c316
-rw-r--r--sys/netinet/libalias/alias_local.h105
-rw-r--r--sys/netinet/libalias/alias_nbt.c576
-rw-r--r--sys/netinet/libalias/alias_old.c77
-rw-r--r--sys/netinet/libalias/alias_util.c137
-rw-r--r--sys/netinet/libalias/libalias.3768
12 files changed, 5908 insertions, 0 deletions
diff --git a/sys/netinet/libalias/HISTORY b/sys/netinet/libalias/HISTORY
new file mode 100644
index 0000000..3d97fd0
--- /dev/null
+++ b/sys/netinet/libalias/HISTORY
@@ -0,0 +1,129 @@
+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
new file mode 100644
index 0000000..8147665
--- /dev/null
+++ b/sys/netinet/libalias/Makefile
@@ -0,0 +1,14 @@
+LIB= alias
+SHLIB_MAJOR= 2
+SHLIB_MINOR= 5
+CFLAGS+=-Wall -I${.CURDIR}
+SRCS= alias.c alias_db.c alias_ftp.c alias_irc.c alias_util.c alias_old.c \
+ alias_nbt.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
new file mode 100644
index 0000000..f0c0804
--- /dev/null
+++ b/sys/netinet/libalias/alias.c
@@ -0,0 +1,1147 @@
+/* -*- 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.
+
+ 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
+
+/*
+ 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;
+
+ 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 )
+ {
+ 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 )
+ {
+ AliasHandleUdpNbtNS(pip, link,
+ &alias_address,
+ &alias_port,
+ &original_address,
+ &ud->uh_dport );
+ }
+
+/* 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;
+ 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 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
new file mode 100644
index 0000000..010db98
--- /dev/null
+++ b/sys/netinet/libalias/alias.h
@@ -0,0 +1,173 @@
+/*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_db.c b/sys/netinet/libalias/alias_db.c
new file mode 100644
index 0000000..7bbb191
--- /dev/null
+++ b/sys/netinet/libalias/alias_db.c
@@ -0,0 +1,2239 @@
+/* -*- 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 (packetAliasMode & PKT_ALIAS_LOG)
+ {
+ 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);
+ 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
new file mode 100644
index 0000000..c6d449d
--- /dev/null
+++ b/sys/netinet/libalias/alias_ftp.c
@@ -0,0 +1,227 @@
+/*
+ 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
new file mode 100644
index 0000000..910e934
--- /dev/null
+++ b/sys/netinet/libalias/alias_irc.c
@@ -0,0 +1,316 @@
+/* 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
new file mode 100644
index 0000000..16d0aaa
--- /dev/null
+++ b/sys/netinet/libalias/alias_local.h
@@ -0,0 +1,105 @@
+/* -*- 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 );
+void AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short);
+void AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *);
+
+
+
+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
new file mode 100644
index 0000000..f3581a7
--- /dev/null
+++ b/sys/netinet/libalias/alias_nbt.c
@@ -0,0 +1,576 @@
+/*
+ * 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:$
+ *
+ * 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 ) {
+
+ u_char *s;
+ u_char c;
+ int compress;
+
+ /* Following length field */
+ if (*p & 0xc0 ) {
+ p = p + 2;
+ 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);
+#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 */
+ 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
+
+void 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;
+
+ /* Calculate data length of UDP packet */
+ uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
+ ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
+#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 ); /* Source Name */
+ p = AliasHandleName ( p ); /* 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 ); /* Destination Name */
+ break;
+ }
+#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
+}
+/* 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,
+ NBTArguments *nbtarg)
+{
+
+ while ( count != 0 ) {
+ /* Name Filed */
+ q = (NBTNsQuestion *)AliasHandleName((u_char *)q );
+
+ /* 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,
+ NBTArguments *nbtarg)
+{
+ NBTNsRNB *nb;
+ u_short bcount;
+
+ /* 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 ( bcount != 0 ) {
+#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;
+ }
+
+ return ((u_char *)nb);
+}
+
+#define SizeOfResourceA 6
+typedef struct {
+ struct in_addr addr;
+} NBTNsResourceA;
+
+u_char *AliasHandleResourceA( NBTNsResource *q,
+ NBTArguments *nbtarg)
+{
+ NBTNsResourceA *a;
+ u_short bcount;
+
+ /* 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 ) {
+#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;
+ }
+ return ((u_char *)a);
+}
+
+typedef struct {
+ u_short opcode:4, flags:8, resv:4;
+} NBTNsResourceNULL;
+
+u_char *AliasHandleResourceNULL( NBTNsResource *q,
+ NBTArguments *nbtarg)
+{
+ NBTNsResourceNULL *n;
+ u_short bcount;
+
+ /* 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 ) {
+ n++;
+ bcount -= sizeof(NBTNsResourceNULL);
+ }
+
+ return ((u_char *)n);
+}
+
+u_char *AliasHandleResourceNS( NBTNsResource *q,
+ NBTArguments *nbtarg)
+{
+ NBTNsResourceNULL *n;
+ u_short bcount;
+
+ /* 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 ); /* XXX */
+
+ return ((u_char *)n + bcount);
+}
+
+typedef struct {
+ u_short numnames;
+} NBTNsResourceNBSTAT;
+
+u_char *AliasHandleResourceNBSTAT( NBTNsResource *q,
+ NBTArguments *nbtarg)
+{
+ NBTNsResourceNBSTAT *n;
+ u_short bcount;
+
+ /* Forward to Resource NBSTAT position */
+ n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
+
+ /* Check out of length */
+ bcount = ntohs(q->rdlen);
+
+ return ((u_char *)n + bcount);
+}
+
+u_char *AliasHandleResource(u_short count,
+ NBTNsResource *q,
+ NBTArguments *nbtarg)
+{
+ while ( count != 0 ) {
+ /* Resource Record Name Filed */
+ q = (NBTNsResource *)AliasHandleName( (u_char *)q );
+#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, nbtarg );
+ break;
+ case RR_TYPE_A:
+ q = (NBTNsResource *)AliasHandleResourceA( q, nbtarg );
+ break;
+ case RR_TYPE_NS:
+ q = (NBTNsResource *)AliasHandleResourceNS( q, nbtarg );
+ break;
+ case RR_TYPE_NULL:
+ q = (NBTNsResource *)AliasHandleResourceNULL( q, nbtarg );
+ break;
+ case RR_TYPE_NBSTAT:
+ q = (NBTNsResource *)AliasHandleResourceNBSTAT( q, nbtarg );
+ break;
+ default: printf("\nUnknown Type of Resource %0x\n",
+ ntohs(q->type) );
+ break;
+ }
+ count--;
+ }
+ fflush(stdout);
+ return ((u_char *)q);
+}
+
+void 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_short dlen;
+ u_char * p;
+ 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);
+ dlen = ntohs( uh->uh_ulen );
+ nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
+ p = (u_char *)(nsh + 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, &nbtarg );
+ }
+
+ /* Answer Resource Records */
+ if (ntohs(nsh->ancount) !=0 ) {
+ p = AliasHandleResource(ntohs(nsh->ancount), (NBTNsResource *)p, &nbtarg );
+ }
+
+ /* Authority Resource Recodrs */
+ if (ntohs(nsh->nscount) !=0 ) {
+ p = AliasHandleResource(ntohs(nsh->nscount), (NBTNsResource *)p, &nbtarg );
+ }
+
+ /* Additional Resource Recodrs */
+ if (ntohs(nsh->arcount) !=0 ) {
+ p = AliasHandleResource(ntohs(nsh->arcount), (NBTNsResource *)p, &nbtarg );
+ }
+
+#ifdef DEBUG
+ PrintRcode(nsh->rcode);
+#endif
+ return;
+}
diff --git a/sys/netinet/libalias/alias_old.c b/sys/netinet/libalias/alias_old.c
new file mode 100644
index 0000000..3f634d4
--- /dev/null
+++ b/sys/netinet/libalias/alias_old.c
@@ -0,0 +1,77 @@
+/*
+ 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
new file mode 100644
index 0000000..fe07653
--- /dev/null
+++ b/sys/netinet/libalias/alias_util.c
@@ -0,0 +1,137 @@
+/*
+ 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
new file mode 100644
index 0000000..b3fcc91
--- /dev/null
+++ b/sys/netinet/libalias/libalias.3
@@ -0,0 +1,768 @@
+.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 PacketAliasOut()
+ 3.2 PacketAliasIn()
+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 PacketAliasIn "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.
+
OpenPOWER on IntegriCloud