Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spawn one ThreadingUDPServer per Interface #23

Closed
wants to merge 3 commits into from

Conversation

mweinelt
Copy link
Contributor

Spawn one ThreadingUDPServer per Interface and bind them to their device scope.

Looks like this:

root     18782  0.4  1.2 553888 12788 ?        Ssl  00:06   0:13 python3 /opt/mesh-announce/respondd.py -i ffda-br -i ffda-tp -i ffda-vpn-1280 -i ffda-vpn-1312 -b ffda-bat
root     20172  0.0  1.0 256244 11044 ?        Ssl  00:44   0:00 python3 /opt/mesh-announce/respondd.py -i ffdef-br -i ffdef-tp -i ffdef-vpn-1312 -b ffdef-bat
udp    UNCONN     0      0      ff02::2:1001%ffdef-vpn-1312:1001                 :::*      users:(("python3",pid=20172,fd=5))
udp    UNCONN     0      0      ff02::2:1001%ffdef-tp:1001                 :::*      users:(("python3",pid=20172,fd=4))
udp    UNCONN     0      0      ff02::2:1001%ffdef-br:1001                 :::*      users:(("python3",pid=20172,fd=3))
udp    UNCONN     0      0      ff02::2:1001%ffda-vpn-1312:1001                 :::*      users:(("python3",pid=18782,fd=6))
udp    UNCONN     0      0      ff02::2:1001%ffda-vpn-1280:1001                 :::*      users:(("python3",pid=18782,fd=5))
udp    UNCONN     0      0      ff02::2:1001%ffda-tp:1001                 :::*      users:(("python3",pid=18782,fd=4))
udp    UNCONN     0      0      ff02::2:1001%ffda-br:1001                 :::*      users:(("python3",pid=18782,fd=3))

@jplitza
Copy link
Member

jplitza commented Oct 21, 2017

Why do you only listen to the multicast address? That breaks unicast requests, doesn't it? Or is it impossible to bind to a device if you don't specify an address?

@mweinelt
Copy link
Contributor Author

mweinelt commented Oct 21, 2017

When I bound the sockets to "" I was running into the "Address already in use" error.

It's certainly possible to detect the link local address on the interface and spawn yet another socketserver for that. Would link-local be sufficient, or is ULA/Global required?

@mweinelt
Copy link
Contributor Author

# ss -lpn | grep 1001 | column -t
udp  UNCONN  0  0  fe80::d8ff:61ff:fe01:103%ffda-vpn-1312:1001   :::*  users:(("python3",pid=29446,fd=10))
udp  UNCONN  0  0  ff02::2:1001%ffda-vpn-1312:1001               :::*  users:(("python3",pid=29446,fd=9))
udp  UNCONN  0  0  fe80::d8ff:61ff:fe00:103%ffda-vpn-1280:1001   :::*  users:(("python3",pid=29446,fd=8))
udp  UNCONN  0  0  ff02::2:1001%ffda-vpn-1280:1001               :::*  users:(("python3",pid=29446,fd=7))
udp  UNCONN  0  0  fe80::d8ff:61ff:fe00:105%ffda-tp:1001         :::*  users:(("python3",pid=29446,fd=6))
udp  UNCONN  0  0  ff02::2:1001%ffda-tp:1001                     :::*  users:(("python3",pid=29446,fd=5))
udp  UNCONN  0  0  fe80::d8ff:61ff:fe00:104%ffda-br:1001         :::*  users:(("python3",pid=29446,fd=4))
udp  UNCONN  0  0  ff02::2:1001%ffda-br:1001                     :::*  users:(("python3",pid=29446,fd=3))
udp  UNCONN  0  0  fe80::d8ff:60ff:fe00:103%ffdef-vpn-1312:1001  :::*  users:(("python3",pid=29420,fd=8))
udp  UNCONN  0  0  ff02::2:1001%ffdef-vpn-1312:1001              :::*  users:(("python3",pid=29420,fd=7))
udp  UNCONN  0  0  fe80::d8ff:60ff:fe00:105%ffdef-tp:1001        :::*  users:(("python3",pid=29420,fd=6))
udp  UNCONN  0  0  ff02::2:1001%ffdef-tp:1001                    :::*  users:(("python3",pid=29420,fd=5))
udp  UNCONN  0  0  fe80::d8ff:60ff:fe00:104%ffdef-br:1001        :::*  users:(("python3",pid=29420,fd=4))
udp  UNCONN  0  0  ff02::2:1001%ffdef-br:1001                    :::*  users:(("python3",pid=29420,fd=3))

