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