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