]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSUNP.c
mDNSResponder-58.8.1.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / mDNSUNP.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: mDNSUNP.c,v $
26 Revision 1.12 2003/09/02 20:47:13 cheshire
27 Fix signed/unsigned warning
28
29 Revision 1.11 2003/08/12 19:56:26 cheshire
30 Update to APSL 2.0
31
32 Revision 1.10 2003/08/06 18:20:51 cheshire
33 Makefile cleanup
34
35 Revision 1.9 2003/07/14 18:11:54 cheshire
36 Fix stricter compiler warnings
37
38 Revision 1.8 2003/07/02 21:19:59 cheshire
39 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
40
41 Revision 1.7 2003/03/20 21:10:31 cheshire
42 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
43
44 Revision 1.6 2003/03/13 03:46:21 cheshire
45 Fixes to make the code build on Linux
46
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();
51
52 Revision 1.4 2002/12/23 22:13:31 jgraessl
53
54 Reviewed by: Stuart Cheshire
55 Initial IPv6 support for mDNSResponder.
56
57 Revision 1.3 2002/09/21 20:44:53 zarzycki
58 Added APSL info
59
60 Revision 1.2 2002/09/19 04:20:44 cheshire
61 Remove high-ascii characters that confuse some systems
62
63 Revision 1.1 2002/09/17 06:24:34 cheshire
64 First checkin
65
66 */
67
68 #include "mDNSUNP.h"
69
70 #include <errno.h>
71 #include <assert.h>
72 #include <string.h>
73 #include <stdlib.h>
74 #include <sys/uio.h>
75 #include <sys/ioctl.h>
76 #include <unistd.h>
77 #include <stdio.h>
78
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
82 <sys/sockio.h>.
83 */
84
85 #ifndef SIOCGIFCONF
86 #include <sys/sockio.h>
87 #endif
88
89 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
90 so only include the header in that case.
91 */
92
93 #ifdef IP_RECVIF
94 #include <net/if_dl.h>
95 #endif
96
97
98 struct ifi_info *get_ifi_info(int family, int doaliases)
99 {
100 int junk;
101 struct ifi_info *ifi, *ifihead, **ifipnext;
102 int sockfd, len, lastlen, flags, myflags;
103 char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
104 struct ifconf ifc;
105 struct ifreq *ifr, ifrcopy;
106 struct sockaddr_in *sinptr;
107
108 #if defined(AF_INET6) && defined(HAVE_IPV6)
109 struct sockaddr_in6 *sinptr6;
110 #endif
111
112 sockfd = -1;
113 buf = NULL;
114 ifihead = NULL;
115
116 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
117 if (sockfd < 0) {
118 goto gotError;
119 }
120
121 lastlen = 0;
122 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
123 for ( ; ; ) {
124 buf = malloc(len);
125 if (buf == NULL) {
126 goto gotError;
127 }
128 ifc.ifc_len = len;
129 ifc.ifc_buf = buf;
130 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
131 if (errno != EINVAL || lastlen != 0) {
132 goto gotError;
133 }
134 } else {
135 if (ifc.ifc_len == lastlen)
136 break; /* success, len has not changed */
137 lastlen = ifc.ifc_len;
138 }
139 len += 10 * sizeof(struct ifreq); /* increment */
140 free(buf);
141 }
142 ifihead = NULL;
143 ifipnext = &ifihead;
144 lastname[0] = 0;
145 /* end get_ifi_info1 */
146
147 /* include get_ifi_info2 */
148 for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
149 ifr = (struct ifreq *) ptr;
150
151 len = GET_SA_LEN(ifr->ifr_addr);
152 ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
153
154 // fprintf(stderr, "intf %d name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
155
156 if (ifr->ifr_addr.sa_family != family)
157 continue; /* ignore if not desired address family */
158
159 myflags = 0;
160 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
161 *cptr = 0; /* replace colon will null */
162 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
163 if (doaliases == 0)
164 continue; /* already processed this interface */
165 myflags = IFI_ALIAS;
166 }
167 memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
168
169 ifrcopy = *ifr;
170 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
171 goto gotError;
172 }
173
174 flags = ifrcopy.ifr_flags;
175 if ((flags & IFF_UP) == 0)
176 continue; /* ignore if interface not up */
177
178 ifi = calloc(1, sizeof(struct ifi_info));
179 if (ifi == NULL) {
180 goto gotError;
181 }
182 *ifipnext = ifi; /* prev points to this new one */
183 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
184
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) {
193 case AF_INET:
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) {
198 goto gotError;
199 }
200 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
201
202 #ifdef SIOCGIFBRDADDR
203 if (flags & IFF_BROADCAST) {
204 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
205 goto gotError;
206 }
207 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
208 ifi->ifi_brdaddr = calloc(1, sizeof(struct sockaddr_in));
209 if (ifi->ifi_brdaddr == NULL) {
210 goto gotError;
211 }
212 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
213 }
214 #endif
215
216 #ifdef SIOCGIFDSTADDR
217 if (flags & IFF_POINTOPOINT) {
218 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
219 goto gotError;
220 }
221 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
222 ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in));
223 if (ifi->ifi_dstaddr == NULL) {
224 goto gotError;
225 }
226 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
227 }
228 #endif
229 }
230 break;
231
232 #if defined(AF_INET6) && defined(HAVE_IPV6)
233 case AF_INET6:
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) {
238 goto gotError;
239 }
240
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));
246 }
247 break;
248 #endif
249
250 default:
251 break;
252 }
253 }
254 goto done;
255
256 gotError:
257 if (ifihead != NULL) {
258 free_ifi_info(ifihead);
259 ifihead = NULL;
260 }
261
262 done:
263 if (buf != NULL) {
264 free(buf);
265 }
266 if (sockfd != -1) {
267 junk = close(sockfd);
268 assert(junk == 0);
269 }
270 return(ifihead); /* pointer to first structure in linked list */
271 }
272 /* end get_ifi_info3 */
273
274 /* include free_ifi_info */
275 void
276 free_ifi_info(struct ifi_info *ifihead)
277 {
278 struct ifi_info *ifi, *ifinext;
279
280 for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
281 if (ifi->ifi_addr != NULL)
282 free(ifi->ifi_addr);
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 */
289 }
290 }
291 /* end free_ifi_info */
292
293 ssize_t
294 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
295 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp)
296 {
297 struct msghdr msg;
298 struct iovec iov[1];
299 ssize_t n;
300
301 #ifdef CMSG_FIRSTHDR
302 struct cmsghdr *cmptr;
303 union {
304 struct cmsghdr cm;
305 char control[1024];
306 } control_un;
307
308 msg.msg_control = control_un.control;
309 msg.msg_controllen = sizeof(control_un.control);
310 msg.msg_flags = 0;
311 #else
312 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
313 #endif /* CMSG_FIRSTHDR */
314
315 msg.msg_name = (void *) sa;
316 msg.msg_namelen = *salenptr;
317 iov[0].iov_base = ptr;
318 iov[0].iov_len = nbytes;
319 msg.msg_iov = iov;
320 msg.msg_iovlen = 1;
321
322 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
323 return(n);
324
325 *salenptr = msg.msg_namelen; /* pass back results */
326 if (pktp) {
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.
333 */
334 memset(pktp, 0, sizeof(struct my_in_pktinfo));
335 pktp->ipi_ifindex = -1;
336 }
337 /* end recvfrom_flags1 */
338
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 */
343 return(n);
344 #else
345
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)
349 return(n);
350
351 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
352 cmptr = CMSG_NXTHDR(&msg, cmptr)) {
353
354 #ifdef IP_PKTINFO
355 #if in_pktinfo_definition_is_missing
356 struct in_pktinfo
357 {
358 int ipi_ifindex;
359 struct in_addr ipi_spec_dst;
360 struct in_addr ipi_addr;
361 };
362 #endif
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;
367
368 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
369 sin->sin_family = AF_INET;
370 sin->sin_addr = tmp->ipi_addr;
371 sin->sin_port = 0;
372 pktp->ipi_ifindex = tmp->ipi_ifindex;
373 continue;
374 }
375 #endif
376
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;
381
382 sin->sin_family = AF_INET;
383 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
384 sin->sin_port = 0;
385 continue;
386 }
387 #endif
388
389 #ifdef IP_RECVIF
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);
397 #endif
398 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
399 // null terminated because of memset above
400 continue;
401 }
402 #endif
403
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);
409
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;
415 sin6->sin6_port = 0;
416 pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
417 continue;
418 }
419 #endif
420 assert(0); // unknown ancillary data
421 }
422 return(n);
423 #endif /* CMSG_FIRSTHDR */
424 }