mdns: improve numerous aspects of Posix backend

Apple's default implementation of the Posix backend for mDNSResponder
has a number of weaknesses. Address several of them, most notably:

* Improve interface tracking, preventing confusion to mdns's state
  machine. Prevents spurious removal/republication cycles whenever
  network interfaces are added or removed.

* Support network interfaces whose indeces are great than 31. Indices
  grow past that range surprisingly quickly, especially with multi-
  homed, mobile, wifi, Bluetooth, VPN, VLANs, or other interfaces
  present.

* Correctly handle edge cases during removal of a network interface.

The fixes are kept as a patch series for clarity.

Signed-off-by: Matt Hoosier <matt.hoosier@garmin.com>
Signed-off-by: Khem Raj <raj.khem@gmail.com>
This commit is contained in:
Matt Hoosier 2020-02-05 16:04:49 -06:00 committed by Khem Raj
parent fd2765bb16
commit a44430fe91
12 changed files with 945 additions and 0 deletions

View File

@ -0,0 +1,60 @@
From 89ea6ac4a8840e8c2be0140a9805c6522c6c5280 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Wed, 28 Jun 2017 17:30:00 -0500
Subject: [PATCH 01/11] Create subroutine for cleaning recent interfaces
Moves functionality for cleaning the list of recent
interfaces into its own subroutine.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 0e10bd5..ffc9696 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -856,6 +856,19 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
return err;
}
+// Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
+mDNSlocal void CleanRecentInterfaces(void)
+{
+ PosixNetworkInterface **ri = &gRecentInterfaces;
+ const mDNSs32 utc = mDNSPlatformUTC();
+ while (*ri)
+ {
+ PosixNetworkInterface *pi = *ri;
+ if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
+ else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
+ }
+}
+
// Creates a PosixNetworkInterface for the interface whose IP address is
// intfAddr and whose name is intfName and registers it with mDNS core.
mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
@@ -1010,16 +1023,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
// Clean up.
if (intfList != NULL) free_ifi_info(intfList);
-
- // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
- PosixNetworkInterface **ri = &gRecentInterfaces;
- const mDNSs32 utc = mDNSPlatformUTC();
- while (*ri)
- {
- PosixNetworkInterface *pi = *ri;
- if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
- else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
- }
+ CleanRecentInterfaces();
return err;
}
--
2.17.1

View File

@ -0,0 +1,58 @@
From a2148df99ddcd122247f95c4cbcce5c4118581a1 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Wed, 28 Jun 2017 17:30:00 -0500
Subject: [PATCH 02/11] Create subroutine for tearing down an interface
Creates a subroutine for tearing down an interface.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index ffc9696..5e5b2cd 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -591,6 +591,19 @@ mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
gRecentInterfaces = intf;
}
+mDNSlocal void TearDownInterface(mDNS *const m, PosixNetworkInterface *intf)
+{
+ mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation);
+ if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
+ FreePosixNetworkInterface(intf);
+
+ num_registered_interfaces--;
+ if (num_registered_interfaces == 0) {
+ num_pkts_accepted = 0;
+ num_pkts_rejected = 0;
+ }
+}
+
// Grab the first interface, deregister it, free it, and repeat until done.
mDNSlocal void ClearInterfaceList(mDNS *const m)
{
@@ -599,13 +612,10 @@ mDNSlocal void ClearInterfaceList(mDNS *const m)
while (m->HostInterfaces)
{
PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
- mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation);
- if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
- FreePosixNetworkInterface(intf);
+ TearDownInterface(m, intf);
}
- num_registered_interfaces = 0;
- num_pkts_accepted = 0;
- num_pkts_rejected = 0;
+
+ assert(num_registered_interfaces == 0);
}
// Sets up a send/receive socket.
--
2.17.1

View File

