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