From alex@zen.nash.org  Sun May 12 12:41:20 1996
Received: from zen.nash.org (nash.pr.mcs.net [204.95.47.72])
          by freefall.freebsd.org (8.7.3/8.7.3) with ESMTP id MAA09935
          Sun, 12 May 1996 12:41:09 -0700 (PDT)
Received: (from alex@localhost) by zen.nash.org (8.7.5/8.6.12) id OAA00723; Sun, 12 May 1996 14:40:24 -0500 (CDT)
Message-Id: <199605121940.OAA00723@zen.nash.org>
Date: Sun, 12 May 1996 14:40:24 -0500 (CDT)
From: Alex Nash <alex@zen.nash.org>
Reply-To: nash@mcs.com
To: FreeBSD-gnats-submit@freebsd.org
Cc: phk@freebsd.org
Subject: Kernel IPFW
X-Send-Pr-Version: 3.2

>Number:         1192
>Category:       kern
>Synopsis:       various ipfw.[ch] changes (see below)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    alex
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun May 12 12:50:02 PDT 1996
>Closed-Date:    Sun Jun 9 16:46:26 PDT 1996
>Last-Modified:  Sun Jun  9 16:48:46 PDT 1996
>Originator:     Alex Nash
>Release:        FreeBSD 2.1-STABLE i386
>Organization:
>Environment:

-current and -stable systems that use ipfw.

>Description:

ip_fw.h:

  A constant used by the ipfw program was missing from the -stable
  branch.

ip_fw.c:

  Added IPFIREWALL_VERBOSE_LIMIT option that prevents denial-of-service
  attacks by flooding a system with IPFW log messages.  This option
  is OFF by default.

  Added the ability to clear the accounting record of a single chain
  entry.  (An update to the ipfw program has been submitted separately
  to accomodate this.)

  Changed the boot up messages to indicate the logging level and
  limit (if enabled).

  Moved the majority of code out of the ipfw_load (module load)
  routine and instead issue a call to ipfw_init which does the same
  thing (sans the splnet() issued at the beginning of ipfw_load).

  WARNING: The new sysctl int has not been tested or even compiled!

LINT:

  Expanded the explanation of the IPFIREWALL_VERBOSE option.

  Added IPFIREWALL_VERBOSE_LIMIT.

>How-To-Repeat:

N/A

>Fix:
	
--- sys/netinet/ip_fw.h	Sun May 12 12:51:26 1996
***************
*** 105,110 ****
--- 105,111 ----
  #define IP_FW_TCPF_PSH		TH_PUSH
  #define IP_FW_TCPF_ACK		TH_ACK
  #define IP_FW_TCPF_URG		TH_URG
+ #define IP_FW_TCPF_ESTAB	0x40
  
  /*
   * New IP firewall options for [gs]etsockopt at the RAW IP level.



--- sys/netinet/ip_fw.c	Sun May 12 12:27:06 1996
***************
*** 41,46 ****
--- 41,51 ----
  #else
  static int fw_verbose = 0;
  #endif
+ #ifdef IPFIREWALL_VERBOSE_LIMIT
+ static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
+ #else
+ static int fw_verbose_limit = 0;
+ #endif
  
  
  LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;
***************
*** 49,54 ****
--- 54,60 ----
  SYSCTL_NODE(net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
  SYSCTL_INT(net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");
  SYSCTL_INT(net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");
+ SYSCTL_INT(net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");
  #endif
  
  #define dprintf(a)	if (!fw_debug); else printf a
***************
*** 68,74 ****
  static int	port_match __P((u_short *portptr, int nports, u_short port,
  				int range_flag));
  static int	tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
! static void	ipfw_report __P((char *txt, int rule, struct ip *ip));
  
  static int (*old_chk_ptr)(struct mbuf *, struct ip *,struct ifnet *, int dir);
  static int (*old_ctl_ptr)(int,struct mbuf **);
--- 74,80 ----
  static int	port_match __P((u_short *portptr, int nports, u_short port,
  				int range_flag));
  static int	tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
! static void	ipfw_report __P((char *txt, int rule, struct ip *ip, int counter));
  
  static int (*old_chk_ptr)(struct mbuf *, struct ip *,struct ifnet *, int dir);
  static int (*old_ctl_ptr)(int,struct mbuf **);
***************
*** 179,191 ****
  }
  
  static void
! ipfw_report(char *txt, int rule, struct ip *ip)
  {
  	struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl);
  	struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl);
  	struct icmp *icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl);
  	if (!fw_verbose)
  		return;
  	printf("ipfw: %d %s ",rule, txt);
  	switch (ip->ip_p) {
  	case IPPROTO_TCP:
--- 185,199 ----
  }
  
  static void
! ipfw_report(char *txt, int rule, struct ip *ip, int counter)
  {
  	struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl);
  	struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl);
  	struct icmp *icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl);
  	if (!fw_verbose)
  		return;
+ 	if (fw_verbose_limit != 0 && counter > fw_verbose_limit)
+ 		return;
  	printf("ipfw: %d %s ",rule, txt);
  	switch (ip->ip_p) {
  	case IPPROTO_TCP:
***************
*** 246,252 ****
  	 * we're not going to pass it...
  	 */
  	if ((ip->ip_off & IP_OFFMASK) == 1) {
! 		ipfw_report("Refuse", -1, ip);
  		m_freem(m);
  		return 0;
  	}
