diff --unified -r linux-orig/arch/i386/config.in linux/arch/i386/config.in --- linux-orig/arch/i386/config.in Fri Apr 28 04:17:56 1995 +++ linux/arch/i386/config.in Tue Mar 5 23:24:39 1996 @@ -46,6 +46,9 @@ bool 'IP multicasting' CONFIG_IP_MULTICAST n bool 'IP firewalling' CONFIG_IP_FIREWALL n bool 'IP accounting' CONFIG_IP_ACCT n +if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_FIREWALL" = "y" ]; then + bool 'IP masquerading (ALPHA)(masqplus version)' CONFIG_IP_MASQUERADE n +fi comment '(it is safe to leave these untouched)' bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n bool 'Reverse ARP' CONFIG_INET_RARP n Only in linux/arch/i386: config.in.orig diff --unified -r linux-orig/include/linux/ip_fw.h linux/include/linux/ip_fw.h --- linux-orig/include/linux/ip_fw.h Thu Mar 9 13:33:55 1995 +++ linux/include/linux/ip_fw.h Tue Mar 5 23:24:39 1996 @@ -15,6 +15,9 @@ * Alan. * * All the real work was done by ..... + * + * Fixes: + * Pauline Middelink : Added masquerading. */ /* @@ -83,7 +86,8 @@ #define IP_FW_F_BIDIR 0x040 /* For bidirectional firewalls */ #define IP_FW_F_TCPSYN 0x080 /* For tcp packets-check SYN only */ #define IP_FW_F_ICMPRPL 0x100 /* Send back icmp unreachable packet */ -#define IP_FW_F_MASK 0x1FF /* All possible flag bits mask */ +#define IP_FW_F_MASQ 0x200 /* Masquerading */ +#define IP_FW_F_MASK 0x3FF /* All possible flag bits mask */ /* * New IP firewall options for [gs]etsockopt at the RAW IP level. @@ -134,14 +138,30 @@ extern struct ip_fw *ip_fw_fwd_chain; extern int ip_fw_blk_policy; extern int ip_fw_fwd_policy; +extern int ip_fw_chk(struct iphdr *, struct device *rif,struct ip_fw *, int, int); extern int ip_fw_ctl(int, void *, int); #endif #ifdef CONFIG_IP_ACCT extern struct ip_fw *ip_acct_chain; -extern void ip_acct_cnt(struct iphdr *, struct device *, struct ip_fw *); extern int ip_acct_ctl(int, void *, int); #endif -extern int ip_fw_chk(struct iphdr *, struct device *rif,struct ip_fw *, int, int); +#ifdef CONFIG_IP_MASQUERADE +struct ip_masq { + struct ip_masq *next; /* next member in list */ + struct timer_list timer; /* Expiration timer */ + __u16 protocol; /* Which protocol are we talking? */ + __u32 src, dst; /* Source and destination IP addresses */ + __u16 sport,dport; /* Source and destoination ports */ + __u16 mport; /* Masquaraded port */ + __u32 init_seq; /* Add delta from this seq. on */ + short delta; /* Delta in sequence numbers */ + short previous_delta; /* Delta in sequence numbers before last resized PORT command */ + char sawfin; /* Did we saw an FIN packet? */ +}; +extern struct ip_masq *ip_msq_hosts; +extern void ip_fw_masquerade(struct sk_buff **, struct device *); +extern int ip_fw_demasquerade(struct sk_buff *); +#endif #endif /* KERNEL */ #endif /* _IP_FW_H */ Only in linux/include/linux: ip_fw.h.orig diff --unified -r linux-orig/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- linux-orig/include/linux/proc_fs.h Sun Feb 12 14:11:02 1995 +++ linux/include/linux/proc_fs.h Tue Mar 5 23:24:40 1996 @@ -74,6 +74,9 @@ #ifdef CONFIG_IP_ACCT PROC_NET_IPACCT, #endif +#ifdef CONFIG_IP_MASQUERADE + PROC_NET_IPMSQHST, +#endif #if defined(CONFIG_WAVELAN) PROC_NET_WAVELAN, #endif /* defined(CONFIG_WAVELAN) */ Only in linux/include/linux: proc_fs.h.orig diff --unified -r linux-orig/net/inet/ip.c linux/net/inet/ip.c --- linux-orig/net/inet/ip.c Tue May 30 07:33:31 1995 +++ linux/net/inet/ip.c Tue Mar 5 23:25:12 1996 @@ -62,6 +62,8 @@ * Alan Cox : RAW sockets demultiplex in the BSD style. * Gunther Mayer : Fix the SNMP reporting typo * Alan Cox : Always in group 224.0.0.1 + * Pauline Middelink : Fast ip_checksum update when forwarding + * Masquerading support. * Alan Cox : Multicast loopback error for 224.0.0.1 * Alan Cox : IP_MULTICAST_LOOP option. * Alan Cox : Use notifiers. @@ -1256,26 +1258,27 @@ * Forward an IP datagram to its next destination. */ -static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) +static void ip_forward(struct sk_buff **skb_ptr, struct device *dev, int is_frag) { + struct sk_buff *skb=*skb_ptr; struct device *dev2; /* Output device */ struct iphdr *iph; /* Our header */ struct sk_buff *skb2; /* Output packet */ struct rtable *rt; /* Route we use */ unsigned char *ptr; /* Data pointer */ unsigned long raddr; /* Router IP address */ - +#ifdef CONFIG_IP_FIREWALL + int fw_res = 0; /* Forwarding Result */ + /* * See if we are allowed to forward this. + * Note: demasqueraded fragments are always 'back'warded. */ -#ifdef CONFIG_IP_FIREWALL - int err; - - if((err=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0))!=1) - { - if(err==-1) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); + if( !(is_frag&4) && (fw_res=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0))<1) + { + if(fw_res==-1) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); return; } #endif @@ -1292,12 +1295,6 @@ iph = skb->h.iph; iph->ttl--; - if (iph->ttl <= 0) - { - /* Tell the sender its packet died... */ - icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev); - return; - } /* * Re-compute the IP header checksum. @@ -1305,7 +1302,25 @@ * and could thus adjust the checksum as Phil Karn does in KA9Q */ +#if 0 ip_send_check(iph); +#else + /* + * Like this? + * Notice we must do the additions in HOST format! + */ + iph->check = ntohs(iph->check) + 0x0100; + if ((iph->check & 0xFF00) == 0) + iph->check++; /* carry overflow */ + iph->check = htons(iph->check); +#endif + + if (iph->ttl <= 0) + { + /* Tell the sender its packet died... */ + icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev); + return; + } /* * OK, the packet is still valid. Fetch its destination address, @@ -1366,12 +1381,26 @@ * arrived upon. We now generate an ICMP HOST REDIRECT giving the route * we calculated. */ -#ifdef CONFIG_IP_NO_ICMP_REDIRECT +#ifdef HAVE_IP_ALIAS + +# ifdef CONFIG_IP_NO_ICMP_REDIRECT if (dev == dev2) return; -#else +# else + if (dev == dev2 && + ((iph->saddr&dev->pa_mask) == (iph->daddr & dev->pa_mask) + || + (!dev->aliases || ip_alias_same_network(rt,iph->saddr)))) + icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev); +# endif +#else /* HAVE_IP_ALIAS */ +# ifdef CONFIG_IP_NO_ICMP_REDIRECT + if (dev == dev2) + return; +# else if (dev == dev2 && (iph->saddr&dev->pa_mask) == (iph->daddr & dev->pa_mask)) icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev); +# endif #endif /* @@ -1381,6 +1410,17 @@ if (dev2->flags & IFF_UP) { +#ifdef CONFIG_IP_MASQUERADE + /* + * If this fragment needs masquerading, make it so... + * (Dont masquerade de-masqueraded fragments) + */ + if (!(is_frag&4) && fw_res==2) + { + ip_fw_masquerade(&skb, dev2); + *skb_ptr=skb; + } +#endif /* * Current design decrees we copy the packet. For identical header @@ -1431,7 +1471,7 @@ * Count mapping we shortcut */ - ip_acct_cnt(iph,dev,ip_acct_chain); + ip_fw_chk(iph,dev,ip_acct_chain,0,1); #endif /* @@ -1449,8 +1489,26 @@ } } +#ifdef HAVE_IP_ALIAS +int +ip_alias_same_network(struct rtable *drt, unsigned long saddr) +{ + struct rtable *srt; + + srt = ip_rt_route(saddr, NULL, NULL); -#endif + /* no route to source network or not directly connected */ + if (!srt || srt->rt_gateway) + return 0; + + if (srt->rt_dst != drt->rt_dst || srt->rt_mask != drt->rt_mask) + return 0; + + return 1; +} +#endif /* HAVE_IP_ALIAS */ + +#endif /* CONFIG_IP_FORWARD */ /* * This function receives all incoming IP datagrams. @@ -1503,7 +1561,7 @@ #ifdef CONFIG_IP_FIREWALL - if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy, 0))!=1) + if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy,0))<1) { if(err==-1) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev); @@ -1578,7 +1636,7 @@ */ #ifdef CONFIG_IP_FORWARD - ip_forward(skb, dev, is_frag); + ip_forward(&skb, dev, is_frag); #else /* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", iph->saddr,iph->daddr);*/ @@ -1615,12 +1673,14 @@ while(1); } #endif + + /* * Account for the packet */ - + #ifdef CONFIG_IP_ACCT - ip_acct_cnt(iph,dev, ip_acct_chain); + ip_fw_chk(iph,dev,ip_acct_chain,0,1); #endif /* @@ -1636,22 +1696,37 @@ skb->dev = dev; iph=skb->h.iph; } - - +#ifdef CONFIG_IP_MASQUERADE + /* + * Do we need to de-masquerade this fragment? + */ + /* + To fix the data corruption problem, we discard datagram with + bad checksum merr=-1. For merr=0 it is not a masquerade. + */ + { + int merr; + if (merr=ip_fw_demasquerade(skb)) { + if(merr > 0) ip_forward(&skb, dev, is_frag|4); + kfree_skb(skb, FREE_WRITE); + return(0); + } + } +#endif /* * Point into the IP datagram, just past the header. */ skb->ip_hdr = iph; skb->h.raw += iph->ihl*4; - + /* * Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies. */ - + hash = iph->protocol & (SOCK_ARRAY_SIZE-1); - + /* If there maybe a raw socket we must check - if not we don't care less */ if((raw_sk=raw_prot.sock_array[hash])!=NULL) { @@ -1923,7 +1998,7 @@ ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_ACCT - ip_acct_cnt(iph,dev, ip_acct_chain); + ip_fw_chk(iph,dev,ip_acct_chain,0,1); #endif #ifdef CONFIG_IP_MULTICAST @@ -2091,6 +2166,8 @@ unsigned char ucval; ucval=get_fs_byte((unsigned char *)optval); + if(ucval<1||ucval>255) + return -EINVAL; sk->ip_mc_ttl=(int)ucval; return 0; } diff --unified -r linux-orig/net/inet/ip_fw.c linux/net/inet/ip_fw.c --- linux-orig/net/inet/ip_fw.c Sun Jun 11 12:45:10 1995 +++ linux/net/inet/ip_fw.c Tue Mar 5 23:25:23 1996 @@ -1,3 +1,6 @@ +/* Should remove or move the defs below - ACC 03/05/96 */ +#define STREAMWORKS 1 +#define TCP_DATA_CHECK 1 /* * IP firewalling code. This is taken from 4.4BSD. Please note the * copyright message below. As per the GPL it must be maintained @@ -21,6 +24,41 @@ * Jos Vos 5/Mar/1995. * * All the real work was done by ..... + * + * Fixes: + * Pauline Middelink : Added masquerading. + * Augusto Cardoso : Added FTP spoofing from kernel 1.3.XX + * Augusto Cardoso : Added RealAudio support from SLIRP + * Augusto Cardoso : Added STREAMWORK support + * Augusto Cardoso : Change UDP expire in demasquerade + * Augusto Cardoso : Change REALAUDIO to version 2.0beta + * Augusto Cardoso : Fix a data corruption problem - see TCP_DATA_CHECK + */ + +/* + * Masquerading functionality + * + * Copyright (c) 1994 Pauline Middelink + * + * The pieces which added masquerading functionality are totaly + * my responsibility and have nothing to with the original authors + * copyright or doing. + * + * Parts distributed under GPL. + */ + +/* + * Extended Masquerading functionality + * + * Copyright (c) 1995, 1996 Augusto Cardoso + * + * Same as above + * + * FTP spoofing adapted from kernel 1.3.37 + * RealAudio based on the SLIRP implementation from Juha Pirkola + * StreamWorks is my own hacking, be aware + * I am not responsible for anything... but if you have comments, bugs or requests + * send email to augusto@villam.com */ /* @@ -58,6 +96,7 @@ #include "protocol.h" #include "route.h" #include "tcp.h" +#include "udp.h" #include #include "sock.h" #include "icmp.h" @@ -104,6 +143,37 @@ #define IP_INFO_FWD 1 #define IP_INFO_ACCT 2 +/* + * Implement IP packet masquerading + */ + +#ifdef CONFIG_IP_MASQUERADE + +#define DEBUG_MASQ 1 +#undef DEBUG_MASQ + +#define MASQUERADE_EXPIRE_TCP 60*60*HZ +#define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ +#define MASQUERADE_EXPIRE_UDP 5*60*HZ + +/* + * Linux ports don't get allocated above 32K. I used a extra 4K port-space + */ +#define MASQ_TYPE_NORMAL 1 +#define MASQ_TYPE_REALAUDIO 2 + +#define PORT_MASQ_BEGIN 50000 +#define PORT_MASQ_END (PORT_MASQ_BEGIN+4096) +#define PORT_MASQ_REALAUDIO_BEGIN 6970 +#define PORT_MASQ_REALAUDIO_END 7170 +#define FTP_DPORT_TBD (PORT_MASQ_END+1) /* Avoid using hardcoded port 20 for ftp data connection */ + +static unsigned short masq_port = PORT_MASQ_BEGIN; +static unsigned short masq_port_realaudio = PORT_MASQ_REALAUDIO_BEGIN; +static char *strProt[] = {"UDP","TCP"}; +struct ip_masq *ip_msq_hosts; + +#endif /* * Returns 1 if the port is matched by the vector, 0 otherwise @@ -136,8 +206,10 @@ /* - * Returns 0 if packet should be dropped, 1 if it should be accepted, - * and -1 if an ICMP host unreachable packet should be sent. + * Returns 0 if packet should be dropped, 1 if it should be + * accepted and -1 if an ICMP host unreachable packet should + * be sent. Returns 2 to indicate it as matched by a masquerading rule. + * * Also does accounting so you can feed it the accounting chain. * If opt is set to 1, it means that we do this for accounting * purposes (searches all entries and handles fragments different). @@ -149,25 +221,16 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int policy, int opt) { struct ip_fw *f; - struct tcphdr *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl); - struct udphdr *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl); + struct tcphdr *tcp=(struct tcphdr *)((unsigned char *)ip+ip->ihl*4); + struct udphdr *udp=(struct udphdr *)((unsigned char *)ip+ip->ihl*4); __u32 src, dst; __u16 src_port=0, dst_port=0; unsigned short f_prt=0, prt; char notcpsyn=1, frag1, match; unsigned short f_flag; - /* - * If the chain is empty follow policy. The BSD one - * accepts anything giving you a time window while - * flushing and rebuilding the tables. - */ - - src = ip->saddr; - dst = ip->daddr; - /* - * This way we handle fragmented packets. + * This way we handle fragmented packets: * we ignore all fragments but the first one * so the whole packet can't be reassembled. * This way we relay on the full info which @@ -195,7 +258,7 @@ * per device. We have a device per address with dummy * devices instead. */ - + dprintf1("Packet "); switch(ip->protocol) { @@ -388,12 +451,765 @@ else f_flag=policy; if(f_flag&IP_FW_F_ACCEPT) - return 1; + return (f_flag&IP_FW_F_MASQ) ? 2 : 1; if(f_flag&IP_FW_F_ICMPRPL) return -1; return 0; } +#ifdef CONFIG_IP_MASQUERADE + +static +void masq_expire(unsigned long data) +{ + struct ip_masq *ms = (struct ip_masq *)data; + struct ip_masq *old,*cur; + unsigned long flags; + +#ifdef DEBUG_MASQ + printk("Masqueraded %s %lX:%X expired\n", + strProt[ms->protocol==IPPROTO_TCP], + ntohl(ms->src),ntohs(ms->sport)); +#endif + + save_flags(flags); + cli(); + + /* delete from list of hosts */ + old = NULL; + cur = ip_msq_hosts; + while (cur!=NULL) { + if (cur==ms) { + if (old==NULL) ip_msq_hosts = ms->next; + else old->next = ms->next; + kfree_s(ms,sizeof(*ms)); + break; + } + old = cur; + cur=cur->next; + } + restore_flags(flags); +} + +/* + * Create a new masquerade list entry, also allocate an + * unused mport, keeping the portnumber between the + * given boundaries MASQ_BEGIN and MASQ_END. + * + * FIXME: possible deadlock if all free ports are exhausted! + */ +static +struct ip_masq *alloc_masq_entry(int type) +{ + struct ip_masq *ms, *mst; + unsigned long flags; + + ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC); + if (ms==NULL) + return NULL; + + memset(ms,0,sizeof(*ms)); + init_timer(&ms->timer); + ms->timer.data = (unsigned long)ms; + ms->timer.function = masq_expire; + + save_flags(flags); + cli(); + do { + /* Try the next available port number */ + if(type == MASQ_TYPE_REALAUDIO) + { + ms->mport = htons(masq_port_realaudio++); + if (masq_port_realaudio==PORT_MASQ_REALAUDIO_END) + masq_port_realaudio = PORT_MASQ_REALAUDIO_BEGIN; + } else + { + ms->mport = htons(masq_port++); + if (masq_port==PORT_MASQ_END) + masq_port = PORT_MASQ_BEGIN; + } + + /* Now hunt through the used ports to see if + * this port is in use... */ + mst = ip_msq_hosts; + while (mst && mst->mport!=ms->mport) + mst = mst->next; + } + while (mst!=NULL); + + /* add new entry in front of list to minimize lookup-time */ + ms->next = ip_msq_hosts; + ip_msq_hosts = ms; + restore_flags(flags); + + return ms; +} + + + /* + * RealAudio emulation - JP. We must try to parse the incoming + * data and try to find the two characters that contain the + * port number. Then we redirect an udp port and replace the + * number with the real port we got. + * + * The 1.0 beta versions of the player are not supported + * any more. + * + * A typical packet for player version 1.0 (release version): + * + * 0000:50 4E 41 00 05 + * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P + * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH + * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v + * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB + * + * Now the port number 0x1BD7 is found at offset 0x04 of the + * Now the port number 0x1BD7 is found at offset 0x04 of the + * second packet. This time we received five bytes first and + * then the rest. You never know how many bytes you get. + * + * A typical packet for player version 2.0 (beta): + * + * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á. + * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0 + * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ + * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas + * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B + * + * Port number 0x1BC1 is found at offset 0x0d. + * + * This is just a horrible switch statement. Variable ra tells + * us where we're going. + */ + +static +int revamp_realaudio(struct sk_buff *skb, struct ip_masq *ms) +{ + struct iphdr *iph = skb->h.iph; + struct tcphdr *th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + struct ip_masq *ms2; + char *bptr, *data = (char *)&th[1]; + + bptr = data; +#ifdef DEBUG_MASQ + printk("REVAMP_REALAUDIO: len %d used %d\n",skb->len, (skb->len - ((unsigned char *)bptr - skb->h.raw))); +#endif + while (skb->len - ((unsigned char *)bptr - skb->h.raw) > 20){ + u_short p, lport; + static int ra = 0; + char ra_tbl[4]; + + ra_tbl[0] = 0x50; + ra_tbl[1] = 0x4e; + ra_tbl[2] = 0x41; + ra_tbl[3] = 0; + +#ifdef DEBUG_MASQ +printk("REVAMP_REALAUDIO: Loop ra %d *bptr %d\n",ra,(int)*bptr); +#endif + switch (ra) { + case 0: + case 2: + case 3: + if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + /* return skb; */ + } + break; + case 1: + /* + * We may get 0x50 several times, ignore them + */ + if (*bptr == 0x50) { + ra = 1; + bptr++; + continue; + } else if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 4: + /* + * skip version number + */ + bptr++; + break; + + case 5: + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of + * the player this may need to be modified. + */ + if (*(bptr + 1) == 0x02) + bptr += 8; + else + bptr += 4; + break; + + case 6: + /* This is the field containing the port + * number that RA-player is listening to. + */ + lport = (((u_char*)bptr)[0] << 8) + + ((u_char *)bptr)[1]; + if (lport < 6970) + lport += 256; /* don't know why */ + /* try to get udp port between 6970 - 7170 */ + ms2 = alloc_masq_entry(MASQ_TYPE_REALAUDIO); + if (ms2==NULL) { + printk("MASQUERADE: no memory left for revamp!\n"); + return 0; + } + ms2->protocol = IPPROTO_UDP; + ms2->src = ms->src; + ms2->dst = ms->dst; + ms2->sport = htons(lport); + ms2->dport = htons(lport); + ms2->timer.expires = MASQUERADE_EXPIRE_UDP; + add_timer(&ms2->timer); + + p=ntohs(ms2->mport); + *(u_char *)bptr++ = (p >> 8) & 0xff; + *(u_char *)bptr++ = p & 0xff; +#ifdef DEBUG_MASQ +printk("REVAMP_REAL: lport %d masq port %d \n",(int)lport,(int)p); +#endif + ra = 0; + return 1; /* port redirected, we're done */ + break; + + default: + ra = 0; + } + ra++; + } + return 1; +} + +/* + * When passing an FTP 'PORT' command, try to replace the IP + * address with an newly assigned (masquereded) port on this + * host, so the ftp-data connect FROM the site will succeed... + * + * Also, when the size of the packet changes, create an delta + * offset, which will be added to every th->seq (and subtracted for + * (th->acqseq) whose seq > init_seq. + * + * Not for the faint of heart! + */ +static +struct sk_buff *revamp(struct sk_buff *skb, struct device *dev, struct ip_masq *ftp) +{ + struct iphdr *iph = skb->h.iph; + struct tcphdr *th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + struct sk_buff *skb2; + char *p, *data = (char *)&th[1]; + unsigned char p1,p2,p3,p4,p5,p6; + unsigned long from; + unsigned short port; + struct ip_masq *ms; + char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ + int diff; + __u32 seq; + + + /* + * Adjust seq with delta-offset for all packets after the most recent +resized PORT command + * and with previous_delta offset for all packets before most recent +resized PORT + */ + + /* + * seq & seq_ack are in network byte order; need conversion before +comparing + */ + seq=ntohl(th->seq); + if (ftp->delta || ftp->previous_delta) + { + if(after(seq,ftp->init_seq) ) + { + th->seq = htonl(seq + ftp->delta); +#ifdef DEBUG_MASQ + printk("masq_revamp : added delta (%d) to +seq\n",ftp->delta); +#endif + } + else + { + th->seq = htonl(seq + ftp->previous_delta); +#ifdef DEBUG_MASQ + printk("masq_revamp : added previous_delta (%d) to +seq\n",ftp->previous_delta); +#endif + } + } +#ifdef DEBUG_MASQ +printk("The number is: %d\n",skb->len - ((unsigned char *)data - skb->h.raw)); +#endif + while (skb->len - ((unsigned char *)data - skb->h.raw) > 18) + { + if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) + { + data ++; + continue; + } + p = data+5; + p1 = simple_strtoul(data+5,&data,10); + if (*data!=',') + continue; + p2 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p3 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p4 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p5 = simple_strtoul(data+1,&data,10); + if (*data!=',') + continue; + p6 = simple_strtoul(data+1,&data,10); + if (*data!='\r' && *data!='\n') + continue; + + from = (p1<<24) | (p2<<16) | (p3<<8) | p4; + port = (p5<<8) | p6; +#ifdef DEBUG_MASQ +printk("PORT %lX:%X detected\n",from,port); +#endif + + /* + * Now create an masquerade entry for it + */ + ms = alloc_masq_entry(MASQ_TYPE_NORMAL); + if (ms==NULL) + return skb; + ms->protocol = IPPROTO_TCP; + ms->src = htonl(from); /* derived from PORT cmd */ + ms->sport = htons(port); /* derived from PORT cmd */ + ms->dst = iph->daddr; + /* + * Hardcoding 20 as dport is not always correct + * At least 1 Windows ftpd uses a random port number instea +20 + * Leave it undefined for now & wait for the first connecti +request to fill it out + */ + ms->dport = htons(FTP_DPORT_TBD); /* ftp-data */ + ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN; + + ms->timer.expires = MASQUERADE_EXPIRE_TCP_FIN; + add_timer(&ms->timer); + + /* + * Replace the old PORT with the new one + */ + from = ntohl(dev->pa_addr); + port = ntohs(ms->mport); + sprintf(buf,"%ld,%ld,%ld,%ld,%d,%d", + from>>24&255,from>>16&255,from>>8&255,from&255, + port>>8&255,port&255); + +#ifdef DEBUG_MASQ +printk("New FTP command:( %s )\n",buf); +#endif + /* + * Calculate required delta-offset to keep TCP happy + */ + diff = strlen(buf) - (data-p); + if (diff==0) { + /* + * simple case, just replace the old PORT cmd + */ + memcpy(p,buf,strlen(buf)); + return skb; + } + /* + * If the PORT command we have fiddled is the first, or is +a + * resend don't do the delta shift again. Doesn't work for + * pathological cases, but we would need a history for +that. + * Also fails if you send 2^31 bytes of data down the link + + * after the first port command. + * + * FIXME: use ftp->init_seq_valid - 0 is a valid sequence. + */ + +#ifdef DEBUG_MASQ +printk("REVAMP: diff %d init_seq %d after %d\n",diff, ftp->init_seq,after(seq, ftp->init_seq)); +#endif + if(!ftp->init_seq || after(seq,ftp->init_seq) ) + { + ftp->previous_delta=ftp->delta; + ftp->delta+=diff; + ftp->init_seq = seq; + } + /* + * Sizes differ, make a copy + */ +#ifdef DEBUG_MASQ +printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",ftp->delta, skb->len); +#endif + +#if NEW_SKB + skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC); +#else +/* +In the current implementation: +mem_len = the size of the original skb+the overhead(sk_buff) +We need to sub. because it will be added again in alloc_skb. +Just add the diff. +*/ + skb2 = alloc_skb(skb->mem_len-sizeof(struct sk_buff)+diff, GFP_ATOMIC); +#endif + if (skb2 == NULL) { + printk("MASQUERADE: No memory available\n"); + return skb; + } + skb2->free = skb->free; +/* I don't see the need for this ??? + skb2->data+=MAX_HEADER; +*/ +/* The New things... + skb_reserve(skb2,MAX_HEADER); +*/ + skb2->len=skb->len + diff; +/* The New stuff + skb_put(skb2,skb->len + diff); +*/ + skb2->h.raw = skb2->data + (skb->h.raw - skb->data); + iph=skb2->h.iph; + /* + * Mend the IP header too + */ + iph->tot_len = htons(diff+ntohs(iph->tot_len)); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + /* + * Copy the packet data into the new buffer. + * Thereby replacing the PORT cmd. + */ + memcpy(skb2->data, skb->data, (p - (char *)skb->data)); + memcpy(&skb2->data[(p - (char *)skb->data)], buf, strlen(buf)); +#ifdef DEBUG_MASQ +printk("New count %d old %d my %d\n", + skb->len - (data-(char *)skb->data), + skb->mem_len - sizeof(struct sk_buff) - ((char *)skb->h.raw - data), + skb->mem_len - sizeof(struct sk_buff) - (data-(char *)skb->data) ); +printk("where len %d mem_len %d sizeof %d data-skb->data %d p-skb->data %d len-buf %d\n", +skb->len,skb->mem_len, +sizeof(struct sk_buff) , (data-(char *)skb->data) , +(p - (char *)skb->data), strlen(buf) +); +#endif + +#ifdef NEW_SKB + memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data, + skb->len - (data-(char *)skb->data)); +#else +/* This is the OLD_MASQ */ + memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data, + skb->mem_len - sizeof(struct sk_buff) - (data-(char *)skb->data) ); +#endif + + /* + * Update tot_len field in ip header ! + * Sequence numbers were allready modified in original packet + */ +#ifdef DEBUG_MASQ +printk("IP H. tot_len %d skb->len %d diff %d\n",iph->tot_len, skb->len, diff); +#endif + iph->tot_len = htons(skb->len + diff); + + /* + * Problem, how to replace the new skb with old one, + * preferably inplace, so all the pointers in the + * calling tree keep ok :( + */ + kfree_skb(skb, FREE_WRITE); + return skb2; + } + return skb; +} + +void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) +{ + struct sk_buff *skb=*skb_ptr; + struct iphdr *iph = skb->h.iph; + unsigned short *portptr; + struct ip_masq *ms; + int size; + + /* + * We can only masquerade protocols with ports... + */ + if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) + return; + + /* + * Now hunt the list to see if we have an old entry + */ + portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); + ms = ip_msq_hosts; + +#ifdef DEBUG_MASQ + printk("Outgoing %s %lX:%X -> %lX:%X\n", + strProt[iph->protocol==IPPROTO_TCP], + ntohl(iph->saddr), ntohs(portptr[0]), + ntohl(iph->daddr), ntohs(portptr[1])); +#endif + while (ms!=NULL) { + if (iph->protocol == ms->protocol && + iph->saddr == ms->src && iph->daddr == ms->dst && + portptr[0] == ms->sport && portptr[1] == ms->dport) { + del_timer(&ms->timer); + break; + } + ms = ms->next; + } + + /* + * Nope, not found, create a new entry for it + */ + if (ms==NULL) { + ms = alloc_masq_entry(MASQ_TYPE_NORMAL); + if (ms==NULL) { + printk("MASQUERADE: no memory left !\n"); + return; + } + ms->protocol = iph->protocol; + ms->src = iph->saddr; + ms->dst = iph->daddr; + ms->sport = portptr[0]; + ms->dport = portptr[1]; + } + + /* + * Change the fragments origin + */ + size = skb->len - ((unsigned char *)portptr - skb->h.raw); + iph->saddr = dev->pa_addr; /* my own address */ + portptr[0] = ms->mport; + + /* + * Adjust packet accordingly to protocol + */ + if (iph->protocol==IPPROTO_UDP) { + ms->timer.expires = MASQUERADE_EXPIRE_UDP; + udp_send_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size,skb->sk); + } + else { + struct tcphdr *th; +/* notdef here */ + if (portptr[1]==htons(21)) { + skb = revamp(*skb_ptr, dev, ms); + *skb_ptr = skb; + iph = skb->h.iph; + portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); +#ifdef DEBUG_MASQ +printk("Before revamp size %d\n",size); +#endif + size = skb->len - ((unsigned char *)portptr-skb->h.raw); +#ifdef DEBUG_MASQ +printk("After revamp size %d\n",size); +#endif + } + else if (portptr[1]==htons(7070)) { + int st_ra=revamp_realaudio(*skb_ptr, ms); + portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); + } +#ifdef notdef +#endif + th = (struct tcphdr *)portptr; + + /* + * Timeout depends if FIN packet was seen + */ + if (ms->sawfin || th->fin) { + ms->timer.expires = MASQUERADE_EXPIRE_TCP_FIN; + ms->sawfin = 1; + } + else ms->timer.expires = MASQUERADE_EXPIRE_TCP; + + tcp_send_check(th,iph->saddr,iph->daddr,size,skb->sk); + } + add_timer(&ms->timer); + ip_send_check(iph); + +#ifdef DEBUG_MASQ + printk("O-routed from %lX:%X over %s\n",ntohl(dev->pa_addr),ntohs(ms->mport),dev->name); +#endif +} + +/* + * Check if it's an masqueraded port, look it up, + * and send it on it's way... + * + * Better not have many hosts using the designated portrange + * as 'normal' ports, or you'll be spending lots of time in + * this function. + */ +int ip_fw_demasquerade(struct sk_buff *skb) +{ + struct iphdr *iph = skb->h.iph; + unsigned short *portptr; + struct ip_masq *ms; + struct tcphdr *th = (struct tcphdr *)(skb->h.raw+(iph->ihl<<2)); + int size; + + if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) + return 0; + + portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]); + if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN || + ntohs(portptr[1]) > PORT_MASQ_END) + && !(ntohs(portptr[1]) >= PORT_MASQ_REALAUDIO_BEGIN && + ntohs(portptr[1]) <= PORT_MASQ_REALAUDIO_END)) + return 0; + +#ifdef DEBUG_MASQ + printk("Incoming %s %lX:%X -> %lX:%X\n", + strProt[iph->protocol==IPPROTO_TCP], + ntohl(iph->saddr), ntohs(portptr[0]), + ntohl(iph->daddr), ntohs(portptr[1])); +#endif + /* + * reroute to original host:port if found... + * + * NB. Cannot check destination address, just for the incoming port. + * reason: archie.doc.ac.uk has 6 interfaces, you send to + * phoenix and get a reply from any other interface(==dst)! + * + * [Only for UDP] - AC + */ +/* +STREAMWORKS CC + Apparently Xing Streamworks will right to our port 1558 from different ports + For the paranoic this may be a security problem??? I am confident that this is OK. + ACC - 12/05/95 +*/ + ms = ip_msq_hosts; + while (ms!=NULL) { + if (iph->protocol==ms->protocol + && (iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) +#ifdef STREAMWORKS + && (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport + || ms->sport == htons(1558) || + ((ntohs(ms->sport) >= PORT_MASQ_REALAUDIO_BEGIN) + && (ntohs(ms->sport) <= PORT_MASQ_REALAUDIO_END) + && (iph->protocol==IPPROTO_UDP))) + && portptr[1]==ms->mport) +#else + && (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) + && portptr[1]==ms->mport) +#endif + { + size = skb->len - ((unsigned char *)portptr - skb->h.raw); +#ifdef TCP_DATA_CHECK + if (iph->protocol==IPPROTO_TCP) + { + unsigned short my_check; + /* Calculate the checksum with th->check in it, + if it is 0, the datagram is okay, otherwise trash it + by return -1. */ + my_check=tcp_check(th, size, iph->saddr, + iph->daddr); + if(my_check != 0) + { +#ifdef DEBUG_MASQ + printk("DEMASQ: BAD CHECKSUM(0x%x) ",my_check); + printk(" %lX:%X -> %lX:%X\n", + ntohl(iph->saddr), ntohs(portptr[0]), + ntohl(iph->daddr), ntohs(portptr[1])); +#endif + return -1; + } + } +#endif + iph->daddr = ms->src; + portptr[1] = ms->sport; + + if(ms->dport==htons(FTP_DPORT_TBD)) + { + ms->dport=portptr[0]; +#ifdef DEBUG_MASQ + printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport)); +#endif + } + + /* + * Yug! adjust UDP/TCP and IP checksums + */ +/* +For UDP there is no ACK, which means the expire timer will shutdown +the connection after the preset time. This is a problem for REALAUDIO and +other applications that require more than the preset time(current 5 min). +My solution is: if we can still talk to the masquerade port inside our +network(the client), then we will reset the timer for every packet that +comes in. The draw back is that we may keep this open longer than necessary, +for example in case the client dies or some other out of normal situation +happens, like a client machine hang. +AC - Feb-21-1996 +*/ + if (iph->protocol==IPPROTO_UDP) + { + del_timer(&ms->timer); + ms->timer.expires = MASQUERADE_EXPIRE_UDP; + add_timer(&ms->timer); + udp_send_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size,skb->sk); + } + else + { + __u32 ack_seq; + /* + * Adjust ack_seq with delta-offset for + * the packets AFTER most recent PORT command ha s caused a shift + * for packets before most recent PORT command, use previous_delta + */ +#ifdef DEBUG_MASQ + printk("demasq : delta=%d ; previous_delta=%d ; init_seq=%lX ; ack_seq=%lX ; after=%d\n",ms->delta,ms->previous_delta,ntohl(ms->init_seq),ntohl(th->ack_seq),after(ntohl(th->ack_seq),ntohl(ms->init_seq))); +#endif + ack_seq=ntohl(th->ack_seq); + if (ms->delta || ms->previous_delta) + { + if(after(ack_seq,ms->init_seq)) + { + th->ack_seq = htonl(ack_seq-ms->delta); +#ifdef DEBUG_MASQ + printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta); +#endif + } + else + { + th->ack_seq = htonl(ack_seq-ms->previous_delta); +#ifdef DEBUG_MASQ + printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta); +#endif + } + } + tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb->sk); + } + ip_send_check(iph); +#ifdef DEBUG_MASQ + printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1])); +#endif + return 1; + } + ms = ms->next; + } + + /* sorry, all this trouble for a no-hit :) */ + return 0; +} +#endif static void zero_fw_chain(struct ip_fw *chainptr) { @@ -442,7 +1258,7 @@ if ( ftmp == NULL ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: malloc said no\n"); + printk("ip_fw_ctl: malloc said no\n"); #endif return( ENOMEM ); } @@ -511,8 +1327,8 @@ addb4--; } - if (((o_da & o_dm) == (n_da & n_dm)) - &&((o_sa & o_sm) == (n_sa & n_sm))) + if (((o_da & o_dm) == (n_da & n_dm)) && + ((o_sa & o_sm) == (n_sa & n_sm))) { if (newkind!=IP_FW_F_ALL && oldkind==IP_FW_F_ALL) @@ -603,7 +1419,7 @@ if (chtmp_prev) chtmp_prev->fw_next=ftmp; else - *chainptr=ftmp; + *chainptr=ftmp; restore_flags(flags); return(0); } @@ -635,13 +1451,13 @@ while( ftmp != NULL ) { matches=1; - if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr + if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr || ftmp->fw_flg!=frwl->fw_flg) - matches=0; + matches=0; tport1=ftmp->fw_nsp+ftmp->fw_ndp; tport2=frwl->fw_nsp+frwl->fw_ndp; @@ -650,8 +1466,8 @@ else if (tport1!=0) { for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++) - if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) - matches=0; + if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) + matches=0; } if(matches) { @@ -661,11 +1477,11 @@ ltmp->fw_next=ftmp->fw_next; kfree_s(ftmp,sizeof(*ftmp)); ftmp=ltmp->fw_next; - } - else - { - *chainptr=ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); + } + else + { + *chainptr=ftmp->fw_next; + kfree_s(ftmp,sizeof(*ftmp)); ftmp=*chainptr; } } @@ -708,7 +1524,7 @@ if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: src range set but n_src_p=%d\n", + printk("ip_fw_ctl: src range set but fw_nsp=%d\n", frwl->fw_nsp); #endif return(NULL); @@ -717,7 +1533,7 @@ if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printk("ip_fw_ctl: dst range set but n_dst_p=%d\n", + printk("ip_fw_ctl: dst range set but fw_ndp=%d\n", frwl->fw_ndp); #endif return(NULL); @@ -740,12 +1556,6 @@ #ifdef CONFIG_IP_ACCT -void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f) -{ - (void) ip_fw_chk(iph, dev, f, 0, 1); - return; -} - int ip_acct_ctl(int stage, void *m, int len) { if ( stage == IP_ACCT_FLUSH ) @@ -775,16 +1585,16 @@ return( del_from_chain(&ip_acct_chain,frwl)); default: /* - * Should be panic but... (Why ??? - AC) + * Should be panic but... (Why ??? - AC) */ #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_acct_ctl: unknown request %d\n",stage); + printk("ip_acct_ctl: unknown request %d\n",stage); #endif return(EINVAL); } } #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_acct_ctl: unknown request %d\n",stage); + printk("ip_acct_ctl: unknown request %d\n",stage); #endif return(EINVAL); } @@ -839,7 +1649,7 @@ if ( len < sizeof(struct ip_fwpkt) ) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: length=%d, expected %d\n", + printk("ip_fw_ctl: length=%d, expected %d\n", len, sizeof(struct ip_fwpkt)); #endif return( EINVAL ); @@ -851,7 +1661,7 @@ if ( ip->ihl != sizeof(struct iphdr) / sizeof(int)) { #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl, + printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl, sizeof(struct ip)/sizeof(int)); #endif return(EINVAL); @@ -908,7 +1718,7 @@ } #ifdef DEBUG_CONFIG_IP_FIREWALL - printf("ip_fw_ctl: unknown request %d\n",stage); + printk("ip_fw_ctl: unknown request %d\n",stage); #endif return(EINVAL); } @@ -1013,4 +1823,49 @@ return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,reset); } +#endif + +#ifdef CONFIG_IP_MASQUERADE + +int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, int length) +{ + off_t pos=0, begin=0; + struct ip_masq *ms; + unsigned long flags; + int len=0; + + len=sprintf(buffer,"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta Expires\n"); + save_flags(flags); + cli(); + + ms=ip_msq_hosts; + while (ms!=NULL) { + int timer_active = del_timer(&ms->timer); + if (!timer_active) + ms->timer.expires = 0; + len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08lX %5d %lu\n", + strProt[ms->protocol==IPPROTO_TCP], + ntohl(ms->src),ntohs(ms->sport), + ntohl(ms->dst),ntohs(ms->dport), + ntohs(ms->mport), + ms->init_seq,ms->delta,ms->timer.expires); + if (timer_active) + add_timer(&ms->timer); + + pos=begin+len; + if(posoffset+length) + break; + ms=ms->next; + } + restore_flags(flags); + *start=buffer+(offset-begin); + len-=(offset-begin); + if(len>length) + len=length; + return len; +} #endif diff --unified -r linux-orig/net/inet/udp.c linux/net/inet/udp.c --- linux-orig/net/inet/udp.c Thu Jan 26 00:25:54 1995 +++ linux/net/inet/udp.c Tue Mar 5 23:24:43 1996 @@ -230,7 +230,7 @@ * doing or get burned... */ -static void udp_send_check(struct udphdr *uh, unsigned long saddr, +void udp_send_check(struct udphdr *uh, unsigned long saddr, unsigned long daddr, int len, struct sock *sk) { uh->check = 0; diff --unified -r linux-orig/net/inet/udp.h linux/net/inet/udp.h --- linux-orig/net/inet/udp.h Wed Dec 1 07:44:15 1993 +++ linux/net/inet/udp.h Tue Mar 5 23:24:43 1996 @@ -33,6 +33,8 @@ extern void udp_err(int err, unsigned char *header, unsigned long daddr, unsigned long saddr, struct inet_protocol *protocol); +extern void udp_send_check(struct udphdr *uh, unsigned long saddr, + unsigned long daddr, int len, struct sock *sk); extern int udp_recvfrom(struct sock *sk, unsigned char *to, int len, int noblock, unsigned flags, struct sockaddr_in *sin, int *addr_len);