From nik@netaxs.comTue Jul 18 09:26:08 1995
Date: Mon, 17 Jul 1995 17:25:26 -0400 (EDT)
From: Nik Weidenbacher <nik@netaxs.com>
To: masq@eves.com
Subject: The 1.2 patch.

I have heard many requests for this, so here it is.  I also posted it to
c.o.l.networking.  

nik

diff -rc linux/arch/i386/config.in linux+masq/arch/i386/config.in
*** linux/arch/i386/config.in	Tue Mar  7 15:25:26 1995
--- linux+masq/arch/i386/config.in	Thu Mar  9 10:00:25 1995
***************
*** 46,51 ****
--- 46,54 ----
  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)' 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
diff -rc linux/include/linux/ip_fw.h linux+masq/include/linux/ip_fw.h
*** linux/include/linux/ip_fw.h	Thu Mar  9 19:33:55 1995
--- linux+masq/include/linux/ip_fw.h	Sat Mar 18 10:46:39 1995
***************
*** 15,20 ****
--- 15,23 ----
   *		Alan.
   *
   *	All the real work was done by .....
+  *
+  * Fixes:
+  *	Pauline Middelink	:	Added masquerading.
   */
  
  /*
***************
*** 83,89 ****
  #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        */
  
  /*    
   *	New IP firewall options for [gs]etsockopt at the RAW IP level.
--- 86,93 ----
  #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_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,147 ****
  extern struct ip_fw *ip_fw_fwd_chain;
  extern int ip_fw_blk_policy;
  extern int ip_fw_fwd_policy;
  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);
  #endif /* KERNEL */
  
  #endif /* _IP_FW_H */
--- 138,166 ----
  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 int ip_acct_ctl(int, void *, int);
  #endif
! #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 */
! 	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 */
diff -rc linux/include/linux/proc_fs.h linux+masq/include/linux/proc_fs.h
*** linux/include/linux/proc_fs.h	Sun Feb 12 20:11:02 1995
--- linux+masq/include/linux/proc_fs.h	Thu Mar  9 10:00:26 1995
***************
*** 74,79 ****
--- 74,82 ----
  #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) */
diff -rc linux/net/inet/ip.c linux+masq/net/inet/ip.c
*** linux/net/inet/ip.c	Thu Mar  9 19:33:55 1995
--- linux+masq/net/inet/ip.c	Sat Mar 18 10:44:03 1995
***************
*** 62,67 ****
--- 62,69 ----
   *		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.
***************
*** 1263,1280 ****
  	struct rtable *rt;	/* Route we use */
  	unsigned char *ptr;	/* Data pointer */
  	unsigned long raddr;	/* Router IP address */
! 	
  	/* 
  	 *	See if we are allowed to forward this.
  	 */
  
! #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);
  		return;
  	}
  #endif
--- 1265,1282 ----
  	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.
  	 */
  
!  	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
***************
*** 1291,1302 ****
  
  	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.
--- 1293,1298 ----
***************
*** 1304,1310 ****
--- 1300,1324 ----
  	 *	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,
***************
*** 1380,1385 ****
--- 1394,1407 ----
  
  	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);
+ #endif
  
  		/*
  		 *	Current design decrees we copy the packet. For identical header
***************
*** 1430,1436 ****
  			 *	Count mapping we shortcut
  			 */
  			 
! 			ip_acct_cnt(iph,dev,ip_acct_chain);
  #endif			
  			
  			/*
--- 1452,1458 ----
  			 *	Count mapping we shortcut
  			 */
  			 
! 			ip_fw_chk(iph,dev,ip_acct_chain,0,1);
  #endif			
  			
  			/*
***************
*** 1501,1507 ****
  
  #ifdef	CONFIG_IP_FIREWALL
  	
! 	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);
--- 1523,1529 ----
  
  #ifdef	CONFIG_IP_FIREWALL
  	
! 	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);
***************
*** 1613,1624 ****
  		while(1);
  	}
  #endif
  	/*
  	 *	Account for the packet
  	 */
! 	 
  #ifdef CONFIG_IP_ACCT
! 	ip_acct_cnt(iph,dev, ip_acct_chain);
  #endif	
  
  	/*
--- 1635,1658 ----
  		while(1);
  	}
  #endif
+ 
+ #ifdef CONFIG_IP_MASQUERADE
+ 	/*
+ 	 * Do we need to de-masquerade this fragment?
+ 	 */
+ 	if (ip_fw_demasquerade(skb)) {
+ 		ip_forward(skb, dev, is_frag|4);
+ 		kfree_skb(skb, FREE_WRITE);
+ 		return(0);
+ 	}
+ #endif
+ 
  	/*
  	 *	Account for the packet
  	 */
