-
-
Notifications
You must be signed in to change notification settings - Fork 36
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
Run mDNS over IPv6, too #69
base: master
Are you sure you want to change the base?
Conversation
A (conditional) `continue` right at the end of a while loop does nothing. While the compiler probably optimizes this away, it should also be removed in the sources to make the code cleaner and easier to read.
mDNS messages can be sent over IPv4 or IPv6. `mdnsd_in` is able to store the source address for both address families, and `mdnsd_out` can fill in the destination `sockaddr` also for both address families. When calling `mdnsd_out`, the caller must fill in the address family in the `to` parameter struct so that the correct data can be chosen and be filled in to the `to` struct. This change makes no assumption whether messages of both or only one of the two address families are processed in the same mdnsd instance. While it probably make sense to separate the IPv4 and IPv6 domains and serve them with separate mdnsd instances, this patch allows for messages on both to be handled by one. This patch does not concern itself with the question how to properly handle Disco, probing and announcement, when only one mdnsd instance serves both domains.
The functions `mdnsd_in` and `mdnsd_out` now take a `struct sockaddr_storage` as argument in order to handle IPv4 and IPv6. This patch only adjusts the `mquery` code to this change.
While the library logs an INFO message when probes etc. are sent, it does not report on normal query messages being built. This patch adds an INFO output when a normal question is asked.
Refactor the code for creating the multicast socket to be able to create a socket for IPv4 and a socket for IPv6. The `mdns_socket` function is replaced by `mdns_ipv4_socket` and `mdns_ipv6_socket` functions.
Now for the real reason why this PR is in draft state. Implementation is not yet finished because I stumbled over a problem when creating IPv6 multicast sockets that I'd like to discuss. The When specifying When specifying When specifying no interface, i.e. not binding to any interface, the program receives unicast IPv4 packets send to When properly bound to When specifying I am at a loss as to why that is and what makes the behaviour differ in such a weird way between IPv4 and IPv6. Maybe I am missing something obvious to someone else. Mapping run mode against packet coming in on interface
|
Turns out there are two different mechanisms at play causing the result above. The first explains the "IPv6 unicast" column. I had tested this with avahi-daemon running at the same time. Which means that another process was bound to the 5353 port and ANY address, with The other issue is due to a misconception I had and how Linux behaves differently for IPv4 and IPv6 multicast packets in that case, and explains the "IPv4 multicast" column. I refactored the code for the socket out into a separate file. The code allows for no interface to be selected and will then use the "default" value for the interface when joining the multicast group. That is, it is up to the kernel to decide on which interface to join the multicast group. The kernel will use the one with the smaller index (in my case I kind of was working with the idea that when not specifying an interface, all mDNS multicast packets should be received. (Which is true for the unicast ones.) But I see how this would be a problem with sending a packet because the outgoing interface would have to be selected somehow. This is currently not really a problem, because for |
Huh, what a ride! I did not know about that behavior when running as different UIDs ... The selection of interface sounds a bit weird though. Don't think the kernel actually goes by smaller ifindex, are you sure it didn't go by the routing table? It's IP networking after all. I mentioned SMCRoute and pim6sd before, but maybe my little mcjoin program is a better match for this particular case. Have a look at receiver.c and sender.c in https://github.com/troglobit/mcjoin/tree/master/src I believe you may find useful IPv6 and IPv4 tips here (doesn't run as root) |
Oh this is purely based on my observation. I did not go into the kernel code to check for the actual decision behaviour. The manual pages for the socket options are not really helpful here. |
Ah then I understand, makes more sense. Sorry for missing PR #70, merged now. |
Any progress on this, @fzs? |
No, unfortunately this had to take a backseat behind other issues for a while. But it is not forgotten. |
OK, great to hear! No worries, just contemplating if I should do a release with what we have right now and postpone this for the next release after that ... any input from you on this would be great. |
In the spirit of "release early, release often" I think a release with what is implemented now is fine. I would not hold back any release waiting for this PR to be finished. For one, because right now I cannot say with any certainty when I will be able to finish this. And also, I tried to split all changes into independent PRs so that a release would be possible at any time. |
Awesome, thank you for the reply! I'll start preparing for the release then 😃 |
This PR should be the final step towards adding support for IPv6. (#10)
Two specific changes should be reviewed with respect to whether they are acceptable this way.
First, I decided to use
sockaddr_storage
in the function signatures ofmdnsd_in
andmdnsd_out
, instead of the generalsockaddr
. This is to make sure that a structure of the correct size is passed, without having to resort to the usual additionalsocklen_t addrlen
parameter to check against. The drawback is that it (kind of) requires the calling code to use astruct sockaddr_storage
which is larger than what the calling code may actually need. (The calling code could still decide to use a smallersockaddr_in
and cast tosockaddr_storage
, but that looks, well, ew.)Second, in
process_out
no additional IP version information is passed in, only the socket descriptor. The function employs thegetsockname
system call to find out if the socket is IPv4 or IPv6. I don't know if this could cause problems with portability, i..e. how well spread that system call is. It is part of POSIX.1-2001. As isgetnameinfo
, but that is only used inmdnsd
, not in the library.This PR is depending on #70 getting merged first.