]> git.saurik.com Git - apple/mdnsresponder.git/blob - CFSocket.c
12b463a42d687bbe1aff28c008c5eac45ca0c980
[apple/mdnsresponder.git] / CFSocket.c
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in
7 * and are subject to the Apple Public Source License Version 1.1
8 * (the "License"). You may not use this file except in compliance
9 * with the License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 // ***************************************************************************
24 // mDNS-CFSocket.c:
25 // Supporting routines to run mDNS on a CFRunLoop platform
26 // ***************************************************************************
27
28 // Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
29 // before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
30 // in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
31 // it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
32 // the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
33 // queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
34 #define mDNS_AllowPort53 1
35
36 // Normally mDNSResponder is advertising local services on all active interfaces.
37 // However, should you wish to build a query-only mDNS client, setting mDNS_AdvertiseLocalAddresses
38 // to zero will cause CFSocket.c to not set the Advertise flag in its mDNS_RegisterInterface calls.
39 int mDNS_AdvertiseLocalAddresses = 1;
40
41 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
42 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
43 #include "mDNSPlatformEnvironment.h" // Defines the specific types needed to run mDNS on this platform
44 #include "mDNSvsprintf.h" // Used to implement debugf_();
45
46 #include <stdio.h>
47 #include <stdarg.h> // For va_list support
48 #include <net/if.h>
49 #include <net/if_dl.h>
50 #include <sys/uio.h>
51 #include <sys/param.h>
52 #include <sys/socket.h>
53
54 // Code contributed by Dave Heller:
55 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
56 // work on Mac OS X 10.1, which does not have the getifaddrs call.
57 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
58
59 #if RUN_ON_PUMA_WITHOUT_IFADDRS
60
61 #include <sys/ioctl.h>
62 #include <sys/sockio.h>
63 #define ifaddrs ifa_info
64 #ifndef ifa_broadaddr
65 #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
66 #endif
67 #include <sys/cdefs.h>
68
69 #else
70
71 #include <ifaddrs.h>
72
73 #endif
74
75 #include <IOKit/IOKitLib.h>
76 #include <IOKit/IOMessage.h>
77
78 // ***************************************************************************
79 // Structures
80
81 typedef struct NetworkInterfaceInfo2_struct NetworkInterfaceInfo2;
82 struct NetworkInterfaceInfo2_struct
83 {
84 NetworkInterfaceInfo ifinfo;
85 mDNS *m;
86 char *ifa_name;
87 NetworkInterfaceInfo2 *alias;
88 int socket;
89 CFSocketRef cfsocket;
90 #if mDNS_AllowPort53
91 int socket53;
92 CFSocketRef cfsocket53;
93 #endif
94 };
95
96 // ***************************************************************************
97 // Functions
98
99 mDNSexport void debugf_(const char *format, ...)
100 {
101 unsigned char buffer[512];
102 va_list ptr;
103 va_start(ptr,format);
104 buffer[mDNS_vsprintf((char *)buffer, format, ptr)] = 0;
105 va_end(ptr);
106 fprintf(stderr, "%s\n", buffer);
107 fflush(stderr);
108 }
109
110 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
111 mDNSIPAddr src, mDNSIPPort srcport, mDNSIPAddr dst, mDNSIPPort dstport)
112 {
113 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2 *)(m->HostInterfaces);
114 struct sockaddr_in to;
115 to.sin_family = AF_INET;
116 to.sin_port = dstport.NotAnInteger;
117 to.sin_addr.s_addr = dst. NotAnInteger;
118
119 if (src.NotAnInteger == 0) debugf("mDNSPlatformSendUDP ERROR! Cannot send from zero source address");
120
121 while (info)
122 {
123 if (info->ifinfo.ip.NotAnInteger == src.NotAnInteger)
124 {
125 int s, err;
126 if (srcport.NotAnInteger == MulticastDNSPort.NotAnInteger) s = info->socket;
127 #if mDNS_AllowPort53
128 else if (srcport.NotAnInteger == UnicastDNSPort.NotAnInteger ) s = info->socket53;
129 #endif
130 else { debugf("Source port %d not allowed", (mDNSu16)srcport.b[0]<<8 | srcport.b[1]); return(-1); }
131 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, sizeof(to));
132 if (err < 0) { perror("mDNSPlatformSendUDP sendto"); return(err); }
133 }
134 info = (NetworkInterfaceInfo2 *)(info->ifinfo.next);
135 }
136
137 return(mStatus_NoError);
138 }
139
140 static ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
141 struct sockaddr *const from, size_t *const fromlen, struct in_addr *dstaddr, char ifname[128])
142 {
143 struct iovec databuffers = { (char *)buffer, max };
144 struct msghdr msg;
145 ssize_t n;
146 struct cmsghdr *cmPtr;
147 char ancillary[1024];
148
149 // Set up the message
150 msg.msg_name = (caddr_t)from;
151 msg.msg_namelen = *fromlen;
152 msg.msg_iov = &databuffers;
153 msg.msg_iovlen = 1;
154 msg.msg_control = (caddr_t)&ancillary;
155 msg.msg_controllen = sizeof(ancillary);
156 msg.msg_flags = 0;
157
158 // Receive the data
159 n = recvmsg(s, &msg, 0);
160 if (n<0 || msg.msg_controllen < sizeof(struct cmsghdr) || (msg.msg_flags & MSG_CTRUNC))
161 { perror("recvmsg"); return(n); }
162
163 *fromlen = msg.msg_namelen;
164
165 // Parse each option out of the ancillary data.
166 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
167 {
168 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
169 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
170 *dstaddr = *(struct in_addr *)CMSG_DATA(cmPtr);
171 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
172 {
173 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
174 if (sdl->sdl_nlen < sizeof(ifname))
175 {
176 mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
177 ifname[sdl->sdl_nlen] = 0;
178 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
179 }
180 }
181 }
182
183 return(n);
184 }
185
186 mDNSlocal void myCFSocketCallBack(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *context)
187 {
188 mDNSIPAddr senderaddr, destaddr;
189 mDNSIPPort senderport;
190 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2 *)context;
191 mDNS *const m = info->m;
192 DNSMessage packet;
193 struct in_addr to;
194 struct sockaddr_in from;
195 size_t fromlen = sizeof(from);
196 char packetifname[128] = "";
197 int err;
198
199 (void)address; // Parameter not used
200 (void)data; // Parameter not used
201
202 if (type != kCFSocketReadCallBack) debugf("myCFSocketCallBack: Why is type not kCFSocketReadCallBack?");
203 #if mDNS_AllowPort53
204 if (s == info->cfsocket53)
205 err = myrecvfrom(info->socket53, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &to, packetifname);
206 else
207 #endif
208 err = myrecvfrom(info->socket, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &to, packetifname);
209
210 if (err < 0) { debugf("myCFSocketCallBack recvfrom error %d", err); return; }
211
212 senderaddr.NotAnInteger = from.sin_addr.s_addr;
213 senderport.NotAnInteger = from.sin_port;
214 destaddr.NotAnInteger = to.s_addr;
215
216 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
217 // sockets API means that even though this socket has only officially joined the multicast group
218 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
219 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
220 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
221 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
222 if (strcmp(info->ifa_name, packetifname))
223 {
224 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s (Ignored -- really arrived on interface %s)",
225 &senderaddr, &destaddr, &info->ifinfo.ip, info->ifa_name, packetifname);
226 return;
227 }
228 else
229 verbosedebugf("myCFSocketCallBack got a packet from %.4a to %.4a on interface %.4a/%s",
230 &senderaddr, &destaddr, &info->ifinfo.ip, info->ifa_name);
231
232 if (err < sizeof(DNSMessageHeader)) { debugf("myCFSocketCallBack packet length (%d) too short", err); return; }
233
234 #if mDNS_AllowPort53
235 if (s == info->cfsocket53)
236 mDNSCoreReceive(m, &packet, (unsigned char*)&packet + err, senderaddr, senderport, destaddr, UnicastDNSPort, info->ifinfo.ip);
237 else
238 #endif
239 mDNSCoreReceive(m, &packet, (unsigned char*)&packet + err, senderaddr, senderport, destaddr, MulticastDNSPort, info->ifinfo.ip);
240 }
241
242 mDNSlocal void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info)
243 {
244 (void)timer; // Parameter not used
245 mDNSCoreTask((mDNS *const)info);
246 }
247
248 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
249 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
250 {
251 CFStringEncoding encoding = kCFStringEncodingUTF8;
252 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
253 if (cfs)
254 {
255 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
256 CFRelease(cfs);
257 }
258 }
259
260 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
261 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
262 {
263 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
264 if (cfs)
265 {
266 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
267 CFRelease(cfs);
268 }
269 }
270
271 mDNSlocal mStatus SetupSocket(struct sockaddr_in *ifa_addr, mDNSIPPort port, int *s, CFSocketRef *c, CFSocketContext *context)
272 {
273 mStatus err;
274 const int on = 1;
275 const int twofivefive = 255;
276 struct ip_mreq imr;
277 struct sockaddr_in listening_sockaddr;
278 CFRunLoopSourceRef rls;
279
280 // Open the socket...
281 *s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
282 *c = NULL;
283 if (*s < 0) { perror("socket"); return(*s); }
284
285 // ... with a shared UDP port
286 err = setsockopt(*s, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
287 if (err < 0) { perror("setsockopt - SO_REUSEPORT"); return(err); }
288
289 // We want to receive destination addresses
290 err = setsockopt(*s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
291 if (err < 0) { perror("setsockopt - IP_RECVDSTADDR"); return(err); }
292
293 // We want to receive interface identifiers
294 err = setsockopt(*s, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
295 if (err < 0) { perror("setsockopt - IP_RECVIF"); return(err); }
296
297 // Add multicast group membership on this interface
298 imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
299 imr.imr_interface = ifa_addr->sin_addr;
300 err = setsockopt(*s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
301 if (err < 0) { perror("setsockopt - IP_ADD_MEMBERSHIP"); return(err); }
302
303 // Specify outgoing interface too
304 err = setsockopt(*s, IPPROTO_IP, IP_MULTICAST_IF, &ifa_addr->sin_addr, sizeof(ifa_addr->sin_addr));
305 if (err < 0) { perror("setsockopt - IP_MULTICAST_IF"); return(err); }
306
307 // Send unicast packets with TTL 255
308 err = setsockopt(*s, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
309 if (err < 0) { perror("setsockopt - IP_TTL"); return(err); }
310
311 // And multicast packets with TTL 255 too
312 err = setsockopt(*s, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
313 if (err < 0) { perror("setsockopt - IP_MULTICAST_TTL"); return(err); }
314
315 // And start listening for packets
316 listening_sockaddr.sin_family = AF_INET;
317 listening_sockaddr.sin_port = port.NotAnInteger;
318 listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
319 err = bind(*s, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
320 if (err)
321 {
322 if (port.NotAnInteger == UnicastDNSPort.NotAnInteger) err = 0;
323 else perror("bind");
324 return(err);
325 }
326
327 *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, context);
328 rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
329 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
330 CFRelease(rls);
331
332 return(err);
333 }
334
335 #if 0
336 mDNSlocal NetworkInterfaceInfo2 *SearchForInterfaceByAddr(mDNS *const m, mDNSIPAddr ip)
337 {
338 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2*)(m->HostInterfaces);
339 while (info)
340 {
341 if (info->ifinfo.ip.NotAnInteger == ip.NotAnInteger) return(info);
342 info = (NetworkInterfaceInfo2 *)(info->ifinfo.next);
343 }
344 return(NULL);
345 }
346 #endif
347
348 mDNSlocal NetworkInterfaceInfo2 *SearchForInterfaceByName(mDNS *const m, char *ifname)
349 {
350 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2*)(m->HostInterfaces);
351 while (info)
352 {
353 if (!strcmp(info->ifa_name, ifname)) return(info);
354 info = (NetworkInterfaceInfo2 *)(info->ifinfo.next);
355 }
356 return(NULL);
357 }
358
359 #if RUN_ON_PUMA_WITHOUT_IFADDRS
360
361 /* Our own header for the programs that need interface configuration info.
362 Include this file, instead of "unp.h". */
363
364 #define IFA_NAME 16 /* same as IFNAMSIZ in <net/if.h> */
365 #define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */
366
367 struct ifa_info {
368 char ifa_name[IFA_NAME]; /* interface name, null terminated */
369 u_char ifa_haddr[IFA_HADDR]; /* hardware address */
370 u_short ifa_hlen; /* #bytes in hardware address: 0, 6, 8 */
371 short ifa_flags; /* IFF_xxx constants from <net/if.h> */
372 short ifa_myflags; /* our own IFI_xxx flags */
373 struct sockaddr *ifa_addr; /* primary address */
374 struct sockaddr *ifa_brdaddr;/* broadcast address */
375 struct sockaddr *ifa_dstaddr;/* destination address */
376 struct ifa_info *ifa_next; /* next of these structures */
377 };
378
379 #define IFI_ALIAS 1 /* ifa_addr is an alias */
380
381 /* function prototypes */
382 struct ifa_info *get_ifa_info(int, int);
383 struct ifa_info *Get_ifa_info(int, int);
384 void free_ifa_info(struct ifa_info *);
385
386 #define HAVE_SOCKADDR_SA_LEN 1
387
388 struct ifa_info *
389 get_ifa_info(int family, int doaliases)
390 {
391 struct ifa_info *ifi, *ifihead, **ifipnext;
392 int sockfd, len, lastlen, flags, myflags;
393 char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
394 struct ifconf ifc;
395 struct ifreq *ifr, ifrcopy;
396 struct sockaddr_in *sinptr;
397
398 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
399
400 lastlen = 0;
401 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
402 for ( ; ; ) {
403 buf = (char *) malloc(len);
404 ifc.ifc_len = len;
405 ifc.ifc_buf = buf;
406 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
407 if (errno != EINVAL || lastlen != 0)
408 debugf("ioctl error");
409 } else {
410 if (ifc.ifc_len == lastlen)
411 break; /* success, len has not changed */
412 lastlen = ifc.ifc_len;
413 }
414 len += 10 * sizeof(struct ifreq); /* increment */
415 free(buf);
416 }
417 ifihead = NULL;
418 ifipnext = &ifihead;
419 lastname[0] = 0;
420 /* end get_ifa_info1 */
421
422 /* include get_ifa_info2 */
423 for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
424 ifr = (struct ifreq *) ptr;
425
426 #ifdef HAVE_SOCKADDR_SA_LEN
427 len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
428 #else
429 switch (ifr->ifr_addr.sa_family) {
430 #ifdef IPV6
431 case AF_INET6:
432 len = sizeof(struct sockaddr_in6);
433 break;
434 #endif
435 case AF_INET:
436 default:
437 len = sizeof(struct sockaddr);
438 break;
439 }
440 #endif /* HAVE_SOCKADDR_SA_LEN */
441 ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
442
443 if (ifr->ifr_addr.sa_family != family)
444 continue; /* ignore if not desired address family */
445
446 myflags = 0;
447 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
448 *cptr = 0; /* replace colon will null */
449 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
450 if (doaliases == 0)
451 continue; /* already processed this interface */
452 myflags = IFI_ALIAS;
453 }
454 memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
455
456 ifrcopy = *ifr;
457 ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
458 flags = ifrcopy.ifr_flags;
459 if ((flags & IFF_UP) == 0)
460 continue; /* ignore if interface not up */
461
462 ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info));
463 *ifipnext = ifi; /* prev points to this new one */
464 ifipnext = &ifi->ifa_next; /* pointer to next one goes here */
465
466 ifi->ifa_flags = flags; /* IFF_xxx values */
467 ifi->ifa_myflags = myflags; /* IFI_xxx values */
468 memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME);
469 ifi->ifa_name[IFA_NAME-1] = '\0';
470 /* end get_ifa_info2 */
471 /* include get_ifa_info3 */
472 switch (ifr->ifr_addr.sa_family) {
473 case AF_INET:
474 sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
475 if (ifi->ifa_addr == NULL) {
476 ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
477 memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in));
478
479 #ifdef SIOCGIFBRDADDR
480 if (flags & IFF_BROADCAST) {
481 ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
482 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
483 ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
484 memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in));
485 }
486 #endif
487
488 #ifdef SIOCGIFDSTADDR
489 if (flags & IFF_POINTOPOINT) {
490 ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
491 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
492 ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
493 memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in));
494 }
495 #endif
496 }
497 break;
498
499 default:
500 break;
501 }
502 }
503 free(buf);
504 return(ifihead); /* pointer to first structure in linked list */
505 }
506 /* end get_ifa_info3 */
507
508 /* include free_ifa_info */
509 mDNSlocal void freeifaddrs(struct ifa_info *ifihead)
510 {
511 struct ifa_info *ifi, *ifinext;
512
513 for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
514 if (ifi->ifa_addr != NULL)
515 free(ifi->ifa_addr);
516 if (ifi->ifa_brdaddr != NULL)
517 free(ifi->ifa_brdaddr);
518 if (ifi->ifa_dstaddr != NULL)
519 free(ifi->ifa_dstaddr);
520 ifinext = ifi->ifa_next; /* can't fetch ifa_next after free() */
521 free(ifi); /* the ifa_info{} itself */
522 }
523 }
524 /* end free_ifa_info */
525
526 struct ifa_info *
527 Get_ifa_info(int family, int doaliases)
528 {
529 struct ifa_info *ifi;
530
531 if ( (ifi = get_ifa_info(family, doaliases)) == NULL)
532 debugf("get_ifa_info error");
533 return(ifi);
534 }
535
536 mDNSlocal int getifaddrs(struct ifa_info **ifalist)
537 {
538 *ifalist = get_ifa_info(PF_INET, false);
539 if( ifalist == nil )
540 return -1;
541 else
542 return(0);
543 }
544
545 #endif
546
547 mDNSlocal mStatus SetupInterface(mDNS *const m, NetworkInterfaceInfo2 *info, struct ifaddrs *ifa)
548 {
549 mStatus err = 0;
550 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)ifa->ifa_addr;
551 CFSocketContext myCFSocketContext = { 0, info, NULL, NULL, NULL };
552
553 info->ifinfo.ip.NotAnInteger = ifa_addr->sin_addr.s_addr;
554 info->ifinfo.Advertise = mDNS_AdvertiseLocalAddresses;
555 info->m = m;
556 info->ifa_name = (char *)mallocL("NetworkInterfaceInfo2 name", strlen(ifa->ifa_name) + 1);
557 if (!info->ifa_name) return(-1);
558 strcpy(info->ifa_name, ifa->ifa_name);
559 info->alias = SearchForInterfaceByName(m, ifa->ifa_name);
560 info->socket = 0;
561 info->cfsocket = 0;
562 #if mDNS_AllowPort53
563 info->socket53 = 0;
564 info->cfsocket53 = 0;
565 #endif
566
567 mDNS_RegisterInterface(m, &info->ifinfo);
568
569 if (info->alias)
570 debugf("SetupInterface: %s Flags %04X %.4a is an alias of %.4a",
571 ifa->ifa_name, ifa->ifa_flags, &info->ifinfo.ip, &info->alias->ifinfo.ip);
572
573 #if mDNS_AllowPort53
574 err = SetupSocket(ifa_addr, UnicastDNSPort, &info->socket53, &info->cfsocket53, &myCFSocketContext);
575 #endif
576 if (!err)
577 err = SetupSocket(ifa_addr, MulticastDNSPort, &info->socket, &info->cfsocket, &myCFSocketContext);
578
579 debugf("SetupInterface: %s Flags %04X %.4a Registered",
580 ifa->ifa_name, ifa->ifa_flags, &info->ifinfo.ip);
581
582 return(err);
583 }
584
585 mDNSlocal void ClearInterfaceList(mDNS *const m)
586 {
587 while (m->HostInterfaces)
588 {
589 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2*)(m->HostInterfaces);
590 mDNS_DeregisterInterface(m, &info->ifinfo);
591 if (info->ifa_name ) freeL("NetworkInterfaceInfo2 name", info->ifa_name);
592 if (info->socket > 0) shutdown(info->socket, 2);
593 if (info->cfsocket) { CFSocketInvalidate(info->cfsocket); CFRelease(info->cfsocket); }
594 #if mDNS_AllowPort53
595 if (info->socket53 > 0) shutdown(info->socket53, 2);
596 if (info->cfsocket53) { CFSocketInvalidate(info->cfsocket53); CFRelease(info->cfsocket53); }
597 #endif
598 freeL("NetworkInterfaceInfo2", info);
599 }
600 }
601
602 mDNSlocal mStatus SetupInterfaceList(mDNS *const m)
603 {
604 struct ifaddrs *ifalist;
605 int err = getifaddrs(&ifalist);
606 struct ifaddrs *ifa = ifalist;
607 struct ifaddrs *theLoopback = NULL;
608 if (err) return(err);
609
610 // Set up the nice label
611 m->nicelabel.c[0] = 0;
612 GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
613 if (m->nicelabel.c[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m->nicelabel);
614
615 // Set up the RFC 1034-compliant label
616 m->hostlabel.c[0] = 0;
617 GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
618 if (m->hostlabel.c[0] == 0) ConvertCStringToDomainLabel("Macintosh", &m->hostlabel);
619
620 mDNS_GenerateFQDN(m);
621
622 while (ifa)
623 {
624 #if 0
625 if (ifa->ifa_addr->sa_family != AF_INET)
626 debugf("SetupInterface: %s Flags %04X Family %d not AF_INET",
627 ifa->ifa_name, ifa->ifa_flags, ifa->ifa_addr->sa_family);
628 if (!(ifa->ifa_flags & IFF_UP))
629 debugf("SetupInterface: %s Flags %04X Interface not IFF_UP", ifa->ifa_name, ifa->ifa_flags);
630 if (ifa->ifa_flags & IFF_LOOPBACK)
631 debugf("SetupInterface: %s Flags %04X Interface IFF_LOOPBACK", ifa->ifa_name, ifa->ifa_flags);
632 if (ifa->ifa_flags & IFF_POINTOPOINT)
633 debugf("SetupInterface: %s Flags %04X Interface IFF_POINTOPOINT", ifa->ifa_name, ifa->ifa_flags);
634 #endif
635 if (ifa->ifa_addr->sa_family == AF_INET && (ifa->ifa_flags & IFF_UP) &&
636 !(ifa->ifa_flags & IFF_POINTOPOINT))
637 {
638 if (ifa->ifa_flags & IFF_LOOPBACK)
639 theLoopback = ifa;
640 else
641 {
642 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2 *)mallocL("NetworkInterfaceInfo2", sizeof(*info));
643 if (!info) debugf("SetupInterfaceList: Out of Memory!");
644 else SetupInterface(m, info, ifa);
645 }
646 }
647 ifa = ifa->ifa_next;
648 }
649
650 if (!m->HostInterfaces && theLoopback)
651 {
652 NetworkInterfaceInfo2 *info = (NetworkInterfaceInfo2 *)mallocL("NetworkInterfaceInfo2", sizeof(*info));
653 if (!info) debugf("SetupInterfaceList: (theLoopback) Out of Memory!");
654 else SetupInterface(m, info, theLoopback);
655 }
656
657 freeifaddrs(ifalist);
658 return(err);
659 }
660
661 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
662 {
663 mDNS *const m = (mDNS *const)context;
664 debugf("*** Network Configuration Change ***");
665 (void)store; // Parameter not used
666 (void)changedKeys; // Parameter not used
667 ClearInterfaceList(m);
668 SetupInterfaceList(m);
669 mDNSCoreSleep(m, false);
670 }
671
672 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
673 {
674 mStatus err = -1;
675 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
676 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder"), NetworkChanged, &context);
677 CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
678 CFStringRef key2 = SCDynamicStoreKeyCreateComputerName(NULL);
679 CFStringRef key3 = SCDynamicStoreKeyCreateHostNames(NULL);
680 CFStringRef pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
681 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
682 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
683
684 if (!store) { fprintf(stderr, "SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error; }
685 if (!key1 || !key2 || !key3 || !keys || !pattern || !patterns) goto error;
686
687 CFArrayAppendValue(keys, key1);
688 CFArrayAppendValue(keys, key2);
689 CFArrayAppendValue(keys, key3);
690 CFArrayAppendValue(patterns, pattern);
691 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
692 { fprintf(stderr, "SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error; }
693
694 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
695 if (!m->p->StoreRLS) { fprintf(stderr, "SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error; }
696
697 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
698 m->p->Store = store;
699 err = 0;
700 goto exit;
701
702 error:
703 if (store) CFRelease(store);
704
705 exit:
706 if (key1) CFRelease(key1);
707 if (key2) CFRelease(key2);
708 if (key3) CFRelease(key3);
709 if (pattern) CFRelease(pattern);
710 if (keys) CFRelease(keys);
711 if (patterns) CFRelease(patterns);
712
713 return(err);
714 }
715
716 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
717 {
718 mDNS *const m = (mDNS *const)refcon;
719 (void)service; // Parameter not used
720 switch(messageType)
721 {
722 case kIOMessageCanSystemPowerOff: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
723 case kIOMessageSystemWillPowerOff: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreSleep(m, true); break; // E0000250
724 case kIOMessageSystemWillNotPowerOff: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
725 case kIOMessageCanSystemSleep: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
726 case kIOMessageSystemWillSleep: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreSleep(m, true); break; // E0000280
727 case kIOMessageSystemWillNotSleep: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
728 case kIOMessageSystemHasPoweredOn: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreSleep(m, false); break; // E0000300
729 default: debugf("PowerChanged unknown message %X", messageType); break;
730 }
731 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
732 }
733
734 mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
735 {
736 IONotificationPortRef thePortRef;
737 m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
738 if (m->p->PowerConnection)
739 {
740 m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
741 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
742 return(mStatus_NoError);
743 }
744 return(-1);
745 }
746
747 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
748 {
749 mStatus err;
750
751 CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, m, NULL, NULL, NULL };
752
753 // Note: Every CFRunLoopTimer has to be created with an initial fire time, and a repeat interval, or it becomes
754 // a one-shot timer and you can't use CFRunLoopTimerSetNextFireDate(timer, when) to schedule subsequent firings.
755 // Here we create it with an initial fire time ten seconds from now, and a repeat interval of ten seconds,
756 // knowing that we'll reschedule it using CFRunLoopTimerSetNextFireDate(timer, when) long before that happens.
757 m->p->CFTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 10.0, 10.0, 0, 1,
758 myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext);
759 CFRunLoopAddTimer(CFRunLoopGetCurrent(), m->p->CFTimer, kCFRunLoopDefaultMode);
760
761 SetupInterfaceList(m);
762
763 err = WatchForNetworkChanges(m);
764 if (err) return(err);
765
766 err = WatchForPowerChanges(m);
767 return(err);
768 }
769
770 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
771 {
772 mStatus result = mDNSPlatformInit_setup(m);
773 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
774 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
775 if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
776 return(result);
777 }
778
779 mDNSexport void mDNSPlatformClose(mDNS *const m)
780 {
781 if (m->p->PowerConnection)
782 {
783 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
784 CFRunLoopSourceInvalidate(m->p->PowerRLS);
785 CFRelease(m->p->PowerRLS);
786 IODeregisterForSystemPower(&m->p->PowerNotifier);
787 m->p->PowerConnection = NULL;
788 m->p->PowerNotifier = NULL;
789 m->p->PowerRLS = NULL;
790 }
791
792 if (m->p->Store)
793 {
794 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
795 CFRunLoopSourceInvalidate(m->p->StoreRLS);
796 CFRelease(m->p->StoreRLS);
797 CFRelease(m->p->Store);
798 m->p->Store = NULL;
799 m->p->StoreRLS = NULL;
800 }
801
802 ClearInterfaceList(m);
803
804 if (m->p->CFTimer)
805 {
806 CFRunLoopTimerInvalidate(m->p->CFTimer);
807 CFRelease(m->p->CFTimer);
808 m->p->CFTimer = NULL;
809 }
810 }
811
812 // To Do: Find out how to implement a proper modular time function in CF
813 mDNSexport void mDNSPlatformScheduleTask(const mDNS *const m, SInt32 NextTaskTime)
814 {
815 if (m->p->CFTimer)
816 {
817 CFAbsoluteTime ticks = (CFAbsoluteTime)(NextTaskTime - mDNSPlatformTimeNow());
818 CFAbsoluteTime interval = ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
819 CFRunLoopTimerSetNextFireDate(m->p->CFTimer, CFAbsoluteTimeGetCurrent() + interval);
820 }
821 }
822
823 // Locking is a no-op here, because we're CFRunLoop-based, so we can never interrupt ourselves
824 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
825 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
826 mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { strcpy((char *)dst, (char *)src); }
827 mDNSexport UInt32 mDNSPlatformStrLen (const void *src) { return(strlen((char*)src)); }
828 mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, UInt32 len) { memcpy(dst, src, len); }
829 mDNSexport Boolean mDNSPlatformMemSame(const void *src, const void *dst, UInt32 len) { return(memcmp(dst, src, len) == 0); }
830 mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { bzero(dst, len); }
831
832 mDNSexport SInt32 mDNSPlatformTimeNow()
833 {
834 struct timeval tp;
835 gettimeofday(&tp, NULL);
836 // tp.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
837 // tp.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
838 // We use the lower 22 bits of tp.tv_sec for the top 22 bits of our result
839 // and we multiply tp.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
840 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
841 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
842 return( (tp.tv_sec << 10) | (tp.tv_usec * 16 / 15625) );
843 }
844
845 mDNSexport SInt32 mDNSPlatformOneSecond = 1024;