Messages in this thread Patch in this message | | | From | Keith Owens <> | Subject | Re: ip_masq_ftp: I wish it could keep the control socket from timing out. | Date | Mon, 05 May 1997 16:24:09 +1000 |
| |
On Mon, 5 May 1997 02:06:47 -0400 (EDT), Sameer Anja <sameer@securities.com> wrote: >Where is the patch available for this??
Masq patches can be found at http://www.indyramp.com/masq. here is the ftp timeout patch anyway, it should patch clean from 2.0.1 through 2.0.29.
--- linux-2.0.8/include/net/ip_masq.h Mon Jul 22 16:55:30 1996 +++ linux/include/net/ip_masq.h Mon Jul 22 17:32:50 1996 @@ -20,6 +20,7 @@ #define MASQUERADE_EXPIRE_TCP 15*60*HZ #define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ #define MASQUERADE_EXPIRE_UDP 5*60*HZ +#define MASQUERADE_EXPIRE_CONTROL 15*60*HZ #define IP_MASQ_F_OUT_SEQ 0x01 /* must do output seq adjust */ #define IP_MASQ_F_IN_SEQ 0x02 /* must do input seq adjust */ @@ -32,6 +33,9 @@ #define IP_MASQ_F_SAW_FIN (IP_MASQ_F_SAW_FIN_IN | \ IP_MASQ_F_SAW_FIN_OUT) /* tcp fin pkts seen */ +#define IP_MASQ_F_CONTROL 0x100 /* this is a control channel */ +#define IP_MASQ_F_NO_SPORT 0x200 /* no sport set yet */ +#define IP_MASQ_F_FTP_PASV 0x400 /* ftp PASV command just issued */ #ifdef __KERNEL__ @@ -59,6 +63,7 @@ struct ip_masq_app *app; /* bound ip_masq_app object */ void *app_data; /* Application private data */ unsigned flags; /* status flags */ + struct ip_masq *control; /* Corresponding control connection */ }; /* @@ -69,6 +74,7 @@ int tcp_timeout; int tcp_fin_timeout; int udp_timeout; + int control_timeout; }; extern struct ip_fw_masq *ip_masq_expire; diff -ur linux-2.0.8/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- linux-2.0.8/net/ipv4/ip_fw.c Mon Jul 22 16:55:30 1996 +++ linux/net/ipv4/ip_fw.c Mon Jul 22 17:00:56 1996 @@ -37,6 +37,8 @@ * Willy Konynenberg <willy@xos.nl> 10/5/96. * Make separate accounting on incoming and outgoing packets possible. * Jos Vos <jos@xos.nl> 18/5/1996. + * Add timeout reprieve for idle control channels. + * Keith Owens <kaos@ocs.com.au> 05/07/1996. * * * Masquerading functionality @@ -997,6 +999,11 @@ if (masq->udp_timeout) { ip_masq_expire->udp_timeout = masq->udp_timeout; + } + + if (masq->control_timeout) + { + ip_masq_expire->control_timeout = masq->control_timeout; } return 0; diff -ur linux-2.0.8/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- linux-2.0.8/net/ipv4/ip_masq.c Mon Jul 22 16:55:30 1996 +++ linux/net/ipv4/ip_masq.c Mon Jul 22 17:00:56 1996 @@ -15,6 +15,7 @@ * Nigel Metheringham : Added ICMP handling for demasquerade * Nigel Metheringham : Checksum checking of masqueraded data * Nigel Metheringham : Better handling of timeouts of TCP conns + * Keith Owens : Keep control channels alive if any related data entries. * * */ @@ -98,7 +99,8 @@ static struct ip_fw_masq ip_masq_dummy = { MASQUERADE_EXPIRE_TCP, MASQUERADE_EXPIRE_TCP_FIN, - MASQUERADE_EXPIRE_UDP + MASQUERADE_EXPIRE_UDP, + MASQUERADE_EXPIRE_CONTROL }; struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy; @@ -219,7 +221,7 @@ * broken out of the ip/tcp headers or directly supplied for those * pathological protocols with address/port in the data stream * (ftp, irc). addresses and ports are in network order. - * called for pkts coming from INside-to-outside the firewall. + * called for pkts coming from outside-to-INside the firewall. * * NB. Cannot check destination address, just for the incoming port. * reason: archie.doc.ac.uk has 6 interfaces, you send to @@ -274,6 +276,12 @@ * pathological protocols with address/port in the data stream * (ftp, irc). addresses and ports are in network order. * called for pkts coming from inside-to-OUTside the firewall. + * + * Normally we know the source address and port but for some protocols + * (e.g. ftp PASV) we do not know the source port initially. Alas the + * hash is keyed on source port so if the first lookup fails then try again + * with a zero port, this time only looking at entries marked "no source + * port". */ struct ip_masq * @@ -289,6 +297,14 @@ d_addr == ms->daddr && d_port == ms->dport ) return ms; } + hash = ip_masq_hash_key(protocol, s_addr, 0); + for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) { + if (ms->flags & IP_MASQ_F_NO_SPORT && + protocol == ms->protocol && + s_addr == ms->saddr && + d_addr == ms->daddr && d_port == ms->dport ) + return ms; + } return NULL; } @@ -315,9 +331,46 @@ static void masq_expire(unsigned long data) { - struct ip_masq *ms = (struct ip_masq *)data; + struct ip_masq *ms = (struct ip_masq *)data, *ms_data; unsigned long flags; + if (ms->flags & IP_MASQ_F_CONTROL) { + /* a control channel is about to expire */ + int idx = 0, reprieve = 0; +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("Masquerade control %s %lX:%X about to expire\n", + masq_proto_name(ms->protocol), + ntohl(ms->saddr),ntohs(ms->sport)); +#endif + save_flags(flags); + cli(); + + /* + * If any other masquerade entry claims that the expiring entry + * is its control channel then keep the control entry alive. + * Useful for long running data channels with inactive control + * links which we don't want to lose, e.g. ftp. + * Assumption: loops such as a->b->a or a->a will never occur. + */ + for (idx = 0; idx < IP_MASQ_TAB_SIZE && !reprieve; idx++) { + for (ms_data = ip_masq_m_tab[idx]; ms_data ; ms_data = ms_data->m_link) { + if (ms_data->control == ms) { + reprieve = 1; /* this control connection can live a bit longer */ + ip_masq_set_expire(ms, ip_masq_expire->control_timeout); +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("Masquerade control %s %lX:%X expiry reprieved\n", + masq_proto_name(ms->protocol), + ntohl(ms->saddr),ntohs(ms->sport)); +#endif + break; + } + } + } + restore_flags(flags); + if (reprieve) + return; + } + #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Masqueraded %s %lX:%X expired\n", masq_proto_name(ms->protocol), @@ -375,6 +428,7 @@ ms->dport = dport; ms->flags = mflags; ms->app_data = NULL; + ms->control = NULL; if (proto == IPPROTO_UDP) ms->flags |= IP_MASQ_F_NO_DADDR; @@ -483,9 +537,31 @@ #endif ms = ip_masq_out_get(iph); - if (ms!=NULL) + if (ms!=NULL) { ip_masq_set_expire(ms,0); + /* + * Set sport if not defined yet (e.g. ftp PASV). Because + * masq entries are hashed on sport, unhash with old value + * and hash with new. + */ + + if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) { + unsigned long flags; + ms->flags &= ~IP_MASQ_F_NO_SPORT; + save_flags(flags); + cli(); + ip_masq_unhash(ms); + ms->sport = portptr[0]; + ip_masq_hash(ms); /* hash on new sport */ + restore_flags(flags); +#ifdef DEBUG_CONFIG_IP_MASQUERADE + printk("ip_fw_masquerade(): filled sport=%d\n", + ntohs(ms->sport)); +#endif + } + } + /* * Nope, not found, create a new entry for it */ @@ -848,7 +924,7 @@ if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) { ms->flags &= ~IP_MASQ_F_NO_DPORT; ms->dport = portptr[0]; -#if DEBUG_CONFIG_IP_MASQUERADE +#ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_demasquerade(): filled dport=%d\n", ntohs(ms->dport)); #endif @@ -856,7 +932,7 @@ if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP) { ms->flags &= ~IP_MASQ_F_NO_DADDR; ms->daddr = iph->saddr; -#if DEBUG_CONFIG_IP_MASQUERADE +#ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_demasquerade(): filled daddr=%X\n", ntohs(ms->daddr)); #endif diff -ur linux-2.0.8/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c --- linux-2.0.8/net/ipv4/ip_masq_ftp.c Mon Jul 22 16:55:30 1996 +++ linux/net/ipv4/ip_masq_ftp.c Mon Jul 22 17:00:56 1996 @@ -10,6 +10,7 @@ * Fixes: * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands * Juan Jose Ciarlante : Code moved and adapted from ip_fw.c + * Keith Owens : Add keep alive for ftp control channel * * * @@ -66,8 +67,9 @@ iph = skb->h.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = (char *)&th[1]; - data_limit = skb->h.raw + skb->len - 18; + if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0)) + ms->flags |= IP_MASQ_F_FTP_PASV; while (data < data_limit) { @@ -123,6 +125,8 @@ if (n_ms==NULL) return 0; + n_ms->control = ms; /* keepalive from data to the control channel */ + ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */ } /* @@ -171,6 +175,108 @@ } +/* + * Look at incoming ftp packets to catch the response to a PASV command. When + * we see one we build a masquerading entry for the client address, client port + * 0 (unknown at the moment), the server address and the server port. Mark the + * current masquerade entry as a control channel and point the new entry at the + * control entry. All this work just for ftp keepalive across masquerading. + * + * The incoming packet should be something like + * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)". + * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number. + * ncftp 2.3.0 cheats by skipping the leading number then going 22 bytes into + * the data so we do the same. If it's good enough for ncftp then it's good + * enough for me. + * + * In this case, the client is the source machine being masqueraded, the server + * is the destination for ftp requests. It all depends on your point of view ... + */ + +int +masq_ftp_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) +{ + struct sk_buff *skb; + struct iphdr *iph; + struct tcphdr *th; + char *data, *data_limit; + unsigned char p1,p2,p3,p4,p5,p6; + __u32 to; + __u16 port; + struct ip_masq *n_ms; + + if (! ms->flags & IP_MASQ_F_FTP_PASV) + return 0; /* quick exit if no outstanding PASV */ + + skb = *skb_p; + iph = skb->h.iph; + th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + data = (char *)&th[1]; + data_limit = skb->h.raw + skb->len; + + while (data < data_limit && *data != ' ') + ++data; + while (data < data_limit && *data == ' ') + ++data; + data += 22; + if (data >= data_limit || *data != '(') + return 0; + p1 = simple_strtoul(data+1, &data, 10); + if (data >= data_limit || *data != ',') + return 0; + p2 = simple_strtoul(data+1, &data, 10); + if (data >= data_limit || *data != ',') + return 0; + p3 = simple_strtoul(data+1, &data, 10); + if (data >= data_limit || *data != ',') + return 0; + p4 = simple_strtoul(data+1, &data, 10); + if (data >= data_limit || *data != ',') + return 0; + p5 = simple_strtoul(data+1, &data, 10); + if (data >= data_limit || *data != ',') + return 0; + p6 = simple_strtoul(data+1, &data, 10); + if (data >= data_limit || *data != ')') + return 0; + + to = (p1<<24) | (p2<<16) | (p3<<8) | p4; + port = (p5<<8) | p6; + + /* + * Now update or create an masquerade entry for it + */ +#if DEBUG_CONFIG_IP_MASQ_FTP + printk("PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port); +#endif + n_ms = ip_masq_out_get_2(iph->protocol, + ms->saddr, 0, + htonl(to), htons(port)); + if (n_ms) { + /* existing masquerade, clear timer */ + ip_masq_set_expire(n_ms,0); + } + else { + n_ms = ip_masq_new(dev, IPPROTO_TCP, + ms->saddr, 0, + htonl(to), htons(port), + IP_MASQ_F_NO_SPORT); + + if (n_ms==NULL) + return 0; + n_ms->control = ms; /* keepalive from data to the control channel */ + ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */ + } + + /* + * keep for a bit longer than tcp_fin, client may not issue open + * to server port before tcp_fin_timeout. + */ + ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3); + ms->flags &= ~IP_MASQ_F_FTP_PASV; + return 0; /* no diff required for incoming packets, thank goodness */ +} + struct ip_masq_app ip_masq_ftp = { NULL, /* next */ "ftp", /* name */ @@ -179,7 +285,7 @@ masq_ftp_init_1, /* ip_masq_init_1 */ masq_ftp_done_1, /* ip_masq_done_1 */ masq_ftp_out, /* pkt_out */ - NULL /* pkt_in */ + masq_ftp_in, /* pkt_in */ }; /* --- linux/net/ipv4/ip_masq.c.orig Thu Jun 6 23:23:49 1996 +++ linux/net/ipv4/ip_masq.c Wed Sep 11 17:23:05 1996 @@ -949,7 +949,7 @@ if (offset < 128) { sprintf(temp, - "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d)", + "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires Flags (free=%d,%d)", ip_masq_free_ports[0], ip_masq_free_ports[1]); len = sprintf(buffer, "%-127s\n", temp); } @@ -968,7 +968,7 @@ timer_active = del_timer(&ms->timer); if (!timer_active) ms->timer.expires = jiffies; - sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu", + sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu %08X", masq_proto_name(ms->protocol), ntohl(ms->saddr), ntohs(ms->sport), ntohl(ms->daddr), ntohs(ms->dport), @@ -976,7 +976,8 @@ ms->out_seq.init_seq, ms->out_seq.delta, ms->out_seq.previous_delta, - ms->timer.expires-jiffies); + ms->timer.expires-jiffies, + ms->flags); if (timer_active) add_timer(&ms->timer); len += sprintf(buffer+len, "%-127s\n", temp);
| |