Bug 99558 - FreeBSD 6.1 can't send packets to INADDR_BROADCAST
Summary: FreeBSD 6.1 can't send packets to INADDR_BROADCAST
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Bruce M Simpson
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-06-27 18:10 UTC by Andrey V. Elsukov
Modified: 2025-02-22 02:13 UTC (History)
1 user (show)

See Also:


Attachments
ip_output.c.patch (620 bytes, patch)
2007-01-05 21:10 UTC, Ryan Beasley
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey V. Elsukov 2006-06-27 18:10:20 UTC
	FreeBSD 6.1 can't send UDP Broadcast. 
	Here is simple test programm:

--- test.c ---
#include <stdio.h>
#include <err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

int main(void)
{
	int sock, val, ret;
	struct sockaddr_in addr;

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0)
		err(1, "socket()");

	addr.sin_family = AF_INET;
	addr.sin_port = htons(5000);
	addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);

	val = 1;
	ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
					(const char*)&val, sizeof(val));
	if (ret < 0)
		err(2, "setsockopt()");

	ret = sendto(sock, "test", 4, 0, (struct sockaddr*)&addr,
				sizeof(addr));

	if (ret != 4)
		err(3, "sendto()");

	close(sock);
	return (0);
}
--- test.c ---


1. I've connect via PPTP tunnel and my host have default route.
[butcher@btr butcher]> ./test
[butcher@btr butcher]> sudo tcpdump -ni ng0 -XX udp port 5000 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ng0, link-type NULL (BSD loopback), capture size 96 bytes
19:25:32.169657 IP 192.168.3.6.53565 > 255.255.255.255.5000: UDP, length 4
        0x0000:  0200 0000 4500 0020 241a 0000 4011 9305  ....E...$...@...
        0x0010:  c0a8 0306 ffff ffff d13d 1388 000c 6f88  .........=....o.
        0x0020:  7465 7374                                test
^C

Message was send, but via PPTP to default destination.

2. I've not connected to PPTP server and don't have default route.

[butcher@btr butcher]> netstat -rnf inet | grep default
[butcher@btr butcher]> ./test
test: sendto(): Network is unreachable

test programm was fail with error.

3. I have the default route.
[butcher@btr butcher]> sudo route add default server
add net default: gateway server
[butcher@btr butcher]> ./test
[butcher@btr butcher]> sudo tcpdump -ni nve0 -XX udp port 5000
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on nve0, link-type EN10MB (Ethernet), capture size 96 bytes
19:29:51.988429 IP 192.168.4.234.54134 > 255.255.255.255.5000: UDP, length 4
0x0000:  0080 4836 9531 4255 5443 4821 0800 4500  ..H6.1BUTCH!..E.
0x0010:  0020 2459 0000 4011 90e2 c0a8 04ea ffff  ..$Y..@.........
0x0020:  ffff d376 1388 000c 6b6b 7465 7374       ...v....kktest
^C

Message was send to default destination with router's destination MAC address.

How-To-Repeat: 	Always.
Comment 1 Bruce M Simpson freebsd_committer freebsd_triage 2006-06-28 21:24:04 UTC
State Changed
From-To: open->feedback

This behaviour is by design. 

Please read the manual page ip(4) for information on the IP_ONESBCAST 
option. The INADDR_BROADCAST destination is by its nature non specific 
and link local therefore you need to use the IP_ONESBCAST option to 
cause undirected broadcasts to be sent on a particular interface. 



Comment 2 Bruce M Simpson freebsd_committer freebsd_triage 2006-06-28 21:24:04 UTC
Responsible Changed
From-To: freebsd-bugs->bms

This behaviour is by design. 

Please read the manual page ip(4) for information on the IP_ONESBCAST 
option. The INADDR_BROADCAST destination is by its nature non specific 
and link local therefore you need to use the IP_ONESBCAST option to 
cause undirected broadcasts to be sent on a particular interface.
Comment 3 Vadim Goncharov 2006-06-29 09:50:37 UTC
bms wrote:

> This behaviour is by design.Please read the manual page ip(4) for  
> information on the IP_ONESBCASToption. The INADDR_BROADCAST destination  
> is by its nature non specificand link local therefore you need to use  
> the IP_ONESBCAST option tocause undirected broadcasts to be sent on a  
> particular interface.

You are wrong.

