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