From nobody@FreeBSD.org  Wed Sep 21 21:17:21 2005
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 900B016A41F
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 21 Sep 2005 21:17:21 +0000 (GMT)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [216.136.204.117])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 445A943D45
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 21 Sep 2005 21:17:21 +0000 (GMT)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id j8LLHKQ7069714
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 21 Sep 2005 21:17:20 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id j8LLHKUC069713;
	Wed, 21 Sep 2005 21:17:20 GMT
	(envelope-from nobody)
Message-Id: <200509212117.j8LLHKUC069713@www.freebsd.org>
Date: Wed, 21 Sep 2005 21:17:20 GMT
From: Pieter de Boer <pieter@thedarkside.nl>
To: freebsd-gnats-submit@FreeBSD.org
Subject: if_tap doesn't filter frames not destined for itself
X-Send-Pr-Version: www-2.3

>Number:         86429
>Category:       kern
>Synopsis:       [if_tap] [patch] if_tap doesn't filter frames not destined for itself
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bms
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 21 21:20:06 GMT 2005
>Closed-Date:    Sun Feb 25 16:00:35 GMT 2007
>Last-Modified:  Sun Feb 25 16:00:35 GMT 2007
>Originator:     Pieter de Boer
>Release:        6.0-BETA4
>Organization:
>Environment:
FreeBSD edinburgh 6.0-BETA4 FreeBSD 6.0-BETA4 #2: Sat Sep 17 18:01:08 CEST 2005 pieter@edinburgh:/usr/obj/usr/src/sys/kernel-31-07-2005 i386

>Description:
      The tap-driver doesn't filter incoming ethernet frames with a different unicast destination mac address than it's own mac address. The frames are sent up to the IP-stack, which may route them when forwarding is turned on. In my case leading to the system doing arp who-has on the destination IP-address in the ethernet frame, because the kernel wants to route the packet. On a virtual internet-exchange (www.virt-ix.net) using tap-tunnels this leads to a packet storm.

>How-To-Repeat:
      Set up a ethernet tunnel using vtund/openvpn, configure two ethernet-addresses on both ends. On one system (A), turn on IP forwarding. On system B, create a static ARP entry for an address in the subnet, with a non-existent MAC address (like de:ad:ba:be:ca:fe). Run tcpdump on system B(!) and ping from system B to the IP address with the fake MAC address. See how system A does an arp request for the destination IP address because it wants to route it. This indicates
the frame was wrongly pushed to the IP stack.

>Fix:
      Adding an extra check to if_tap.c fixes this bug. The following patch works
on my system.

--- if_tap.c.orig	Wed Sep  7 21:12:10 2005
+++ if_tap.c	Thu Sep  8 22:05:46 2005
@@ -801,6 +801,7 @@
 	struct uio	*uio;
 	int		 flag;
 {
+	struct ether_header	*eh;
 	struct tap_softc	*tp = dev->si_drv1;
 	struct ifnet		*ifp = tp->tap_ifp;
 	struct mbuf		*m;
@@ -825,6 +826,21 @@
 	}
 
 	m->m_pkthdr.rcvif = ifp;
