--- linux/net/inet/ip_fw.c	Wed Feb 15 14:21:53 1995
+++ linux-old/net/inet/ip_fw.c	Sun Feb 12 17:31:30 1995
@@ -4,9 +4,18 @@
  *	and the licenses thus do not conflict. While this port is subject
  *	to the GPL I also place my modifications under the original 
  *	license in recognition of the original copyright. 
+ *				-- Alan Cox.
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
+ *	Zeroing /proc and other additions
+ *		Jos Vos 4/Feb/1995.
+ *	Merged and included the FreeBSD-Current changes at Urgen's request
+ *	(but hey its a lot cleaner now). Urgen would prefer in some ways
+ *	we waited for his final product but since Linux 1.2.0 is about to
+ *	appear its not practical - Read: It works, its not clean but please
+ *	don't consider it to be his standard of finished work.
+ *		Alan Cox 12/Feb/1995
  *
  *	All the real work was done by .....
  */
@@ -25,6 +34,7 @@
  * This software is provided ``AS IS'' without any warranties of any kind.
  */
 
+#include <linux/config.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/types.h>
@@ -39,6 +49,8 @@
 #include <linux/in.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/icmp.h>
+#include <linux/udp.h>
 #include "ip.h"
 #include "protocol.h"
 #include "route.h"
@@ -52,11 +64,34 @@
  *	Implement IP packet firewall
  */
 
+#ifdef CONFIG_IPFIREWALL_DEBUG 
+#define dprintf1(a)		printk(a)
+#define dprintf2(a1,a2)		printk(a1,a2)
+#define dprintf3(a1,a2,a3)	printk(a1,a2,a3)
+#define dprintf4(a1,a2,a3,a4)	printk(a1,a2,a3,a4)
+#else
+#define dprintf1(a)	
+#define dprintf2(a1,a2)
+#define dprintf3(a1,a2,a3)
+#define dprintf4(a1,a2,a3,a4)
+#endif
+
+#define print_ip(a)	 printf("%d.%d.%d.%d",(ntohl(a.s_addr)>>24)&0xFF,\
+					      (ntohl(a.s_addr)>>16)&0xFF,\
+					      (ntohl(a.s_addr)>>8)&0xFF,\
+					      (ntohl(a.s_addr))&0xFF);
+
+#ifdef IPFIREWALL_DEBUG
+#define dprint_ip(a)	print_ip(a)
+#else
+#define dprint_ip(a)	
+#endif
+
 #ifdef CONFIG_IP_FIREWALL
 struct ip_fw *ip_fw_fwd_chain;
 struct ip_fw *ip_fw_blk_chain;
-int ip_fw_blk_policy=1;
-int ip_fw_fwd_policy=1;
+int ip_fw_blk_policy=IP_FW_F_ACCEPT;
+int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
 #endif
 #ifdef CONFIG_IP_ACCT
 struct ip_fw *ip_acct_chain;
@@ -67,16 +102,6 @@
 #define IP_INFO_ACCT	2
 
 
-extern inline void print_ip(unsigned long xaddr)
-{
-	unsigned long addr = ntohl(xaddr);
-	printk("%ld.%ld.%ld.%ld",(addr>>24) & 0xff,
-                         (addr>>16)&0xff,
-                         (addr>>8)&0xff,
-                         addr&0xFF);
-}                  
-
-
 /*
  *	Returns 1 if the port is matched by the vector, 0 otherwise
  */
@@ -104,336 +129,230 @@
 	return(0);
 }
 
+#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
+
 
 /*
- *	Returns 0 if packet should be dropped, 1 or more if it should be accepted
+ *	Returns 0 if packet should be dropped, 1 or more if it should be accepted.
+ *	Also does accounting so you can feed it the accounting chain.
  */
 
-#ifdef CONFIG_IP_FIREWALL
 
