1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
26 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
27 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
28 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
29 * therefore common sense dictates that if they are part of a compound statement then they
30 * should be indented to the same level as everything else in that compound statement.
31 * Indenting curly braces at the same level as the "if" implies that curly braces are
32 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
33 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
34 * understand why variable y is not of type "char*" just proves the point that poor code
35 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37 Change History (most recent first):
40 Revision 1.75 2006/01/05 22:04:57 cheshire
41 <rdar://problem/4399479> Log error message when send fails with "operation not permitted"
43 Revision 1.74 2006/01/05 21:45:27 cheshire
44 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
46 Revision 1.73 2005/10/11 21:31:46 cheshire
47 <rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms)
49 Revision 1.72 2005/09/08 20:45:26 cheshire
50 Default dot-local host name should be "Computer" not "Macintosh",
51 since the machine this is running on is most likely NOT a Mac.
53 Revision 1.71 2005/02/26 01:29:12 cheshire
54 Ignore multicasts accidentally delivered to our unicast receiving socket
56 Revision 1.70 2005/02/04 00:39:59 cheshire
57 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
59 Revision 1.69 2004/12/18 02:03:28 cheshire
60 Need to #include "dns_sd.h"
62 Revision 1.68 2004/12/18 00:51:52 cheshire
63 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
65 Revision 1.67 2004/12/17 23:37:48 cheshire
66 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
67 (and other repetitive configuration changes)
69 Revision 1.66 2004/12/01 04:27:28 cheshire
70 <rdar://problem/3872803> Darwin patches for Solaris and Suse
71 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
73 Revision 1.65 2004/11/30 22:37:01 cheshire
74 Update copyright dates and add "Mode: C; tab-width: 4" headers
76 Revision 1.64 2004/11/23 03:39:47 cheshire
77 Let interface name/index mapping capability live directly in JNISupport.c,
78 instead of having to call through to the daemon via IPC to get this information.
80 Revision 1.63 2004/11/12 03:16:43 rpantos
81 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
83 Revision 1.62 2004/10/28 03:24:42 cheshire
84 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
86 Revision 1.61 2004/10/16 00:17:01 cheshire
87 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
89 Revision 1.60 2004/09/26 23:20:36 ksekar
90 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
92 Revision 1.59 2004/09/21 21:02:55 cheshire
93 Set up ifname before calling mDNS_RegisterInterface()
95 Revision 1.58 2004/09/17 01:08:54 cheshire
96 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
97 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
98 declared in that file are ONLY appropriate to single-address-space embedded applications.
99 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
101 Revision 1.57 2004/09/17 00:19:11 cheshire
102 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
104 Revision 1.56 2004/09/17 00:15:56 cheshire
105 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
107 Revision 1.55 2004/09/16 00:24:49 cheshire
108 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
110 Revision 1.54 2004/09/15 23:55:00 ksekar
111 <rdar://problem/3800597> mDNSPosix should #include stdint.h
113 Revision 1.53 2004/09/14 23:42:36 cheshire
114 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
116 Revision 1.52 2004/08/25 16:42:13 ksekar
117 Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
120 Revision 1.51 2004/08/14 03:22:42 cheshire
121 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
122 Add GetUserSpecifiedDDNSName() routine
123 Convert ServiceRegDomain to domainname instead of C string
124 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
126 Revision 1.50 2004/08/11 01:20:20 cheshire
127 Declare private local functions using "mDNSlocal"
129 Revision 1.49 2004/07/26 22:49:31 ksekar
130 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
132 Revision 1.48 2004/07/20 01:47:36 rpantos
133 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
135 Revision 1.47 2004/06/25 00:26:27 rpantos
136 Changes to fix the Posix build on Solaris.
138 Revision 1.46 2004/05/13 04:54:20 ksekar
139 Unified list copy/free code. Added symetric list for
141 Revision 1.45 2004/05/12 22:03:09 ksekar
142 Made GetSearchDomainList a true platform-layer call (declaration moved
143 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
144 only on non-OSX platforms. Changed call to return a copy of the list
145 to avoid shared memory issues. Added a routine to free the list.
147 Revision 1.44 2004/04/21 02:49:11 cheshire
148 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
150 Revision 1.43 2004/04/14 23:09:29 ksekar
151 Support for TSIG signed dynamic updates.
153 Revision 1.42 2004/04/09 17:43:04 cheshire
154 Make sure to set the McastTxRx field so that duplicate suppression works correctly
156 Revision 1.41 2004/02/06 01:19:51 cheshire
157 Conditionally exclude IPv6 code unless HAVE_IPV6 is set
159 Revision 1.40 2004/02/05 01:00:01 rpantos
160 Fix some issues that turned up when building for FreeBSD.
162 Revision 1.39 2004/01/28 21:12:15 cheshire
163 Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
165 Revision 1.38 2004/01/27 20:15:23 cheshire
166 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
168 Revision 1.37 2004/01/24 05:12:03 cheshire
169 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
171 Revision 1.36 2004/01/24 04:59:16 cheshire
172 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
174 Revision 1.35 2004/01/23 21:37:08 cheshire
175 For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
177 Revision 1.34 2004/01/22 03:43:09 cheshire
178 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
180 Revision 1.33 2004/01/21 21:54:20 cheshire
181 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
183 Revision 1.32 2004/01/20 01:49:28 rpantos
184 Tweak error handling of last checkin a bit.
186 Revision 1.31 2004/01/20 01:39:27 rpantos
187 Respond to If changes by rebuilding interface list.
189 Revision 1.30 2003/12/11 19:40:36 cheshire
190 Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
192 Revision 1.29 2003/12/11 18:53:22 cheshire
193 Fix compiler warning reported by Paul Guyot
195 Revision 1.28 2003/12/11 03:03:51 rpantos
196 Clean up mDNSPosix so that it builds on OS X again.
198 Revision 1.27 2003/12/08 20:47:02 rpantos
199 Add support for mDNSResponder on Linux.
201 Revision 1.26 2003/11/14 20:59:09 cheshire
202 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
203 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
205 Revision 1.25 2003/10/30 19:25:49 cheshire
206 Fix signed/unsigned warning on certain compilers
208 Revision 1.24 2003/08/18 23:12:23 cheshire
209 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
211 Revision 1.23 2003/08/12 19:56:26 cheshire
214 Revision 1.22 2003/08/06 18:46:15 cheshire
215 LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
217 Revision 1.21 2003/08/06 18:20:51 cheshire
220 Revision 1.20 2003/08/05 23:56:26 cheshire
221 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
222 (Right now mDNSPosix.c just reports 255 -- we should fix this)
224 Revision 1.19 2003/07/19 03:15:16 cheshire
225 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
226 and add the obvious trivial implementations to each platform support layer
228 Revision 1.18 2003/07/14 18:11:54 cheshire
229 Fix stricter compiler warnings
231 Revision 1.17 2003/07/13 01:08:38 cheshire
232 There's not much point running mDNS over a point-to-point link; exclude those
234 Revision 1.16 2003/07/02 21:19:59 cheshire
235 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
237 Revision 1.15 2003/06/18 05:48:41 cheshire
240 Revision 1.14 2003/05/26 03:21:30 cheshire
241 Tidy up address structure naming:
242 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
243 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
244 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
246 Revision 1.13 2003/05/26 03:01:28 cheshire
247 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
249 Revision 1.12 2003/05/21 03:49:18 cheshire
252 Revision 1.11 2003/05/06 00:00:50 cheshire
253 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
255 Revision 1.10 2003/04/25 01:45:57 cheshire
256 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
258 Revision 1.9 2003/03/20 21:10:31 cheshire
259 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
261 Revision 1.8 2003/03/15 04:40:38 cheshire
262 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
264 Revision 1.7 2003/03/13 03:46:21 cheshire
265 Fixes to make the code build on Linux
267 Revision 1.6 2003/03/08 00:35:56 cheshire
268 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
270 Revision 1.5 2002/12/23 22:13:31 jgraessl
271 Reviewed by: Stuart Cheshire
272 Initial IPv6 support for mDNSResponder.
274 Revision 1.4 2002/09/27 01:47:45 cheshire
275 Workaround for Linux 2.0 systems that don't have IP_PKTINFO
277 Revision 1.3 2002/09/21 20:44:53 zarzycki
280 Revision 1.2 2002/09/19 21:25:36 cheshire
281 mDNS_snprintf() doesn't need to be in a separate file
283 Revision 1.1 2002/09/17 06:24:34 cheshire
287 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
288 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
300 #include <sys/types.h>
301 #include <sys/time.h>
302 #include <sys/socket.h>
304 #include <sys/select.h>
305 #include <netinet/in.h>
306 #include <arpa/inet.h>
307 #include <time.h> // platform support for UTC time
310 #include <asm/types.h>
311 #include <linux/netlink.h>
312 #include <linux/rtnetlink.h>
313 #else // USES_NETLINK
314 #include <net/route.h>
316 #endif // USES_NETLINK
319 #include "GenLinkedList.h"
321 // ***************************************************************************
324 // We keep a list of client-supplied event sources in PosixEventSource records
325 struct PosixEventSource
327 mDNSPosixEventCallback Callback
;
330 struct PosixEventSource
*Next
;
332 typedef struct PosixEventSource PosixEventSource
;
334 // Context record for interface change callback
340 typedef struct IfChangeRec IfChangeRec
;
342 // Note that static data is initialized to zero in (modern) C.
343 static fd_set gEventFDs
;
344 static int gMaxFD
; // largest fd in gEventFDs
345 static GenLinkedList gEventSources
; // linked list of PosixEventSource's
346 static sigset_t gEventSignalSet
; // Signals which event loop listens for
347 static sigset_t gEventSignals
; // Signals which were received while inside loop
349 // ***************************************************************************
350 // Globals (for debugging)
352 static int num_registered_interfaces
= 0;
353 static int num_pkts_accepted
= 0;
354 static int num_pkts_rejected
= 0;
356 // ***************************************************************************
359 int gMDNSPlatformPosixVerboseLevel
= 0;
361 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
363 mDNSlocal
void SockAddrTomDNSAddr(const struct sockaddr
*const sa
, mDNSAddr
*ipAddr
, mDNSIPPort
*ipPort
)
365 switch (sa
->sa_family
)
369 struct sockaddr_in
* sin
= (struct sockaddr_in
*)sa
;
370 ipAddr
->type
= mDNSAddrType_IPv4
;
371 ipAddr
->ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
372 if (ipPort
) ipPort
->NotAnInteger
= sin
->sin_port
;
379 struct sockaddr_in6
* sin6
= (struct sockaddr_in6
*)sa
;
380 #ifndef NOT_HAVE_SA_LEN
381 assert(sin6
->sin6_len
== sizeof(*sin6
));
383 ipAddr
->type
= mDNSAddrType_IPv6
;
384 ipAddr
->ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
385 if (ipPort
) ipPort
->NotAnInteger
= sin6
->sin6_port
;
391 verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa
->sa_family
);
392 ipAddr
->type
= mDNSAddrType_None
;
393 if (ipPort
) ipPort
->NotAnInteger
= 0;
398 #if COMPILER_LIKES_PRAGMA_MARK
399 #pragma mark ***** Send and Receive
402 // mDNS core calls this routine when it needs to send a packet.
403 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
404 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
407 struct sockaddr_storage to
;
408 PosixNetworkInterface
* thisIntf
= (PosixNetworkInterface
*)(InterfaceID
);
409 int sendingsocket
= -1;
414 assert( (((char *) end
) - ((char *) msg
)) > 0 );
415 assert(dstPort
.NotAnInteger
!= 0);
417 if (dst
->type
== mDNSAddrType_IPv4
)
419 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&to
;
420 #ifndef NOT_HAVE_SA_LEN
421 sin
->sin_len
= sizeof(*sin
);
423 sin
->sin_family
= AF_INET
;
424 sin
->sin_port
= dstPort
.NotAnInteger
;
425 sin
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
426 sendingsocket
= thisIntf
? thisIntf
->multicastSocket4
: m
->p
->unicastSocket4
;
430 else if (dst
->type
== mDNSAddrType_IPv6
)
432 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&to
;
433 mDNSPlatformMemZero(sin6
, sizeof(*sin6
));
434 #ifndef NOT_HAVE_SA_LEN
435 sin6
->sin6_len
= sizeof(*sin6
);
437 sin6
->sin6_family
= AF_INET6
;
438 sin6
->sin6_port
= dstPort
.NotAnInteger
;
439 sin6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
440 sendingsocket
= thisIntf
? thisIntf
->multicastSocket6
: m
->p
->unicastSocket6
;
444 if (sendingsocket
>= 0)
445 err
= sendto(sendingsocket
, msg
, (char*)end
- (char*)msg
, 0, (struct sockaddr
*)&to
, GET_SA_LEN(to
));
447 if (err
> 0) err
= 0;
450 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
451 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
452 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
455 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
456 errno
, strerror(errno
), dst
, &thisIntf
->coreIntf
.ip
, thisIntf
->intfName
, thisIntf
->index
);
458 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno
, strerror(errno
), dst
);
461 return PosixErrorToStatus(err
);
464 // This routine is called when the main loop detects that data is available on a socket.
465 mDNSlocal
void SocketDataReady(mDNS
*const m
, PosixNetworkInterface
*intf
, int skt
)
467 mDNSAddr senderAddr
, destAddr
;
468 mDNSIPPort senderPort
;
471 struct my_in_pktinfo packetInfo
;
472 struct sockaddr_storage from
;
477 const mDNSInterfaceID InterfaceID
= intf
? intf
->coreIntf
.InterfaceID
: NULL
;
482 fromLen
= sizeof(from
);
484 packetLen
= recvfrom_flags(skt
, &packet
, sizeof(packet
), &flags
, (struct sockaddr
*) &from
, &fromLen
, &packetInfo
, &ttl
);
488 SockAddrTomDNSAddr((struct sockaddr
*)&from
, &senderAddr
, &senderPort
);
489 SockAddrTomDNSAddr((struct sockaddr
*)&packetInfo
.ipi_addr
, &destAddr
, NULL
);
491 // If we have broken IP_RECVDSTADDR functionality (so far
492 // I've only seen this on OpenBSD) then apply a hack to
493 // convince mDNS Core that this isn't a spoof packet.
494 // Basically what we do is check to see whether the
495 // packet arrived as a multicast and, if so, set its
496 // destAddr to the mDNS address.
498 // I must admit that I could just be doing something
499 // wrong on OpenBSD and hence triggering this problem
500 // but I'm at a loss as to how.
502 // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
503 // no way to tell the destination address or interface this packet arrived on,
504 // so all we can do is just assume it's a multicast
506 #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
507 if ( (destAddr
.NotAnInteger
== 0) && (flags
& MSG_MCAST
) )
509 destAddr
.type
= senderAddr
.type
;
510 if (senderAddr
.type
== mDNSAddrType_IPv4
) destAddr
.ip
.v4
= AllDNSLinkGroupv4
;
511 else if (senderAddr
.type
== mDNSAddrType_IPv6
) destAddr
.ip
.v6
= AllDNSLinkGroupv6
;
515 // We only accept the packet if the interface on which it came
516 // in matches the interface associated with this socket.
517 // We do this match by name or by index, depending on which
518 // information is available. recvfrom_flags sets the name
519 // to "" if the name isn't available, or the index to -1
520 // if the index is available. This accomodates the various
521 // different capabilities of our target platforms.
526 // Ignore multicasts accidentally delivered to our unicast receiving socket
527 if (mDNSAddrIsDNSMulticast(&destAddr
)) packetLen
= -1;
531 if ( packetInfo
.ipi_ifname
[0] != 0 ) reject
= (strcmp(packetInfo
.ipi_ifname
, intf
->intfName
) != 0);
532 else if ( packetInfo
.ipi_ifindex
!= -1 ) reject
= (packetInfo
.ipi_ifindex
!= intf
->index
);
536 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
537 &senderAddr
, &destAddr
, packetInfo
.ipi_ifname
, packetInfo
.ipi_ifindex
,
538 &intf
->coreIntf
.ip
, intf
->intfName
, intf
->index
, skt
);
541 if (num_pkts_rejected
> (num_pkts_accepted
+ 1) * (num_registered_interfaces
+ 1) * 2)
544 "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
545 num_pkts_accepted
+ num_pkts_rejected
, num_pkts_accepted
, num_pkts_rejected
);
546 num_pkts_accepted
= 0;
547 num_pkts_rejected
= 0;
552 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
553 &senderAddr
, &destAddr
, &intf
->coreIntf
.ip
, intf
->intfName
, intf
->index
, skt
);
560 mDNSCoreReceive(m
, &packet
, (mDNSu8
*)&packet
+ packetLen
,
561 &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, InterfaceID
);
564 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
565 TCPConnectionCallback callback
, void *context
, int *descriptor
)
568 (void)dstport
; // Unused
569 (void)InterfaceID
; // Unused
570 (void)callback
; // Unused
571 (void)context
; // Unused
572 (void)descriptor
; // Unused
573 return(mStatus_UnsupportedErr
);
576 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
581 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
585 (void)buflen
; // Unused
589 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
597 #if COMPILER_LIKES_PRAGMA_MARK
598 #pragma mark ***** Get/Free Search Domain List
601 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
603 static DNameListElem tmp
;
604 static mDNSBool init
= mDNSfalse
;
608 MakeDomainNameFromDNSNameString(&tmp
.name
, "local.");
612 return mDNS_CopyDNameList(&tmp
);
615 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
620 #if COMPILER_LIKES_PRAGMA_MARK
621 #pragma mark ***** Init and Term
624 // This gets the current hostname, truncating it at the first dot if necessary
625 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
628 gethostname((char *)(&namelabel
->c
[1]), MAX_DOMAIN_LABEL
);
629 while (len
< MAX_DOMAIN_LABEL
&& namelabel
->c
[len
+1] && namelabel
->c
[len
+1] != '.') len
++;
630 namelabel
->c
[0] = len
;
633 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
634 // Other platforms can either get the information from the appropriate place,
635 // or they can alternatively just require all registering services to provide an explicit name
636 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
638 // On Unix we have no better name than the host name, so we just use that.
639 GetUserSpecifiedRFC1034ComputerName( namelabel
);
642 mDNSexport
int ParseDNSServers(mDNS
*m
, const char *filePath
)
647 int numOfServers
= 0;
648 FILE *fp
= fopen(filePath
, "r");
649 if (fp
== NULL
) return -1;
650 while (fgets(line
,sizeof(line
),fp
))
653 line
[255]='\0'; // just to be safe
654 if (sscanf(line
,"%10s %15s", keyword
, nameserver
) != 2) continue; // it will skip whitespaces
655 if (strncmp(keyword
,"nameserver",10)) continue;
656 if (inet_aton(nameserver
, (struct in_addr
*)&ina
) != 0)
659 DNSAddr
.type
= mDNSAddrType_IPv4
;
660 DNSAddr
.ip
.v4
.NotAnInteger
= ina
.s_addr
;
661 mDNS_AddDNSServer(m
, &DNSAddr
, NULL
);
665 return (numOfServers
> 0) ? 0 : -1;
668 // Searches the interface list looking for the named interface.
669 // Returns a pointer to if it found, or NULL otherwise.
670 mDNSlocal PosixNetworkInterface
*SearchForInterfaceByName(mDNS
*const m
, const char *intfName
)
672 PosixNetworkInterface
*intf
;
675 assert(intfName
!= NULL
);
677 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
678 while ( (intf
!= NULL
) && (strcmp(intf
->intfName
, intfName
) != 0) )
679 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
684 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
686 PosixNetworkInterface
*intf
;
690 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
692 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
693 while ( (intf
!= NULL
) && (mDNSu32
) intf
->index
!= index
)
694 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
696 return (mDNSInterfaceID
) intf
;
699 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
701 PosixNetworkInterface
*intf
;
705 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
707 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
708 while ( (intf
!= NULL
) && (mDNSInterfaceID
) intf
!= id
)
709 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
711 return intf
? intf
->index
: 0;
714 // Frees the specified PosixNetworkInterface structure. The underlying
715 // interface must have already been deregistered with the mDNS core.
716 mDNSlocal
void FreePosixNetworkInterface(PosixNetworkInterface
*intf
)
718 assert(intf
!= NULL
);
719 if (intf
->intfName
!= NULL
) free((void *)intf
->intfName
);
720 if (intf
->multicastSocket4
!= -1) assert(close(intf
->multicastSocket4
) == 0);
722 if (intf
->multicastSocket6
!= -1) assert(close(intf
->multicastSocket6
) == 0);
727 // Grab the first interface, deregister it, free it, and repeat until done.
728 mDNSlocal
void ClearInterfaceList(mDNS
*const m
)
732 while (m
->HostInterfaces
)
734 PosixNetworkInterface
*intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
735 mDNS_DeregisterInterface(m
, &intf
->coreIntf
);
736 if (gMDNSPlatformPosixVerboseLevel
> 0) fprintf(stderr
, "Deregistered interface %s\n", intf
->intfName
);
737 FreePosixNetworkInterface(intf
);
739 num_registered_interfaces
= 0;
740 num_pkts_accepted
= 0;
741 num_pkts_rejected
= 0;
744 // Sets up a send/receive socket.
745 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
746 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
747 mDNSlocal
int SetupSocket(struct sockaddr
*intfAddr
, mDNSIPPort port
, int interfaceIndex
, int *sktPtr
)
750 static const int kOn
= 1;
751 static const int kIntTwoFiveFive
= 255;
752 static const unsigned char kByteTwoFiveFive
= 255;
753 const mDNSBool JoinMulticastGroup
= (port
.NotAnInteger
!= 0);
755 (void) interfaceIndex
; // This parameter unused on plaforms that don't have IPv6
756 assert(intfAddr
!= NULL
);
757 assert(sktPtr
!= NULL
);
758 assert(*sktPtr
== -1);
760 // Open the socket...
761 if (intfAddr
->sa_family
== AF_INET
) *sktPtr
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
763 else if (intfAddr
->sa_family
== AF_INET6
) *sktPtr
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
767 if (*sktPtr
< 0) { err
= errno
; perror("socket"); }
769 // ... with a shared UDP port, if it's for multicast receiving
770 if (err
== 0 && port
.NotAnInteger
)
772 #if defined(SO_REUSEPORT)
773 err
= setsockopt(*sktPtr
, SOL_SOCKET
, SO_REUSEPORT
, &kOn
, sizeof(kOn
));
774 #elif defined(SO_REUSEADDR)
775 err
= setsockopt(*sktPtr
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
777 #error This platform has no way to avoid address busy errors on multicast.
779 if (err
< 0) { err
= errno
; perror("setsockopt - SO_REUSExxxx"); }
782 // We want to receive destination addresses and interface identifiers.
783 if (intfAddr
->sa_family
== AF_INET
)
786 struct sockaddr_in bindAddr
;
789 #if defined(IP_PKTINFO) // Linux
790 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_PKTINFO
, &kOn
, sizeof(kOn
));
791 if (err
< 0) { err
= errno
; perror("setsockopt - IP_PKTINFO"); }
792 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
793 #if defined(IP_RECVDSTADDR)
794 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVDSTADDR
, &kOn
, sizeof(kOn
));
795 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVDSTADDR"); }
797 #if defined(IP_RECVIF)
800 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVIF
, &kOn
, sizeof(kOn
));
801 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVIF"); }
805 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
808 #if defined(IP_RECVTTL) // Linux
811 setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVTTL
, &kOn
, sizeof(kOn
));
812 // We no longer depend on being able to get the received TTL, so don't worry if the option fails
816 // Add multicast group membership on this interface
817 if (err
== 0 && JoinMulticastGroup
)
819 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
820 imr
.imr_interface
= ((struct sockaddr_in
*)intfAddr
)->sin_addr
;
821 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
822 if (err
< 0) { err
= errno
; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
825 // Specify outgoing interface too
826 if (err
== 0 && JoinMulticastGroup
)
828 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_IF
, &((struct sockaddr_in
*)intfAddr
)->sin_addr
, sizeof(struct in_addr
));
829 if (err
< 0) { err
= errno
; perror("setsockopt - IP_MULTICAST_IF"); }
832 // Per the mDNS spec, send unicast packets with TTL 255
835 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_TTL
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
836 if (err
< 0) { err
= errno
; perror("setsockopt - IP_TTL"); }
839 // and multicast packets with TTL 255 too
840 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
843 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_TTL
, &kByteTwoFiveFive
, sizeof(kByteTwoFiveFive
));
844 if (err
< 0 && errno
== EINVAL
)
845 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_TTL
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
846 if (err
< 0) { err
= errno
; perror("setsockopt - IP_MULTICAST_TTL"); }
849 // And start listening for packets
852 bindAddr
.sin_family
= AF_INET
;
853 bindAddr
.sin_port
= port
.NotAnInteger
;
854 bindAddr
.sin_addr
.s_addr
= INADDR_ANY
; // Want to receive multicasts AND unicasts on this socket
855 err
= bind(*sktPtr
, (struct sockaddr
*) &bindAddr
, sizeof(bindAddr
));
856 if (err
< 0) { err
= errno
; perror("bind"); fflush(stderr
); }
858 } // endif (intfAddr->sa_family == AF_INET)
861 else if (intfAddr
->sa_family
== AF_INET6
)
863 struct ipv6_mreq imr6
;
864 struct sockaddr_in6 bindAddr6
;
865 #if defined(IPV6_PKTINFO)
868 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_PKTINFO
, &kOn
, sizeof(kOn
));
869 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_PKTINFO"); }
872 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
874 #if defined(IPV6_HOPLIMIT)
877 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &kOn
, sizeof(kOn
));
878 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_HOPLIMIT"); }
882 // Add multicast group membership on this interface
883 if (err
== 0 && JoinMulticastGroup
)
885 imr6
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&AllDNSLinkGroupv6
;
886 imr6
.ipv6mr_interface
= interfaceIndex
;
887 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &imr6
, sizeof(imr6
));
891 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6
.ipv6mr_multiaddr
, imr6
.ipv6mr_interface
);
892 perror("setsockopt - IPV6_JOIN_GROUP");
896 // Specify outgoing interface too
897 if (err
== 0 && JoinMulticastGroup
)
899 u_int multicast_if
= interfaceIndex
;
900 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &multicast_if
, sizeof(multicast_if
));
901 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_MULTICAST_IF"); }
904 // We want to receive only IPv6 packets on this socket.
905 // Without this option, we may get IPv4 addresses as mapped addresses.
908 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_V6ONLY
, &kOn
, sizeof(kOn
));
909 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_V6ONLY"); }
912 // Per the mDNS spec, send unicast packets with TTL 255
915 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
916 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_UNICAST_HOPS"); }
919 // and multicast packets with TTL 255 too
920 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
923 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &kByteTwoFiveFive
, sizeof(kByteTwoFiveFive
));
924 if (err
< 0 && errno
== EINVAL
)
925 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
926 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
929 // And start listening for packets
932 mDNSPlatformMemZero(&bindAddr6
, sizeof(bindAddr6
));
933 #ifndef NOT_HAVE_SA_LEN
934 bindAddr6
.sin6_len
= sizeof(bindAddr6
);
936 bindAddr6
.sin6_family
= AF_INET6
;
937 bindAddr6
.sin6_port
= port
.NotAnInteger
;
938 bindAddr6
.sin6_flowinfo
= 0;
939 bindAddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
940 bindAddr6
.sin6_scope_id
= 0;
941 err
= bind(*sktPtr
, (struct sockaddr
*) &bindAddr6
, sizeof(bindAddr6
));
942 if (err
< 0) { err
= errno
; perror("bind"); fflush(stderr
); }
944 } // endif (intfAddr->sa_family == AF_INET6)
947 // Set the socket to non-blocking.
950 err
= fcntl(*sktPtr
, F_GETFL
, 0);
951 if (err
< 0) err
= errno
;
954 err
= fcntl(*sktPtr
, F_SETFL
, err
| O_NONBLOCK
);
955 if (err
< 0) err
= errno
;
960 if (err
!= 0 && *sktPtr
!= -1) { assert(close(*sktPtr
) == 0); *sktPtr
= -1; }
961 assert( (err
== 0) == (*sktPtr
!= -1) );
965 // Creates a PosixNetworkInterface for the interface whose IP address is
966 // intfAddr and whose name is intfName and registers it with mDNS core.
967 mDNSlocal
int SetupOneInterface(mDNS
*const m
, struct sockaddr
*intfAddr
, struct sockaddr
*intfMask
, const char *intfName
, int intfIndex
)
970 PosixNetworkInterface
*intf
;
971 PosixNetworkInterface
*alias
= NULL
;
974 assert(intfAddr
!= NULL
);
975 assert(intfName
!= NULL
);
976 assert(intfMask
!= NULL
);
978 // Allocate the interface structure itself.
979 intf
= (PosixNetworkInterface
*)malloc(sizeof(*intf
));
980 if (intf
== NULL
) { assert(0); err
= ENOMEM
; }
982 // And make a copy of the intfName.
985 intf
->intfName
= strdup(intfName
);
986 if (intf
->intfName
== NULL
) { assert(0); err
= ENOMEM
; }
991 // Set up the fields required by the mDNS core.
992 SockAddrTomDNSAddr(intfAddr
, &intf
->coreIntf
.ip
, NULL
);
993 SockAddrTomDNSAddr(intfMask
, &intf
->coreIntf
.mask
, NULL
);
994 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
995 strncpy(intf
->coreIntf
.ifname
, intfName
, sizeof(intf
->coreIntf
.ifname
));
996 intf
->coreIntf
.ifname
[sizeof(intf
->coreIntf
.ifname
)-1] = 0;
997 intf
->coreIntf
.Advertise
= m
->AdvertiseLocalAddresses
;
998 intf
->coreIntf
.McastTxRx
= mDNStrue
;
1000 // Set up the extra fields in PosixNetworkInterface.
1001 assert(intf
->intfName
!= NULL
); // intf->intfName already set up above
1002 intf
->index
= intfIndex
;
1003 intf
->multicastSocket4
= -1;
1005 intf
->multicastSocket6
= -1;
1007 alias
= SearchForInterfaceByName(m
, intf
->intfName
);
1008 if (alias
== NULL
) alias
= intf
;
1009 intf
->coreIntf
.InterfaceID
= (mDNSInterfaceID
)alias
;
1012 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName
, &intf
->coreIntf
.ip
, &alias
->coreIntf
.ip
);
1015 // Set up the multicast socket
1018 if (alias
->multicastSocket4
== -1 && intfAddr
->sa_family
== AF_INET
)
1019 err
= SetupSocket(intfAddr
, MulticastDNSPort
, intf
->index
, &alias
->multicastSocket4
);
1021 else if (alias
->multicastSocket6
== -1 && intfAddr
->sa_family
== AF_INET6
)
1022 err
= SetupSocket(intfAddr
, MulticastDNSPort
, intf
->index
, &alias
->multicastSocket6
);
1026 // The interface is all ready to go, let's register it with the mDNS core.
1028 err
= mDNS_RegisterInterface(m
, &intf
->coreIntf
, 0);
1033 num_registered_interfaces
++;
1034 debugf("SetupOneInterface: %s %#a Registered", intf
->intfName
, &intf
->coreIntf
.ip
);
1035 if (gMDNSPlatformPosixVerboseLevel
> 0)
1036 fprintf(stderr
, "Registered interface %s\n", intf
->intfName
);
1040 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1041 debugf("SetupOneInterface: %s %#a failed to register %d", intfName
, &intf
->coreIntf
.ip
, err
);
1042 if (intf
) { FreePosixNetworkInterface(intf
); intf
= NULL
; }
1045 assert( (err
== 0) == (intf
!= NULL
) );
1050 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
1051 mDNSlocal
int SetupInterfaceList(mDNS
*const m
)
1053 mDNSBool foundav4
= mDNSfalse
;
1055 struct ifi_info
*intfList
= get_ifi_info(AF_INET
, mDNStrue
);
1056 struct ifi_info
*firstLoopback
= NULL
;
1059 debugf("SetupInterfaceList");
1061 if (intfList
== NULL
) err
= ENOENT
;
1064 if (err
== 0) /* Link the IPv6 list to the end of the IPv4 list */
1066 struct ifi_info
**p
= &intfList
;
1067 while (*p
) p
= &(*p
)->ifi_next
;
1068 *p
= get_ifi_info(AF_INET6
, mDNStrue
);
1074 struct ifi_info
*i
= intfList
;
1077 if ( ((i
->ifi_addr
->sa_family
== AF_INET
)
1079 || (i
->ifi_addr
->sa_family
== AF_INET6
)
1081 ) && (i
->ifi_flags
& IFF_UP
) && !(i
->ifi_flags
& IFF_POINTOPOINT
) )
1083 if (i
->ifi_flags
& IFF_LOOPBACK
)
1085 if (firstLoopback
== NULL
)
1090 if (SetupOneInterface(m
, i
->ifi_addr
, i
->ifi_netmask
, i
->ifi_name
, i
->ifi_index
) == 0)
1091 if (i
->ifi_addr
->sa_family
== AF_INET
)
1092 foundav4
= mDNStrue
;
1098 // If we found no normal interfaces but we did find a loopback interface, register the
1099 // loopback interface. This allows self-discovery if no interfaces are configured.
1100 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1101 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1102 // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
1103 if ( !foundav4
&& firstLoopback
)
1104 (void) SetupOneInterface(m
, firstLoopback
->ifi_addr
, firstLoopback
->ifi_netmask
, firstLoopback
->ifi_name
, firstLoopback
->ifi_index
);
1108 if (intfList
!= NULL
) free_ifi_info(intfList
);
1114 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1116 // Open a socket that will receive interface change notifications
1117 mDNSlocal mStatus
OpenIfNotifySocket( int *pFD
)
1119 mStatus err
= mStatus_NoError
;
1120 struct sockaddr_nl snl
;
1124 sock
= socket( AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
1128 // Configure read to be non-blocking because inbound msg size is not known in advance
1129 (void) fcntl( sock
, F_SETFL
, O_NONBLOCK
);
1131 /* Subscribe the socket to Link & IP addr notifications. */
1132 bzero( &snl
, sizeof snl
);
1133 snl
.nl_family
= AF_NETLINK
;
1134 snl
.nl_groups
= RTMGRP_LINK
| RTMGRP_IPV4_IFADDR
;
1135 ret
= bind( sock
, (struct sockaddr
*) &snl
, sizeof snl
);
1145 mDNSlocal
void PrintNetLinkMsg( const struct nlmsghdr
*pNLMsg
)
1147 const char *kNLMsgTypes
[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1148 const char *kNLRtMsgTypes
[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1150 printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg
->nlmsg_len
,
1151 pNLMsg
->nlmsg_type
< RTM_BASE
? kNLMsgTypes
[ pNLMsg
->nlmsg_type
] : kNLRtMsgTypes
[ pNLMsg
->nlmsg_type
- RTM_BASE
],
1152 pNLMsg
->nlmsg_flags
);
1154 if ( RTM_NEWLINK
<= pNLMsg
->nlmsg_type
&& pNLMsg
->nlmsg_type
<= RTM_GETLINK
)
1156 struct ifinfomsg
*pIfInfo
= (struct ifinfomsg
*) NLMSG_DATA( pNLMsg
);
1157 printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo
->ifi_family
,
1158 pIfInfo
->ifi_type
, pIfInfo
->ifi_index
, pIfInfo
->ifi_flags
, pIfInfo
->ifi_change
);
1161 else if ( RTM_NEWADDR
<= pNLMsg
->nlmsg_type
&& pNLMsg
->nlmsg_type
<= RTM_GETADDR
)
1163 struct ifaddrmsg
*pIfAddr
= (struct ifaddrmsg
*) NLMSG_DATA( pNLMsg
);
1164 printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr
->ifa_family
,
1165 pIfAddr
->ifa_index
, pIfAddr
->ifa_flags
);
1171 mDNSlocal mDNSu32
ProcessRoutingNotification( int sd
)
1172 // Read through the messages on sd and if any indicate that any interface records should
1173 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1177 struct nlmsghdr
*pNLMsg
= (struct nlmsghdr
*) buff
;
1180 // The structure here is more complex than it really ought to be because,
1181 // unfortunately, there's no good way to size a buffer in advance large
1182 // enough to hold all pending data and so avoid message fragmentation.
1183 // (Note that FIONREAD is not supported on AF_NETLINK.)
1185 readCount
= read( sd
, buff
, sizeof buff
);
1188 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1189 // If not, discard already-processed messages in buffer and read more data.
1190 if ( ( (char*) &pNLMsg
[1] > ( buff
+ readCount
)) || // i.e. *pNLMsg extends off end of buffer
1191 ( (char*) pNLMsg
+ pNLMsg
->nlmsg_len
> ( buff
+ readCount
)))
1193 if ( buff
< (char*) pNLMsg
) // we have space to shuffle
1195 // discard processed data
1196 readCount
-= ( (char*) pNLMsg
- buff
);
1197 memmove( buff
, pNLMsg
, readCount
);
1198 pNLMsg
= (struct nlmsghdr
*) buff
;
1201 readCount
+= read( sd
, buff
+ readCount
, sizeof buff
- readCount
);
1202 continue; // spin around and revalidate with new readCount
1205 break; // Otherwise message does not fit in buffer
1209 PrintNetLinkMsg( pNLMsg
);
1212 // Process the NetLink message
1213 if ( pNLMsg
->nlmsg_type
== RTM_GETLINK
|| pNLMsg
->nlmsg_type
== RTM_NEWLINK
)
1214 result
|= 1 << ((struct ifinfomsg
*) NLMSG_DATA( pNLMsg
))->ifi_index
;
1215 else if ( pNLMsg
->nlmsg_type
== RTM_DELADDR
|| pNLMsg
->nlmsg_type
== RTM_NEWADDR
)
1216 result
|= 1 << ((struct ifaddrmsg
*) NLMSG_DATA( pNLMsg
))->ifa_index
;
1218 // Advance pNLMsg to the next message in the buffer
1219 if ( ( pNLMsg
->nlmsg_flags
& NLM_F_MULTI
) != 0 && pNLMsg
->nlmsg_type
!= NLMSG_DONE
)
1221 ssize_t len
= readCount
- ( (char*)pNLMsg
- buff
);
1222 pNLMsg
= NLMSG_NEXT( pNLMsg
, len
);
1231 #else // USES_NETLINK
1233 // Open a socket that will receive interface change notifications
1234 mDNSlocal mStatus
OpenIfNotifySocket( int *pFD
)
1236 *pFD
= socket( AF_ROUTE
, SOCK_RAW
, 0);
1239 return mStatus_UnknownErr
;
1241 // Configure read to be non-blocking because inbound msg size is not known in advance
1242 (void) fcntl( *pFD
, F_SETFL
, O_NONBLOCK
);
1244 return mStatus_NoError
;
1248 mDNSlocal
void PrintRoutingSocketMsg( const struct ifa_msghdr
*pRSMsg
)
1250 const char *kRSMsgTypes
[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1251 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1252 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1254 int index
= pRSMsg
->ifam_type
== RTM_IFINFO
? ((struct if_msghdr
*) pRSMsg
)->ifm_index
: pRSMsg
->ifam_index
;
1256 printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg
->ifam_msglen
, kRSMsgTypes
[ pRSMsg
->ifam_type
], index
);
1260 mDNSlocal mDNSu32
ProcessRoutingNotification( int sd
)
1261 // Read through the messages on sd and if any indicate that any interface records should
1262 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1266 struct ifa_msghdr
*pRSMsg
= (struct ifa_msghdr
*) buff
;
1269 readCount
= read( sd
, buff
, sizeof buff
);
1270 if ( readCount
< (ssize_t
) sizeof( struct ifa_msghdr
))
1271 return mStatus_UnsupportedErr
; // cannot decipher message
1274 PrintRoutingSocketMsg( pRSMsg
);
1277 // Process the message
1278 if ( pRSMsg
->ifam_type
== RTM_NEWADDR
|| pRSMsg
->ifam_type
== RTM_DELADDR
||
1279 pRSMsg
->ifam_type
== RTM_IFINFO
)
1281 if ( pRSMsg
->ifam_type
== RTM_IFINFO
)
1282 result
|= 1 << ((struct if_msghdr
*) pRSMsg
)->ifm_index
;
1284 result
|= 1 << pRSMsg
->ifam_index
;
1290 #endif // USES_NETLINK
1292 // Called when data appears on interface change notification socket
1293 mDNSlocal
void InterfaceChangeCallback( void *context
)
1295 IfChangeRec
*pChgRec
= (IfChangeRec
*) context
;
1297 mDNSu32 changedInterfaces
= 0;
1298 struct timeval zeroTimeout
= { 0, 0 };
1301 FD_SET( pChgRec
->NotifySD
, &readFDs
);
1305 changedInterfaces
|= ProcessRoutingNotification( pChgRec
->NotifySD
);
1307 while ( 0 < select( pChgRec
->NotifySD
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
));
1309 // Currently we rebuild the entire interface list whenever any interface change is
1310 // detected. If this ever proves to be a performance issue in a multi-homed
1311 // configuration, more care should be paid to changedInterfaces.
1312 if ( changedInterfaces
)
1313 mDNSPlatformPosixRefreshInterfaceList( pChgRec
->mDNS
);
1316 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1317 mDNSlocal mStatus
WatchForInterfaceChange(mDNS
*const m
)
1320 IfChangeRec
*pChgRec
;
1322 pChgRec
= (IfChangeRec
*) mDNSPlatformMemAllocate( sizeof *pChgRec
);
1323 if ( pChgRec
== NULL
)
1324 return mStatus_NoMemoryErr
;
1327 err
= OpenIfNotifySocket( &pChgRec
->NotifySD
);
1329 err
= mDNSPosixAddFDToEventLoop( pChgRec
->NotifySD
, InterfaceChangeCallback
, pChgRec
);
1334 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1335 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1336 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1337 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
1340 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1341 struct sockaddr_in s5353
;
1342 s5353
.sin_family
= AF_INET
;
1343 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1344 s5353
.sin_addr
.s_addr
= 0;
1345 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
1347 if (err
) debugf("No unicast UDP responses");
1348 else debugf("Unicast UDP responses okay");
1352 // mDNS core calls this routine to initialise the platform-specific data.
1353 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1359 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
1361 // Tell mDNS core the names of this machine.
1363 // Set up the nice label
1364 m
->nicelabel
.c
[0] = 0;
1365 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1366 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Computer");
1368 // Set up the RFC 1034-compliant label
1369 m
->hostlabel
.c
[0] = 0;
1370 GetUserSpecifiedRFC1034ComputerName(&m
->hostlabel
);
1371 if (m
->hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->hostlabel
, "Computer");
1375 sa
.sa_family
= AF_INET
;
1376 m
->p
->unicastSocket4
= -1;
1377 if (err
== mStatus_NoError
) err
= SetupSocket(&sa
, zeroIPPort
, 0, &m
->p
->unicastSocket4
);
1379 sa
.sa_family
= AF_INET6
;
1380 m
->p
->unicastSocket6
= -1;
1381 if (err
== mStatus_NoError
) err
= SetupSocket(&sa
, zeroIPPort
, 0, &m
->p
->unicastSocket6
);
1384 // Tell mDNS core about the network interfaces on this machine.
1385 if (err
== mStatus_NoError
) err
= SetupInterfaceList(m
);
1387 // Tell mDNS core about DNS Servers
1388 if (err
== mStatus_NoError
) ParseDNSServers(m
, uDNS_SERVERS_FILE
);
1390 if (err
== mStatus_NoError
)
1392 err
= WatchForInterfaceChange(m
);
1393 // Failure to observe interface changes is non-fatal.
1394 if ( err
!= mStatus_NoError
)
1396 fprintf(stderr
, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err
);
1397 err
= mStatus_NoError
;
1401 // We don't do asynchronous initialization on the Posix platform, so by the time
1402 // we get here the setup will already have succeeded or failed. If it succeeded,
1403 // we should just call mDNSCoreInitComplete() immediately.
1404 if (err
== mStatus_NoError
)
1405 mDNSCoreInitComplete(m
, mStatus_NoError
);
1407 return PosixErrorToStatus(err
);
1410 // mDNS core calls this routine to clean up the platform-specific data.
1411 // In our case all we need to do is to tear down every network interface.
1412 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1415 ClearInterfaceList(m
);
1416 if (m
->p
->unicastSocket4
!= -1) assert(close(m
->p
->unicastSocket4
) == 0);
1418 if (m
->p
->unicastSocket6
!= -1) assert(close(m
->p
->unicastSocket6
) == 0);
1422 mDNSexport mStatus
mDNSPlatformPosixRefreshInterfaceList(mDNS
*const m
)
1425 ClearInterfaceList(m
);
1426 err
= SetupInterfaceList(m
);
1427 return PosixErrorToStatus(err
);
1430 #if COMPILER_LIKES_PRAGMA_MARK
1431 #pragma mark ***** Locking
1434 // On the Posix platform, locking is a no-op because we only ever enter
1435 // mDNS core on the main thread.
1437 // mDNS core calls this routine when it wants to prevent
1438 // the platform from reentering mDNS core code.
1439 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
)
1444 // mDNS core calls this routine when it release the lock taken by
1445 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1446 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
)
1451 #if COMPILER_LIKES_PRAGMA_MARK
1452 #pragma mark ***** Strings
1455 // mDNS core calls this routine to copy C strings.
1456 // On the Posix platform this maps directly to the ANSI C strcpy.
1457 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
)
1459 strcpy((char *)dst
, (char *)src
);
1462 // mDNS core calls this routine to get the length of a C string.
1463 // On the Posix platform this maps directly to the ANSI C strlen.
1464 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
)
1466 return strlen((char*)src
);
1469 // mDNS core calls this routine to copy memory.
1470 // On the Posix platform this maps directly to the ANSI C memcpy.
1471 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
)
1473 memcpy(dst
, src
, len
);
1476 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1477 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1478 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
)
1480 return memcmp(dst
, src
, len
) == 0;
1483 // mDNS core calls this routine to clear blocks of memory.
1484 // On the Posix platform this is a simple wrapper around ANSI C memset.
1485 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
)
1487 memset(dst
, 0, len
);
1490 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(malloc(len
)); }
1491 mDNSexport
void mDNSPlatformMemFree (void *mem
) { free(mem
); }
1493 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
1496 gettimeofday(&tv
, NULL
);
1500 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1024;
1502 mDNSexport mStatus
mDNSPlatformTimeInit(void)
1504 // No special setup is required on Posix -- we just use gettimeofday();
1505 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1506 // We should find a better way to do this
1507 return(mStatus_NoError
);
1510 mDNSexport mDNSs32
mDNSPlatformRawTime()
1513 gettimeofday(&tv
, NULL
);
1514 // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
1515 // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
1516 // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
1517 // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
1518 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1519 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1520 return( (tv
.tv_sec
<< 10) | (tv
.tv_usec
* 16 / 15625) );
1523 mDNSexport mDNSs32
mDNSPlatformUTC(void)
1528 mDNSlocal
void mDNSPosixAddToFDSet(int *nfds
, fd_set
*readfds
, int s
)
1530 if (*nfds
< s
+ 1) *nfds
= s
+ 1;
1534 mDNSexport
void mDNSPosixGetFDSet(mDNS
*m
, int *nfds
, fd_set
*readfds
, struct timeval
*timeout
)
1537 struct timeval interval
;
1539 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1540 mDNSs32 nextevent
= mDNS_Execute(m
);
1542 // 2. Build our list of active file descriptors
1543 PosixNetworkInterface
*info
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
1544 if (m
->p
->unicastSocket4
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, m
->p
->unicastSocket4
);
1546 if (m
->p
->unicastSocket6
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, m
->p
->unicastSocket6
);
1550 if (info
->multicastSocket4
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, info
->multicastSocket4
);
1552 if (info
->multicastSocket6
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, info
->multicastSocket6
);
1554 info
= (PosixNetworkInterface
*)(info
->coreIntf
.next
);
1557 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
1558 ticks
= nextevent
- mDNS_TimeNow(m
);
1559 if (ticks
< 1) ticks
= 1;
1560 interval
.tv_sec
= ticks
>> 10; // The high 22 bits are seconds
1561 interval
.tv_usec
= ((ticks
& 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
1563 // 4. If client's proposed timeout is more than what we want, then reduce it
1564 if (timeout
->tv_sec
> interval
.tv_sec
||
1565 (timeout
->tv_sec
== interval
.tv_sec
&& timeout
->tv_usec
> interval
.tv_usec
))
1566 *timeout
= interval
;
1569 mDNSexport
void mDNSPosixProcessFDSet(mDNS
*const m
, fd_set
*readfds
)
1571 PosixNetworkInterface
*info
;
1573 assert(readfds
!= NULL
);
1574 info
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
1576 if (m
->p
->unicastSocket4
!= -1 && FD_ISSET(m
->p
->unicastSocket4
, readfds
))
1578 FD_CLR(m
->p
->unicastSocket4
, readfds
);
1579 SocketDataReady(m
, NULL
, m
->p
->unicastSocket4
);
1582 if (m
->p
->unicastSocket6
!= -1 && FD_ISSET(m
->p
->unicastSocket6
, readfds
))
1584 FD_CLR(m
->p
->unicastSocket6
, readfds
);
1585 SocketDataReady(m
, NULL
, m
->p
->unicastSocket6
);
1591 if (info
->multicastSocket4
!= -1 && FD_ISSET(info
->multicastSocket4
, readfds
))
1593 FD_CLR(info
->multicastSocket4
, readfds
);
1594 SocketDataReady(m
, info
, info
->multicastSocket4
);
1597 if (info
->multicastSocket6
!= -1 && FD_ISSET(info
->multicastSocket6
, readfds
))
1599 FD_CLR(info
->multicastSocket6
, readfds
);
1600 SocketDataReady(m
, info
, info
->multicastSocket6
);
1603 info
= (PosixNetworkInterface
*)(info
->coreIntf
.next
);
1608 mDNSlocal
void DetermineMaxEventFD( void )
1610 PosixEventSource
*iSource
;
1613 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1614 if ( gMaxFD
< iSource
->fd
)
1615 gMaxFD
= iSource
->fd
;
1618 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
1619 mStatus
mDNSPosixAddFDToEventLoop( int fd
, mDNSPosixEventCallback callback
, void *context
)
1621 PosixEventSource
*newSource
;
1623 if ( gEventSources
.LinkOffset
== 0)
1624 InitLinkedList( &gEventSources
, offsetof( PosixEventSource
, Next
));
1626 if ( fd
>= (int) FD_SETSIZE
|| fd
< 0)
1627 return mStatus_UnsupportedErr
;
1628 if ( callback
== NULL
)
1629 return mStatus_BadParamErr
;
1631 newSource
= (PosixEventSource
*) malloc( sizeof *newSource
);
1632 if ( NULL
== newSource
)
1633 return mStatus_NoMemoryErr
;
1635 newSource
->Callback
= callback
;
1636 newSource
->Context
= context
;
1639 AddToTail( &gEventSources
, newSource
);
1640 FD_SET( fd
, &gEventFDs
);
1642 DetermineMaxEventFD();
1644 return mStatus_NoError
;
1647 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
1648 mStatus
mDNSPosixRemoveFDFromEventLoop( int fd
)
1650 PosixEventSource
*iSource
;
1652 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1654 if ( fd
== iSource
->fd
)
1656 FD_CLR( fd
, &gEventFDs
);
1657 RemoveFromList( &gEventSources
, iSource
);
1659 DetermineMaxEventFD();
1660 return mStatus_NoError
;
1663 return mStatus_NoSuchNameErr
;
1666 // Simply note the received signal in gEventSignals.
1667 mDNSlocal
void NoteSignal( int signum
)
1669 sigaddset( &gEventSignals
, signum
);
1672 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
1673 mStatus
mDNSPosixListenForSignalInEventLoop( int signum
)
1675 struct sigaction action
;
1678 bzero( &action
, sizeof action
); // more portable than member-wise assignment
1679 action
.sa_handler
= NoteSignal
;
1680 err
= sigaction( signum
, &action
, (struct sigaction
*) NULL
);
1682 sigaddset( &gEventSignalSet
, signum
);
1687 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
1688 mStatus
mDNSPosixIgnoreSignalInEventLoop( int signum
)
1690 struct sigaction action
;
1693 bzero( &action
, sizeof action
); // more portable than member-wise assignment
1694 action
.sa_handler
= SIG_DFL
;
1695 err
= sigaction( signum
, &action
, (struct sigaction
*) NULL
);
1697 sigdelset( &gEventSignalSet
, signum
);
1702 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
1703 // Return as soon as internal timeout expires, or a signal we're listening for is received.
1704 mStatus
mDNSPosixRunEventLoopOnce( mDNS
*m
, const struct timeval
*pTimeout
,
1705 sigset_t
*pSignalsReceived
, mDNSBool
*pDataDispatched
)
1707 fd_set listenFDs
= gEventFDs
;
1708 int fdMax
= 0, numReady
;
1709 struct timeval timeout
= *pTimeout
;
1711 // Include the sockets that are listening to the wire in our select() set
1712 mDNSPosixGetFDSet( m
, &fdMax
, &listenFDs
, &timeout
); // timeout may get modified
1713 if ( fdMax
< gMaxFD
)
1716 numReady
= select( fdMax
+ 1, &listenFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
);
1718 // If any data appeared, invoke its callback
1721 PosixEventSource
*iSource
;
1723 (void) mDNSPosixProcessFDSet( m
, &listenFDs
); // call this first to process wire data for clients
1725 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1727 if ( FD_ISSET( iSource
->fd
, &listenFDs
))
1729 iSource
->Callback( iSource
->Context
);
1730 break; // in case callback removed elements from gEventSources
1733 *pDataDispatched
= mDNStrue
;
1736 *pDataDispatched
= mDNSfalse
;
1738 (void) sigprocmask( SIG_BLOCK
, &gEventSignalSet
, (sigset_t
*) NULL
);
1739 *pSignalsReceived
= gEventSignals
;
1740 sigemptyset( &gEventSignals
);
1741 (void) sigprocmask( SIG_UNBLOCK
, &gEventSignalSet
, (sigset_t
*) NULL
);
1743 return mStatus_NoError
;