@ -0,0 +1,50 @@
From 71a7c728ae0d8143b66aa40decca74ebaa9aa2ce Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Wed, 28 Jun 2017 17:30:00 -0500
Subject: [PATCH 03/11] Track interface socket family
Tracks the socket family associated with the interface.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 1 +
mDNSPosix/mDNSPosix.h | 2 ++
2 files changed, 3 insertions(+)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 5e5b2cd..8fe22be 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -918,6 +918,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
// Set up the extra fields in PosixNetworkInterface.
assert(intf->intfName != NULL); // intf->intfName already set up above
intf->index = intfIndex;
+ intf->sa_family = intfAddr->sa_family;
intf->multicastSocket4 = -1;
#if HAVE_IPV6
intf->multicastSocket6 = -1;
diff --git a/mDNSPosix/mDNSPosix.h b/mDNSPosix/mDNSPosix.h
index ca60d80..f77c185 100644
--- a/mDNSPosix/mDNSPosix.h
+++ b/mDNSPosix/mDNSPosix.h
@@ -19,6 +19,7 @@
#define __mDNSPlatformPosix_h
#include <signal.h>
+#include <sys/socket.h>
#include <sys/time.h>
#ifdef __cplusplus
@@ -40,6 +41,7 @@ struct PosixNetworkInterface
const char * intfName;
PosixNetworkInterface * aliasIntf;
int index;
+ sa_family_t sa_family;
int multicastSocket4;
#if HAVE_IPV6
int multicastSocket6;
--
2.17.1

View File

@ -0,0 +1,177 @@
From e1f483510a1011e37540fdee8f3bc36111fa45a0 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Thu, 13 Jul 2017 09:00:00 -0500
Subject: [PATCH 04/11] Use list for changed interfaces
Uses a linked list to store the index of changed network interfaces
instead of a bitfield. This allows for network interfaces with an
index greater than 31 (an index of 36 was seen on Android).
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 67 +++++++++++++++++++++++++++++++++----------
1 file changed, 52 insertions(+), 15 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 8fe22be..699855a 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -75,6 +75,14 @@ struct IfChangeRec
};
typedef struct IfChangeRec IfChangeRec;
+// Used to build a list of network interface indices
+struct NetworkInterfaceIndex
+{
+ int if_index;
+ struct NetworkInterfaceIndex *Next;
+};
+typedef struct NetworkInterfaceIndex NetworkInterfaceIndex;
+
// Note that static data is initialized to zero in (modern) C.
static fd_set gEventFDs;
static int gMaxFD; // largest fd in gEventFDs
@@ -1071,6 +1079,32 @@ mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
return err;
}
+mDNSlocal mDNSBool ListContainsInterfaceIndex(GenLinkedList *list, int if_index)
+{
+ NetworkInterfaceIndex *item;
+
+ for (item = (NetworkInterfaceIndex*)list->Head; item != NULL; item = item->Next)
+ {
+ if (if_index == item->if_index) return mDNStrue;
+ }
+
+ return mDNSfalse;
+}
+
+mDNSlocal void AddInterfaceIndexToList(GenLinkedList *list, int if_index)
+{
+ NetworkInterfaceIndex *item;
+
+ if (ListContainsInterfaceIndex(list, if_index)) return;
+
+ item = malloc(sizeof *item);
+ if (item == NULL) return;
+
+ item->if_index = if_index;
+ item->Next = NULL;
+ AddToTail(list, item);
+}
+
#if MDNS_DEBUGMSGS
mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
{
@@ -1098,14 +1132,13 @@ mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
}
#endif
-mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
+mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces)
// Read through the messages on sd and if any indicate that any interface records should
// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
{
ssize_t readCount;
char buff[4096];
struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
- mDNSu32 result = 0;
// The structure here is more complex than it really ought to be because,
// unfortunately, there's no good way to size a buffer in advance large
@@ -1141,9 +1174,9 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
// Process the NetLink message
if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
- result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
+ AddInterfaceIndexToList(changedInterfaces, ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index);
else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
- result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
+ AddInterfaceIndexToList(changedInterfaces, ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index);
// Advance pNLMsg to the next message in the buffer
if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
@@ -1154,8 +1187,6 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
else
break; // all done!
}
-
- return result;
}
#else // USES_NETLINK
@@ -1187,14 +1218,13 @@ mDNSlocal void PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
}
#endif
-mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
+mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces)
// Read through the messages on sd and if any indicate that any interface records should
// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
{
ssize_t readCount;
char buff[4096];
struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff;
- mDNSu32 result = 0;
readCount = read(sd, buff, sizeof buff);
if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
@@ -1209,12 +1239,10 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
pRSMsg->ifam_type == RTM_IFINFO)
{
if (pRSMsg->ifam_type == RTM_IFINFO)
- result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
+ AddInterfaceIndexToList(changedInterfaces, ((struct if_msghdr*) pRSMsg)->ifm_index);
else
- result |= 1 << pRSMsg->ifam_index;
+ AddInterfaceIndexToList(changedInterfaces, pRSMsg->ifam_index);
}
-
- return result;
}
#endif // USES_NETLINK
@@ -1224,7 +1252,8 @@ mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
{
IfChangeRec *pChgRec = (IfChangeRec*) context;
fd_set readFDs;
- mDNSu32 changedInterfaces = 0;
+ GenLinkedList changedInterfaces;
+ NetworkInterfaceIndex *changedInterface;
struct timeval zeroTimeout = { 0, 0 };
(void)fd; // Unused
@@ -1233,17 +1262,25 @@ mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
FD_ZERO(&readFDs);
FD_SET(pChgRec->NotifySD, &readFDs);
+ InitLinkedList(&changedInterfaces, offsetof(NetworkInterfaceIndex, Next));
+
do
{
- changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
+ ProcessRoutingNotification(pChgRec->NotifySD, &changedInterfaces);
}
while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
// Currently we rebuild the entire interface list whenever any interface change is
// detected. If this ever proves to be a performance issue in a multi-homed
// configuration, more care should be paid to changedInterfaces.
- if (changedInterfaces)
+ if (changedInterfaces.Head != NULL)
mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
+
+ while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL)
+ {
+ RemoveFromList(&changedInterfaces, changedInterface);
+ free(changedInterface);
+ }
}
// Register with either a Routing Socket or RtNetLink to listen for interface changes.
--
2.17.1

View File

@ -0,0 +1,212 @@
From 92025cab86619f548bf3eb816a1804ef40507ca7 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Mon, 24 Jul 2017 09:38:55 -0500
Subject: [PATCH 05/11] Handle noisy netlink sockets
The POSIX implementation currently clears all network interfaces
when netlink indicates that there has been a change. This causes
the following problems:
1) Applications are informed that all of the services they are
tracking have been removed.
2) Increases network load because the client must re-query for
all records it is interested in.
This changes netlink notification handling by:
1) Always comparing with the latest interface list returned
by the OS.
2) Confirming that the interface has been changed in a way
that we care about.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 143 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 133 insertions(+), 10 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 699855a..59a8b8c 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -1247,14 +1247,38 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change
#endif // USES_NETLINK
+// Test whether the given PosixNetworkInterface matches the given struct ifi_info
+mDNSlocal mDNSBool InterfacesMatch(PosixNetworkInterface *intf, struct ifi_info *ifi)
+{
+ mDNSBool match = mDNSfalse;
+ mDNSAddr ip, mask;
+
+ if((intf->index == ifi->ifi_index) &&
+ (intf->sa_family == ifi->ifi_addr->sa_family) &&
+ (strcmp(intf->coreIntf.ifname, ifi->ifi_name) == 0))
+ {
+ SockAddrTomDNSAddr(ifi->ifi_addr, &ip, NULL);
+ SockAddrTomDNSAddr(ifi->ifi_netmask, &mask, NULL);
+
+ match = mDNSSameAddress(&intf->coreIntf.ip, &ip) &&
+ mDNSSameAddress(&intf->coreIntf.mask, &mask);
+ }
+
+ return match;
+}
+
// Called when data appears on interface change notification socket
mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
{
IfChangeRec *pChgRec = (IfChangeRec*) context;
+ mDNS *m = pChgRec->mDNS;
fd_set readFDs;
GenLinkedList changedInterfaces;
NetworkInterfaceIndex *changedInterface;
struct timeval zeroTimeout = { 0, 0 };
+ struct ifi_info *ifi_list, **ifi, *ifi_free, *ifi_loop4 = NULL;
+ PosixNetworkInterface *intf, *intfNext;
+ mDNSBool found, foundav4;
(void)fd; // Unused
(void)filter; // Unused
@@ -1270,12 +1294,115 @@ mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
}
while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
- // Currently we rebuild the entire interface list whenever any interface change is
- // detected. If this ever proves to be a performance issue in a multi-homed
- // configuration, more care should be paid to changedInterfaces.
- if (changedInterfaces.Head != NULL)
- mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
+ CleanRecentInterfaces();
+
+ if (changedInterfaces.Head == NULL) goto cleanup;
+
+ ifi_list = get_ifi_info(AF_INET, mDNStrue);
+ if (ifi_list == NULL) goto cleanup;
+
+#if HAVE_IPV6
+ /* Link the IPv6 list to the end of the IPv4 list */
+ ifi = &ifi_list;
+ while (*ifi != NULL) ifi = &(*ifi)->ifi_next;
+ *ifi = get_ifi_info(AF_INET6, mDNStrue);
+#endif
+
+ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext)
+ {
+ intfNext = (PosixNetworkInterface*)(intf->coreIntf.next);
+
+ // Loopback interface(s) are handled later
+ if (intf->coreIntf.Loopback) continue;
+
+ found = mDNSfalse;
+ for (ifi = &ifi_list; *ifi != NULL; ifi = &(*ifi)->ifi_next)
+ {
+ if (InterfacesMatch(intf, *ifi))
+ {
+ found = mDNStrue;
+
+ // Removes unchanged from ifi_list
+ ifi_free = *ifi;
+ *ifi = (*ifi)->ifi_next;
+ ifi_free->ifi_next = NULL;
+ free_ifi_info(ifi_free);
+
+ break;
+ }
+ }
+
+ // Removes changed and old interfaces from m->HostInterfaces
+ if (!found) TearDownInterface(m, intf);
+ }
+
+ // Add new and changed interfaces in ifi_list
+ // Save off loopback interface in case it is needed later
+ for (ifi = &ifi_list; *ifi != NULL; ifi = &(*ifi)->ifi_next)
+ {
+ if ((ifi_loop4 == NULL) &&
+ ((*ifi)->ifi_addr->sa_family == AF_INET) &&
+ ((*ifi)->ifi_flags & IFF_UP) &&
+ ((*ifi)->ifi_flags & IFF_LOOPBACK))
+ {
+ ifi_loop4 = *ifi;
+ continue;
+ }
+
+ if ( (((*ifi)->ifi_addr->sa_family == AF_INET)
+#if HAVE_IPV6
+ || ((*ifi)->ifi_addr->sa_family == AF_INET6)
+#endif
+ ) && ((*ifi)->ifi_flags & IFF_UP)
+ && !((*ifi)->ifi_flags & IFF_POINTOPOINT)
+ && !((*ifi)->ifi_flags & IFF_LOOPBACK))
+ {
+ SetupOneInterface(m, *ifi);
+ }
+ }
+
+ // Determine if there is at least one non-loopback IPv4 interface. This is to work around issues
+ // with multicast loopback on IPv6 interfaces -- see corresponding logic in SetupInterfaceList().
+ foundav4 = mDNSfalse;
+ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = (PosixNetworkInterface*)(intf->coreIntf.next))
+ {
+ if (intf->sa_family == AF_INET && !intf->coreIntf.Loopback)
+ {
+ foundav4 = mDNStrue;
+ break;
+ }
+ }
+
+ if (foundav4)
+ {
+ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext)
+ {
+ intfNext = (PosixNetworkInterface*)(intf->coreIntf.next);
+ if (intf->coreIntf.Loopback) TearDownInterface(m, intf);
+ }
+ }
+ else
+ {
+ found = mDNSfalse;
+
+ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = (PosixNetworkInterface*)(intf->coreIntf.next))
+ {
+ if (intf->coreIntf.Loopback)
+ {
+ found = mDNStrue;
+ break;
+ }
+ }
+
+ if (!found && (ifi_loop4 != NULL))
+ {
+ SetupOneInterface(m, ifi_loop4);
+ }
+ }
+
+ if (ifi_list != NULL) free_ifi_info(ifi_list);
+cleanup:
while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL)
{
RemoveFromList(&changedInterfaces, changedInterface);
@@ -1400,15 +1527,11 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
#endif
}
-// This is used internally by InterfaceChangeCallback.
-// It's also exported so that the Standalone Responder (mDNSResponderPosix)
+// This is exported so that the Standalone Responder (mDNSResponderPosix)
// can call it in response to a SIGHUP (mainly for debugging purposes).
mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
{
int err;
- // This is a pretty heavyweight way to process interface changes --
- // destroying the entire interface list and then making fresh one from scratch.
- // We should make it like the OS X version, which leaves unchanged interfaces alone.
ClearInterfaceList(m);
err = SetupInterfaceList(m);
return PosixErrorToStatus(err);
--
2.17.1

View File

@ -0,0 +1,51 @@
From 157d67f152777754c059ced7511352102f23ffae Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Mon, 24 Jul 2017 09:39:18 -0500
Subject: [PATCH 06/11] Remove unneeded function
Removes a function we no longer need by integrating it into the only
function that calls it. This was originally separated so that we could
only process network interfaces that netlink indicated had been changed,
this has since been extended to test for all network intefaces.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 59a8b8c..3fc5451 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -1079,24 +1079,15 @@ mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
return err;
}
-mDNSlocal mDNSBool ListContainsInterfaceIndex(GenLinkedList *list, int if_index)
+mDNSlocal void AddInterfaceIndexToList(GenLinkedList *list, int if_index)
{
NetworkInterfaceIndex *item;
for (item = (NetworkInterfaceIndex*)list->Head; item != NULL; item = item->Next)
{
- if (if_index == item->if_index) return mDNStrue;
+ if (if_index == item->if_index) return;
}
- return mDNSfalse;
-}
-
-mDNSlocal void AddInterfaceIndexToList(GenLinkedList *list, int if_index)
-{
- NetworkInterfaceIndex *item;
-
- if (ListContainsInterfaceIndex(list, if_index)) return;
-
item = malloc(sizeof *item);
if (item == NULL) return;
--
2.17.1

View File

@ -0,0 +1,129 @@
From 07a9401d84804d7f0181aa4fb0f13a54b2a1c9a8 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Tue, 1 Aug 2017 17:06:01 -0500
Subject: [PATCH 07/11] Indicate loopback interface to mDNS core
Tells the mDNS core if an interface is a loopback interface,
similar to AddInterfaceToList() in the MacOS implementation.
Also reorganizes SetupOneInterface() to use a const struct
rather than growing its parameter list again.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 37 ++++++++++++++++++-------------------
1 file changed, 18 insertions(+), 19 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 3fc5451..798ab10 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -889,16 +889,14 @@ mDNSlocal void CleanRecentInterfaces(void)
// Creates a PosixNetworkInterface for the interface whose IP address is
// intfAddr and whose name is intfName and registers it with mDNS core.
-mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
+mDNSlocal int SetupOneInterface(mDNS *const m, struct ifi_info *const ifi)
{
int err = 0;
PosixNetworkInterface *intf;
PosixNetworkInterface *alias = NULL;
assert(m != NULL);
- assert(intfAddr != NULL);
- assert(intfName != NULL);
- assert(intfMask != NULL);
+ assert(ifi != NULL);
// Allocate the interface structure itself.
intf = (PosixNetworkInterface*)calloc(1, sizeof(*intf));
@@ -907,26 +905,27 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
// And make a copy of the intfName.
if (err == 0)
{
- intf->intfName = strdup(intfName);
+ intf->intfName = strdup(ifi->ifi_name);
if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
}
if (err == 0)
{
// Set up the fields required by the mDNS core.
- SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
- SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
+ SockAddrTomDNSAddr(ifi->ifi_addr, &intf->coreIntf.ip, NULL);
+ SockAddrTomDNSAddr(ifi->ifi_netmask, &intf->coreIntf.mask, NULL);
//LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
- strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
+ strncpy(intf->coreIntf.ifname, ifi->ifi_name, sizeof(intf->coreIntf.ifname));
intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
intf->coreIntf.McastTxRx = mDNStrue;
+ intf->coreIntf.Loopback = ((ifi->ifi_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
// Set up the extra fields in PosixNetworkInterface.
assert(intf->intfName != NULL); // intf->intfName already set up above
- intf->index = intfIndex;
- intf->sa_family = intfAddr->sa_family;
+ intf->index = ifi->ifi_index;
+ intf->sa_family = ifi->ifi_addr->sa_family;
intf->multicastSocket4 = -1;
#if HAVE_IPV6
intf->multicastSocket6 = -1;
@@ -936,17 +935,17 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
if (alias != intf)
- debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
+ debugf("SetupOneInterface: %s %#a is an alias of %#a", ifi->ifi_name, &intf->coreIntf.ip, &alias->coreIntf.ip);
}
// Set up the multicast socket
if (err == 0)
{
- if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
- err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
+ if (alias->multicastSocket4 == -1 && ifi->ifi_addr->sa_family == AF_INET)
+ err = SetupSocket(ifi->ifi_addr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
#if HAVE_IPV6
- else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
- err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
+ else if (alias->multicastSocket6 == -1 && ifi->ifi_addr->sa_family == AF_INET6)
+ err = SetupSocket(ifi->ifi_addr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
#endif
}
@@ -973,8 +972,8 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
}
else
{
- // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
- debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
+ // Use ifi->ifi_name instead of intf->intfName in the next line to avoid dereferencing NULL.
+ debugf("SetupOneInterface: %s %#a failed to register %d", ifi->ifi_name, &intf->coreIntf.ip, err);
if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
}
@@ -1023,7 +1022,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
}
else
{
- if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
+ if (SetupOneInterface(m, i) == 0)
if (i->ifi_addr->sa_family == AF_INET)
foundav4 = mDNStrue;
}
@@ -1037,7 +1036,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
// In the interim, we skip loopback interface only if we found at least one v4 interface to use
// if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
if (!foundav4 && firstLoopback)
- (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
+ (void) SetupOneInterface(m, firstLoopback);
}
// Clean up.
--
2.17.1

View File

@ -0,0 +1,39 @@
From 0fcc0f210f3a9310a1963de640b384ce866410fd Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Wed, 9 Aug 2017 09:16:58 -0500
Subject: [PATCH 08/11] Mark deleted interfaces as being changed
Netlink notification handling ignores messages for deleted links,
RTM_DELLINK. It does handle RTM_GETLINK. According to libnl docu-
mentation (http://www.infradead.org/~tgr/libnl/doc/route.html)
RTM_DELLINK can be sent by the kernel, but RTM_GETLINK cannot.
There was likely a mixup in the original implementation, so this
change replaces handling for RTM_GETLINK with RTM_DELLINK.
Testing and Verification Instructions:
1. Use ip-link to add and remove a VLAN interface and verify
that mDNSResponder handles the deleted link.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 798ab10..a8a57df 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -1163,7 +1163,7 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change
#endif
// Process the NetLink message
- if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
+ if (pNLMsg->nlmsg_type == RTM_DELLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
AddInterfaceIndexToList(changedInterfaces, ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index);
else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
AddInterfaceIndexToList(changedInterfaces, ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index);
--
2.17.1

View File

@ -0,0 +1,45 @@
From 38cff19781f81586926b02f0fd1cb36c040395e0 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Thu, 10 Aug 2017 08:21:53 -0500
Subject: [PATCH 09/11] Fix possible NULL dereference
Fixes a possible NULL dereference if memory for
the PosixNetworkInterface could not be allocated.
Other logic seems to prevent dereferencing this
variable if NULL, but this instance seems to have
been overlooked.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index a8a57df..3243ed4 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -951,12 +951,15 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct ifi_info *const ifi)
// If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
// and skip the probe phase of the probe/announce packet sequence.
- intf->coreIntf.DirectLink = mDNSfalse;
+ if (err == 0)
+ {
+ intf->coreIntf.DirectLink = mDNSfalse;
#ifdef DIRECTLINK_INTERFACE_NAME
- if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0)
- intf->coreIntf.DirectLink = mDNStrue;
+ if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0)
+ intf->coreIntf.DirectLink = mDNStrue;
#endif
- intf->coreIntf.SupportsUnicastMDNSResponse = mDNStrue;
+ intf->coreIntf.SupportsUnicastMDNSResponse = mDNStrue;
+ }
// The interface is all ready to go, let's register it with the mDNS core.
if (err == 0)
--
2.17.1

View File

@ -0,0 +1,62 @@
From 382b3b924e43abd1bdc5792918161d0922666691 Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Thu, 10 Aug 2017 08:27:32 -0500
Subject: [PATCH 10/11] Handle errors from socket calls
Adds handling for socket() or read() returning a
negative value (indicating an error has occurred).
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 3243ed4..84af26b 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -1129,7 +1129,7 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change
// Read through the messages on sd and if any indicate that any interface records should
// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
{
- ssize_t readCount;
+ ssize_t readVal, readCount;
char buff[4096];
struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
@@ -1138,7 +1138,10 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change
// enough to hold all pending data and so avoid message fragmentation.
// (Note that FIONREAD is not supported on AF_NETLINK.)
- readCount = read(sd, buff, sizeof buff);
+ readVal = read(sd, buff, sizeof buff);
+ if (readVal < 0) return;
+ readCount = readVal;
+
while (1)
{
// Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
@@ -1154,7 +1157,9 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change
pNLMsg = (struct nlmsghdr*) buff;
// read more data
- readCount += read(sd, buff + readCount, sizeof buff - readCount);
+ readVal = read(sd, buff + readCount, sizeof buff - readCount);
+ if (readVal < 0) return;
+ readCount += readVal;
continue; // spin around and revalidate with new readCount
}
else
@@ -1429,6 +1434,7 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
int err;
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in s5353;
+ if (s < 0) return mDNSfalse;
s5353.sin_family = AF_INET;
s5353.sin_port = MulticastDNSPort.NotAnInteger;
s5353.sin_addr.s_addr = 0;
--
2.17.1

View File

@ -0,0 +1,51 @@
From 19de26db69408f02241e232b39224589a0f630df Mon Sep 17 00:00:00 2001
From: Nate Karstens <nate.karstens@garmin.com>
Date: Thu, 10 Aug 2017 08:46:03 -0500
Subject: [PATCH 11/11] Change a dynamic allocation to file-scope variable
Changes a variable from being dynamically-allocated to being
statically-allocated at the file scope. Addresses a Coverity
issue where it appeared that the memory was being leaked.
Upstream-Status: Submitted [dts@apple.com]
Signed-off-by: Nate Karstens <nate.karstens@garmin.com>
---
mDNSPosix/mDNSPosix.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
index 84af26b..b7795ed 100644
--- a/mDNSPosix/mDNSPosix.c
+++ b/mDNSPosix/mDNSPosix.c
@@ -91,6 +91,7 @@ static sigset_t gEventSignalSet; // Signals which event loop list
static sigset_t gEventSignals; // Signals which were received while inside loop
static PosixNetworkInterface *gRecentInterfaces;
+static IfChangeRec gChgRec;
// ***************************************************************************
// Globals (for debugging)
@@ -1412,16 +1413,11 @@ cleanup:
mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
{
mStatus err;
- IfChangeRec *pChgRec;
- pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
- if (pChgRec == NULL)
- return mStatus_NoMemoryErr;
-
- pChgRec->mDNS = m;
- err = OpenIfNotifySocket(&pChgRec->NotifySD);
+ gChgRec.mDNS = m;
+ err = OpenIfNotifySocket(&gChgRec.NotifySD);
if (err == 0)
- err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+ err = mDNSPosixAddFDToEventLoop(gChgRec.NotifySD, InterfaceChangeCallback, &gChgRec);
return err;
}
--
2.17.1

View File

@ -11,6 +11,17 @@ RPROVIDES_${PN} += "libdns_sd.so"
SRC_URI = "https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-${PV}.tar.gz \
file://build.patch;patchdir=.. \
file://mdns.service \
file://0001-Create-subroutine-for-cleaning-recent-interfaces.patch;patchdir=.. \
file://0002-Create-subroutine-for-tearing-down-an-interface.patch;patchdir=.. \
file://0003-Track-interface-socket-family.patch;patchdir=.. \
file://0004-Use-list-for-changed-interfaces.patch;patchdir=.. \
file://0005-Handle-noisy-netlink-sockets.patch;patchdir=.. \
file://0006-Remove-unneeded-function.patch;patchdir=.. \
file://0007-Indicate-loopback-interface-to-mDNS-core.patch;patchdir=.. \
file://0008-Mark-deleted-interfaces-as-being-changed.patch;patchdir=.. \
file://0009-Fix-possible-NULL-dereference.patch;patchdir=.. \
file://0010-Handle-errors-from-socket-calls.patch;patchdir=.. \
file://0011-Change-a-dynamic-allocation-to-file-scope-variable.patch;patchdir=.. \
"
SRC_URI[md5sum] = "aeb92d838a4aa2402ef128ed501484eb"
SRC_URI[sha256sum] = "3cc71582e8eee469c2de8ecae1d769e7f32b3468dfb7f2ca77f1dee1f30a7d1e"