xref: /titanic_44/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNSUNP.c (revision 7014882c6a3672fd0e5d60200af8643ae53c5928)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /* -*- Mode: C; tab-width: 4 -*-
6  *
7  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #include "mDNSUNP.h"
23 
24 #include "mDNSDebug.h"
25 
26 #include <errno.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/uio.h>
31 #include <sys/ioctl.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 
35 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
36    macro, usually defined in <sys/param.h> or someplace like that, to make sure the
37    CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
38    should be set to the name of the header to include to get the ALIGN(P) macro.
39 */
40 #ifdef NEED_ALIGN_MACRO
41 #include NEED_ALIGN_MACRO
42 #endif
43 
44 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
45    other platforms don't even have that include file.  So,
46    if we haven't yet got a definition, let's try to find
47    <sys/sockio.h>.
48 */
49 
50 #ifndef SIOCGIFCONF
51     #include <sys/sockio.h>
52 #endif
53 
54 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
55    so only include the header in that case.
56 */
57 
58 #ifdef  IP_RECVIF
59     #include <net/if_dl.h>
60 #endif
61 
62 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
63 #if !HAVE_SOLARIS
64 #include <net/if_var.h>
65 #else
66 #include <alloca.h>
67 #endif /* !HAVE_SOLARIS */
68 #include <netinet/in_var.h>
69 // NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
70 #endif
71 
72 #if defined(AF_INET6) && HAVE_IPV6
73 
74 #if HAVE_LINUX
75 #include <netdb.h>
76 #include <arpa/inet.h>
77 
78 /* Converts a prefix length to IPv6 network mask */
79 void plen_to_mask(int plen, char *addr) {
80 	int i;
81 	int colons=7; /* Number of colons in IPv6 address */
82 	int bits_in_block=16; /* Bits per IPv6 block */
83 	for(i=0;i<=colons;i++) {
84 		int block, ones=0xffff, ones_in_block;
85 		if(plen>bits_in_block) ones_in_block=bits_in_block;
86 		else                   ones_in_block=plen;
87 		block = ones & (ones << (bits_in_block-ones_in_block));
88 		i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
89 		plen -= ones_in_block;
90 		}
91 	}
92 
93 /* Gets IPv6 interface information from the /proc filesystem in linux*/
94 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
95 	{
96 	struct ifi_info *ifi, *ifihead, **ifipnext;
97 	FILE *fp;
98 	char addr[8][5];
99 	int flags, myflags, index, plen, scope;
100 	char ifname[8], lastname[IFNAMSIZ];
101 	char addr6[32+7+1]; /* don't forget the seven ':' */
102 	struct addrinfo hints, *res0;
103 	struct sockaddr_in6 *sin6;
104 	struct in6_addr *addrptr;
105 	int err;
106 
107 	res0=NULL;
108 	ifihead = NULL;
109 	ifipnext = &ifihead;
110 	lastname[0] = 0;
111 
112 	if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
113 		while (fscanf(fp,
114 					  "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
115 					  addr[0],addr[1],addr[2],addr[3],
116 					  addr[4],addr[5],addr[6],addr[7],
117 					  &index, &plen, &scope, &flags, ifname) != EOF) {
118 
119 			myflags = 0;
120 			if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
121 				if (doaliases == 0)
122 					continue;   /* already processed this interface */
123 				myflags = IFI_ALIAS;
124 				}
125 			memcpy(lastname, ifname, IFNAMSIZ);
126 			ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
127 			if (ifi == NULL) {
128 				goto gotError;
129 				}
130 
131 			*ifipnext = ifi;            /* prev points to this new one */
132 			ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
133 
134 			sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
135 					addr[0],addr[1],addr[2],addr[3],
136 					addr[4],addr[5],addr[6],addr[7]);
137 
138 			/* Add address of the interface */
139 			memset(&hints, 0, sizeof(hints));
140 			hints.ai_family = AF_INET6;
141 			hints.ai_flags = AI_NUMERICHOST;
142 			err = getaddrinfo(addr6, NULL, &hints, &res0);
143 			if (err) {
144 				goto gotError;
145 				}
146 			ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
147 			if (ifi->ifi_addr == NULL) {
148 				goto gotError;
149 				}
150 			memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
151 
152 			/* Add netmask of the interface */
153 			char ipv6addr[INET6_ADDRSTRLEN];
154 			plen_to_mask(plen, ipv6addr);
155 			ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
156 			if (ifi->ifi_addr == NULL) {
157 				goto gotError;
158 				}
159 			sin6=calloc(1, sizeof(struct sockaddr_in6));
160 			addrptr=calloc(1, sizeof(struct in6_addr));
161 			inet_pton(family, ipv6addr, addrptr);
162 			sin6->sin6_family=family;
163 			sin6->sin6_addr=*addrptr;
164 			sin6->sin6_scope_id=scope;
165 			memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
166 			free(sin6);
167 
168 
169 			/* Add interface name */
170 			memcpy(ifi->ifi_name, ifname, IFI_NAME);
171 
172 			/* Add interface index */
173 			ifi->ifi_index = index;
174 
175 			/* If interface is in /proc then it is up*/
176 			ifi->ifi_flags = IFF_UP;
177 
178 			freeaddrinfo(res0);
179 			res0=NULL;
180 			}
181 		}
182 	goto done;
183 
184 	gotError:
185 	if (ifihead != NULL) {
186 		free_ifi_info(ifihead);
187 		ifihead = NULL;
188 		}
189 	if (res0 != NULL) {
190 		freeaddrinfo(res0);
191 		res0=NULL;
192 		}
193 	done:
194 	return(ifihead);    /* pointer to first structure in linked list */
195 	}
196 
197 #endif  /* LINUX */
198 #endif  /* defined(AF_INET6) && HAVE_IPV6 */
199 
200 #if HAVE_SOLARIS
201 
202 /*
203  * Converts prefix length to network mask. Assumes
204  * addr points to a zeroed out buffer and prefix <= sizeof(addr)
205  * Unlike plen_to_mask returns netmask in binary form and not
206  * in text form.
207  */
208 static void plen_to_netmask(int prefix, unsigned char *addr) {
209     for (; prefix > 8; prefix -= 8)
210         *addr++ = 0xff;
211     for (; prefix > 0; prefix--)
212         *addr = (*addr >> 1) | 0x80;
213 }
214 
215 /*
216  * This function goes through all the IP interfaces associated with a
217  * physical interface and finds the best matched one for use by mDNS.
218  * Returns NULL when none of the IP interfaces associated with a physical
219  * interface are usable. Otherwise returns the best matched interface
220  * information and a pointer to the best matched lifreq.
221  */
222 struct ifi_info *
223 select_src_ifi_info_solaris(int sockfd, int numifs,
224         struct lifreq *lifrlist, const char *curifname,
225         struct lifreq **best_lifr)
226 {
227     struct lifreq *lifr;
228     struct lifreq lifrcopy;
229     struct ifi_info *ifi;
230     char *chptr;
231     char cmpifname[LIFNAMSIZ];
232     int i;
233     uint64_t best_lifrflags;
234     uint64_t ifflags;
235 
236     *best_lifr = NULL;
237 
238     /*
239      * Check all logical interfaces associated with the physical
240      * interface and figure out which one works best for us.
241      */
242     for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
243 
244         if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
245             continue; /* skip interface */
246 
247         /* Strip logical interface number before checking ifname */
248         if ((chptr = strchr(cmpifname, ':')) != NULL)
249             *chptr = '\0';
250 
251         /*
252          * Check ifname to see if the logical interface is associated
253          * with the physical interface we are interested in.
254          */
255         if (strcmp(cmpifname, curifname) != 0)
256             continue;
257 
258         lifrcopy = *lifr;
259         if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
260             /* interface removed */
261             if (errno == ENXIO)
262                 continue;
263             return(NULL);
264         }
265         ifflags = lifrcopy.lifr_flags;
266 
267         /* ignore address if not up */
268         if ((ifflags & IFF_UP) == 0)
269             continue;
270         /*
271          * Avoid address if any of the following flags are set:
272          *  IFF_NOXMIT: no packets transmitted over interface
273          *  IFF_NOLOCAL: no address
274          *  IFF_PRIVATE: is not advertised
275          */
276         if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
277             continue;
278 
279 	/* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
280         if (lifr->lifr_addr.ss_family == AF_INET) {
281 		struct sockaddr_in *sinptr;
282 
283 		sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
284 		if (sinptr->sin_addr.s_addr == INADDR_ANY)
285 			continue;
286 	}
287 
288         if (*best_lifr != NULL) {
289             /*
290              * Check if we found a better interface by checking
291              * the flags. If flags are identical we prefer
292              * the new found interface.
293              */
294             uint64_t diff_flags = best_lifrflags ^ ifflags;
295 
296             /* If interface has a different set of flags */
297             if (diff_flags != 0) {
298                 /* Check flags in increasing order of ones we prefer */
299 
300                 /* Address temporary? */
301                 if ((diff_flags & IFF_TEMPORARY) &&
302                     (ifflags & IFF_TEMPORARY))
303                     continue;
304                 /* Deprecated address? */
305                 if ((diff_flags & IFF_DEPRECATED) &&
306                     (ifflags & IFF_DEPRECATED))
307                     continue;
308                 /* Last best-matched interface address has preferred? */
309                 if ((diff_flags & IFF_PREFERRED) &&
310                     ((ifflags & IFF_PREFERRED) == 0))
311                     continue;
312             }
313         }
314 
315         /* Set best match interface & flags */
316         *best_lifr = lifr;
317         best_lifrflags = ifflags;
318     }
319 
320     if (*best_lifr == NULL)
321         return(NULL);
322 
323     /* Found a match: return the interface information */
324     ifi = calloc(1, sizeof(struct ifi_info));
325     if (ifi == NULL)
326         return(NULL);
327 
328     ifi->ifi_flags = best_lifrflags;
329     ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
330     if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
331         free(ifi);
332         return(NULL);
333     }
334     return(ifi);
335 }
336 
337 /*
338  * Returns a list of IP interface information on Solaris. The function
339  * returns all IP interfaces on the system with IPv4 address assigned
340  * when passed AF_INET and returns IP interfaces with IPv6 address assigned
341  * when AF_INET6 is passed.
342  */
343 struct ifi_info *get_ifi_info_solaris(int family)
344 {
345     struct ifi_info     *ifi, *ifihead, **ifipnext;
346     int   sockfd;
347     int  len;
348     char  *buf;
349     char *cptr;
350     char  ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
351     struct sockaddr_in *sinptr;
352     struct lifnum lifn;
353     struct lifconf lifc;
354     struct lifreq *lifrp, *best_lifr;
355     struct lifreq lifrcopy;
356     int numifs, nlifr, n;
357 #if defined(AF_INET6) && HAVE_IPV6
358     struct sockaddr_in6 *sinptr6;
359 #endif
360 
361     ifihead = NULL;
362 
363     sockfd = socket(family, SOCK_DGRAM, 0);
364     if (sockfd < 0)
365         goto gotError;
366 
367 again:
368     lifn.lifn_family = family;
369     lifn.lifn_flags = 0;
370     if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
371         goto gotError;
372     /*
373      * Pad interface count to detect & retrieve any
374      * additional interfaces between IFNUM & IFCONF calls.
375      */
376     lifn.lifn_count += 4;
377     numifs = lifn.lifn_count;
378     len = numifs * sizeof (struct lifreq);
379     buf = alloca(len);
380 
381     lifc.lifc_family = family;
382     lifc.lifc_len = len;
383     lifc.lifc_buf = buf;
384     lifc.lifc_flags = 0;
385 
386     if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
387         goto gotError;
388 
389     nlifr = lifc.lifc_len / sizeof(struct lifreq);
390     if (nlifr >= numifs)
391         goto again;
392 
393     lifrp = lifc.lifc_req;
394     ifipnext = &ifihead;
395 
396     for (n = nlifr; n > 0; n--, lifrp++) {
397 
398         if (lifrp->lifr_addr.ss_family != family)
399             continue;
400 
401         /*
402          * See if we have already processed the interface
403          * by checking the interface names.
404          */
405         if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
406             goto gotError;
407         if ((cptr = strchr(ifname, ':')) != NULL)
408             *cptr = '\0';
409 
410         /*
411          * If any of the interfaces found so far share the physical
412          * interface name then we have already processed the interface.
413          */
414         for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
415 
416             /* Retrieve physical interface name */
417             (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
418 
419             /* Strip logical interface number before checking ifname */
420             if ((cptr = strchr(cmpifname, ':')) != NULL)
421                 *cptr = '\0';
422 
423             if (strcmp(cmpifname, ifname) == 0)
424                 break;
425         }
426         if (ifi != NULL)
427             continue; /* already processed */
428 
429         /*
430          * New interface, find the one with the preferred source
431          * address for our use in Multicast DNS.
432          */
433         if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
434             lifc.lifc_req, ifname, &best_lifr)) == NULL)
435             continue;
436 
437         assert(best_lifr != NULL);
438         assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
439                (best_lifr->lifr_addr.ss_family == AF_INET));
440 
441         switch (best_lifr->lifr_addr.ss_family) {
442 
443 #if defined(AF_INET6) && HAVE_IPV6
444         case AF_INET6:
445             sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
446             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
447             if (ifi->ifi_addr == NULL)
448                 goto gotError;
449             memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
450 
451             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
452             if (ifi->ifi_netmask == NULL)
453                 goto gotError;
454             sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
455             sinptr6->sin6_family = AF_INET6;
456             plen_to_netmask(best_lifr->lifr_addrlen,
457                     (unsigned char *) &(sinptr6->sin6_addr));
458             break;
459 #endif
460 
461         case AF_INET:
462             sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
463             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
464             if (ifi->ifi_addr == NULL)
465                 goto gotError;
466 
467             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
468 
469             lifrcopy = *best_lifr;
470             if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
471                 /* interface removed */
472                 if (errno == ENXIO) {
473                     free(ifi->ifi_addr);
474                     free(ifi);
475                     continue;
476                 }
477                 goto gotError;
478             }
479 
480             ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
481             if (ifi->ifi_netmask == NULL)
482                 goto gotError;
483             sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
484             sinptr->sin_family = AF_INET;
485             memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
486             break;
487 
488         default:
489             /* never reached */
490             break;
491         }
492 
493         *ifipnext = ifi;            /* prev points to this new one */
494         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
495     }
496 
497     (void) close(sockfd);
498     return(ifihead);    /* pointer to first structure in linked list */
499 
500 gotError:
501     if (sockfd != -1)
502         (void) close(sockfd);
503     if (ifihead != NULL)
504         free_ifi_info(ifihead);
505     return(NULL);
506 }
507 
508 #endif /* HAVE_SOLARIS */
509 
510 struct ifi_info *get_ifi_info(int family, int doaliases)
511 {
512     int                 junk;
513     struct ifi_info     *ifi, *ifihead, **ifipnext;
514     int                 sockfd, sockf6, len, lastlen, flags, myflags;
515 #ifdef NOT_HAVE_IF_NAMETOINDEX
516     int                 index = 200;
517 #endif
518     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
519     struct ifconf       ifc;
520     struct ifreq        *ifr, ifrcopy;
521     struct sockaddr_in  *sinptr;
522 
523 #if defined(AF_INET6) && HAVE_IPV6
524     struct sockaddr_in6 *sinptr6;
525 #endif
526 
527 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
528     if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
529 #elif HAVE_SOLARIS
530     return get_ifi_info_solaris(family);
531 #endif
532 
533     sockfd = -1;
534     sockf6 = -1;
535     buf = NULL;
536     ifihead = NULL;
537 
538     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
539     if (sockfd < 0) {
540         goto gotError;
541     }
542 
543     lastlen = 0;
544     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
545     for ( ; ; ) {
546         buf = (char*)malloc(len);
547         if (buf == NULL) {
548             goto gotError;
549         }
550         ifc.ifc_len = len;
551         ifc.ifc_buf = buf;
552         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
553             if (errno != EINVAL || lastlen != 0) {
554                 goto gotError;
555             }
556         } else {
557             if (ifc.ifc_len == lastlen)
558                 break;      /* success, len has not changed */
559             lastlen = ifc.ifc_len;
560         }
561         len += 10 * sizeof(struct ifreq);   /* increment */
562         free(buf);
563     }
564     ifihead = NULL;
565     ifipnext = &ifihead;
566     lastname[0] = 0;
567 /* end get_ifi_info1 */
568 
569 /* include get_ifi_info2 */
570     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
571         ifr = (struct ifreq *) ptr;
572 
573         /* Advance to next one in buffer */
574         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
575             ptr += sizeof(struct ifreq);
576         else
577             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
578 
579 //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
580 
581         if (ifr->ifr_addr.sa_family != family)
582             continue;   /* ignore if not desired address family */
583 
584         myflags = 0;
585         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
586             *cptr = 0;      /* replace colon will null */
587         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
588             if (doaliases == 0)
589                 continue;   /* already processed this interface */
590             myflags = IFI_ALIAS;
591         }
592         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
593 
594         ifrcopy = *ifr;
595         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
596             goto gotError;
597         }
598 
599         flags = ifrcopy.ifr_flags;
600         if ((flags & IFF_UP) == 0)
601             continue;   /* ignore if interface not up */
602 
603         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
604         if (ifi == NULL) {
605             goto gotError;
606         }
607         *ifipnext = ifi;            /* prev points to this new one */
608         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
609 
610         ifi->ifi_flags = flags;     /* IFF_xxx values */
611         ifi->ifi_myflags = myflags; /* IFI_xxx values */
612 #ifndef NOT_HAVE_IF_NAMETOINDEX
613         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
614 #else
615         ifrcopy = *ifr;
616 #ifdef SIOCGIFINDEX
617         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
618             ifi->ifi_index = ifrcopy.ifr_index;
619         else
620 #endif
621             ifi->ifi_index = index++;	/* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
622 #endif
623         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
624         ifi->ifi_name[IFI_NAME-1] = '\0';
625 /* end get_ifi_info2 */
626 /* include get_ifi_info3 */
627         switch (ifr->ifr_addr.sa_family) {
628         case AF_INET:
629             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
630             if (ifi->ifi_addr == NULL) {
631                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
632                 if (ifi->ifi_addr == NULL) {
633                     goto gotError;
634                 }
635                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
636 
637 #ifdef  SIOCGIFNETMASK
638 				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
639 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
640 				if (ifi->ifi_netmask == NULL) goto gotError;
641 				sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
642 				/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
643 #ifndef NOT_HAVE_SA_LEN
644 				sinptr->sin_len    = sizeof(struct sockaddr_in);
645 #endif
646 				sinptr->sin_family = AF_INET;
647 				memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
648 #endif
649 
650 #ifdef  SIOCGIFBRDADDR
651                 if (flags & IFF_BROADCAST) {
652                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
653                         goto gotError;
654                     }
655                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
656 					/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
657 #ifndef NOT_HAVE_SA_LEN
658 					sinptr->sin_len    = sizeof( struct sockaddr_in );
659 #endif
660 					sinptr->sin_family = AF_INET;
661                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
662                     if (ifi->ifi_brdaddr == NULL) {
663                         goto gotError;
664                     }
665                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
666                 }
667 #endif
668 
669 #ifdef  SIOCGIFDSTADDR
670                 if (flags & IFF_POINTOPOINT) {
671                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
672                         goto gotError;
673                     }
674                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
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                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
681                     if (ifi->ifi_dstaddr == NULL) {
682                         goto gotError;
683                     }
684                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
685                 }
686 #endif
687             }
688             break;
689 
690 #if defined(AF_INET6) && HAVE_IPV6
691         case AF_INET6:
692             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
693             if (ifi->ifi_addr == NULL) {
694                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
695                 if (ifi->ifi_addr == NULL) {
696                     goto gotError;
697                 }
698 
699                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
700                 /* We need to strip that out */
701                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
702                 	sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
703                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
704 
705 #ifdef  SIOCGIFNETMASK_IN6
706 				{
707 				struct in6_ifreq ifr6;
708 				if (sockf6 == -1)
709 					sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
710 				bzero(&ifr6, sizeof(ifr6));
711 				memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
712 				memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
713 				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
714 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
715 				if (ifi->ifi_netmask == NULL) goto gotError;
716 				sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
717 				memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
718 				}
719 #endif
720             }
721             break;
722 #endif
723 
724         default:
725             break;
726         }
727     }
728     goto done;
729 
730 gotError:
731     if (ifihead != NULL) {
732         free_ifi_info(ifihead);
733         ifihead = NULL;
734     }
735 
736 done:
737     if (buf != NULL) {
738         free(buf);
739     }
740     if (sockfd != -1) {
741         junk = close(sockfd);
742         assert(junk == 0);
743     }
744     if (sockf6 != -1) {
745         junk = close(sockf6);
746         assert(junk == 0);
747     }
748     return(ifihead);    /* pointer to first structure in linked list */
749 }
750 /* end get_ifi_info3 */
751 
752 /* include free_ifi_info */
753 void
754 free_ifi_info(struct ifi_info *ifihead)
755 {
756     struct ifi_info *ifi, *ifinext;
757 
758     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
759         if (ifi->ifi_addr != NULL)
760             free(ifi->ifi_addr);
761         if (ifi->ifi_brdaddr != NULL)
762             free(ifi->ifi_brdaddr);
763         if (ifi->ifi_dstaddr != NULL)
764             free(ifi->ifi_dstaddr);
765         if (ifi->ifi_netmask != NULL)
766             free(ifi->ifi_netmask);
767         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
768         free(ifi);                  /* the ifi_info{} itself */
769     }
770 }
771 /* end free_ifi_info */
772 
773 ssize_t
774 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
775                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
776 {
777     struct msghdr   msg;
778     struct iovec    iov[1];
779     ssize_t         n;
780 
781 #ifdef CMSG_FIRSTHDR
782     struct cmsghdr  *cmptr;
783     union {
784       struct cmsghdr    cm;
785       char              control[1024];
786       pad64_t	align8; /* ensure structure is 8-byte aligned on sparc */
787     } control_un;
788 
789 	*ttl = 255;			// If kernel fails to provide TTL data then assume the TTL was 255 as it should be
790 
791     msg.msg_control = (void *) control_un.control;
792     msg.msg_controllen = sizeof(control_un.control);
793     msg.msg_flags = 0;
794 #else
795     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
796 #endif /* CMSG_FIRSTHDR */
797 
798     msg.msg_name = (char *) sa;
799     msg.msg_namelen = *salenptr;
800     iov[0].iov_base = (char *)ptr;
801     iov[0].iov_len = nbytes;
802     msg.msg_iov = iov;
803     msg.msg_iovlen = 1;
804 
805     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
806         return(n);
807 
808     *salenptr = msg.msg_namelen;    /* pass back results */
809     if (pktp) {
810         /* 0.0.0.0, i/f = -1 */
811         /* We set the interface to -1 so that the caller can
812            tell whether we returned a meaningful value or
813            just some default.  Previously this code just
814            set the value to 0, but I'm concerned that 0
815            might be a valid interface value.
816         */
817         memset(pktp, 0, sizeof(struct my_in_pktinfo));
818         pktp->ipi_ifindex = -1;
819     }
820 /* end recvfrom_flags1 */
821 
822 /* include recvfrom_flags2 */
823 #ifndef CMSG_FIRSTHDR
824 	#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
825     *flagsp = 0;                    /* pass back results */
826     return(n);
827 #else
828 
829     *flagsp = msg.msg_flags;        /* pass back results */
830     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
831         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
832         return(n);
833 
834     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
835          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
836 
837 #ifdef  IP_PKTINFO
838 #if in_pktinfo_definition_is_missing
839 struct in_pktinfo
840 {
841         int             ipi_ifindex;
842         struct in_addr  ipi_spec_dst;
843         struct in_addr  ipi_addr;
844 };
845 #endif
846         if (cmptr->cmsg_level == IPPROTO_IP &&
847             cmptr->cmsg_type == IP_PKTINFO) {
848             struct in_pktinfo *tmp;
849             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
850 
851             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
852             sin->sin_family = AF_INET;
853             sin->sin_addr = tmp->ipi_addr;
854             sin->sin_port = 0;
855             pktp->ipi_ifindex = tmp->ipi_ifindex;
856             continue;
857         }
858 #endif
859 
860 #ifdef  IP_RECVDSTADDR
861         if (cmptr->cmsg_level == IPPROTO_IP &&
862             cmptr->cmsg_type == IP_RECVDSTADDR) {
863             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
864 
865             sin->sin_family = AF_INET;
866             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
867             sin->sin_port = 0;
868             continue;
869         }
870 #endif
871 
872 #ifdef  IP_RECVIF
873         if (cmptr->cmsg_level == IPPROTO_IP &&
874             cmptr->cmsg_type == IP_RECVIF) {
875             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
876 #ifndef HAVE_BROKEN_RECVIF_NAME
877             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
878             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
879 #endif
880 	    (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
881             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
882             // null terminated because of memset above
883             continue;
884         }
885 #endif
886 
887 #ifdef  IP_RECVTTL
888         if (cmptr->cmsg_level == IPPROTO_IP &&
889             cmptr->cmsg_type == IP_RECVTTL) {
890 			*ttl = *(u_char*)CMSG_DATA(cmptr);
891             continue;
892         }
893         else if (cmptr->cmsg_level == IPPROTO_IP &&
894             cmptr->cmsg_type == IP_TTL) {		// some implementations seem to send IP_TTL instead of IP_RECVTTL
895 			*ttl = *(int*)CMSG_DATA(cmptr);
896             continue;
897         }
898 #endif
899 
900 #if defined(IPV6_PKTINFO) && HAVE_IPV6
901         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
902             cmptr->cmsg_type == IPV6_PKTINFO) {
903             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
904 			struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
905 
906             sin6->sin6_family   = AF_INET6;
907 #ifndef NOT_HAVE_SA_LEN
908             sin6->sin6_len      = sizeof(*sin6);
909 #endif
910             sin6->sin6_addr     = ip6_info->ipi6_addr;
911             sin6->sin6_flowinfo = 0;
912             sin6->sin6_scope_id = 0;
913             sin6->sin6_port     = 0;
914 			pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
915             continue;
916         }
917 #endif
918 
919 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
920         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
921             cmptr->cmsg_type == IPV6_HOPLIMIT) {
922 			*ttl = *(int*)CMSG_DATA(cmptr);
923             continue;
924         }
925 #endif
926         assert(0);  // unknown ancillary data
927     }
928     return(n);
929 #endif /* CMSG_FIRSTHDR */
930 }
931 
932 // **********************************************************************************************
933 
934 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
935 // Returns 0 on success, -1 on failure.
936 
937 #ifdef NOT_HAVE_DAEMON
938 #include <fcntl.h>
939 #include <sys/stat.h>
940 #include <signal.h>
941 
942 int daemon(int nochdir, int noclose)
943     {
944 	switch (fork())
945 		{
946 		case -1: return (-1);	// Fork failed
947 		case 0:  break;			// Child -- continue
948 		default: _exit(0);		// Parent -- exit
949 		}
950 
951 	if (setsid() == -1) return(-1);
952 
953 	signal(SIGHUP, SIG_IGN);
954 
955 	switch (fork())				// Fork again, primarily for reasons of Unix trivia
956 		{
957 		case -1: return (-1);	// Fork failed
958 		case 0:  break;			// Child -- continue
959 		default: _exit(0);		// Parent -- exit
960 		}
961 
962 	if (!nochdir) (void)chdir("/");
963 	umask(0);
964 
965 	if (!noclose)
966 		{
967 		int fd = open("/dev/null", O_RDWR, 0);
968 		if (fd != -1)
969 			{
970 			// Avoid unnecessarily duplicating a file descriptor to itself
971 			if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
972 			if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
973 			if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
974 			if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
975 				(void)close (fd);
976 			}
977 		}
978 	return (0);
979     }
980 #endif /* NOT_HAVE_DAEMON */
981