-int ip_fw_chk(struct iphdr *ip, struct ip_fw *chain, int policy)
+int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int policy)
 {
-	unsigned long src, dst;
-	char got_proto=0;
-	int frwl_proto, proto=0;
 	struct ip_fw *f;
-	unsigned short src_port=0, dst_port=0;
-	unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]);
-
-	if (!chain) 
-		return(policy);  /* If no chain, use your policy. */
-
-	src = ip->saddr;
-	dst = ip->daddr;
-
-#ifdef DEBUG_CONFIG_IP_FIREWALL
-	{
-		printk("packet ");
-		switch(ip->protocol) 
-		{
-			case IPPROTO_TCP:
-				printf("TCP ");
-				break;
-			case IPPROTO_UDP:
-				printf("UDP ");
-				break;
-			case IPPROTO_ICMP:
-				printf("ICMP:%d ",((char *)portptr)[0]&0xff);
-				break;
-			default:
-				printf("p=%d ",ip->protocol);
-				break;
-		}
-		print_ip(ip->saddr);
-		if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
-		{
-			printf(":%d ",ntohs(portptr[0]));
-		}
-		print_ip(ip->daddr);
-		if ( ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
-		{
-			printf(":%d ",ntohs(portptr[1]));
-		}
-		printf("\n");
-	}
-#endif
+	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;
+	unsigned short		f_flag;
 
-	for (f=chain;f;f=f->next) 
-	{
-		if ((src&f->src_mask.s_addr)==f->src.s_addr
-			&&  (dst&f->dst_mask.s_addr)==f->dst.s_addr) 
-		{
-			frwl_proto=f->flags&IP_FW_F_KIND;
-			if (frwl_proto==IP_FW_F_ALL) 
-			{
-				/* Universal frwl - we've got a match! */
-
-#ifdef DEBUG_CONFIG_IP_FIREWALL
-				printf("universal frwl match\n");
-#endif
-				f->p_cnt++;
-				f->b_cnt+=ntohs(ip->tot_len);
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
-				if (!(f->flags & IP_FW_F_ACCEPT))
-					goto bad_packet;
-				return 1;
-#else
-				return( f->flags & IP_FW_F_ACCEPT );
-#endif
-			}
-			else
-			{
-				/*
-				 *	Specific firewall - packet's protocol must match firewall's
-				 */
-				if (!got_proto) 
-				{
-					/*
-	 				 * We still had not determined the protocol
-					 * of this packet,now the time to do so.
-					 */
-					switch(ip->protocol) 
-					{
-						case IPPROTO_TCP:
-							/*
-							 * 	First two shorts in TCP are src/dst ports
-							 */
-							proto=IP_FW_F_TCP;
-							src_port=ntohs(portptr[0]);
-							dst_port=ntohs(portptr[1]);
-							break;
-						case IPPROTO_UDP:
-							/*
-							 *	First two shorts in UDP are src/dst ports
-			 				 */
-							proto = IP_FW_F_UDP;
-							src_port = ntohs(portptr[0]);
-							dst_port = ntohs(portptr[1]);
-							break;
-						case IPPROTO_ICMP:
-							proto=IP_FW_F_ICMP;
-							break;
-						default:
-							proto=IP_FW_F_ALL;
-#ifdef DEBUG_CONFIG_IP_FIREWALL
-							printf("non TCP/UDP packet\n");
-#endif
-					}
-					got_proto=1;
-				} 
-				/*
-				 * At this moment we surely know the protocol of this
-				 * packet and we'll check if it matches,then proceed further..
-				 */
-				if (proto==frwl_proto) 
-				{
-	
-					if (proto==IP_FW_F_ICMP || (port_match(&f->ports[0],f->n_src_p,src_port,
-						f->flags&IP_FW_F_SRNG) &&
-					        port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port,
-						f->flags&IP_FW_F_DRNG))) 
-					{
-					/* We've got a match! */
-					f->p_cnt++;
-					f->b_cnt+=ntohs(ip->tot_len);
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
-						if (!(f->flags & IP_FW_F_ACCEPT))
-							goto bad_packet;
-						return 1;
-#else
-						return( f->flags & IP_FW_F_ACCEPT);
-#endif
-					} /* Ports match */
-				} /* Proto matches */
-			}  /* ALL/Specific */
-		} /* IP addr/mask matches */
-	} /* Loop */
-	
 	/*
-	 * If we get here then none of the firewalls matched.
-	 * So now we relay on policy defined by user-unmatched packet can
-	 * be ever accepted or rejected...
+	 *	If the chain is empty follow policy. The BSD one
+	 *	accepts anything giving you a time window while
+	 *	flushing and rebuilding the tables.
 	 */
-
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
-	if (!(policy))
-		goto bad_packet;
-	return 1;
-#else
-	return(policy);
-#endif
+	 
+	src = ip->saddr;
+	dst = ip->daddr;
 
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
-bad_packet:
-	/*
-	 * VERY ugly piece of code which actually
-	 * makes kernel printf for denied 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
+	 *	stored only in first packet.
+	 *
+	 *	Note that this theoretically allows partial packet
+	 *	spoofing. Not very dangerous but paranoid people may
+	 *	wish to play with this. It also allows the so called
+	 *	"fragment bomb" denial of service attack on some types
+	 *	of system.
 	 */
-	if (f->flags&IP_FW_F_PRN) 
-	{
-		printf("ip_fw_chk says no to ");
-		switch(ip->protocol) 
-		{
-			case IPPROTO_TCP:
-				printf("TCP ");
-				break;
-			case IPPROTO_UDP:
-				printf("UDP ");
-				break;
-			case IPPROTO_ICMP:
-				printf("ICMP:%d ",((char *)portptr)[0]&0xff);
-				break;
-			default:
-				printf("p=%d ",ip->protocol);
-				break;
-		}
-		print_ip(ip->saddr);
-		if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
-		{
-			printf(":%d ",ntohs(portptr[0]));
-		}
-		else
-		{
-			printf("\n");
-		}
-		print_ip(ip->daddr);
-		if ( ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ) 
-		{
-			printf(":%d ",ntohs(portptr[1]));
-		}
-		printf("\n");
-	}
-	return(0);
-#endif
-}
-#endif /* CONFIG_IP_FIREWALL */
-
-
-
-
-#ifdef CONFIG_IP_ACCT
-void ip_acct_cnt(struct iphdr *ip,struct ip_fw *chain)
-{
-	unsigned long src, dst;
-	char got_proto=0,rev=0;
-	int frwl_proto, proto=0;
-	struct ip_fw *f;
-	unsigned short src_port=0, dst_port=0;
-	unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]);
 
