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