1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/ioctl.h>
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.
35 #ifdef NEED_ALIGN_MACRO
36 #include NEED_ALIGN_MACRO
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
46 #include <sys/sockio.h>
49 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
50 so only include the header in that case.
54 #include <net/if_dl.h>
57 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
59 #include <net/if_var.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
67 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
69 #include <arpa/inet.h>
71 /* Converts a prefix length to IPv6 network mask */
72 void plen_to_mask(int plen
, char *addr
) {
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
;
86 /* Gets IPv6 interface information from the /proc filesystem in linux*/
87 struct ifi_info
*get_ifi_info_linuxv6(int family
, int doaliases
)
89 struct ifi_info
*ifi
, *ifihead
, **ifipnext
, *ifipold
, **ifiptr
;
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
;
105 if ((fp
= fopen(PROC_IFINET6_PATH
, "r")) != NULL
) {
106 sockfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
111 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
112 addr
[0],addr
[1],addr
[2],addr
[3],
113 addr
[4],addr
[5],addr
[6],addr
[7],
114 &index
, &plen
, &scope
, &flags
, ifname
) != EOF
) {
117 if (strncmp(lastname
, ifname
, IFNAMSIZ
) == 0) {
119 continue; /* already processed this interface */
122 memcpy(lastname
, ifname
, IFNAMSIZ
);
123 ifi
= (struct ifi_info
*)calloc(1, sizeof(struct ifi_info
));
128 ifipold
= *ifipnext
; /* need this later */
130 *ifipnext
= ifi
; /* prev points to this new one */
131 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
133 sprintf(addr6
, "%s:%s:%s:%s:%s:%s:%s:%s",
134 addr
[0],addr
[1],addr
[2],addr
[3],
135 addr
[4],addr
[5],addr
[6],addr
[7]);
137 /* Add address of the interface */
138 memset(&hints
, 0, sizeof(hints
));
139 hints
.ai_family
= AF_INET6
;
140 hints
.ai_flags
= AI_NUMERICHOST
;
141 err
= getaddrinfo(addr6
, NULL
, &hints
, &res0
);
145 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in6
));
146 if (ifi
->ifi_addr
== NULL
) {
149 memcpy(ifi
->ifi_addr
, res0
->ai_addr
, sizeof(struct sockaddr_in6
));
151 /* Add netmask of the interface */
152 char ipv6addr
[INET6_ADDRSTRLEN
];
153 plen_to_mask(plen
, ipv6addr
);
154 ifi
->ifi_netmask
= calloc(1, sizeof(struct sockaddr_in6
));
155 if (ifi
->ifi_netmask
== NULL
) {
159 ((struct sockaddr_in6
*)ifi
->ifi_netmask
)->sin6_family
=family
;
160 ((struct sockaddr_in6
*)ifi
->ifi_netmask
)->sin6_scope_id
=scope
;
161 inet_pton(family
, ipv6addr
, &((struct sockaddr_in6
*)ifi
->ifi_netmask
)->sin6_addr
);
163 /* Add interface name */
164 memcpy(ifi
->ifi_name
, ifname
, IFI_NAME
);
166 /* Add interface index */
167 ifi
->ifi_index
= index
;
169 /* Add interface flags*/
170 memcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
171 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
172 if (errno
== EADDRNOTAVAIL
) {
174 * If the main interface is configured with no IP address but
175 * an alias interface exists with an IP address, you get
176 * EADDRNOTAVAIL for the main interface
179 free(ifi
->ifi_netmask
);
188 ifi
->ifi_flags
= ifr
.ifr_flags
;
196 if (ifihead
!= NULL
) {
197 free_ifi_info(ifihead
);
206 assert(close(sockfd
) == 0);
211 return(ifihead
); /* pointer to first structure in linked list */
213 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
218 * Converts prefix length to network mask. Assumes
219 * addr points to a zeroed out buffer and prefix <= sizeof(addr)
220 * Unlike plen_to_mask returns netmask in binary form and not
223 static void plen_to_netmask(int prefix
, unsigned char *addr
) {
224 for (; prefix
> 8; prefix
-= 8)
226 for (; prefix
> 0; prefix
--)
227 *addr
= (*addr
>> 1) | 0x80;
231 * This function goes through all the IP interfaces associated with a
232 * physical interface and finds the best matched one for use by mDNS.
233 * Returns NULL when none of the IP interfaces associated with a physical
234 * interface are usable. Otherwise returns the best matched interface
235 * information and a pointer to the best matched lifreq.
238 select_src_ifi_info_solaris(int sockfd
, int numifs
,
239 struct lifreq
*lifrlist
, const char *curifname
,
240 struct lifreq
**best_lifr
)
243 struct lifreq lifrcopy
;
244 struct ifi_info
*ifi
;
246 char cmpifname
[LIFNAMSIZ
];
248 uint64_t best_lifrflags
= 0;
254 * Check all logical interfaces associated with the physical
255 * interface and figure out which one works best for us.
257 for (i
= numifs
, lifr
= lifrlist
; i
> 0; --i
, ++lifr
) {
259 if (strlcpy(cmpifname
, lifr
->lifr_name
, sizeof(cmpifname
)) >= sizeof(cmpifname
))
260 continue; /* skip interface */
262 /* Strip logical interface number before checking ifname */
263 if ((chptr
= strchr(cmpifname
, ':')) != NULL
)
267 * Check ifname to see if the logical interface is associated
268 * with the physical interface we are interested in.
270 if (strcmp(cmpifname
, curifname
) != 0)
274 if (ioctl(sockfd
, SIOCGLIFFLAGS
, &lifrcopy
) < 0) {
275 /* interface removed */
280 ifflags
= lifrcopy
.lifr_flags
;
282 /* ignore address if not up */
283 if ((ifflags
& IFF_UP
) == 0)
286 * Avoid address if any of the following flags are set:
287 * IFF_NOXMIT: no packets transmitted over interface
288 * IFF_NOLOCAL: no address
289 * IFF_PRIVATE: is not advertised
291 if (ifflags
& (IFF_NOXMIT
| IFF_NOLOCAL
| IFF_PRIVATE
))
294 /* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
295 if (lifr
->lifr_addr
.ss_family
== AF_INET
) {
296 struct sockaddr_in
*sinptr
;
298 sinptr
= (struct sockaddr_in
*) &lifr
->lifr_addr
;
299 if (sinptr
->sin_addr
.s_addr
== INADDR_ANY
)
303 if (*best_lifr
!= NULL
) {
305 * Check if we found a better interface by checking
306 * the flags. If flags are identical we prefer
307 * the new found interface.
309 uint64_t diff_flags
= best_lifrflags
^ ifflags
;
311 /* If interface has a different set of flags */
312 if (diff_flags
!= 0) {
313 /* Check flags in increasing order of ones we prefer */
315 /* Address temporary? */
316 if ((diff_flags
& IFF_TEMPORARY
) &&
317 (ifflags
& IFF_TEMPORARY
))
319 /* Deprecated address? */
320 if ((diff_flags
& IFF_DEPRECATED
) &&
321 (ifflags
& IFF_DEPRECATED
))
323 /* Last best-matched interface address has preferred? */
324 if ((diff_flags
& IFF_PREFERRED
) &&
325 ((ifflags
& IFF_PREFERRED
) == 0))
330 /* Set best match interface & flags */
332 best_lifrflags
= ifflags
;
335 if (*best_lifr
== NULL
)
338 /* Found a match: return the interface information */
339 ifi
= calloc(1, sizeof(struct ifi_info
));
343 ifi
->ifi_flags
= best_lifrflags
;
344 ifi
->ifi_index
= if_nametoindex((*best_lifr
)->lifr_name
);
345 if (strlcpy(ifi
->ifi_name
, (*best_lifr
)->lifr_name
, sizeof(ifi
->ifi_name
)) >= sizeof(ifi
->ifi_name
)) {
353 * Returns a list of IP interface information on Solaris. The function
354 * returns all IP interfaces on the system with IPv4 address assigned
355 * when passed AF_INET and returns IP interfaces with IPv6 address assigned
356 * when AF_INET6 is passed.
358 struct ifi_info
*get_ifi_info_solaris(int family
)
360 struct ifi_info
*ifi
, *ifihead
, **ifipnext
;
365 char ifname
[LIFNAMSIZ
], cmpifname
[LIFNAMSIZ
];
366 struct sockaddr_in
*sinptr
;
369 struct lifreq
*lifrp
, *best_lifr
;
370 struct lifreq lifrcopy
;
371 int numifs
, nlifr
, n
;
372 #if defined(AF_INET6) && HAVE_IPV6
373 struct sockaddr_in6
*sinptr6
;
378 sockfd
= socket(family
, SOCK_DGRAM
, 0);
383 lifn
.lifn_family
= family
;
385 if (ioctl(sockfd
, SIOCGLIFNUM
, &lifn
) < 0)
388 * Pad interface count to detect & retrieve any
389 * additional interfaces between IFNUM & IFCONF calls.
391 lifn
.lifn_count
+= 4;
392 numifs
= lifn
.lifn_count
;
393 len
= numifs
* sizeof (struct lifreq
);
396 lifc
.lifc_family
= family
;
401 if (ioctl(sockfd
, SIOCGLIFCONF
, &lifc
) < 0)
404 nlifr
= lifc
.lifc_len
/ sizeof(struct lifreq
);
408 lifrp
= lifc
.lifc_req
;
411 for (n
= nlifr
; n
> 0; n
--, lifrp
++) {
413 if (lifrp
->lifr_addr
.ss_family
!= family
)
417 * See if we have already processed the interface
418 * by checking the interface names.
420 if (strlcpy(ifname
, lifrp
->lifr_name
, sizeof(ifname
)) >= sizeof(ifname
))
422 if ((cptr
= strchr(ifname
, ':')) != NULL
)
426 * If any of the interfaces found so far share the physical
427 * interface name then we have already processed the interface.
429 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifi
->ifi_next
) {
431 /* Retrieve physical interface name */
432 (void) strlcpy(cmpifname
, ifi
->ifi_name
, sizeof(cmpifname
));
434 /* Strip logical interface number before checking ifname */
435 if ((cptr
= strchr(cmpifname
, ':')) != NULL
)
438 if (strcmp(cmpifname
, ifname
) == 0)
442 continue; /* already processed */
445 * New interface, find the one with the preferred source
446 * address for our use in Multicast DNS.
448 if ((ifi
= select_src_ifi_info_solaris(sockfd
, nlifr
,
449 lifc
.lifc_req
, ifname
, &best_lifr
)) == NULL
)
452 assert(best_lifr
!= NULL
);
453 assert((best_lifr
->lifr_addr
.ss_family
== AF_INET6
) ||
454 (best_lifr
->lifr_addr
.ss_family
== AF_INET
));
456 switch (best_lifr
->lifr_addr
.ss_family
) {
458 #if defined(AF_INET6) && HAVE_IPV6
460 sinptr6
= (struct sockaddr_in6
*) &best_lifr
->lifr_addr
;
461 ifi
->ifi_addr
= malloc(sizeof(struct sockaddr_in6
));
462 if (ifi
->ifi_addr
== NULL
)
464 memcpy(ifi
->ifi_addr
, sinptr6
, sizeof(struct sockaddr_in6
));
466 ifi
->ifi_netmask
= calloc(1, sizeof(struct sockaddr_in6
));
467 if (ifi
->ifi_netmask
== NULL
)
469 sinptr6
= (struct sockaddr_in6
*)(ifi
->ifi_netmask
);
470 sinptr6
->sin6_family
= AF_INET6
;
471 plen_to_netmask(best_lifr
->lifr_addrlen
,
472 (unsigned char *) &(sinptr6
->sin6_addr
));
477 sinptr
= (struct sockaddr_in
*) &best_lifr
->lifr_addr
;
478 ifi
->ifi_addr
= malloc(sizeof(struct sockaddr_in
));
479 if (ifi
->ifi_addr
== NULL
)
482 memcpy(ifi
->ifi_addr
, sinptr
, sizeof(struct sockaddr_in
));
484 lifrcopy
= *best_lifr
;
485 if (ioctl(sockfd
, SIOCGLIFNETMASK
, &lifrcopy
) < 0) {
486 /* interface removed */
487 if (errno
== ENXIO
) {
495 ifi
->ifi_netmask
= malloc(sizeof(struct sockaddr_in
));
496 if (ifi
->ifi_netmask
== NULL
)
498 sinptr
= (struct sockaddr_in
*) &lifrcopy
.lifr_addr
;
499 sinptr
->sin_family
= AF_INET
;
500 memcpy(ifi
->ifi_netmask
, sinptr
, sizeof(struct sockaddr_in
));
508 *ifipnext
= ifi
; /* prev points to this new one */
509 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
512 (void) close(sockfd
);
513 return(ifihead
); /* pointer to first structure in linked list */
517 (void) close(sockfd
);
519 free_ifi_info(ifihead
);
523 #endif /* HAVE_SOLARIS */
525 struct ifi_info
*get_ifi_info(int family
, int doaliases
)
528 struct ifi_info
*ifi
, *ifihead
, **ifipnext
, *ifipold
, **ifiptr
;
529 int sockfd
, sockf6
, len
, lastlen
, flags
, myflags
;
530 #ifdef NOT_HAVE_IF_NAMETOINDEX
533 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
535 struct ifreq
*ifr
, ifrcopy
;
536 struct sockaddr_in
*sinptr
;
538 #if defined(AF_INET6) && HAVE_IPV6
539 struct sockaddr_in6
*sinptr6
;
542 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
543 if (family
== AF_INET6
) return get_ifi_info_linuxv6(family
, doaliases
);
545 return get_ifi_info_solaris(family
);
553 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
559 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
561 buf
= (char*)malloc(len
);
567 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
568 if (errno
!= EINVAL
|| lastlen
!= 0) {
572 if (ifc
.ifc_len
== lastlen
)
573 break; /* success, len has not changed */
574 lastlen
= ifc
.ifc_len
;
576 len
+= 10 * sizeof(struct ifreq
); /* increment */
582 /* end get_ifi_info1 */
584 /* include get_ifi_info2 */
585 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
586 ifr
= (struct ifreq
*) ptr
;
588 /* Advance to next one in buffer */
589 if (sizeof(struct ifreq
) > sizeof(ifr
->ifr_name
) + GET_SA_LEN(ifr
->ifr_addr
))
590 ptr
+= sizeof(struct ifreq
);
592 ptr
+= sizeof(ifr
->ifr_name
) + GET_SA_LEN(ifr
->ifr_addr
);
594 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
596 if (ifr
->ifr_addr
.sa_family
!= family
)
597 continue; /* ignore if not desired address family */
600 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
601 *cptr
= 0; /* replace colon will null */
602 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
604 continue; /* already processed this interface */
607 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
610 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
) < 0) {
614 flags
= ifrcopy
.ifr_flags
;
615 if ((flags
& IFF_UP
) == 0)
616 continue; /* ignore if interface not up */
618 ifi
= (struct ifi_info
*)calloc(1, sizeof(struct ifi_info
));
622 ifipold
= *ifipnext
; /* need this later */
624 *ifipnext
= ifi
; /* prev points to this new one */
625 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
627 ifi
->ifi_flags
= flags
; /* IFF_xxx values */
628 ifi
->ifi_myflags
= myflags
; /* IFI_xxx values */
629 #ifndef NOT_HAVE_IF_NAMETOINDEX
630 ifi
->ifi_index
= if_nametoindex(ifr
->ifr_name
);
634 if ( 0 >= ioctl(sockfd
, SIOCGIFINDEX
, &ifrcopy
))
635 ifi
->ifi_index
= ifrcopy
.ifr_index
;
638 ifi
->ifi_index
= index
++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
640 memcpy(ifi
->ifi_name
, ifr
->ifr_name
, IFI_NAME
);
641 ifi
->ifi_name
[IFI_NAME
-1] = '\0';
642 /* end get_ifi_info2 */
643 /* include get_ifi_info3 */
644 switch (ifr
->ifr_addr
.sa_family
) {
646 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
647 if (ifi
->ifi_addr
== NULL
) {
648 ifi
->ifi_addr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
649 if (ifi
->ifi_addr
== NULL
) {
652 memcpy(ifi
->ifi_addr
, sinptr
, sizeof(struct sockaddr_in
));
654 #ifdef SIOCGIFNETMASK
655 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifrcopy
) < 0) {
656 if (errno
== EADDRNOTAVAIL
) {
658 * If the main interface is configured with no IP address but
659 * an alias interface exists with an IP address, you get
660 * EADDRNOTAVAIL for the main interface
672 ifi
->ifi_netmask
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
673 if (ifi
->ifi_netmask
== NULL
) goto gotError
;
674 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_addr
;
675 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
676 #ifndef NOT_HAVE_SA_LEN
677 sinptr
->sin_len
= sizeof(struct sockaddr_in
);
679 sinptr
->sin_family
= AF_INET
;
680 memcpy(ifi
->ifi_netmask
, sinptr
, sizeof(struct sockaddr_in
));
683 #ifdef SIOCGIFBRDADDR
684 if (flags
& IFF_BROADCAST
) {
685 if (ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
) < 0) {
688 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
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
);
693 sinptr
->sin_family
= AF_INET
;
694 ifi
->ifi_brdaddr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
695 if (ifi
->ifi_brdaddr
== NULL
) {
698 memcpy(ifi
->ifi_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
702 #ifdef SIOCGIFDSTADDR
703 if (flags
& IFF_POINTOPOINT
) {
704 if (ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
) < 0) {
707 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
708 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
709 #ifndef NOT_HAVE_SA_LEN
710 sinptr
->sin_len
= sizeof( struct sockaddr_in
);
712 sinptr
->sin_family
= AF_INET
;
713 ifi
->ifi_dstaddr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
714 if (ifi
->ifi_dstaddr
== NULL
) {
717 memcpy(ifi
->ifi_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
723 #if defined(AF_INET6) && HAVE_IPV6
725 sinptr6
= (struct sockaddr_in6
*) &ifr
->ifr_addr
;
726 if (ifi
->ifi_addr
== NULL
) {
727 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in6
));
728 if (ifi
->ifi_addr
== NULL
) {
732 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
733 /* We need to strip that out */
734 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6
->sin6_addr
))
735 sinptr6
->sin6_addr
.s6_addr
[2] = sinptr6
->sin6_addr
.s6_addr
[3] = 0;
736 memcpy(ifi
->ifi_addr
, sinptr6
, sizeof(struct sockaddr_in6
));
738 #ifdef SIOCGIFNETMASK_IN6
740 struct in6_ifreq ifr6
;
742 sockf6
= socket(AF_INET6
, SOCK_DGRAM
, 0);
743 memset(&ifr6
, 0, sizeof(ifr6
));
744 memcpy(&ifr6
.ifr_name
, &ifr
->ifr_name
, sizeof(ifr6
.ifr_name
));
745 memcpy(&ifr6
.ifr_ifru
.ifru_addr
, &ifr
->ifr_addr
, sizeof(ifr6
.ifr_ifru
.ifru_addr
));
746 if (ioctl(sockf6
, SIOCGIFNETMASK_IN6
, &ifr6
) < 0) {
747 if (errno
== EADDRNOTAVAIL
) {
749 * If the main interface is configured with no IP address but
750 * an alias interface exists with an IP address, you get
751 * EADDRNOTAVAIL for the main interface
762 ifi
->ifi_netmask
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in6
));
763 if (ifi
->ifi_netmask
== NULL
) goto gotError
;
764 sinptr6
= (struct sockaddr_in6
*) &ifr6
.ifr_ifru
.ifru_addr
;
765 memcpy(ifi
->ifi_netmask
, sinptr6
, sizeof(struct sockaddr_in6
));
779 if (ifihead
!= NULL
) {
780 free_ifi_info(ifihead
);
789 junk
= close(sockfd
);
793 junk
= close(sockf6
);
796 return(ifihead
); /* pointer to first structure in linked list */
798 /* end get_ifi_info3 */
800 /* include free_ifi_info */
802 free_ifi_info(struct ifi_info
*ifihead
)
804 struct ifi_info
*ifi
, *ifinext
;
806 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
807 if (ifi
->ifi_addr
!= NULL
)
809 if (ifi
->ifi_netmask
!= NULL
)
810 free(ifi
->ifi_netmask
);
811 if (ifi
->ifi_brdaddr
!= NULL
)
812 free(ifi
->ifi_brdaddr
);
813 if (ifi
->ifi_dstaddr
!= NULL
)
814 free(ifi
->ifi_dstaddr
);
815 ifinext
= ifi
->ifi_next
; /* can't fetch ifi_next after free() */
816 free(ifi
); /* the ifi_info{} itself */
819 /* end free_ifi_info */
822 recvfrom_flags(int fd
, void *ptr
, size_t nbytes
, int *flagsp
,
823 struct sockaddr
*sa
, socklen_t
*salenptr
, struct my_in_pktinfo
*pktp
, u_char
*ttl
)
830 struct cmsghdr
*cmptr
;
834 pad64_t align8
; /* ensure structure is 8-byte aligned on sparc */
837 *ttl
= 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
839 msg
.msg_control
= (void *) control_un
.control
;
840 msg
.msg_controllen
= sizeof(control_un
.control
);
843 memset(&msg
, 0, sizeof(msg
)); /* make certain msg_accrightslen = 0 */
844 #endif /* CMSG_FIRSTHDR */
846 msg
.msg_name
= (char *) sa
;
847 msg
.msg_namelen
= *salenptr
;
848 iov
[0].iov_base
= (char *)ptr
;
849 iov
[0].iov_len
= nbytes
;
853 if ( (n
= recvmsg(fd
, &msg
, *flagsp
)) < 0)
856 *salenptr
= msg
.msg_namelen
; /* pass back results */
858 /* 0.0.0.0, i/f = -1 */
859 /* We set the interface to -1 so that the caller can
860 tell whether we returned a meaningful value or
861 just some default. Previously this code just
862 set the value to 0, but I'm concerned that 0
863 might be a valid interface value.
865 memset(pktp
, 0, sizeof(struct my_in_pktinfo
));
866 pktp
->ipi_ifindex
= -1;
868 /* end recvfrom_flags1 */
870 /* include recvfrom_flags2 */
871 #ifndef CMSG_FIRSTHDR
872 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
873 *flagsp
= 0; /* pass back results */
877 *flagsp
= msg
.msg_flags
; /* pass back results */
878 if (msg
.msg_controllen
< (socklen_t
)sizeof(struct cmsghdr
) ||
879 (msg
.msg_flags
& MSG_CTRUNC
) || pktp
== NULL
)
882 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
!= NULL
;
883 cmptr
= CMSG_NXTHDR(&msg
, cmptr
)) {
886 #if in_pktinfo_definition_is_missing
890 struct in_addr ipi_spec_dst
;
891 struct in_addr ipi_addr
;
894 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
895 cmptr
->cmsg_type
== IP_PKTINFO
) {
896 struct in_pktinfo
*tmp
;
897 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
899 tmp
= (struct in_pktinfo
*) CMSG_DATA(cmptr
);
900 sin
->sin_family
= AF_INET
;
901 sin
->sin_addr
= tmp
->ipi_addr
;
903 pktp
->ipi_ifindex
= tmp
->ipi_ifindex
;
908 #ifdef IP_RECVDSTADDR
909 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
910 cmptr
->cmsg_type
== IP_RECVDSTADDR
) {
911 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
913 sin
->sin_family
= AF_INET
;
914 sin
->sin_addr
= *(struct in_addr
*)CMSG_DATA(cmptr
);
921 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
922 cmptr
->cmsg_type
== IP_RECVIF
) {
923 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*) CMSG_DATA(cmptr
);
924 #ifndef HAVE_BROKEN_RECVIF_NAME
925 int nameLen
= (sdl
->sdl_nlen
< IFI_NAME
- 1) ? sdl
->sdl_nlen
: (IFI_NAME
- 1);
926 strncpy(pktp
->ipi_ifname
, sdl
->sdl_data
, nameLen
);
929 * the is memcpy used for sparc? no idea;)
930 * pktp->ipi_ifindex = sdl->sdl_index;
932 (void) memcpy(&pktp
->ipi_ifindex
, CMSG_DATA(cmptr
), sizeof(uint_t
));
933 #ifdef HAVE_BROKEN_RECVIF_NAME
934 if (sdl
->sdl_index
== 0) {
935 pktp
->ipi_ifindex
= *(uint_t
*)sdl
;
938 assert(pktp
->ipi_ifname
[IFI_NAME
- 1] == 0);
939 // null terminated because of memset above
945 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
946 cmptr
->cmsg_type
== IP_RECVTTL
) {
947 *ttl
= *(u_char
*)CMSG_DATA(cmptr
);
950 else if (cmptr
->cmsg_level
== IPPROTO_IP
&&
951 cmptr
->cmsg_type
== IP_TTL
) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
952 *ttl
= *(int*)CMSG_DATA(cmptr
);
957 #if defined(IPV6_PKTINFO) && HAVE_IPV6
958 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
959 cmptr
->cmsg_type
== IPV6_PKTINFO
) {
960 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&pktp
->ipi_addr
;
961 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmptr
);
963 sin6
->sin6_family
= AF_INET6
;
964 #ifndef NOT_HAVE_SA_LEN
965 sin6
->sin6_len
= sizeof(*sin6
);
967 sin6
->sin6_addr
= ip6_info
->ipi6_addr
;
968 sin6
->sin6_flowinfo
= 0;
969 sin6
->sin6_scope_id
= 0;
971 pktp
->ipi_ifindex
= ip6_info
->ipi6_ifindex
;
976 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
977 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
978 cmptr
->cmsg_type
== IPV6_HOPLIMIT
) {
979 *ttl
= *(int*)CMSG_DATA(cmptr
);
983 assert(0); // unknown ancillary data
986 #endif /* CMSG_FIRSTHDR */
989 // **********************************************************************************************
991 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
992 // Returns 0 on success, -1 on failure.
994 #ifdef NOT_HAVE_DAEMON
996 #include <sys/stat.h>
997 #include <sys/signal.h>
999 int daemon(int nochdir
, int noclose
)
1003 case -1: return (-1); // Fork failed
1004 case 0: break; // Child -- continue
1005 default: _exit(0); // Parent -- exit
1008 if (setsid() == -1) return(-1);
1010 signal(SIGHUP
, SIG_IGN
);
1012 switch (fork()) // Fork again, primarily for reasons of Unix trivia
1014 case -1: return (-1); // Fork failed
1015 case 0: break; // Child -- continue
1016 default: _exit(0); // Parent -- exit
1019 if (!nochdir
) (void)chdir("/");
1024 int fd
= open("/dev/null", O_RDWR
, 0);
1027 // Avoid unnecessarily duplicating a file descriptor to itself
1028 if (fd
!= STDIN_FILENO
) (void)dup2(fd
, STDIN_FILENO
);
1029 if (fd
!= STDOUT_FILENO
) (void)dup2(fd
, STDOUT_FILENO
);
1030 if (fd
!= STDERR_FILENO
) (void)dup2(fd
, STDERR_FILENO
);
1031 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
)
1037 #endif /* NOT_HAVE_DAEMON */