-	if (!chain) 
-		return;     
+	if (ip->frag_off&IP_OFFSET)
+		return(1);
 
 	src = ip->saddr;
 	dst = ip->daddr;
 
-	for (f=chain;f;f=f->next) 
-	{
-		if ((src&f->src_mask.s_addr)==f->src.s_addr
-			&&  (dst&f->dst_mask.s_addr)==f->dst.s_addr) 
-		{
-			rev=0;
-			goto addr_match;
-		}
-	 	if  ((f->flags&IP_FW_F_BIDIR) &&
-		    ((src&f->src_mask.s_addr)==f->dst.s_addr
-		&&  (dst&f->dst_mask.s_addr)==f->src.s_addr)) 
-		{ 
-			rev=1;
-			goto addr_match;
-		}
-		continue;
-addr_match:
-		frwl_proto=f->flags&IP_FW_F_KIND;
-		if (frwl_proto==IP_FW_F_ALL) 
+	/*
+	 *	If we got interface from which packet came
+	 *	we can use the address directly. This is unlike
+	 *	4.4BSD derived systems that have an address chain
+	 *	per device. We have a device per address with dummy
+	 *	devices instead.
+	 */
+	 
+	dprintf1("Packet ");
+	switch(ip->protocol) 
+	{
+		case IPPROTO_TCP:
+			dprintf1("TCP ");
+			src_port=ntohs(tcp->source);
+			dst_port=ntohs(tcp->dest);
+			if(tcp->syn)
+				notcpsyn=0; /* We *DO* have SYN, value FALSE */
+			prt=IP_FW_F_TCP;
+			break;
+		case IPPROTO_UDP:
+			dprintf1("UDP ");
+			src_port=ntohs(udp->source);
+			dst_port=ntohs(udp->dest);
+			prt=IP_FW_F_UDP;
+			break;
+		case IPPROTO_ICMP:
+			dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff);
+			prt=IP_FW_F_ICMP;
+			break;
+		default:
+			dprintf2("p=%d ",ip->protocol);
+			prt=IP_FW_F_ALL;
+			break;
+	}
+	dprint_ip(ip->saddr);
+	
+	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
+		dprintf2(":%d ", src_port);
+	dprint_ip(ip->daddr);
+	if ( ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
+		dprintf2(":%d ",dst_port);
+	dprintf1("\n");
+
+	for (f=chain;f;f=f->fw_next) 
+	{
+		/*
+		 *	This is a bit simpler as we don't have to walk
+		 *	an interface chain as you do in BSD - same logic
+		 *	however.
+		 */
+		if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
+		&&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr) 
 		{
-			/*	Universal frwl - we've got a match! */
-     			f->p_cnt++;	/*	Rise packet count */
-
 			/*
-			 *	Rise byte count, convert from host to network byte order.
-		     	 */
-		     	 
-			f->b_cnt+=ntohs(ip->tot_len);
+			 *	Look for a VIA match 
+			 */
+			if(f->fw_via.s_addr && rif)
+			{
+				if(rif->pa_addr!=f->fw_via.s_addr)
+					continue;	/* Mismatch */
+			}
+			/*
+			 *	Drop through - this is a match
+			 */
 		}
 		else
+			continue;
+		
+		/*
+		 *	Ok the chain addresses match.
+		 */
+
+		f_prt=f->fw_flg&IP_FW_F_KIND;
+		if (f_prt!=IP_FW_F_ALL) 
 		{
 			/*
-			 *	Specific firewall - packet's protocol must match firewall's
+			 * This is actually buggy as if you set SYN flag 
+			 * on UDP or ICMP firewall it will never work,but 
+			 * actually it is a concern of software which sets
+			 * firewall entries.
 			 */
 			 
-			if (!got_proto) 
-			{
-				/*
- 				 *	We still had not determined the protocol
-				 *	of this packet,now the time to do so.
-				 */
-				switch(ip->protocol) 
-				{
-				    	case IPPROTO_TCP:
-						/*
-						 *	First two shorts in TCP are src/dst ports
-						 */
-						proto=IP_FW_F_TCP;
-						src_port=ntohs(portptr[0]);
-						dst_port=ntohs(portptr[1]);
-						break;
-	    				case IPPROTO_UDP:
-						/*
-						 * First two shorts in UDP are src/dst ports
-						 */
-						proto = IP_FW_F_UDP;
-						src_port = ntohs(portptr[0]);
-						dst_port = ntohs(portptr[1]);
-						break;
-	    				case IPPROTO_ICMP:
-						proto=IP_FW_F_ICMP;
-						break;
-					default:
-						proto=IP_FW_F_ALL;
-				}
-				got_proto=1;
-			} 
+			 if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
+			 	continue;
 			/*
-			 * At this moment we surely know the protocol of this
-			 * packet and we'll check if it matches,then proceed further..
+			 *	Specific firewall - packet's protocol
+			 *	must match firewall's.
 			 */
-			if (proto==frwl_proto) 
+
+			if(prt!=f_prt)
+				continue;
+				
+			if(!(prt==IP_FW_F_ICMP ||(
+				port_match(&f->fw_pts[0], f->fw_nsp, src_port,
+					f->fw_flg&IP_FW_F_SRNG) &&
+				port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
+					f->fw_flg&IP_FW_F_SRNG))))
 			{
+				continue;
+			}
+		}
+#ifdef CONFIG_IP_FIREWALL_VERBOSE
+		/*
+		 * VERY ugly piece of code which actually
+		 * makes kernel printf for denied packets...
+		 */
 
