8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.lib / mdnsd / mDNSUNP.c
blob0b174e8301b1e61e4bb1bdd83e72a5d60011695d
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
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.
18 #include "mDNSUNP.h"
20 #include <errno.h>
21 #include <assert.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/uio.h>
25 #include <sys/ioctl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <stdio.h>
30 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
31 macro, usually defined in <sys/param.h> or someplace like that, to make sure the
32 CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
33 should be set to the name of the header to include to get the ALIGN(P) macro.
35 #ifdef NEED_ALIGN_MACRO
36 #include NEED_ALIGN_MACRO
37 #endif
39 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
40 other platforms don't even have that include file. So,
41 if we haven't yet got a definition, let's try to find
42 <sys/sockio.h>.
45 #ifndef SIOCGIFCONF
46 #include <sys/sockio.h>
47 #endif
49 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
50 so only include the header in that case.
53 #ifdef IP_RECVIF
54 #include <net/if_dl.h>
55 #endif
57 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
58 #if !HAVE_SOLARIS
59 #include <net/if_var.h>
60 #else
61 #include <alloca.h>
62 #endif /* !HAVE_SOLARIS */
63 #include <netinet/in_var.h>
64 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
65 #endif
67 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
68 #include <netdb.h>
69 #include <arpa/inet.h>
71 /* Converts a prefix length to IPv6 network mask */
72 void plen_to_mask(int plen, char *addr) {
73 int i;
74 int colons=7; /* Number of colons in IPv6 address */
75 int bits_in_block=16; /* Bits per IPv6 block */
76 for(i=0; i<=colons; i++) {
77 int block, ones=0xffff, ones_in_block;
78 if (plen>bits_in_block) ones_in_block=bits_in_block;
79 else ones_in_block=plen;
80 block = ones & (ones << (bits_in_block-ones_in_block));
81 i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
82 plen -= ones_in_block;
86 /* Gets IPv6 interface information from the /proc filesystem in linux*/
87 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
89 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
90 FILE *fp = NULL;
91 char addr[8][5];
92 int flags, myflags, index, plen, scope;
93 char ifname[9], lastname[IFNAMSIZ];
94 char addr6[32+7+1]; /* don't forget the seven ':' */
95 struct addrinfo hints, *res0;
96 int err;
97 int sockfd = -1;
98 struct ifreq ifr;
100 res0=NULL;
101 ifihead = NULL;
102 ifipnext = &ifihead;
103 lastname[0] = 0;
105 if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
106 sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
107 if (sockfd < 0) {
108 goto gotError;
110 while (fscanf(fp,
111 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
112 addr[0],addr[1],addr[2],addr[3],
113 addr[4],addr[5],addr[6],addr[7],
114 &index, &plen, &scope, &flags, ifname) != EOF) {
116 myflags = 0;
117 if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
118 if (doaliases == 0)
119 continue; /* already processed this interface */
120 myflags = IFI_ALIAS;
122 memcpy(lastname, ifname, IFNAMSIZ);
123 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
124 if (ifi == NULL) {
125 goto gotError;
128 ifipold = *ifipnext; /* need this later */
129 ifiptr = ifipnext;
130 *ifipnext = ifi; /* prev points to this new one */
131 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
133 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
134 addr[0],addr[1],addr[2],addr[3],
135 addr[4],addr[5],addr[6],addr[7]);
137 /* Add address of the interface */
138 memset(&hints, 0, sizeof(hints));
139 hints.ai_family = AF_INET6;
140 hints.ai_flags = AI_NUMERICHOST;
141 err = getaddrinfo(addr6, NULL, &hints, &res0);
142 if (err) {
143 goto gotError;
145 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
146 if (ifi->ifi_addr == NULL) {
147 goto gotError;
149 memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
151 /* Add netmask of the interface */
152 char ipv6addr[INET6_ADDRSTRLEN];
153 plen_to_mask(plen, ipv6addr);
154 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
155 if (ifi->ifi_netmask == NULL) {
156 goto gotError;
159 ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=family;
160 ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
161 inet_pton(family, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
163 /* Add interface name */
164 memcpy(ifi->ifi_name, ifname, IFI_NAME);
166 /* Add interface index */
167 ifi->ifi_index = index;
169 /* Add interface flags*/
170 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
171 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
172 if (errno == EADDRNOTAVAIL) {
174 * If the main interface is configured with no IP address but
175 * an alias interface exists with an IP address, you get
176 * EADDRNOTAVAIL for the main interface
178 free(ifi->ifi_addr);
179 free(ifi->ifi_netmask);
180 free(ifi);
181 ifipnext = ifiptr;
182 *ifipnext = ifipold;
183 continue;
184 } else {
185 goto gotError;
188 ifi->ifi_flags = ifr.ifr_flags;
189 freeaddrinfo(res0);
190 res0=NULL;
193 goto done;
195 gotError:
196 if (ifihead != NULL) {
197 free_ifi_info(ifihead);
198 ifihead = NULL;
200 if (res0 != NULL) {
201 freeaddrinfo(res0);
202 res0=NULL;
204 done:
205 if (sockfd != -1) {
206 assert(close(sockfd) == 0);
208 if (fp != NULL) {
209 fclose(fp);
211 return(ifihead); /* pointer to first structure in linked list */
213 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
215 #if HAVE_SOLARIS
218 * Converts prefix length to network mask. Assumes
219 * addr points to a zeroed out buffer and prefix <= sizeof(addr)
220 * Unlike plen_to_mask returns netmask in binary form and not
221 * in text form.
223 static void plen_to_netmask(int prefix, unsigned char *addr) {
224 for (; prefix > 8; prefix -= 8)
225 *addr++ = 0xff;
226 for (; prefix > 0; prefix--)
227 *addr = (*addr >> 1) | 0x80;
231 * This function goes through all the IP interfaces associated with a
232 * physical interface and finds the best matched one for use by mDNS.
233 * Returns NULL when none of the IP interfaces associated with a physical
234 * interface are usable. Otherwise returns the best matched interface
235 * information and a pointer to the best matched lifreq.
237 struct ifi_info *
238 select_src_ifi_info_solaris(int sockfd, int numifs,
239 struct lifreq *lifrlist, const char *curifname,
240 struct lifreq **best_lifr)
242 struct lifreq *lifr;
243 struct lifreq lifrcopy;
244 struct ifi_info *ifi;
245 char *chptr;
246 char cmpifname[LIFNAMSIZ];
247 int i;
248 uint64_t best_lifrflags = 0;
249 uint64_t ifflags;
251 *best_lifr = NULL;
254 * Check all logical interfaces associated with the physical
255 * interface and figure out which one works best for us.
257 for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
259 if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
260 continue; /* skip interface */
262 /* Strip logical interface number before checking ifname */
263 if ((chptr = strchr(cmpifname, ':')) != NULL)
264 *chptr = '\0';
267 * Check ifname to see if the logical interface is associated
268 * with the physical interface we are interested in.
270 if (strcmp(cmpifname, curifname) != 0)
271 continue;
273 lifrcopy = *lifr;
274 if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
275 /* interface removed */
276 if (errno == ENXIO)
277 continue;
278 return(NULL);
280 ifflags = lifrcopy.lifr_flags;
282 /* ignore address if not up */
283 if ((ifflags & IFF_UP) == 0)
284 continue;
286 * Avoid address if any of the following flags are set:
287 * IFF_NOXMIT: no packets transmitted over interface
288 * IFF_NOLOCAL: no address
289 * IFF_PRIVATE: is not advertised
291 if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
292 continue;
294 /* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
295 if (lifr->lifr_addr.ss_family == AF_INET) {
296 struct sockaddr_in *sinptr;
298 sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
299 if (sinptr->sin_addr.s_addr == INADDR_ANY)
300 continue;
303 if (*best_lifr != NULL) {
305 * Check if we found a better interface by checking
306 * the flags. If flags are identical we prefer
307 * the new found interface.
309 uint64_t diff_flags = best_lifrflags ^ ifflags;
311 /* If interface has a different set of flags */
312 if (diff_flags != 0) {
313 /* Check flags in increasing order of ones we prefer */
315 /* Address temporary? */
316 if ((diff_flags & IFF_TEMPORARY) &&
317 (ifflags & IFF_TEMPORARY))
318 continue;
319 /* Deprecated address? */
320 if ((diff_flags & IFF_DEPRECATED) &&
321 (ifflags & IFF_DEPRECATED))
322 continue;
323 /* Last best-matched interface address has preferred? */
324 if ((diff_flags & IFF_PREFERRED) &&
325 ((ifflags & IFF_PREFERRED) == 0))
326 continue;
330 /* Set best match interface & flags */
331 *best_lifr = lifr;
332 best_lifrflags = ifflags;
335 if (*best_lifr == NULL)
336 return(NULL);
338 /* Found a match: return the interface information */
339 ifi = calloc(1, sizeof(struct ifi_info));
340 if (ifi == NULL)
341 return(NULL);
343 ifi->ifi_flags = best_lifrflags;
344 ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
345 if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
346 free(ifi);
347 return(NULL);
349 return(ifi);
353 * Returns a list of IP interface information on Solaris. The function
354 * returns all IP interfaces on the system with IPv4 address assigned
355 * when passed AF_INET and returns IP interfaces with IPv6 address assigned
356 * when AF_INET6 is passed.
358 struct ifi_info *get_ifi_info_solaris(int family)
360 struct ifi_info *ifi, *ifihead, **ifipnext;
361 int sockfd;
362 int len;
363 char *buf;
364 char *cptr;
365 char ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
366 struct sockaddr_in *sinptr;
367 struct lifnum lifn;
368 struct lifconf lifc;
369 struct lifreq *lifrp, *best_lifr;
370 struct lifreq lifrcopy;
371 int numifs, nlifr, n;
372 #if defined(AF_INET6) && HAVE_IPV6
373 struct sockaddr_in6 *sinptr6;
374 #endif
376 ifihead = NULL;
378 sockfd = socket(family, SOCK_DGRAM, 0);
379 if (sockfd < 0)
380 goto gotError;
382 again:
383 lifn.lifn_family = family;
384 lifn.lifn_flags = 0;
385 if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
386 goto gotError;
388 * Pad interface count to detect & retrieve any
389 * additional interfaces between IFNUM & IFCONF calls.
391 lifn.lifn_count += 4;
392 numifs = lifn.lifn_count;
393 len = numifs * sizeof (struct lifreq);
394 buf = alloca(len);
396 lifc.lifc_family = family;
397 lifc.lifc_len = len;
398 lifc.lifc_buf = buf;
399 lifc.lifc_flags = 0;
401 if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
402 goto gotError;
404 nlifr = lifc.lifc_len / sizeof(struct lifreq);
405 if (nlifr >= numifs)
406 goto again;
408 lifrp = lifc.lifc_req;
409 ifipnext = &ifihead;
411 for (n = nlifr; n > 0; n--, lifrp++) {
413 if (lifrp->lifr_addr.ss_family != family)
414 continue;
417 * See if we have already processed the interface
418 * by checking the interface names.
420 if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
421 goto gotError;
422 if ((cptr = strchr(ifname, ':')) != NULL)
423 *cptr = '\0';
426 * If any of the interfaces found so far share the physical
427 * interface name then we have already processed the interface.
429 for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
431 /* Retrieve physical interface name */
432 (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
434 /* Strip logical interface number before checking ifname */
435 if ((cptr = strchr(cmpifname, ':')) != NULL)
436 *cptr = '\0';
438 if (strcmp(cmpifname, ifname) == 0)
439 break;
441 if (ifi != NULL)
442 continue; /* already processed */
445 * New interface, find the one with the preferred source
446 * address for our use in Multicast DNS.
448 if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
449 lifc.lifc_req, ifname, &best_lifr)) == NULL)
450 continue;
452 assert(best_lifr != NULL);
453 assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
454 (best_lifr->lifr_addr.ss_family == AF_INET));
456 switch (best_lifr->lifr_addr.ss_family) {
458 #if defined(AF_INET6) && HAVE_IPV6
459 case AF_INET6:
460 sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
461 ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
462 if (ifi->ifi_addr == NULL)
463 goto gotError;
464 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
466 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
467 if (ifi->ifi_netmask == NULL)
468 goto gotError;
469 sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
470 sinptr6->sin6_family = AF_INET6;
471 plen_to_netmask(best_lifr->lifr_addrlen,
472 (unsigned char *) &(sinptr6->sin6_addr));
473 break;
474 #endif
476 case AF_INET:
477 sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
478 ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
479 if (ifi->ifi_addr == NULL)
480 goto gotError;
482 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
484 lifrcopy = *best_lifr;
485 if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
486 /* interface removed */
487 if (errno == ENXIO) {
488 free(ifi->ifi_addr);
489 free(ifi);
490 continue;
492 goto gotError;
495 ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
496 if (ifi->ifi_netmask == NULL)
497 goto gotError;
498 sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
499 sinptr->sin_family = AF_INET;
500 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
501 break;
503 default:
504 /* never reached */
505 break;
508 *ifipnext = ifi; /* prev points to this new one */
509 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
512 (void) close(sockfd);
513 return(ifihead); /* pointer to first structure in linked list */
515 gotError:
516 if (sockfd != -1)
517 (void) close(sockfd);
518 if (ifihead != NULL)
519 free_ifi_info(ifihead);
520 return(NULL);
523 #endif /* HAVE_SOLARIS */
525 struct ifi_info *get_ifi_info(int family, int doaliases)
527 int junk;
528 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
529 int sockfd, sockf6, len, lastlen, flags, myflags;
530 #ifdef NOT_HAVE_IF_NAMETOINDEX
531 int index = 200;
532 #endif
533 char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
534 struct ifconf ifc;
535 struct ifreq *ifr, ifrcopy;
536 struct sockaddr_in *sinptr;
538 #if defined(AF_INET6) && HAVE_IPV6
539 struct sockaddr_in6 *sinptr6;
540 #endif
542 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
543 if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
544 #elif HAVE_SOLARIS
545 return get_ifi_info_solaris(family);
546 #endif
548 sockfd = -1;
549 sockf6 = -1;
550 buf = NULL;
551 ifihead = NULL;
553 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
554 if (sockfd < 0) {
555 goto gotError;
558 lastlen = 0;
559 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
560 for ( ; ; ) {
561 buf = (char*)malloc(len);
562 if (buf == NULL) {
563 goto gotError;
565 ifc.ifc_len = len;
566 ifc.ifc_buf = buf;
567 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
568 if (errno != EINVAL || lastlen != 0) {
569 goto gotError;
571 } else {
572 if (ifc.ifc_len == lastlen)
573 break; /* success, len has not changed */
574 lastlen = ifc.ifc_len;
576 len += 10 * sizeof(struct ifreq); /* increment */
577 free(buf);
579 ifihead = NULL;
580 ifipnext = &ifihead;
581 lastname[0] = 0;
582 /* end get_ifi_info1 */
584 /* include get_ifi_info2 */
585 for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
586 ifr = (struct ifreq *) ptr;
588 /* Advance to next one in buffer */
589 if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
590 ptr += sizeof(struct ifreq);
591 else
592 ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
594 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
596 if (ifr->ifr_addr.sa_family != family)
597 continue; /* ignore if not desired address family */
599 myflags = 0;
600 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
601 *cptr = 0; /* replace colon will null */
602 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
603 if (doaliases == 0)
604 continue; /* already processed this interface */
605 myflags = IFI_ALIAS;
607 memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
609 ifrcopy = *ifr;
610 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
611 goto gotError;
614 flags = ifrcopy.ifr_flags;
615 if ((flags & IFF_UP) == 0)
616 continue; /* ignore if interface not up */
618 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
619 if (ifi == NULL) {
620 goto gotError;
622 ifipold = *ifipnext; /* need this later */
623 ifiptr = ifipnext;
624 *ifipnext = ifi; /* prev points to this new one */
625 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
627 ifi->ifi_flags = flags; /* IFF_xxx values */
628 ifi->ifi_myflags = myflags; /* IFI_xxx values */
629 #ifndef NOT_HAVE_IF_NAMETOINDEX
630 ifi->ifi_index = if_nametoindex(ifr->ifr_name);
631 #else
632 ifrcopy = *ifr;
633 #ifdef SIOCGIFINDEX
634 if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
635 ifi->ifi_index = ifrcopy.ifr_index;
636 else
637 #endif
638 ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
639 #endif
640 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
641 ifi->ifi_name[IFI_NAME-1] = '\0';
642 /* end get_ifi_info2 */
643 /* include get_ifi_info3 */
644 switch (ifr->ifr_addr.sa_family) {
645 case AF_INET:
646 sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
647 if (ifi->ifi_addr == NULL) {
648 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
649 if (ifi->ifi_addr == NULL) {
650 goto gotError;
652 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
654 #ifdef SIOCGIFNETMASK
655 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
656 if (errno == EADDRNOTAVAIL) {
658 * If the main interface is configured with no IP address but
659 * an alias interface exists with an IP address, you get
660 * EADDRNOTAVAIL for the main interface
662 free(ifi->ifi_addr);
663 free(ifi);
664 ifipnext = ifiptr;
665 *ifipnext = ifipold;
666 continue;
667 } else {
668 goto gotError;
672 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
673 if (ifi->ifi_netmask == NULL) goto gotError;
674 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
675 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
676 #ifndef NOT_HAVE_SA_LEN
677 sinptr->sin_len = sizeof(struct sockaddr_in);
678 #endif
679 sinptr->sin_family = AF_INET;
680 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
681 #endif
683 #ifdef SIOCGIFBRDADDR
684 if (flags & IFF_BROADCAST) {
685 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
686 goto gotError;
688 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
689 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
690 #ifndef NOT_HAVE_SA_LEN
691 sinptr->sin_len = sizeof( struct sockaddr_in );
692 #endif
693 sinptr->sin_family = AF_INET;
694 ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
695 if (ifi->ifi_brdaddr == NULL) {
696 goto gotError;
698 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
700 #endif
702 #ifdef SIOCGIFDSTADDR
703 if (flags & IFF_POINTOPOINT) {
704 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
705 goto gotError;
707 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
708 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
709 #ifndef NOT_HAVE_SA_LEN
710 sinptr->sin_len = sizeof( struct sockaddr_in );
711 #endif
712 sinptr->sin_family = AF_INET;
713 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
714 if (ifi->ifi_dstaddr == NULL) {
715 goto gotError;
717 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
719 #endif
721 break;
723 #if defined(AF_INET6) && HAVE_IPV6
724 case AF_INET6:
725 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
726 if (ifi->ifi_addr == NULL) {
727 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
728 if (ifi->ifi_addr == NULL) {
729 goto gotError;
732 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
733 /* We need to strip that out */
734 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
735 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
736 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
738 #ifdef SIOCGIFNETMASK_IN6
740 struct in6_ifreq ifr6;
741 if (sockf6 == -1)
742 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
743 memset(&ifr6, 0, sizeof(ifr6));
744 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
745 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
746 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
747 if (errno == EADDRNOTAVAIL) {
749 * If the main interface is configured with no IP address but
750 * an alias interface exists with an IP address, you get
751 * EADDRNOTAVAIL for the main interface
753 free(ifi->ifi_addr);
754 free(ifi);
755 ifipnext = ifiptr;
756 *ifipnext = ifipold;
757 continue;
758 } else {
759 goto gotError;
762 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
763 if (ifi->ifi_netmask == NULL) goto gotError;
764 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
765 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
767 #endif
769 break;
770 #endif
772 default:
773 break;
776 goto done;
778 gotError:
779 if (ifihead != NULL) {
780 free_ifi_info(ifihead);
781 ifihead = NULL;
784 done:
785 if (buf != NULL) {
786 free(buf);
788 if (sockfd != -1) {
789 junk = close(sockfd);
790 assert(junk == 0);
792 if (sockf6 != -1) {
793 junk = close(sockf6);
794 assert(junk == 0);
796 return(ifihead); /* pointer to first structure in linked list */
798 /* end get_ifi_info3 */
800 /* include free_ifi_info */
801 void
802 free_ifi_info(struct ifi_info *ifihead)
804 struct ifi_info *ifi, *ifinext;
806 for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
807 if (ifi->ifi_addr != NULL)
808 free(ifi->ifi_addr);
809 if (ifi->ifi_netmask != NULL)
810 free(ifi->ifi_netmask);
811 if (ifi->ifi_brdaddr != NULL)
812 free(ifi->ifi_brdaddr);
813 if (ifi->ifi_dstaddr != NULL)
814 free(ifi->ifi_dstaddr);
815 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
816 free(ifi); /* the ifi_info{} itself */
819 /* end free_ifi_info */
821 ssize_t
822 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
823 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
825 struct msghdr msg;
826 struct iovec iov[1];
827 ssize_t n;
829 #ifdef CMSG_FIRSTHDR
830 struct cmsghdr *cmptr;
831 union {
832 struct cmsghdr cm;
833 char control[1024];
834 pad64_t align8; /* ensure structure is 8-byte aligned on sparc */
835 } control_un;
837 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
839 msg.msg_control = (void *) control_un.control;
840 msg.msg_controllen = sizeof(control_un.control);
841 msg.msg_flags = 0;
842 #else
843 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
844 #endif /* CMSG_FIRSTHDR */
846 msg.msg_name = (char *) sa;
847 msg.msg_namelen = *salenptr;
848 iov[0].iov_base = (char *)ptr;
849 iov[0].iov_len = nbytes;
850 msg.msg_iov = iov;
851 msg.msg_iovlen = 1;
853 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
854 return(n);
856 *salenptr = msg.msg_namelen; /* pass back results */
857 if (pktp) {
858 /* 0.0.0.0, i/f = -1 */
859 /* We set the interface to -1 so that the caller can
860 tell whether we returned a meaningful value or
861 just some default. Previously this code just
862 set the value to 0, but I'm concerned that 0
863 might be a valid interface value.
865 memset(pktp, 0, sizeof(struct my_in_pktinfo));
866 pktp->ipi_ifindex = -1;
868 /* end recvfrom_flags1 */
870 /* include recvfrom_flags2 */
871 #ifndef CMSG_FIRSTHDR
872 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
873 *flagsp = 0; /* pass back results */
874 return(n);
875 #else
877 *flagsp = msg.msg_flags; /* pass back results */
878 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
879 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
880 return(n);
882 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
883 cmptr = CMSG_NXTHDR(&msg, cmptr)) {
885 #ifdef IP_PKTINFO
886 #if in_pktinfo_definition_is_missing
887 struct in_pktinfo
889 int ipi_ifindex;
890 struct in_addr ipi_spec_dst;
891 struct in_addr ipi_addr;
893 #endif
894 if (cmptr->cmsg_level == IPPROTO_IP &&
895 cmptr->cmsg_type == IP_PKTINFO) {
896 struct in_pktinfo *tmp;
897 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
899 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
900 sin->sin_family = AF_INET;
901 sin->sin_addr = tmp->ipi_addr;
902 sin->sin_port = 0;
903 pktp->ipi_ifindex = tmp->ipi_ifindex;
904 continue;
906 #endif
908 #ifdef IP_RECVDSTADDR
909 if (cmptr->cmsg_level == IPPROTO_IP &&
910 cmptr->cmsg_type == IP_RECVDSTADDR) {
911 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
913 sin->sin_family = AF_INET;
914 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
915 sin->sin_port = 0;
916 continue;
918 #endif
920 #ifdef IP_RECVIF
921 if (cmptr->cmsg_level == IPPROTO_IP &&
922 cmptr->cmsg_type == IP_RECVIF) {
923 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
924 #ifndef HAVE_BROKEN_RECVIF_NAME
925 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
926 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
927 #endif
929 * the is memcpy used for sparc? no idea;)
930 * pktp->ipi_ifindex = sdl->sdl_index;
932 (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
933 #ifdef HAVE_BROKEN_RECVIF_NAME
934 if (sdl->sdl_index == 0) {
935 pktp->ipi_ifindex = *(uint_t*)sdl;
937 #endif
938 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
939 // null terminated because of memset above
940 continue;
942 #endif
944 #ifdef IP_RECVTTL
945 if (cmptr->cmsg_level == IPPROTO_IP &&
946 cmptr->cmsg_type == IP_RECVTTL) {
947 *ttl = *(u_char*)CMSG_DATA(cmptr);
948 continue;
950 else if (cmptr->cmsg_level == IPPROTO_IP &&
951 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
952 *ttl = *(int*)CMSG_DATA(cmptr);
953 continue;
955 #endif
957 #if defined(IPV6_PKTINFO) && HAVE_IPV6
958 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
959 cmptr->cmsg_type == IPV6_PKTINFO) {
960 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
961 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
963 sin6->sin6_family = AF_INET6;
964 #ifndef NOT_HAVE_SA_LEN
965 sin6->sin6_len = sizeof(*sin6);
966 #endif
967 sin6->sin6_addr = ip6_info->ipi6_addr;
968 sin6->sin6_flowinfo = 0;
969 sin6->sin6_scope_id = 0;
970 sin6->sin6_port = 0;
971 pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
972 continue;
974 #endif
976 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
977 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
978 cmptr->cmsg_type == IPV6_HOPLIMIT) {
979 *ttl = *(int*)CMSG_DATA(cmptr);
980 continue;
982 #endif
983 assert(0); // unknown ancillary data
985 return(n);
986 #endif /* CMSG_FIRSTHDR */
989 // **********************************************************************************************
991 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
992 // Returns 0 on success, -1 on failure.
994 #ifdef NOT_HAVE_DAEMON
995 #include <fcntl.h>
996 #include <sys/stat.h>
997 #include <sys/signal.h>
999 int daemon(int nochdir, int noclose)
1001 switch (fork())
1003 case -1: return (-1); // Fork failed
1004 case 0: break; // Child -- continue
1005 default: _exit(0); // Parent -- exit
1008 if (setsid() == -1) return(-1);
1010 signal(SIGHUP, SIG_IGN);
1012 switch (fork()) // Fork again, primarily for reasons of Unix trivia
1014 case -1: return (-1); // Fork failed
1015 case 0: break; // Child -- continue
1016 default: _exit(0); // Parent -- exit
1019 if (!nochdir) (void)chdir("/");
1020 umask(0);
1022 if (!noclose)
1024 int fd = open("/dev/null", O_RDWR, 0);
1025 if (fd != -1)
1027 // Avoid unnecessarily duplicating a file descriptor to itself
1028 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
1029 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
1030 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
1031 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
1032 (void)close (fd);
1035 return (0);
1037 #endif /* NOT_HAVE_DAEMON */