aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Somers <brian@FreeBSD.org>1999-02-27 02:16:01 +0000
committerBrian Somers <brian@FreeBSD.org>1999-02-27 02:16:01 +0000
commit7d96f4efd258d006626436837be5c6add536afdd (patch)
tree946fdb3216600a8021dd74123ccdcb001beccc75
parent2704b2cb2bf62b4c978f79a2ea41fbb3eadddb93 (diff)
downloadsrc-7d96f4efd258d006626436837be5c6add536afdd.tar.gz
src-7d96f4efd258d006626436837be5c6add536afdd.zip
Version 3.0: January 1, 1999
- Transparent proxying support added. - PPTP redirecting support added based on patches contributed by Dru Nelson <dnelson@redwoodsoft.com>. Submitted by: Charles Mott <cmott@srv.net>
Notes
Notes: svn path=/head/; revision=44307
-rw-r--r--lib/libalias/HISTORY5
-rw-r--r--lib/libalias/Makefile8
-rw-r--r--lib/libalias/alias.c242
-rw-r--r--lib/libalias/alias.h39
-rw-r--r--lib/libalias/alias_db.c108
-rw-r--r--lib/libalias/alias_local.h71
-rw-r--r--lib/libalias/alias_proxy.c801
-rw-r--r--sys/netinet/libalias/HISTORY5
-rw-r--r--sys/netinet/libalias/Makefile8
-rw-r--r--sys/netinet/libalias/alias.c242
-rw-r--r--sys/netinet/libalias/alias.h39
-rw-r--r--sys/netinet/libalias/alias_db.c108
-rw-r--r--sys/netinet/libalias/alias_local.h71
-rw-r--r--sys/netinet/libalias/alias_proxy.c801
14 files changed, 2352 insertions, 196 deletions
diff --git a/lib/libalias/HISTORY b/lib/libalias/HISTORY
index 3d97fd0803b1..575d1b4aa13d 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 <dnelson@redwoodsoft.com>.
diff --git a/lib/libalias/Makefile b/lib/libalias/Makefile
index 665d14e10b3d..ea6966449999 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 50e597f4364a..13d972c6ff8b 100644
--- a/lib/libalias/alias.c
+++ b/lib/libalias/alias.c
@@ -93,6 +93,10 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
+#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 010db9885a5a..14325f4aa2e9 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 dc9d020bd858..c1d6985e5cf0 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 <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-
+
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -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 38462810733a..da451259cdf0 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 000000000000..27a56c25daed
--- /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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/* BSD IPV4 includes */
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <arpa/inet.h>
+
+#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<nbits; i++)
+ imask = (imask >> 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; i<OPTION_LEN_INT16; i++)
+ accumulate -= *(sptr++);
+
+ sptr = (u_short *) pip;
+ accumulate += *sptr;
+ pip->ip_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 <addr>[:<port>]
+ * [port <port>]
+ * [rule n]
+ * [proto tcp|udp]
+ * [src <addr>[/n]]
+ * [dst <addr>[/n]]
+ * [type encode_tcp_stream|encode_ip_hdr|no_encode]
+ *
+ * delete <rule number>
+ *
+ * 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; i<len; i++)
+ buffer[i] = tolower(buffer[i]);
+
+/* Set default proxy type */
+
+/* Set up default values */
+ rule_index = 0;
+ proxy_type = PROXY_TYPE_ENCODE_NONE;
+ proto = IPPROTO_TCP;
+ proxy_port = 0;
+ server_addr.s_addr = 0;
+ server_port = 0;
+ src_addr.s_addr = 0;
+ IpMask(0, &src_mask);
+ dst_addr.s_addr = 0;
+ IpMask(0, &dst_mask);
+
+ str_port[0] = 0;
+ str_server_port[0] = 0;
+
+/* Parse command string with state machine */
+#define STATE_READ_KEYWORD 0
+#define STATE_READ_TYPE 1
+#define STATE_READ_PORT 2
+#define STATE_READ_SERVER 3
+#define STATE_READ_RULE 4
+#define STATE_READ_DELETE 5
+#define STATE_READ_PROTO 6
+#define STATE_READ_SRC 7
+#define STATE_READ_DST 8
+ state = STATE_READ_KEYWORD;
+ token = strtok(buffer, " \t");
+ token_count = 0;
+ while (token != NULL)
+ {
+ token_count++;
+ switch (state)
+ {
+ case STATE_READ_KEYWORD:
+ if (strcmp(token, "type") == 0)
+ state = STATE_READ_TYPE;
+ else if (strcmp(token, "port") == 0)
+ state = STATE_READ_PORT;
+ else if (strcmp(token, "server") == 0)
+ state = STATE_READ_SERVER;
+ else if (strcmp(token, "rule") == 0)
+ state = STATE_READ_RULE;
+ else if (strcmp(token, "delete") == 0)
+ state = STATE_READ_DELETE;
+ else if (strcmp(token, "proto") == 0)
+ state = STATE_READ_PROTO;
+ else if (strcmp(token, "src") == 0)
+ state = STATE_READ_SRC;
+ else if (strcmp(token, "dst") == 0)
+ state = STATE_READ_DST;
+ else
+ return -1;
+ break;
+
+ case STATE_READ_TYPE:
+ if (strcmp(token, "encode_ip_hdr") == 0)
+ proxy_type = PROXY_TYPE_ENCODE_IPHDR;
+ else if (strcmp(token, "encode_tcp_stream") == 0)
+ proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
+ else if (strcmp(token, "no_encode") == 0)
+ proxy_type = PROXY_TYPE_ENCODE_NONE;
+ else
+ return -1;
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_PORT:
+ strcpy(str_port, token);
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_SERVER:
+ {
+ int err;
+ char *p;
+ char s[sizeof(buffer)];
+
+ p = token;
+ while (*p != ':' && *p != 0)
+ p++;
+
+ if (*p != ':')
+ {
+ err = IpAddr(token, &server_addr);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ *p = ' ';
+
+ n = sscanf(token, "%s %s", s, str_server_port);
+ if (n != 2)
+ return -1;
+
+ err = IpAddr(s, &server_addr);
+ if (err)
+ return -1;
+ }
+ }
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_RULE:
+ n = sscanf(token, "%d", &rule_index);
+ if (n != 1 || rule_index < 0)
+ return -1;
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_DELETE:
+ {
+ int err;
+ int rule_to_delete;
+
+ if (token_count != 2)
+ return -1;
+
+ n = sscanf(token, "%d", &rule_to_delete);
+ if (n != 1)
+ return -1;
+ err = RuleNumberDelete(rule_to_delete);
+ if (err)
+ return -1;
+ return 0;
+ }
+
+ case STATE_READ_PROTO:
+ if (strcmp(token, "tcp") == 0)
+ proto = IPPROTO_TCP;
+ else if (strcmp(token, "udp") == 0)
+ proto = IPPROTO_UDP;
+ else
+ return -1;
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_SRC:
+ case STATE_READ_DST:
+ {
+ int err;
+ char *p;
+ struct in_addr mask;
+ struct in_addr addr;
+
+ p = token;
+ while (*p != '/' && *p != 0)
+ p++;
+
+ if (*p != '/')
+ {
+ IpMask(32, &mask);
+ err = IpAddr(token, &addr);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ int n;
+ int nbits;
+ char s[sizeof(buffer)];
+
+ *p = ' ';
+ n = sscanf(token, "%s %d", s, &nbits);
+ if (n != 2)
+ return -1;
+
+ err = IpAddr(s, &addr);
+ if (err)
+ return -1;
+
+ err = IpMask(nbits, &mask);
+ if (err)
+ return -1;
+ }
+
+ if (state == STATE_READ_SRC)
+ {
+ src_addr = addr;
+ src_mask = mask;
+ }
+ else
+ {
+ dst_addr = addr;
+ dst_mask = mask;
+ }
+ }
+ state = STATE_READ_KEYWORD;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ token = strtok(NULL, " \t");
+ }
+#undef STATE_READ_KEYWORD
+#undef STATE_READ_TYPE
+#undef STATE_READ_PORT
+#undef STATE_READ_SERVER
+#undef STATE_READ_RULE
+#undef STATE_READ_DELETE
+#undef STATE_READ_PROTO
+#undef STATE_READ_SRC
+#undef STATE_READ_DST
+
+/* Convert port strings to numbers. This needs to be done after
+ the string is parsed, because the prototype might not be designated
+ before the ports (which might be symbolic entries in /etc/services) */
+
+ if (strlen(str_port) != 0)
+ {
+ int err;
+
+ err = IpPort(str_port, proto, &proxy_port);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ proxy_port = 0;
+ }
+
+ if (strlen(str_server_port) != 0)
+ {
+ int err;
+
+ err = IpPort(str_server_port, proto, &server_port);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ server_port = 0;
+ }
+
+/* Check that at least the server address has been defined */
+ if (server_addr.s_addr == 0)
+ return -1;
+
+/* Add to linked list */
+ proxy_entry = malloc(sizeof(struct proxy_entry));
+ if (proxy_entry == NULL)
+ return -1;
+
+ proxy_entry->proxy_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;
+}
diff --git a/sys/netinet/libalias/HISTORY b/sys/netinet/libalias/HISTORY
index 3d97fd0803b1..575d1b4aa13d 100644
--- a/sys/netinet/libalias/HISTORY
+++ b/sys/netinet/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 <dnelson@redwoodsoft.com>.
diff --git a/sys/netinet/libalias/Makefile b/sys/netinet/libalias/Makefile
index 665d14e10b3d..ea6966449999 100644
--- a/sys/netinet/libalias/Makefile
+++ b/sys/netinet/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/sys/netinet/libalias/alias.c b/sys/netinet/libalias/alias.c
index 50e597f4364a..13d972c6ff8b 100644
--- a/sys/netinet/libalias/alias.c
+++ b/sys/netinet/libalias/alias.c
@@ -93,6 +93,10 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
+#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/sys/netinet/libalias/alias.h b/sys/netinet/libalias/alias.h
index 010db9885a5a..14325f4aa2e9 100644
--- a/sys/netinet/libalias/alias.h
+++ b/sys/netinet/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/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c
index dc9d020bd858..c1d6985e5cf0 100644
--- a/sys/netinet/libalias/alias_db.c
+++ b/sys/netinet/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 <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-
+
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -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/sys/netinet/libalias/alias_local.h b/sys/netinet/libalias/alias_local.h
index 38462810733a..da451259cdf0 100644
--- a/sys/netinet/libalias/alias_local.h
+++ b/sys/netinet/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/sys/netinet/libalias/alias_proxy.c b/sys/netinet/libalias/alias_proxy.c
new file mode 100644
index 000000000000..27a56c25daed
--- /dev/null
+++ b/sys/netinet/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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/* BSD IPV4 includes */
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <arpa/inet.h>
+
+#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<nbits; i++)
+ imask = (imask >> 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; i<OPTION_LEN_INT16; i++)
+ accumulate -= *(sptr++);
+
+ sptr = (u_short *) pip;
+ accumulate += *sptr;
+ pip->ip_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 <addr>[:<port>]
+ * [port <port>]
+ * [rule n]
+ * [proto tcp|udp]
+ * [src <addr>[/n]]
+ * [dst <addr>[/n]]
+ * [type encode_tcp_stream|encode_ip_hdr|no_encode]
+ *
+ * delete <rule number>
+ *
+ * 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; i<len; i++)
+ buffer[i] = tolower(buffer[i]);
+
+/* Set default proxy type */
+
+/* Set up default values */
+ rule_index = 0;
+ proxy_type = PROXY_TYPE_ENCODE_NONE;
+ proto = IPPROTO_TCP;
+ proxy_port = 0;
+ server_addr.s_addr = 0;
+ server_port = 0;
+ src_addr.s_addr = 0;
+ IpMask(0, &src_mask);
+ dst_addr.s_addr = 0;
+ IpMask(0, &dst_mask);
+
+ str_port[0] = 0;
+ str_server_port[0] = 0;
+
+/* Parse command string with state machine */
+#define STATE_READ_KEYWORD 0
+#define STATE_READ_TYPE 1
+#define STATE_READ_PORT 2
+#define STATE_READ_SERVER 3
+#define STATE_READ_RULE 4
+#define STATE_READ_DELETE 5
+#define STATE_READ_PROTO 6
+#define STATE_READ_SRC 7
+#define STATE_READ_DST 8
+ state = STATE_READ_KEYWORD;
+ token = strtok(buffer, " \t");
+ token_count = 0;
+ while (token != NULL)
+ {
+ token_count++;
+ switch (state)
+ {
+ case STATE_READ_KEYWORD:
+ if (strcmp(token, "type") == 0)
+ state = STATE_READ_TYPE;
+ else if (strcmp(token, "port") == 0)
+ state = STATE_READ_PORT;
+ else if (strcmp(token, "server") == 0)
+ state = STATE_READ_SERVER;
+ else if (strcmp(token, "rule") == 0)
+ state = STATE_READ_RULE;
+ else if (strcmp(token, "delete") == 0)
+ state = STATE_READ_DELETE;
+ else if (strcmp(token, "proto") == 0)
+ state = STATE_READ_PROTO;
+ else if (strcmp(token, "src") == 0)
+ state = STATE_READ_SRC;
+ else if (strcmp(token, "dst") == 0)
+ state = STATE_READ_DST;
+ else
+ return -1;
+ break;
+
+ case STATE_READ_TYPE:
+ if (strcmp(token, "encode_ip_hdr") == 0)
+ proxy_type = PROXY_TYPE_ENCODE_IPHDR;
+ else if (strcmp(token, "encode_tcp_stream") == 0)
+ proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
+ else if (strcmp(token, "no_encode") == 0)
+ proxy_type = PROXY_TYPE_ENCODE_NONE;
+ else
+ return -1;
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_PORT:
+ strcpy(str_port, token);
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_SERVER:
+ {
+ int err;
+ char *p;
+ char s[sizeof(buffer)];
+
+ p = token;
+ while (*p != ':' && *p != 0)
+ p++;
+
+ if (*p != ':')
+ {
+ err = IpAddr(token, &server_addr);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ *p = ' ';
+
+ n = sscanf(token, "%s %s", s, str_server_port);
+ if (n != 2)
+ return -1;
+
+ err = IpAddr(s, &server_addr);
+ if (err)
+ return -1;
+ }
+ }
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_RULE:
+ n = sscanf(token, "%d", &rule_index);
+ if (n != 1 || rule_index < 0)
+ return -1;
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_DELETE:
+ {
+ int err;
+ int rule_to_delete;
+
+ if (token_count != 2)
+ return -1;
+
+ n = sscanf(token, "%d", &rule_to_delete);
+ if (n != 1)
+ return -1;
+ err = RuleNumberDelete(rule_to_delete);
+ if (err)
+ return -1;
+ return 0;
+ }
+
+ case STATE_READ_PROTO:
+ if (strcmp(token, "tcp") == 0)
+ proto = IPPROTO_TCP;
+ else if (strcmp(token, "udp") == 0)
+ proto = IPPROTO_UDP;
+ else
+ return -1;
+ state = STATE_READ_KEYWORD;
+ break;
+
+ case STATE_READ_SRC:
+ case STATE_READ_DST:
+ {
+ int err;
+ char *p;
+ struct in_addr mask;
+ struct in_addr addr;
+
+ p = token;
+ while (*p != '/' && *p != 0)
+ p++;
+
+ if (*p != '/')
+ {
+ IpMask(32, &mask);
+ err = IpAddr(token, &addr);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ int n;
+ int nbits;
+ char s[sizeof(buffer)];
+
+ *p = ' ';
+ n = sscanf(token, "%s %d", s, &nbits);
+ if (n != 2)
+ return -1;
+
+ err = IpAddr(s, &addr);
+ if (err)
+ return -1;
+
+ err = IpMask(nbits, &mask);
+ if (err)
+ return -1;
+ }
+
+ if (state == STATE_READ_SRC)
+ {
+ src_addr = addr;
+ src_mask = mask;
+ }
+ else
+ {
+ dst_addr = addr;
+ dst_mask = mask;
+ }
+ }
+ state = STATE_READ_KEYWORD;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ token = strtok(NULL, " \t");
+ }
+#undef STATE_READ_KEYWORD
+#undef STATE_READ_TYPE
+#undef STATE_READ_PORT
+#undef STATE_READ_SERVER
+#undef STATE_READ_RULE
+#undef STATE_READ_DELETE
+#undef STATE_READ_PROTO
+#undef STATE_READ_SRC
+#undef STATE_READ_DST
+
+/* Convert port strings to numbers. This needs to be done after
+ the string is parsed, because the prototype might not be designated
+ before the ports (which might be symbolic entries in /etc/services) */
+
+ if (strlen(str_port) != 0)
+ {
+ int err;
+
+ err = IpPort(str_port, proto, &proxy_port);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ proxy_port = 0;
+ }
+
+ if (strlen(str_server_port) != 0)
+ {
+ int err;
+
+ err = IpPort(str_server_port, proto, &server_port);
+ if (err)
+ return -1;
+ }
+ else
+ {
+ server_port = 0;
+ }
+
+/* Check that at least the server address has been defined */
+ if (server_addr.s_addr == 0)
+ return -1;
+
+/* Add to linked list */
+ proxy_entry = malloc(sizeof(struct proxy_entry));
+ if (proxy_entry == NULL)
+ return -1;
+
+ proxy_entry->proxy_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;
+}