-				if ((proto==IP_FW_F_ICMP ||
-					(port_match(&f->ports[0],f->n_src_p,src_port,
-					f->flags&IP_FW_F_SRNG) &&
-					port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port,
-					f->flags&IP_FW_F_DRNG)))
-					|| ((rev)   
-						&& (port_match(&f->ports[0],f->n_src_p,dst_port,
-                        	                f->flags&IP_FW_F_SRNG)
-						&& port_match(&f->ports[f->n_src_p],f->n_dst_p,src_port,
-	                       	                f->flags&IP_FW_F_DRNG))))
-				{
-					f->p_cnt++;                   /* Rise packet count */
-					/*
-					 * Rise byte count, convert from host to network byte order.
-					 */
-					f->b_cnt+=ntohs(ip->tot_len);
-				} /* Ports match */
-			} /* Proto matches */
-		}  /* ALL/Specific */
-	} /* IP addr/mask matches */
-} /* End of whole function */
-#endif /* CONFIG_IP_ACCT */
+		if (f->fw_flg & IP_FW_F_PRN)
+		{
+			if(f->fw_flg&IP_FW_F_ACCEPT)
+				printk("Accept ");
+			else
+				printk("Deny ");
+			switch(ip->protocol)
+			{
+				case IPPROTO_TCP:
+					printk("TCP ");
+					break;
+				case IPPROTO_UDP:
+					printk("UDP ");
+				case IPPROTO_ICMP:
+					printk("ICMP ");
+					break;
+				default:
+					printk("p=%d ",ip->protocol);
+					break;
+			}
+			print_ip(ip->saddr);
+			if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+				printk(":%d", src_port);
+			printk(" ");
+			print_ip(ip->daddr);
+			if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+				printk(":%d",dst_port);
+			printk("\n");
+		}
+#endif		
+		if(f->fw_flg&IP_FW_F_ACCEPT)
+		{
+			f->fw_bcnt+=ntohs(ip->tot_len);
+			f->fw_pcnt++;
+			return 1;
+		}
+		break;
+	} /* Loop */
+	
+	/*
+	 * If we get here then none of the firewalls matched or one matched
+	 * but was a no. So now we rely on policy defined in the rejecting
+	 * entry or if none was found in the policy variable
+	 */
 
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
+	if(f!=NULL)	/* A deny match */
+		f_flag=f->fw_flg;
+	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)
 {
 	struct ip_fw *ctmp=chainptr;
 	while(ctmp) 
 	{
-		ctmp->p_cnt=0l;
-		ctmp->b_cnt=0l;
-		ctmp=ctmp->next;
+		ctmp->fw_pcnt=0L;
+		ctmp->fw_bcnt=0L;
+		ctmp=ctmp->fw_next;
 	}
 }
 
@@ -446,7 +365,7 @@
 	{
 		struct ip_fw *ftmp;
 		ftmp = *chainptr;
-		*chainptr = ftmp->next;
+		*chainptr = ftmp->fw_next;
 		kfree_s(ftmp,sizeof(*ftmp));
 	}
 	restore_flags(flags);
@@ -475,15 +394,15 @@
 #ifdef DEBUG_CONFIG_IP_FIREWALL
 		printf("ip_fw_ctl:  malloc said no\n");
 #endif
-		return( ENOSPC );
+		return( ENOMEM );
 	}
 
 	memcpy(ftmp, frwl, sizeof( struct ip_fw ) );
 	
-	ftmp->p_cnt=0L;
-	ftmp->b_cnt=0L;
+	ftmp->fw_pcnt=0L;
+	ftmp->fw_bcnt=0L;
 
-	ftmp->next = NULL;
+	ftmp->fw_next = NULL;
 
 	cli();
 	
