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