]>
git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSUNP.c
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.12 2003/09/02 20:47:13 cheshire
27 Fix signed/unsigned warning
29 Revision 1.11 2003/08/12 19:56:26 cheshire
32 Revision 1.10 2003/08/06 18:20:51 cheshire
35 Revision 1.9 2003/07/14 18:11:54 cheshire
36 Fix stricter compiler warnings
38 Revision 1.8 2003/07/02 21:19:59 cheshire
39 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
41 Revision 1.7 2003/03/20 21:10:31 cheshire
42 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
44 Revision 1.6 2003/03/13 03:46:21 cheshire
45 Fixes to make the code build on Linux
47 Revision 1.5 2003/02/07 03:02:02 cheshire
48 Submitted by: Mitsutaka Watanabe
49 The code saying "index += 1;" was effectively making up random interface index values.
50 The right way to find the correct interface index is if_nametoindex();
52 Revision 1.4 2002/12/23 22:13:31 jgraessl
54 Reviewed by: Stuart Cheshire
55 Initial IPv6 support for mDNSResponder.
57 Revision 1.3 2002/09/21 20:44:53 zarzycki
60 Revision 1.2 2002/09/19 04:20:44 cheshire
61 Remove high-ascii characters that confuse some systems
63 Revision 1.1 2002/09/17 06:24:34 cheshire
75 #include <sys/ioctl.h>
79 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
80 other platforms don't even have that include file. So,
81 if we haven't yet got a definition, let's try to find
86 #include <sys/sockio.h>
89 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
90 so only include the header in that case.
94 #include <net/if_dl.h>
98 struct ifi_info
*get_ifi_info(int family
, int doaliases
)
101 struct ifi_info
*ifi
, *ifihead
, **ifipnext
;
102 int sockfd
, len
, lastlen
, flags
, myflags
;
103 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
105 struct ifreq
*ifr
, ifrcopy
;
106 struct sockaddr_in
*sinptr
;
108 #if defined(AF_INET6) && defined(HAVE_IPV6)
109 struct sockaddr_in6
*sinptr6
;
116 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
122 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
130 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
131 if (errno
!= EINVAL
|| lastlen
!= 0) {
135 if (ifc
.ifc_len
== lastlen
)
136 break; /* success, len has not changed */
137 lastlen
= ifc
.ifc_len
;
139 len
+= 10 * sizeof(struct ifreq
); /* increment */
145 /* end get_ifi_info1 */
147 /* include get_ifi_info2 */
148 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
149 ifr
= (struct ifreq
*) ptr
;
151 len
= GET_SA_LEN(ifr
->ifr_addr
);
152 ptr
+= sizeof(ifr
->ifr_name
) + len
; /* for next one in buffer */
154 // fprintf(stderr, "intf %d name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
156 if (ifr
->ifr_addr
.sa_family
!= family
)
157 continue; /* ignore if not desired address family */
160 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
161 *cptr
= 0; /* replace colon will null */
162 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
164 continue; /* already processed this interface */
167 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
170 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
) < 0) {
174 flags
= ifrcopy
.ifr_flags
;
175 if ((flags
& IFF_UP
) == 0)
176 continue; /* ignore if interface not up */
178 ifi
= calloc(1, sizeof(struct ifi_info
));
182 *ifipnext
= ifi
; /* prev points to this new one */
183 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
185 ifi
->ifi_flags
= flags
; /* IFF_xxx values */
186 ifi
->ifi_myflags
= myflags
; /* IFI_xxx values */
187 ifi
->ifi_index
= if_nametoindex(ifr
->ifr_name
);
188 memcpy(ifi
->ifi_name
, ifr
->ifr_name
, IFI_NAME
);
189 ifi
->ifi_name
[IFI_NAME
-1] = '\0';
190 /* end get_ifi_info2 */
191 /* include get_ifi_info3 */
192 switch (ifr
->ifr_addr
.sa_family
) {
194 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
195 if (ifi
->ifi_addr
== NULL
) {
196 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in
));
197 if (ifi
->ifi_addr
== NULL
) {
200 memcpy(ifi
->ifi_addr
, sinptr
, sizeof(struct sockaddr_in
));
202 #ifdef SIOCGIFBRDADDR
203 if (flags
& IFF_BROADCAST
) {
204 if (ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
) < 0) {
207 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
208 ifi
->ifi_brdaddr
= calloc(1, sizeof(struct sockaddr_in
));
209 if (ifi
->ifi_brdaddr
== NULL
) {
212 memcpy(ifi
->ifi_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
216 #ifdef SIOCGIFDSTADDR
217 if (flags
& IFF_POINTOPOINT
) {
218 if (ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
) < 0) {
221 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
222 ifi
->ifi_dstaddr
= calloc(1, sizeof(struct sockaddr_in
));
223 if (ifi
->ifi_dstaddr
== NULL
) {
226 memcpy(ifi
->ifi_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
232 #if defined(AF_INET6) && defined(HAVE_IPV6)
234 sinptr6
= (struct sockaddr_in6
*) &ifr
->ifr_addr
;
235 if (ifi
->ifi_addr
== NULL
) {
236 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in6
));
237 if (ifi
->ifi_addr
== NULL
) {
241 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
242 /* We need to strip that out */
243 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6
->sin6_addr
))
244 sinptr6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
245 memcpy(ifi
->ifi_addr
, sinptr6
, sizeof(struct sockaddr_in6
));
257 if (ifihead
!= NULL
) {
258 free_ifi_info(ifihead
);
267 junk
= close(sockfd
);
270 return(ifihead
); /* pointer to first structure in linked list */
272 /* end get_ifi_info3 */
274 /* include free_ifi_info */
276 free_ifi_info(struct ifi_info
*ifihead
)
278 struct ifi_info
*ifi
, *ifinext
;
280 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
281 if (ifi
->ifi_addr
!= NULL
)
283 if (ifi
->ifi_brdaddr
!= NULL
)
284 free(ifi
->ifi_brdaddr
);
285 if (ifi
->ifi_dstaddr
!= NULL
)
286 free(ifi
->ifi_dstaddr
);
287 ifinext
= ifi
->ifi_next
; /* can't fetch ifi_next after free() */
288 free(ifi
); /* the ifi_info{} itself */
291 /* end free_ifi_info */
294 recvfrom_flags(int fd
, void *ptr
, size_t nbytes
, int *flagsp
,
295 struct sockaddr
*sa
, socklen_t
*salenptr
, struct my_in_pktinfo
*pktp
)
302 struct cmsghdr
*cmptr
;
308 msg
.msg_control
= control_un
.control
;
309 msg
.msg_controllen
= sizeof(control_un
.control
);
312 memset(&msg
, 0, sizeof(msg
)); /* make certain msg_accrightslen = 0 */
313 #endif /* CMSG_FIRSTHDR */
315 msg
.msg_name
= (void *) sa
;
316 msg
.msg_namelen
= *salenptr
;
317 iov
[0].iov_base
= ptr
;
318 iov
[0].iov_len
= nbytes
;
322 if ( (n
= recvmsg(fd
, &msg
, *flagsp
)) < 0)
325 *salenptr
= msg
.msg_namelen
; /* pass back results */
327 /* 0.0.0.0, i/f = -1 */
328 /* We set the interface to -1 so that the caller can
329 tell whether we returned a meaningful value or
330 just some default. Previously this code just
331 set the value to 0, but I'm concerned that 0
332 might be a valid interface value.
334 memset(pktp
, 0, sizeof(struct my_in_pktinfo
));
335 pktp
->ipi_ifindex
= -1;
337 /* end recvfrom_flags1 */
339 /* include recvfrom_flags2 */
340 #ifndef CMSG_FIRSTHDR
341 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
342 *flagsp
= 0; /* pass back results */
346 *flagsp
= msg
.msg_flags
; /* pass back results */
347 if (msg
.msg_controllen
< (socklen_t
)sizeof(struct cmsghdr
) ||
348 (msg
.msg_flags
& MSG_CTRUNC
) || pktp
== NULL
)
351 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
!= NULL
;
352 cmptr
= CMSG_NXTHDR(&msg
, cmptr
)) {
355 #if in_pktinfo_definition_is_missing
359 struct in_addr ipi_spec_dst
;
360 struct in_addr ipi_addr
;
363 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
364 cmptr
->cmsg_type
== IP_PKTINFO
) {
365 struct in_pktinfo
*tmp
;
366 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
368 tmp
= (struct in_pktinfo
*) CMSG_DATA(cmptr
);
369 sin
->sin_family
= AF_INET
;
370 sin
->sin_addr
= tmp
->ipi_addr
;
372 pktp
->ipi_ifindex
= tmp
->ipi_ifindex
;
377 #ifdef IP_RECVDSTADDR
378 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
379 cmptr
->cmsg_type
== IP_RECVDSTADDR
) {
380 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
382 sin
->sin_family
= AF_INET
;
383 sin
->sin_addr
= *(struct in_addr
*)CMSG_DATA(cmptr
);
390 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
391 cmptr
->cmsg_type
== IP_RECVIF
) {
392 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*) CMSG_DATA(cmptr
);
393 int nameLen
= (sdl
->sdl_nlen
< IFI_NAME
- 1) ? sdl
->sdl_nlen
: (IFI_NAME
- 1);
394 pktp
->ipi_ifindex
= sdl
->sdl_index
;
395 #ifndef HAVE_BROKEN_RECVIF_NAME
396 strncpy(pktp
->ipi_ifname
, sdl
->sdl_data
, nameLen
);
398 assert(pktp
->ipi_ifname
[IFI_NAME
- 1] == 0);
399 // null terminated because of memset above
404 #if defined(IPV6_PKTINFO) && defined(HAVE_IPV6)
405 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
406 cmptr
->cmsg_type
== IPV6_PKTINFO
) {
407 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&pktp
->ipi_addr
;
408 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmptr
);
410 sin6
->sin6_family
= AF_INET6
;
411 sin6
->sin6_len
= sizeof(*sin6
);
412 sin6
->sin6_addr
= ip6_info
->ipi6_addr
;
413 sin6
->sin6_flowinfo
= 0;
414 sin6
->sin6_scope_id
= 0;
416 pktp
->ipi_ifindex
= ip6_info
->ipi6_ifindex
;
420 assert(0); // unknown ancillary data
423 #endif /* CMSG_FIRSTHDR */