+	
+	/* Check length first */
+	if (m->m_len < sizeof(struct ether_header)) {
+		m_freem(m);
+		return(0);
+	}
+
+	/* Only pass it up to the ether_input() layer if it's meant for us. */
+	eh = mtod(m, struct ether_header *);
+	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 && bcmp(eh->ether_dhost, 
+	    IFP2ENADDR(ifp), ETHER_ADDR_LEN) && 
+	    (eh->ether_dhost[0] & 1) == 0) {
+		m_freem(m);
+		return(0);
+	}
 
 	/* Pass packet up to parent. */
 	(*ifp->if_input)(ifp, m);

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->bms 
Responsible-Changed-By: bms 
Responsible-Changed-When: Mon Sep 25 16:49:20 UTC 2006 
Responsible-Changed-Why:  
I'll take this.  I'm sure I saw behaviour like this with tap today in -CURRENT. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=86429 

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Tue, 26 Sep 2006 23:30:01 +0100

 I can definitely reproduce this in 6.1-RELEASE.

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Tue, 26 Sep 2006 23:44:27 +0100

 The patch as supplied doesn't seem to fix the problem, though it seems 
 well thought out and intentioned. Further investigation needed.

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Wed, 27 Sep 2006 00:14:17 +0100

 My bad! I'm barking up the wrong tree here.
 
 When I try to reproduce the condition described in the PR with the 
 patch, I can't trigger it.
 I'll to reproduce without the patch. I have cleaned up the provided 
 patch slightly, it is attached here.
 
 What I was attempting to reproduce was the effect that multiple tap 
 interfaces seem to have, that is, they all appear to be in the same 
 broadcast domain. This has caused problems with various IP forwarding 
 experiments I've been doing with FreeBSD and QEMU.
 
      
 HOST-----tap0------------ed0--------------------QEMU--ed1----tap1---HOST
 
     192.168.253.1/24        192.168.253.250/24                
 10.0.0.1/24     no address assigned
 
 This is how things look topology-wise; both tap0 and tap1 reside in the 
 host, and are connected to ed0 and ed1 inside the virtual machine 
 respectively. tap1 has no address assigned on the host side.
 
 However, tcpdumping on tap0 and tap1 shows traffic which shouldn't be 
 seen on that side of the host, when I ping 10.0.0.2, I see ARP requests 
 on the tap0 side -- bad, naughty tap.
 
 I think this may actually be related to how bpf taps are happening in 
 tap, which is a completely different problem.
 Sorry for the confusion...
 
 

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Wed, 27 Sep 2006 00:15:12 +0100

 This is a multi-part message in MIME format.
 --------------010502090205080101060703
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 That patch in full.
 
 --------------010502090205080101060703
 Content-Type: text/x-patch;
  name="if_tap.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="if_tap.diff"
 
 --- if_tap.c.orig	Thu Aug 25 06:01:20 2005
 +++ if_tap.c	Wed Sep 27 00:11:38 2006
 @@ -803,6 +803,7 @@
  	struct uio	*uio;
  	int		 flag;
  {
 +	struct ether_header	*eh;
  	struct tap_softc	*tp = dev->si_drv1;
  	struct ifnet		*ifp = tp->tap_ifp;
  	struct mbuf		*m;
 @@ -827,6 +828,21 @@
  	}
  
  	m->m_pkthdr.rcvif = ifp;
 +
 +	/* Check length first */
 +	if (m->m_len < sizeof(struct ether_header)) {
 +		m_freem(m);
 +		return (0);
 +	}
 +
 +	/* Only pass it up to the ether_input() layer if it's meant for us. */
 +	eh = mtod(m, struct ether_header *);
 +	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
 +	    bcmp(eh->ether_dhost, IFP2ENADDR(ifp), ETHER_ADDR_LEN) &&
 +	    !ETHER_IS_MULTICAST(eh->ether_dhost)) {
 +		m_freem(m);
 +		return (0);
 +	}
  
  	/* Pass packet up to parent. */
  	(*ifp->if_input)(ifp, m);
 
 --------------010502090205080101060703--

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Wed, 27 Sep 2006 00:27:56 +0100

 I can't seem to reproduce this on 6.1-RELEASE without the patch either.
 Checking cvs logs, I don't see any commits which could have directly 
 fixed this.
 I wonder if the submitter can reproduce this problem on 6.1-RELEASE or 
 later?
State-Changed-From-To: open->feedback 
State-Changed-By: bms 
State-Changed-When: Wed Sep 27 10:06:59 UTC 2006 
State-Changed-Why:  
In 6.1-RELEASE, if_ethersubr.c has near identical checks to this patch 
in the ether_input() and subsequent ether_demux() paths. 
I can't reproduce this on 6.1-RELEASE, can you try there also? 
If so, can you try changing the patch to perform this check further 
down the stack i.e. in the ether_demux() path to keep the code common? 

http://www.freebsd.org/cgi/query-pr.cgi?pr=86429 

From: Pieter de Boer <pieter@thedarkside.nl>
To: Bruce M Simpson <bms@FreeBSD.org>,  bug-followup@freebsd.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Sun, 01 Oct 2006 15:01:54 +0200

 > In 6.1-RELEASE, if_ethersubr.c has near identical checks to this patch
 > in the ether_input() and subsequent ether_demux() paths.
 > I can't reproduce this on 6.1-RELEASE, can you try there also?
 > If so, can you try changing the patch to perform this check further
 > down the stack i.e. in the ether_demux() path to keep the code common?
 > 
 > http://www.freebsd.org/cgi/query-pr.cgi?pr=86429
 I can successfully reproduce this on 6.2-PRERELEASE from about two weeks 
 ago.
 
 This is the setup:
 
 Host A: tap1 = 195.16.84.89/29 (MAC 00:bd:ae:43:1c:01)
          Static arp entry:
 ? (195.16.84.91) at de:ad:ca:fe:ba:be on tap1 permanent [ethernet]
 
 Host B: tap0 = 195.16.84.90/29 (MAC 00:bd:bc:92:00:00)
 	IP Forwarding turned on:
 	net.inet.ip.forwarding: 0 -> 1
 
 
 Using OpenVPN to tunnel ethernet between the two hosts.
 
  From host A I send a ping to 195.16.84.91, with MAC address 
 de:ad:ca:fe:ba:be. This is sent over the tunnel to host B, which tries 
 to route it and sends a ICMP redirect for. Using tcpdump on host A (not 
 to influence the packet flow on host B):
 
 listening on tap1, link-type EN10MB (Ethernet), capture size 96 bytes
 14:38:04.637796 00:bd:ae:43:1c:01 > de:ad:ca:fe:ba:be, ethertype IPv4 
 (0x0800), length 98: 195.16.84.89 > 195.16.84.91: ICMP echo request, id 
 31349, seq 0, length 64
 14:38:04.666891 00:bd:bc:92:00:00 > ff:ff:ff:ff:ff:ff, ethertype ARP 
 (0x0806), length 42: arp who-has 195.16.84.91 tell 195.16.84.90
 14:38:04.669145 00:bd:bc:92:00:00 > 00:bd:ae:43:1c:01, ethertype IPv4 
 (0x0800), length 70: 195.16.84.90 > 195.16.84.89: ICMP redirect 
 195.16.84.91 to host 195.16.84.91, length 36
 
 As can be seen, a ethernet frame is sent to de:ad:ca:fe:ba:be, which is 
 sent to the higher layers on host B, even though it's not the correct 
 MAC-address of the tap0-interface of host B. Host B acts according to 
 normal router behaviour by ARP requesting and sending a ICMP redirect.
 
 The patch I made last year implements a check in the tap-driver to 
 filter such frames unless promiscuous mode is turned on. This is done to 
 ensure that the tap-interface behaves the same as real, physical NICs 
 do. That's the reason I implemented it in the tap-driver itself.  It 
 looks similar to the checks further down, because I copied and adapted 
 the code from there..
