]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSUNP.c
mDNSResponder-107.1.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 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23
24 Change History (most recent first):
25
26 $Log: mDNSUNP.c,v $
27 Revision 1.26 2005/04/08 21:43:59 ksekar
28 <rdar://problem/4083426> mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
29 Submitted by Andrew de Quincey
30
31 Revision 1.25 2005/04/08 21:37:57 ksekar
32 <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
33
34 Revision 1.24 2005/04/08 21:30:16 ksekar
35 <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
36 Patch submitted by Bernd Kuhls
37
38 Revision 1.23 2004/12/01 04:25:05 cheshire
39 <rdar://problem/3872803> Darwin patches for Solaris and Suse
40 Provide daemon() for platforms that don't have it
41
42 Revision 1.22 2004/11/30 22:37:01 cheshire
43 Update copyright dates and add "Mode: C; tab-width: 4" headers
44
45 Revision 1.21 2004/11/08 22:13:59 rpantos
46 Create sockf6 lazily when v6 interface found.
47
48 Revision 1.20 2004/10/16 00:17:01 cheshire
49 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
50
51 Revision 1.19 2004/07/20 01:47:36 rpantos
52 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
53
54 Revision 1.18 2004/07/08 21:30:21 rpantos
55
56 Revision 1.17 2004/06/25 00:26:27 rpantos
57 Changes to fix the Posix build on Solaris.
58
59 Revision 1.16 2004/03/20 05:37:09 cheshire
60 Fix contributed by Terry Lambert & Alfred Perlstein:
61 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
62
63 Revision 1.15 2004/02/14 01:09:45 rpantos
64 Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
65
66 Revision 1.14 2003/12/11 18:53:40 cheshire
67 Fix compiler warning reported by Paul Guyot
68
69 Revision 1.13 2003/12/08 20:47:02 rpantos
70 Add support for mDNSResponder on Linux.
71
72 Revision 1.12 2003/09/02 20:47:13 cheshire
73 Fix signed/unsigned warning
74
75 Revision 1.11 2003/08/12 19:56:26 cheshire
76 Update to APSL 2.0
77
78 Revision 1.10 2003/08/06 18:20:51 cheshire
79 Makefile cleanup
80
81 Revision 1.9 2003/07/14 18:11:54 cheshire
82 Fix stricter compiler warnings
83
84 Revision 1.8 2003/07/02 21:19:59 cheshire
85 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
86
87 Revision 1.7 2003/03/20 21:10:31 cheshire
88 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
89
90 Revision 1.6 2003/03/13 03:46:21 cheshire
91 Fixes to make the code build on Linux
92
93 Revision 1.5 2003/02/07 03:02:02 cheshire
94 Submitted by: Mitsutaka Watanabe
95 The code saying "index += 1;" was effectively making up random interface index values.
96 The right way to find the correct interface index is if_nametoindex();
97
98 Revision 1.4 2002/12/23 22:13:31 jgraessl
99
100 Reviewed by: Stuart Cheshire
101 Initial IPv6 support for mDNSResponder.
102
103 Revision 1.3 2002/09/21 20:44:53 zarzycki
104 Added APSL info
105
106 Revision 1.2 2002/09/19 04:20:44 cheshire
107 Remove high-ascii characters that confuse some systems
108
109 Revision 1.1 2002/09/17 06:24:34 cheshire
110 First checkin
111
112 */
113
114 #include "mDNSUNP.h"
115
116 #include <errno.h>
117 #include <assert.h>
118 #include <string.h>
119 #include <stdlib.h>
120 #include <sys/uio.h>
121 #include <sys/ioctl.h>
122 #include <unistd.h>
123 #include <stdio.h>
124
125 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
126 other platforms don't even have that include file. So,
127 if we haven't yet got a definition, let's try to find
128 <sys/sockio.h>.
129 */
130
131 #ifndef SIOCGIFCONF
132 #include <sys/sockio.h>
133 #endif
134
135 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
136 so only include the header in that case.
137 */
138
139 #ifdef IP_RECVIF
140 #include <net/if_dl.h>
141 #endif
142
143 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
144 #include <netinet6/in6_var.h>
145 #endif
146
147 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
148 #include <netdb.h>
149 #include <arpa/inet.h>
150
151 /* Converts a prefix length to IPv6 network mask */
152 void plen_to_mask(int plen, char *addr) {
153 int i;
154 int colons=7; /* Number of colons in IPv6 address */
155 int bits_in_block=16; /* Bits per IPv6 block */
156 for(i=0;i<=colons;i++) {
157 int block, ones=0xffff, ones_in_block;
158 if(plen>bits_in_block) ones_in_block=bits_in_block;
159 else ones_in_block=plen;
160 block = ones & (ones << (bits_in_block-ones_in_block));
161 i==0 ? sprintf(addr, "%x", block) :
162 sprintf(addr, "%s:%x", addr, block);
163 plen -= ones_in_block;
164 }
165 }
166
167 /* Gets IPv6 interface information from the /proc filesystem in linux*/
168 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
169 {
170 struct ifi_info *ifi, *ifihead, **ifipnext;
171 FILE *fp;
172 char addr[8][5];
173 int flags, myflags, index, plen, scope;
174 char ifname[8], lastname[IFNAMSIZ];
175 char addr6[33];
176 struct addrinfo hints, *res0;
177 struct sockaddr_in6 *sin6;
178 struct in6_addr *addrptr;
179 int err;
180
181 res0=NULL;
182 ifihead = NULL;
183 ifipnext = &ifihead;
184 lastname[0] = 0;
185
186 if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
187 while (fscanf(fp,
188 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
189 addr[0],addr[1],addr[2],addr[3],
190 addr[4],addr[5],addr[6],addr[7],
191 &index, &plen, &scope, &flags, ifname) != EOF) {
192
193 myflags = 0;
194 if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
195 if (doaliases == 0)
196 continue; /* already processed this interface */
197 myflags = IFI_ALIAS;
198 }
199 memcpy(lastname, ifname, IFNAMSIZ);
200 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
201 if (ifi == NULL) {
202 goto gotError;
203 }
204
205 *ifipnext = ifi; /* prev points to this new one */
206 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
207
208 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
209 addr[0],addr[1],addr[2],addr[3],
210 addr[4],addr[5],addr[6],addr[7]);
211
212 /* Add address of the interface */
213 memset(&hints, 0, sizeof(hints));
214 hints.ai_family = AF_INET6;
215 hints.ai_flags = AI_NUMERICHOST;
216 err = getaddrinfo(addr6, NULL, &hints, &res0);
217 if (err) {
218 goto gotError;
219 }
220 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
221 if (ifi->ifi_addr == NULL) {
222 goto gotError;
223 }
224 memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
225
226 /* Add netmask of the interface */
227 char ipv6addr[INET6_ADDRSTRLEN];
228 plen_to_mask(plen, ipv6addr);
229 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
230 if (ifi->ifi_addr == NULL) {
231 goto gotError;
232 }
233 sin6=calloc(1, sizeof(struct sockaddr_in6));
234 addrptr=calloc(1, sizeof(struct in6_addr));
235 inet_pton(family, ipv6addr, addrptr);
236 sin6->sin6_family=family;
237 sin6->sin6_addr=*addrptr;
238 sin6->sin6_scope_id=scope;
239 memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
240 free(sin6);
241
242
243 /* Add interface name */
244 memcpy(ifi->ifi_name, ifname, IFI_NAME);
245
246 /* Add interface index */
247 ifi->ifi_index = index;
248
249 /* If interface is in /proc then it is up*/
250 ifi->ifi_flags = IFF_UP;
251
252 freeaddrinfo(res0);
253 res0=NULL;
254 }
255 }
256 goto done;
257
258 gotError:
259 if (ifihead != NULL) {
260 free_ifi_info(ifihead);
261 ifihead = NULL;
262 }
263 if (res0 != NULL) {
264 freeaddrinfo(res0);
265 res0=NULL;
266 }
267 done:
268 return(ifihead); /* pointer to first structure in linked list */
269 }
270 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
271
272 struct ifi_info *get_ifi_info(int family, int doaliases)
273 {
274 int junk;
275 struct ifi_info *ifi, *ifihead, **ifipnext;
276 int sockfd, sockf6, len, lastlen, flags, myflags;
277 #ifdef NOT_HAVE_IF_NAMETOINDEX
278 int index = 200;
279 #endif
280 char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
281 struct ifconf ifc;
282 struct ifreq *ifr, ifrcopy;
283 struct sockaddr_in *sinptr;
284
285 #if defined(AF_INET6) && HAVE_IPV6
286 struct sockaddr_in6 *sinptr6;
287 #endif
288
289 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
290 if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
291 #endif
292
293 sockfd = -1;
294 sockf6 = -1;
295 buf = NULL;
296 ifihead = NULL;
297
298 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
299 if (sockfd < 0) {
300 goto gotError;
301 }
302
303 lastlen = 0;
304 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
305 for ( ; ; ) {
306 buf = (char*)malloc(len);
307 if (buf == NULL) {
308 goto gotError;
309 }
310 ifc.ifc_len = len;
311 ifc.ifc_buf = buf;
312 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
313 if (errno != EINVAL || lastlen != 0) {
314 goto gotError;
315 }
316 } else {
317 if (ifc.ifc_len == lastlen)
318 break; /* success, len has not changed */
319 lastlen = ifc.ifc_len;
320 }
321 len += 10 * sizeof(struct ifreq); /* increment */
322 free(buf);
323 }
324 ifihead = NULL;
325 ifipnext = &ifihead;
326 lastname[0] = 0;
327 /* end get_ifi_info1 */
328
329 /* include get_ifi_info2 */
330 for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
331 ifr = (struct ifreq *) ptr;
332
333 len = GET_SA_LEN(ifr->ifr_addr);
334 ptr += sizeof(struct ifreq); /* for next one in buffer */
335
336 // fprintf(stderr, "intf %d name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
337
338 if (ifr->ifr_addr.sa_family != family)
339 continue; /* ignore if not desired address family */
340
341 myflags = 0;
342 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
343 *cptr = 0; /* replace colon will null */
344 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
345 if (doaliases == 0)
346 continue; /* already processed this interface */
347 myflags = IFI_ALIAS;
348 }
349 memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
350
351 ifrcopy = *ifr;
352 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
353 goto gotError;
354 }
355
356 flags = ifrcopy.ifr_flags;
357 if ((flags & IFF_UP) == 0)
358 continue; /* ignore if interface not up */
359
360 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
361 if (ifi == NULL) {
362 goto gotError;
363 }
364 *ifipnext = ifi; /* prev points to this new one */
365 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
366
367 ifi->ifi_flags = flags; /* IFF_xxx values */
368 ifi->ifi_myflags = myflags; /* IFI_xxx values */
369 #ifndef NOT_HAVE_IF_NAMETOINDEX
370 ifi->ifi_index = if_nametoindex(ifr->ifr_name);
371 #else
372 ifrcopy = *ifr;
373 if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
374 ifi->ifi_index = ifrcopy.ifr_index;
375 else
376 ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
377 #endif
378 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
379 ifi->ifi_name[IFI_NAME-1] = '\0';
380 /* end get_ifi_info2 */
381 /* include get_ifi_info3 */
382 switch (ifr->ifr_addr.sa_family) {
383 case AF_INET:
384 sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
385 if (ifi->ifi_addr == NULL) {
386 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
387 if (ifi->ifi_addr == NULL) {
388 goto gotError;
389 }
390 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
391
392 #ifdef SIOCGIFNETMASK
393 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
394 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
395 if (ifi->ifi_netmask == NULL) goto gotError;
396 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
397 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
398 #endif
399
400 #ifdef SIOCGIFBRDADDR
401 if (flags & IFF_BROADCAST) {
402 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
403 goto gotError;
404 }
405 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
406 ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
407 if (ifi->ifi_brdaddr == NULL) {
408 goto gotError;
409 }
410 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
411 }
412 #endif
413
414 #ifdef SIOCGIFDSTADDR
415 if (flags & IFF_POINTOPOINT) {
416 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
417 goto gotError;
418 }
419 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
420 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
421 if (ifi->ifi_dstaddr == NULL) {
422 goto gotError;
423 }
424 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
425 }
426 #endif
427 }
428 break;
429
430 #if defined(AF_INET6) && HAVE_IPV6
431 case AF_INET6:
432 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
433 if (ifi->ifi_addr == NULL) {
434 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
435 if (ifi->ifi_addr == NULL) {
436 goto gotError;
437 }
438
439 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
440 /* We need to strip that out */
441 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
442 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
443 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
444
445 #ifdef SIOCGIFNETMASK_IN6
446 {
447 struct in6_ifreq ifr6;
448 if (sockf6 == -1)
449 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
450 bzero(&ifr6, sizeof(ifr6));
451 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
452 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
453 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
454 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
455 if (ifi->ifi_netmask == NULL) goto gotError;
456 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
457 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
458 }
459 #endif
460 }
461 break;
462 #endif
463
464 default:
465 break;
466 }
467 }
468 goto done;
469
470 gotError:
471 if (ifihead != NULL) {
472 free_ifi_info(ifihead);
473 ifihead = NULL;
474 }
475
476 done:
477 if (buf != NULL) {
478 free(buf);
479 }
480 if (sockfd != -1) {
481 junk = close(sockfd);
482 assert(junk == 0);
483 }
484 if (sockf6 != -1) {
485 junk = close(sockf6);
486 assert(junk == 0);
487 }
488 return(ifihead); /* pointer to first structure in linked list */
489 }
490 /* end get_ifi_info3 */
491
492 /* include free_ifi_info */
493 void
494 free_ifi_info(struct ifi_info *ifihead)
495 {
496 struct ifi_info *ifi, *ifinext;
497
498 for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
499 if (ifi->ifi_addr != NULL)
500 free(ifi->ifi_addr);
501 if (ifi->ifi_brdaddr != NULL)
502 free(ifi->ifi_brdaddr);
503 if (ifi->ifi_dstaddr != NULL)
504 free(ifi->ifi_dstaddr);
505 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
506 free(ifi); /* the ifi_info{} itself */
507 }
508 }
509 /* end free_ifi_info */
510
511 ssize_t
512 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
513 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
514 {
515 struct msghdr msg;
516 struct iovec iov[1];
517 ssize_t n;
518
519 #ifdef CMSG_FIRSTHDR
520 struct cmsghdr *cmptr;
521 union {
522 struct cmsghdr cm;
523 char control[1024];
524 } control_un;
525
526 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
527
528 msg.msg_control = control_un.control;
529 msg.msg_controllen = sizeof(control_un.control);
530 msg.msg_flags = 0;
531 #else
532 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
533 #endif /* CMSG_FIRSTHDR */
534
535 msg.msg_name = (char *) sa;
536 msg.msg_namelen = *salenptr;
537 iov[0].iov_base = (char *)ptr;
538 iov[0].iov_len = nbytes;
539 msg.msg_iov = iov;
540 msg.msg_iovlen = 1;
541
542 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
543 return(n);
544
545 *salenptr = msg.msg_namelen; /* pass back results */
546 if (pktp) {
547 /* 0.0.0.0, i/f = -1 */
548 /* We set the interface to -1 so that the caller can
549 tell whether we returned a meaningful value or
550 just some default. Previously this code just
551 set the value to 0, but I'm concerned that 0
552 might be a valid interface value.
553 */
554 memset(pktp, 0, sizeof(struct my_in_pktinfo));
555 pktp->ipi_ifindex = -1;
556 }
557 /* end recvfrom_flags1 */
558
559 /* include recvfrom_flags2 */
560 #ifndef CMSG_FIRSTHDR
561 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
562 *flagsp = 0; /* pass back results */
563 return(n);
564 #else
565
566 *flagsp = msg.msg_flags; /* pass back results */
567 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
568 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
569 return(n);
570
571 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
572 cmptr = CMSG_NXTHDR(&msg, cmptr)) {
573
574 #ifdef IP_PKTINFO
575 #if in_pktinfo_definition_is_missing
576 struct in_pktinfo
577 {
578 int ipi_ifindex;
579 struct in_addr ipi_spec_dst;
580 struct in_addr ipi_addr;
581 };
582 #endif
583 if (cmptr->cmsg_level == IPPROTO_IP &&
584 cmptr->cmsg_type == IP_PKTINFO) {
585 struct in_pktinfo *tmp;
586 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
587
588 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
589 sin->sin_family = AF_INET;
590 sin->sin_addr = tmp->ipi_addr;
591 sin->sin_port = 0;
592 pktp->ipi_ifindex = tmp->ipi_ifindex;
593 continue;
594 }
595 #endif
596
597 #ifdef IP_RECVDSTADDR
598 if (cmptr->cmsg_level == IPPROTO_IP &&
599 cmptr->cmsg_type == IP_RECVDSTADDR) {
600 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
601
602 sin->sin_family = AF_INET;
603 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
604 sin->sin_port = 0;
605 continue;
606 }
607 #endif
608
609 #ifdef IP_RECVIF
610 if (cmptr->cmsg_level == IPPROTO_IP &&
611 cmptr->cmsg_type == IP_RECVIF) {
612 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
613 #ifndef HAVE_BROKEN_RECVIF_NAME
614 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
615 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
616 #endif
617 pktp->ipi_ifindex = sdl->sdl_index;
618 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
619 // null terminated because of memset above
620 continue;
621 }
622 #endif
623
624 #ifdef IP_RECVTTL
625 if (cmptr->cmsg_level == IPPROTO_IP &&
626 cmptr->cmsg_type == IP_RECVTTL) {
627 *ttl = *(u_char*)CMSG_DATA(cmptr);
628 continue;
629 }
630 else if (cmptr->cmsg_level == IPPROTO_IP &&
631 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
632 *ttl = *(int*)CMSG_DATA(cmptr);
633 continue;
634 }
635 #endif
636
637 #if defined(IPV6_PKTINFO) && HAVE_IPV6
638 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
639 cmptr->cmsg_type == IPV6_PKTINFO) {
640 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
641 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
642
643 sin6->sin6_family = AF_INET6;
644 #ifndef NOT_HAVE_SA_LEN
645 sin6->sin6_len = sizeof(*sin6);
646 #endif
647 sin6->sin6_addr = ip6_info->ipi6_addr;
648 sin6->sin6_flowinfo = 0;
649 sin6->sin6_scope_id = 0;
650 sin6->sin6_port = 0;
651 pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
652 continue;
653 }
654 #endif
655
656 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
657 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
658 cmptr->cmsg_type == IPV6_HOPLIMIT) {
659 *ttl = *(int*)CMSG_DATA(cmptr);
660 continue;
661 }
662 #endif
663 assert(0); // unknown ancillary data
664 }
665 return(n);
666 #endif /* CMSG_FIRSTHDR */
667 }
668
669 // **********************************************************************************************
670
671 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
672 // Returns 0 on success, -1 on failure.
673
674 #ifdef NOT_HAVE_DAEMON
675 #include <fcntl.h>
676 #include <sys/stat.h>
677 #include <signal.h>
678
679 int daemon(int nochdir, int noclose)
680 {
681 switch (fork())
682 {
683 case -1: return (-1); // Fork failed
684 case 0: break; // Child -- continue
685 default: _exit(0); // Parent -- exit
686 }
687
688 if (setsid() == -1) return(-1);
689
690 signal(SIGHUP, SIG_IGN);
691
692 switch (fork()) // Fork again, primarily for reasons of Unix trivia
693 {
694 case -1: return (-1); // Fork failed
695 case 0: break; // Child -- continue
696 default: _exit(0); // Parent -- exit
697 }
698
699 if (!nochdir) (void)chdir("/");
700 umask(0);
701
702 if (!noclose)
703 {
704 int fd = open("/dev/null", O_RDWR, 0);
705 if (fd != -1)
706 {
707 // Avoid unnecessarily duplicating a file descriptor to itself
708 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
709 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
710 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
711 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
712 (void)close (fd);
713 }
714 }
715 return (0);
716 }
717 #endif /* NOT_HAVE_DAEMON */