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