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>
This commit is contained in:
Brian Somers 1999-02-27 02:16:01 +00:00
parent 2704b2cb2b
commit 7d96f4efd2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=44307
14 changed files with 2352 additions and 196 deletions

View File

@ -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>.

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) */

801
lib/libalias/alias_proxy.c Normal file
View File

@ -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;
}

View File

@ -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>.

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) */

View File

@ -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;
}