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. @@ -136,7 +136,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. @@ -574,9 +574,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. free(intf);
  107. }
  108. @@ -703,6 +711,29 @@ mDNSlocal int SetupSocket(struct sockadd
  109. if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
  110. }
  111. +#ifdef __linux__
  112. +#ifdef SO_BINDTODEVICE
  113. + if (err == 0 && interfaceIndex)
  114. + {
  115. + char ifname[IFNAMSIZ];
  116. + if (if_indextoname(interfaceIndex, ifname))
  117. + {
  118. + err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
  119. + if (err < 0)
  120. + {
  121. + err = errno;
  122. + perror("setsockopt - SO_BINDTODEVICE");
  123. + }
  124. + }
  125. + else
  126. + {
  127. + err = errno;
  128. + perror("if_indextoname");
  129. + }
  130. + }
  131. +#endif /* SO_BINDTODEVICE */
  132. +#endif /* __linux__ */
  133. +
  134. // And start listening for packets
  135. if (err == 0)
  136. {
  137. @@ -784,6 +815,29 @@ mDNSlocal int SetupSocket(struct sockadd
  138. if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
  139. }
  140. +#ifdef __linux__
  141. +#ifdef SO_BINDTODEVICE
  142. + if (err == 0 && interfaceIndex)
  143. + {
  144. + char ifname[IFNAMSIZ];
  145. + if (if_indextoname(interfaceIndex, ifname))
  146. + {
  147. + err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
  148. + if (err < 0)
  149. + {
  150. + err = errno;
  151. + perror("setsockopt - SO_BINDTODEVICE");
  152. + }
  153. + }
  154. + else
  155. + {
  156. + err = errno;
  157. + perror("if_indextoname");
  158. + }
  159. + }
  160. +#endif /* SO_BINDTODEVICE */
  161. +#endif /* __linux__ */
  162. +
  163. // And start listening for packets
  164. if (err == 0)
  165. {
  166. @@ -815,7 +869,12 @@ mDNSlocal int SetupSocket(struct sockadd
  167. }
  168. // Clean up
  169. - if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
  170. + if (err != 0 && *sktPtr != -1)
  171. + {
  172. + int rv = close(*sktPtr);
  173. + assert(rv == 0);
  174. + *sktPtr = -1;
  175. + }
  176. assert((err == 0) == (*sktPtr != -1));
  177. return err;
  178. }
  179. @@ -994,7 +1053,7 @@ mDNSlocal mStatus OpenIfNotifySocket(int
  180. /* Subscribe the socket to Link & IP addr notifications. */
  181. mDNSPlatformMemZero(&snl, sizeof snl);
  182. snl.nl_family = AF_NETLINK;
  183. - snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
  184. + snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
  185. ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
  186. if (0 == ret)
  187. *pFD = sock;
  188. @@ -1072,11 +1131,18 @@ mDNSlocal mDNSu32 ProcessRoutingNo
  189. PrintNetLinkMsg(pNLMsg);
  190. #endif
  191. + // this result isn't used anywhere as a number, just as
  192. + // non-zero - however, I have seen devices with more than 32
  193. + // interfaces at some point..
  194. + // (on Linux, every tunnel increases index for example)
  195. +
  196. // Process the NetLink message
  197. if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
  198. - result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
  199. + result |= 1;
  200. + // << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
  201. else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
  202. - result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
  203. + result |= 1;
  204. + // << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
  205. // Advance pNLMsg to the next message in the buffer
  206. if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
  207. @@ -1247,8 +1313,12 @@ mDNSexport mStatus mDNSPlatformInit(mDNS
  208. if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
  209. #endif
  210. + // In Linux case, we can't set up sockets with different owner -
  211. + // it blows up SO_REUSEPORT. So we do this step bit later.
  212. +#ifndef __linux__
  213. // Tell mDNS core about the network interfaces on this machine.
  214. if (err == mStatus_NoError) err = SetupInterfaceList(m);
  215. +#endif /* !__linux__ */
  216. // Tell mDNS core about DNS Servers
  217. mDNS_Lock(m);
  218. @@ -1281,9 +1351,17 @@ mDNSexport void mDNSPlatformClose(mDNS *
  219. {
  220. assert(m != NULL);
  221. ClearInterfaceList(m);
  222. - if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
  223. + if (m->p->unicastSocket4 != -1)
  224. + {
  225. + int rv = close(m->p->unicastSocket4);
  226. + assert(rv == 0);
  227. + }
  228. #if HAVE_IPV6
  229. - if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
  230. + if (m->p->unicastSocket6 != -1)
  231. + {
  232. + int rv = close(m->p->unicastSocket6);
  233. + assert(rv == 0);
  234. + }
  235. #endif
  236. }
  237. @@ -1533,14 +1611,14 @@ mDNSexport mStatus mDNSPlatformClearS
  238. mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
  239. {
  240. (void) sock; // unused
  241. -
  242. +
  243. return (mDNSu16)-1;
  244. }
  245. mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
  246. {
  247. (void) InterfaceID; // unused
  248. -
  249. +
  250. return mDNSfalse;
  251. }
  252. --- a/mDNSPosix/mDNSUNP.c
  253. +++ b/mDNSPosix/mDNSUNP.c
  254. @@ -61,154 +61,86 @@
  255. #endif
  256. #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  257. -#include <netdb.h>
  258. -#include <arpa/inet.h>
  259. +#include <sys/types.h>
  260. +#include <ifaddrs.h>
  261. -/* Converts a prefix length to IPv6 network mask */
  262. -void plen_to_mask(int plen, char *addr) {
  263. - int i;
  264. - int colons=7; /* Number of colons in IPv6 address */
  265. - int bits_in_block=16; /* Bits per IPv6 block */
  266. - for(i=0; i<=colons; i++) {
  267. - int block, ones=0xffff, ones_in_block;
  268. - if (plen>bits_in_block) ones_in_block=bits_in_block;
  269. - else ones_in_block=plen;
  270. - block = ones & (ones << (bits_in_block-ones_in_block));
  271. - i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
  272. - plen -= ones_in_block;
  273. - }
  274. -}
  275. -/* Gets IPv6 interface information from the /proc filesystem in linux*/
  276. -struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
  277. +/* Correct way to deal with this is just to use getifaddrs (glibc
  278. + * 2.3.3+ and various BSDs, but BSDs are 'slightly different' just to
  279. + * make life interesting). We assume Linux getifaddrs is available,
  280. + * and if not, please upgrade. */
  281. +struct ifi_info *get_ifi_info_linuxv6(int doaliases)
  282. {
  283. - struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
  284. - FILE *fp;
  285. - char addr[8][5];
  286. - int flags, myflags, index, plen, scope;
  287. - char ifname[9], lastname[IFNAMSIZ];
  288. - char addr6[32+7+1]; /* don't forget the seven ':' */
  289. - struct addrinfo hints, *res0;
  290. - struct sockaddr_in6 *sin6;
  291. - struct in6_addr *addrptr;
  292. - int err;
  293. - int sockfd = -1;
  294. - struct ifreq ifr;
  295. -
  296. - res0=NULL;
  297. - ifihead = NULL;
  298. - ifipnext = &ifihead;
  299. - lastname[0] = 0;
  300. -
  301. - if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
  302. - sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
  303. - if (sockfd < 0) {
  304. - goto gotError;
  305. - }
  306. - while (fscanf(fp,
  307. - "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
  308. - addr[0],addr[1],addr[2],addr[3],
  309. - addr[4],addr[5],addr[6],addr[7],
  310. - &index, &plen, &scope, &flags, ifname) != EOF) {
  311. -
  312. - myflags = 0;
  313. - if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
  314. - if (doaliases == 0)
  315. - continue; /* already processed this interface */
  316. - myflags = IFI_ALIAS;
  317. - }
  318. - memcpy(lastname, ifname, IFNAMSIZ);
  319. - ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
  320. - if (ifi == NULL) {
  321. - goto gotError;
  322. - }
  323. -
  324. - ifipold = *ifipnext; /* need this later */
  325. - ifiptr = ifipnext;
  326. - *ifipnext = ifi; /* prev points to this new one */
  327. - ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
  328. -
  329. - sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
  330. - addr[0],addr[1],addr[2],addr[3],
  331. - addr[4],addr[5],addr[6],addr[7]);
  332. -
  333. - /* Add address of the interface */
  334. - memset(&hints, 0, sizeof(hints));
  335. - hints.ai_family = AF_INET6;
  336. - hints.ai_flags = AI_NUMERICHOST;
  337. - err = getaddrinfo(addr6, NULL, &hints, &res0);
  338. - if (err) {
  339. - goto gotError;
  340. - }
  341. - ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
  342. - if (ifi->ifi_addr == NULL) {
  343. - goto gotError;
  344. - }
  345. - memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
  346. -
  347. - /* Add netmask of the interface */
  348. - char ipv6addr[INET6_ADDRSTRLEN];
  349. - plen_to_mask(plen, ipv6addr);
  350. - ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
  351. - if (ifi->ifi_addr == NULL) {
  352. - goto gotError;
  353. - }
  354. - sin6=calloc(1, sizeof(struct sockaddr_in6));
  355. - addrptr=calloc(1, sizeof(struct in6_addr));
  356. - inet_pton(family, ipv6addr, addrptr);
  357. - sin6->sin6_family=family;
  358. - sin6->sin6_addr=*addrptr;
  359. - sin6->sin6_scope_id=scope;
  360. - memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
  361. - free(sin6);
  362. -
  363. -
  364. - /* Add interface name */
  365. - memcpy(ifi->ifi_name, ifname, IFI_NAME);
  366. -
  367. - /* Add interface index */
  368. - ifi->ifi_index = index;
  369. -
  370. - /* Add interface flags*/
  371. - memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
  372. - if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
  373. - if (errno == EADDRNOTAVAIL) {
  374. - /*
  375. - * If the main interface is configured with no IP address but
  376. - * an alias interface exists with an IP address, you get
  377. - * EADDRNOTAVAIL for the main interface
  378. - */
  379. - free(ifi->ifi_addr);
  380. - free(ifi);
  381. - ifipnext = ifiptr;
  382. - *ifipnext = ifipold;
  383. - continue;
  384. - } else {
  385. - goto gotError;
  386. - }
  387. - }
  388. - ifi->ifi_flags = ifr.ifr_flags;
  389. - freeaddrinfo(res0);
  390. - res0=NULL;
  391. - }
  392. - }
  393. - goto done;
  394. + struct ifaddrs *ifap, *ifa;
  395. + struct ifi_info *ifi = NULL, *head = NULL;
  396. -gotError:
  397. - if (ifihead != NULL) {
  398. - free_ifi_info(ifihead);
  399. - ifihead = NULL;
  400. - }
  401. - if (res0 != NULL) {
  402. - freeaddrinfo(res0);
  403. - res0=NULL;
  404. + /* doaliases seems always true in the calls in current code */
  405. + assert(doaliases);
  406. +
  407. + if (getifaddrs(&ifap) < 0)
  408. + {
  409. + return NULL;
  410. }
  411. -done:
  412. - if (sockfd != -1) {
  413. - assert(close(sockfd) == 0);
  414. + for (ifa = ifap ; ifa ; ifa = ifa->ifa_next)
  415. + {
  416. + /* Care only about IPv6 addresses on non-point-to-point links. */
  417. + if (!ifa->ifa_addr
  418. + || ifa->ifa_addr->sa_family != AF_INET6)
  419. + continue;
  420. + ifi = calloc(1, sizeof(*ifi));
  421. + if (!ifi)
  422. + break;
  423. + strncpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME);
  424. + /* We ignore ifi_{haddr,hlen}, everyone else does too */
  425. + ifi->ifi_flags = ifa->ifa_flags;
  426. + /* We ignore ifi_myflags; IFI_ALIAS isn't used anywhere */
  427. + ifi->ifi_index = if_nametoindex(ifa->ifa_name);
  428. + if (!(ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6))))
  429. + break;
  430. + memcpy(ifi->ifi_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6));
  431. +
  432. + if (ifa->ifa_netmask)
  433. + {
  434. + if (!(ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in6))))
  435. + break;
  436. + memcpy(ifi->ifi_netmask, ifa->ifa_netmask,
  437. + sizeof(struct sockaddr_in6));
  438. + }
  439. +
  440. + if (!(ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6))))
  441. + break;
  442. + memcpy(ifi->ifi_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6));
  443. +
  444. +
  445. + if (ifa->ifa_flags & IFF_POINTOPOINT && ifa->ifa_dstaddr)
  446. + {
  447. + if (!(ifi->ifi_dstaddr = malloc(sizeof(struct sockaddr_in6))))
  448. + break;
  449. + memcpy(ifi->ifi_dstaddr, ifa->ifa_dstaddr,
  450. + sizeof(struct sockaddr_in6));
  451. + }
  452. + else if (ifa->ifa_broadaddr)
  453. + {
  454. + if (!(ifi->ifi_brdaddr = malloc(sizeof(struct sockaddr_in6))))
  455. + break;
  456. + memcpy(ifi->ifi_brdaddr, ifa->ifa_broadaddr,
  457. + sizeof(struct sockaddr_in6));
  458. + }
  459. + ifi->ifi_next = head;
  460. + head = ifi;
  461. + ifi = NULL;
  462. + };
  463. + if (ifi)
  464. + {
  465. + /* An error occurred. Let's bail out. */
  466. + ifi->ifi_next = head;
  467. + free_ifi_info(head);
  468. + return NULL;
  469. }
  470. - return(ifihead); /* pointer to first structure in linked list */
  471. + freeifaddrs(ifap);
  472. + return head;
  473. }
  474. +
  475. #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  476. struct ifi_info *get_ifi_info(int family, int doaliases)
  477. @@ -229,7 +161,7 @@ struct ifi_info *get_ifi_info(int family
  478. #endif
  479. #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  480. - if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
  481. + if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
  482. #endif
  483. sockfd = -1;
  484. --- a/mDNSPosix/mDNSUNP.h
  485. +++ b/mDNSPosix/mDNSUNP.h
  486. @@ -97,8 +97,7 @@ struct ifi_info {
  487. };
  488. #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
  489. -#define PROC_IFINET6_PATH "/proc/net/if_inet6"
  490. -extern struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases);
  491. +extern struct ifi_info *get_ifi_info_linuxv6(int doaliases);
  492. #endif
  493. #if defined(AF_INET6) && HAVE_IPV6
  494. --- a/mDNSShared/dnsextd_parser.y
  495. +++ b/mDNSShared/dnsextd_parser.y
  496. @@ -15,6 +15,8 @@
  497. * limitations under the License.
  498. */
  499. +%parse-param { void *context }
  500. +
  501. %{
  502. #include <stdio.h>
  503. #include <stdlib.h>
  504. @@ -23,7 +25,7 @@
  505. #include "DebugServices.h"
  506. #include "dnsextd.h"
  507. -void yyerror( const char* error );
  508. +void yyerror( void *context, const char* error );
  509. int yylex(void);
  510. @@ -378,7 +380,7 @@ int yywrap(void);
  511. extern int yylineno;
  512. -void yyerror( const char *str )
  513. +void yyerror( void *context, const char *str )
  514. {
  515. fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str );
  516. }