@@ -494,11 +413,11 @@
 	else
 	{
 		chtmp_prev=NULL;
-		for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->next) 
+		for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) 
 		{
 			addb4=0;
-			newkind=ftmp->flags & IP_FW_F_KIND;
-			oldkind=chtmp->flags & IP_FW_F_KIND;
+			newkind=ftmp->fw_flg & IP_FW_F_KIND;
+			oldkind=chtmp->fw_flg & IP_FW_F_KIND;
 	
 			if (newkind!=IP_FW_F_ALL 
 				&&  oldkind!=IP_FW_F_ALL
@@ -513,15 +432,15 @@
 			 *	Sorry,but i had to do this....
 			 */
 
-			n_sa=ntohl(ftmp->src.s_addr);
-			n_da=ntohl(ftmp->dst.s_addr);
-			n_sm=ntohl(ftmp->src_mask.s_addr);
-			n_dm=ntohl(ftmp->dst_mask.s_addr);
-
-			o_sa=ntohl(chtmp->src.s_addr);
-			o_da=ntohl(chtmp->dst.s_addr);
-			o_sm=ntohl(chtmp->src_mask.s_addr);
-			o_dm=ntohl(chtmp->dst_mask.s_addr);
+			n_sa=ntohl(ftmp->fw_src.s_addr);
+			n_da=ntohl(ftmp->fw_dst.s_addr);
+			n_sm=ntohl(ftmp->fw_smsk.s_addr);
+			n_dm=ntohl(ftmp->fw_dmsk.s_addr);
+
+			o_sa=ntohl(chtmp->fw_src.s_addr);
+			o_da=ntohl(chtmp->fw_dst.s_addr);
+			o_sm=ntohl(chtmp->fw_smsk.s_addr);
+			o_dm=ntohl(chtmp->fw_dmsk.s_addr);
 
 			m_src_mask = o_sm & n_sm;
 			m_dst_mask = o_dm & n_dm;
@@ -563,23 +482,24 @@
 					 *	of ports.
 					 */
 
-					if (ftmp->flags & IP_FW_F_SRNG) 
-						n_sr=ftmp->ports[1]-ftmp->ports[0];
+					if (ftmp->fw_flg & IP_FW_F_SRNG) 
+						n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0];
 					else 
-						n_sr=(ftmp->n_src_p)?ftmp->n_src_p : 0xFFFF;
+						n_sr=(ftmp->fw_nsp)?
+							ftmp->fw_nsp : 0xFFFF;
 						
-					if (chtmp->flags & IP_FW_F_SRNG) 
-						o_sr=chtmp->ports[1]-chtmp->ports[0];
+					if (chtmp->fw_flg & IP_FW_F_SRNG) 
+						o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0];
 					else 
-						o_sr=(chtmp->n_src_p)?chtmp->n_src_p : 0xFFFF;
+						o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF;
 
 					if (n_sr<o_sr)
 						addb4++;
 					if (n_sr>o_sr)
 						addb4--;
 					