--- 254,263 ----
  	 * we're not going to pass it...
  	 */
  	if ((ip->ip_off & IP_OFFMASK) == 1) {
! 		static int frag_counter = 0;
! 
! 		++frag_counter;
! 		ipfw_report("Refuse", -1, ip, frag_counter);
  		m_freem(m);
  		return 0;
  	}
***************
*** 398,408 ****
  		f->fw_bcnt+=ip->ip_len;
  		if (f->fw_flg & IP_FW_F_PRN) {
  			if (f->fw_flg & IP_FW_F_ACCEPT)
! 				ipfw_report("Accept", f->fw_number, ip);
  			else if (f->fw_flg & IP_FW_F_COUNT)
! 				ipfw_report("Count", f->fw_number, ip);
  			else
! 				ipfw_report("Deny", f->fw_number, ip);
  		}
  		if (f->fw_flg & IP_FW_F_ACCEPT)
  			return 1;
--- 409,419 ----
  		f->fw_bcnt+=ip->ip_len;
  		if (f->fw_flg & IP_FW_F_PRN) {
  			if (f->fw_flg & IP_FW_F_ACCEPT)
! 				ipfw_report("Accept", f->fw_number, ip, f->fw_pcnt);
  			else if (f->fw_flg & IP_FW_F_COUNT)
! 				ipfw_report("Count", f->fw_number, ip, f->fw_pcnt);
  			else
! 				ipfw_report("Deny", f->fw_number, ip, f->fw_pcnt);
  		}
  		if (f->fw_flg & IP_FW_F_ACCEPT)
  			return 1;
***************
*** 518,523 ****
--- 529,563 ----
  	return (EINVAL);
  }
  
+ static int
+ zero_entry(m)
+ 	struct mbuf *m;
+ {
+ 	struct ip_fw *frwl;
+ 	struct ip_fw_chain *fcp;
+ 	int s;
+ 
+ 	if (m) {
+ 		frwl = check_ipfw_struct(m);
+ 
+ 		if (!frwl)
+ 			return(EINVAL);
+ 	}
+ 	else
+ 		frwl = NULL;
+ 
+ 	/*
+ 	 *	It's possible to insert multiple chain entries with the
+ 	 *	same number, so we don't stop after finding the first
+ 	 *	match if zeroing a specific entry.
+ 	 */
+ 	s = splnet();
+ 	for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
+ 		if (!frwl || frwl->fw_number == fcp->rule->fw_number)
+ 			fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
+ 	splx(s);
+ }
+ 
  static struct ip_fw *
  check_ipfw_struct(m)
  	struct mbuf *m;
***************
*** 600,612 ****
  		return (0);
  	}
  	if (stage == IP_FW_ZERO) {
! 		int s = splnet();
! 		struct ip_fw_chain *fcp;
! 		for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
! 			fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
! 		splx(s);
  		if (m) (void)m_free(m);
! 		return (0);
  	}
  	if (m == NULL) {
  		printf("ip_fw_ctl:  NULL mbuf ptr\n");
--- 640,648 ----
  		return (0);
  	}
  	if (stage == IP_FW_ZERO) {
! 		error = zero_entry(m);
  		if (m) (void)m_free(m);
! 		return (error);
  	}
  	if (m == NULL) {
  		printf("ip_fw_ctl:  NULL mbuf ptr\n");
***************
*** 647,653 ****
  	deny.fw_number = (u_short)-1;
  	add_entry(&ip_fw_chain, &deny);
  	
! 	printf("IP firewall initialized\n");
  }
  
  #ifdef ACTUALLY_LKM_NOT_KERNEL
--- 683,697 ----
  	deny.fw_number = (u_short)-1;
  	add_entry(&ip_fw_chain, &deny);
  	
! 	printf("IP firewall initialized, ");
! #ifndef IPFIREWALL_VERBOSE
! 	printf("logging disabled\n");
! #else
! 	if (fw_verbose_limit == 0)
! 		printf("unlimited logging\n");
! 	else
! 		printf("logging limited to %d packets/entry\n", fw_verbose_limit);
! #endif
  }
  
  #ifdef ACTUALLY_LKM_NOT_KERNEL
***************
*** 662,682 ****
  ipfw_load(struct lkm_table *lkmtp, int cmd)
  {
  	int s=splnet();
- 	struct ip_fw deny;
  
          old_chk_ptr = ip_fw_chk_ptr;
          old_ctl_ptr = ip_fw_ctl_ptr;
- 	ip_fw_chk_ptr = ip_fw_chk;
- 	ip_fw_ctl_ptr = ip_fw_ctl;
- 
- 	LIST_INIT(&ip_fw_chain);
- 	bzero(&deny, sizeof deny);
- 	deny.fw_flg = IP_FW_F_ALL;
- 	deny.fw_number = (u_short)-1;
- 	add_entry(&ip_fw_chain, &deny);
  
  	splx(s);
- 	printf("IP firewall loaded\n");
  	return 0;
  }
  
--- 706,717 ----
  ipfw_load(struct lkm_table *lkmtp, int cmd)
  {
  	int s=splnet();
  
          old_chk_ptr = ip_fw_chk_ptr;
          old_ctl_ptr = ip_fw_ctl_ptr;
  
+ 	ip_fw_init();
  	splx(s);
  	return 0;
  }


--- sys/i386/conf/LINT        Sat May 11 08:28:06 1996
***************
*** 185,192 ****
  # with mrouted(8).
  #
  # IPFIREWALL enables support for IP firewall construction, in
! # conjunction with the `ipfw' program.  IPFIREWALL_VERBOSE does
! # the obvious thing.
  #
  # ARP_PROXYALL enables global proxy ARP.  Beware!  This can burn
  # your house down!  See netinet/if_ether.c for the gory details.
--- 185,193 ----
  # with mrouted(8).
  #
  # IPFIREWALL enables support for IP firewall construction, in
! # conjunction with the `ipfw' program.  IPFIREWALL_VERBOSE prints
! # logged packets on the console.  IPFIREWALL_VERBOSE_LIMIT limits
! # the number of times a matching entry can print.
  #
  # ARP_PROXYALL enables global proxy ARP.  Beware!  This can burn
  # your house down!  See netinet/if_ether.c for the gory details.
***************
*** 198,203 ****
--- 199,205 ----
  options         IPFIREWALL              #firewall
  options         IPFIREWALL_VERBOSE      #print information about
                                        # dropped packets
+ options               "IPFIREWALL_VERBOSE_LIMIT=100" # limit verbosity
  options               ARP_PROXYALL            # global proxy ARP
>Release-Note:
>Audit-Trail:

From: Garrett Wollman <wollman@lcs.mit.edu>
To: nash@mcs.com
Cc: FreeBSD-gnats-submit@freebsd.org, phk@freebsd.org
Subject: kern/1192: Kernel IPFW
Date: Sun, 12 May 1996 16:23:32 -0400

 <<On Sun, 12 May 1996 14:40:24 -0500 (CDT), Alex Nash <alex@zen.nash.org> said:
 
 >   Moved the majority of code out of the ipfw_load (module load)
 >   routine and instead issue a call to ipfw_init which does the same
 >   thing (sans the splnet() issued at the beginning of ipfw_load).
 
 Actually, I would very much like to get rid of the
 dynamically-loadable IPFW module entirely.  If you are running any
 sort of a reasonable router configuration (i.e., with multiple cards
 from the same vendor), you will have to reconfigure the kernel anyway,
 and I think there are probably good security reasons for wanting in
 that way.  (What if the LKM fails to load because you are out of disk
 space in /tmp?  Oops.)  Perhaps more significantly, it puts extra hair
 in the IP input and output paths that doesn't need to be there in the
 common case (workstation or non-firewalling router), so I'd like to
 see it removed.
 
 (And yes, I do remember that I'm the one who suggested making it into
 an LKM in the first place!)
 
 -GAWollman
 
 --
 Garrett A. Wollman   | Shashish is simple, it's discreet, it's brief. ... 
 wollman@lcs.mit.edu  | Shashish is the bonding of hearts in spite of distance.
 Opinions not those of| It is a bond more powerful than absence.  We like people
 MIT, LCS, ANA, or NSA| who like Shashish.  - Claude McKenzie + Florent Vollant

From: Poul-Henning Kamp <phk@critter.tfs.com>
To: Garrett Wollman <wollman@lcs.mit.edu>
Cc: nash@mcs.com, FreeBSD-gnats-submit@freebsd.org
Subject: Re: kern/1192: Kernel IPFW 
Date: Sun, 12 May 1996 20:57:43 +0000

 > Actually, I would very much like to get rid of the
 > dynamically-loadable IPFW module entirely.
 
 I think that this makes sense from a security point of view, but
 people use it for a lot of things besides security.  The hooks
 are very general and can be used for a bunch of other things as
 well, so I think this is all in all, not a good idea.
 
 --
 Poul-Henning Kamp           | phk@FreeBSD.ORG       FreeBSD Core-team.
 http://www.freebsd.org/~phk | phk@login.dknet.dk    Private mailbox.
 whois: [PHK]                | phk@ref.tfs.com       TRW Financial Systems, Inc.
 Future will arrive by its own means, progress not so.
Responsible-Changed-From-To: freebsd-bugs->alex 
Responsible-Changed-By: alex 
Responsible-Changed-When: Wed May 29 16:28:29 PDT 1996 
Responsible-Changed-Why:  
I now have a chance to fix the things I complained about :) 
State-Changed-From-To: open->closed 
State-Changed-By: alex 
State-Changed-When: Sun Jun 9 16:46:26 PDT 1996 
State-Changed-Why:  
Changes entered into -current under the following versions: 

src/sbin/ipfw.c:         1.25 
src/sys/netinet/ip_fw.c: 1.37 
src/sys/netinet/ip_fw.h: 1.20 

>Unformatted:
