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.66 2004/12/01 04:27:28 cheshire
41 <rdar://problem/3872803> Darwin patches for Solaris and Suse
42 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
44 Revision 1.65 2004/11/30 22:37:01 cheshire
45 Update copyright dates and add "Mode: C; tab-width: 4" headers
47 Revision 1.64 2004/11/23 03:39:47 cheshire
48 Let interface name/index mapping capability live directly in JNISupport.c,
49 instead of having to call through to the daemon via IPC to get this information.
51 Revision 1.63 2004/11/12 03:16:43 rpantos
52 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
54 Revision 1.62 2004/10/28 03:24:42 cheshire
55 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
57 Revision 1.61 2004/10/16 00:17:01 cheshire
58 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
60 Revision 1.60 2004/09/26 23:20:36 ksekar
61 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
63 Revision 1.59 2004/09/21 21:02:55 cheshire
64 Set up ifname before calling mDNS_RegisterInterface()
66 Revision 1.58 2004/09/17 01:08:54 cheshire
67 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
68 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
69 declared in that file are ONLY appropriate to single-address-space embedded applications.
70 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
72 Revision 1.57 2004/09/17 00:19:11 cheshire
73 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
75 Revision 1.56 2004/09/17 00:15:56 cheshire
76 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
78 Revision 1.55 2004/09/16 00:24:49 cheshire
79 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
81 Revision 1.54 2004/09/15 23:55:00 ksekar
82 <rdar://problem/3800597> mDNSPosix should #include stdint.h
84 Revision 1.53 2004/09/14 23:42:36 cheshire
85 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
87 Revision 1.52 2004/08/25 16:42:13 ksekar
88 Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
91 Revision 1.51 2004/08/14 03:22:42 cheshire
92 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
93 Add GetUserSpecifiedDDNSName() routine
94 Convert ServiceRegDomain to domainname instead of C string
95 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
97 Revision 1.50 2004/08/11 01:20:20 cheshire
98 Declare private local functions using "mDNSlocal"
100 Revision 1.49 2004/07/26 22:49:31 ksekar
101 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
103 Revision 1.48 2004/07/20 01:47:36 rpantos
104 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
106 Revision 1.47 2004/06/25 00:26:27 rpantos
107 Changes to fix the Posix build on Solaris.
109 Revision 1.46 2004/05/13 04:54:20 ksekar
110 Unified list copy/free code. Added symetric list for
112 Revision 1.45 2004/05/12 22:03:09 ksekar
113 Made GetSearchDomainList a true platform-layer call (declaration moved
114 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
115 only on non-OSX platforms. Changed call to return a copy of the list
116 to avoid shared memory issues. Added a routine to free the list.
118 Revision 1.44 2004/04/21 02:49:11 cheshire
119 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
121 Revision 1.43 2004/04/14 23:09:29 ksekar
122 Support for TSIG signed dynamic updates.
124 Revision 1.42 2004/04/09 17:43:04 cheshire
125 Make sure to set the McastTxRx field so that duplicate suppression works correctly
127 Revision 1.41 2004/02/06 01:19:51 cheshire
128 Conditionally exclude IPv6 code unless HAVE_IPV6 is set
130 Revision 1.40 2004/02/05 01:00:01 rpantos
131 Fix some issues that turned up when building for FreeBSD.
133 Revision 1.39 2004/01/28 21:12:15 cheshire
134 Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
136 Revision 1.38 2004/01/27 20:15:23 cheshire
137 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
139 Revision 1.37 2004/01/24 05:12:03 cheshire
140 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
142 Revision 1.36 2004/01/24 04:59:16 cheshire
143 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
145 Revision 1.35 2004/01/23 21:37:08 cheshire
146 For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
148 Revision 1.34 2004/01/22 03:43:09 cheshire
149 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
151 Revision 1.33 2004/01/21 21:54:20 cheshire
152 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
154 Revision 1.32 2004/01/20 01:49:28 rpantos
155 Tweak error handling of last checkin a bit.
157 Revision 1.31 2004/01/20 01:39:27 rpantos
158 Respond to If changes by rebuilding interface list.
160 Revision 1.30 2003/12/11 19:40:36 cheshire
161 Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
163 Revision 1.29 2003/12/11 18:53:22 cheshire
164 Fix compiler warning reported by Paul Guyot
166 Revision 1.28 2003/12/11 03:03:51 rpantos
167 Clean up mDNSPosix so that it builds on OS X again.
169 Revision 1.27 2003/12/08 20:47:02 rpantos
170 Add support for mDNSResponder on Linux.
172 Revision 1.26 2003/11/14 20:59:09 cheshire
173 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
174 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
176 Revision 1.25 2003/10/30 19:25:49 cheshire
177 Fix signed/unsigned warning on certain compilers
179 Revision 1.24 2003/08/18 23:12:23 cheshire
180 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
182 Revision 1.23 2003/08/12 19:56:26 cheshire
185 Revision 1.22 2003/08/06 18:46:15 cheshire
186 LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
188 Revision 1.21 2003/08/06 18:20:51 cheshire
191 Revision 1.20 2003/08/05 23:56:26 cheshire
192 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
193 (Right now mDNSPosix.c just reports 255 -- we should fix this)
195 Revision 1.19 2003/07/19 03:15:16 cheshire
196 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
197 and add the obvious trivial implementations to each platform support layer
199 Revision 1.18 2003/07/14 18:11:54 cheshire
200 Fix stricter compiler warnings
202 Revision 1.17 2003/07/13 01:08:38 cheshire
203 There's not much point running mDNS over a point-to-point link; exclude those
205 Revision 1.16 2003/07/02 21:19:59 cheshire
206 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
208 Revision 1.15 2003/06/18 05:48:41 cheshire
211 Revision 1.14 2003/05/26 03:21:30 cheshire
212 Tidy up address structure naming:
213 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
214 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
215 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
217 Revision 1.13 2003/05/26 03:01:28 cheshire
218 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
220 Revision 1.12 2003/05/21 03:49:18 cheshire
223 Revision 1.11 2003/05/06 00:00:50 cheshire
224 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
226 Revision 1.10 2003/04/25 01:45:57 cheshire
227 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
229 Revision 1.9 2003/03/20 21:10:31 cheshire
230 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
232 Revision 1.8 2003/03/15 04:40:38 cheshire
233 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
235 Revision 1.7 2003/03/13 03:46:21 cheshire
236 Fixes to make the code build on Linux
238 Revision 1.6 2003/03/08 00:35:56 cheshire
239 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
241 Revision 1.5 2002/12/23 22:13:31 jgraessl
242 Reviewed by: Stuart Cheshire
243 Initial IPv6 support for mDNSResponder.
245 Revision 1.4 2002/09/27 01:47:45 cheshire
246 Workaround for Linux 2.0 systems that don't have IP_PKTINFO
248 Revision 1.3 2002/09/21 20:44:53 zarzycki
251 Revision 1.2 2002/09/19 21:25:36 cheshire
252 mDNS_snprintf() doesn't need to be in a separate file
254 Revision 1.1 2002/09/17 06:24:34 cheshire
258 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
259 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
270 #include <sys/types.h>
271 #include <sys/time.h>
272 #include <sys/socket.h>
274 #include <sys/select.h>
275 #include <netinet/in.h>
276 #include <time.h> // platform support for UTC time
279 #include <asm/types.h>
280 #include <linux/netlink.h>
281 #include <linux/rtnetlink.h>
282 #else // USES_NETLINK
283 #include <net/route.h>
285 #endif // USES_NETLINK
288 #include "GenLinkedList.h"
290 // ***************************************************************************
293 // We keep a list of client-supplied event sources in PosixEventSource records
294 struct PosixEventSource
296 mDNSPosixEventCallback Callback
;
299 struct PosixEventSource
*Next
;
301 typedef struct PosixEventSource PosixEventSource
;
303 // Context record for interface change callback
309 typedef struct IfChangeRec IfChangeRec
;
311 // Note that static data is initialized to zero in (modern) C.
312 static fd_set gEventFDs
;
313 static int gMaxFD
; // largest fd in gEventFDs
314 static GenLinkedList gEventSources
; // linked list of PosixEventSource's
315 static sigset_t gEventSignalSet
; // Signals which event loop listens for
316 static sigset_t gEventSignals
; // Signals which were received while inside loop
318 // ***************************************************************************
319 // Globals (for debugging)
321 static int num_registered_interfaces
= 0;
322 static int num_pkts_accepted
= 0;
323 static int num_pkts_rejected
= 0;
325 // ***************************************************************************
328 int gMDNSPlatformPosixVerboseLevel
= 0;
330 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
332 mDNSlocal
void SockAddrTomDNSAddr(const struct sockaddr
*const sa
, mDNSAddr
*ipAddr
, mDNSIPPort
*ipPort
)
334 switch (sa
->sa_family
)
338 struct sockaddr_in
* sin
= (struct sockaddr_in
*)sa
;
339 ipAddr
->type
= mDNSAddrType_IPv4
;
340 ipAddr
->ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
341 if (ipPort
) ipPort
->NotAnInteger
= sin
->sin_port
;
348 struct sockaddr_in6
* sin6
= (struct sockaddr_in6
*)sa
;
349 #ifndef NOT_HAVE_SA_LEN
350 assert(sin6
->sin6_len
== sizeof(*sin6
));
352 ipAddr
->type
= mDNSAddrType_IPv6
;
353 ipAddr
->ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
354 if (ipPort
) ipPort
->NotAnInteger
= sin6
->sin6_port
;
360 verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa
->sa_family
);
361 ipAddr
->type
= mDNSAddrType_None
;
362 if (ipPort
) ipPort
->NotAnInteger
= 0;
367 #if COMPILER_LIKES_PRAGMA_MARK
368 #pragma mark ***** Send and Receive
371 // mDNS core calls this routine when it needs to send a packet.
372 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
373 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
376 struct sockaddr_storage to
;
377 PosixNetworkInterface
* thisIntf
= (PosixNetworkInterface
*)(InterfaceID
);
378 int sendingsocket
= -1;
383 assert( (((char *) end
) - ((char *) msg
)) > 0 );
384 assert(dstPort
.NotAnInteger
!= 0);
386 if (dst
->type
== mDNSAddrType_IPv4
)
388 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&to
;
389 #ifndef NOT_HAVE_SA_LEN
390 sin
->sin_len
= sizeof(*sin
);
392 sin
->sin_family
= AF_INET
;
393 sin
->sin_port
= dstPort
.NotAnInteger
;
394 sin
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
395 sendingsocket
= thisIntf
? thisIntf
->multicastSocket4
: m
->p
->unicastSocket4
;
399 else if (dst
->type
== mDNSAddrType_IPv6
)
401 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&to
;
402 mDNSPlatformMemZero(sin6
, sizeof(*sin6
));
403 #ifndef NOT_HAVE_SA_LEN
404 sin6
->sin6_len
= sizeof(*sin6
);
406 sin6
->sin6_family
= AF_INET6
;
407 sin6
->sin6_port
= dstPort
.NotAnInteger
;
408 sin6
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
409 sendingsocket
= thisIntf
? thisIntf
->multicastSocket6
: m
->p
->unicastSocket6
;
413 if (sendingsocket
>= 0)
414 err
= sendto(sendingsocket
, msg
, (char*)end
- (char*)msg
, 0, (struct sockaddr
*)&to
, GET_SA_LEN(to
));
416 if (err
> 0) err
= 0;
420 verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
421 errno
, strerror(errno
), dst
, &thisIntf
->coreIntf
.ip
, thisIntf
->intfName
, thisIntf
->index
);
423 verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno
, strerror(errno
), dst
);
426 return PosixErrorToStatus(err
);
429 // This routine is called when the main loop detects that data is available on a socket.
430 mDNSlocal
void SocketDataReady(mDNS
*const m
, PosixNetworkInterface
*intf
, int skt
)
432 mDNSAddr senderAddr
, destAddr
;
433 mDNSIPPort senderPort
;
436 struct my_in_pktinfo packetInfo
;
437 struct sockaddr_storage from
;
442 const mDNSInterfaceID InterfaceID
= intf
? intf
->coreIntf
.InterfaceID
: NULL
;
447 fromLen
= sizeof(from
);
449 packetLen
= recvfrom_flags(skt
, &packet
, sizeof(packet
), &flags
, (struct sockaddr
*) &from
, &fromLen
, &packetInfo
, &ttl
);
453 SockAddrTomDNSAddr((struct sockaddr
*)&from
, &senderAddr
, &senderPort
);
454 SockAddrTomDNSAddr((struct sockaddr
*)&packetInfo
.ipi_addr
, &destAddr
, NULL
);
456 // If we have broken IP_RECVDSTADDR functionality (so far
457 // I've only seen this on OpenBSD) then apply a hack to
458 // convince mDNS Core that this isn't a spoof packet.
459 // Basically what we do is check to see whether the
460 // packet arrived as a multicast and, if so, set its
461 // destAddr to the mDNS address.
463 // I must admit that I could just be doing something
464 // wrong on OpenBSD and hence triggering this problem
465 // but I'm at a loss as to how.
467 // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
468 // no way to tell the destination address or interface this packet arrived on,
469 // so all we can do is just assume it's a multicast
471 #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
472 if ( (destAddr
.NotAnInteger
== 0) && (flags
& MSG_MCAST
) )
474 destAddr
.type
= senderAddr
.type
;
475 if (senderAddr
.type
== mDNSAddrType_IPv4
) destAddr
.ip
.v4
= AllDNSLinkGroupv4
;
476 else if (senderAddr
.type
== mDNSAddrType_IPv6
) destAddr
.ip
.v6
= AllDNSLinkGroupv6
;
480 // We only accept the packet if the interface on which it came
481 // in matches the interface associated with this socket.
482 // We do this match by name or by index, depending on which
483 // information is available. recvfrom_flags sets the name
484 // to "" if the name isn't available, or the index to -1
485 // if the index is available. This accomodates the various
486 // different capabilities of our target platforms.
491 if ( packetInfo
.ipi_ifname
[0] != 0 ) reject
= (strcmp(packetInfo
.ipi_ifname
, intf
->intfName
) != 0);
492 else if ( packetInfo
.ipi_ifindex
!= -1 ) reject
= (packetInfo
.ipi_ifindex
!= intf
->index
);
496 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d",
497 &senderAddr
, &destAddr
, packetInfo
.ipi_ifname
, packetInfo
.ipi_ifindex
,
498 &intf
->coreIntf
.ip
, intf
->intfName
, intf
->index
);
501 if (num_pkts_rejected
> (num_pkts_accepted
+ 1) * (num_registered_interfaces
+ 1) * 2)
504 "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
505 num_pkts_accepted
+ num_pkts_rejected
, num_pkts_accepted
, num_pkts_rejected
);
506 num_pkts_accepted
= 0;
507 num_pkts_rejected
= 0;
512 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d",
513 &senderAddr
, &destAddr
, &intf
->coreIntf
.ip
, intf
->intfName
, intf
->index
);
520 mDNSCoreReceive(m
, &packet
, (mDNSu8
*)&packet
+ packetLen
,
521 &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, InterfaceID
);
524 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
525 TCPConnectionCallback callback
, void *context
, int *descriptor
)
528 (void)dstport
; // Unused
529 (void)InterfaceID
; // Unused
530 (void)callback
; // Unused
531 (void)context
; // Unused
532 (void)descriptor
; // Unused
533 return(mStatus_UnsupportedErr
);
536 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
541 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
545 (void)buflen
; // Unused
549 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
557 #if COMPILER_LIKES_PRAGMA_MARK
558 #pragma mark ***** Get/Free Search Domain List
561 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
563 static DNameListElem tmp
;
564 static mDNSBool init
= mDNSfalse
;
568 MakeDomainNameFromDNSNameString(&tmp
.name
, "local.");
572 return mDNS_CopyDNameList(&tmp
);
575 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
580 #if COMPILER_LIKES_PRAGMA_MARK
581 #pragma mark ***** Init and Term
584 // This gets the current hostname, truncating it at the first dot if necessary
585 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
588 gethostname((char *)(&namelabel
->c
[1]), MAX_DOMAIN_LABEL
);
589 while (len
< MAX_DOMAIN_LABEL
&& namelabel
->c
[len
+1] && namelabel
->c
[len
+1] != '.') len
++;
590 namelabel
->c
[0] = len
;
593 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
594 // Other platforms can either get the information from the appropriate place,
595 // or they can alternatively just require all registering services to provide an explicit name
596 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
598 // On Unix we have no better name than the host name, so we just use that.
599 GetUserSpecifiedRFC1034ComputerName( namelabel
);
602 // Searches the interface list looking for the named interface.
603 // Returns a pointer to if it found, or NULL otherwise.
604 mDNSlocal PosixNetworkInterface
*SearchForInterfaceByName(mDNS
*const m
, const char *intfName
)
606 PosixNetworkInterface
*intf
;
609 assert(intfName
!= NULL
);
611 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
612 while ( (intf
!= NULL
) && (strcmp(intf
->intfName
, intfName
) != 0) )
613 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
618 extern mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
620 PosixNetworkInterface
*intf
;
624 if (index
== (mDNSu32
)~0) return(mDNSInterface_LocalOnly
);
626 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
627 while ( (intf
!= NULL
) && (mDNSu32
) intf
->index
!= index
)
628 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
630 return (mDNSInterfaceID
) intf
;
633 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
635 PosixNetworkInterface
*intf
;
639 if (id
== mDNSInterface_LocalOnly
) return((mDNSu32
)~0);
641 intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
642 while ( (intf
!= NULL
) && (mDNSInterfaceID
) intf
!= id
)
643 intf
= (PosixNetworkInterface
*)(intf
->coreIntf
.next
);
645 return intf
? intf
->index
: 0;
648 // Frees the specified PosixNetworkInterface structure. The underlying
649 // interface must have already been deregistered with the mDNS core.
650 mDNSlocal
void FreePosixNetworkInterface(PosixNetworkInterface
*intf
)
652 assert(intf
!= NULL
);
653 if (intf
->intfName
!= NULL
) free((void *)intf
->intfName
);
654 if (intf
->multicastSocket4
!= -1) assert(close(intf
->multicastSocket4
) == 0);
656 if (intf
->multicastSocket6
!= -1) assert(close(intf
->multicastSocket6
) == 0);
661 // Grab the first interface, deregister it, free it, and repeat until done.
662 mDNSlocal
void ClearInterfaceList(mDNS
*const m
)
666 while (m
->HostInterfaces
)
668 PosixNetworkInterface
*intf
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
669 mDNS_DeregisterInterface(m
, &intf
->coreIntf
);
670 if (gMDNSPlatformPosixVerboseLevel
> 0) fprintf(stderr
, "Deregistered interface %s\n", intf
->intfName
);
671 FreePosixNetworkInterface(intf
);
673 num_registered_interfaces
= 0;
674 num_pkts_accepted
= 0;
675 num_pkts_rejected
= 0;
678 // Sets up a send/receive socket.
679 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
680 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
681 mDNSlocal
int SetupSocket(struct sockaddr
*intfAddr
, mDNSIPPort port
, int interfaceIndex
, int *sktPtr
)
684 static const int kOn
= 1;
685 static const int kIntTwoFiveFive
= 255;
686 static const unsigned char kByteTwoFiveFive
= 255;
688 (void) interfaceIndex
; // This parameter unused on plaforms that don't have IPv6
689 assert(intfAddr
!= NULL
);
690 assert(sktPtr
!= NULL
);
691 assert(*sktPtr
== -1);
693 // Open the socket...
694 if (intfAddr
->sa_family
== AF_INET
) *sktPtr
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
696 else if (intfAddr
->sa_family
== AF_INET6
) *sktPtr
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
700 if (*sktPtr
< 0) { err
= errno
; perror("socket"); }
702 // ... with a shared UDP port, if it's for multicast receiving
703 if (err
== 0 && port
.NotAnInteger
)
705 #if defined(SO_REUSEPORT)
706 err
= setsockopt(*sktPtr
, SOL_SOCKET
, SO_REUSEPORT
, &kOn
, sizeof(kOn
));
707 #elif defined(SO_REUSEADDR)
708 err
= setsockopt(*sktPtr
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
710 #error This platform has no way to avoid address busy errors on multicast.
712 if (err
< 0) { err
= errno
; perror("setsockopt - SO_REUSExxxx"); }
715 // We want to receive destination addresses and interface identifiers.
716 if (intfAddr
->sa_family
== AF_INET
)
719 struct sockaddr_in bindAddr
;
722 #if defined(IP_PKTINFO) // Linux
723 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_PKTINFO
, &kOn
, sizeof(kOn
));
724 if (err
< 0) { err
= errno
; perror("setsockopt - IP_PKTINFO"); }
725 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
726 #if defined(IP_RECVDSTADDR)
727 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVDSTADDR
, &kOn
, sizeof(kOn
));
728 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVDSTADDR"); }
730 #if defined(IP_RECVIF)
733 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVIF
, &kOn
, sizeof(kOn
));
734 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVIF"); }
738 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
741 #if defined(IP_RECVTTL) // Linux
744 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_RECVTTL
, &kOn
, sizeof(kOn
));
745 if (err
< 0) { err
= errno
; perror("setsockopt - IP_RECVTTL"); }
749 // Add multicast group membership on this interface
750 if (err
== 0 && port
.NotAnInteger
)
752 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
753 imr
.imr_interface
= ((struct sockaddr_in
*)intfAddr
)->sin_addr
;
754 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
755 if (err
< 0) { err
= errno
; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
758 // Specify outgoing interface too
759 if (err
== 0 && port
.NotAnInteger
)
761 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_IF
, &((struct sockaddr_in
*)intfAddr
)->sin_addr
, sizeof(struct in_addr
));
762 if (err
< 0) { err
= errno
; perror("setsockopt - IP_MULTICAST_IF"); }
765 // Per the mDNS spec, send unicast packets with TTL 255
768 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_TTL
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
769 if (err
< 0) { err
= errno
; perror("setsockopt - IP_TTL"); }
772 // and multicast packets with TTL 255 too
773 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
776 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_TTL
, &kByteTwoFiveFive
, sizeof(kByteTwoFiveFive
));
777 if (err
< 0 && errno
== EINVAL
)
778 err
= setsockopt(*sktPtr
, IPPROTO_IP
, IP_MULTICAST_TTL
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
779 if (err
< 0) { err
= errno
; perror("setsockopt - IP_MULTICAST_TTL"); }
782 // And start listening for packets
785 bindAddr
.sin_family
= AF_INET
;
786 bindAddr
.sin_port
= port
.NotAnInteger
;
787 bindAddr
.sin_addr
.s_addr
= INADDR_ANY
; // Want to receive multicasts AND unicasts on this socket
788 err
= bind(*sktPtr
, (struct sockaddr
*) &bindAddr
, sizeof(bindAddr
));
789 if (err
< 0) { err
= errno
; perror("bind"); fflush(stderr
); }
791 } // endif (intfAddr->sa_family == AF_INET)
794 else if (intfAddr
->sa_family
== AF_INET6
)
796 struct ipv6_mreq imr6
;
797 struct sockaddr_in6 bindAddr6
;
798 #if defined(IPV6_PKTINFO)
801 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_PKTINFO
, &kOn
, sizeof(kOn
));
802 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_PKTINFO"); }
805 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
807 #if defined(IPV6_HOPLIMIT)
810 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &kOn
, sizeof(kOn
));
811 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_HOPLIMIT"); }
815 // Add multicast group membership on this interface
816 if (err
== 0 && port
.NotAnInteger
)
818 imr6
.ipv6mr_multiaddr
= *(const struct in6_addr
*)&AllDNSLinkGroupv6
;
819 imr6
.ipv6mr_interface
= interfaceIndex
;
820 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &imr6
, sizeof(imr6
));
824 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6
.ipv6mr_multiaddr
, imr6
.ipv6mr_interface
);
825 perror("setsockopt - IPV6_JOIN_GROUP");
829 // Specify outgoing interface too
830 if (err
== 0 && port
.NotAnInteger
)
832 u_int multicast_if
= interfaceIndex
;
833 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &multicast_if
, sizeof(multicast_if
));
834 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_MULTICAST_IF"); }
837 // We want to receive only IPv6 packets on this socket.
838 // Without this option, we may get IPv4 addresses as mapped addresses.
841 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_V6ONLY
, &kOn
, sizeof(kOn
));
842 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_V6ONLY"); }
845 // Per the mDNS spec, send unicast packets with TTL 255
848 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
849 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_UNICAST_HOPS"); }
852 // and multicast packets with TTL 255 too
853 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
856 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &kByteTwoFiveFive
, sizeof(kByteTwoFiveFive
));
857 if (err
< 0 && errno
== EINVAL
)
858 err
= setsockopt(*sktPtr
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &kIntTwoFiveFive
, sizeof(kIntTwoFiveFive
));
859 if (err
< 0) { err
= errno
; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
862 // And start listening for packets
865 mDNSPlatformMemZero(&bindAddr6
, sizeof(bindAddr6
));
866 #ifndef NOT_HAVE_SA_LEN
867 bindAddr6
.sin6_len
= sizeof(bindAddr6
);
869 bindAddr6
.sin6_family
= AF_INET6
;
870 bindAddr6
.sin6_port
= port
.NotAnInteger
;
871 bindAddr6
.sin6_flowinfo
= 0;
872 // bindAddr6.sin6_addr.s_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
873 bindAddr6
.sin6_scope_id
= 0;
874 err
= bind(*sktPtr
, (struct sockaddr
*) &bindAddr6
, sizeof(bindAddr6
));
875 if (err
< 0) { err
= errno
; perror("bind"); fflush(stderr
); }
877 } // endif (intfAddr->sa_family == AF_INET6)
880 // Set the socket to non-blocking.
883 err
= fcntl(*sktPtr
, F_GETFL
, 0);
884 if (err
< 0) err
= errno
;
887 err
= fcntl(*sktPtr
, F_SETFL
, err
| O_NONBLOCK
);
888 if (err
< 0) err
= errno
;
893 if (err
!= 0 && *sktPtr
!= -1) { assert(close(*sktPtr
) == 0); *sktPtr
= -1; }
894 assert( (err
== 0) == (*sktPtr
!= -1) );
898 // Creates a PosixNetworkInterface for the interface whose IP address is
899 // intfAddr and whose name is intfName and registers it with mDNS core.
900 mDNSlocal
int SetupOneInterface(mDNS
*const m
, struct sockaddr
*intfAddr
, struct sockaddr
*intfMask
, const char *intfName
, int intfIndex
)
903 PosixNetworkInterface
*intf
;
904 PosixNetworkInterface
*alias
= NULL
;
907 assert(intfAddr
!= NULL
);
908 assert(intfName
!= NULL
);
909 assert(intfMask
!= NULL
);
911 // Allocate the interface structure itself.
912 intf
= (PosixNetworkInterface
*)malloc(sizeof(*intf
));
913 if (intf
== NULL
) { assert(0); err
= ENOMEM
; }
915 // And make a copy of the intfName.
918 intf
->intfName
= strdup(intfName
);
919 if (intf
->intfName
== NULL
) { assert(0); err
= ENOMEM
; }
924 // Set up the fields required by the mDNS core.
925 SockAddrTomDNSAddr(intfAddr
, &intf
->coreIntf
.ip
, NULL
);
926 SockAddrTomDNSAddr(intfMask
, &intf
->coreIntf
.mask
, NULL
);
927 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
928 strncpy(intf
->coreIntf
.ifname
, intfName
, sizeof(intf
->coreIntf
.ifname
));
929 intf
->coreIntf
.ifname
[sizeof(intf
->coreIntf
.ifname
)-1] = 0;
930 intf
->coreIntf
.Advertise
= m
->AdvertiseLocalAddresses
;
931 intf
->coreIntf
.McastTxRx
= mDNStrue
;
933 // Set up the extra fields in PosixNetworkInterface.
934 assert(intf
->intfName
!= NULL
); // intf->intfName already set up above
935 intf
->index
= intfIndex
;
936 intf
->multicastSocket4
= -1;
938 intf
->multicastSocket6
= -1;
940 alias
= SearchForInterfaceByName(m
, intf
->intfName
);
941 if (alias
== NULL
) alias
= intf
;
942 intf
->coreIntf
.InterfaceID
= (mDNSInterfaceID
)alias
;
945 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName
, &intf
->coreIntf
.ip
, &alias
->coreIntf
.ip
);
948 // Set up the multicast socket
951 if (alias
->multicastSocket4
== -1 && intfAddr
->sa_family
== AF_INET
)
952 err
= SetupSocket(intfAddr
, MulticastDNSPort
, intf
->index
, &alias
->multicastSocket4
);
954 else if (alias
->multicastSocket6
== -1 && intfAddr
->sa_family
== AF_INET6
)
955 err
= SetupSocket(intfAddr
, MulticastDNSPort
, intf
->index
, &alias
->multicastSocket6
);
959 // The interface is all ready to go, let's register it with the mDNS core.
961 err
= mDNS_RegisterInterface(m
, &intf
->coreIntf
);
966 num_registered_interfaces
++;
967 debugf("SetupOneInterface: %s %#a Registered", intf
->intfName
, &intf
->coreIntf
.ip
);
968 if (gMDNSPlatformPosixVerboseLevel
> 0)
969 fprintf(stderr
, "Registered interface %s\n", intf
->intfName
);
973 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
974 debugf("SetupOneInterface: %s %#a failed to register %d", intfName
, &intf
->coreIntf
.ip
, err
);
975 if (intf
) { FreePosixNetworkInterface(intf
); intf
= NULL
; }
978 assert( (err
== 0) == (intf
!= NULL
) );
983 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
984 mDNSlocal
int SetupInterfaceList(mDNS
*const m
)
986 mDNSBool foundav4
= mDNSfalse
;
988 struct ifi_info
*intfList
= get_ifi_info(AF_INET
, mDNStrue
);
989 struct ifi_info
*firstLoopback
= NULL
;
992 debugf("SetupInterfaceList");
994 if (intfList
== NULL
) err
= ENOENT
;
997 if (err
== 0) /* Link the IPv6 list to the end of the IPv4 list */
999 struct ifi_info
**p
= &intfList
;
1000 while (*p
) p
= &(*p
)->ifi_next
;
1001 *p
= get_ifi_info(AF_INET6
, mDNStrue
);
1007 struct ifi_info
*i
= intfList
;
1010 if ( ((i
->ifi_addr
->sa_family
== AF_INET
)
1012 || (i
->ifi_addr
->sa_family
== AF_INET6
)
1014 ) && (i
->ifi_flags
& IFF_UP
) && !(i
->ifi_flags
& IFF_POINTOPOINT
) )
1016 if (i
->ifi_flags
& IFF_LOOPBACK
)
1018 if (firstLoopback
== NULL
)
1023 if (SetupOneInterface(m
, i
->ifi_addr
, i
->ifi_netmask
, i
->ifi_name
, i
->ifi_index
) == 0)
1024 if (i
->ifi_addr
->sa_family
== AF_INET
)
1025 foundav4
= mDNStrue
;
1031 // If we found no normal interfaces but we did find a loopback interface, register the
1032 // loopback interface. This allows self-discovery if no interfaces are configured.
1033 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1034 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1035 // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
1036 if ( !foundav4
&& firstLoopback
)
1037 (void) SetupOneInterface(m
, firstLoopback
->ifi_addr
, firstLoopback
->ifi_netmask
, firstLoopback
->ifi_name
, firstLoopback
->ifi_index
);
1041 if (intfList
!= NULL
) free_ifi_info(intfList
);
1047 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1049 // Open a socket that will receive interface change notifications
1050 mDNSlocal mStatus
OpenIfNotifySocket( int *pFD
)
1052 mStatus err
= mStatus_NoError
;
1053 struct sockaddr_nl snl
;
1057 sock
= socket( AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
1061 // Configure read to be non-blocking because inbound msg size is not known in advance
1062 (void) fcntl( sock
, F_SETFL
, O_NONBLOCK
);
1064 /* Subscribe the socket to Link & IP addr notifications. */
1065 bzero( &snl
, sizeof snl
);
1066 snl
.nl_family
= AF_NETLINK
;
1067 snl
.nl_groups
= RTMGRP_LINK
| RTMGRP_IPV4_IFADDR
;
1068 ret
= bind( sock
, (struct sockaddr
*) &snl
, sizeof snl
);
1078 mDNSlocal
void PrintNetLinkMsg( const struct nlmsghdr
*pNLMsg
)
1080 const char *kNLMsgTypes
[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1081 const char *kNLRtMsgTypes
[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1083 printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg
->nlmsg_len
,
1084 pNLMsg
->nlmsg_type
< RTM_BASE
? kNLMsgTypes
[ pNLMsg
->nlmsg_type
] : kNLRtMsgTypes
[ pNLMsg
->nlmsg_type
- RTM_BASE
],
1085 pNLMsg
->nlmsg_flags
);
1087 if ( RTM_NEWLINK
<= pNLMsg
->nlmsg_type
&& pNLMsg
->nlmsg_type
<= RTM_GETLINK
)
1089 struct ifinfomsg
*pIfInfo
= (struct ifinfomsg
*) NLMSG_DATA( pNLMsg
);
1090 printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo
->ifi_family
,
1091 pIfInfo
->ifi_type
, pIfInfo
->ifi_index
, pIfInfo
->ifi_flags
, pIfInfo
->ifi_change
);
1094 else if ( RTM_NEWADDR
<= pNLMsg
->nlmsg_type
&& pNLMsg
->nlmsg_type
<= RTM_GETADDR
)
1096 struct ifaddrmsg
*pIfAddr
= (struct ifaddrmsg
*) NLMSG_DATA( pNLMsg
);
1097 printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr
->ifa_family
,
1098 pIfAddr
->ifa_index
, pIfAddr
->ifa_flags
);
1104 mDNSlocal mDNSu32
ProcessRoutingNotification( int sd
)
1105 // Read through the messages on sd and if any indicate that any interface records should
1106 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1110 struct nlmsghdr
*pNLMsg
= (struct nlmsghdr
*) buff
;
1113 // The structure here is more complex than it really ought to be because,
1114 // unfortunately, there's no good way to size a buffer in advance large
1115 // enough to hold all pending data and so avoid message fragmentation.
1116 // (Note that FIONREAD is not supported on AF_NETLINK.)
1118 readCount
= read( sd
, buff
, sizeof buff
);
1121 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1122 // If not, discard already-processed messages in buffer and read more data.
1123 if ( ( (char*) &pNLMsg
[1] > ( buff
+ readCount
)) || // i.e. *pNLMsg extends off end of buffer
1124 ( (char*) pNLMsg
+ pNLMsg
->nlmsg_len
> ( buff
+ readCount
)))
1126 if ( buff
< (char*) pNLMsg
) // we have space to shuffle
1128 // discard processed data
1129 readCount
-= ( (char*) pNLMsg
- buff
);
1130 memmove( buff
, pNLMsg
, readCount
);
1131 pNLMsg
= (struct nlmsghdr
*) buff
;
1134 readCount
+= read( sd
, buff
+ readCount
, sizeof buff
- readCount
);
1135 continue; // spin around and revalidate with new readCount
1138 break; // Otherwise message does not fit in buffer
1142 PrintNetLinkMsg( pNLMsg
);
1145 // Process the NetLink message
1146 if ( pNLMsg
->nlmsg_type
== RTM_GETLINK
|| pNLMsg
->nlmsg_type
== RTM_NEWLINK
)
1147 result
|= 1 << ((struct ifinfomsg
*) NLMSG_DATA( pNLMsg
))->ifi_index
;
1148 else if ( pNLMsg
->nlmsg_type
== RTM_DELADDR
|| pNLMsg
->nlmsg_type
== RTM_NEWADDR
)
1149 result
|= 1 << ((struct ifaddrmsg
*) NLMSG_DATA( pNLMsg
))->ifa_index
;
1151 // Advance pNLMsg to the next message in the buffer
1152 if ( ( pNLMsg
->nlmsg_flags
& NLM_F_MULTI
) != 0 && pNLMsg
->nlmsg_type
!= NLMSG_DONE
)
1154 ssize_t len
= readCount
- ( (char*)pNLMsg
- buff
);
1155 pNLMsg
= NLMSG_NEXT( pNLMsg
, len
);
1164 #else // USES_NETLINK
1166 // Open a socket that will receive interface change notifications
1167 mDNSlocal mStatus
OpenIfNotifySocket( int *pFD
)
1169 *pFD
= socket( AF_ROUTE
, SOCK_RAW
, 0);
1172 return mStatus_UnknownErr
;
1174 // Configure read to be non-blocking because inbound msg size is not known in advance
1175 (void) fcntl( *pFD
, F_SETFL
, O_NONBLOCK
);
1177 return mStatus_NoError
;
1181 mDNSlocal
void PrintRoutingSocketMsg( const struct ifa_msghdr
*pRSMsg
)
1183 const char *kRSMsgTypes
[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1184 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1185 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1187 int index
= pRSMsg
->ifam_type
== RTM_IFINFO
? ((struct if_msghdr
*) pRSMsg
)->ifm_index
: pRSMsg
->ifam_index
;
1189 printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg
->ifam_msglen
, kRSMsgTypes
[ pRSMsg
->ifam_type
], index
);
1193 mDNSlocal mDNSu32
ProcessRoutingNotification( int sd
)
1194 // Read through the messages on sd and if any indicate that any interface records should
1195 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1199 struct ifa_msghdr
*pRSMsg
= (struct ifa_msghdr
*) buff
;
1202 readCount
= read( sd
, buff
, sizeof buff
);
1203 if ( readCount
< (ssize_t
) sizeof( struct ifa_msghdr
))
1204 return mStatus_UnsupportedErr
; // cannot decipher message
1207 PrintRoutingSocketMsg( pRSMsg
);
1210 // Process the message
1211 if ( pRSMsg
->ifam_type
== RTM_NEWADDR
|| pRSMsg
->ifam_type
== RTM_DELADDR
||
1212 pRSMsg
->ifam_type
== RTM_IFINFO
)
1214 if ( pRSMsg
->ifam_type
== RTM_IFINFO
)
1215 result
|= 1 << ((struct if_msghdr
*) pRSMsg
)->ifm_index
;
1217 result
|= 1 << pRSMsg
->ifam_index
;
1223 #endif // USES_NETLINK
1225 // Called when data appears on interface change notification socket
1226 mDNSlocal
void InterfaceChangeCallback( void *context
)
1228 IfChangeRec
*pChgRec
= (IfChangeRec
*) context
;
1230 mDNSu32 changedInterfaces
= 0;
1231 struct timeval zeroTimeout
= { 0, 0 };
1234 FD_SET( pChgRec
->NotifySD
, &readFDs
);
1238 changedInterfaces
|= ProcessRoutingNotification( pChgRec
->NotifySD
);
1240 while ( 0 < select( pChgRec
->NotifySD
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
));
1242 // Currently we rebuild the entire interface list whenever any interface change is
1243 // detected. If this ever proves to be a performance issue in a multi-homed
1244 // configuration, more care should be paid to changedInterfaces.
1245 if ( changedInterfaces
)
1246 mDNSPlatformPosixRefreshInterfaceList( pChgRec
->mDNS
);
1249 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
1250 mDNSlocal mStatus
WatchForInterfaceChange(mDNS
*const m
)
1253 IfChangeRec
*pChgRec
;
1255 pChgRec
= (IfChangeRec
*) mDNSPlatformMemAllocate( sizeof *pChgRec
);
1256 if ( pChgRec
== NULL
)
1257 return mStatus_NoMemoryErr
;
1260 err
= OpenIfNotifySocket( &pChgRec
->NotifySD
);
1262 err
= mDNSPosixAddFDToEventLoop( pChgRec
->NotifySD
, InterfaceChangeCallback
, pChgRec
);
1267 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1268 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1269 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
1270 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
1273 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1274 struct sockaddr_in s5353
;
1275 s5353
.sin_family
= AF_INET
;
1276 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1277 s5353
.sin_addr
.s_addr
= 0;
1278 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
1280 if (err
) debugf("No unicast UDP responses");
1281 else debugf("Unicast UDP responses okay");
1285 // mDNS core calls this routine to initialise the platform-specific data.
1286 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1292 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
1294 // Tell mDNS core the names of this machine.
1296 // Set up the nice label
1297 m
->nicelabel
.c
[0] = 0;
1298 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1299 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
1301 // Set up the RFC 1034-compliant label
1302 m
->hostlabel
.c
[0] = 0;
1303 GetUserSpecifiedRFC1034ComputerName(&m
->hostlabel
);
1304 if (m
->hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->hostlabel
, "Macintosh");
1308 sa
.sa_family
= AF_INET
;
1309 m
->p
->unicastSocket4
= -1;
1310 if (err
== mStatus_NoError
) err
= SetupSocket(&sa
, zeroIPPort
, 0, &m
->p
->unicastSocket4
);
1312 sa
.sa_family
= AF_INET6
;
1313 m
->p
->unicastSocket6
= -1;
1314 if (err
== mStatus_NoError
) err
= SetupSocket(&sa
, zeroIPPort
, 0, &m
->p
->unicastSocket6
);
1317 // Tell mDNS core about the network interfaces on this machine.
1318 if (err
== mStatus_NoError
) err
= SetupInterfaceList(m
);
1320 if (err
== mStatus_NoError
)
1322 err
= WatchForInterfaceChange(m
);
1323 // Failure to observe interface changes is non-fatal.
1324 if ( err
!= mStatus_NoError
)
1326 fprintf(stderr
, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err
);
1327 err
= mStatus_NoError
;
1331 // We don't do asynchronous initialization on the Posix platform, so by the time
1332 // we get here the setup will already have succeeded or failed. If it succeeded,
1333 // we should just call mDNSCoreInitComplete() immediately.
1334 if (err
== mStatus_NoError
)
1335 mDNSCoreInitComplete(m
, mStatus_NoError
);
1337 return PosixErrorToStatus(err
);
1340 // mDNS core calls this routine to clean up the platform-specific data.
1341 // In our case all we need to do is to tear down every network interface.
1342 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1345 ClearInterfaceList(m
);
1346 if (m
->p
->unicastSocket4
!= -1) assert(close(m
->p
->unicastSocket4
) == 0);
1348 if (m
->p
->unicastSocket6
!= -1) assert(close(m
->p
->unicastSocket6
) == 0);
1352 extern mStatus
mDNSPlatformPosixRefreshInterfaceList(mDNS
*const m
)
1355 ClearInterfaceList(m
);
1356 err
= SetupInterfaceList(m
);
1357 return PosixErrorToStatus(err
);
1360 #if COMPILER_LIKES_PRAGMA_MARK
1361 #pragma mark ***** Locking
1364 // On the Posix platform, locking is a no-op because we only ever enter
1365 // mDNS core on the main thread.
1367 // mDNS core calls this routine when it wants to prevent
1368 // the platform from reentering mDNS core code.
1369 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
)
1374 // mDNS core calls this routine when it release the lock taken by
1375 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
1376 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
)
1381 #if COMPILER_LIKES_PRAGMA_MARK
1382 #pragma mark ***** Strings
1385 // mDNS core calls this routine to copy C strings.
1386 // On the Posix platform this maps directly to the ANSI C strcpy.
1387 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
)
1389 strcpy((char *)dst
, (char *)src
);
1392 // mDNS core calls this routine to get the length of a C string.
1393 // On the Posix platform this maps directly to the ANSI C strlen.
1394 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
)
1396 return strlen((char*)src
);
1399 // mDNS core calls this routine to copy memory.
1400 // On the Posix platform this maps directly to the ANSI C memcpy.
1401 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
)
1403 memcpy(dst
, src
, len
);
1406 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1407 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
1408 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
)
1410 return memcmp(dst
, src
, len
) == 0;
1413 // mDNS core calls this routine to clear blocks of memory.
1414 // On the Posix platform this is a simple wrapper around ANSI C memset.
1415 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
)
1417 memset(dst
, 0, len
);
1420 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(malloc(len
)); }
1421 mDNSexport
void mDNSPlatformMemFree (void *mem
) { free(mem
); }
1423 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
1426 gettimeofday(&tv
, NULL
);
1430 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1024;
1432 mDNSexport mStatus
mDNSPlatformTimeInit(void)
1434 // No special setup is required on Posix -- we just use gettimeofday();
1435 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1436 // We should find a better way to do this
1437 return(mStatus_NoError
);
1440 mDNSexport mDNSs32
mDNSPlatformRawTime()
1443 gettimeofday(&tv
, NULL
);
1444 // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
1445 // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
1446 // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
1447 // 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.
1448 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1449 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1450 return( (tv
.tv_sec
<< 10) | (tv
.tv_usec
* 16 / 15625) );
1453 mDNSexport mDNSs32
mDNSPlatformUTC(void)
1458 mDNSlocal
void mDNSPosixAddToFDSet(int *nfds
, fd_set
*readfds
, int s
)
1460 if (*nfds
< s
+ 1) *nfds
= s
+ 1;
1464 mDNSexport
void mDNSPosixGetFDSet(mDNS
*m
, int *nfds
, fd_set
*readfds
, struct timeval
*timeout
)
1467 struct timeval interval
;
1469 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1470 mDNSs32 nextevent
= mDNS_Execute(m
);
1472 // 2. Build our list of active file descriptors
1473 PosixNetworkInterface
*info
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
1474 if (m
->p
->unicastSocket4
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, m
->p
->unicastSocket4
);
1476 if (m
->p
->unicastSocket6
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, m
->p
->unicastSocket6
);
1480 if (info
->multicastSocket4
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, info
->multicastSocket4
);
1482 if (info
->multicastSocket6
!= -1) mDNSPosixAddToFDSet(nfds
, readfds
, info
->multicastSocket6
);
1484 info
= (PosixNetworkInterface
*)(info
->coreIntf
.next
);
1487 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
1488 ticks
= nextevent
- mDNS_TimeNow(m
);
1489 if (ticks
< 1) ticks
= 1;
1490 interval
.tv_sec
= ticks
>> 10; // The high 22 bits are seconds
1491 interval
.tv_usec
= ((ticks
& 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
1493 // 4. If client's proposed timeout is more than what we want, then reduce it
1494 if (timeout
->tv_sec
> interval
.tv_sec
||
1495 (timeout
->tv_sec
== interval
.tv_sec
&& timeout
->tv_usec
> interval
.tv_usec
))
1496 *timeout
= interval
;
1499 mDNSexport
void mDNSPosixProcessFDSet(mDNS
*const m
, fd_set
*readfds
)
1501 PosixNetworkInterface
*info
;
1503 assert(readfds
!= NULL
);
1504 info
= (PosixNetworkInterface
*)(m
->HostInterfaces
);
1506 if (m
->p
->unicastSocket4
!= -1 && FD_ISSET(m
->p
->unicastSocket4
, readfds
))
1508 FD_CLR(m
->p
->unicastSocket4
, readfds
);
1509 SocketDataReady(m
, NULL
, m
->p
->unicastSocket4
);
1512 if (m
->p
->unicastSocket6
!= -1 && FD_ISSET(m
->p
->unicastSocket6
, readfds
))
1514 FD_CLR(m
->p
->unicastSocket6
, readfds
);
1515 SocketDataReady(m
, NULL
, m
->p
->unicastSocket6
);
1521 if (info
->multicastSocket4
!= -1 && FD_ISSET(info
->multicastSocket4
, readfds
))
1523 FD_CLR(info
->multicastSocket4
, readfds
);
1524 SocketDataReady(m
, info
, info
->multicastSocket4
);
1527 if (info
->multicastSocket6
!= -1 && FD_ISSET(info
->multicastSocket6
, readfds
))
1529 FD_CLR(info
->multicastSocket6
, readfds
);
1530 SocketDataReady(m
, info
, info
->multicastSocket6
);
1533 info
= (PosixNetworkInterface
*)(info
->coreIntf
.next
);
1538 mDNSlocal
void DetermineMaxEventFD( void )
1540 PosixEventSource
*iSource
;
1543 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1544 if ( gMaxFD
< iSource
->fd
)
1545 gMaxFD
= iSource
->fd
;
1548 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
1549 mStatus
mDNSPosixAddFDToEventLoop( int fd
, mDNSPosixEventCallback callback
, void *context
)
1551 PosixEventSource
*newSource
;
1553 if ( gEventSources
.LinkOffset
== 0)
1554 InitLinkedList( &gEventSources
, offsetof( PosixEventSource
, Next
));
1556 if ( fd
>= (int) FD_SETSIZE
|| fd
< 0)
1557 return mStatus_UnsupportedErr
;
1558 if ( callback
== NULL
)
1559 return mStatus_BadParamErr
;
1561 newSource
= (PosixEventSource
*) malloc( sizeof *newSource
);
1562 if ( NULL
== newSource
)
1563 return mStatus_NoMemoryErr
;
1565 newSource
->Callback
= callback
;
1566 newSource
->Context
= context
;
1569 AddToTail( &gEventSources
, newSource
);
1570 FD_SET( fd
, &gEventFDs
);
1572 DetermineMaxEventFD();
1574 return mStatus_NoError
;
1577 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
1578 mStatus
mDNSPosixRemoveFDFromEventLoop( int fd
)
1580 PosixEventSource
*iSource
;
1582 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1584 if ( fd
== iSource
->fd
)
1586 FD_CLR( fd
, &gEventFDs
);
1587 RemoveFromList( &gEventSources
, iSource
);
1589 DetermineMaxEventFD();
1590 return mStatus_NoError
;
1593 return mStatus_NoSuchNameErr
;
1596 // Simply note the received signal in gEventSignals.
1597 mDNSlocal
void NoteSignal( int signum
)
1599 sigaddset( &gEventSignals
, signum
);
1602 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
1603 mStatus
mDNSPosixListenForSignalInEventLoop( int signum
)
1605 struct sigaction action
;
1608 bzero( &action
, sizeof action
); // more portable than member-wise assignment
1609 action
.sa_handler
= NoteSignal
;
1610 err
= sigaction( signum
, &action
, (struct sigaction
*) NULL
);
1612 sigaddset( &gEventSignalSet
, signum
);
1617 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
1618 mStatus
mDNSPosixIgnoreSignalInEventLoop( int signum
)
1620 struct sigaction action
;
1623 bzero( &action
, sizeof action
); // more portable than member-wise assignment
1624 action
.sa_handler
= SIG_DFL
;
1625 err
= sigaction( signum
, &action
, (struct sigaction
*) NULL
);
1627 sigdelset( &gEventSignalSet
, signum
);
1632 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
1633 // Return as soon as internal timeout expires, or a signal we're listening for is received.
1634 mStatus
mDNSPosixRunEventLoopOnce( mDNS
*m
, const struct timeval
*pTimeout
,
1635 sigset_t
*pSignalsReceived
, mDNSBool
*pDataDispatched
)
1637 fd_set listenFDs
= gEventFDs
;
1638 int fdMax
= 0, numReady
;
1639 struct timeval timeout
= *pTimeout
;
1641 // Include the sockets that are listening to the wire in our select() set
1642 mDNSPosixGetFDSet( m
, &fdMax
, &listenFDs
, &timeout
); // timeout may get modified
1643 if ( fdMax
< gMaxFD
)
1646 numReady
= select( fdMax
+ 1, &listenFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
);
1648 // If any data appeared, invoke its callback
1651 PosixEventSource
*iSource
;
1653 (void) mDNSPosixProcessFDSet( m
, &listenFDs
); // call this first to process wire data for clients
1655 for ( iSource
=(PosixEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
1657 if ( FD_ISSET( iSource
->fd
, &listenFDs
))
1659 iSource
->Callback( iSource
->Context
);
1660 break; // in case callback removed elements from gEventSources
1663 *pDataDispatched
= mDNStrue
;
1666 *pDataDispatched
= mDNSfalse
;
1668 (void) sigprocmask( SIG_BLOCK
, &gEventSignalSet
, (sigset_t
*) NULL
);
1669 *pSignalsReceived
= gEventSignals
;
1670 sigemptyset( &gEventSignals
);
1671 (void) sigprocmask( SIG_UNBLOCK
, &gEventSignalSet
, (sigset_t
*) NULL
);
1673 return mStatus_NoError
;