From 087590fb63a5b25c88d45340abc88c8c425db6be Mon Sep 17 00:00:00 2001 From: brian Date: Sat, 27 Feb 1999 02:16:01 +0000 Subject: Version 3.0: January 1, 1999 - Transparent proxying support added. - PPTP redirecting support added based on patches contributed by Dru Nelson . Submitted by: Charles Mott --- lib/libalias/HISTORY | 5 + lib/libalias/Makefile | 8 +- lib/libalias/alias.c | 242 +++++++++++--- lib/libalias/alias.h | 39 +-- lib/libalias/alias_db.c | 108 ++++-- lib/libalias/alias_local.h | 71 +++- lib/libalias/alias_proxy.c | 801 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1176 insertions(+), 98 deletions(-) create mode 100644 lib/libalias/alias_proxy.c (limited to 'lib/libalias') diff --git a/lib/libalias/HISTORY b/lib/libalias/HISTORY index 3d97fd0..575d1b4 100644 --- a/lib/libalias/HISTORY +++ b/lib/libalias/HISTORY @@ -127,3 +127,8 @@ Version 2.5: December, 1997 (ee) Version 2.6: May, 1998 (amurai) - Added supporting routine for NetBios over TCP/IP. + +Version 3.0: January 1, 1999 + - Transparent proxying support added. + - PPTP redirecting support added based on patches + contributed by Dru Nelson . diff --git a/lib/libalias/Makefile b/lib/libalias/Makefile index 665d14e..ea69664 100644 --- a/lib/libalias/Makefile +++ b/lib/libalias/Makefile @@ -1,11 +1,11 @@ -# $Id$ +# $Id: Makefile,v 1.9 1998/08/31 12:14:30 brian Exp $ LIB= alias -SHLIB_MAJOR= 2 -SHLIB_MINOR= 5 +SHLIB_MAJOR= 3 +SHLIB_MINOR= 0 CFLAGS+= -Wall -I${.CURDIR} SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \ - alias_nbt.c alias_old.c alias_util.c + alias_nbt.c alias_proxy.c alias_util.c MAN3= libalias.3 beforeinstall: diff --git a/lib/libalias/alias.c b/lib/libalias/alias.c index 50e597f..13d972c 100644 --- a/lib/libalias/alias.c +++ b/lib/libalias/alias.c @@ -93,6 +93,10 @@ #include #include +#ifndef IPPROTO_GRE +#define IPPROTO_GRE 47 +#endif + #include "alias_local.h" #include "alias.h" @@ -104,38 +108,13 @@ #define IRC_CONTROL_PORT_NUMBER_2 6668 #define CUSEEME_PORT_NUMBER 7648 -/* - The following macro is used to update an - internet checksum. "delta" is a 32-bit - accumulation of all the changes to the - checksum (adding in new 16-bit words and - subtracting out old words), and "cksum" - is the checksum value to be updated. -*/ -#define ADJUST_CHECKSUM(acc, cksum) { \ - acc += cksum; \ - if (acc < 0) \ - { \ - acc = -acc; \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) ~acc; \ - } \ - else \ - { \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) acc; \ - } \ -} - /* TCP Handling Routines TcpMonitorIn() -- These routines monitor TCP connections, and - TcpMonitorOut() -- delete a link node when a connection is closed. + TcpMonitorOut() delete a link 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 @@ -406,7 +385,6 @@ fragment contained in ICMP data section */ return(PKT_ALIAS_IGNORED); } - static int IcmpAliasIn3(struct ip *pip) { @@ -429,6 +407,10 @@ IcmpAliasIn(struct ip *pip) int iresult; struct icmp *ic; +/* Return if proxy-only mode is enabled */ + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) + return PKT_ALIAS_OK; + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); iresult = PKT_ALIAS_IGNORED; @@ -563,6 +545,10 @@ IcmpAliasOut(struct ip *pip) int iresult; struct icmp *ic; +/* Return if proxy-only mode is enabled */ + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) + return PKT_ALIAS_OK; + ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); iresult = PKT_ALIAS_IGNORED; @@ -588,12 +574,73 @@ IcmpAliasOut(struct ip *pip) return(iresult); } + + +static int +PptpAliasIn(struct ip *pip) +{ +/* + Handle incoming PPTP packets. The + only thing which is done in this case is to alias + the dest IP address of the packet to our inside + machine. +*/ + struct in_addr alias_addr; + + if (!GetPptpAlias (&alias_addr)) + return PKT_ALIAS_IGNORED; + + if (pip->ip_src.s_addr != alias_addr.s_addr) { + + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_addr, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = alias_addr; + } + + return PKT_ALIAS_OK; +} + + +static int +PptpAliasOut(struct ip *pip) +{ +/* + Handle outgoing PPTP packets. The + only thing which is done in this case is to alias + the source IP address of the packet. +*/ + struct in_addr alias_addr; + + if (!GetPptpAlias (&alias_addr)) + return PKT_ALIAS_IGNORED; + + if (pip->ip_src.s_addr == alias_addr.s_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 UdpAliasIn(struct ip *pip) { struct udphdr *ud; struct alias_link *link; +/* Return if proxy-only mode is enabled */ + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) + return PKT_ALIAS_OK; + ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, @@ -670,6 +717,10 @@ UdpAliasOut(struct ip *pip) struct udphdr *ud; struct alias_link *link; +/* Return if proxy-only mode is enabled */ + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) + return PKT_ALIAS_OK; + ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, @@ -751,14 +802,18 @@ TcpAliasIn(struct ip *pip) { struct in_addr alias_address; struct in_addr original_address; + struct in_addr proxy_address; u_short alias_port; + u_short proxy_port; int accumulate; u_short *sptr; alias_address = GetAliasAddress(link); original_address = GetOriginalAddress(link); + proxy_address = GetProxyAddress(link); alias_port = tc->th_dport; tc->th_dport = GetOriginalPort(link); + proxy_port = GetProxyPort(link); /* Adjust TCP checksum since destination port is being unaliased */ /* and destination port is being altered. */ @@ -771,6 +826,22 @@ TcpAliasIn(struct ip *pip) accumulate -= *sptr++; accumulate -= *sptr; +/* If this is a proxy, then modify the tcp source port and + checksum accumulation */ + if (proxy_port != 0) + { + accumulate += tc->th_sport; + tc->th_sport = proxy_port; + accumulate -= tc->th_sport; + + sptr = (u_short *) &pip->ip_src; + accumulate += *sptr++; + accumulate += *sptr; + sptr = (u_short *) &proxy_address; + accumulate -= *sptr++; + accumulate -= *sptr; + } + /* See if ack number needs to be modified */ if (GetAckModified(link) == 1) { @@ -792,11 +863,28 @@ TcpAliasIn(struct ip *pip) ADJUST_CHECKSUM(accumulate, tc->th_sum); /* Restore original IP address */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); + sptr = (u_short *) &pip->ip_dst; + accumulate = *sptr++; + accumulate += *sptr; pip->ip_dst = original_address; + sptr = (u_short *) &pip->ip_dst; + accumulate -= *sptr++; + accumulate -= *sptr; + +/* If this is a transparent proxy packet, then modify the source + address */ + if (proxy_address.s_addr != 0) + { + sptr = (u_short *) &pip->ip_src; + accumulate += *sptr++; + accumulate += *sptr; + pip->ip_src = proxy_address; + sptr = (u_short *) &pip->ip_src; + accumulate -= *sptr++; + accumulate -= *sptr; + } + + ADJUST_CHECKSUM(accumulate, pip->ip_sum); /* Monitor TCP connection state */ TcpMonitorIn(pip, link); @@ -809,39 +897,94 @@ TcpAliasIn(struct ip *pip) static int TcpAliasOut(struct ip *pip, int maxpacketsize) { + int proxy_type; + u_short dest_port; + u_short proxy_server_port; + struct in_addr dest_address; + struct in_addr proxy_server_address; struct tcphdr *tc; struct alias_link *link; tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + proxy_type = ProxyCheck(pip, &proxy_server_address, &proxy_server_port); + + if (proxy_type == 0 && (packetAliasMode & PKT_ALIAS_PROXY_ONLY)) + return PKT_ALIAS_OK; + +/* If this is a transparent proxy, save original destination, + then alter the destination and adust checksums */ + dest_port = tc->th_dport; + dest_address = pip->ip_dst; + if (proxy_type != 0) + { + int accumulate; + u_short *sptr; + + accumulate = tc->th_dport; + tc->th_dport = proxy_server_port; + accumulate -= tc->th_dport; + + sptr = (u_short *) &(pip->ip_dst); + accumulate += *sptr++; + accumulate += *sptr; + sptr = (u_short *) &proxy_server_address; + accumulate -= *sptr++; + accumulate -= *sptr; + + ADJUST_CHECKSUM(accumulate, tc->th_sum); + + sptr = (u_short *) &(pip->ip_dst); + accumulate = *sptr++; + accumulate += *sptr; + pip->ip_dst = proxy_server_address; + sptr = (u_short *) &(pip->ip_dst); + accumulate -= *sptr++; + accumulate -= *sptr; + + ADJUST_CHECKSUM(accumulate, pip->ip_sum); + } + 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; + struct in_addr alias_address; int accumulate; u_short *sptr; +/* Save original destination address, if this is a proxy packet. + Also modify packet to include destination encoding. */ + if (proxy_type != 0) + { + SetProxyPort(link, dest_port); + SetProxyAddress(link, dest_address); + ProxyModify(link, pip, maxpacketsize, proxy_type); + } + +/* Get alias address and port */ alias_port = GetAliasPort(link); alias_address = GetAliasAddress(link); /* Monitor tcp connection state */ TcpMonitorOut(pip, link); -/* Special processing for ftp connection */ +/* Special processing for IP encoding protocols */ 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) + || 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; + tc->th_sport = alias_port; + accumulate -= tc->th_sport; + sptr = (u_short *) &(pip->ip_src); accumulate += *sptr++; accumulate += *sptr; @@ -869,15 +1012,16 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) 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); + sptr = (u_short *) &(pip->ip_src); + accumulate = *sptr++; + accumulate += *sptr; pip->ip_src = alias_address; + sptr = (u_short *) &(pip->ip_src); + accumulate -= *sptr++; + accumulate -= *sptr; + + ADJUST_CHECKSUM(accumulate, pip->ip_sum) return(PKT_ALIAS_OK); } @@ -1031,6 +1175,9 @@ PacketAliasIn(char *ptr, int maxpacketsize) struct ip *pip; int iresult; + if (packetAliasMode & PKT_ALIAS_REVERSE) + return PacketAliasOut(ptr, maxpacketsize); + HouseKeeping(); ClearCheckNewLink(); pip = (struct ip *) ptr; @@ -1055,6 +1202,9 @@ PacketAliasIn(char *ptr, int maxpacketsize) case IPPROTO_TCP: iresult = TcpAliasIn(pip); break; + case IPPROTO_GRE: + iresult = PptpAliasIn(pip); + break; } if (ntohs(pip->ip_off) & IP_MF) @@ -1097,8 +1247,6 @@ PacketAliasIn(char *ptr, int maxpacketsize) #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 @@ -1109,6 +1257,9 @@ PacketAliasOut(char *ptr, /* valid IP packet */ struct in_addr addr_save; struct ip *pip; + if (packetAliasMode & PKT_ALIAS_REVERSE) + return PacketAliasIn(ptr, maxpacketsize); + HouseKeeping(); ClearCheckNewLink(); pip = (struct ip *) ptr; @@ -1153,6 +1304,9 @@ PacketAliasOut(char *ptr, /* valid IP packet */ case IPPROTO_TCP: iresult = TcpAliasOut(pip, maxpacketsize); break; + case IPPROTO_GRE: + iresult = PptpAliasOut(pip); + break; } } else diff --git a/lib/libalias/alias.h b/lib/libalias/alias.h index 010db98..14325f4 100644 --- a/lib/libalias/alias.h +++ b/lib/libalias/alias.h @@ -7,7 +7,7 @@ This software is placed into the public domain with no restrictions on its distribution. - $Id: alias.h,v 1.7 1998/01/16 12:56:07 bde Exp $ + $Id: alias.h,v 1.8 1998/04/19 21:42:05 brian Exp $ */ @@ -55,6 +55,10 @@ struct alias_link; struct in_addr, u_short, u_char); + extern int + PacketAliasPptp(struct in_addr); + + extern struct alias_link * PacketAliasRedirectAddr(struct in_addr, struct in_addr); @@ -82,28 +86,10 @@ struct alias_link; extern u_short PacketAliasInternetChecksum(u_short *, int); +/* Transparent Proxying */ + extern int + PacketAliasProxyRule(char *); -/* - In version 2.2, the function names were rationalized - to all be of the form PacketAlias... These are the - old function names for backwards compatibility -*/ -extern int SaveFragmentPtr(char *); -extern char *GetNextFragmentPtr(char *); -extern void FragmentAliasIn(char *, char *); -extern void SetPacketAliasAddress(struct in_addr); -extern void InitPacketAlias(void); -extern unsigned int SetPacketAliasMode(unsigned int, unsigned int); -extern int PacketAliasIn2(char *, struct in_addr, int maxpacketsize); -extern int PacketAliasOut2(char *, struct in_addr, int maxpacketsize); -extern int -PacketAliasPermanentLink(struct in_addr, u_short, - struct in_addr, u_short, - u_short, u_char); -extern u_short InternetChecksum(u_short *, int); - -/* Obsolete constant */ -#define PKT_ALIAS_NEW_LINK 5 /********************** Mode flags ********************/ /* Set these flags using SetPacketAliasMode() */ @@ -138,7 +124,6 @@ extern u_short InternetChecksum(u_short *, int); 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 */ @@ -162,6 +147,14 @@ extern u_short InternetChecksum(u_short *, int); #define PKT_ALIAS_PUNCH_FW 0x40 #endif +/* If PKT_ALIAS_PROXY_ONLY is set, then NAT will be disabled and only + transparent proxying performed */ +#define PKT_ALIAS_PROXY_ONLY 0x40 + +/* If PKT_ALIAS_REVERSE is set, the actions of PacketAliasIn() + and PacketAliasOut() are reversed */ +#define PKT_ALIAS_REVERSE 0x80 + /* Return Codes */ #define PKT_ALIAS_ERROR -1 #define PKT_ALIAS_OK 1 diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c index dc9d020..c1d6985 100644 --- a/lib/libalias/alias_db.c +++ b/lib/libalias/alias_db.c @@ -56,12 +56,12 @@ 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) @@ -73,10 +73,10 @@ 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.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 + unknown dest port These permament links allow for incoming connections to machines on the local network. They can be given with a @@ -111,7 +111,7 @@ #include #include #include - + #include #include #include @@ -139,7 +139,7 @@ #define LINK_TABLE_IN_SIZE 4001 /* Parameters used for cleanup of expired links */ -#define ALIAS_CLEANUP_INTERVAL_SECS 60 +#define ALIAS_CLEANUP_INTERVAL_SECS 60 #define ALIAS_CLEANUP_MAX_SPOKES 30 /* Timouts (in seconds) for different link types) */ @@ -174,14 +174,14 @@ /* Dummy port number codes used for FindLinkIn/Out() and AddLink(). These constants can be anything except zero, which indicates an - unknown port numbea. */ + unknown port number. */ #define NO_DEST_PORT 1 #define NO_SRC_PORT 1 -/* Data Structures +/* Data Structures The fundamental data structure used in this program is "struct alias_link". Whenever a TCP connection is made, @@ -237,11 +237,13 @@ struct tcp_dat 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; /* . */ + struct in_addr dst_addr; + struct in_addr alias_addr; + struct in_addr proxy_addr; + u_short src_port; + u_short dst_port; + u_short alias_port; + u_short proxy_port; int link_type; /* Type of link: tcp, udp, icmp, frag */ @@ -348,6 +350,12 @@ static int fireWallFD = -1; /* File descriptor to be able to */ /* flag. */ #endif +static int pptpAliasFlag; /* Indicates if PPTP aliasing is */ + /* on or off */ +static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ + /* packets. */ + + @@ -853,15 +861,17 @@ AddLink(struct in_addr src_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; + link->src_addr = src_addr; + link->dst_addr = dst_addr; + link->alias_addr = alias_addr; + link->proxy_addr.s_addr = 0; + link->src_port = src_port; + link->dst_port = dst_port; + link->proxy_port = 0; + link->link_type = link_type; + link->sockfd = -1; + link->flags = 0; + link->timestamp = timeStamp; /* Expiration time */ switch (link_type) @@ -1304,7 +1314,9 @@ FindUdpTcpIn(struct in_addr dst_addr, dst_port, alias_port, link_type, 1); - if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL) + if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) + && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) + && link == NULL) { struct in_addr target_addr; @@ -1578,6 +1590,34 @@ SetAckModified(struct alias_link *link) } +struct in_addr +GetProxyAddress(struct alias_link *link) +{ + return link->proxy_addr; +} + + +void +SetProxyAddress(struct alias_link *link, struct in_addr addr) +{ + link->proxy_addr = addr; +} + + +u_short +GetProxyPort(struct alias_link *link) +{ + return link->proxy_port; +} + + +void +SetProxyPort(struct alias_link *link, u_short port) +{ + link->proxy_port = port; +} + + int GetAckModified(struct alias_link *link) { @@ -1906,6 +1946,26 @@ PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, return link; } +/* Translate PPTP packets to a machine on the inside + */ +int +PacketAliasPptp(struct in_addr src_addr) +{ + + pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */ + pptpAliasFlag = 1; + + + return 1; +} + +int GetPptpAlias (struct in_addr* alias_addr) +{ + if (pptpAliasFlag) + *alias_addr = pptpAliasAddr; + + return pptpAliasFlag; +} /* Static address translation */ struct alias_link * @@ -2007,6 +2067,8 @@ PacketAliasInit(void) packetAliasMode = PKT_ALIAS_SAME_PORTS | PKT_ALIAS_USE_SOCKETS | PKT_ALIAS_RESET_ON_ADDR_CHANGE; + + pptpAliasFlag = 0; } void diff --git a/lib/libalias/alias_local.h b/lib/libalias/alias_local.h index 3846281..da45125 100644 --- a/lib/libalias/alias_local.h +++ b/lib/libalias/alias_local.h @@ -1,9 +1,11 @@ /* -*- 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 + as any future add-ons). It also includes macros, globals and + struct definitions shared by more than one alias*.c file. + + This include file 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. @@ -15,9 +17,54 @@ #ifndef ALIAS_LOCAL_H #define ALIAS_LOCAL_H + +/* + Macros + */ + +/* + 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; \ + } \ +} + + +/* + Globals +*/ + extern int packetAliasMode; -struct alias_link; + +/* + Structs +*/ + +struct alias_link; /* Incomplete structure */ + + +/* + Prototypes +*/ /* General utilities */ u_short IpChecksum(struct ip *); @@ -71,6 +118,10 @@ struct in_addr GetDefaultAliasAddress(void); void SetDefaultAliasAddress(struct in_addr); u_short GetOriginalPort(struct alias_link *); u_short GetAliasPort(struct alias_link *); +struct in_addr GetProxyAddress(struct alias_link *); +void SetProxyAddress(struct alias_link *, struct in_addr); +u_short GetProxyPort(struct alias_link *); +void SetProxyPort(struct alias_link *, u_short); void SetAckModified(struct alias_link *); int GetAckModified(struct alias_link *); int GetDeltaAckIn(struct ip *, struct alias_link *); @@ -88,13 +139,24 @@ void HouseKeeping(void); /* Tcp specfic routines */ /*lint -save -library Suppress flexelint warnings */ + +/* FTP routines */ void AliasHandleFtpOut(struct ip *, struct alias_link *, int); + +/* IRC routines */ void AliasHandleIrcOut(struct ip *pip, struct alias_link *link, int maxsize ); + +/* NetBIOS routines */ int AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short); int AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *); + +/* CUSeeMe routines */ void AliasHandleCUSeeMeOut(struct ip *, struct alias_link *); void AliasHandleCUSeeMeIn(struct ip *, struct in_addr); +/* Transparent proxy routines */ +int ProxyCheck(struct ip *, struct in_addr *, u_short *); +void ProxyModify(struct alias_link *, struct ip *, int, int); enum alias_tcp_state { @@ -103,5 +165,6 @@ enum alias_tcp_state { ALIAS_TCP_STATE_DISCONNECTED }; +int GetPptpAlias (struct in_addr*); /*lint -restore */ #endif /* defined(ALIAS_LOCAL_H) */ diff --git a/lib/libalias/alias_proxy.c b/lib/libalias/alias_proxy.c new file mode 100644 index 0000000..27a56c2 --- /dev/null +++ b/lib/libalias/alias_proxy.c @@ -0,0 +1,801 @@ +/* file: alias_proxy.c + + This file encapsulates special operations related to transparent + proxy redirection. This is where packets with a particular destination, + usually tcp port 80, are redirected to a proxy server. + + When packets are proxied, the destination address and port are + modified. In certain cases, it is necessary to somehow encode + the original address/port info into the packet. Two methods are + presently supported: addition of a [DEST addr port] string at the + beginning a of tcp stream, or inclusion of an optional field + in the IP header. + + There is one public API function: + + PacketAliasProxyRule() -- Adds and deletes proxy + rules. + + Rules are stored in a linear linked list, so lookup efficiency + won't be too good for large lists. + + + Initial development: April, 1998 (cjm) +*/ + + +/* System includes */ +#include +#include +#include +#include +#include + +#include +#include + +/* BSD IPV4 includes */ +#include +#include +#include +#include + +#include + +#include "alias_local.h" /* Functions used by alias*.c */ +#include "alias.h" /* Public API functions for libalias */ + + + +/* + Data structures + */ + +/* + * A linked list of arbitrary length, based on struct proxy_entry is + * used to store proxy rules. + */ +struct proxy_entry +{ +#define PROXY_TYPE_ENCODE_NONE 1 +#define PROXY_TYPE_ENCODE_TCPSTREAM 2 +#define PROXY_TYPE_ENCODE_IPHDR 3 + int rule_index; + int proxy_type; + u_char proto; + u_short proxy_port; + u_short server_port; + + struct in_addr server_addr; + + struct in_addr src_addr; + struct in_addr src_mask; + + struct in_addr dst_addr; + struct in_addr dst_mask; + + struct proxy_entry *next; + struct proxy_entry *last; +}; + + + +/* + File scope variables +*/ + +static struct proxy_entry *proxyList; + + + +/* Local (static) functions: + + IpMask() -- Utility function for creating IP + masks from integer (1-32) specification. + IpAddr() -- Utility function for converting string + to IP address + IpPort() -- Utility function for converting string + to port number + RuleAdd() -- Adds an element to the rule list. + RuleDelete() -- Removes an element from the rule list. + RuleNumberDelete() -- Removes all elements from the rule list + having a certain rule number. + ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning + of a TCP stream. + ProxyEncodeIpHeader() -- Adds an IP option indicating the true + destination of a proxied IP packet +*/ + +static int IpMask(int, struct in_addr *); +static int IpAddr(char *, struct in_addr *); +static int IpPort(char *, int, int *); +static void RuleAdd(struct proxy_entry *); +static void RuleDelete(struct proxy_entry *); +static int RuleNumberDelete(int); +static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); +static void ProxyEncodeIpHeader(struct ip *, int); + +static int +IpMask(int nbits, struct in_addr *mask) +{ + int i; + u_int imask; + + if (nbits < 0 || nbits > 32) + return -1; + + imask = 0; + for (i=0; i> 1) + 0x80000000; + mask->s_addr = htonl(imask); + + return 0; +} + +static int +IpAddr(char *s, struct in_addr *addr) +{ + if (inet_aton(s, addr) == 0) + return -1; + else + return 0; +} + +static int +IpPort(char *s, int proto, int *port) +{ + int n; + + n = sscanf(s, "%d", port); + if (n != 1) + { + struct servent *se; + + if (proto == IPPROTO_TCP) + se = getservbyname(s, "tcp"); + else if (proto == IPPROTO_UDP) + se = getservbyname(s, "udp"); + else + return -1; + + if (se == NULL) + return -1; + + *port = (u_int) ntohs(se->s_port); + } + + return 0; +} + +void +RuleAdd(struct proxy_entry *entry) +{ + int rule_index; + struct proxy_entry *ptr; + struct proxy_entry *ptr_last; + + if (proxyList == NULL) + { + proxyList = entry; + entry->last = NULL; + entry->next = NULL; + return; + } + + rule_index = entry->rule_index; + ptr = proxyList; + ptr_last = NULL; + while (ptr != NULL) + { + if (ptr->rule_index >= rule_index) + { + if (ptr_last == NULL) + { + entry->next = proxyList; + entry->last = NULL; + proxyList->last = entry; + proxyList = entry; + return; + } + + ptr_last->next = entry; + ptr->last = entry; + entry->last = ptr->last; + entry->next = ptr; + return; + } + ptr_last = ptr; + ptr = ptr->next; + } + + ptr_last->next = entry; + entry->last = ptr_last; + entry->next = NULL; +} + +static void +RuleDelete(struct proxy_entry *entry) +{ + if (entry->last != NULL) + entry->last->next = entry->next; + else + proxyList = entry->next; + + if (entry->next != NULL) + entry->next->last = entry->last; + + free(entry); +} + +static int +RuleNumberDelete(int rule_index) +{ + int err; + struct proxy_entry *ptr; + + err = -1; + ptr = proxyList; + while (ptr != NULL) + { + struct proxy_entry *ptr_next; + + ptr_next = ptr->next; + if (ptr->rule_index == rule_index) + { + err = 0; + RuleDelete(ptr); + } + + ptr = ptr_next; + } + + return err; +} + +static void +ProxyEncodeTcpStream(struct alias_link *link, + struct ip *pip, + int maxpacketsize) +{ + int slen; + char buffer[40]; + struct tcphdr *tc; + +/* Compute pointer to tcp header */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + +/* Don't modify if once already modified */ + + if (GetAckModified (link)) + return; + +/* Translate destination address and port to string form */ + snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", + inet_ntoa(GetProxyAddress (link)), (u_int) ntohs(GetProxyPort (link))); + +/* Pad string out to a multiple of two in length */ + slen = strlen(buffer); + switch (slen % 2) + { + case 0: + strcat(buffer, " \n"); + slen += 2; + break; + case 1: + strcat(buffer, "\n"); + slen += 1; + } + +/* Check for packet overflow */ + if ((ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) + return; + +/* Shift existing TCP data and insert destination string */ + { + int dlen; + int hlen; + u_char *p; + + hlen = (pip->ip_hl + tc->th_off) << 2; + dlen = ntohs (pip->ip_len) - hlen; + +/* Modify first packet that has data in it */ + + if (dlen == 0) + return; + + p = (char *) pip; + p += hlen; + + memmove(p + slen, p, dlen); + memcpy(p, buffer, slen); + } + +/* Save information about modfied sequence number */ + { + int delta; + + SetAckModified(link); + delta = GetDeltaSeqOut(pip, link); + AddSeq(pip, link, delta+slen); + } + +/* Update IP header packet length and checksum */ + { + int accumulate; + + accumulate = pip->ip_len; + pip->ip_len = htons(ntohs(pip->ip_len) + slen); + accumulate -= pip->ip_len; + + ADJUST_CHECKSUM(accumulate, pip->ip_sum); + } + +/* Update TCP checksum, Use TcpChecksum since so many things have + already changed. */ + + tc->th_sum = 0; + tc->th_sum = TcpChecksum (pip); +} + +static void +ProxyEncodeIpHeader(struct ip *pip, + int maxpacketsize) +{ +#define OPTION_LEN_BYTES 8 +#define OPTION_LEN_INT16 4 +#define OPTION_LEN_INT32 2 + u_char option[OPTION_LEN_BYTES]; + +fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); +fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); + +/* Check to see that there is room to add an IP option */ + if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) + return; + +/* Build option and copy into packet */ + { + u_char *ptr; + struct tcphdr *tc; + + ptr = (u_char *) pip; + ptr += 20; + memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); + + option[0] = 0x64; /* class: 3 (reserved), option 4 */ + option[1] = OPTION_LEN_BYTES; + + memcpy(&option[2], (u_char *) &pip->ip_dst, 4); + + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + memcpy(&option[6], (u_char *) &tc->th_sport, 2); + + memcpy(ptr, option, 8); + } + +/* Update checksum, header length and packet length */ + { + int i; + int accumulate; + u_short *sptr; + + sptr = (u_short *) option; + accumulate = 0; + for (i=0; iip_hl += OPTION_LEN_INT32; + accumulate -= *sptr; + + accumulate += pip->ip_len; + pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); + accumulate -= pip->ip_len; + + ADJUST_CHECKSUM(accumulate, pip->ip_sum); + } +#undef OPTION_LEN_BYTES +#undef OPTION_LEN_INT16 +#undef OPTION_LEN_INT32 +fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); +fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); +} + + +/* Functions by other packet alias source files + + ProxyCheck() -- Checks whether an outgoing packet should + be proxied. + ProxyModify() -- Encodes the original destination address/port + for a packet which is to be redirected to + a proxy server. +*/ + +int +ProxyCheck(struct ip *pip, + struct in_addr *proxy_server_addr, + u_short *proxy_server_port) +{ + u_short dst_port; + struct in_addr src_addr; + struct in_addr dst_addr; + struct proxy_entry *ptr; + + src_addr = pip->ip_src; + dst_addr = pip->ip_dst; + dst_port = ((struct tcphdr *) ((char *) pip + (pip->ip_hl << 2))) + ->th_dport; + + ptr = proxyList; + while (ptr != NULL) + { + u_short proxy_port; + + proxy_port = ptr->proxy_port; + if ((dst_port == proxy_port || proxy_port == 0) + && pip->ip_p == ptr->proto + && src_addr.s_addr != ptr->server_addr.s_addr) + { + struct in_addr src_addr_masked; + struct in_addr dst_addr_masked; + + src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; + dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; + + if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) + && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) + { + if ((*proxy_server_port = ptr->server_port) == 0) + *proxy_server_port = dst_port; + *proxy_server_addr = ptr->server_addr; + return ptr->proxy_type; + } + } + ptr = ptr->next; + } + + return 0; +} + +void +ProxyModify(struct alias_link *link, + struct ip *pip, + int maxpacketsize, + int proxy_type) +{ + switch (proxy_type) + { + case PROXY_TYPE_ENCODE_IPHDR: + ProxyEncodeIpHeader(pip, maxpacketsize); + break; + + case PROXY_TYPE_ENCODE_TCPSTREAM: + ProxyEncodeTcpStream(link, pip, maxpacketsize); + break; + } +} + + +/* + Public API functions +*/ + +int +PacketAliasProxyRule(char *cmd) +{ +/* + * This function takes command strings of the form: + * + * server [:] + * [port ] + * [rule n] + * [proto tcp|udp] + * [src [/n]] + * [dst [/n]] + * [type encode_tcp_stream|encode_ip_hdr|no_encode] + * + * delete + * + * Subfields can be in arbitrary order. Port numbers and addresses + * must be in either numeric or symbolic form. An optional rule number + * is used to control the order in which rules are searched. If two + * rules have the same number, then search order cannot be guaranteed, + * and the rules should be disjoint. If no rule number is specified, + * then 0 is used, and group 0 rules are always checked before any + * others. + */ + int i, n, len; + int cmd_len; + int token_count; + int state; + char *token; + char buffer[256]; + char str_port[sizeof(buffer)]; + char str_server_port[sizeof(buffer)]; + + int rule_index; + int proto; + int proxy_type; + int proxy_port; + int server_port; + struct in_addr server_addr; + struct in_addr src_addr, src_mask; + struct in_addr dst_addr, dst_mask; + struct proxy_entry *proxy_entry; + +/* Copy command line into a buffer */ + cmd_len = strlen(cmd); + if (cmd_len > (sizeof(buffer) - 1)) + return -1; + strcpy(buffer, cmd); + +/* Convert to lower case */ + len = strlen(buffer); + for (i=0; iproxy_type = proxy_type; + proxy_entry->rule_index = rule_index; + proxy_entry->proto = proto; + proxy_entry->proxy_port = htons(proxy_port); + proxy_entry->server_port = htons(server_port); + proxy_entry->server_addr = server_addr; + proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; + proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; + proxy_entry->src_mask = src_mask; + proxy_entry->dst_mask = dst_mask; + + RuleAdd(proxy_entry); + + return 0; +} -- cgit v1.1