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