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