Bug 209491

Summary: Broadcast storm with ipfw+natd+gateway
Product: Base System Reporter: Rudolf Čejka <cejkar>
Component: kernAssignee: Andrey V. Elsukov <ae>
Status: Closed FIXED    
Severity: Affects Some People CC: ae, dipdill, eugen, gnn, marcinkk, pi, ports
Priority: ---    
Version: CURRENT   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
Proposed patch (untested)
none
Proposed patch (untested)
none
teach divert(4) to restore M_[BM]CAST flags none

Description Rudolf Čejka 2016-05-14 01:03:18 UTC
After commit 290383 (replace fastforward path with tryforward), there is atleast one possible system configuration, which can be source of broadcast storm. Simply put in your /etc/rc.conf:

    firewall_enable="YES"
    firewall_type="OPEN"

    natd_enable="YES"
    natd_interface="em0"

    gateway_enable="YES"

After reboot, you have a divert rule in ipfw with runnig natd:

    00050 divert 8668 ip4 from any to any via em0

Then, simply send a broadcast to this system, and it responds with 2 * (TTL - 1) broadcasts sent back.

Have atleast two of these systems on one local subnet with configured samba server, which sends one broadcast per minute, and this is practically sufficient to shut down your site with broadcast storm.

Pre-290383 system just receives the broadcast:

08:55:25.167489 IP 10.0.2.4.21680 > 10.0.2.255.netbios-ns: [|SMB]

After-290383 system with IP 10.0.2.15 receives the broadcast, and then responds with 126 broadcasts with reowned(translated) source address:

09:02:33.939027 IP 10.0.2.4.21490 > 10.0.2.255.netbios-ns: [|SMB]
09:02:33.939255 IP 10.0.2.15.21490 > 10.0.2.255.netbios-ns: [|SMB]
09:02:33.939303 IP 10.0.2.15.21490 > 10.0.2.255.netbios-ns: [|SMB]
09:02:33.939472 IP 10.0.2.15.44294 > 10.0.2.255.netbios-ns: [|SMB]
09:02:33.939524 IP 10.0.2.15.44294 > 10.0.2.255.netbios-ns: [|SMB]
09:02:33.939630 IP 10.0.2.15.40288 > 10.0.2.255.netbios-ns: [|SMB]
09:02:33.939661 IP 10.0.2.15.40288 > 10.0.2.255.netbios-ns: [|SMB]
...

(I thought that it was just one or two replied broadcasts, but in my testing environment in VirtualBox with two systems, one sending broadcast and one storming, it really showed this output and I could not find any other explanation of this. However, example above with one samba server and three storming systems was really real...)
Comment 1 Eugene Grosbein 2016-09-16 18:38:20 UTC
As quick workaround, insert following rule to your ipfw ruleset:

ipfw add 51 deny ip from any to any out recv em0 xmit em0 diverted
Comment 2 marcinkk 2017-04-03 13:47:33 UTC
The same problem here. Observed after upgrading from 10.3 to 11.0.

When I have 1 or 2 machines with natd in the network everything seems ok. Wireshark shows incereased number of broadcasts, but the network still works. After runnig a third and next machines the whole local network goes down because of broadcast storm :(

The workaround works fine. I've addedd to /etc/rc.firewall on all my machines after "divert natd" rule this one:

${fwcmd} add 51 deny ip from any to any out recv ${natd_interface} xmit ${natd_interface} diverted
Comment 3 Eugene Grosbein freebsd_committer freebsd_triage 2017-04-13 03:12:56 UTC
*** Bug 215256 has been marked as a duplicate of this bug. ***
Comment 4 Andrey V. Elsukov freebsd_committer freebsd_triage 2017-05-10 20:39:19 UTC
Created attachment 182485 [details]
Proposed patch (untested)

Can you test this patch?

The problem appeared after transition to ip_tryforward(). Due to the lack of M_BCAST flag on the diverted mbuf, it does not considered as broadcast packet and handled by tryforward code, that sends such packets to the wire, instead of handling in ip_input().
Comment 5 Andrey V. Elsukov freebsd_committer freebsd_triage 2017-05-10 21:06:42 UTC
Created attachment 182486 [details]
Proposed patch (untested)

Simplify the patch.
Comment 6 Eugene Grosbein freebsd_committer freebsd_triage 2017-05-10 21:54:40 UTC
Created attachment 182488 [details]
teach divert(4) to restore M_[BM]CAST flags

My version of patch does nearly same thing but it additionally includes incoming multicast packets having same problem.

Another note: one should reboot system after rebuilding sources even if ipdivert.ko modules is used. It is not safe currently to re-load ipdivert.ko without reboot, so do not force it.
Comment 7 commit-hook freebsd_committer freebsd_triage 2017-05-17 09:04:19 UTC
A commit references this bug:

Author: ae
Date: Wed May 17 09:04:09 UTC 2017
New revision: 318399
URL: https://svnweb.freebsd.org/changeset/base/318399

Log:
  Set M_BCAST and M_MCAST flags on mbuf sent via divert socket.

  r290383 has changed how mbufs sent by divert socket are handled.
  Previously they are always handled by slow path processing in ip_input().
  Now ip_tryforward() is invoked from ip_input() before in_broadcast() check.
  Since diverted packet lost all mbuf flags, it passes the broadcast check
  in ip_tryforward() due to missing M_BCAST flag. In the result the broadcast
  packet is forwarded to the wire instead of be consumed by network stack.

  Add in_broadcast() check to the div_output() function. And restore the
  M_BCAST flag if destination address is broadcast for the given network
  interface.

  PR:		209491
  MFC after:	1 week

Changes:
  head/sys/netinet/ip_divert.c
Comment 8 commit-hook freebsd_committer freebsd_triage 2017-05-24 09:04:47 UTC
A commit references this bug:

Author: ae
Date: Wed May 24 09:03:46 UTC 2017
New revision: 318778
URL: https://svnweb.freebsd.org/changeset/base/318778

Log:
  MFC r318399:
    Set M_BCAST and M_MCAST flags on mbuf sent via divert socket.

    r290383 has changed how mbufs sent by divert socket are handled.
    Previously they are always handled by slow path processing in ip_input().
    Now ip_tryforward() is invoked from ip_input() before in_broadcast() check.
    Since diverted packet lost all mbuf flags, it passes the broadcast check
    in ip_tryforward() due to missing M_BCAST flag. In the result the broadcast
    packet is forwarded to the wire instead of be consumed by network stack.

    Add in_broadcast() check to the div_output() function. And restore the
    M_BCAST flag if destination address is broadcast for the given network
    interface.

    PR:		209491

Changes:
_U  stable/11/
  stable/11/sys/netinet/ip_divert.c