From ru@ucb.crimea.ua Tue Mar 23 05:34:13 1999
Return-Path: <ru@ucb.crimea.ua>
Received: from relay.ucb.crimea.ua (relay.ucb.crimea.ua [212.110.138.1])
	by hub.freebsd.org (Postfix) with ESMTP id 2D6F214C2B
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 23 Mar 1999 05:32:42 -0800 (PST)
	(envelope-from ru@ucb.crimea.ua)
Received: (from ru@localhost)
	by relay.ucb.crimea.ua (8.9.2/8.9.2/UCB) id PAA51137;
	Tue, 23 Mar 1999 15:32:07 +0200 (EET)
	(envelope-from ru)
Message-Id: <199903231332.PAA51137@relay.ucb.crimea.ua>
Date: Tue, 23 Mar 1999 15:32:07 +0200 (EET)
From: Ruslan Ermilov <ru@ucb.crimea.ua>
Reply-To: ru@ucb.crimea.ua
To: FreeBSD-gnats-submit@freebsd.org
Subject: ipfirewall `deny' rules act as `reject' for `out' packets
X-Send-Pr-Version: 3.2

>Number:         10747
>Category:       kern
>Synopsis:       [PATCH] ipfirewall `deny' rules act as `reject' for `out' packets
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 23 05:40:01 PST 1999
>Closed-Date:    Fri May 5 01:50:11 PDT 2000
>Last-Modified:  Fri May  5 01:51:49 PDT 2000
>Originator:     Ruslan Ermilov
>Release:        FreeBSD 3.1-STABLE i386
>Organization:
United Commercial Bank
>Environment:

options IPFIREWALL

>Description:

When a packet matches `deny' rule, it is assumed to be silently dropped,
and no further notification should be sent.  Under some circumstances,
router will send ICMP host-unreachable message back to the originator.
It's only seen when matching outgoing packets.  The problem is how
ip_forward(), ip_output() and ip_fw_chk() interact.


Assume we have the following rules:

00100 deny ip from any to 1.2.3.4 out
00200 allow ip from any to any


Host x.x.x.x sends IP packet to host 1.2.3.4 via this router.
On the router:

1. ip_input() calls ip_fw_chk(IN)
2. ip_fw_chk() matches the packet with rule 200
2. ip_input() decides to forward the packet and calls ip_forward()
3. ip_forward() calls ip_output()
4. ip_output() calls ip_fw_chk(OUT)
5. ip_fw_chk() matches the packet with rule 100 and sets `m' to NULL
6. ip_output() returns EACCES
7. ip_forward() calls icmp_error(.., ICMP_UNREACH, ICMP_UNREACH_HOST, ...)


Moreover, if you have the following rules:
00100 unreach <code> ip from any to 1.2.3.4 out
00200 allow ip from any to any

the router will send 2 ICMP unreachable messages in reply to the packet.
First (with the code <code>) will be sent from ip_fw_chk().  Then
ip_forward() will send ICMP host-unreachable.  See `how-to-repeat'.


>How-To-Repeat:

router[192.168.1.1]# ipfw l
00100 unreach filter-prohib ip from any to 1.2.3.4 out
00200 allow ip from any to any

host[192.168.1.13]# ping -c1 1.2.3.4

router[192.168.1.1]# tcpdump -t -n -v icmp
tcpdump: listening on fxp0
192.168.1.13 > 1.2.3.4: icmp: echo request (ttl 32, id 21565)
192.168.1.1 > 192.168.1.13: icmp: host 1.2.3.4 unreachable - admin prohibited filter (ttl 255, id 17780)
192.168.1.1 > 192.168.1.13: icmp: host 1.2.3.4 unreachable (ttl 255, id 17781)

Take the note of the `id' fields of last two packets.


>Fix:

No easy fix comes to my mind, sorry.


>Release-Note:
>Audit-Trail:

From: Ruslan Ermilov <ru@freebsd.org>
To: freebsd-gnats-submit@freebsd.org, ru@freebsd.org
Cc:  
Subject: Re: kern/10747: ipfirewall `deny' rules act as `reject' for `out' packets
Date: Fri, 11 Jun 1999 13:41:28 +0300

 Index: ip_input.c
 ===================================================================
 RCS file: /usr/FreeBSD-CVS/src/sys/netinet/ip_input.c,v
 retrieving revision 1.111.2.2
 diff -u -u -r1.111.2.2 ip_input.c
 --- ip_input.c	1999/05/04 16:23:58	1.111.2.2
 +++ ip_input.c	1999/06/05 04:55:04
 @@ -1510,6 +1510,9 @@
  		/* type, code set above */
  		break;
  
 +	case EPERM:			/* firewall rejected/denied packet */
 +		return;			/* don't call icmp_error() twice */
 +
  	case ENETUNREACH:		/* shouldn't happen, checked above */
  	case EHOSTUNREACH:
  	case ENETDOWN:
 Index: ip_output.c
 ===================================================================
 RCS file: /usr/FreeBSD-CVS/src/sys/netinet/ip_output.c,v
 retrieving revision 1.85.2.3
 diff -u -u -r1.85.2.3 ip_output.c
 --- ip_output.c	1999/05/04 16:24:00	1.85.2.3
 +++ ip_output.c	1999/06/05 04:46:49
 @@ -450,7 +450,7 @@
                   * packets in case of doubt.
                   */
  		if (!m) { /* firewall said to reject */
 -			error = EACCES;
 +			error = EPERM;
  			goto done;
  		}
  		if (off == 0 && dst == old) /* common case */
 
State-Changed-From-To: open->closed 
State-Changed-By: ru 
State-Changed-When: Fri May 5 01:50:11 PDT 2000 
State-Changed-Why:  
Superseded by PR kern/18382 
>Unformatted:
