1*4a64e381SAndroid Build Coastguard WorkerFrom 00289e89cccb9567d6ea6bd2a394fd14b61e5ad1 Mon Sep 17 00:00:00 2001
2*4a64e381SAndroid Build Coastguard WorkerMessage-ID: <00289e89cccb9567d6ea6bd2a394fd14b61e5ad1.1687508149.git.stefan@agner.ch>
3*4a64e381SAndroid Build Coastguard WorkerIn-Reply-To: <e136dcdcdd93ef32ada981e89c195905eb809eea.1687508149.git.stefan@agner.ch>
4*4a64e381SAndroid Build Coastguard WorkerReferences: <e136dcdcdd93ef32ada981e89c195905eb809eea.1687508149.git.stefan@agner.ch>
5*4a64e381SAndroid Build Coastguard WorkerFrom: Nate Karstens <[email protected]>
6*4a64e381SAndroid Build Coastguard WorkerDate: Mon, 24 Jul 2017 09:38:55 -0500
7*4a64e381SAndroid Build Coastguard WorkerSubject: [PATCH] Handle noisy netlink sockets
8*4a64e381SAndroid Build Coastguard Worker
9*4a64e381SAndroid Build Coastguard WorkerThe POSIX implementation currently clears all network interfaces
10*4a64e381SAndroid Build Coastguard Workerwhen netlink indicates that there has been a change. This causes
11*4a64e381SAndroid Build Coastguard Workerthe following problems:
12*4a64e381SAndroid Build Coastguard Worker
13*4a64e381SAndroid Build Coastguard Worker  1) Applications are informed that all of the services they are
14*4a64e381SAndroid Build Coastguard Worker     tracking have been removed.
15*4a64e381SAndroid Build Coastguard Worker  2) Increases network load because the client must re-query for
16*4a64e381SAndroid Build Coastguard Worker     all records it is interested in.
17*4a64e381SAndroid Build Coastguard Worker
18*4a64e381SAndroid Build Coastguard WorkerThis changes netlink notification handling by:
19*4a64e381SAndroid Build Coastguard Worker
20*4a64e381SAndroid Build Coastguard Worker  1) Always comparing with the latest interface list returned
21*4a64e381SAndroid Build Coastguard Worker     by the OS.
22*4a64e381SAndroid Build Coastguard Worker  2) Confirming that the interface has been changed in a way
23*4a64e381SAndroid Build Coastguard Worker     that we care about.
24*4a64e381SAndroid Build Coastguard Worker
25*4a64e381SAndroid Build Coastguard WorkerUpstream-Status: Submitted [[email protected]]
26*4a64e381SAndroid Build Coastguard Worker
27*4a64e381SAndroid Build Coastguard WorkerSigned-off-by: Nate Karstens <[email protected]>
28*4a64e381SAndroid Build Coastguard WorkerSigned-off-by: Alex Kiernan <[email protected]>
29*4a64e381SAndroid Build Coastguard Worker---
30*4a64e381SAndroid Build Coastguard Worker mDNSPosix/mDNSPosix.c | 182 +++++++++++++++++++++++++++++++++++++++---
31*4a64e381SAndroid Build Coastguard Worker 1 file changed, 172 insertions(+), 10 deletions(-)
32*4a64e381SAndroid Build Coastguard Worker
33*4a64e381SAndroid Build Coastguard Workerdiff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
34*4a64e381SAndroid Build Coastguard Workerindex 9867881..ad7000d 100644
35*4a64e381SAndroid Build Coastguard Worker--- a/mDNSPosix/mDNSPosix.c
36*4a64e381SAndroid Build Coastguard Worker+++ b/mDNSPosix/mDNSPosix.c
37*4a64e381SAndroid Build Coastguard Worker@@ -1788,14 +1788,43 @@ mDNSlocal void          ProcessRoutingNotification(int sd, GenLinkedList *change
38*4a64e381SAndroid Build Coastguard Worker
39*4a64e381SAndroid Build Coastguard Worker #endif // USES_NETLINK
40*4a64e381SAndroid Build Coastguard Worker
41*4a64e381SAndroid Build Coastguard Worker+// Test whether the given PosixNetworkInterface matches the given struct ifaddrs
42*4a64e381SAndroid Build Coastguard Worker+mDNSlocal mDNSBool InterfacesMatch(PosixNetworkInterface *intf, struct ifaddrs *ifi)
43*4a64e381SAndroid Build Coastguard Worker+{
44*4a64e381SAndroid Build Coastguard Worker+    mDNSBool match = mDNSfalse;
45*4a64e381SAndroid Build Coastguard Worker+    mDNSAddr ip, mask;
46*4a64e381SAndroid Build Coastguard Worker+    int if_index;
47*4a64e381SAndroid Build Coastguard Worker+
48*4a64e381SAndroid Build Coastguard Worker+    if_index = if_nametoindex(ifi->ifa_name);
49*4a64e381SAndroid Build Coastguard Worker+    if (if_index == 0)
50*4a64e381SAndroid Build Coastguard Worker+        return mDNSfalse;
51*4a64e381SAndroid Build Coastguard Worker+
52*4a64e381SAndroid Build Coastguard Worker+    if((intf->index == if_index) &&
53*4a64e381SAndroid Build Coastguard Worker+       (intf->sa_family == ifi->ifa_addr->sa_family) &&
54*4a64e381SAndroid Build Coastguard Worker+       (strcmp(intf->coreIntf.ifname, ifi->ifa_name) == 0))
55*4a64e381SAndroid Build Coastguard Worker+        {
56*4a64e381SAndroid Build Coastguard Worker+        SockAddrTomDNSAddr(ifi->ifa_addr,    &ip,   NULL);
57*4a64e381SAndroid Build Coastguard Worker+        SockAddrTomDNSAddr(ifi->ifa_netmask, &mask, NULL);
58*4a64e381SAndroid Build Coastguard Worker+
59*4a64e381SAndroid Build Coastguard Worker+        match = mDNSSameAddress(&intf->coreIntf.ip, &ip) &&
60*4a64e381SAndroid Build Coastguard Worker+                mDNSSameAddress(&intf->coreIntf.mask, &mask);
61*4a64e381SAndroid Build Coastguard Worker+        }
62*4a64e381SAndroid Build Coastguard Worker+
63*4a64e381SAndroid Build Coastguard Worker+    return match;
64*4a64e381SAndroid Build Coastguard Worker+}
65*4a64e381SAndroid Build Coastguard Worker+
66*4a64e381SAndroid Build Coastguard Worker // Called when data appears on interface change notification socket
67*4a64e381SAndroid Build Coastguard Worker mDNSlocal void InterfaceChangeCallback(int fd, void *context)
68*4a64e381SAndroid Build Coastguard Worker {
69*4a64e381SAndroid Build Coastguard Worker     IfChangeRec     *pChgRec = (IfChangeRec*) context;
70*4a64e381SAndroid Build Coastguard Worker+    mDNS            *m = pChgRec->mDNS;
71*4a64e381SAndroid Build Coastguard Worker     fd_set readFDs;
72*4a64e381SAndroid Build Coastguard Worker     GenLinkedList changedInterfaces;
73*4a64e381SAndroid Build Coastguard Worker     NetworkInterfaceIndex *changedInterface;
74*4a64e381SAndroid Build Coastguard Worker     struct timeval zeroTimeout = { 0, 0 };
75*4a64e381SAndroid Build Coastguard Worker+    struct ifaddrs *ifa_list, **ifi, *ifa_loop4 = NULL;
76*4a64e381SAndroid Build Coastguard Worker+    PosixNetworkInterface *intf, *intfNext;
77*4a64e381SAndroid Build Coastguard Worker+    mDNSBool found, foundav4;
78*4a64e381SAndroid Build Coastguard Worker
79*4a64e381SAndroid Build Coastguard Worker     (void)fd; // Unused
80*4a64e381SAndroid Build Coastguard Worker
81*4a64e381SAndroid Build Coastguard Worker@@ -1810,12 +1839,149 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context)
82*4a64e381SAndroid Build Coastguard Worker     }
83*4a64e381SAndroid Build Coastguard Worker     while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
84*4a64e381SAndroid Build Coastguard Worker
85*4a64e381SAndroid Build Coastguard Worker-    // Currently we rebuild the entire interface list whenever any interface change is
86*4a64e381SAndroid Build Coastguard Worker-    // detected. If this ever proves to be a performance issue in a multi-homed
87*4a64e381SAndroid Build Coastguard Worker-    // configuration, more care should be paid to changedInterfaces.
88*4a64e381SAndroid Build Coastguard Worker-    if (changedInterfaces.Head != NULL)
89*4a64e381SAndroid Build Coastguard Worker-        mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
90*4a64e381SAndroid Build Coastguard Worker+    CleanRecentInterfaces();
91*4a64e381SAndroid Build Coastguard Worker+
92*4a64e381SAndroid Build Coastguard Worker+    if (changedInterfaces.Head == NULL) goto cleanup;
93*4a64e381SAndroid Build Coastguard Worker+
94*4a64e381SAndroid Build Coastguard Worker+    if (getifaddrs(&ifa_list) < 0) goto cleanup;
95*4a64e381SAndroid Build Coastguard Worker+
96*4a64e381SAndroid Build Coastguard Worker+    for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext)
97*4a64e381SAndroid Build Coastguard Worker+    {
98*4a64e381SAndroid Build Coastguard Worker+        intfNext = (PosixNetworkInterface*)(intf->coreIntf.next);
99*4a64e381SAndroid Build Coastguard Worker+
100*4a64e381SAndroid Build Coastguard Worker+        // Loopback interface(s) are handled later
101*4a64e381SAndroid Build Coastguard Worker+        if (intf->coreIntf.Loopback) continue;
102*4a64e381SAndroid Build Coastguard Worker+
103*4a64e381SAndroid Build Coastguard Worker+        found = mDNSfalse;
104*4a64e381SAndroid Build Coastguard Worker+        for (ifi = &ifa_list; *ifi != NULL; ifi = &(*ifi)->ifa_next)
105*4a64e381SAndroid Build Coastguard Worker+        {
106*4a64e381SAndroid Build Coastguard Worker+            if (InterfacesMatch(intf, *ifi))
107*4a64e381SAndroid Build Coastguard Worker+            {
108*4a64e381SAndroid Build Coastguard Worker+                found = mDNStrue;
109*4a64e381SAndroid Build Coastguard Worker+                break;
110*4a64e381SAndroid Build Coastguard Worker+            }
111*4a64e381SAndroid Build Coastguard Worker+        }
112*4a64e381SAndroid Build Coastguard Worker+
113*4a64e381SAndroid Build Coastguard Worker+        // Removes changed and old interfaces from m->HostInterfaces
114*4a64e381SAndroid Build Coastguard Worker+        if (!found) TearDownInterface(m, intf);
115*4a64e381SAndroid Build Coastguard Worker+    }
116*4a64e381SAndroid Build Coastguard Worker+
117*4a64e381SAndroid Build Coastguard Worker+    // Add new and changed interfaces in ifa_list
118*4a64e381SAndroid Build Coastguard Worker+    // Save off loopback interface in case it is needed later
119*4a64e381SAndroid Build Coastguard Worker+    for (ifi = &ifa_list; *ifi != NULL; ifi = &(*ifi)->ifa_next)
120*4a64e381SAndroid Build Coastguard Worker+    {
121*4a64e381SAndroid Build Coastguard Worker+        found = mDNSfalse;
122*4a64e381SAndroid Build Coastguard Worker+        for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext)
123*4a64e381SAndroid Build Coastguard Worker+        {
124*4a64e381SAndroid Build Coastguard Worker+            intfNext = (PosixNetworkInterface*)(intf->coreIntf.next);
125*4a64e381SAndroid Build Coastguard Worker+
126*4a64e381SAndroid Build Coastguard Worker+            // Loopback interface(s) are handled later
127*4a64e381SAndroid Build Coastguard Worker+            if (intf->coreIntf.Loopback) continue;
128*4a64e381SAndroid Build Coastguard Worker+
129*4a64e381SAndroid Build Coastguard Worker+            if (InterfacesMatch(intf, *ifi))
130*4a64e381SAndroid Build Coastguard Worker+            {
131*4a64e381SAndroid Build Coastguard Worker+                found = mDNStrue;
132*4a64e381SAndroid Build Coastguard Worker+                break;
133*4a64e381SAndroid Build Coastguard Worker+            }
134*4a64e381SAndroid Build Coastguard Worker+
135*4a64e381SAndroid Build Coastguard Worker+            // Removes changed and old interfaces from m->HostInterfaces
136*4a64e381SAndroid Build Coastguard Worker+        }
137*4a64e381SAndroid Build Coastguard Worker+        if (found)
138*4a64e381SAndroid Build Coastguard Worker+	    continue;
139*4a64e381SAndroid Build Coastguard Worker+
140*4a64e381SAndroid Build Coastguard Worker+        if ((ifa_loop4 == NULL) &&
141*4a64e381SAndroid Build Coastguard Worker+            ((*ifi)->ifa_addr->sa_family == AF_INET) &&
142*4a64e381SAndroid Build Coastguard Worker+            ((*ifi)->ifa_flags & IFF_UP) &&
143*4a64e381SAndroid Build Coastguard Worker+            ((*ifi)->ifa_flags & IFF_LOOPBACK))
144*4a64e381SAndroid Build Coastguard Worker+        {
145*4a64e381SAndroid Build Coastguard Worker+            ifa_loop4 = *ifi;
146*4a64e381SAndroid Build Coastguard Worker+            continue;
147*4a64e381SAndroid Build Coastguard Worker+        }
148*4a64e381SAndroid Build Coastguard Worker+
149*4a64e381SAndroid Build Coastguard Worker+        if (     (((*ifi)->ifa_addr->sa_family == AF_INET)
150*4a64e381SAndroid Build Coastguard Worker+#if HAVE_IPV6
151*4a64e381SAndroid Build Coastguard Worker+                  || ((*ifi)->ifa_addr->sa_family == AF_INET6)
152*4a64e381SAndroid Build Coastguard Worker+#endif
153*4a64e381SAndroid Build Coastguard Worker+                  ) && ((*ifi)->ifa_flags & IFF_UP)
154*4a64e381SAndroid Build Coastguard Worker+                    && !((*ifi)->ifa_flags & IFF_POINTOPOINT)
155*4a64e381SAndroid Build Coastguard Worker+                    && !((*ifi)->ifa_flags & IFF_LOOPBACK))
156*4a64e381SAndroid Build Coastguard Worker+        {
157*4a64e381SAndroid Build Coastguard Worker+            struct ifaddrs *i = *ifi;
158*4a64e381SAndroid Build Coastguard Worker+
159*4a64e381SAndroid Build Coastguard Worker+#define ethernet_addr_len 6
160*4a64e381SAndroid Build Coastguard Worker+            uint8_t hwaddr[ethernet_addr_len];
161*4a64e381SAndroid Build Coastguard Worker+            int hwaddr_len = 0;
162*4a64e381SAndroid Build Coastguard Worker+
163*4a64e381SAndroid Build Coastguard Worker+#if defined(TARGET_OS_LINUX) && TARGET_OS_LINUX
164*4a64e381SAndroid Build Coastguard Worker+            struct ifreq ifr;
165*4a64e381SAndroid Build Coastguard Worker+            int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
166*4a64e381SAndroid Build Coastguard Worker+            if (sockfd >= 0)
167*4a64e381SAndroid Build Coastguard Worker+            {
168*4a64e381SAndroid Build Coastguard Worker+                /* Add hardware address */
169*4a64e381SAndroid Build Coastguard Worker+                memcpy(ifr.ifr_name, i->ifa_name, IFNAMSIZ);
170*4a64e381SAndroid Build Coastguard Worker+                if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != -1)
171*4a64e381SAndroid Build Coastguard Worker+                {
172*4a64e381SAndroid Build Coastguard Worker+                    if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER)
173*4a64e381SAndroid Build Coastguard Worker+                    {
174*4a64e381SAndroid Build Coastguard Worker+                        memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ethernet_addr_len);
175*4a64e381SAndroid Build Coastguard Worker+                        hwaddr_len = ethernet_addr_len;
176*4a64e381SAndroid Build Coastguard Worker+                    }
177*4a64e381SAndroid Build Coastguard Worker+                }
178*4a64e381SAndroid Build Coastguard Worker+                close(sockfd);
179*4a64e381SAndroid Build Coastguard Worker+            }
180*4a64e381SAndroid Build Coastguard Worker+            else
181*4a64e381SAndroid Build Coastguard Worker+            {
182*4a64e381SAndroid Build Coastguard Worker+                memset(hwaddr, 0, sizeof(hwaddr));
183*4a64e381SAndroid Build Coastguard Worker+            }
184*4a64e381SAndroid Build Coastguard Worker+#endif // TARGET_OS_LINUX
185*4a64e381SAndroid Build Coastguard Worker+            SetupOneInterface(m, i->ifa_addr, i->ifa_netmask,
186*4a64e381SAndroid Build Coastguard Worker+                              hwaddr, hwaddr_len, i->ifa_name, if_nametoindex(i->ifa_name), i->ifa_flags);
187*4a64e381SAndroid Build Coastguard Worker+        }
188*4a64e381SAndroid Build Coastguard Worker+    }
189*4a64e381SAndroid Build Coastguard Worker+
190*4a64e381SAndroid Build Coastguard Worker+    // Determine if there is at least one non-loopback IPv4 interface. This is to work around issues
191*4a64e381SAndroid Build Coastguard Worker+    // with multicast loopback on IPv6 interfaces -- see corresponding logic in SetupInterfaceList().
192*4a64e381SAndroid Build Coastguard Worker+    foundav4 = mDNSfalse;
193*4a64e381SAndroid Build Coastguard Worker+    for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = (PosixNetworkInterface*)(intf->coreIntf.next))
194*4a64e381SAndroid Build Coastguard Worker+    {
195*4a64e381SAndroid Build Coastguard Worker+        if (intf->sa_family == AF_INET && !intf->coreIntf.Loopback)
196*4a64e381SAndroid Build Coastguard Worker+        {
197*4a64e381SAndroid Build Coastguard Worker+            foundav4 = mDNStrue;
198*4a64e381SAndroid Build Coastguard Worker+            break;
199*4a64e381SAndroid Build Coastguard Worker+        }
200*4a64e381SAndroid Build Coastguard Worker+    }
201*4a64e381SAndroid Build Coastguard Worker+
202*4a64e381SAndroid Build Coastguard Worker+    if (foundav4)
203*4a64e381SAndroid Build Coastguard Worker+    {
204*4a64e381SAndroid Build Coastguard Worker+        for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext)
205*4a64e381SAndroid Build Coastguard Worker+        {
206*4a64e381SAndroid Build Coastguard Worker+            intfNext = (PosixNetworkInterface*)(intf->coreIntf.next);
207*4a64e381SAndroid Build Coastguard Worker+            if (intf->coreIntf.Loopback) TearDownInterface(m, intf);
208*4a64e381SAndroid Build Coastguard Worker+        }
209*4a64e381SAndroid Build Coastguard Worker+    }
210*4a64e381SAndroid Build Coastguard Worker+    else
211*4a64e381SAndroid Build Coastguard Worker+    {
212*4a64e381SAndroid Build Coastguard Worker+        found = mDNSfalse;
213*4a64e381SAndroid Build Coastguard Worker+
214*4a64e381SAndroid Build Coastguard Worker+        for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = (PosixNetworkInterface*)(intf->coreIntf.next))
215*4a64e381SAndroid Build Coastguard Worker+        {
216*4a64e381SAndroid Build Coastguard Worker+            if (intf->coreIntf.Loopback)
217*4a64e381SAndroid Build Coastguard Worker+            {
218*4a64e381SAndroid Build Coastguard Worker+                found = mDNStrue;
219*4a64e381SAndroid Build Coastguard Worker+                break;
220*4a64e381SAndroid Build Coastguard Worker+            }
221*4a64e381SAndroid Build Coastguard Worker+        }
222*4a64e381SAndroid Build Coastguard Worker+
223*4a64e381SAndroid Build Coastguard Worker+        if (!found && (ifa_loop4 != NULL))
224*4a64e381SAndroid Build Coastguard Worker+        {
225*4a64e381SAndroid Build Coastguard Worker+            SetupOneInterface(m, ifa_loop4->ifa_addr, ifa_loop4->ifa_netmask,
226*4a64e381SAndroid Build Coastguard Worker+                              NULL, 0, ifa_loop4->ifa_name, if_nametoindex(ifa_loop4->ifa_name), ifa_loop4->ifa_flags);
227*4a64e381SAndroid Build Coastguard Worker+        }
228*4a64e381SAndroid Build Coastguard Worker+    }
229*4a64e381SAndroid Build Coastguard Worker+
230*4a64e381SAndroid Build Coastguard Worker+    if (ifa_list != NULL) freeifaddrs(ifa_list);
231*4a64e381SAndroid Build Coastguard Worker
232*4a64e381SAndroid Build Coastguard Worker+cleanup:
233*4a64e381SAndroid Build Coastguard Worker     while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL)
234*4a64e381SAndroid Build Coastguard Worker     {
235*4a64e381SAndroid Build Coastguard Worker         RemoveFromList(&changedInterfaces, changedInterface);
236*4a64e381SAndroid Build Coastguard Worker@@ -1947,15 +2113,11 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
237*4a64e381SAndroid Build Coastguard Worker #endif
238*4a64e381SAndroid Build Coastguard Worker }
239*4a64e381SAndroid Build Coastguard Worker
240*4a64e381SAndroid Build Coastguard Worker-// This is used internally by InterfaceChangeCallback.
241*4a64e381SAndroid Build Coastguard Worker-// It's also exported so that the Standalone Responder (mDNSResponderPosix)
242*4a64e381SAndroid Build Coastguard Worker+// This is exported so that the Standalone Responder (mDNSResponderPosix)
243*4a64e381SAndroid Build Coastguard Worker // can call it in response to a SIGHUP (mainly for debugging purposes).
244*4a64e381SAndroid Build Coastguard Worker mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
245*4a64e381SAndroid Build Coastguard Worker {
246*4a64e381SAndroid Build Coastguard Worker     int err;
247*4a64e381SAndroid Build Coastguard Worker-    // This is a pretty heavyweight way to process interface changes --
248*4a64e381SAndroid Build Coastguard Worker-    // destroying the entire interface list and then making fresh one from scratch.
249*4a64e381SAndroid Build Coastguard Worker-    // We should make it like the OS X version, which leaves unchanged interfaces alone.
250*4a64e381SAndroid Build Coastguard Worker     ClearInterfaceList(m);
251*4a64e381SAndroid Build Coastguard Worker     err = SetupInterfaceList(m);
252*4a64e381SAndroid Build Coastguard Worker     return PosixErrorToStatus(err);
253*4a64e381SAndroid Build Coastguard Worker--
254*4a64e381SAndroid Build Coastguard Worker2.41.0
255*4a64e381SAndroid Build Coastguard Worker
256