From 781f5bff105e2b341e76efe04ea322b2c9497ca8 Mon Sep 17 00:00:00 2001 From: eivind Date: Fri, 9 Jan 1998 21:13:35 +0000 Subject: Teach libalias to work with IPFW firewalls (controlled by a flag). Obtained from: Yes development tree (+ 10 lines of patches from Charles Mott, original libalias author) --- lib/libalias/HISTORY | 4 + lib/libalias/Makefile | 2 +- lib/libalias/alias.c | 38 ++-- lib/libalias/alias.h | 17 +- lib/libalias/alias_db.c | 423 ++++++++++++++++++++++++++++++++++++++------- lib/libalias/alias_ftp.c | 7 +- lib/libalias/alias_irc.c | 3 + lib/libalias/alias_local.h | 14 +- lib/libalias/libalias.3 | 60 ++++++- 9 files changed, 475 insertions(+), 93 deletions(-) (limited to 'lib/libalias') diff --git a/lib/libalias/HISTORY b/lib/libalias/HISTORY index 78a7e08..5d29e34 100644 --- a/lib/libalias/HISTORY +++ b/lib/libalias/HISTORY @@ -120,3 +120,7 @@ Version 2.4: September 1, 1997 (cjm) This part of the code was incorrectly re-implemented in version 2.1. +Version 2.5: December, 1997 (ee) + - Added PKT_ALIAS_PUNCH_FW mode for firewall + bypass of FTP/IRC DCC data connections. Also added + improved TCP connection monitoring. diff --git a/lib/libalias/Makefile b/lib/libalias/Makefile index 3c291b2..6ce9e46 100644 --- a/lib/libalias/Makefile +++ b/lib/libalias/Makefile @@ -1,6 +1,6 @@ LIB= alias SHLIB_MAJOR= 2 -SHLIB_MINOR= 4 +SHLIB_MINOR= 5 CFLAGS+=-Wall -I${.CURDIR} SRCS= alias.c alias_db.c alias_ftp.c alias_irc.c alias_util.c alias_old.c MAN3=libalias.3 diff --git a/lib/libalias/alias.c b/lib/libalias/alias.c index a9c1e3b..c8ef65a 100644 --- a/lib/libalias/alias.c +++ b/lib/libalias/alias.c @@ -73,6 +73,8 @@ - Eliminated PacketAliasIn2() and PacketAliasOut2() as poorly conceived. + See HISTORY file for additional revisions. + */ #include @@ -149,12 +151,15 @@ TcpMonitorIn(struct ip *pip, struct alias_link *link) switch (GetStateIn(link)) { - case 0: - if (tc->th_flags & TH_SYN) SetStateIn(link, 1); + case ALIAS_TCP_STATE_NOT_CONNECTED: + if (tc->th_flags & TH_SYN) + SetStateIn(link, ALIAS_TCP_STATE_CONNECTED); break; - case 1: + case ALIAS_TCP_STATE_CONNECTED: if (tc->th_flags & TH_FIN - || tc->th_flags & TH_RST) SetStateIn(link, 2); + || tc->th_flags & TH_RST) + SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED); + break; } } @@ -167,12 +172,15 @@ TcpMonitorOut(struct ip *pip, struct alias_link *link) switch (GetStateOut(link)) { - case 0: - if (tc->th_flags & TH_SYN) SetStateOut(link, 1); + case ALIAS_TCP_STATE_NOT_CONNECTED: + if (tc->th_flags & TH_SYN) + SetStateOut(link, ALIAS_TCP_STATE_CONNECTED); break; - case 1: + case ALIAS_TCP_STATE_CONNECTED: if (tc->th_flags & TH_FIN - || tc->th_flags & TH_RST) SetStateOut(link, 2); + || tc->th_flags & TH_RST) + SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED); + break; } } @@ -776,7 +784,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) || 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 */ @@ -977,6 +985,11 @@ PacketAliasIn(char *ptr, int maxpacketsize) pip = (struct ip *) ptr; alias_addr = pip->ip_dst; + /* Defense against mangled packets */ + if (ntohs(pip->ip_len) > maxpacketsize + || (pip->ip_hl<<2) > maxpacketsize) + return PKT_ALIAS_IGNORED; + iresult = PKT_ALIAS_IGNORED; if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 ) { @@ -1002,7 +1015,7 @@ PacketAliasIn(char *ptr, int maxpacketsize) { iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; SetFragmentAddr(link, pip->ip_dst); - } + } else { iresult = PKT_ALIAS_ERROR; @@ -1049,6 +1062,11 @@ PacketAliasOut(char *ptr, /* valid IP packet */ ClearCheckNewLink(); pip = (struct ip *) ptr; + /* Defense against mangled packets */ + if (ntohs(pip->ip_len) > maxpacketsize + || (pip->ip_hl<<2) > maxpacketsize) + return PKT_ALIAS_IGNORED; + addr_save = GetDefaultAliasAddress(); if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) { diff --git a/lib/libalias/alias.h b/lib/libalias/alias.h index 50d8056..9d1f755 100644 --- a/lib/libalias/alias.h +++ b/lib/libalias/alias.h @@ -26,11 +26,17 @@ struct alias_link; PacketAliasInit(void); extern void + PacketAliasUninit(void); + + extern void PacketAliasSetAddress(struct in_addr); extern unsigned int PacketAliasSetMode(unsigned int, unsigned int); + extern void + PacketAliasSetFWBase(unsigned int, unsigned int); + /* Packet Handling */ extern int PacketAliasIn(char *, int maxpacketsize); @@ -136,6 +142,14 @@ extern u_short InternetChecksum(u_short *, int); bit is set after a call to PacketAliasInit(). */ #define PKT_ALIAS_RESET_ON_ADDR_CHANGE 0x20 +/* If PKT_ALIAS_PUNCH_FW is set, active FTP and IRC DCC connections + will create a 'hole' in the firewall to allow the transfers to + work. Where (IPFW "line-numbers") the hole is created is + controlled by PacketAliasSetFWBase(base, size). The hole will be + attached to that particular alias_link, so when the link goes away + so do the hole. */ +#define PKT_ALIAS_PUNCH_FW 0x40 + /* Return Codes */ #define PKT_ALIAS_ERROR -1 #define PKT_ALIAS_OK 1 @@ -143,8 +157,5 @@ extern u_short InternetChecksum(u_short *, int); #define PKT_ALIAS_UNRESOLVED_FRAGMENT 3 #define PKT_ALIAS_FOUND_HEADER_FRAGMENT 4 -#undef __libalias_version -#define __libalias_version "2.4" - #endif /*lint -restore */ diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c index 3579dca..d5dff37 100644 --- a/lib/libalias/alias_db.c +++ b/lib/libalias/alias_db.c @@ -90,7 +90,7 @@ SetExpire() function added. (cjm) DeleteLink() no longer frees memory association with a pointer - to a fragment (this bug was first recognized by E. Eiklund in + to a fragment (this bug was first recognized by E. Eklund in v1.9). Version 2.1: May, 1997 (cjm) @@ -102,6 +102,8 @@ added to the API. The first function is a more generalized version of PacketAliasPermanentLink(). The second function implements static network address translation. + + See HISTORY file for additional revisions. */ @@ -114,6 +116,7 @@ #include #include #include +#include /* BSD network include files */ #include @@ -143,10 +146,33 @@ /* Timouts (in seconds) for different link types) */ #define ICMP_EXPIRE_TIME 60 #define UDP_EXPIRE_TIME 60 -#define TCP_EXPIRE_TIME 90 #define FRAGMENT_ID_EXPIRE_TIME 10 #define FRAGMENT_PTR_EXPIRE_TIME 30 +/* TCP link expire time for different cases */ +/* When the link has been used and closed - minimal grace time to + allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ +#ifndef TCP_EXPIRE_DEAD +# define TCP_EXPIRE_DEAD 10 +#endif + +/* When the link has been used and closed on one side - the other side + is allowed to still send data */ +#ifndef TCP_EXPIRE_SINGLEDEAD +# define TCP_EXPIRE_SINGLEDEAD 90 +#endif + +/* When the link isn't yet up */ +#ifndef TCP_EXPIRE_INITIAL +# define TCP_EXPIRE_INITIAL 300 +#endif + +/* When the link is up */ +#ifndef TCP_EXPIRE_CONNECTED +# define TCP_EXPIRE_CONNECTED 86400 +#endif + + /* Dummy port number codes used for FindLinkIn/Out() and AddLink(). These constants can be anything except zero, which indicates an unknown port numbea. */ @@ -206,6 +232,7 @@ struct tcp_dat { struct tcp_state state; struct ack_data_record ack[N_LINK_TCP_DATA]; + int fwhole; /* Which firewall record is used for this hole? */ }; struct alias_link /* Main data structure */ @@ -234,6 +261,7 @@ struct alias_link /* Main data structure */ #define LINK_UNKNOWN_DEST_ADDR 0x02 #define LINK_PERMANENT 0x04 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ +#define LINK_UNFIREWALLED 0x08 int timestamp; /* Time link was last accessed */ int expire_time; /* Expire time for link */ @@ -309,12 +337,16 @@ static int deleteAllLinks; /* If equal to zero, DeleteLink() */ static FILE *monitorFile; /* File descriptor for link */ /* statistics monitoring file */ -static int firstCall = 1; /* Needed by InitAlias() */ - static int newDefaultLink; /* Indicates if a new aliasing */ /* link has been created after a */ /* call to PacketAliasIn/Out(). */ +static int fireWallFD = -1; /* File descriptor to be able to */ + /* control firewall. Opened by */ + /* PacketAliasSetMode on first */ + /* setting the PKT_ALIAS_PUNCH_FW */ + /* flag. */ + @@ -344,6 +376,14 @@ static int SeqDiff(u_long, u_long); static void ShowAliasStats(void); +/* Firewall control */ +static void InitPunchFW(void); +static void UninitPunchFW(void); +static void ClearFWHole(struct alias_link *link); + +/* Log file control */ +static void InitPacketAliasLog(void); +static void UninitPacketAliasLog(void); static u_int StartPointIn(struct in_addr alias_addr, @@ -429,6 +469,7 @@ Link creation and deletion: IncrementalCleanup() - look for stale links in a single chain DeleteLink() - remove link AddLink() - add link + ReLink() - change link Link search: FindLinkOut() - find link for outgoing packets @@ -451,6 +492,11 @@ AddLink(struct in_addr, struct in_addr, struct in_addr, u_short, u_short, int, int); static struct alias_link * +ReLink(struct alias_link *, + struct in_addr, struct in_addr, struct in_addr, + u_short, u_short, int, int); + +static struct alias_link * FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); static struct alias_link * @@ -680,8 +726,8 @@ IncrementalCleanup(void) struct tcp_dat *tcp_aux; tcp_aux = link->data.tcp; - if (tcp_aux->state.in != 1 - || tcp_aux->state.out != 1) + if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED + || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) { DeleteLink(link); icount++; @@ -706,6 +752,9 @@ DeleteLink(struct alias_link *link) if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) return; +/* Delete associatied firewall hole, if any */ + ClearFWHole(link); + /* Adjust output table pointers */ link_last = link->last_out; link_next = link->next_out; @@ -820,7 +869,7 @@ AddLink(struct in_addr src_addr, link->expire_time = UDP_EXPIRE_TIME; break; case LINK_TCP: - link->expire_time = TCP_EXPIRE_TIME; + link->expire_time = TCP_EXPIRE_INITIAL; break; case LINK_FRAGMENT_ID: link->expire_time = FRAGMENT_ID_EXPIRE_TIME; @@ -889,12 +938,13 @@ AddLink(struct in_addr src_addr, int i; tcpLinkCount++; - aux_tcp->state.in = 0; - aux_tcp->state.out = 0; + aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; + aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; aux_tcp->state.index = 0; aux_tcp->state.ack_modified = 0; for (i=0; iack[i].active = 0; + aux_tcp->fwhole = -1; } else { @@ -924,6 +974,30 @@ AddLink(struct in_addr src_addr, return(link); } +static struct alias_link * +ReLink(struct alias_link *old_link, + struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_short src_port, + u_short dst_port, + int alias_port_param, /* if less than zero, alias */ + int link_type) /* port will be automatically */ +{ /* chosen. If greater than */ + struct alias_link *new_link; /* zero, equal to alias port */ + + new_link = AddLink(src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port_param, + link_type); + if (new_link != NULL && + old_link->link_type == LINK_TCP && + old_link->data.tcp && + old_link->data.tcp->fwhole > 0) { + PunchFWHole(new_link); + } + DeleteLink(old_link); + return new_link; +} static struct alias_link * FindLinkOut(struct in_addr src_addr, @@ -1057,55 +1131,34 @@ FindLinkIn(struct in_addr dst_addr, if (link_fully_specified != NULL) { - return (link_fully_specified); + return link_fully_specified; } else if (link_unknown_dst_port != NULL) { - if (replace_partial_links) - { - link = AddLink(link_unknown_dst_port->src_addr, dst_addr, - alias_addr, - link_unknown_dst_port->src_port, dst_port, - alias_port, link_type); - DeleteLink(link_unknown_dst_port); - return(link); - } - else - { - return(link_unknown_dst_port); - } + return replace_partial_links + ? ReLink(link_unknown_dst_port, + link_unknown_dst_port->src_addr, dst_addr, alias_addr, + link_unknown_dst_port->src_port, dst_port, alias_port, + link_type) + : link_unknown_dst_port; } else if (link_unknown_dst_addr != NULL) { - if (replace_partial_links) - { - link = AddLink(link_unknown_dst_addr->src_addr, dst_addr, - alias_addr, - link_unknown_dst_addr->src_port, dst_port, - alias_port, link_type); - DeleteLink(link_unknown_dst_addr); - return(link); - } - else - { - return(link_unknown_dst_addr); - } + return replace_partial_links + ? ReLink(link_unknown_dst_addr, + link_unknown_dst_addr->src_addr, dst_addr, alias_addr, + link_unknown_dst_addr->src_port, dst_port, alias_port, + link_type) + : link_unknown_dst_addr; } else if (link_unknown_all != NULL) { - if (replace_partial_links) - { - link = AddLink(link_unknown_all->src_addr, dst_addr, - alias_addr, - link_unknown_all->src_port, dst_port, - alias_port, link_type); - DeleteLink(link_unknown_all); - return(link); - } - else - { - return(link_unknown_all); - } + return replace_partial_links + ? ReLink(link_unknown_all, + link_unknown_all->src_addr, dst_addr, alias_addr, + link_unknown_all->src_port, dst_port, alias_port, + link_type) + : link_unknown_all; } else { @@ -1389,7 +1442,24 @@ void SetStateIn(struct alias_link *link, int state) { /* TCP input state */ - (link->data.tcp)->state.in = state; + switch (state) { + case ALIAS_TCP_STATE_DISCONNECTED: + if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { + link->expire_time = TCP_EXPIRE_DEAD; + } else { + link->expire_time = TCP_EXPIRE_SINGLEDEAD; + } + link->data.tcp->state.in = state; + break; + case ALIAS_TCP_STATE_CONNECTED: + link->expire_time = TCP_EXPIRE_CONNECTED; + /*FALLTHROUGH*/ + case ALIAS_TCP_STATE_NOT_CONNECTED: + link->data.tcp->state.in = state; + break; + default: + abort(); + } } @@ -1397,7 +1467,24 @@ void SetStateOut(struct alias_link *link, int state) { /* TCP output state */ - (link->data.tcp)->state.out = state; + switch (state) { + case ALIAS_TCP_STATE_DISCONNECTED: + if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { + link->expire_time = TCP_EXPIRE_DEAD; + } else { + link->expire_time = TCP_EXPIRE_SINGLEDEAD; + } + link->data.tcp->state.out = state; + break; + case ALIAS_TCP_STATE_CONNECTED: + link->expire_time = TCP_EXPIRE_CONNECTED; + /*FALLTHROUGH*/ + case ALIAS_TCP_STATE_NOT_CONNECTED: + link->data.tcp->state.out = state; + break; + default: + abort(); + } } @@ -1405,7 +1492,7 @@ int GetStateIn(struct alias_link *link) { /* TCP input state */ - return( (link->data.tcp)->state.in); + return link->data.tcp->state.in; } @@ -1413,7 +1500,7 @@ int GetStateOut(struct alias_link *link) { /* TCP output state */ - return( (link->data.tcp)->state.out); + return link->data.tcp->state.out; } @@ -1471,12 +1558,17 @@ GetAliasPort(struct alias_link *link) return(link->alias_port); } +u_short +GetDestPort(struct alias_link *link) +{ + return(link->dst_port); +} void SetAckModified(struct alias_link *link) { /* Indicate that ack numbers have been modified in a TCP connection */ - (link->data.tcp)->state.ack_modified = 1; + link->data.tcp->state.ack_modified = 1; } @@ -1484,7 +1576,7 @@ int GetAckModified(struct alias_link *link) { /* See if ack numbers have been modified */ - return( (link->data.tcp)->state.ack_modified ); + return link->data.tcp->state.ack_modified; } @@ -1511,7 +1603,7 @@ packet size was altered is searched. { struct ack_data_record x; - x = (link->data.tcp)->ack[i]; + x = link->data.tcp->ack[i]; if (x.active == 1) { int ack_diff; @@ -1562,7 +1654,7 @@ packet size was altered is searched. { struct ack_data_record x; - x = (link->data.tcp)->ack[i]; + x = link->data.tcp->ack[i]; if (x.active == 1) { int seq_diff; @@ -1615,14 +1707,14 @@ been altered, then this list will begin to overwrite itself. x.delta = delta; x.active = 1; - i = (link->data.tcp)->state.index; - (link->data.tcp)->ack[i] = x; + i = link->data.tcp->state.index; + link->data.tcp->ack[i] = x; i++; if (i == N_LINK_TCP_DATA) - (link->data.tcp)->state.index = 0; + link->data.tcp->state.index = 0; else - (link->data.tcp)->state.index = i; + link->data.tcp->state.index = i; } void @@ -1722,7 +1814,7 @@ HouseKeeping(void) /* Init the log file and enable logging */ -void +static void InitPacketAliasLog(void) { if ((~packetAliasMode & PKT_ALIAS_LOG) @@ -1736,7 +1828,7 @@ InitPacketAliasLog(void) /* Close the log-file and disable logging. */ -void +static void UninitPacketAliasLog(void) { if( monitorFile ) @@ -1758,6 +1850,7 @@ UninitPacketAliasLog(void) PacketAliasRedirectDelete() PacketAliasSetAddress() PacketAliasInit() + PacketAliasUninit() PacketAliasSetMode() (prototypes in alias.h) @@ -1868,6 +1961,7 @@ PacketAliasInit(void) int i; struct timeval tv; struct timezone tz; + static int firstCall = 1; if (firstCall == 1) { @@ -1881,6 +1975,7 @@ PacketAliasInit(void) for (i=0; i +#include +#include +#include + +static void ClearAllFWHoles(void); + +static int fireWallBaseNum; /* The first firewall entry free for our use */ +static int fireWallNumNums; /* How many entries can we use? */ +static int fireWallActiveNum; /* Which entry did we last use? */ +static char *fireWallField; /* bool array for entries */ + +#define fw_setfield(field, num) \ +do { \ + (field)[num] = 1; \ +} /*lint -save -e717 */ while(0) /*lint -restore */ +#define fw_clrfield(field, num) \ +do { \ + (field)[num] = 0; \ +} /*lint -save -e717 */ while(0) /*lint -restore */ +#define fw_tstfield(field, num) ((field)[num]) + +void +PacketAliasSetFWBase(unsigned int base, unsigned int num) { + fireWallBaseNum = base; + fireWallNumNums = num; +} + +static void +InitPunchFW(void) { + fireWallField = malloc(fireWallNumNums); + if (fireWallField) { + memset(fireWallField, 0, fireWallNumNums); + if (fireWallFD < 0) { + fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + } + ClearAllFWHoles(); + fireWallActiveNum = fireWallBaseNum; + } +} + +static void +UninitPunchFW(void) { + ClearAllFWHoles(); + if (fireWallFD >= 0) + close(fireWallFD); + fireWallFD = -1; + if (fireWallField) + free(fireWallField); + fireWallField = NULL; + packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; +} + +/* Make a certain link go through the firewall */ +void +PunchFWHole(struct alias_link *link) { + int r; /* Result code */ + struct ip_fw rule; /* On-the-fly built rule */ + int fwhole; /* Where to punch hole */ + +/* Don't do anything unless we are asked to */ + if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || + fireWallFD < 0 || + link->link_type != LINK_TCP || + !link->data.tcp) + return; + + memset(&rule, 0, sizeof rule); + +/** Build rule **/ + + /* Find empty slot */ + for (fwhole = fireWallActiveNum; + fwhole < fireWallBaseNum + fireWallNumNums && + fw_tstfield(fireWallField, fwhole); + fwhole++) + ; + if (fwhole >= fireWallBaseNum + fireWallNumNums || + fw_tstfield(fireWallField, fwhole)) { + for (fwhole = fireWallBaseNum; + fwhole < fireWallActiveNum && + fw_tstfield(fireWallField, fwhole); + fwhole++) + ; + if (fwhole == fireWallActiveNum) { + /* No rule point empty - we can't punch more holes. */ + fireWallActiveNum = fireWallBaseNum; + fprintf(stderr, "libalias: Unable to create firewall hole!\n"); + return; + } + } + /* Start next search at next position */ + fireWallActiveNum = fwhole+1; + + /* Build generic part of the two rules */ + rule.fw_number = fwhole; +#if __FreeBSD_version < 300000 + rule.fw_nsp = 1; /* 1 source port */ + rule.fw_ndp = 1; /* 1 destination port */ +#else + rule.fw_nports = 1; /* Number of source ports; dest ports follow */ +#endif + rule.fw_flg = IP_FW_F_ACCEPT; + rule.fw_prot = IPPROTO_TCP; + rule.fw_smsk.s_addr = INADDR_BROADCAST; + rule.fw_dmsk.s_addr = INADDR_BROADCAST; + + /* Build and apply specific part of the rules */ + rule.fw_src = GetOriginalAddress(link); + rule.fw_dst = GetDestAddress(link); + rule.fw_pts[0] = ntohs(GetOriginalPort(link)); + rule.fw_pts[1] = ntohs(GetDestPort(link)); + + /* Skip non-bound links - XXX should not be strictly necessary, + but seems to leave hole if not done. Leak of non-bound links? + (Code should be left even if the problem is fixed - it is a + clear optimization) */ + if (rule.fw_pts[0] != 0 && rule.fw_pts[1] != 0) { + r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); + if (r) + err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); + rule.fw_src = GetDestAddress(link); + rule.fw_dst = GetOriginalAddress(link); + rule.fw_pts[0] = ntohs(GetDestPort(link)); + rule.fw_pts[1] = ntohs(GetOriginalPort(link)); + r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); + if (r) + err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); + } +/* Indicate hole applied */ + link->data.tcp->fwhole = fwhole; + fw_setfield(fireWallField, fwhole); +} + +/* Remove a hole in a firewall associated with a particular alias + link. Calling this too often is harmless. */ +static void +ClearFWHole(struct alias_link *link) { + if (link->link_type == LINK_TCP && link->data.tcp) { + int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ + struct ip_fw rule; + + if (fwhole < 0) + return; + + memset(&rule, 0, sizeof rule); + rule.fw_number = fwhole; + while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) + ; + fw_clrfield(fireWallField, fwhole); + link->data.tcp->fwhole = -1; + } +} + +/* Clear out the entire range dedicated to firewall holes. */ +static void +ClearAllFWHoles(void) { + struct ip_fw rule; /* On-the-fly built rule */ + int i; + + if (fireWallFD < 0) + return; + + memset(&rule, 0, sizeof rule); + for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { + rule.fw_number = i; + while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) + ; + } + memset(fireWallField, 0, fireWallNumNums); +} diff --git a/lib/libalias/alias_ftp.c b/lib/libalias/alias_ftp.c index e03c04b..df6d02c 100644 --- a/lib/libalias/alias_ftp.c +++ b/lib/libalias/alias_ftp.c @@ -32,6 +32,8 @@ Very minor changes to conform with local/global/function naming conventions withing the packet alising module. + + See HISTORY file for record of revisions. */ /* Includes */ @@ -150,6 +152,9 @@ NewFtpPortCommand(struct ip *pip, int slen, hlen, tlen, dlen; struct tcphdr *tc; +/* Punch hole in firewall */ + PunchFWHole(ftp_link); + /* Calculate data length of TCP packet */ tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); hlen = (pip->ip_hl + tc->th_off) << 2; @@ -167,7 +172,7 @@ NewFtpPortCommand(struct ip *pip, /* Decompose alias address into quad format */ alias_address = GetAliasAddress(link); - ptr = (char *) &alias_address; + ptr = (u_char *) &alias_address.s_addr; a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr; /* Decompose alias port into pair format */ diff --git a/lib/libalias/alias_irc.c b/lib/libalias/alias_irc.c index 3657368..933e3c6 100644 --- a/lib/libalias/alias_irc.c +++ b/lib/libalias/alias_irc.c @@ -223,6 +223,9 @@ lFOUND_CTCP: struct in_addr alias_address; /* Address from aliasing */ u_short alias_port; /* Port given by aliasing */ + /* Generate firewall hole as appropriate */ + PunchFWHole(dcc_link); + alias_address = GetAliasAddress(link); iCopy += snprintf(&newpacket[iCopy], sizeof(newpacket)-iCopy, diff --git a/lib/libalias/alias_local.h b/lib/libalias/alias_local.h index d71c80a..ba5f31f 100644 --- a/lib/libalias/alias_local.h +++ b/lib/libalias/alias_local.h @@ -12,6 +12,8 @@ */ +#ifndef ALIAS_LOCAL_H +#define ALIAS_LOCAL_H extern int packetAliasMode; @@ -53,7 +55,6 @@ FindOriginalAddress(struct in_addr); struct in_addr FindAliasAddress(struct in_addr); - /* External data access/modification */ void GetFragmentAddr(struct alias_link *, struct in_addr *); void SetFragmentAddr(struct alias_link *, struct in_addr); @@ -77,6 +78,8 @@ int GetDeltaSeqOut(struct ip *, struct alias_link *); void AddSeq(struct ip *, struct alias_link *, int); void SetExpire(struct alias_link *, int); void ClearCheckNewLink(void); +void PunchFWHole(struct alias_link *); + /* Housekeeping function */ void HouseKeeping(void); @@ -86,8 +89,11 @@ void HouseKeeping(void); void AliasHandleFtpOut(struct ip *, struct alias_link *, int); void AliasHandleIrcOut(struct ip *pip, struct alias_link *link, int maxsize ); -/* Log file control */ -void InitPacketAliasLog(void); -void UninitPacketAliasLog(void); +enum alias_tcp_state { + ALIAS_TCP_STATE_NOT_CONNECTED, + ALIAS_TCP_STATE_CONNECTED, + ALIAS_TCP_STATE_DISCONNECTED +}; /*lint -restore */ +#endif /* defined(ALIAS_LOCAL_H) */ diff --git a/lib/libalias/libalias.3 b/lib/libalias/libalias.3 index 6c86232..51f3194 100644 --- a/lib/libalias/libalias.3 +++ b/lib/libalias/libalias.3 @@ -20,8 +20,10 @@ of the text. 1. Introduction 2. Initialization and Control 2.1 PacketAliasInit() - 2.2 PacketAliasSetAddress() - 2.3 PacketAliasSetMode() + 2.2 PacketAliasUninit() + 2.3 PacketAliasSetAddress() + 2.4 PacketAliasSetMode() + 2.5 PacketAliasSetFWBase() 3. Packet Handling 3.1 PacketAliasOut() 3.2 PacketAliasIn() @@ -116,7 +118,24 @@ PacketAliasSetMode(). It is mandatory that this function be called at the beginning of a program prior to any packet handling. -.Ss 2.2 PacketAliasSetAddress() +.Ss 2.2 PacketAliasUnInit() + +.Ft void +.Fn PacketAliasUnInit "void" + +This function has no argument or return +value and is used to clear any resources +attached to internal data structures. + +This functions should be called when a +program stop using the aliasing engine; +it do, among other things, clear out any +firewall holes. To provide backwards +compatibility and extra security, it is +added to the atexit() chain by +PacketAliasInit(). Calling it multiple +times is harmless. +.Ss 2.3 PacketAliasSetAddress() .Ft void .Fn PacketAliasSetAddress "struct in_addr addr" @@ -145,7 +164,7 @@ call). It is mandatory that this function be called prior to any packet handling. -.Ss 2.3 PacketAliasSetMode() +.Ss 2.4 PacketAliasSetMode() .Ft void .Fn PacketAliasSetMode "int mode" "int mask" @@ -224,7 +243,31 @@ change or remain the same between dial-ups. If this mode bit is not set, it the link table will never be reset in the event of an address change. +.It PKT_ALIAS_PUNCH_FW. +This option make libalias `punch holes' in an +ipfw based firewall for FTP/IRC DCC connections. +The holes punched are bound by from/to IP address +and port; it will not be possible to use a hole +for another connection. A hole is removed when +the connection that use it die. To cater for +unexpected death of a program using libalias (e.g +kill -9), changing the state of the flag will +clear the entire ipfw range allocated for holes. +This will also happen on the initial call to +PacketAliasSetFWBase(). This call must happen +prior to setting this flag. + .El + +.Ss 2.5 PacketAliasSetFWBase() + +.Ft void +.Fn PacketAliasSetFWBase "unsigned int base" "unsigned int num" + +Set IPFW range allocated for punching firewall holes (with the +PKT_ALIAS_PUNCH_FW flag). The range will be cleared for all rules on +initialization. + .Sh 3. Packet Handling The packet handling functions are used to modify incoming (remote->local) and outgoing @@ -295,7 +338,7 @@ protocols place addresss and port information in the encapsulated data stream which have to be modified and can account for changes in packet length. Well known examples of such protocols -are FTP and IRC. +are FTP and IRC DCC. Return codes: .Bl -hang -offset left @@ -570,9 +613,10 @@ valid, PacketAliasInternetChecksum() will return zero. .Sh 7. Authors Charles Mott (cmott@srv.net), versions 1.0 - 1.8, 2.0 - 2.4. -Eivind Eiklund (eivind@freebsd.org), versions 1.8b and 1.9. -Added IRC support as well as contributing a number of -architectural improvements. +Eivind Eklund (eivind@freebsd.org), versions 1.8b, 1.9 and +2.5. Added IRC DCC support as well as contributing a number of +architectural improvements; added the firewall bypass +for FTP/IRC DCC. .Sh 8. Acknowledgments -- cgit v1.1