summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>1997-05-23 04:41:31 +0000
committerbrian <brian@FreeBSD.org>1997-05-23 04:41:31 +0000
commitce3ace26df6c870e4bf92d045835c796257cfa6f (patch)
tree8a2a8b1cbd664a0196de827b84f6cb57956a9e93
parent06bdbfe53903bf424f310df2f18d3870279c6841 (diff)
parentcf067e235ad379654a27faa2ed5d9368e611a7ec (diff)
downloadFreeBSD-src-ce3ace26df6c870e4bf92d045835c796257cfa6f.zip
FreeBSD-src-ce3ace26df6c870e4bf92d045835c796257cfa6f.tar.gz
This commit was generated by cvs2svn to compensate for changes in r26026,
which included commits to RCS files with non-trunk default branches.
-rw-r--r--lib/libalias/Makefile11
-rw-r--r--lib/libalias/alias.c1142
-rw-r--r--lib/libalias/alias.h102
-rw-r--r--lib/libalias/alias_db.c1972
-rw-r--r--lib/libalias/alias_ftp.c220
-rw-r--r--lib/libalias/alias_irc.c311
-rw-r--r--lib/libalias/alias_local.h91
-rw-r--r--lib/libalias/alias_util.c135
8 files changed, 3984 insertions, 0 deletions
diff --git a/lib/libalias/Makefile b/lib/libalias/Makefile
new file mode 100644
index 0000000..6081e48
--- /dev/null
+++ b/lib/libalias/Makefile
@@ -0,0 +1,11 @@
+LIB= alias
+SHLIB_MAJOR= 2
+SHLIB_MINOR= 1
+CFLAGS+=-Wall -I${.CURDIR}
+SRCS= alias.c alias_db.c alias_ftp.c alias_irc.c alias_util.c
+
+beforeinstall:
+ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/alias.h \
+ ${DESTDIR}/usr/include
+
+.include <bsd.lib.mk>
diff --git a/lib/libalias/alias.c b/lib/libalias/alias.c
new file mode 100644
index 0000000..1a9eb36
--- /dev/null
+++ b/lib/libalias/alias.c
@@ -0,0 +1,1142 @@
+/* -*- 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).
+*/
+
+#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 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 0:
+ if (tc->th_flags & TH_SYN) SetStateIn(link, 1);
+ break;
+ case 1:
+ if (tc->th_flags & TH_FIN
+ || tc->th_flags & TH_RST) SetStateIn(link, 2);
+ }
+}
+
+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 0:
+ if (tc->th_flags & TH_SYN) SetStateOut(link, 1);
+ break;
+ case 1:
+ if (tc->th_flags & TH_FIN
+ || tc->th_flags & TH_RST) SetStateOut(link, 2);
+ }
+}
+
+
+
+
+
+/* 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 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 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 TCP 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
+
+ SaveFragmentPtr()
+ GetNextFragmentPtr()
+ FragmentAliasIn()
+ PacketAliasIn()
+ PacketAliasOut()
+ PacketAliasIn2()
+ PacketAliasOut2()
+
+(prototypes in alias.h)
+*/
+
+
+int
+SaveFragmentPtr(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 *
+GetNextFragmentPtr(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);
+ SetExpire(link, 0); /* Deletes link */
+
+ return(fptr);
+ }
+ else
+ {
+ return(NULL);
+ }
+}
+
+
+void
+FragmentAliasIn(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();
+ pip = (struct ip *) ptr;
+ alias_addr = pip->ip_dst;
+
+ 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();
+ pip = (struct ip *) ptr;
+
+ 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);
+}
+
+
+int
+PacketAliasIn2(char *ptr, /* valid IP packet */
+ struct in_addr addr, /* Default aliasing address */
+ int maxpacketsize /* How much the packet data may grow
+ (FTP and IRC inline changes) */
+ )
+{
+ int result_code;
+ struct in_addr addr_save;
+
+ ClearNewDefaultLink();
+ addr_save = GetDefaultAliasAddress();
+
+ SetDefaultTargetAddress(addr);
+ result_code = PacketAliasIn(ptr, maxpacketsize);
+ ClearDefaultTargetAddress();
+
+ if (result_code == PKT_ALIAS_OK)
+ {
+ if (CheckNewDefaultLink())
+ return PKT_ALIAS_NEW_LINK;
+ }
+
+ return result_code;
+}
+
+
+int
+PacketAliasOut2(char *ptr, /* valid IP packet */
+ struct in_addr addr, /* Default aliasing address */
+ int maxpacketsize /* How much the packet data may grow
+ (FTP and IRC inline changes) */
+ )
+{
+ int result_code;
+ struct in_addr addr_save;
+
+ ClearNewDefaultLink();
+ addr_save = GetDefaultAliasAddress();
+
+ SetDefaultAliasAddress(addr);
+ result_code = PacketAliasOut(ptr, maxpacketsize);
+ SetDefaultAliasAddress(addr_save);
+
+ if (result_code == PKT_ALIAS_OK)
+ {
+ if (CheckNewDefaultLink())
+ return PKT_ALIAS_NEW_LINK;
+ }
+
+ return result_code;
+}
diff --git a/lib/libalias/alias.h b/lib/libalias/alias.h
new file mode 100644
index 0000000..0063802
--- /dev/null
+++ b/lib/libalias/alias.h
@@ -0,0 +1,102 @@
+/*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.
+*/
+
+
+#ifndef _ALIAS_H_
+#define _ALIAS_H_
+
+/* Alias link representativei (incomplete struct) */
+struct alias_link;
+
+/* External interfaces (API) to packet aliasing engine */
+extern int SaveFragmentPtr(char *);
+extern char *GetNextFragmentPtr(char *);
+extern void FragmentAliasIn(char *, char *);
+extern int PacketAliasIn(char *, int maxpacketsize);
+extern int PacketAliasOut(char *, int maxpacketsize);
+extern int PacketAliasIn2(char *, struct in_addr, int maxpacketsize);
+extern int PacketAliasOut2(char *, struct in_addr, int maxpacketsize);
+extern void SetPacketAliasAddress(struct in_addr);
+extern void InitPacketAlias(void);
+extern void InitPacketAliasLog(void);
+extern void UninitPacketAliasLog(void);
+extern unsigned int SetPacketAliasMode(unsigned int, unsigned int);
+extern struct alias_link *
+PacketAliasRedirectPort(struct in_addr, u_short,
+ struct in_addr, u_short,
+ struct in_addr, u_short,
+ u_char);
+extern int
+PacketAliasPermanentLink(struct in_addr, u_short,
+ struct in_addr, u_short,
+ u_short, u_char);
+extern struct alias_link *
+PacketAliasRedirectAddr(struct in_addr,
+ struct in_addr);
+void PacketAliasRedirectDelete(struct alias_link *);
+
+
+/* InternetChecksum() is not specifically part of the
+ packet aliasing API, but is sometimes needed outside
+ the module. (~for instance, natd uses it to create
+ an ICMP error message when interface size is
+ exceeded.) */
+
+extern u_short InternetChecksum(u_short *, int);
+
+
+/********************** 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 1
+
+/* 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 2
+
+/* If PKT_ALIAS_SAME_PORTS is set, packets will be attempted sent from
+ the same port as they originated on. This allow eg rsh to work
+ *99% of the time*, but _not_ 100%. (It will be slightly flakey
+ instead of not working at all.) */
+#define PKT_ALIAS_SAME_PORTS 4
+
+/* 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. */
+#define PKT_ALIAS_USE_SOCKETS 8
+
+/* 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 16
+
+
+
+/* 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
+#define PKT_ALIAS_NEW_LINK 5
+
+#endif
+/*lint -restore */
diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c
new file mode 100644
index 0000000..dafd9f8
--- /dev/null
+++ b/lib/libalias/alias_db.c
@@ -0,0 +1,1972 @@
+/* -*- 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. Eiklund 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.
+*/
+
+
+/* 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 TCP_EXPIRE_TIME 90
+#define FRAGMENT_ID_EXPIRE_TIME 10
+#define FRAGMENT_PTR_EXPIRE_TIME 30
+
+/* 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];
+};
+
+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 */
+
+ 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 */
+ {
+ struct in_addr frag_addr;
+ char *frag_ptr;
+ 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 firstCall = 1; /* Needed by InitAlias() */
+
+static int newDefaultLink; /* Indicates if a new aliasing */
+ /* link has been created after a */
+ /* call to PacketAliasIn/Out(). */
+
+
+
+
+
+
+/* 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);
+
+
+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
+
+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 *
+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
+ {
+ 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];
+ linkTableOut[i] = NULL;
+ 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 != 1
+ || tcp_aux->state.out != 1)
+ {
+ 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;
+
+/* 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--;
+ 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_TIME;
+ 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 = 0;
+ aux_tcp->state.out = 0;
+ 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;
+ }
+ 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 *
+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)
+ {
+ if (replace_partial_links)
+ {
+ link = AddLink(link_unknown_dst_port->src_addr, dst_addr,
+ alias_addr,
+ link_unknown_dst_port->src_port, dst_port,
+ alias_port, link_type);
+ DeleteLink(link_unknown_dst_port);
+ return(link);
+ }
+ else
+ {
+ return(link_unknown_dst_port);
+ }
+ }
+ else if (link_unknown_dst_addr != NULL)
+ {
+ if (replace_partial_links)
+ {
+ link = AddLink(link_unknown_dst_addr->src_addr, dst_addr,
+ alias_addr,
+ link_unknown_dst_addr->src_port, dst_port,
+ alias_port, link_type);
+ DeleteLink(link_unknown_dst_addr);
+ return(link);
+ }
+ else
+ {
+ return(link_unknown_dst_addr);
+ }
+ }
+ else if (link_unknown_all != NULL)
+ {
+ if (replace_partial_links)
+ {
+ link = AddLink(link_unknown_all->src_addr, dst_addr,
+ alias_addr,
+ link_unknown_all->src_port, dst_port,
+ alias_port, link_type);
+ DeleteLink(link_unknown_all);
+ return(link);
+ }
+ else
+ {
+ return(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()
+ ClearNewLink()
+ CheckNewLink()
+*/
+
+
+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 */
+ (link->data.tcp)->state.in = state;
+}
+
+
+void
+SetStateOut(struct alias_link *link, int state)
+{
+ /* TCP output state */
+ (link->data.tcp)->state.out = state;
+}
+
+
+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;
+}
+
+
+void
+SetDefaultTargetAddress(struct in_addr target_addr)
+{
+ targetAddress = target_addr;
+}
+
+
+void ClearDefaultTargetAddress(void)
+{
+ targetAddress.s_addr = 0;
+}
+
+
+u_short
+GetOriginalPort(struct alias_link *link)
+{
+ return(link->src_port);
+}
+
+
+u_short
+GetAliasPort(struct alias_link *link)
+{
+ return(link->alias_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
+ClearNewDefaultLink(void)
+{
+ newDefaultLink = 0;
+}
+
+
+int
+CheckNewDefaultLink(void)
+{
+ return newDefaultLink;
+}
+
+
+
+/*
+ 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;
+ }
+}
+
+
+
+
+
+/* Outside world interfaces
+
+-- "outside world" means other than alias*.c routines --
+
+ PacketAliasRedirectPort()
+ PacketAliasRedirectAddr()
+ SetPacketAliasAddress()
+ InitPacketAliasLog()
+ UninitPacketAliasLog()
+ InitPacketAlias()
+ SetPacketAliasMode()
+
+(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;
+}
+
+
+/* This function is slightly less generalized than
+ PacketAliasRedirectPort and is included for backwards
+ compatibility */
+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;
+
+ link = PacketAliasRedirectPort(src_addr, src_port,
+ dst_addr, dst_port,
+ nullAddress, alias_port,
+ proto);
+
+ if (link == NULL)
+ return -1;
+ else
+ return 0;
+}
+
+
+/* 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 very dangerous function to put in the API,
+ because an invalid pointer can crash the program. */
+
+ deleteAllLinks = 1;
+ DeleteLink(link);
+ deleteAllLinks = 0;
+}
+
+
+void
+SetPacketAliasAddress(struct in_addr addr)
+{
+ if (aliasAddress.s_addr != addr.s_addr)
+ {
+ CleanupAliasData();
+ aliasAddress = addr;
+ }
+}
+
+
+/* Init the log file and enable logging */
+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. */
+void
+UninitPacketAliasLog(void)
+{
+ if( monitorFile )
+ fclose(monitorFile);
+ packetAliasMode &= ~PKT_ALIAS_LOG;
+}
+
+
+void
+InitPacketAlias(void)
+{
+ int i;
+ struct timeval tv;
+ struct timezone tz;
+
+ 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;
+
+ firstCall = 0;
+ }
+ else
+ {
+ deleteAllLinks = 1;
+ CleanupAliasData();
+ deleteAllLinks = 0;
+ }
+
+ aliasAddress.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;
+
+ if (packetAliasMode & PKT_ALIAS_LOG)
+ {
+ InitPacketAliasLog();
+ fprintf(monitorFile, "Packet aliasing initialized.\n");
+ }
+}
+
+
+/* Change mode for some operations */
+unsigned int
+SetPacketAliasMode
+(
+ 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 */
+ }
+/* _Disable_ logging? */
+ if (~flags & mask & PKT_ALIAS_LOG) {
+ UninitPacketAliasLog();
+ }
+
+/* Other flags can be set/cleared without special action */
+ packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
+ return packetAliasMode;
+}
+
+
+/*
+ Clear all packet aliasing links, but leave mode
+ flags unchanged. Typically used when the interface
+ address changes and all existing links become
+ invalid.
+*/
diff --git a/lib/libalias/alias_ftp.c b/lib/libalias/alias_ftp.c
new file mode 100644
index 0000000..e03c04b
--- /dev/null
+++ b/lib/libalias/alias_ftp.c
@@ -0,0 +1,220 @@
+/*
+ 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.
+*/
+
+/* 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;
+
+/* 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 = (char *) &alias_address;
+ 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/lib/libalias/alias_irc.c b/lib/libalias/alias_irc.c
new file mode 100644
index 0000000..3657368
--- /dev/null
+++ b/lib/libalias/alias_irc.c
@@ -0,0 +1,311 @@
+/* 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 */
+
+ alias_address = GetAliasAddress(link);
+ iCopy += snprintf(&newpacket[iCopy],
+ sizeof(newpacket)-iCopy,
+ "%lu ", 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/lib/libalias/alias_local.h b/lib/libalias/alias_local.h
new file mode 100644
index 0000000..dd1a2f4
--- /dev/null
+++ b/lib/libalias/alias_local.h
@@ -0,0 +1,91 @@
+/* -*- 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>
+*/
+
+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);
+void SetDefaultTargetAddress(struct in_addr);
+void ClearDefaultTargetAddress(void);
+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 ClearNewDefaultLink(void);
+int CheckNewDefaultLink(void);
+
+/* 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 );
+/*lint -restore */
diff --git a/lib/libalias/alias_util.c b/lib/libalias/alias_util.c
new file mode 100644
index 0000000..e5906ca
--- /dev/null
+++ b/lib/libalias/alias_util.c
@@ -0,0 +1,135 @@
+/*
+ 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_local.h"
+
+u_short
+InternetChecksum(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( InternetChecksum((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;
+ }
+}
+
OpenPOWER on IntegriCloud