You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

549 lines
18 KiB

  1. --- /dev/null
  2. +++ b/.gitignore
  3. @@ -0,0 +1,4 @@
  4. +Clients/build
  5. +mDNSPosix/build
  6. +mDNSPosix/objects
  7. +
  8. --- a/mDNSPosix/PosixDaemon.c
  9. +++ b/mDNSPosix/PosixDaemon.c
  10. @@ -37,6 +37,11 @@
  11. #include <fcntl.h>
  12. #include <pwd.h>
  13. #include <sys/types.h>
  14. +#ifdef __linux__
  15. +#include <sys/capability.h> /* !!! We require libcap-dev for this. Oh well. */
  16. +/* prctl is required to enable inheriting of capabilities across setuid */
  17. +#include <sys/prctl.h>
  18. +#endif /* __linux__ */
  19. #if __APPLE__
  20. #undef daemon
  21. @@ -184,16 +189,50 @@ int main(int argc, char **argv)
  22. Reconfigure(&mDNSStorage);
  23. +#ifdef __linux__
  24. + /*
  25. + * SO_BINDTODEVICE is privileged operation; however, we can get
  26. + * around it using capabilities instead of remaining root.
  27. + */
  28. + if (mStatus_NoError == err)
  29. + {
  30. + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0)
  31. + perror("prctl PR_SET_KEEPCAPS");
  32. + }
  33. +#endif /* __linux__ */
  34. +
  35. // Now that we're finished with anything privileged, switch over to running as "nobody"
  36. if (mStatus_NoError == err)
  37. {
  38. const struct passwd *pw = getpwnam("nobody");
  39. if (pw != NULL)
  40. + {
  41. setuid(pw->pw_uid);
  42. +#ifdef __linux__
  43. + struct __user_cap_header_struct ch;
  44. + struct __user_cap_data_struct cd[_LINUX_CAPABILITY_U32S_3];
  45. +
  46. + memset(&ch, 0, sizeof(ch));
  47. + ch.version = _LINUX_CAPABILITY_VERSION_3;
  48. + ch.pid = getpid();
  49. + memset(&cd[0], 0, sizeof(cd));
  50. + /* CAP_NET_RAW is required to use SO_BINDTODEVICE */
  51. + int caps = CAP_TO_MASK(CAP_NET_RAW);
  52. + cd[0].permitted = caps;
  53. + cd[0].effective = caps;
  54. + if (capset(&ch, &cd[0]) < 0)
  55. + perror("capset");
  56. +#endif /* __linux__ */
  57. + }
  58. else
  59. LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
  60. }
  61. +#ifdef __linux__
  62. + if (mStatus_NoError == err)
  63. + err = mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage);
  64. +#endif /* __linux__ */
  65. +
  66. if (mStatus_NoError == err)
  67. err = MainLoop(&mDNSStorage);
  68. --- a/mDNSPosix/Responder.c
  69. +++ b/mDNSPosix/Responder.c
  70. @@ -603,7 +603,8 @@ static mStatus RegisterServicesInFile(co
  71. status = mStatus_UnknownErr;
  72. }
  73. - assert(0 == fclose(fp));
  74. + int rv = fclose(fp);
  75. + assert(0 == rv);
  76. return status;
  77. }
  78. --- a/mDNSPosix/mDNSPosix.c
  79. +++ b/mDNSPosix/mDNSPosix.c
  80. @@ -138,7 +138,7 @@ mDNSlocal void SockAddrTomDNSAddr(const
  81. // mDNS core calls this routine when it needs to send a packet.
  82. mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
  83. - mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
  84. + mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
  85. mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
  86. {
  87. int err = 0;
  88. @@ -583,9 +583,17 @@ mDNSlocal void FreePosixNetworkInterface
  89. {
  90. assert(intf != NULL);
  91. if (intf->intfName != NULL) free((void *)intf->intfName);
  92. - if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
  93. + if (intf->multicastSocket4 != -1)
  94. + {
  95. + int rv = close(intf->multicastSocket4);
  96. + assert(rv == 0);
  97. + }
  98. #if HAVE_IPV6
  99. - if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
  100. + if (intf->multicastSocket6 != -1)
  101. + {
  102. + int rv = close(intf->multicastSocket6);
  103. + assert(rv == 0);
  104. + }
  105. #endif
  106. // Move interface to the RecentInterfaces list for a minute
  107. @@ -724,6 +732,29 @@ mDNSlocal int SetupSocket(struct sockadd
  108. if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
  109. }
  110. +#ifdef __linux__
  111. +#ifdef SO_BINDTODEVICE
  112. + if (err == 0 && interfaceIndex)
  113. + {
  114. + char ifname[IFNAMSIZ];
  115. + if (if_indextoname(interfaceIndex, ifname))
  116. + {
  117. + err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
  118. + if (err < 0)
  119. + {
  120. + err = errno;
  121. + perror("setsockopt - SO_BINDTODEVICE");
  122. + }
  123. + }
  124. + else
  125. + {
  126. + err = errno;
  127. + perror("if_indextoname");
  128. + }
  129. + }
  130. +#endif /* SO_BINDTODEVICE */
  131. +#endif /* __linux__ */
  132. +
  133. // And start listening for packets
  134. if (err == 0)
  135. {
  136. @@ -805,6 +836,29 @@ mDNSlocal int SetupSocket(struct sockadd
  137. if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
  138. }
  139. +#ifdef __linux__
  140. +#ifdef SO_BINDTODEVICE
  141. + if (err == 0 && interfaceIndex)
  142. + {
  143. + char ifname[IFNAMSIZ];
  144. + if (if_indextoname(interfaceIndex, ifname))
  145. + {
  146. + err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
  147. + if (err < 0)
  148. + {
  149. + err = errno;
  150. + perror("setsockopt - SO_BINDTODEVICE");
  151. + }
  152. + }
  153. + else
  154. + {
  155. + err = errno;
  156. + perror("if_indextoname");
  157. + }
  158. + }
  159. +#endif /* SO_BINDTODEVICE */
  160. +#endif /* __linux__ */
  161. +
  162. // And start listening for packets
  163. if (err == 0)
  164. {
  165. @@ -836,7 +890,12 @@ mDNSlocal int SetupSocket(struct sockadd
  166. }
  167. // Clean up
  168. - if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
  169. + if (err != 0 && *sktPtr != -1)
  170. + {
  171. + int rv = close(*sktPtr);
  172. + assert(rv == 0);
  173. + *sktPtr = -1;
  174. + }
  175. assert((err == 0) == (*sktPtr != -1));
  176. return err;
  177. }
  178. @@ -1026,7 +1085,7 @@ mDNSlocal mStatus OpenIfNotifySocket(int
  179. /* Subscribe the socket to Link & IP addr notifications. */
  180. mDNSPlatformMemZero(&snl, sizeof snl);
  181. snl.nl_family = AF_NETLINK;
  182. - snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
  183. + snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
  184. ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
  185. if (0 == ret)
  186. *pFD = sock;
  187. @@ -1104,11 +1163,18 @@ mDNSlocal mDNSu32 ProcessRoutingNo
  188. PrintNetLinkMsg(pNLMsg);
  189. #endif
  190. + // this result isn't used anywhere as a number, just as
  191. + // non-zero - however, I have seen devices with more than 32
  192. + // interfaces at some point..
  193. + // (on Linux, every tunnel increases index for example)
  194. +
  195. // Process the NetLink message
  196. if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
  197. - result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
  198. + result |= 1;
  199. + // << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
  200. else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
  201. - result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
  202. + result |= 1;
  203. + // << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
  204. // Advance pNLMsg to the next message in the buffer
  205. if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
  206. @@ -1279,8 +1345,12 @@ mDNSexport mStatus mDNSPlatformInit(mDNS
  207. if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
  208. #endif
  209. + // In Linux case, we can't set up sockets with different owner -
  210. + // it blows up SO_REUSEPORT. So we do this step bit later.
  211. +#ifndef __linux__
  212. // Tell mDNS core about the network interfaces on this machine.
  213. if (err == mStatus_NoError) err = SetupInterfaceList(m);
  214. +#endif /* !__linux__ */
  215. // Tell mDNS core about DNS Servers
  216. mDNS_Lock(m);
  217. @@ -1313,9 +1383,17 @@ mDNSexport void mDNSPlatformClose(mDNS *
  218. {
  219. assert(m != NULL);
  220. ClearInterfaceList(m);
  221. - if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
  222. + if (m->p->unicastSocket4 != -1)
  223. + {
  224. + int rv = close(m->p->unicastSocket4);
  225. + assert(rv == 0);
  226. + }
  227. #if HAVE_IPV6
  228. - if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
  229. + if (m->p->unicastSocket6 != -1)
  230. + {
  231. + int rv = close(m->p->unicastSocket6);
  232. + assert(rv == 0);
  233. + }
  234. #endif
  235. }
  236. @@ -1571,14 +1649,14 @@ mDNSexport mStatus mDNSPlatformClearS
  237. mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
  238. {
  239. (void) sock; // unused
  240. -
  241. +
  242. return (mDNSu16)-1;
  243. }
  244. mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
  245. {
  246. (void) InterfaceID; // unused
  247. -
  248. +
  249. return mDNSfalse;
  250. }
  251. --- a/mDNSPosix/mDNSUNP.c
  252. +++ b/mDNSPosix/mDNSUNP.c
  253. @@ -61,154 +61,86 @@
  254. #endif
  255. #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  256. -#include <netdb.h>
  257. -#include <arpa/inet.h>
  258. +#include <sys/types.h>
  259. +#include <ifaddrs.h>
  260. -/* Converts a prefix length to IPv6 network mask */
  261. -void plen_to_mask(int plen, char *addr) {
  262. - int i;
  263. - int colons=7; /* Number of colons in IPv6 address */
  264. - int bits_in_block=16; /* Bits per IPv6 block */
  265. - for(i=0; i<=colons; i++) {
  266. - int block, ones=0xffff, ones_in_block;
  267. - if (plen>bits_in_block) ones_in_block=bits_in_block;
  268. - else ones_in_block=plen;
  269. - block = ones & (ones << (bits_in_block-ones_in_block));
  270. - i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
  271. - plen -= ones_in_block;
  272. - }
  273. -}
  274. -/* Gets IPv6 interface information from the /proc filesystem in linux*/
  275. -struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
  276. +/* Correct way to deal with this is just to use getifaddrs (glibc
  277. + * 2.3.3+ and various BSDs, but BSDs are 'slightly different' just to
  278. + * make life interesting). We assume Linux getifaddrs is available,
  279. + * and if not, please upgrade. */
  280. +struct ifi_info *get_ifi_info_linuxv6(int doaliases)
  281. {
  282. - struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
  283. - FILE *fp;
  284. - char addr[8][5];
  285. - int flags, myflags, index, plen, scope;
  286. - char ifname[9], lastname[IFNAMSIZ];
  287. - char addr6[32+7+1]; /* don't forget the seven ':' */
  288. - struct addrinfo hints, *res0;
  289. - struct sockaddr_in6 *sin6;
  290. - struct in6_addr *addrptr;
  291. - int err;
  292. - int sockfd = -1;
  293. - struct ifreq ifr;
  294. -
  295. - res0=NULL;
  296. - ifihead = NULL;
  297. - ifipnext = &ifihead;
  298. - lastname[0] = 0;
  299. -
  300. - if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
  301. - sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
  302. - if (sockfd < 0) {
  303. - goto gotError;
  304. - }
  305. - while (fscanf(fp,
  306. - "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
  307. - addr[0],addr[1],addr[2],addr[3],
  308. - addr[4],addr[5],addr[6],addr[7],
  309. - &index, &plen, &scope, &flags, ifname) != EOF) {
  310. -
  311. - myflags = 0;
  312. - if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
  313. - if (doaliases == 0)
  314. - continue; /* already processed this interface */
  315. - myflags = IFI_ALIAS;
  316. - }
  317. - memcpy(lastname, ifname, IFNAMSIZ);
  318. - ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
  319. - if (ifi == NULL) {
  320. - goto gotError;
  321. - }
  322. -
  323. - ifipold = *ifipnext; /* need this later */
  324. - ifiptr = ifipnext;
  325. - *ifipnext = ifi; /* prev points to this new one */
  326. - ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
  327. -
  328. - sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
  329. - addr[0],addr[1],addr[2],addr[3],
  330. - addr[4],addr[5],addr[6],addr[7]);
  331. -
  332. - /* Add address of the interface */
  333. - memset(&hints, 0, sizeof(hints));
  334. - hints.ai_family = AF_INET6;
  335. - hints.ai_flags = AI_NUMERICHOST;
  336. - err = getaddrinfo(addr6, NULL, &hints, &res0);
  337. - if (err) {
  338. - goto gotError;
  339. - }
  340. - ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
  341. - if (ifi->ifi_addr == NULL) {
  342. - goto gotError;
  343. - }
  344. - memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
  345. -
  346. - /* Add netmask of the interface */
  347. - char ipv6addr[INET6_ADDRSTRLEN];
  348. - plen_to_mask(plen, ipv6addr);
  349. - ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
  350. - if (ifi->ifi_addr == NULL) {
  351. - goto gotError;
  352. - }
  353. - sin6=calloc(1, sizeof(struct sockaddr_in6));
  354. - addrptr=calloc(1, sizeof(struct in6_addr));
  355. - inet_pton(family, ipv6addr, addrptr);
  356. - sin6->sin6_family=family;
  357. - sin6->sin6_addr=*addrptr;
  358. - sin6->sin6_scope_id=scope;
  359. - memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
  360. - free(sin6);
  361. -
  362. -
  363. - /* Add interface name */
  364. - memcpy(ifi->ifi_name, ifname, IFI_NAME);
  365. -
  366. - /* Add interface index */
  367. - ifi->ifi_index = index;
  368. -
  369. - /* Add interface flags*/
  370. - memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
  371. - if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
  372. - if (errno == EADDRNOTAVAIL) {
  373. - /*
  374. - * If the main interface is configured with no IP address but
  375. - * an alias interface exists with an IP address, you get
  376. - * EADDRNOTAVAIL for the main interface
  377. - */
  378. - free(ifi->ifi_addr);
  379. - free(ifi);
  380. - ifipnext = ifiptr;
  381. - *ifipnext = ifipold;
  382. - continue;
  383. - } else {
  384. - goto gotError;
  385. - }
  386. - }
  387. - ifi->ifi_flags = ifr.ifr_flags;
  388. - freeaddrinfo(res0);
  389. - res0=NULL;
  390. - }
  391. - }
  392. - goto done;
  393. + struct ifaddrs *ifap, *ifa;
  394. + struct ifi_info *ifi = NULL, *head = NULL;
  395. -gotError:
  396. - if (ifihead != NULL) {
  397. - free_ifi_info(ifihead);
  398. - ifihead = NULL;
  399. - }
  400. - if (res0 != NULL) {
  401. - freeaddrinfo(res0);
  402. - res0=NULL;
  403. + /* doaliases seems always true in the calls in current code */
  404. + assert(doaliases);
  405. +
  406. + if (getifaddrs(&ifap) < 0)
  407. + {
  408. + return NULL;
  409. }
  410. -done:
  411. - if (sockfd != -1) {
  412. - assert(close(sockfd) == 0);
  413. + for (ifa = ifap ; ifa ; ifa = ifa->ifa_next)
  414. + {
  415. + /* Care only about IPv6 addresses on non-point-to-point links. */
  416. + if (!ifa->ifa_addr
  417. + || ifa->ifa_addr->sa_family != AF_INET6)
  418. + continue;
  419. + ifi = calloc(1, sizeof(*ifi));
  420. + if (!ifi)
  421. + break;
  422. + strncpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME);
  423. + /* We ignore ifi_{haddr,hlen}, everyone else does too */
  424. + ifi->ifi_flags = ifa->ifa_flags;
  425. + /* We ignore ifi_myflags; IFI_ALIAS isn't used anywhere */
  426. + ifi->ifi_index = if_nametoindex(ifa->ifa_name);
  427. + if (!(ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6))))
  428. + break;
  429. + memcpy(ifi->ifi_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6));
  430. +
  431. + if (ifa->ifa_netmask)
  432. + {
  433. + if (!(ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in6))))
  434. + break;
  435. + memcpy(ifi->ifi_netmask, ifa->ifa_netmask,
  436. + sizeof(struct sockaddr_in6));
  437. + }
  438. +
  439. + if (!(ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6))))
  440. + break;
  441. + memcpy(ifi->ifi_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6));
  442. +
  443. +
  444. + if (ifa->ifa_flags & IFF_POINTOPOINT && ifa->ifa_dstaddr)
  445. + {
  446. + if (!(ifi->ifi_dstaddr = malloc(sizeof(struct sockaddr_in6))))
  447. + break;
  448. + memcpy(ifi->ifi_dstaddr, ifa->ifa_dstaddr,
  449. + sizeof(struct sockaddr_in6));
  450. + }
  451. + else if (ifa->ifa_broadaddr)
  452. + {
  453. + if (!(ifi->ifi_brdaddr = malloc(sizeof(struct sockaddr_in6))))
  454. + break;
  455. + memcpy(ifi->ifi_brdaddr, ifa->ifa_broadaddr,
  456. + sizeof(struct sockaddr_in6));
  457. + }
  458. + ifi->ifi_next = head;
  459. + head = ifi;
  460. + ifi = NULL;
  461. + };
  462. + if (ifi)
  463. + {
  464. + /* An error occurred. Let's bail out. */
  465. + ifi->ifi_next = head;
  466. + free_ifi_info(head);
  467. + return NULL;
  468. }
  469. - return(ifihead); /* pointer to first structure in linked list */
  470. + freeifaddrs(ifap);
  471. + return head;
  472. }
  473. +
  474. #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  475. struct ifi_info *get_ifi_info(int family, int doaliases)
  476. @@ -229,7 +161,7 @@ struct ifi_info *get_ifi_info(int family
  477. #endif
  478. #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  479. - if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
  480. + if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
  481. #endif
  482. sockfd = -1;
  483. --- a/mDNSPosix/mDNSUNP.h
  484. +++ b/mDNSPosix/mDNSUNP.h
  485. @@ -97,8 +97,7 @@ struct ifi_info {
  486. };
  487. #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  488. -#define PROC_IFINET6_PATH "/proc/net/if_inet6"
  489. -extern struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases);
  490. +extern struct ifi_info *get_ifi_info_linuxv6(int doaliases);
  491. #endif
  492. #if defined(AF_INET6) && HAVE_IPV6
  493. --- a/mDNSShared/dnsextd_parser.y
  494. +++ b/mDNSShared/dnsextd_parser.y
  495. @@ -15,6 +15,8 @@
  496. * limitations under the License.
  497. */
  498. +%parse-param { void *context }
  499. +
  500. %{
  501. #include <stdio.h>
  502. #include <stdlib.h>
  503. @@ -23,7 +25,7 @@
  504. #include "DebugServices.h"
  505. #include "dnsextd.h"
  506. -void yyerror( const char* error );
  507. +void yyerror( void *context, const char* error );
  508. int yylex(void);
  509. @@ -378,7 +380,7 @@ int yywrap(void);
  510. extern int yylineno;
  511. -void yyerror( const char *str )
  512. +void yyerror( void *context, const char *str )
  513. {
  514. fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str );
  515. }