State-Changed-From-To: feedback->open 
State-Changed-By: bms 
State-Changed-When: Sat Oct 7 16:26:57 UTC 2006 
State-Changed-Why:  
Re-opened. I will have to build OpenVPN for my test images and attempt to 
reproduce the test case exactly as submitter describes 

http://www.freebsd.org/cgi/query-pr.cgi?pr=86429 

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/86429: [if_tap] [patch] if_tap doesn't filter frames not
 destined for itself
Date: Sat, 03 Feb 2007 01:27:00 +0000

 I can reproduce this bug with -CURRENT as described using OpenVPN and ping.
State-Changed-From-To: open->patched 
State-Changed-By: bms 
State-Changed-When: Sat Feb 3 02:58:32 UTC 2007 
State-Changed-Why:  
Committed, pending MFC, thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=86429 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/86429: commit references a PR
Date: Sat,  3 Feb 2007 02:57:54 +0000 (UTC)

 bms         2007-02-03 02:57:46 UTC
 
   FreeBSD src repository
 
   Modified files:
     sys/net              if_tap.c 
   Log:
   Drop unicast Ethernet frames not destined for the configured address
   of a tap(4) instance, if IFF_PROMISC is not set.
   
   In tap(4), we should emulate the effect IFF_PROMISC would have on
   hardware, otherwise we risk introducing layer 2 loops if tap(4) is
   used with bridges. This means not even bpf(4) gets to see them.
   
   This patch has been tested in a variety of situations. Multicast and
   broadcast frames are correctly allowed through. I have observed this
   behaviour causing problems with multiple QEMU instances hosted on
   the same FreeBSD machine.
   
   The checks in in ether_demux() [if_ethersubr.c, rev 1.222, line 638]
   are insufficient to prevent this bug from occurring, as ifp->if_vlantrunk
   will always be NULL for the non-vlan case.
   
   MFC after:      3 weeks
   PR:             86429
   Submitted by:   Pieter de Boer (with changes)
   
   Revision  Changes    Path
   1.68      +18 -0     src/sys/net/if_tap.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/86429: commit references a PR
Date: Sat, 24 Feb 2007 11:11:41 +0000 (UTC)

 bms         2007-02-24 11:11:36 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_6)
     sys/net              if_tap.c 
   Log:
   MFC rev 1.68:
     Drop unicast Ethernet frames not destined for the configured address
     of a tap(4) instance, if IFF_PROMISC is not set.
   
     In tap(4), we should emulate the effect IFF_PROMISC would have on
     hardware, otherwise we risk introducing layer 2 loops if tap(4) is
     used with bridges. This means not even bpf(4) gets to see them.
   
     This patch has been tested in a variety of situations. Multicast and
     broadcast frames are correctly allowed through. I have observed this
     behaviour causing problems with multiple QEMU instances hosted on
     the same FreeBSD machine.
   
     The checks in in ether_demux() [if_ethersubr.c, rev 1.222, line 638]
     are insufficient to prevent this bug from occurring, as ifp->if_vlantrunk
     will always be NULL for the non-vlan case.
   
   PR:             86429
   Submitted by:   Pieter de Boer (with changes)
   
   Revision  Changes    Path
   1.55.2.7  +18 -0     src/sys/net/if_tap.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: bms 
State-Changed-When: Sun Feb 25 16:00:08 UTC 2007 
State-Changed-Why:  
MFC 

http://www.freebsd.org/cgi/query-pr.cgi?pr=86429 
>Unformatted:
