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