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