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