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

IPv6 MDNS #35

Closed
wants to merge 13 commits into from
Closed

IPv6 MDNS #35

wants to merge 13 commits into from

Conversation

twinshadow
Copy link

@twinshadow twinshadow commented Nov 8, 2019

This PR is split into 3 commits, but they may not be entirely distinct. It basically goes like this:

  1. Add support for interfaces to store multiple IP addresses.
  2. Add support for using multiple addresses in service and control functions.
  3. Add support for sending and receiving IPv6 packets.

I've kept my FreeBSD patch in here as well, since I tested this with FreeBSD-current as well as OpenBSD-current.

Samples

Lookup of IPv6 addresses from mdnsctl

$ mdnsctl lookup Android.local
Address: 192.168.86.164
$ mdnsctl lookup -6 Android.local
Address: fe80::aa6b:adff:fe16:13e7

mdnsd advertisiment appearing on mdns-sd from another system. tutti.local is running mdnsd with these patches.

dns-sd -G v4v6 tutti.local
DATE: ---Thu 07 Nov 2019---
20:57:57.205  ...STARTING...
Timestamp     A/R Flags if Hostname                               Address                                      TTL
20:57:57.207  Add     3  1 tutti.local.                           FDCC:F80E:8097:0000:0000:0000:0000:0001%<0>  120
20:57:57.208  Add     2  1 tutti.local.                           192.168.32.5                                 120

Issues

  • The daemon only responds with the first address on an interface. I might be missing something obvious, but it looks like there would have to be substantial changes needed to handle packet fragmenting in pkt_handle_qst to respond with multiple A and/or AAAA records.

Fixes #4

Cheers!

- Multiple addresses per interface (no effect)
- Get address changes from route socket
- remove all kif_* functions
- use getifaddrs to get all addresses for an interface
- Define udp4/udp6 structures for MDNS FD and events
mdnsd/kiface.c Outdated
Comment on lines 57 to 59
#ifdef __FreeBSD__
#define rtm_hdrlen rtm_msglen
#endif
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect this is wrong -- on OpenBSD rtm_hdrlen is documented as being

	u_short	rtm_hdrlen;	/* sizeof(rt_msghdr) to skip over the header */

while rtm_msglen on both FreeBSD and OpenBSD is documented as being

	u_short	rtm_msglen;	/* to skip over non-understood messages */

so at kiface.c:150

                sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
                get_rtaddrs(rtm->rtm_addrs, sa, rti_info);

you'll be skipping the whole message rather than just the header of the message.

@twinshadow
Copy link
Author

twinshadow commented Dec 1, 2019 via email

@nbriggs
Copy link
Contributor

nbriggs commented Dec 1, 2019

sizeof(*rtm) rather than sizeof(&rtm) if you're not going to use sizeof(struct rt_msghdr)

But even with that correction, it still takes a segmentation fault (on FreeBSD) if you add or delete an address on the interface that mdnsd is monitoring.

@nbriggs
Copy link
Contributor

nbriggs commented Dec 1, 2019

The documentation for FreeBSD route(4) says

The RTM_IFINFO message uses a if_msghdr header, the RTM_NEWADDR and
RTM_DELADDR messages use a ifa_msghdr header, the RTM_NEWMADDR and
RTM_DELMADDR messages use a ifma_msghdr header, the RTM_IFANNOUNCE
message uses a if_announcemsghdr header, and all other messages use the
rt_msghdr header.

So while you can walk the messages by the rtm_msglen you have to get the type of message to know what the header length is -- a problem you don't have in OpenBSD because you've got the variable header length in the common part of the header(s).

mdnsd/kiface.c Outdated
@@ -275,6 +141,9 @@ kev_dispatch_msg(int fd, short event, void *bula)
if (iface == NULL) /* this interface isn't configured */
continue;

sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
Copy link
Contributor

Choose a reason for hiding this comment

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

If there are actually multiple messages in buf, presumably this should be next + rtm->rtm_hdrlen or you're going to pick up the wrong socket addresses from the 2nd and subsequent messages.

@twinshadow
Copy link
Author

In OpenBSD, struct rt_msghdr->rtm_addrs and struct ifa_msghdr->ifam_addrs point to the same offset in the buffer. This is not true in FreeBSD, so the bitmask wasn't being passed to get_rtaddrs with the right value, even though the initial offset was correct.

@nbriggs
Copy link
Contributor

nbriggs commented Dec 1, 2019

No SIGSEGVs now. It does get a bit confused if you delete the only IPv4 address off the interface it's listening on -- a situation that wouldn't have made sense before IPv6 support.

void
kev_init(void)
{
int opt = 0, rcvbuf, default_rcvbuf;
int rtfilter;
Copy link
Contributor

Choose a reason for hiding this comment

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

If you're going to #ifdef __OpenBSD__ the rtfilter = ... perhaps you could #ifdef the declaration for rtfilter.

@twinshadow
Copy link
Author

twinshadow commented Dec 3, 2019

No SIGSEGVs now. It does get a bit confused if you delete the only IPv4 address off the interface it's listening on -- a situation that wouldn't have made sense before IPv6 support.

I've added some patches to tone-down the warnings from lack of IPv4 addresses. Still working on a patches to respond to remote DNS queries with all IP addresses and update the cache when changes occur to local interfaces.

If there are packets going out on multiple interfaces while operating on MDNS
IPV4/6, interfaces should not be expected to be dual-stack. IPv6 only requires
an index, and doesn't seem to have any problems if there are no IPv6 addresses
on the interface. IPv4 requires an address on the interface to do any
multicast operations.
@@ -448,6 +473,10 @@ parse_flags(const char *word, int *flags)
*flags |= F_A;
r++;
break;
case '6':
Copy link
Contributor

Choose a reason for hiding this comment

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

The usage info for the "lookup" subcommand wasn't updated to include the new "6" flag.

@twinshadow
Copy link
Author

I just realized that bug #31 will more easily trigger with this PR, since more addresses are added to the fixed-size array. I'll have to add a fix for that here.

Adds a check when adding addresses in pge_initprimary to prevent writing to
unallocated memory and causing the program to segfault.

Fixes #31, but this code should be refactored in the future.
New feature or bug is that responses will contain both A and AAAA without regard
for the request specifier for A or AAAA. I need to read the spec more.
Send the correct AF for the RR type and enumerate all interfaces for addresses.
@twinshadow
Copy link
Author

DNS responses from the daemon now send all addresses from all interfaces and can respond to mdnsctl with the appropriate address from any interface (eg. em0 being IPv6 only and bridge0 being IPv4 only). I've tested out the MDNS packet changes with mdns-sd on NetBSD.

The only other things I can think to commit are style, grammar, and comment changes before rebasing everything for merging.

@twinshadow twinshadow closed this by deleting the head repository Mar 4, 2024
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.

IPv6 not implemented
2 participants