]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSUNP.c
mDNSResponder-878.200.35.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / mDNSUNP.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "mDNSUNP.h"
19
20 #include <errno.h>
21 #include <assert.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/uio.h>
25 #include <sys/ioctl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <stdio.h>
29
30 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
31 macro, usually defined in <sys/param.h> or someplace like that, to make sure the
32 CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
33 should be set to the name of the header to include to get the ALIGN(P) macro.
34 */
35 #ifdef NEED_ALIGN_MACRO
36 #include NEED_ALIGN_MACRO
37 #endif
38
39 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
40 other platforms don't even have that include file. So,
41 if we haven't yet got a definition, let's try to find
42 <sys/sockio.h>.
43 */
44
45 #ifndef SIOCGIFCONF
46 #include <sys/sockio.h>
47 #endif
48
49 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
50 so only include the header in that case.
51 */
52
53 #ifdef IP_RECVIF
54 #include <net/if_dl.h>
55 #endif
56
57 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
58 #include <net/if_var.h>
59 #include <netinet/in_var.h>
60 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
61 #endif
62
63 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
64 #include <netdb.h>
65 #include <arpa/inet.h>
66
67 /* Converts a prefix length to IPv6 network mask */
68 void plen_to_mask(int plen, char *addr) {
69 int i;
70 int colons=7; /* Number of colons in IPv6 address */
71 int bits_in_block=16; /* Bits per IPv6 block */
72 for(i=0; i<=colons; i++) {
73 int block, ones=0xffff, ones_in_block;
74 if (plen>bits_in_block) ones_in_block=bits_in_block;
75 else ones_in_block=plen;
76 block = ones & (ones << (bits_in_block-ones_in_block));
77 i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
78 plen -= ones_in_block;
79 }
80 }
81
82 /* Gets IPv6 interface information from the /proc filesystem in linux*/
83 struct ifi_info *get_ifi_info_linuxv6(int doaliases)
84 {
85 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
86 FILE *fp = NULL;
87 int i, nitems, flags, index, plen, scope;
88 struct addrinfo hints, *res0;
89 int err;
90 int sockfd = -1;
91 struct ifreq ifr;
92 char ifnameFmt[16], addrStr[32 + 7 + 1], ifname[IFNAMSIZ], lastname[IFNAMSIZ];
93
94 res0=NULL;
95 ifihead = NULL;
96 ifipnext = &ifihead;
97
98 if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
99 sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
100 if (sockfd < 0) {
101 goto gotError;
102 }
103
104 // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>.
105
106 // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The
107 // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width
108 // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For
109 // example, it could be defined in hexadecimal or as an arithmetic expression.
110
111 snprintf(ifnameFmt, sizeof(ifnameFmt), "%%%ds", IFNAMSIZ - 1);
112
113 // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx".
114 // The remaining 32 IPv6 address characters come from /proc/net/if_inet6.
115
116 for (i = 4; i < 39; i += 5) addrStr[i] = ':';
117 addrStr[39] = '\0';
118
119 lastname[0] = '\0';
120 for (;;) {
121 nitems = fscanf(fp, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x",
122 &addrStr[0], &addrStr[5], &addrStr[10], &addrStr[15],
123 &addrStr[20], &addrStr[25], &addrStr[30], &addrStr[35],
124 &index, &plen, &scope, &flags);
125 if (nitems != 12) break;
126
127 nitems = fscanf(fp, ifnameFmt, ifname);
128 if (nitems != 1) break;
129
130 if (strcmp(lastname, ifname) == 0) {
131 if (doaliases == 0)
132 continue; /* already processed this interface */
133 }
134 memcpy(lastname, ifname, IFNAMSIZ);
135 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
136 if (ifi == NULL) {
137 goto gotError;
138 }
139
140 ifipold = *ifipnext; /* need this later */
141 ifiptr = ifipnext;
142 *ifipnext = ifi; /* prev points to this new one */
143 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
144
145 /* Add address of the interface */
146 memset(&hints, 0, sizeof(hints));
147 hints.ai_family = AF_INET6;
148 hints.ai_flags = AI_NUMERICHOST;
149 err = getaddrinfo(addrStr, NULL, &hints, &res0);
150 if (err) {
151 goto gotError;
152 }
153 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
154 if (ifi->ifi_addr == NULL) {
155 goto gotError;
156 }
157 memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
158
159 /* Add netmask of the interface */
160 char ipv6addr[INET6_ADDRSTRLEN];
161 plen_to_mask(plen, ipv6addr);
162 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
163 if (ifi->ifi_netmask == NULL) {
164 goto gotError;
165 }
166
167 ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=AF_INET6;
168 ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
169 inet_pton(AF_INET6, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
170
171 /* Add interface name */
172 memcpy(ifi->ifi_name, ifname, IFI_NAME);
173
174 /* Add interface index */
175 ifi->ifi_index = index;
176
177 /* Add interface flags*/
178 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
179 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
180 if (errno == EADDRNOTAVAIL) {
181 /*
182 * If the main interface is configured with no IP address but
183 * an alias interface exists with an IP address, you get
184 * EADDRNOTAVAIL for the main interface
185 */
186 free(ifi->ifi_addr);
187 free(ifi->ifi_netmask);
188 free(ifi);
189 ifipnext = ifiptr;
190 *ifipnext = ifipold;
191 continue;
192 } else {
193 goto gotError;
194 }
195 }
196 ifi->ifi_flags = ifr.ifr_flags;
197 freeaddrinfo(res0);
198 res0=NULL;
199 }
200 }
201 goto done;
202
203 gotError:
204 if (ifihead != NULL) {
205 free_ifi_info(ifihead);
206 ifihead = NULL;
207 }
208 if (res0 != NULL) {
209 freeaddrinfo(res0);
210 res0=NULL;
211 }
212 done:
213 if (sockfd != -1) {
214 int rv;
215 rv = close(sockfd);
216 assert(rv == 0);
217 }
218 if (fp != NULL) {
219 fclose(fp);
220 }
221 return(ifihead); /* pointer to first structure in linked list */
222 }
223 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
224
225 struct ifi_info *get_ifi_info(int family, int doaliases)
226 {
227 int junk;
228 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
229 int sockfd, sockf6, len, lastlen, flags, myflags;
230 #ifdef NOT_HAVE_IF_NAMETOINDEX
231 int index = 200;
232 #endif
233 char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
234 struct ifconf ifc;
235 struct ifreq *ifr, ifrcopy;
236 struct sockaddr_in *sinptr;
237
238 #if defined(AF_INET6) && HAVE_IPV6
239 struct sockaddr_in6 *sinptr6;
240 #endif
241
242 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
243 if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
244 #endif
245
246 sockfd = -1;
247 sockf6 = -1;
248 buf = NULL;
249 ifihead = NULL;
250
251 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
252 if (sockfd < 0) {
253 goto gotError;
254 }
255
256 lastlen = 0;
257 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
258 for ( ; ; ) {
259 buf = (char*)malloc(len);
260 if (buf == NULL) {
261 goto gotError;
262 }
263 ifc.ifc_len = len;
264 ifc.ifc_buf = buf;
265 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
266 if (errno != EINVAL || lastlen != 0) {
267 goto gotError;
268 }
269 } else {
270 if (ifc.ifc_len == lastlen)
271 break; /* success, len has not changed */
272 lastlen = ifc.ifc_len;
273 }
274 len += 10 * sizeof(struct ifreq); /* increment */
275 free(buf);
276 }
277 ifihead = NULL;
278 ifipnext = &ifihead;
279 lastname[0] = 0;
280 /* end get_ifi_info1 */
281
282 /* include get_ifi_info2 */
283 for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
284 ifr = (struct ifreq *) ptr;
285
286 /* Advance to next one in buffer */
287 if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
288 ptr += sizeof(struct ifreq);
289 else
290 ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
291
292 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
293
294 if (ifr->ifr_addr.sa_family != family)
295 continue; /* ignore if not desired address family */
296
297 myflags = 0;
298 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
299 *cptr = 0; /* replace colon will null */
300 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
301 if (doaliases == 0)
302 continue; /* already processed this interface */
303 myflags = IFI_ALIAS;
304 }
305 memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
306
307 ifrcopy = *ifr;
308 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
309 goto gotError;
310 }
311
312 flags = ifrcopy.ifr_flags;
313 if ((flags & IFF_UP) == 0)
314 continue; /* ignore if interface not up */
315
316 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
317 if (ifi == NULL) {
318 goto gotError;
319 }
320 ifipold = *ifipnext; /* need this later */
321 ifiptr = ifipnext;
322 *ifipnext = ifi; /* prev points to this new one */
323 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
324
325 ifi->ifi_flags = flags; /* IFF_xxx values */
326 ifi->ifi_myflags = myflags; /* IFI_xxx values */
327 #ifndef NOT_HAVE_IF_NAMETOINDEX
328 ifi->ifi_index = if_nametoindex(ifr->ifr_name);
329 #else
330 ifrcopy = *ifr;
331 #ifdef SIOCGIFINDEX
332 if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
333 ifi->ifi_index = ifrcopy.ifr_index;
334 else
335 #endif
336 ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
337 #endif
338 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
339 ifi->ifi_name[IFI_NAME-1] = '\0';
340 /* end get_ifi_info2 */
341 /* include get_ifi_info3 */
342 switch (ifr->ifr_addr.sa_family) {
343 case AF_INET:
344 sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
345 if (ifi->ifi_addr == NULL) {
346 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
347 if (ifi->ifi_addr == NULL) {
348 goto gotError;
349 }
350 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
351
352 #ifdef SIOCGIFNETMASK
353 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
354 if (errno == EADDRNOTAVAIL) {
355 /*
356 * If the main interface is configured with no IP address but
357 * an alias interface exists with an IP address, you get
358 * EADDRNOTAVAIL for the main interface
359 */
360 free(ifi->ifi_addr);
361 free(ifi);
362 ifipnext = ifiptr;
363 *ifipnext = ifipold;
364 continue;
365 } else {
366 goto gotError;
367 }
368 }
369
370 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
371 if (ifi->ifi_netmask == NULL) goto gotError;
372 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
373 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
374 #ifndef NOT_HAVE_SA_LEN
375 sinptr->sin_len = sizeof(struct sockaddr_in);
376 #endif
377 sinptr->sin_family = AF_INET;
378 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
379 #endif
380
381 #ifdef SIOCGIFBRDADDR
382 if (flags & IFF_BROADCAST) {
383 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
384 goto gotError;
385 }
386 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
387 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
388 #ifndef NOT_HAVE_SA_LEN
389 sinptr->sin_len = sizeof( struct sockaddr_in );
390 #endif
391 sinptr->sin_family = AF_INET;
392 ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
393 if (ifi->ifi_brdaddr == NULL) {
394 goto gotError;
395 }
396 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
397 }
398 #endif
399
400 #ifdef SIOCGIFDSTADDR
401 if (flags & IFF_POINTOPOINT) {
402 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
403 goto gotError;
404 }
405 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
406 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
407 #ifndef NOT_HAVE_SA_LEN
408 sinptr->sin_len = sizeof( struct sockaddr_in );
409 #endif
410 sinptr->sin_family = AF_INET;
411 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
412 if (ifi->ifi_dstaddr == NULL) {
413 goto gotError;
414 }
415 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
416 }
417 #endif
418 }
419 break;
420
421 #if defined(AF_INET6) && HAVE_IPV6
422 case AF_INET6:
423 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
424 if (ifi->ifi_addr == NULL) {
425 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
426 if (ifi->ifi_addr == NULL) {
427 goto gotError;
428 }
429
430 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
431 /* We need to strip that out */
432 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
433 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
434 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
435
436 #ifdef SIOCGIFNETMASK_IN6
437 {
438 struct in6_ifreq ifr6;
439 if (sockf6 == -1)
440 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
441 memset(&ifr6, 0, sizeof(ifr6));
442 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
443 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
444 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
445 if (errno == EADDRNOTAVAIL) {
446 /*
447 * If the main interface is configured with no IP address but
448 * an alias interface exists with an IP address, you get
449 * EADDRNOTAVAIL for the main interface
450 */
451 free(ifi->ifi_addr);
452 free(ifi);
453 ifipnext = ifiptr;
454 *ifipnext = ifipold;
455 continue;
456 } else {
457 goto gotError;
458 }
459 }
460 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
461 if (ifi->ifi_netmask == NULL) goto gotError;
462 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
463 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
464 }
465 #endif
466 }
467 break;
468 #endif
469
470 default:
471 break;
472 }
473 }
474 goto done;
475
476 gotError:
477 if (ifihead != NULL) {
478 free_ifi_info(ifihead);
479 ifihead = NULL;
480 }
481
482 done:
483 if (buf != NULL) {
484 free(buf);
485 }
486 if (sockfd != -1) {
487 junk = close(sockfd);
488 assert(junk == 0);
489 }
490 if (sockf6 != -1) {
491 junk = close(sockf6);
492 assert(junk == 0);
493 }
494 return(ifihead); /* pointer to first structure in linked list */
495 }
496 /* end get_ifi_info3 */
497
498 /* include free_ifi_info */
499 void
500 free_ifi_info(struct ifi_info *ifihead)
501 {
502 struct ifi_info *ifi, *ifinext;
503
504 for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
505 if (ifi->ifi_addr != NULL)
506 free(ifi->ifi_addr);
507 if (ifi->ifi_netmask != NULL)
508 free(ifi->ifi_netmask);
509 if (ifi->ifi_brdaddr != NULL)
510 free(ifi->ifi_brdaddr);
511 if (ifi->ifi_dstaddr != NULL)
512 free(ifi->ifi_dstaddr);
513 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
514 free(ifi); /* the ifi_info{} itself */
515 }
516 }
517 /* end free_ifi_info */
518
519 ssize_t
520 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
521 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
522 {
523 struct msghdr msg;
524 struct iovec iov[1];
525 ssize_t n;
526
527 #ifdef CMSG_FIRSTHDR
528 struct cmsghdr *cmptr;
529 union {
530 struct cmsghdr cm;
531 char control[1024];
532 } control_un;
533
534 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
535
536 msg.msg_control = control_un.control;
537 msg.msg_controllen = sizeof(control_un.control);
538 msg.msg_flags = 0;
539 #else
540 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
541 #endif /* CMSG_FIRSTHDR */
542
543 msg.msg_name = (char *) sa;
544 msg.msg_namelen = *salenptr;
545 iov[0].iov_base = (char *)ptr;
546 iov[0].iov_len = nbytes;
547 msg.msg_iov = iov;
548 msg.msg_iovlen = 1;
549
550 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
551 return(n);
552
553 *salenptr = msg.msg_namelen; /* pass back results */
554 if (pktp) {
555 /* 0.0.0.0, i/f = -1 */
556 /* We set the interface to -1 so that the caller can
557 tell whether we returned a meaningful value or
558 just some default. Previously this code just
559 set the value to 0, but I'm concerned that 0
560 might be a valid interface value.
561 */
562 memset(pktp, 0, sizeof(struct my_in_pktinfo));
563 pktp->ipi_ifindex = -1;
564 }
565 /* end recvfrom_flags1 */
566
567 /* include recvfrom_flags2 */
568 #ifndef CMSG_FIRSTHDR
569 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
570 *flagsp = 0; /* pass back results */
571 return(n);
572 #else
573
574 *flagsp = msg.msg_flags; /* pass back results */
575 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
576 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
577 return(n);
578
579 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
580 cmptr = CMSG_NXTHDR(&msg, cmptr)) {
581
582 #ifdef IP_PKTINFO
583 #if in_pktinfo_definition_is_missing
584 struct in_pktinfo
585 {
586 int ipi_ifindex;
587 struct in_addr ipi_spec_dst;
588 struct in_addr ipi_addr;
589 };
590 #endif
591 if (cmptr->cmsg_level == IPPROTO_IP &&
592 cmptr->cmsg_type == IP_PKTINFO) {
593 struct in_pktinfo *tmp;
594 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
595
596 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
597 sin->sin_family = AF_INET;
598 sin->sin_addr = tmp->ipi_addr;
599 sin->sin_port = 0;
600 pktp->ipi_ifindex = tmp->ipi_ifindex;
601 continue;
602 }
603 #endif
604
605 #ifdef IP_RECVDSTADDR
606 if (cmptr->cmsg_level == IPPROTO_IP &&
607 cmptr->cmsg_type == IP_RECVDSTADDR) {
608 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
609
610 sin->sin_family = AF_INET;
611 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
612 sin->sin_port = 0;
613 continue;
614 }
615 #endif
616
617 #ifdef IP_RECVIF
618 if (cmptr->cmsg_level == IPPROTO_IP &&
619 cmptr->cmsg_type == IP_RECVIF) {
620 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
621 #ifndef HAVE_BROKEN_RECVIF_NAME
622 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
623 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
624 #endif
625 pktp->ipi_ifindex = sdl->sdl_index;
626 #ifdef HAVE_BROKEN_RECVIF_NAME
627 if (sdl->sdl_index == 0) {
628 pktp->ipi_ifindex = *(uint_t*)sdl;
629 }
630 #endif
631 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
632 // null terminated because of memset above
633 continue;
634 }
635 #endif
636
637 #ifdef IP_RECVTTL
638 if (cmptr->cmsg_level == IPPROTO_IP &&
639 cmptr->cmsg_type == IP_RECVTTL) {
640 *ttl = *(u_char*)CMSG_DATA(cmptr);
641 continue;
642 }
643 else if (cmptr->cmsg_level == IPPROTO_IP &&
644 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
645 *ttl = *(int*)CMSG_DATA(cmptr);
646 continue;
647 }
648 #endif
649
650 #if defined(IPV6_PKTINFO) && HAVE_IPV6
651 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
652 cmptr->cmsg_type == IPV6_2292_PKTINFO) {
653 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
654 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
655
656 sin6->sin6_family = AF_INET6;
657 #ifndef NOT_HAVE_SA_LEN
658 sin6->sin6_len = sizeof(*sin6);
659 #endif
660 sin6->sin6_addr = ip6_info->ipi6_addr;
661 sin6->sin6_flowinfo = 0;
662 sin6->sin6_scope_id = 0;
663 sin6->sin6_port = 0;
664 pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
665 continue;
666 }
667 #endif
668
669 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
670 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
671 cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
672 *ttl = *(int*)CMSG_DATA(cmptr);
673 continue;
674 }
675 #endif
676 assert(0); // unknown ancillary data
677 }
678 return(n);
679 #endif /* CMSG_FIRSTHDR */
680 }
681
682 // **********************************************************************************************
683
684 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
685 // Returns 0 on success, -1 on failure.
686
687 #ifdef NOT_HAVE_DAEMON
688 #include <fcntl.h>
689 #include <sys/stat.h>
690 #include <sys/signal.h>
691
692 int daemon(int nochdir, int noclose)
693 {
694 switch (fork())
695 {
696 case -1: return (-1); // Fork failed
697 case 0: break; // Child -- continue
698 default: _exit(0); // Parent -- exit
699 }
700
701 if (setsid() == -1) return(-1);
702
703 signal(SIGHUP, SIG_IGN);
704
705 switch (fork()) // Fork again, primarily for reasons of Unix trivia
706 {
707 case -1: return (-1); // Fork failed
708 case 0: break; // Child -- continue
709 default: _exit(0); // Parent -- exit
710 }
711
712 if (!nochdir) (void)chdir("/");
713 umask(0);
714
715 if (!noclose)
716 {
717 int fd = open("/dev/null", O_RDWR, 0);
718 if (fd != -1)
719 {
720 // Avoid unnecessarily duplicating a file descriptor to itself
721 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
722 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
723 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
724 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
725 (void)close (fd);
726 }
727 }
728 return (0);
729 }
730 #endif /* NOT_HAVE_DAEMON */