This behaviour violates both POLA and STD 0005 (RFC 919), regardless of  
any implementation-specific details like socket options. It requires that  
IP broadcast address must be mapped to link-level broadcast address, and  
STD 0041 (RFC 894) clearly specifies that on Ethernet it MUST be only  
ff:ff:ff:ff:ff:ff - while FreeBSD 6.0 and 6.1 send such packet with  
destination MAC address of gateway, by default routing (WRONG!) instead of  
link-level broadcast.

Talking about IP_ONESBCAST option is unrelated to this bug, as FreeBSD 5.4  
and 5.5 (I've tested) behaves correctly, while having this option too. It  
only tells about selection of interface, and not about resending broadcast  
to default router with his MAC addr instead of link-level broadcast on  
that interface. Here is excerpt from perl program ports/net/wakeonlan,  
doing broadcast to user-specified address - it works correctly (in subject  
of this PR) on FreeBSD 5 without IP_ONESBCAST option:

         socket(S, AF_INET, SOCK_DGRAM, $proto) or die "socket : $!";
         setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt :  
$!";

         print "Sending magic packet to $ipaddr:$port with $hwaddr\n";

         send(S, $pkt, 0, $them) or die "send : $!";

-- 
WBR, Vadim Goncharov
Comment 4 Bruce M Simpson 2006-06-29 10:50:03 UTC
A few comments:

 * Please, when submitting tcpdump output, use the -e option to display
   the decoded link-layer addresses. It is all too easy for those of us
   who work on FreeBSD in what free time we can spare from our full-time
   jobs to miss such details, as I am sure you can appreciate, FreeBSD
   is a volunteer project.

 * Please attach the code in full you used to produce this condition
   as an attachment to the PR.

 * Based on the tcpdump output the submitter sent, this looks like
   it could be a regression introduced during the 6.x lifetime around
   the code which implements the IP_ONESBCAST option (which I introduced
   in FreeBSD 4.8), but this needs to be reproduced/confirmed.

 * Sends to 255.255.255.255 have never worked on FreeBSD the way STD0005
   documents them. This is because 255.255.255.255 doesn't get any
   special treatment on the transmit path -- it is by design, and
   FreeBSD has always worked this way.

On Thu, Jun 29, 2006 at 03:50:37PM +0700, Vadim Goncharov wrote:
> Talking about IP_ONESBCAST option is unrelated to this bug, as FreeBSD 
> 5.4  and 5.5 (I've tested) behaves correctly, while having this option 
> too. It  only tells about selection of interface, and not about 
> resending broadcast  to default router with his MAC addr instead of 
> link-level broadcast on  that interface. Here is excerpt from perl 
[..]

Incorrect. The bug report was about the undirected broadcast address.
IP_ONESBCAST is the only way to send an undirected broadcast datagram
on FreeBSD without relying on the default route behaviour you comment on,
as explained in the documentation.

It is important to distinguish between undirected broadcasts
(255.255.255.255) and directed broadcasts here (e.g. 192.168.1.255 in
a network 192.168.1.0/24).

You seem to be suggesting there is a problem with *all* forms of
broadcast IPv4 traffic, both directed and undirected. This would point
to a problem in the ARP layer, which would be a serious issue for the
entire network stack.

Can you please submit the information needed to reproduce this problem,
and in particular, the date where you first noticed the problem?

Thank you.
Comment 5 Andrey V. Elsukov 2006-07-03 06:56:16 UTC
Andre Oppermann wrote:
> The attached patch should fix the problem with SENDONES (untested).

The problem was not resolved for me with this patch. :(

-- 
WBR, Andrey V. Elsukov
Comment 6 Andre Oppermann freebsd_committer freebsd_triage 2006-07-03 08:48:25 UTC
Andrey V. Elsukov wrote:
> Andre Oppermann wrote:
>> The attached patch should fix the problem with SENDONES (untested).
> 
> The problem was not resolved for me with this patch. :(

Did you get an error message or did it simply put in the gateway's
MAC address again?  Was the IP destination address correct this time?
Can you provide a tcpdump again?  Have you set both SO_BROADCAST and
IP_SENDONES?

-- 
Andre
Comment 7 Andrey V. Elsukov 2006-07-03 11:54:37 UTC
Andre Oppermann wrote:
> Did you get an error message or did it simply put in the gateway's
> MAC address again?  Was the IP destination address correct this time?
> Can you provide a tcpdump again?  Have you set both SO_BROADCAST and
> IP_SENDONES?

Seems nothing has changed.
Without default route i can't send broadcast
(with both SO_BROADCAST and IP_ONESBCAST).

With default route i have an equal messages
(with IP_ONESBCAST and without).

The tcpdump output is the same.

-- 
WBR, Andrey V. Elsukov
Comment 8 Andre Oppermann freebsd_committer freebsd_triage 2006-08-30 20:38:04 UTC
Andrey V. Elsukov wrote:
> Andre Oppermann wrote:
>> Did you get an error message or did it simply put in the gateway's
>> MAC address again?  Was the IP destination address correct this time?
>> Can you provide a tcpdump again?  Have you set both SO_BROADCAST and
>> IP_SENDONES?
> 
> Seems nothing has changed.
> Without default route i can't send broadcast
> (with both SO_BROADCAST and IP_ONESBCAST).
> 
> With default route i have an equal messages
> (with IP_ONESBCAST and without).
> 
> The tcpdump output is the same.

OK, this time it is fixed.  Please try again, if it works as it should
then I'll commit it asap.

  http://people.freebsd.org/sendonesfix-20060830.diff
  http://people.freebsd.org/sendonestest-20060830.c

The IP_ONESBCAST socket option is dependent on the SO_BROADCAST socket
option which allows the sending of broadcast messages in general.  Jails
for example do not have this permission and will fail there.

Another change I made is the unconditional setting of TTL=1.  Allowing
any higher TTL is not useful and actually dangerous.  After the fix is
in I'll change the ip(4) manpage accordingly.

-- 
Andre
Comment 9 oppermann 2006-09-01 20:52:49 UTC
Andre Oppermann wrote:
> Andrey V. Elsukov wrote:
>> Andre Oppermann wrote:
>>> Did you get an error message or did it simply put in the gateway's
>>> MAC address again?  Was the IP destination address correct this time?
>>> Can you provide a tcpdump again?  Have you set both SO_BROADCAST and
>>> IP_SENDONES?
>>
>> Seems nothing has changed.
>> Without default route i can't send broadcast
>> (with both SO_BROADCAST and IP_ONESBCAST).
>>
>> With default route i have an equal messages
>> (with IP_ONESBCAST and without).
>>
>> The tcpdump output is the same.
> 
> OK, this time it is fixed.  Please try again, if it works as it should
> then I'll commit it asap.
> 
>  http://people.freebsd.org/sendonesfix-20060830.diff
>  http://people.freebsd.org/sendonestest-20060830.c

OK, correct URL here:

http://people.freebsd.org/~andre/sendonesfix-20060830.diff
http://people.freebsd.org/~andre/sendonestest-20060830.c

> The IP_ONESBCAST socket option is dependent on the SO_BROADCAST socket
> option which allows the sending of broadcast messages in general.  Jails
> for example do not have this permission and will fail there.
> 
> Another change I made is the unconditional setting of TTL=1.  Allowing
> any higher TTL is not useful and actually dangerous.  After the fix is
> in I'll change the ip(4) manpage accordingly.

-- 
Andre
Comment 10 Andrey V. Elsukov 2006-09-04 10:01:35 UTC
Andre Oppermann wrote:
> OK, correct URL here:
> 
> http://people.freebsd.org/~andre/sendonesfix-20060830.diff
> http://people.freebsd.org/~andre/sendonestest-20060830.c
> 
>> The IP_ONESBCAST socket option is dependent on the SO_BROADCAST socket
>> option which allows the sending of broadcast messages in general.  Jails
>> for example do not have this permission and will fail there.

Ok, i've tried your patches with fresh RELENG_6 kernel sources.

1. Without default gateway, ip_dst = 172.21.81.255 (broadcast for my 
subnet), SO_BROADCAST and IP_ONESBCAST was set.
This works as described in ip(4) - I have a datagram with dst_ip 
255.255.255.255 and broadcast MAC address.

2. Without default gateway, ip_dst = 172.21.81.255, SO_BROADCAST was 
set (without IP_ONESBCAST).
I have a datagram with dst_ip 172.21.81.255 and broadcast MAC address.

3. Without default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST 
was set (without IP_ONESBCAST).
sendto(): Network is unreachable

4. Without default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST 
and IP_ONESBCAST was set.
sendto(): Network is unreachable

5. With default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST and 
IP_ONESBCAST was set.
sendto(): Network is unreachable

6. With default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST was 
set (without IP_ONESBCAST).
I have a datagram with ip_dst = 255.255.255.255 and gateway's MAC as 
destination ethernet address.

7. With default gateway, ip_dst = 172.21.81.255, SO_BROADCAST was set 
(without IP_ONESBCAST).
I have a datagram with ip_dst = 172.21.81.255 and broadcast 
destination ethernet address.

8. With default gateway, ip_dst = 172.21.81.255, SO_BROADCAST and 
IP_ONESBCAST was set.
I have a datagram with ip_dst = 255.255.255.255 and broadcast 
destination ethernet address.

So, i think tests #4, #5 and #6 is incorrect, but maybe this is by design?
-- 
WBR, Andrey V. Elsukov
Comment 11 Andre Oppermann freebsd_committer freebsd_triage 2006-09-04 10:45:59 UTC
Andrey V. Elsukov wrote:
> Andre Oppermann wrote:
>> OK, correct URL here:
>>
>> http://people.freebsd.org/~andre/sendonesfix-20060830.diff
>> http://people.freebsd.org/~andre/sendonestest-20060830.c
>>
>>> The IP_ONESBCAST socket option is dependent on the SO_BROADCAST socket
>>> option which allows the sending of broadcast messages in general.  Jails
>>> for example do not have this permission and will fail there.
> 
> Ok, i've tried your patches with fresh RELENG_6 kernel sources.
> 
> 1. Without default gateway, ip_dst = 172.21.81.255 (broadcast for my 
> subnet), SO_BROADCAST and IP_ONESBCAST was set.
> This works as described in ip(4) - I have a datagram with dst_ip 
> 255.255.255.255 and broadcast MAC address.
> 
> 2. Without default gateway, ip_dst = 172.21.81.255, SO_BROADCAST was set 
> (without IP_ONESBCAST).
> I have a datagram with dst_ip 172.21.81.255 and broadcast MAC address.
> 
> 3. Without default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST was 
> set (without IP_ONESBCAST).
> sendto(): Network is unreachable
> 
> 4. Without default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST and 
> IP_ONESBCAST was set.
> sendto(): Network is unreachable
> 
> 5. With default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST and 
> IP_ONESBCAST was set.
> sendto(): Network is unreachable
> 
> 6. With default gateway, ip_dst = INADDR_BROADCAST, SO_BROADCAST was set 
> (without IP_ONESBCAST).
> I have a datagram with ip_dst = 255.255.255.255 and gateway's MAC as 
> destination ethernet address.
> 
> 7. With default gateway, ip_dst = 172.21.81.255, SO_BROADCAST was set 
> (without IP_ONESBCAST).
> I have a datagram with ip_dst = 172.21.81.255 and broadcast destination 
> ethernet address.
> 
> 8. With default gateway, ip_dst = 172.21.81.255, SO_BROADCAST and 
> IP_ONESBCAST was set.
> I have a datagram with ip_dst = 255.255.255.255 and broadcast 
> destination ethernet address.
> 
> So, i think tests #4, #5 and #6 is incorrect, but maybe this is by design?

There may be a couple of bugs in the broadcast code and I have to look
at the standards to find out what the expected behavior should is.  #4 and #5
is correct however.  When specifying IP_ONESBCAST you must supply a valid
subnet broadcast address and INADDR_BROADCAST is not one of them.  #3 and #6
are certainly not correct and I will look into fixing them as well.

The important message here is that the fix IP_ONESBCAST works as intended.
So I'm going to commit it to -current with a MFC date in a few days.

-- 
Andre
Comment 12 Andre Oppermann freebsd_committer freebsd_triage 2006-09-06 18:13:48 UTC
State Changed
From-To: feedback->patched

The patch has been committed to -current today.  MFC after 3 days to 6-stable. 


Comment 13 Andre Oppermann freebsd_committer freebsd_triage 2006-09-06 18:13:48 UTC
Responsible Changed
From-To: bms->andre

Take over.
Comment 14 dfilter service freebsd_committer freebsd_triage 2006-10-06 21:26:16 UTC
andre       2006-10-06 20:26:06 UTC

  FreeBSD src repository

  Modified files:        (Branch: RELENG_6)
    sys/net              if.c if_var.h 
    sys/netinet          ip_output.c raw_ip.c udp_usrreq.c 
  Log:
  MFC:
   - Fix the socket option IP_ONESBCAST by giving it its own case in ip_output()
     and skip over the normal IP processing.
   - Add a supporting function ifa_ifwithbroadaddr() to verify and validate the
     supplied subnet broadcast address.
   - Check inp_flags instead of inp_vflag for INP_ONESBCAST flag.
  
  PR:             kern/99558
  Approved by:    re (kensmith)
  
  Revision    Changes    Path
  1.234.2.17  +27 -0     src/sys/net/if.c
  1.98.2.6    +1 -0      src/sys/net/if_var.h
  1.242.2.15  +11 -2     src/sys/netinet/ip_output.c
  1.150.2.5   +1 -1      src/sys/netinet/raw_ip.c
  1.175.2.8   +2 -2      src/sys/netinet/udp_usrreq.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"
Comment 15 Ryan Beasley freebsd_committer freebsd_triage 2007-01-05 21:10:33 UTC
Hi, Andre.

Sorry to bug you, but there appears to be a small problem with this
patch to ip_output.c (RELENG_6 1.242.2.15).

In the previous version, the IP_SENDONES flag is tested only if
ifbroadcast is set.  In the new version, if IP_SENDONES is set, the
destination is unconditionally set to INADDR_BROADCAST.  As a result, it
appears that -all- unicast packets sent on a IP_SENDONES socket are
affected and result in ENETUNREACH.

Attached to this message is a small change I made which appears to fix
this.  Could you please review it?

Thanks!

-- 
Ryan Beasley <ryanb@FreeBSD.org>
Comment 16 Ryan Beasley freebsd_committer freebsd_triage 2007-01-05 21:24:39 UTC
Ryan Beasley wrote:
> In the previous version, the IP_SENDONES flag is tested only if
> ifbroadcast is set.  In the new version, if IP_SENDONES is set, the
> destination is unconditionally set to INADDR_BROADCAST.  As a result, it
> appears that -all- unicast packets sent on a IP_SENDONES socket are
> affected and result in ENETUNREACH.

Er, please excuse me.  :)  I mean to say that if IP_ONESBCAST /
IP_SENDONES is set, then all packets follow the same branch, where
non-broadcasts end up discarded w/ ENETUNREACH.  (When I first wrote
that paragraph a few hours ago, before I attempted a patch, I
misunderstood the block which tests the destination address for
broadcasting.)

-- 
Ryan Beasley <ryanb@FreeBSD.org>
Comment 17 Bruce M Simpson freebsd_committer freebsd_triage 2007-03-05 10:03:06 UTC
Responsible Changed
From-To: andre->bms

andre@ fixed the original bug (thanks!) but ryan@ raises the issue 
that IP_ONESBCAST can't just be left set on a socket w/o affecting 
normal traffic. 
It was never intended to be used in this way, and the best way to 
deal with this is probably to update the documentation in ip(4). 
In future we'd hope to get rid of IP_ONESBCAST when we have an opportunity 
to refactor the FIB.
Comment 18 Bruce M Simpson freebsd_committer freebsd_triage 2007-03-18 02:07:26 UTC
State Changed
From-To: patched->closed

The fix was MFCed, however I have pending work related to this in p4.
Comment 19 commit-hook freebsd_committer freebsd_triage 2025-02-22 02:13:05 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=3b281d1421a78b588c5fc4182009ce62d8823d95

commit 3b281d1421a78b588c5fc4182009ce62d8823d95
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-02-22 02:11:00 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-02-22 02:11:00 +0000

    netinet: enforce broadcast mode for all-ones and all-zeroes destinations

    When a socket has SO_BROADCAST set and destination address is INADDR_ANY
    or INADDR_BROADCAST, the kernel shall pick up first broadcast capable
    interface and broadcast the packet out of it.  Since this API is not
    reliable on a machine with > 1 broadcast capable interfaces, all practical
    software seems to use IP_ONESBCAST or other mechanisms to send broadcasts.
    This has been broken at least since FreeBSD 6.0, see bug 99558.  Back then
    the problem was in the fact that in_broadcast() check was always done
    against the gateway address, not the destination address.  Later, with
    90cc51a1ab4be, a second problem piled on top - we aren't checking for
    INADDR_ANY and INADDR_BROADCAST at all.

    Better late than never, fix that by checking destination address.

    PR:                     99558
    Reviewed by:            markj
    Differential Revision:  https://reviews.freebsd.org/D49042

 sys/netinet/in.h        |  7 +++++++
 sys/netinet/ip_output.c | 15 ++++++++++-----
 2 files changed, 17 insertions(+), 5 deletions(-)