!  
  #ifdef CONFIG_IP_ACCT
! 	ip_fw_chk(iph,dev,ip_acct_chain,0,1);
  #endif	
  
  	/*
***************
*** 1634,1641 ****
  		skb->dev = dev;
  		iph=skb->h.iph;
  	}
- 	
- 		 
  
  	/*
  	 *	Point into the IP datagram, just past the header.
--- 1668,1673 ----
***************
*** 1643,1655 ****
  
  	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)
  	{
--- 1675,1687 ----
  
  	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)
  	{
***************
*** 1921,1927 ****
  	 
  	ip_statistics.IpOutRequests++;
  #ifdef CONFIG_IP_ACCT
! 	ip_acct_cnt(iph,dev, ip_acct_chain);
  #endif	
  	
  #ifdef CONFIG_IP_MULTICAST	
--- 1953,1959 ----
  	 
  	ip_statistics.IpOutRequests++;
  #ifdef CONFIG_IP_ACCT
! 	ip_fw_chk(iph,dev,ip_acct_chain,0,1);
  #endif	
  	
  #ifdef CONFIG_IP_MULTICAST	
diff -rc linux/net/inet/ip_fw.c linux+masq/net/inet/ip_fw.c
*** linux/net/inet/ip_fw.c	Fri Mar 10 09:07:14 1995
--- linux+masq/net/inet/ip_fw.c	Sat Mar 18 11:15:41 1995
***************
*** 21,26 ****
--- 21,41 ----
   *		Jos Vos 5/Mar/1995.
   *
   *	All the real work was done by .....
+  *
+  * Fixes:
+  *	Pauline Middelink	:	Added masquerading.
+  */
+ 
+ /*
+  * 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.
   */
  
  /*
***************
*** 58,63 ****
--- 73,79 ----
  #include "protocol.h"
  #include "route.h"
  #include "tcp.h"
+ #include "udp.h"
  #include <linux/skbuff.h>
  #include "sock.h"
  #include "icmp.h"
***************
*** 104,109 ****
--- 120,148 ----
  #define IP_INFO_FWD	1
  #define IP_INFO_ACCT	2
  
+ /*
+  *	Implement IP packet masquerading
+  */
+ 
+ #ifdef CONFIG_IP_MASQUERADE
+ 
+ #undef DEBUG_MASQ
+ 
+ #define MASQUERADE_EXPIRE_TCP     15*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 PORT_MASQ_BEGIN	32768
+ #define PORT_MASQ_END	(PORT_MASQ_BEGIN+4096)
+ 
+ static unsigned short masq_port = PORT_MASQ_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,143 ****
  
  
  /*
!  *	Returns 0 if packet should be dropped, 1 if it should be accepted,
!  *	and -1 if an ICMP host unreachable packet should be sent.
   *	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).
--- 175,184 ----
  
  
  /*
!  *	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,173 ****
  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);
  	__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.
  	 *	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
--- 190,205 ----
  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 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;
  
  	/* 
! 	 *	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,201 ****
  	 *	per device. We have a device per address with dummy
  	 *	devices instead.
  	 */
! 	 
  	dprintf1("Packet ");
  	switch(ip->protocol) 
  	{
--- 227,233 ----
  	 *	per device. We have a device per address with dummy
  	 *	devices instead.
  	 */
! 
  	dprintf1("Packet ");
  	switch(ip->protocol) 
  	{
***************
*** 388,399 ****
  	else
  		f_flag=policy;
  	if(f_flag&IP_FW_F_ACCEPT)
! 		return 1;
  	if(f_flag&IP_FW_F_ICMPRPL)
  		return -1;
  	return 0;
  }
  
  
  static void zero_fw_chain(struct ip_fw *chainptr)
  {
--- 420,811 ----
  	else
  		f_flag=policy;
  	if(f_flag&IP_FW_F_ACCEPT)
! 		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(void)
+ {
+ 	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 */
+ 		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;
+ }
+ 
+ #ifdef notdef
+ 
+ /*
+  * 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[20];		/* xxx.xxx.xxx.xxx\r\n */
+ 	
+ 	/*
+ 	 * Adjust seq and ack_seq with delta-offset for
+ 	 * the packets AFTER this one...
+ 	 */
+ 	if (ftp->delta && after(ftp->init_seq,th->seq)) {
+ 		th->seq += ftp->delta;
+ 		th->ack_seq += ftp->delta;
+ 	}
+ 
+ 	while (skb->len - ((unsigned char *)data - skb->h.raw) > 18)
+ 	{
+ 		if (memcmp(data,"PORT ",5)!=0 && memcmp(data,"port ",5)!=0) {
+ 			data += 5;
+ 			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;
+ printk("PORT %lX:%X detected\n",from,port);
+ 	
+ 		/*
+ 		 * Now create an masquerade entry for it
+ 		 */
+ 		ms = alloc_masq_entry();
+ 		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;
+ 		ms->dport    = htons(20);	/* ftp-data */
+ 		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);
+ 
+ 		/*
+ 		 * Calculate required delta-offset to keep TCP happy
+ 		 */
+ 		ftp->delta += strlen(buf) - (data-p);
+ 		if (ftp->delta==0) {
+ 			/*
+ 			 * simple case, just replace the old PORT cmd
+ 			 */
+ 			ftp->init_seq = 0;
+ 			memcpy(p,buf,strlen(buf));
+ 			return skb;
+ 		}
+ 
+ 		/*
+ 		 * Sizes differ, make a copy
+ 		 */
+ printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",ftp->delta, skb->len);
+ 		if (!ftp->init_seq)
+ 			ftp->init_seq = th->seq;
+ 
+ 		skb2 = alloc_skb(skb->mem_len-sizeof(struct sk_buff)+ftp->delta, GFP_ATOMIC);
+ 		if (skb2 == NULL) {
+ 			printk("MASQUERADE: No memory available\n");
+ 			return skb;
+ 		}
+ 		skb2->free = skb->free;
+ 		skb2->len = skb->len + ftp->delta;
+ 		skb2->h.raw = &skb2->data[skb->h.raw - skb->data];
+ 
+ 		/*
+ 		 *	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));
+ 		memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data,
+ 			skb->mem_len - sizeof(struct sk_buff) - ((char *)skb->h.raw - data));
+ 
+ 		/*
+ 		 * 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;
+ }
+ #endif
+ 
+ void ip_fw_masquerade(struct sk_buff *skb, struct device *dev)
+ {
+ 	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();
+ 		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;
+ #ifdef notdef
+ 		if (portptr[1]==htons(21)) {
+ 			skb = revamp(skb, dev, ms);
+ 			iph = skb->h.iph;
+ 			portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
+ 		}
+ #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;
+ 	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)
+ 		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)!
+ 	 */
+ 	ms = ip_msq_hosts;
+ 	while (ms!=NULL) {
+ 		if (iph->protocol==ms->protocol &&
+ /*		    iph->saddr==ms->dst && */
+ 		    portptr[0]==ms->dport &&
+ 		    portptr[1]==ms->mport)
+ 		{
+ 			size = skb->len - ((unsigned char *)portptr - skb->h.raw);
+ 			iph->daddr = ms->src;
+ 			portptr[1] = ms->sport;
+ 			
+ 			/*
+ 			 * Yug! adjust UDP/TCP and IP checksums
+ 			 */
+ 			if (iph->protocol==IPPROTO_UDP)
+ 				udp_send_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size,skb->sk);
+ 			else
+ 				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,448 ****
  	if ( ftmp == NULL ) 
  	{
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 		printf("ip_fw_ctl:  malloc said no\n");
  #endif
  		return( ENOMEM );
  	}
--- 854,860 ----
  	if ( ftmp == NULL ) 
  	{
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 		printk("ip_fw_ctl:  malloc said no\n");
  #endif
  		return( ENOMEM );
  	}
***************
*** 511,518 ****
  					addb4--;
  			}
  
! 			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)
--- 923,930 ----
  					addb4--;
  			}
  
! 			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,609 ****
  	if (chtmp_prev)
  		chtmp_prev->fw_next=ftmp;
  	else
!         	*chainptr=ftmp;
  	restore_flags(flags);
  	return(0);
  }
--- 1015,1021 ----
  	if (chtmp_prev)
  		chtmp_prev->fw_next=ftmp;
  	else
! 		*chainptr=ftmp;
  	restore_flags(flags);
  	return(0);
  }
***************
*** 635,647 ****
  	while( ftmp != NULL )
  	{
  		matches=1;
! 	     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;
  
  		tport1=ftmp->fw_nsp+ftmp->fw_ndp;
  		tport2=frwl->fw_nsp+frwl->fw_ndp;
--- 1047,1059 ----
  	while( ftmp != NULL )
  	{
  		matches=1;
! 		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;
  
  		tport1=ftmp->fw_nsp+ftmp->fw_ndp;
  		tport2=frwl->fw_nsp+frwl->fw_ndp;
***************
*** 650,657 ****
  		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(matches)
  		{
--- 1062,1069 ----
  		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(matches)
  		{
***************
*** 661,671 ****
  				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));
  				ftmp=*chainptr;
  			}       
  		}
--- 1073,1083 ----
  				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));
  				ftmp=*chainptr;
  			}       
  		}
***************
*** 708,714 ****
  	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",
  			frwl->fw_nsp);
  #endif
  		return(NULL);
--- 1120,1126 ----
  	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 fw_nsp=%d\n",
  			frwl->fw_nsp);
  #endif
  		return(NULL);
***************
*** 717,723 ****
  	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",
  			frwl->fw_ndp);
  #endif
  		return(NULL);
--- 1129,1135 ----
  	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 fw_ndp=%d\n",
  			frwl->fw_ndp);
  #endif
  		return(NULL);
***************
*** 740,751 ****
  
  #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 )
--- 1152,1157 ----
***************
*** 775,790 ****
  				return( del_from_chain(&ip_acct_chain,frwl));
  			default:
  				/*
!  				 *	Should be panic but... (Why ??? - AC)
  				 */
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 				printf("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);
  #endif
  	return(EINVAL);
  }
--- 1181,1196 ----
  				return( del_from_chain(&ip_acct_chain,frwl));
  			default:
  				/*
! 				 *	Should be panic but... (Why ??? - AC)
  				 */
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 				printk("ip_acct_ctl:  unknown request %d\n",stage);
  #endif
  				return(EINVAL);
  		}
  	}
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 	printk("ip_acct_ctl:  unknown request %d\n",stage);
  #endif
  	return(EINVAL);
  }
***************
*** 839,845 ****
  		if ( len < sizeof(struct ip_fwpkt) )
  		{
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 			printf("ip_fw_ctl: length=%d, expected %d\n",
  				len, sizeof(struct ip_fwpkt));
  #endif
  			return( EINVAL );
--- 1245,1251 ----
  		if ( len < sizeof(struct ip_fwpkt) )
  		{
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 			printk("ip_fw_ctl: length=%d, expected %d\n",
  				len, sizeof(struct ip_fwpkt));
  #endif
  			return( EINVAL );
***************
*** 851,857 ****
  		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,
  					sizeof(struct ip)/sizeof(int));
  #endif
  			return(EINVAL);
--- 1257,1263 ----
  		if ( ip->ihl != sizeof(struct iphdr) / sizeof(int))
  		{
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 			printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
  					sizeof(struct ip)/sizeof(int));
  #endif
  			return(EINVAL);
***************
*** 908,914 ****
  	} 
  
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 	printf("ip_fw_ctl:  unknown request %d\n",stage);
  #endif
  	return(EINVAL);
  }
--- 1314,1320 ----
  	} 
  
  #ifdef DEBUG_CONFIG_IP_FIREWALL
! 	printk("ip_fw_ctl:  unknown request %d\n",stage);
  #endif
  	return(EINVAL);
  }
***************
*** 1013,1016 ****
--- 1419,1467 ----
  	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(pos<offset) {
+ 			len=0;
+ 			begin=pos;
+ 		}
+ 		if(pos>offset+length)
+ 			break;
+ 		ms=ms->next;
+ 	}
+ 	restore_flags(flags);
+ 	*start=buffer+(offset-begin);
+ 	len-=(offset-begin);
+ 	if(len>length)
+ 		len=length;
+ 	return len;
+ }
  #endif
diff -rc linux/net/inet/udp.c linux+masq/net/inet/udp.c
*** linux/net/inet/udp.c	Thu Jan 26 06:25:54 1995
--- linux+masq/net/inet/udp.c	Thu Mar  9 10:00:27 1995
***************
*** 230,236 ****
   *	doing or get burned...
   */
  
! static void udp_send_check(struct udphdr *uh, unsigned long saddr, 
  	       unsigned long daddr, int len, struct sock *sk)
  {
  	uh->check = 0;
--- 230,236 ----
   *	doing or get burned...
   */
  
! void udp_send_check(struct udphdr *uh, unsigned long saddr, 
  	       unsigned long daddr, int len, struct sock *sk)
  {
  	uh->check = 0;
diff -rc linux/net/inet/udp.h linux+masq/net/inet/udp.h
*** linux/net/inet/udp.h	Wed Dec  1 13:44:15 1993
--- linux+masq/net/inet/udp.h	Thu Mar  9 10:00:27 1995
***************
*** 33,38 ****
--- 33,40 ----
  
  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);


