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 */
plen_to_mask(int plen,char * addr)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*/
get_ifi_info_linuxv6(int family,int doaliases)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 */
plen_to_netmask(int prefix,unsigned char * addr)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 *
select_src_ifi_info_solaris(int sockfd,int numifs,struct lifreq * lifrlist,const char * curifname,struct lifreq ** best_lifr)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 */
get_ifi_info_solaris(int family)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
get_ifi_info(int family,int doaliases)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
free_ifi_info(struct ifi_info * ifihead)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
recvfrom_flags(int fd,void * ptr,size_t nbytes,int * flagsp,struct sockaddr * sa,socklen_t * salenptr,struct my_in_pktinfo * pktp,u_char * ttl)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
daemon(int nochdir,int noclose)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