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