-					n_n=ftmp->n_src_p;
-					n_o=chtmp->n_src_p;
+					n_n=ftmp->fw_nsp;
+					n_o=chtmp->fw_nsp;
 	
 					/*
 					 * Actually this cannot happen as the frwl control
@@ -591,15 +511,15 @@
 						(n_o>(IP_FW_MAX_PORTS-2)))
 						goto skip_check;
 
-					if (ftmp->flags & IP_FW_F_DRNG) 
-					       n_dr=ftmp->ports[n_n+1]-ftmp->ports[n_n];
+					if (ftmp->fw_flg & IP_FW_F_DRNG) 
+					       n_dr=ftmp->fw_pts[n_n+1]-ftmp->fw_pts[n_n];
 					else 
-					       n_dr=(ftmp->n_dst_p)? ftmp->n_dst_p : 0xFFFF;
+					       n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF;
 
-					if (chtmp->flags & IP_FW_F_DRNG) 
-						o_dr=chtmp->ports[n_o+1]-chtmp->ports[n_o];
+					if (chtmp->fw_flg & IP_FW_F_DRNG) 
+						o_dr=chtmp->fw_pts[n_o+1]-chtmp->fw_pts[n_o];
 					else 
-						o_dr=(chtmp->n_dst_p)? chtmp->n_dst_p : 0xFFFF;
+						o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF;
 					if (n_dr<o_dr)
 						addb4++;
 					if (n_dr>o_dr)
@@ -611,13 +531,13 @@
 			{
 				if (chtmp_prev) 
 				{
-					chtmp_prev->next=ftmp; 
-					ftmp->next=chtmp;
+					chtmp_prev->fw_next=ftmp; 
+					ftmp->fw_next=chtmp;
 				} 
 				else 
 				{
 					*chainptr=ftmp;
-					ftmp->next=chtmp;
+					ftmp->fw_next=chtmp;
 				}
 				restore_flags(flags);
 				return 0;
@@ -627,7 +547,7 @@
 	}
 	
 	if (chtmp_prev)
-		chtmp_prev->next=ftmp;
+		chtmp_prev->fw_next=ftmp;
 	else
         	*chainptr=ftmp;
 	restore_flags(flags);
@@ -649,7 +569,7 @@
 	if ( ftmp == NULL ) 
 	{
 #ifdef DEBUG_CONFIG_IP_FIREWALL
-		printf("ip_fw_ctl:  chain is empty\n");
+		printk("ip_fw_ctl:  chain is empty\n");
 #endif
 		restore_flags(flags);
 		return( EINVAL );
@@ -661,21 +581,22 @@
 	while( ftmp != NULL )
 	{
 		matches=1;
-		if ((memcmp(&ftmp->src,&frwl->src,sizeof(struct in_addr))) 
-     			|| (memcmp(&ftmp->src_mask,&frwl->src_mask,sizeof(struct in_addr)))
-     			|| (memcmp(&ftmp->dst,&frwl->dst,sizeof(struct in_addr)))
-     			|| (memcmp(&ftmp->dst_mask,&frwl->dst_mask,sizeof(struct in_addr)))
-     			|| (ftmp->flags!=frwl->flags))
+	     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->n_src_p+ftmp->n_dst_p;
-		tport2=frwl->n_src_p+frwl->n_dst_p;
+		tport1=ftmp->fw_nsp+ftmp->fw_ndp;
+		tport2=frwl->fw_nsp+frwl->fw_ndp;
 		if (tport1!=tport2)
 		        matches=0;
 		else if (tport1!=0)
 		{
 			for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
-        		if (ftmp->ports[tmpnum]!=frwl->ports[tmpnum])
+        		if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
         			matches=0;
 		}
 		if(matches)
@@ -683,13 +604,13 @@
 			was_found=1;
 			if (ltmp)
 			{
-				ltmp->next=ftmp->next;
+				ltmp->fw_next=ftmp->fw_next;
 				kfree_s(ftmp,sizeof(*ftmp));
-				ftmp=ltmp->next;
+				ftmp=ltmp->fw_next;
         		}
       			else
       			{
-      				*chainptr=ftmp->next; 
+      				*chainptr=ftmp->fw_next; 
 	 			kfree_s(ftmp,sizeof(*ftmp));
 				ftmp=*chainptr;
 			}       
@@ -697,7 +618,7 @@
 		else
 		{
 			ltmp = ftmp;
-			ftmp = ftmp->next;
+			ftmp = ftmp->fw_next;
 		 }
 	}
 	restore_flags(flags);
@@ -715,44 +636,44 @@
 	if ( len != sizeof(struct ip_fw) )
 	{
 #ifdef DEBUG_CONFIG_IP_FIREWALL
-		printf("ip_fw_ctl: len=%d, want %d\n",m->m_len,
+		printk("ip_fw_ctl: len=%d, want %d\n",m->m_len,
 					sizeof(struct ip_fw));
 #endif
 		return(NULL);
 	}
 
-	if ( (frwl->flags & ~IP_FW_F_MASK) != 0 )
+	if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
 	{
 #ifdef DEBUG_CONFIG_IP_FIREWALL
-		printf("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
-			frwl->flags);
+		printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
+			frwl->fw_flg);
 #endif
 		return(NULL);
 	}
 
-	if ( (frwl->flags & IP_FW_F_SRNG) && frwl->n_src_p < 2 ) 
+	if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) 
 	{
 #ifdef DEBUG_CONFIG_IP_FIREWALL
-		printf("ip_fw_ctl: src range set but n_src_p=%d\n",
-			frwl->n_src_p);
+		printk("ip_fw_ctl: src range set but n_src_p=%d\n",
+			frwl->fw_nsp);
 #endif
 		return(NULL);
 	}
 
-	if ( (frwl->flags & IP_FW_F_DRNG) && frwl->n_dst_p < 2 ) 
+	if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) 
 	{
 #ifdef DEBUG_CONFIG_IP_FIREWALL
-		printf("ip_fw_ctl: dst range set but n_dst_p=%d\n",
-			frwl->n_dst_p);
+		printk("ip_fw_ctl: dst range set but n_dst_p=%d\n",
+			frwl->fw_ndp);
 #endif
 		return(NULL);
 	}
 
-	if ( frwl->n_src_p + frwl->n_dst_p > IP_FW_MAX_PORTS ) 
+	if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS ) 
 	{
 #ifdef DEBUG_CONFIG_IP_FIREWALL
-		printf("ip_fw_ctl: too many ports (%d+%d)\n",
-			frwl->n_src_p,frwl->n_dst_p);
+		printk("ip_fw_ctl: too many ports (%d+%d)\n",
+			frwl->fw_nsp,frwl->fw_ndp);
 #endif
 		return(NULL);
 	}
@@ -764,6 +685,12 @@
 
 
 #ifdef CONFIG_IP_ACCT
+
+int ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f)
+{
+	return ip_fw_chk(iph, dev, f, 0);
+}
+
 int ip_acct_ctl(int stage, void *m, int len)
 {
 	if ( stage == IP_ACCT_FLUSH )
@@ -839,8 +766,6 @@
 	{
 		int *tmp_policy_ptr;
 		tmp_policy_ptr=(int *)m;
-		if ((*tmp_policy_ptr)!=1 && (*tmp_policy_ptr)!=0)
-			return (EINVAL);
 		if ( stage == IP_FW_POLICY_BLK )
 			ip_fw_blk_policy=*tmp_policy_ptr;
 		else
@@ -872,7 +797,7 @@
 			return(EINVAL);
 		}
 
-		if ( ip_fw_chk(ip,
+		if ( ip_fw_chk(ip, NULL,
 			stage == IP_FW_CHK_BLK ?
 	                ip_fw_blk_chain : ip_fw_fwd_chain,
 			stage == IP_FW_CHK_BLK ?
@@ -912,7 +837,7 @@
 	 		 *	Should be panic but... (Why are BSD people panic obsessed ??)
 			 */
 #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);
 		}
