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