Problem receiving UDP broadcast packets.

G

Grant Edwards

It just occurred to me: You might get some additional mileage out of
popping the network adapter into promiscuous mode. In fact, it Might
be necessary irrespective of the rest of your approach.

The network adapter is already receiving all the packets I want to
receive, so putting it into promiscuous mode would only increase the
number of unwanted packets.
 
G

Grant Edwards

Have you considered what will happen if you have, say, 1000 such
devices, and they all respond at the same time?

Yes. Firstly, there will very rarely be more than a handful of such
devices. Secondly, I plan on inserting a small, psuedo-random delay
before replying. Thirdly, the management program typically repeats
the discovery process a few times in case any packets get dropped.
 
G

Grant Edwards

Am 20.04.2011 01:54, schrieb Grant Edwards:

Just to pitch in here (because nobody's mentioned it yet AFAICT): yes,
there's a filtering done (at least under Linux, and I'd guess something
similar on xBSD too) to packets based on the source address coming in on
an interface, and it's called the reverse path filter and is on by
default (the tunable on Linux is /proc/sys/net/ipv4/conf/*/rp_filter).

Brilliant! While I had determined that such filtering took place, I'd
been unable to figure out if it was configurable.
The idea behind the reverse path filter is that your machine won't
accept packets coming in over an interface when a return packet (i.e.,
the presumed response) won't be routed over the same interface, and from
what I gather, this is what makes the TCP/IP stack drop the packets
because your machine will not route packets to 192.168.x.x over the same
interface it sees the packet coming in. This is a _security_ feature,
because it makes address spoofing harder.

And it's an eminently sensible feature.
If you need to see the packets regardless, either use a promiscuous mode
sniffer (i.e., tcpdump, but that's relatively easy to mirror in Python
using SOCK_RAW, capturing packets at the ethernet level), or add a route
on your system for the 192.168.x.x network on the same interface.

I've thought about the SOCK_RAW option, but the CPU load of looking
all received Ethernet packets in user-space would be a big down-side.

Adding the route isn't an option since 1) the device doesn't know what
route to add, and 2) adding such a route could break the normal
networking operation.
 
G

Grant Edwards

- Actually, you Might be able to configure your device to have a
netmask of 0.0.0.0, IP address of 255.255.255.255 and broadcast of
255.255.255.255.
- I've seen something a bit similar used for detecting IP address
conflicts automatically.
- A network guru I used to work with told me that you could configure
a machine with a broadcast of 255.255.255.255 more simply than messing
around with the netmask, while still achieving the same result for
general purpose networking.

I'll look into that.
With a netmask of 0.0.0.0, I suspect you will receive all broadcasts
on the wire, given appropriate listening code.

That might be an option as well, as long as it doesn't disrupt normal
operation of the interface.
 
G

Grant Edwards

Am 20.04.2011 00:21, schrieb Grant Edwards:
I'm have problems figuring out how to receive UDP broadcast packets on
Linux. [...]

On the receiving machine, I've used tcpdump to verify that broadcast
packets are being seen and have a destination IP of 255.255.255.255 and
destination MAC of ff:ff:ff:ff:ff:ff [...]
But, the receiving Python program never sees any packets unless the
_source_ IP address in the packets is on the same subnet as the
receiving machine. In this test case, the receiving machine has an IP
address of 172.16.12.34/16. If I change the receiving machine's IP
address to 10.0.0.123, then the receiving program sees the packets.

Even though the destination address is 255.255.255.255, the receiving
machine appears to discard the packets based on the _source_ IP. Can
anybody provide example Python code for Linux that receives UDP
broadcast packets regardless of their source IP address?

This probably is more of a Linux networking question than a Python
question, but I'm hoping somebody has solved this problem in Python.

You must set the network interface to promiscous mode on the
receiving side:

os.system("ifconfig eth0 promisc")

Why?

The network interface is already receiving the packets I want, since
they're beign sent with a destination MAC of ff:ff:ff:ff:ff:ff.
 
H

Heiko Wundram

Am 20.04.2011 16:30, schrieb Grant Edwards:
I've thought about the SOCK_RAW option, but the CPU load of looking
all received Ethernet packets in user-space would be a big down-side.

Not necessarily: instead of using UDP datagrams to send the data, use
ethernet datagrams (without any IP/UDP header) with your own
ethernet-type (there is a range of "local" types that you can use for
your own local use-case), and then simply create a RAW socket that only
listens on packets that have the specified ethernet types. We use
something similar at work for a high-availability application.

The server-side looks something like:

"""
PKT_TYPE = 0x1234 # My very own ethertype.

sock = socket(AF_PACKET,SOCK_DGRAM,htons(PKT_TYPE))
sock.bind(("ethxyz",PKT_TYPE))

while True:
data, (_, _, _, _, addr) = sock.recvfrom(1500)
print "I got:", repr(data), "from etheraddr:", addr
"""

The client-side looks similar.

Because you're using UDP broacast, you have unreliable transport anyway,
and if the client-side supports sending ethernet datagrams (with a
broadcast address), I'd rather advise to use that for your use case.
This makes you independent of IP configuration (and as I can see, you're
actually not interested in the "routing" that IP gives you, but rather
interested in contacting all nodes on a local ethernet; why not use
ethernet directly?).
 
G

Grant Edwards

Am 20.04.2011 16:30, schrieb Grant Edwards:

Not necessarily: instead of using UDP datagrams to send the data,

There's the rub. The requirement is to use UDP.
use ethernet datagrams (without any IP/UDP header) with your own
ethernet-type (there is a range of "local" types that you can use for
your own local use-case), and then simply create a RAW socket that
only listens on packets that have the specified ethernet types. We
use something similar at work for a high-availability application.

Same here. What I'm working on is a replacement for just such a
protocol. The problem is that this whole scheme has to work easily
with the management program running on Windows. While doing a custom
Ethernet protocol on Linux is dead-simple (it does require either
UID==0 or CAP_NET_RAW), doing it on Windows is painful in the extreme.

Thus the requirement to use something that works using "normal UDP" on
the manager end of things (even if it requires jumping through some
hoops on the device end).

[Insert standard whinge about how once again, Microsoft royally
botches something and we non-Windows people have to suffer.]
 
G

Grant Edwards

Same here. What I'm working on is a replacement for just such a
protocol.

Now that I think of it, I added raw socket support to Python just so I
could implement that protocol in Python!

[A rather vain attempt to inject some Python content back into the
thread.]
 
G

Grant Edwards

On LINUX this is called "avahi", which has Python bindings. Avahi
auto-configuration / discovery works very well.

<http://avahi.org/>
<http://freshmeat.net/projects/avahi>
<http://pypi.python.org/pypi/pybonjour/1.1.1>
<http://avahi.org/wiki/PythonBrowseExample>

See also:
<http://pypi.python.org/pypi/pybonjour/1.1.1>
at least you may be able to lift code from them (License is non-viral
MIT)

I've looked at those protocols and they aren't particularly suited to
what we want to do. One of our requirements is to be able to discover
a device with a static IP address (or no IP address?) that isn't on
the same subnet -- and I don't see how those protocols can do that.

Since the management program already has to implement the UDP based
protocol I'm working on, it would be a big win if I didn't have to
make the management program add support for a second protocol.
 
G

Grant Edwards

- Actually, you Might be able to configure your device to have a
netmask of 0.0.0.0, IP address of 255.255.255.255 and broadcast of
255.255.255.255.

255.255.255.255 isn't allowed as an IP address.

I tried a netmask of 0.0.0.0, and it didn't make any differnce.
 
G

Grant Edwards

Brilliant! While I had determined that such filtering took place, I'd
been unable to figure out if it was configurable.

Bingo!

Turning off reverse-path filtering solved my original problem (not
receiving broadcasts sent to 255.255.255.255 because the source IP
wasn't reachable via the receiving interface).

It doesn't help with the "new" requirement of receiving subnet
broadcasts that don't match the interface on which they're received,
since it's destination IP filtering that's dropping those.

Apparently that requirement is due to the fact that on some OSes (some
flavors of BSD and Windows) applications can't broadcast to
255.255.255.255, they can only do subnet broadcasts.
 
G

Grant Edwards

I'm have problems figuring out how to receive UDP broadcast packets on
Linux.

Thanks to everybody for their help with what turned out to have little
or nothing to do with Python itself.

The main problem was reverse-path filtering (which is enabled by
default on Linux). Disabling it allowed me to receive packets sent to
255.255.255.255 regardless of the sender's IP address.

Another minor issue that cropped up was that I ended up having to use
two sockets: an Rx socket bound to ('',port) and a Tx socket bound to
(myip,port).

Even though the protocol spec said that subnet broadcasts were used,
tracing a few transactions between existing implementations showed
that only global broadcasts were used. More testing showed that
existing implementations won't respond to subnet broadcasts unless
they're already configured to be on the proper subnet. So, receiving
subnet broadcasts that don't match an interface turned out to be a
wild goose chase.

It's all working now...
 
D

Dan Stromberg

The network adapter is already receiving all the packets I want to
receive, so putting it into promiscuous mode would only increase the
number of unwanted packets.

I think tcpdump and tshark (was tethereal) will put the interface into
promiscuous mode so it can see more traffic; on OSF/1 (Tru64), we had
to do this manually for said programs to see all that was possible
(barring the presence of a switch not repeating packets the way
routers and hubs would).
 
H

Heiko Wundram

Am 21.04.2011 03:35, schrieb Dan Stromberg:
I think tcpdump and tshark (was tethereal) will put the interface into
promiscuous mode so it can see more traffic; on OSF/1 (Tru64), we had
to do this manually for said programs to see all that was possible
(barring the presence of a switch not repeating packets the way
routers and hubs would).

It actually depends on the network adapter/card that's in use: many
modern cards (especially those in the lower price segment, i.e. Realtek)
don't (properly) implement "MAC"-filtering at the hardware level, and in
this case, there's no difference for the operating system between
promiscuous mode and non-promiscuous mode (because the card will forward
all packets that it sees coming in over the ethernet bus to the
operating system, which will then discard those at the ethernet level it
doesn't deem necessary to process at a higher level, for example because
the destination MAC is unicast, but not the cards own, so the
destination wasn't the system itself).

For pricier cards/chips, this filtering (which also includes restricting
the multicast-destinations that are forwarded to the operating system,
think IPv6-multicast which uses quite a range of multicast MAC addresses
for its neighbour discovery) is implemented at the hardware level, and
the ethernet adapter throws away uninteresting packets and doesn't
signal the operating system (think of the cost of interrupts you save;
on high throughput links, this makes perfect sense). Putting the card
into promiscuous mode basically disables this filtering, so that the
card will again forward all packets to the operating system.

This is why tcpdump for example puts the network adapter into
promiscuous mode, but normally (see above, depending on the network
adapter), that's not required because the operating system "sees all"
ethernet packets anyway.
 
G

Grant Edwards

I think tcpdump and tshark (was tethereal) will put the interface into
promiscuous mode so it can see more traffic;

It can (and by default does). I was using "-p" so it didn't.
on OSF/1 (Tru64), we had
to do this manually for said programs to see all that was possible
(barring the presence of a switch not repeating packets the way
routers and hubs would).

* The packets were being sent to MAC address ff:ff:ff:ff:ff:ff, so the
NIC does not have to be in promiscuous mode to receive them.

* tcpdump saw them even when it doesn't put the NIC in promiscuous
mode.

* The kernel was seeing the packets because it was logging them as
martians and discarding them (something I didn't notice until later).

* Turning off reverse-path filtering in the TCP stack allowed the
packets to be received as expected.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top