@mweinelt
Copy link
Contributor Author

The changes should be sufficient to address the issue. Do you have more feedback?

@jplitza
Copy link
Member

jplitza commented Oct 25, 2017

I'm not entirely happy with having to bind to every single address, and don't know if there are use cases of querying a non-link-local address, but I'd be fine with merging.

@mweinelt
Copy link
Contributor Author

Listening on link-local only is supposed to be a protection against attacks from outside the mesh.
via freifunk-gluon/packages#142

With the BSD Socket API there is little choice between binding anything or just a single address, so I'm not sure where else this would go.

@neocturne
Copy link

Shouldn't a single socket bound to any be sufficient? Just join all the interfaces' multicast groups after binding. Filtering for link-local addresses can be done after receiving a packet just fine if desired (it's what Gluon's respondd does).

@jplitza
Copy link
Member

jplitza commented Oct 31, 2017

@NeoRaider That's what we do now, but that way, you cannot serve different data on different interfaces.

@mweinelt
Copy link
Contributor Author

@jplitza We talked about this on IRC and it might be possible to bind to device with any, join the multicast group and filter in the process for link-local sources.

Honestly, I don't like that approach much, binding should be preferred to filtering, even if it uses twice the amount of sockets. What's the cost here?

Another issue is, that the bind to e.g. the vpn interface breaks as soon as fastd is restarted. uradvd solves this by monitoring the netlink events and (I guess) rebinding.

@rubo77
Copy link
Contributor

rubo77 commented Nov 30, 2017

Is this doing any harm, if you only use one interface in your domain?

It seems like the version on https://github.com/freifunk-darmstadt/mesh-announce works fine so far.

Can this be merged?

@mweinelt
Copy link
Contributor Author

mweinelt commented Nov 30, 2017

Known Issue:
If an interface which mesh-announce was bound to vanishes and reappears mesh-announce would need to rebind the socket or else it wouldn't listen on that interface anymore.

@mweinelt
Copy link
Contributor Author

mweinelt commented Dec 5, 2017

With the latest patch mesh-announce will check every 15 seconds all configured interfaces for changed interface ids, which would indicate that the interface vanished and reappeared.

In such a case mesh-announce will now stop the threads listening on the vanished interface and create new threads when the interface reappears.

Copy link
Member

@jplitza jplitza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally got around to have a look at this PR. Thanks for the work, @mweinelt! I had a few minor comments.

In general, maybe we also want to rebind if new addresses appear? That's unlikely, but hey…

)
threading.Thread(target=ucast_server.serve_forever).start()

return socket.if_nametoindex(iface), [mcast_server, ucast_server]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are multiple link-local addresses on the interface, you only return the thread corresponding to the last address.

.format(iface))
if_threads[iface] = listen(
iface, args.group, args.port, args.directory, env)
except OSError as ex:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This except covers quite a lot of code (all of listen()) when really we are only interested in whether socket.if_nametoindex(iface) has succeeded. Using something like new_ifidx = socket.if_nametoindex(iface), you could also save the duplicate code for shutting down the threads.

)

group_bin = socket.inet_pton(socket.AF_INET6, group)
mreq = group_bin + struct.pack('@I', socket.if_nametoindex(iface))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you start respondd with an interface that doesn't (yet) exist, this call to socket.if_nametoindex will raise an uncaught exception. But as we (re)bind to (specified) interfaces appearing later on, this could just as well be caught and return an empty thread list.

@mweinelt
Copy link
Contributor Author

Before we continue with this we should discuss, whether one instance should serve multiple domains (#28) or if one instance should be started per domain.

@rubo77 rubo77 force-pushed the master branch 2 times, most recently from fc25806 to 4440264 Compare July 27, 2018 11:30
@rubo77
Copy link
Contributor

rubo77 commented Oct 13, 2018

Is this the solution you realized in https://github.com/freifunk-darmstadt/mesh-announce ?

could this be rebased then?

@mweinelt
Copy link
Contributor Author

This is that solution, but it breaks with site-local scoped multicast groups, which are required since freifunk-gluon/gluon@59a4427.

@mweinelt mweinelt closed this Apr 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants