1

I am using the Elixir/ Erlang package on raspbian to try and build a simple UDP send/receive app. For information, I am using this tutorial.

When I try to send the UDP packet to the network on the broadcast IP address given to my eth0 interface, I am getting a "Permission denied" message.

Is it really not allowed to broadcast UDP messages to the network from linux? And if so, how to give permission to a specific package to broadcast messages? I have tested it with localhost IP address 127.0.0.1 and I am getting no error.

AdminBee
  • 21,637
  • 21
  • 47
  • 71
TAs
  • 13
  • 2

1 Answers1

0

To send a broadcast using the BSD sockets API, you have to declare your destination is a broadcast address. This is done with the systemcall setsockopt(2).

Here's an example, voluntarily not using erlang because:

  • I don't know erlang
  • The issue is not related to erlang but to the BSD sockets API.

I'll illustrate with the IPv4 loopback addresses. localhost isn't merely 127.0.0.1 but currently 127.0.0.1/8 so part of the 127.0.0.0/8 net block. That means (at least on Linux currently) this does support the broadcast semantic as can be seen with:

$ ip route get 127.255.255.255
broadcast 127.255.255.255 dev lo table local src 127.0.0.1 uid 1000 
    cache <local,brd> 

So reproducing with the handy socat command that is a good tool to debug communication with applications:

$ echo test | socat udp4-datagram:127.255.255.255:5555 -
2021/07/04 08:40:06 socat[327412] E sendto(5, 0x55976a7a1000, 5, 0, AF=2 127.255.255.255:5555, 16): Permission denied

This requires to declare the destination is a broadcast:

$ echo test | socat udp4-datagram:127.255.255.255:5555,broadcast -
$ echo $?
0

$ echo test | strace -e trace=socket,setsockopt,sendto -- socat udp4-datagram:127.255.255.255:5555,broadcast -
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) = 5
setsockopt(5, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
sendto(5, "test\n", 5, 0, {sa_family=AF_INET, sin_port=htons(5555), sin_addr=inet_addr("127.255.255.255")}, 16) = 5
+++ exited with 0 +++

erlang has setsockopt(2) references in its inet module documentation reference: socket_setopt().

socket_setopt() =
    gen_sctp:option() | gen_tcp:option() | gen_udp:option()
setopts(Socket, Options) -> ok | {error, posix()}
  
Types
Socket = socket()
Options = [socket_setopt()]

Sets one or more options for a socket.

{broadcast, Boolean} (UDP sockets)

Enables/disables permission to send broadcasts.

You'll have to figure out how to add this to your erlang code.

A.B
  • 31,762
  • 2
  • 62
  • 101
  • The example I chose doesn't tell why this is needed, but I don't have a definitive answer about this. It's certainly related to the fact that the layer 3 (IP) broadcast address will be translated as a layer 2 (Ethernet) broadcast address instead of triggering an address resolution protocol (ARP), but the address definition on the interface has already this information. Of course on layer 3 interfaces such as the loopback interface, this doesn't even happen. – A.B Jul 04 '21 at 09:09
  • 1
    Thank you for your help. Spot on. I had to enable broadcast when calling the `:gen_udp() method`. The complete command is `{:ok, socket} = :gen_udp.open(8680, [:binary, {:active, false}, broadcast: true])` – TAs Jul 10 '21 at 13:24