]>
git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSUNP.c
1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
27 Revision 1.23 2004/12/01 04:25:05 cheshire
28 <rdar://problem/3872803> Darwin patches for Solaris and Suse
29 Provide daemon() for platforms that don't have it
31 Revision 1.22 2004/11/30 22:37:01 cheshire
32 Update copyright dates and add "Mode: C; tab-width: 4" headers
34 Revision 1.21 2004/11/08 22:13:59 rpantos
35 Create sockf6 lazily when v6 interface found.
37 Revision 1.20 2004/10/16 00:17:01 cheshire
38 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
40 Revision 1.19 2004/07/20 01:47:36 rpantos
41 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
43 Revision 1.18 2004/07/08 21:30:21 rpantos
45 Revision 1.17 2004/06/25 00:26:27 rpantos
46 Changes to fix the Posix build on Solaris.
48 Revision 1.16 2004/03/20 05:37:09 cheshire
49 Fix contributed by Terry Lambert & Alfred Perlstein:
50 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
52 Revision 1.15 2004/02/14 01:09:45 rpantos
53 Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
55 Revision 1.14 2003/12/11 18:53:40 cheshire
56 Fix compiler warning reported by Paul Guyot
58 Revision 1.13 2003/12/08 20:47:02 rpantos
59 Add support for mDNSResponder on Linux.
61 Revision 1.12 2003/09/02 20:47:13 cheshire
62 Fix signed/unsigned warning
64 Revision 1.11 2003/08/12 19:56:26 cheshire
67 Revision 1.10 2003/08/06 18:20:51 cheshire
70 Revision 1.9 2003/07/14 18:11:54 cheshire
71 Fix stricter compiler warnings
73 Revision 1.8 2003/07/02 21:19:59 cheshire
74 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
76 Revision 1.7 2003/03/20 21:10:31 cheshire
77 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
79 Revision 1.6 2003/03/13 03:46:21 cheshire
80 Fixes to make the code build on Linux
82 Revision 1.5 2003/02/07 03:02:02 cheshire
83 Submitted by: Mitsutaka Watanabe
84 The code saying "index += 1;" was effectively making up random interface index values.
85 The right way to find the correct interface index is if_nametoindex();
87 Revision 1.4 2002/12/23 22:13:31 jgraessl
89 Reviewed by: Stuart Cheshire
90 Initial IPv6 support for mDNSResponder.
92 Revision 1.3 2002/09/21 20:44:53 zarzycki
95 Revision 1.2 2002/09/19 04:20:44 cheshire
96 Remove high-ascii characters that confuse some systems
98 Revision 1.1 2002/09/17 06:24:34 cheshire
110 #include <sys/ioctl.h>
114 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
115 other platforms don't even have that include file. So,
116 if we haven't yet got a definition, let's try to find
121 #include <sys/sockio.h>
124 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
125 so only include the header in that case.
129 #include <net/if_dl.h>
132 #if defined(AF_INET6) && HAVE_IPV6
133 #include <netinet6/in6_var.h>
136 struct ifi_info
*get_ifi_info(int family
, int doaliases
)
139 struct ifi_info
*ifi
, *ifihead
, **ifipnext
;
140 int sockfd
, sockf6
, len
, lastlen
, flags
, myflags
;
141 #ifdef NOT_HAVE_IF_NAMETOINDEX
144 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
146 struct ifreq
*ifr
, ifrcopy
;
147 struct sockaddr_in
*sinptr
;
149 #if defined(AF_INET6) && HAVE_IPV6
150 struct sockaddr_in6
*sinptr6
;
158 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
164 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
166 buf
= (char*)malloc(len
);
172 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
173 if (errno
!= EINVAL
|| lastlen
!= 0) {
177 if (ifc
.ifc_len
== lastlen
)
178 break; /* success, len has not changed */
179 lastlen
= ifc
.ifc_len
;
181 len
+= 10 * sizeof(struct ifreq
); /* increment */
187 /* end get_ifi_info1 */
189 /* include get_ifi_info2 */
190 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
191 ifr
= (struct ifreq
*) ptr
;
193 len
= GET_SA_LEN(ifr
->ifr_addr
);
194 ptr
+= sizeof(ifr
->ifr_name
) + len
; /* for next one in buffer */
196 // fprintf(stderr, "intf %d name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
198 if (ifr
->ifr_addr
.sa_family
!= family
)
199 continue; /* ignore if not desired address family */
202 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
203 *cptr
= 0; /* replace colon will null */
204 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
206 continue; /* already processed this interface */
209 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
212 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
) < 0) {
216 flags
= ifrcopy
.ifr_flags
;
217 if ((flags
& IFF_UP
) == 0)
218 continue; /* ignore if interface not up */
220 ifi
= (struct ifi_info
*)calloc(1, sizeof(struct ifi_info
));
224 *ifipnext
= ifi
; /* prev points to this new one */
225 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
227 ifi
->ifi_flags
= flags
; /* IFF_xxx values */
228 ifi
->ifi_myflags
= myflags
; /* IFI_xxx values */
229 #ifndef NOT_HAVE_IF_NAMETOINDEX
230 ifi
->ifi_index
= if_nametoindex(ifr
->ifr_name
);
233 if ( 0 >= ioctl(sockfd
, SIOCGIFINDEX
, &ifrcopy
))
234 ifi
->ifi_index
= ifrcopy
.ifr_index
;
236 ifi
->ifi_index
= index
++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
238 memcpy(ifi
->ifi_name
, ifr
->ifr_name
, IFI_NAME
);
239 ifi
->ifi_name
[IFI_NAME
-1] = '\0';
240 /* end get_ifi_info2 */
241 /* include get_ifi_info3 */
242 switch (ifr
->ifr_addr
.sa_family
) {
244 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
245 if (ifi
->ifi_addr
== NULL
) {
246 ifi
->ifi_addr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
247 if (ifi
->ifi_addr
== NULL
) {
250 memcpy(ifi
->ifi_addr
, sinptr
, sizeof(struct sockaddr_in
));
252 #ifdef SIOCGIFNETMASK
253 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifrcopy
) < 0) goto gotError
;
254 ifi
->ifi_netmask
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
255 if (ifi
->ifi_netmask
== NULL
) goto gotError
;
256 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_addr
;
257 memcpy(ifi
->ifi_netmask
, sinptr
, sizeof(struct sockaddr_in
));
260 #ifdef SIOCGIFBRDADDR
261 if (flags
& IFF_BROADCAST
) {
262 if (ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
) < 0) {
265 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
266 ifi
->ifi_brdaddr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
267 if (ifi
->ifi_brdaddr
== NULL
) {
270 memcpy(ifi
->ifi_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
274 #ifdef SIOCGIFDSTADDR
275 if (flags
& IFF_POINTOPOINT
) {
276 if (ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
) < 0) {
279 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
280 ifi
->ifi_dstaddr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
281 if (ifi
->ifi_dstaddr
== NULL
) {
284 memcpy(ifi
->ifi_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
290 #if defined(AF_INET6) && HAVE_IPV6
292 sinptr6
= (struct sockaddr_in6
*) &ifr
->ifr_addr
;
293 if (ifi
->ifi_addr
== NULL
) {
294 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in6
));
295 if (ifi
->ifi_addr
== NULL
) {
299 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
300 /* We need to strip that out */
301 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6
->sin6_addr
))
302 sinptr6
->sin6_addr
.s6_addr
[2] = sinptr6
->sin6_addr
.s6_addr
[3] = 0;
303 memcpy(ifi
->ifi_addr
, sinptr6
, sizeof(struct sockaddr_in6
));
305 #ifdef SIOCGIFNETMASK_IN6
307 struct in6_ifreq ifr6
;
309 sockf6
= socket(AF_INET6
, SOCK_DGRAM
, 0);
310 bzero(&ifr6
, sizeof(ifr6
));
311 memcpy(&ifr6
.ifr_name
, &ifr
->ifr_name
, sizeof(ifr6
.ifr_name
));
312 memcpy(&ifr6
.ifr_ifru
.ifru_addr
, &ifr
->ifr_addr
, sizeof(ifr6
.ifr_ifru
.ifru_addr
));
313 if (ioctl(sockf6
, SIOCGIFNETMASK_IN6
, &ifr6
) < 0) goto gotError
;
314 ifi
->ifi_netmask
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in6
));
315 if (ifi
->ifi_netmask
== NULL
) goto gotError
;
316 sinptr6
= (struct sockaddr_in6
*) &ifr6
.ifr_ifru
.ifru_addr
;
317 memcpy(ifi
->ifi_netmask
, sinptr6
, sizeof(struct sockaddr_in6
));
331 if (ifihead
!= NULL
) {
332 free_ifi_info(ifihead
);
341 junk
= close(sockfd
);
345 junk
= close(sockf6
);
348 return(ifihead
); /* pointer to first structure in linked list */
350 /* end get_ifi_info3 */
352 /* include free_ifi_info */
354 free_ifi_info(struct ifi_info
*ifihead
)
356 struct ifi_info
*ifi
, *ifinext
;
358 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
359 if (ifi
->ifi_addr
!= NULL
)
361 if (ifi
->ifi_brdaddr
!= NULL
)
362 free(ifi
->ifi_brdaddr
);
363 if (ifi
->ifi_dstaddr
!= NULL
)
364 free(ifi
->ifi_dstaddr
);
365 ifinext
= ifi
->ifi_next
; /* can't fetch ifi_next after free() */
366 free(ifi
); /* the ifi_info{} itself */
369 /* end free_ifi_info */
372 recvfrom_flags(int fd
, void *ptr
, size_t nbytes
, int *flagsp
,
373 struct sockaddr
*sa
, socklen_t
*salenptr
, struct my_in_pktinfo
*pktp
, u_char
*ttl
)
380 struct cmsghdr
*cmptr
;
386 *ttl
= 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
388 msg
.msg_control
= control_un
.control
;
389 msg
.msg_controllen
= sizeof(control_un
.control
);
392 memset(&msg
, 0, sizeof(msg
)); /* make certain msg_accrightslen = 0 */
393 #endif /* CMSG_FIRSTHDR */
395 msg
.msg_name
= (char *) sa
;
396 msg
.msg_namelen
= *salenptr
;
397 iov
[0].iov_base
= (char *)ptr
;
398 iov
[0].iov_len
= nbytes
;
402 if ( (n
= recvmsg(fd
, &msg
, *flagsp
)) < 0)
405 *salenptr
= msg
.msg_namelen
; /* pass back results */
407 /* 0.0.0.0, i/f = -1 */
408 /* We set the interface to -1 so that the caller can
409 tell whether we returned a meaningful value or
410 just some default. Previously this code just
411 set the value to 0, but I'm concerned that 0
412 might be a valid interface value.
414 memset(pktp
, 0, sizeof(struct my_in_pktinfo
));
415 pktp
->ipi_ifindex
= -1;
417 /* end recvfrom_flags1 */
419 /* include recvfrom_flags2 */
420 #ifndef CMSG_FIRSTHDR
421 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
422 *flagsp
= 0; /* pass back results */
426 *flagsp
= msg
.msg_flags
; /* pass back results */
427 if (msg
.msg_controllen
< (socklen_t
)sizeof(struct cmsghdr
) ||
428 (msg
.msg_flags
& MSG_CTRUNC
) || pktp
== NULL
)
431 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
!= NULL
;
432 cmptr
= CMSG_NXTHDR(&msg
, cmptr
)) {
435 #if in_pktinfo_definition_is_missing
439 struct in_addr ipi_spec_dst
;
440 struct in_addr ipi_addr
;
443 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
444 cmptr
->cmsg_type
== IP_PKTINFO
) {
445 struct in_pktinfo
*tmp
;
446 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
448 tmp
= (struct in_pktinfo
*) CMSG_DATA(cmptr
);
449 sin
->sin_family
= AF_INET
;
450 sin
->sin_addr
= tmp
->ipi_addr
;
452 pktp
->ipi_ifindex
= tmp
->ipi_ifindex
;
457 #ifdef IP_RECVDSTADDR
458 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
459 cmptr
->cmsg_type
== IP_RECVDSTADDR
) {
460 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
462 sin
->sin_family
= AF_INET
;
463 sin
->sin_addr
= *(struct in_addr
*)CMSG_DATA(cmptr
);
470 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
471 cmptr
->cmsg_type
== IP_RECVIF
) {
472 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*) CMSG_DATA(cmptr
);
473 #ifndef HAVE_BROKEN_RECVIF_NAME
474 int nameLen
= (sdl
->sdl_nlen
< IFI_NAME
- 1) ? sdl
->sdl_nlen
: (IFI_NAME
- 1);
475 strncpy(pktp
->ipi_ifname
, sdl
->sdl_data
, nameLen
);
477 pktp
->ipi_ifindex
= sdl
->sdl_index
;
478 assert(pktp
->ipi_ifname
[IFI_NAME
- 1] == 0);
479 // null terminated because of memset above
485 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
486 cmptr
->cmsg_type
== IP_RECVTTL
) {
487 *ttl
= *(u_char
*)CMSG_DATA(cmptr
);
490 else if (cmptr
->cmsg_level
== IPPROTO_IP
&&
491 cmptr
->cmsg_type
== IP_TTL
) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
492 *ttl
= *(int*)CMSG_DATA(cmptr
);
497 #if defined(IPV6_PKTINFO) && HAVE_IPV6
498 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
499 cmptr
->cmsg_type
== IPV6_PKTINFO
) {
500 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&pktp
->ipi_addr
;
501 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmptr
);
503 sin6
->sin6_family
= AF_INET6
;
504 #ifndef NOT_HAVE_SA_LEN
505 sin6
->sin6_len
= sizeof(*sin6
);
507 sin6
->sin6_addr
= ip6_info
->ipi6_addr
;
508 sin6
->sin6_flowinfo
= 0;
509 sin6
->sin6_scope_id
= 0;
511 pktp
->ipi_ifindex
= ip6_info
->ipi6_ifindex
;
516 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
517 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
518 cmptr
->cmsg_type
== IPV6_HOPLIMIT
) {
519 *ttl
= *(int*)CMSG_DATA(cmptr
);
523 assert(0); // unknown ancillary data
526 #endif /* CMSG_FIRSTHDR */
529 // **********************************************************************************************
531 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
532 // Returns 0 on success, -1 on failure.
534 #ifdef NOT_HAVE_DAEMON
536 #include <sys/stat.h>
537 int daemon(int nochdir
, int noclose
)
541 case -1: return (-1); // Fork failed
542 case 0: break; // Child -- continue
543 default: _exit(0); // Parent -- exit
546 if (setsid() == -1) return(-1);
548 signal(SIGHUP
, SIG_IGN
);
550 switch (fork()) // Fork again, primarily for reasons of Unix trivia
552 case -1: return (-1); // Fork failed
553 case 0: break; // Child -- continue
554 default: _exit(0); // Parent -- exit
557 if (!nochdir
) (void)chdir("/");
562 int fd
= open("/dev/null", O_RDWR
, 0);
565 // Avoid unnecessarily duplicating a file descriptor to itself
566 if (fd
!= STDIN_FILENO
) (void)dup2(fd
, STDIN_FILENO
);
567 if (fd
!= STDOUT_FILENO
) (void)dup2(fd
, STDOUT_FILENO
);
568 if (fd
!= STDERR_FILENO
) (void)dup2(fd
, STDERR_FILENO
);
569 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
)
575 #endif /* NOT_HAVE_DAEMON */