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