@@ -968,16 +893,16 @@
 	
 	while(i!=NULL)
 	{
-		len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %X ",
-			ntohl(i->src.s_addr),ntohl(i->src_mask.s_addr),
-			ntohl(i->dst.s_addr),ntohl(i->dst_mask.s_addr),
-			i->flags);
+		len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ",
+			ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
+			ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
+			ntohl(i->fw_via.s_addr),i->fw_flg);
 		len+=sprintf(buffer+len,"%u %u %lu %lu ",
-			i->n_src_p,i->n_dst_p, i->p_cnt,i->b_cnt);
+			i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
 		len+=sprintf(buffer+len,"%u %u %u %u %u %u %u %u %u %u\n",
-			i->ports[0],i->ports[1],i->ports[2],i->ports[3],	
-			i->ports[4],i->ports[5],i->ports[6],i->ports[7],	
-			i->ports[8],i->ports[9]);	
+			i->fw_pts[0],i->fw_pts[1],i->fw_pts[2],i->fw_pts[3],	
+			i->fw_pts[4],i->fw_pts[5],i->fw_pts[6],i->fw_pts[7],	
+			i->fw_pts[8],i->fw_pts[9]);	
 		pos=begin+len;
 		if(pos<offset)
 		{
@@ -987,12 +912,12 @@
 		else if(reset)
 		{
 			/* This needs to be done at this specific place! */
-			i->p_cnt=0L;
-			i->b_cnt=0L;
+			i->fw_pcnt=0L;
+			i->fw_bcnt=0L;
 		}
 		if(pos>offset+length)
 			break;
-		i=i->next;
+		i=i->fw_next;
 	}
 	restore_flags(flags);
 	*start=buffer+(offset-begin);
@@ -1005,23 +930,38 @@
 
 #ifdef CONFIG_IP_ACCT
 
-int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
+int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length)
 {
-	return ip_chain_procinfo(IP_INFO_ACCT,buffer,start,offset,length,reset);
+	return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,0);
 }
 
+int ip_acct0_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+	return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,1);
+}
+
 #endif
 
 #ifdef CONFIG_IP_FIREWALL
 
-int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
+int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+	return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,0);
+}
+
+int ip_fw_blk0_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+	return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,1);
+}
+
+int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length)
 {
-	return ip_chain_procinfo(IP_INFO_BLK,buffer,start,offset,length,reset);
+	return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,0);
 }
 
-int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
+int ip_fw_fwd0_procinfo(char *buffer, char **start, off_t offset, int length)
 {
-	return ip_chain_procinfo(IP_INFO_FWD,buffer,start,offset,length,reset);
+	return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,1);
 }
 
 #endif
--- linux/include/linux/ip_fw.h	Sun Feb  5 12:44:40 1995
+++ linux-old/include/linux/ip_fw.h	Sat Feb 11 20:43:58 1995
@@ -7,6 +7,12 @@
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
+ *	Merged and included the FreeBSD-Current changes at Urgen's request
+ *	(but hey its a lot cleaner now). Urgen would prefer in some ways
+ *	we waited for his final product but since Linux 1.2.0 is about to
+ *	appear its not practical - Read: It works, its not clean but please
+ *	don't consider it to be his standard of finished work.
+ *		Alan.
  *
  *	All the real work was done by .....
  */
@@ -38,43 +44,46 @@
 
 struct ip_fw 
 {
-	struct ip_fw *next;			/* Next firewall on chain */
-	struct in_addr src, dst;		/* Source and destination IP addr */
-	struct in_addr src_mask, dst_mask;	/* Mask for src and dest IP addr */
-	unsigned short flags;			/* Flags word */
-	unsigned short n_src_p, n_dst_p;        /* # of src ports and # of dst ports */
+	struct ip_fw  *fw_next;			/* Next firewall on chain */
+	struct in_addr fw_src, fw_dst;		/* Source and destination IP addr */
+	struct in_addr fw_smsk, fw_dmsk;	/* Mask for src and dest IP addr */
+	struct in_addr fw_via;			/* IP address of interface "via" */
+	unsigned short fw_flg;			/* Flags word */
+	unsigned short fw_nsp, fw_ndp;          /* N'of src ports and # of dst ports */
 						/* in ports array (dst ports follow */
     						/* src ports; max of 10 ports in all; */
     						/* count of 0 means match all ports) */
 #define IP_FW_MAX_PORTS	10      		/* A reasonable maximum */
-	unsigned short ports[IP_FW_MAX_PORTS];  /* Array of port numbers to match */
-	unsigned long p_cnt,b_cnt;		/* Packet and byte counters */
+	unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
+	unsigned long  fw_pcnt,fw_bcnt;		/* Packet and byte counters */
 };
 
 /*
  *	Values for "flags" field .
  */
 
-#define IP_FW_F_ALL	0x00	/* This is a universal packet firewall*/
-#define IP_FW_F_TCP	0x01	/* This is a TCP packet firewall      */
-#define IP_FW_F_UDP	0x02	/* This is a UDP packet firewall      */
-#define IP_FW_F_ICMP	0x03	/* This is a ICMP packet firewall     */
-#define IP_FW_F_KIND	0x03	/* Mask to isolate firewall kind      */
-#define IP_FW_F_ACCEPT	0x04	/* This is an accept firewall (as     *
+#define IP_FW_F_ALL	0x000	/* This is a universal packet firewall*/
+#define IP_FW_F_TCP	0x001	/* This is a TCP packet firewall      */
+#define IP_FW_F_UDP	0x002	/* This is a UDP packet firewall      */
+#define IP_FW_F_ICMP	0x003	/* This is a ICMP packet firewall     */
+#define IP_FW_F_KIND	0x003	/* Mask to isolate firewall kind      */
+#define IP_FW_F_ACCEPT	0x004	/* This is an accept firewall (as     *
 				 *         opposed to a deny firewall)*
 				 *                                    */
-#define IP_FW_F_SRNG	0x08	/* The first two src ports are a min  *
+#define IP_FW_F_SRNG	0x008	/* The first two src ports are a min  *
 				 * and max range (stored in host byte *
 				 * order).                            *
 				 *                                    */
-#define IP_FW_F_DRNG	0x10	/* The first two dst ports are a min  *
+#define IP_FW_F_DRNG	0x010	/* The first two dst ports are a min  *
 				 * and max range (stored in host byte *
 				 * order).                            *
 				 * (ports[0] <= port <= ports[1])     *
 				 *                                    */
-#define IP_FW_F_PRN	0x20	/* In verbose mode print this firewall*/
-#define IP_FW_F_BIDIR	0x40	/* For accounting-count two way       */
-#define IP_FW_F_MASK	0x7F	/* All possible flag bits mask        */
+#define IP_FW_F_PRN	0x020	/* In verbose mode print this firewall*/
+#define IP_FW_F_BIDIR	0x040	/* For accounting-count two way       */
+#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.
@@ -116,14 +125,14 @@
 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 ip_fw *, 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 ip_fw *);
+extern int 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);
 #endif /* KERNEL */
 
 #endif /* _IP_FW_H */
--- linux/net/inet/ip.c	Sun Feb  5 12:44:40 1995
+++ linux-old/net/inet/ip.c	Sun Feb 12 21:01:50 1995
@@ -1262,14 +1219,18 @@
 	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
-	if(!ip_fw_chk(skb->h.iph, ip_fw_fwd_chain, ip_fw_fwd_policy))
+	int err;
+	
+	if((err=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy))!=1)
 	{
+		if(err==-1)
+			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
 		return;
 	}
 #endif
@@ -1425,7 +1386,7 @@
 			 *	Count mapping we shortcut
 			 */
 			 
-			ip_acct_cnt(iph,ip_acct_chain);
+			ip_acct_cnt(iph,dev,ip_acct_chain);
 #endif			
 			
 			/*
@@ -1462,6 +1423,9 @@
 				take up stack space. */
 	int brd=IS_MYADDR;
 	int is_frag=0;
+#ifdef CONFIG_IP_FIREWALL
+	int err;
+#endif	
 
 	ip_statistics.IpInReceives++;
 
@@ -1493,9 +1457,11 @@
 
 #ifdef	CONFIG_IP_FIREWALL
 	
-	if(!LOOPBACK(iph->daddr) && !ip_fw_chk(iph,ip_fw_blk_chain,
-			ip_fw_blk_policy))
+	if( 
+		(err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy))!=1)
 	{
+		if(err==-1)
+			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);
 		kfree_skb(skb, FREE_WRITE);
 		return 0;	
 	}
@@ -1609,7 +1575,7 @@
 	 */
 	 
 #ifdef CONFIG_IP_ACCT
-	ip_acct_cnt(iph,ip_acct_chain);
+	ip_acct_cnt(iph,dev, ip_acct_chain);
 #endif	
 
 	/*
@@ -1906,7 +1872,7 @@
 	 
 	ip_statistics.IpOutRequests++;
 #ifdef CONFIG_IP_ACCT
-	ip_acct_cnt(iph,ip_acct_chain);
+	ip_acct_cnt(iph,dev, ip_acct_chain);
 #endif	
 	
 #ifdef CONFIG_IP_MULTICAST	
