xref: /titanic_41/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNSPosix.c (revision 180be2b71286f24b86109da3865e48b6ed708bcc)
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Formatting notes:
18  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19  * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20  * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21  * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22  * therefore common sense dictates that if they are part of a compound statement then they
23  * should be indented to the same level as everything else in that compound statement.
24  * Indenting curly braces at the same level as the "if" implies that curly braces are
25  * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27  * understand why variable y is not of type "char*" just proves the point that poor code
28  * layout leads people to unfortunate misunderstandings about how the C language really works.)
29 
30 	Change History (most recent first):
31 
32 $Log: mDNSPosix.c,v $
33 Revision 1.78.2.1  2006/08/29 06:24:34  cheshire
34 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
35 
36 Revision 1.78  2006/06/28 09:12:22  cheshire
37 Added debugging message
38 
39 Revision 1.77  2006/03/19 02:00:11  cheshire
40 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
41 
42 Revision 1.76  2006/01/09 19:29:16  cheshire
43 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
44 
45 Revision 1.75  2006/01/05 22:04:57  cheshire
46 <rdar://problem/4399479> Log error message when send fails with "operation not permitted"
47 
48 Revision 1.74  2006/01/05 21:45:27  cheshire
49 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
50 
51 Revision 1.73  2005/10/11 21:31:46  cheshire
52 <rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms)
53 
54 Revision 1.72  2005/09/08 20:45:26  cheshire
55 Default dot-local host name should be "Computer" not "Macintosh",
56 since the machine this is running on is most likely NOT a Mac.
57 
58 Revision 1.71  2005/02/26 01:29:12  cheshire
59 Ignore multicasts accidentally delivered to our unicast receiving socket
60 
61 Revision 1.70  2005/02/04 00:39:59  cheshire
62 Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
63 
64 Revision 1.69  2004/12/18 02:03:28  cheshire
65 Need to #include "dns_sd.h"
66 
67 Revision 1.68  2004/12/18 00:51:52  cheshire
68 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
69 
70 Revision 1.67  2004/12/17 23:37:48  cheshire
71 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
72 (and other repetitive configuration changes)
73 
74 Revision 1.66  2004/12/01 04:27:28  cheshire
75 <rdar://problem/3872803> Darwin patches for Solaris and Suse
76 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
77 
78 Revision 1.65  2004/11/30 22:37:01  cheshire
79 Update copyright dates and add "Mode: C; tab-width: 4" headers
80 
81 Revision 1.64  2004/11/23 03:39:47  cheshire
82 Let interface name/index mapping capability live directly in JNISupport.c,
83 instead of having to call through to the daemon via IPC to get this information.
84 
85 Revision 1.63  2004/11/12 03:16:43  rpantos
86 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
87 
88 Revision 1.62  2004/10/28 03:24:42  cheshire
89 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
90 
91 Revision 1.61  2004/10/16 00:17:01  cheshire
92 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
93 
94 Revision 1.60  2004/09/26 23:20:36  ksekar
95 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
96 
97 Revision 1.59  2004/09/21 21:02:55  cheshire
98 Set up ifname before calling mDNS_RegisterInterface()
99 
100 Revision 1.58  2004/09/17 01:08:54  cheshire
101 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
102   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
103   declared in that file are ONLY appropriate to single-address-space embedded applications.
104   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
105 
106 Revision 1.57  2004/09/17 00:19:11  cheshire
107 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
108 
109 Revision 1.56  2004/09/17 00:15:56  cheshire
110 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
111 
112 Revision 1.55  2004/09/16 00:24:49  cheshire
113 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
114 
115 Revision 1.54  2004/09/15 23:55:00  ksekar
116 <rdar://problem/3800597> mDNSPosix should #include stdint.h
117 
118 Revision 1.53  2004/09/14 23:42:36  cheshire
119 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
120 
121 Revision 1.52  2004/08/25 16:42:13  ksekar
122 Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
123 hostname parameter.
124 
125 Revision 1.51  2004/08/14 03:22:42  cheshire
126 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
127 Add GetUserSpecifiedDDNSName() routine
128 Convert ServiceRegDomain to domainname instead of C string
129 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
130 
131 Revision 1.50  2004/08/11 01:20:20  cheshire
132 Declare private local functions using "mDNSlocal"
133 
134 Revision 1.49  2004/07/26 22:49:31  ksekar
135 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
136 
137 Revision 1.48  2004/07/20 01:47:36  rpantos
138 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
139 
140 Revision 1.47  2004/06/25 00:26:27  rpantos
141 Changes to fix the Posix build on Solaris.
142 
143 Revision 1.46  2004/05/13 04:54:20  ksekar
144 Unified list copy/free code.  Added symetric list for
145 
146 Revision 1.45  2004/05/12 22:03:09  ksekar
147 Made GetSearchDomainList a true platform-layer call (declaration moved
148 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
149 only on non-OSX platforms.  Changed call to return a copy of the list
150 to avoid shared memory issues.  Added a routine to free the list.
151 
152 Revision 1.44  2004/04/21 02:49:11  cheshire
153 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
154 
155 Revision 1.43  2004/04/14 23:09:29  ksekar
156 Support for TSIG signed dynamic updates.
157 
158 Revision 1.42  2004/04/09 17:43:04  cheshire
159 Make sure to set the McastTxRx field so that duplicate suppression works correctly
160 
161 Revision 1.41  2004/02/06 01:19:51  cheshire
162 Conditionally exclude IPv6 code unless HAVE_IPV6 is set
163 
164 Revision 1.40  2004/02/05 01:00:01  rpantos
165 Fix some issues that turned up when building for FreeBSD.
166 
167 Revision 1.39  2004/01/28 21:12:15  cheshire
168 Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
169 
170 Revision 1.38  2004/01/27 20:15:23  cheshire
171 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
172 
173 Revision 1.37  2004/01/24 05:12:03  cheshire
174 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
175 
176 Revision 1.36  2004/01/24 04:59:16  cheshire
177 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
178 
179 Revision 1.35  2004/01/23 21:37:08  cheshire
180 For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
181 
182 Revision 1.34  2004/01/22 03:43:09  cheshire
183 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
184 
185 Revision 1.33  2004/01/21 21:54:20  cheshire
186 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
187 
188 Revision 1.32  2004/01/20 01:49:28  rpantos
189 Tweak error handling of last checkin a bit.
190 
191 Revision 1.31  2004/01/20 01:39:27  rpantos
192 Respond to If changes by rebuilding interface list.
193 
194 Revision 1.30  2003/12/11 19:40:36  cheshire
195 Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
196 
197 Revision 1.29  2003/12/11 18:53:22  cheshire
198 Fix compiler warning reported by Paul Guyot
199 
200 Revision 1.28  2003/12/11 03:03:51  rpantos
201 Clean up mDNSPosix so that it builds on OS X again.
202 
203 Revision 1.27  2003/12/08 20:47:02  rpantos
204 Add support for mDNSResponder on Linux.
205 
206 Revision 1.26  2003/11/14 20:59:09  cheshire
207 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
208 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
209 
210 Revision 1.25  2003/10/30 19:25:49  cheshire
211 Fix signed/unsigned warning on certain compilers
212 
213 Revision 1.24  2003/08/18 23:12:23  cheshire
214 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
215 
216 Revision 1.23  2003/08/12 19:56:26  cheshire
217 Update to APSL 2.0
218 
219 Revision 1.22  2003/08/06 18:46:15  cheshire
220 LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
221 
222 Revision 1.21  2003/08/06 18:20:51  cheshire
223 Makefile cleanup
224 
225 Revision 1.20  2003/08/05 23:56:26  cheshire
226 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
227 (Right now mDNSPosix.c just reports 255 -- we should fix this)
228 
229 Revision 1.19  2003/07/19 03:15:16  cheshire
230 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
231 and add the obvious trivial implementations to each platform support layer
232 
233 Revision 1.18  2003/07/14 18:11:54  cheshire
234 Fix stricter compiler warnings
235 
236 Revision 1.17  2003/07/13 01:08:38  cheshire
237 There's not much point running mDNS over a point-to-point link; exclude those
238 
239 Revision 1.16  2003/07/02 21:19:59  cheshire
240 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
241 
242 Revision 1.15  2003/06/18 05:48:41  cheshire
243 Fix warnings
244 
245 Revision 1.14  2003/05/26 03:21:30  cheshire
246 Tidy up address structure naming:
247 mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
248 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
249 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
250 
251 Revision 1.13  2003/05/26 03:01:28  cheshire
252 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
253 
254 Revision 1.12  2003/05/21 03:49:18  cheshire
255 Fix warning
256 
257 Revision 1.11  2003/05/06 00:00:50  cheshire
258 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
259 
260 Revision 1.10  2003/04/25 01:45:57  cheshire
261 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
262 
263 Revision 1.9  2003/03/20 21:10:31  cheshire
264 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
265 
266 Revision 1.8  2003/03/15 04:40:38  cheshire
267 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
268 
269 Revision 1.7  2003/03/13 03:46:21  cheshire
270 Fixes to make the code build on Linux
271 
272 Revision 1.6  2003/03/08 00:35:56  cheshire
273 Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
274 
275 Revision 1.5  2002/12/23 22:13:31  jgraessl
276 Reviewed by: Stuart Cheshire
277 Initial IPv6 support for mDNSResponder.
278 
279 Revision 1.4  2002/09/27 01:47:45  cheshire
280 Workaround for Linux 2.0 systems that don't have IP_PKTINFO
281 
282 Revision 1.3  2002/09/21 20:44:53  zarzycki
283 Added APSL info
284 
285 Revision 1.2  2002/09/19 21:25:36  cheshire
286 mDNS_snprintf() doesn't need to be in a separate file
287 
288 Revision 1.1  2002/09/17 06:24:34  cheshire
289 First checkin
290 */
291 
292 #pragma ident	"%Z%%M%	%I%	%E% SMI"
293 
294 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
295 #include "mDNSPosix.h"				 // Defines the specific types needed to run mDNS on this platform
296 #include "dns_sd.h"
297 
298 #include <assert.h>
299 #include <stdio.h>
300 #include <stdlib.h>
301 #include <errno.h>
302 #include <string.h>
303 #include <unistd.h>
304 #include <syslog.h>
305 #include <stdarg.h>
306 #include <fcntl.h>
307 #include <sys/types.h>
308 #include <sys/time.h>
309 #include <sys/socket.h>
310 #include <sys/uio.h>
311 #include <sys/select.h>
312 #include <netinet/in.h>
313 #include <arpa/inet.h>
314 #include <time.h>                   // platform support for UTC time
315 
316 #if USES_NETLINK
317 #include <asm/types.h>
318 #include <linux/netlink.h>
319 #include <linux/rtnetlink.h>
320 #else // USES_NETLINK
321 #include <net/route.h>
322 #include <net/if.h>
323 #endif // USES_NETLINK
324 
325 #include "mDNSUNP.h"
326 #include "GenLinkedList.h"
327 
328 // ***************************************************************************
329 // Structures
330 
331 // We keep a list of client-supplied event sources in PosixEventSource records
332 struct PosixEventSource
333 	{
334 	mDNSPosixEventCallback		Callback;
335 	void						*Context;
336 	int							fd;
337 	struct  PosixEventSource	*Next;
338 	};
339 typedef struct PosixEventSource	PosixEventSource;
340 
341 // Context record for interface change callback
342 struct IfChangeRec
343 	{
344 	int			NotifySD;
345 	mDNS*		mDNS;
346 	};
347 typedef struct IfChangeRec	IfChangeRec;
348 
349 // Note that static data is initialized to zero in (modern) C.
350 static fd_set			gEventFDs;
351 static int				gMaxFD;					// largest fd in gEventFDs
352 static GenLinkedList	gEventSources;			// linked list of PosixEventSource's
353 static sigset_t			gEventSignalSet;		// Signals which event loop listens for
354 static sigset_t			gEventSignals;			// Signals which were received while inside loop
355 
356 // ***************************************************************************
357 // Globals (for debugging)
358 
359 static int num_registered_interfaces = 0;
360 static int num_pkts_accepted = 0;
361 static int num_pkts_rejected = 0;
362 
363 // ***************************************************************************
364 // Functions
365 
366 int gMDNSPlatformPosixVerboseLevel = 0;
367 
368 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
369 
SockAddrTomDNSAddr(const struct sockaddr * const sa,mDNSAddr * ipAddr,mDNSIPPort * ipPort)370 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
371 	{
372 	switch (sa->sa_family)
373 		{
374 		case AF_INET:
375 			{
376 			struct sockaddr_in* sin          = (struct sockaddr_in*)sa;
377 			ipAddr->type                     = mDNSAddrType_IPv4;
378 			ipAddr->ip.v4.NotAnInteger       = sin->sin_addr.s_addr;
379 			if (ipPort) ipPort->NotAnInteger = sin->sin_port;
380 			break;
381 			}
382 
383 #if HAVE_IPV6
384 		case AF_INET6:
385 			{
386 			struct sockaddr_in6* sin6        = (struct sockaddr_in6*)sa;
387 #ifndef NOT_HAVE_SA_LEN
388 			assert(sin6->sin6_len == sizeof(*sin6));
389 #endif
390 			ipAddr->type                     = mDNSAddrType_IPv6;
391 			ipAddr->ip.v6                    = *(mDNSv6Addr*)&sin6->sin6_addr;
392 			if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
393 			break;
394 			}
395 #endif
396 
397 		default:
398 			verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
399 			ipAddr->type = mDNSAddrType_None;
400 			if (ipPort) ipPort->NotAnInteger = 0;
401 			break;
402 		}
403 	}
404 
405 #if COMPILER_LIKES_PRAGMA_MARK
406 #pragma mark ***** Send and Receive
407 #endif
408 
409 // mDNS core calls this routine when it needs to send a packet.
mDNSPlatformSendUDP(const mDNS * const m,const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID,const mDNSAddr * dst,mDNSIPPort dstPort)410 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
411 	mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
412 	{
413 	int                     err = 0;
414 	struct sockaddr_storage to;
415 	PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
416 	int sendingsocket = -1;
417 
418 	assert(m != NULL);
419 	assert(msg != NULL);
420 	assert(end != NULL);
421 	assert( (((char *) end) - ((char *) msg)) > 0 );
422 	assert(dstPort.NotAnInteger != 0);
423 
424 	if (dst->type == mDNSAddrType_IPv4)
425 		{
426 		struct sockaddr_in *sin = (struct sockaddr_in*)&to;
427 #ifndef NOT_HAVE_SA_LEN
428 		sin->sin_len            = sizeof(*sin);
429 #endif
430 		sin->sin_family         = AF_INET;
431 		sin->sin_port           = dstPort.NotAnInteger;
432 		sin->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
433 		sendingsocket           = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
434 		}
435 
436 #if HAVE_IPV6
437 	else if (dst->type == mDNSAddrType_IPv6)
438 		{
439 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
440 		mDNSPlatformMemZero(sin6, sizeof(*sin6));
441 #ifndef NOT_HAVE_SA_LEN
442 		sin6->sin6_len            = sizeof(*sin6);
443 #endif
444 		sin6->sin6_family         = AF_INET6;
445 		sin6->sin6_port           = dstPort.NotAnInteger;
446 		sin6->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
447 		sendingsocket             = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
448 		}
449 #endif
450 
451 	if (sendingsocket >= 0)
452 		err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
453 
454 	if      (err > 0) err = 0;
455 	else if (err < 0)
456 		{
457 		static int MessageCount = 0;
458         // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
459 		if (!mDNSAddressIsAllDNSLinkGroup(dst))
460 			if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
461 
462 		if (MessageCount < 1000)
463 			{
464 			MessageCount++;
465 			if (thisIntf)
466 				LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
467 							  errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
468 			else
469 				LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
470 			}
471 		}
472 
473 	return PosixErrorToStatus(err);
474 	}
475 
476 // This routine is called when the main loop detects that data is available on a socket.
SocketDataReady(mDNS * const m,PosixNetworkInterface * intf,int skt)477 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
478 	{
479 	mDNSAddr   senderAddr, destAddr;
480 	mDNSIPPort senderPort;
481 	ssize_t                 packetLen;
482 	DNSMessage              packet;
483 	struct my_in_pktinfo    packetInfo;
484 	struct sockaddr_storage from;
485 	socklen_t               fromLen;
486 	int                     flags;
487 	mDNSu8					ttl;
488 	mDNSBool                reject;
489 	const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
490 
491 	assert(m    != NULL);
492 	assert(skt  >= 0);
493 
494 	fromLen = sizeof(from);
495 	flags   = 0;
496 	packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
497 
498 	if (packetLen >= 0)
499 		{
500 		SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
501 		SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
502 
503 		// If we have broken IP_RECVDSTADDR functionality (so far
504 		// I've only seen this on OpenBSD) then apply a hack to
505 		// convince mDNS Core that this isn't a spoof packet.
506 		// Basically what we do is check to see whether the
507 		// packet arrived as a multicast and, if so, set its
508 		// destAddr to the mDNS address.
509 		//
510 		// I must admit that I could just be doing something
511 		// wrong on OpenBSD and hence triggering this problem
512 		// but I'm at a loss as to how.
513 		//
514 		// If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
515 		// no way to tell the destination address or interface this packet arrived on,
516 		// so all we can do is just assume it's a multicast
517 
518 		#if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
519 			if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
520 				{
521 				destAddr.type = senderAddr.type;
522 				if      (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4;
523 				else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
524 				}
525 		#endif
526 
527 		// We only accept the packet if the interface on which it came
528 		// in matches the interface associated with this socket.
529 		// We do this match by name or by index, depending on which
530 		// information is available.  recvfrom_flags sets the name
531 		// to "" if the name isn't available, or the index to -1
532 		// if the index is available.  This accomodates the various
533 		// different capabilities of our target platforms.
534 
535 		reject = mDNSfalse;
536 		if (!intf)
537 			{
538 			// Ignore multicasts accidentally delivered to our unicast receiving socket
539 			if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
540 			}
541 		else
542 			{
543 			if      ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
544 			else if ( packetInfo.ipi_ifindex != -1 )  reject = (packetInfo.ipi_ifindex != intf->index);
545 
546 			if (reject)
547 				{
548 				verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
549 					&senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
550 					&intf->coreIntf.ip, intf->intfName, intf->index, skt);
551 				packetLen = -1;
552 				num_pkts_rejected++;
553 				if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
554 					{
555 					fprintf(stderr,
556 						"*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
557 						num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
558 					num_pkts_accepted = 0;
559 					num_pkts_rejected = 0;
560 					}
561 				}
562 			else
563 				{
564 				verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
565 					&senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
566 				num_pkts_accepted++;
567 				}
568 			}
569 		}
570 
571 	if (packetLen >= 0)
572 		mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
573 			&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
574 	}
575 
mDNSPlatformTCPConnect(const mDNSAddr * dst,mDNSOpaque16 dstport,mDNSInterfaceID InterfaceID,TCPConnectionCallback callback,void * context,int * descriptor)576 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
577 										  TCPConnectionCallback callback, void *context, int *descriptor)
578 	{
579 	(void)dst;			// Unused
580 	(void)dstport;		// Unused
581 	(void)InterfaceID;	// Unused
582 	(void)callback;		// Unused
583 	(void)context;		// Unused
584 	(void)descriptor;	// Unused
585 	return(mStatus_UnsupportedErr);
586 	}
587 
mDNSPlatformTCPCloseConnection(int sd)588 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
589 	{
590 	(void)sd;			// Unused
591 	}
592 
mDNSPlatformReadTCP(int sd,void * buf,int buflen)593 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
594 	{
595 	(void)sd;			// Unused
596 	(void)buf;			// Unused
597 	(void)buflen;			// Unused
598 	return(0);
599 	}
600 
mDNSPlatformWriteTCP(int sd,const char * msg,int len)601 mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
602 	{
603 	(void)sd;			// Unused
604 	(void)msg;			// Unused
605 	(void)len;			// Unused
606 	return(0);
607 	}
608 
609 #if COMPILER_LIKES_PRAGMA_MARK
610 #pragma mark ***** Get/Free Search Domain List
611 #endif
612 
mDNSPlatformGetSearchDomainList(void)613 mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
614 	{
615 	static DNameListElem tmp;
616 	static mDNSBool init = mDNSfalse;
617 
618 	if (!init)
619 		{
620 		MakeDomainNameFromDNSNameString(&tmp.name, "local.");
621 		tmp.next = NULL;
622 		init = mDNStrue;
623 		}
624 	return mDNS_CopyDNameList(&tmp);
625 	}
626 
mDNSPlatformGetRegDomainList(void)627 mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
628 	{
629 	return NULL;
630 	}
631 
632 #if COMPILER_LIKES_PRAGMA_MARK
633 #pragma mark ***** Init and Term
634 #endif
635 
636 // This gets the current hostname, truncating it at the first dot if necessary
GetUserSpecifiedRFC1034ComputerName(domainlabel * const namelabel)637 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
638 	{
639 	int len = 0;
640 	gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
641 	while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
642 	namelabel->c[0] = len;
643 	}
644 
645 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
646 // Other platforms can either get the information from the appropriate place,
647 // or they can alternatively just require all registering services to provide an explicit name
GetUserSpecifiedFriendlyComputerName(domainlabel * const namelabel)648 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
649 	{
650 	// On Unix we have no better name than the host name, so we just use that.
651 	GetUserSpecifiedRFC1034ComputerName( namelabel);
652 	}
653 
ParseDNSServers(mDNS * m,const char * filePath)654 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
655 	{
656 	char line[256];
657 	char nameserver[16];
658 	char keyword[10];
659 	int  numOfServers = 0;
660 	FILE *fp = fopen(filePath, "r");
661 	if (fp == NULL) return -1;
662 	while (fgets(line,sizeof(line),fp))
663 		{
664 		struct in_addr ina;
665 		line[255]='\0';		// just to be safe
666 		if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue;	// it will skip whitespaces
667 		if (strncmp(keyword,"nameserver",10)) continue;
668 		if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
669 			{
670 			mDNSAddr DNSAddr;
671 			DNSAddr.type = mDNSAddrType_IPv4;
672 			DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
673 			mDNS_AddDNSServer(m, &DNSAddr, NULL);
674 			numOfServers++;
675 			}
676 		}
677 	fclose(fp);
678 	return (numOfServers > 0) ? 0 : -1;
679 	}
680 
681 // Searches the interface list looking for the named interface.
682 // Returns a pointer to if it found, or NULL otherwise.
SearchForInterfaceByName(mDNS * const m,const char * intfName)683 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
684 	{
685 	PosixNetworkInterface *intf;
686 
687 	assert(m != NULL);
688 	assert(intfName != NULL);
689 
690 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
691 	while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) )
692 		intf = (PosixNetworkInterface *)(intf->coreIntf.next);
693 
694 	return intf;
695 	}
696 
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS * const m,mDNSu32 index)697 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
698 	{
699 	PosixNetworkInterface *intf;
700 
701 	assert(m != NULL);
702 
703 	if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
704 
705 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
706 	while ( (intf != NULL) && (mDNSu32) intf->index != index)
707 		intf = (PosixNetworkInterface *)(intf->coreIntf.next);
708 
709 	return (mDNSInterfaceID) intf;
710 	}
711 
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS * const m,mDNSInterfaceID id)712 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
713 	{
714 	PosixNetworkInterface *intf;
715 
716 	assert(m != NULL);
717 
718 	if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
719 
720 	intf = (PosixNetworkInterface*)(m->HostInterfaces);
721 	while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
722 		intf = (PosixNetworkInterface *)(intf->coreIntf.next);
723 
724 	return intf ? intf->index : 0;
725 	}
726 
727 // Frees the specified PosixNetworkInterface structure. The underlying
728 // interface must have already been deregistered with the mDNS core.
FreePosixNetworkInterface(PosixNetworkInterface * intf)729 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
730 	{
731 	assert(intf != NULL);
732 	if (intf->intfName != NULL)        free((void *)intf->intfName);
733 	if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
734 #if HAVE_IPV6
735 	if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
736 #endif
737 	free(intf);
738 	}
739 
740 // Grab the first interface, deregister it, free it, and repeat until done.
ClearInterfaceList(mDNS * const m)741 mDNSlocal void ClearInterfaceList(mDNS *const m)
742 	{
743 	assert(m != NULL);
744 
745 	while (m->HostInterfaces)
746 		{
747 		PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
748 		mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
749 		if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
750 		FreePosixNetworkInterface(intf);
751 		}
752 	num_registered_interfaces = 0;
753 	num_pkts_accepted = 0;
754 	num_pkts_rejected = 0;
755 	}
756 
757 // Sets up a send/receive socket.
758 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
759 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
SetupSocket(struct sockaddr * intfAddr,mDNSIPPort port,int interfaceIndex,int * sktPtr)760 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
761 	{
762 	int err = 0;
763 	static const int kOn = 1;
764 	static const int kIntTwoFiveFive = 255;
765 	static const unsigned char kByteTwoFiveFive = 255;
766 	const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
767 
768 	(void) interfaceIndex;	// This parameter unused on plaforms that don't have IPv6
769 	assert(intfAddr != NULL);
770 	assert(sktPtr != NULL);
771 	assert(*sktPtr == -1);
772 
773 	// Open the socket...
774 	if      (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET,  SOCK_DGRAM, IPPROTO_UDP);
775 #if HAVE_IPV6
776 	else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
777 #endif
778 	else return EINVAL;
779 
780 	if (*sktPtr < 0) { err = errno; perror("socket"); }
781 
782 	// ... with a shared UDP port, if it's for multicast receiving
783 	if (err == 0 && port.NotAnInteger)
784 		{
785 		#if defined(SO_REUSEPORT)
786 			err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
787 		#elif defined(SO_REUSEADDR)
788 			err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
789 		#else
790 			#error This platform has no way to avoid address busy errors on multicast.
791 		#endif
792 		if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
793 		}
794 
795 	// We want to receive destination addresses and interface identifiers.
796 	if (intfAddr->sa_family == AF_INET)
797 		{
798 		struct ip_mreq imr;
799 		struct sockaddr_in bindAddr;
800 		if (err == 0)
801 			{
802 			#if defined(IP_PKTINFO)						// Linux and Solaris
803 				err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
804 				if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
805 			#elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF)		// BSD
806 				#if defined(IP_RECVDSTADDR)
807 					err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
808 					if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
809 				#endif
810 				#if defined(IP_RECVIF)
811 					if (err == 0)
812 						{
813 						err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
814 						if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
815 						}
816 				#endif
817 			#else
818 				#warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
819 			#endif
820 			}
821 	#if defined(IP_RECVTTL)									// Linux
822 		if (err == 0)
823 			{
824 			setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
825 			// We no longer depend on being able to get the received TTL, so don't worry if the option fails
826 			}
827 	#endif
828 
829 		// Add multicast group membership on this interface
830 		if (err == 0 && JoinMulticastGroup)
831 			{
832 			imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
833 			imr.imr_interface        = ((struct sockaddr_in*)intfAddr)->sin_addr;
834 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
835 			if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
836 			}
837 
838 		// Specify outgoing interface too
839 		if (err == 0 && JoinMulticastGroup)
840 			{
841 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
842 			if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
843 			}
844 
845 		// Per the mDNS spec, send unicast packets with TTL 255
846 		if (err == 0)
847 			{
848 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
849 			if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
850 			}
851 
852 		// and multicast packets with TTL 255 too
853 		// There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
854 		if (err == 0)
855 			{
856 			err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
857 			if (err < 0 && errno == EINVAL)
858 				err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
859 			if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
860 			}
861 
862 		// And start listening for packets
863 		if (err == 0)
864 			{
865 			bindAddr.sin_family      = AF_INET;
866 			bindAddr.sin_port        = port.NotAnInteger;
867 			bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
868 			err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
869 			if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
870 			}
871 		} // endif (intfAddr->sa_family == AF_INET)
872 
873 #if HAVE_IPV6
874 	else if (intfAddr->sa_family == AF_INET6)
875 		{
876 		struct ipv6_mreq imr6;
877 		struct sockaddr_in6 bindAddr6;
878 	#if defined(IPV6_RECVPKTINFO) 	// Solaris
879 		if (err == 0)
880 			{
881 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
882 				if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
883 			}
884 
885 	#elif defined(IPV6_PKTINFO)
886 		if (err == 0)
887 			{
888 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_PKTINFO, &kOn, sizeof(kOn));
889 				if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
890 			}
891 	#else
892 		#warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
893 	#endif
894 	#if defined(IPV6_RECVHOPLIMIT) // Solaris
895 		if (err == 0)
896 			{
897 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn));
898 				if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
899 			}
900 
901 	#elif defined(IPV6_HOPLIMIT)
902 		if (err == 0)
903 			{
904 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_HOPLIMIT, &kOn, sizeof(kOn));
905 				if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
906 			}
907 	#endif
908 
909 		// Add multicast group membership on this interface
910 		if (err == 0 && JoinMulticastGroup)
911 			{
912 			imr6.ipv6mr_multiaddr       = *(const struct in6_addr*)&AllDNSLinkGroupv6;
913 			imr6.ipv6mr_interface       = interfaceIndex;
914 			//LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
915 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
916 			if (err < 0)
917 				{
918 				err = errno;
919 				verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
920 				perror("setsockopt - IPV6_JOIN_GROUP");
921 				}
922 			}
923 
924 		// Specify outgoing interface too
925 		if (err == 0 && JoinMulticastGroup)
926 			{
927 			u_int	multicast_if = interfaceIndex;
928 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
929 			if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
930 			}
931 
932 		// We want to receive only IPv6 packets on this socket.
933 		// Without this option, we may get IPv4 addresses as mapped addresses.
934 		if (err == 0)
935 			{
936 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
937 			if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
938 			}
939 
940 		// Per the mDNS spec, send unicast packets with TTL 255
941 		if (err == 0)
942 			{
943 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
944 			if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
945 			}
946 
947 		// and multicast packets with TTL 255 too
948 		// There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
949 		if (err == 0)
950 			{
951 			err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
952 			if (err < 0 && errno == EINVAL)
953 				err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
954 			if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
955 			}
956 
957 		// And start listening for packets
958 		if (err == 0)
959 			{
960 			mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
961 #ifndef NOT_HAVE_SA_LEN
962 			bindAddr6.sin6_len         = sizeof(bindAddr6);
963 #endif
964 			bindAddr6.sin6_family      = AF_INET6;
965 			bindAddr6.sin6_port        = port.NotAnInteger;
966 			bindAddr6.sin6_flowinfo    = 0;
967 			bindAddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
968 			bindAddr6.sin6_scope_id    = 0;
969 			err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
970 			if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
971 			}
972 		} // endif (intfAddr->sa_family == AF_INET6)
973 #endif
974 
975 	// Set the socket to non-blocking.
976 	if (err == 0)
977 		{
978 		err = fcntl(*sktPtr, F_GETFL, 0);
979 		if (err < 0) err = errno;
980 		else
981 			{
982 			err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
983 			if (err < 0) err = errno;
984 			}
985 		}
986 
987 	// Clean up
988 	if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
989 	assert( (err == 0) == (*sktPtr != -1) );
990 	return err;
991 	}
992 
993 // Creates a PosixNetworkInterface for the interface whose IP address is
994 // intfAddr and whose name is intfName and registers it with mDNS core.
SetupOneInterface(mDNS * const m,struct sockaddr * intfAddr,struct sockaddr * intfMask,const char * intfName,int intfIndex)995 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
996 	{
997 	int err = 0;
998 	PosixNetworkInterface *intf;
999 	PosixNetworkInterface *alias = NULL;
1000 
1001 	assert(m != NULL);
1002 	assert(intfAddr != NULL);
1003 	assert(intfName != NULL);
1004 	assert(intfMask != NULL);
1005 
1006 	// Allocate the interface structure itself.
1007 	intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
1008 	if (intf == NULL) { assert(0); err = ENOMEM; }
1009 
1010 	// And make a copy of the intfName.
1011 	if (err == 0)
1012 		{
1013 		intf->intfName = strdup(intfName);
1014 		if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1015 		}
1016 
1017 	if (err == 0)
1018 		{
1019 		// Set up the fields required by the mDNS core.
1020 		SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
1021 		SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
1022 		//LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
1023 		strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
1024 		intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
1025 		intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
1026 		intf->coreIntf.McastTxRx = mDNStrue;
1027 
1028 		// Set up the extra fields in PosixNetworkInterface.
1029 		assert(intf->intfName != NULL);         // intf->intfName already set up above
1030 		intf->index                = intfIndex;
1031 		intf->multicastSocket4     = -1;
1032 #if HAVE_IPV6
1033 		intf->multicastSocket6     = -1;
1034 #endif
1035 		alias                      = SearchForInterfaceByName(m, intf->intfName);
1036 		if (alias == NULL) alias   = intf;
1037 		intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
1038 
1039 		if (alias != intf)
1040 			debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
1041 		}
1042 
1043 	// Set up the multicast socket
1044 	if (err == 0)
1045 		{
1046 		if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
1047 			err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
1048 #if HAVE_IPV6
1049 		else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
1050 			err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
1051 #endif
1052 		}
1053 
1054 	// The interface is all ready to go, let's register it with the mDNS core.
1055 	if (err == 0)
1056 		err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
1057 
1058 	// Clean up.
1059 	if (err == 0)
1060 		{
1061 		num_registered_interfaces++;
1062 		debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
1063 		if (gMDNSPlatformPosixVerboseLevel > 0)
1064 			fprintf(stderr, "Registered interface %s\n", intf->intfName);
1065 		}
1066 	else
1067 		{
1068 		// Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1069 		debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
1070 		if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
1071 		}
1072 
1073 	assert( (err == 0) == (intf != NULL) );
1074 
1075 	return err;
1076 	}
1077 
1078 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
SetupInterfaceList(mDNS * const m)1079 mDNSlocal int SetupInterfaceList(mDNS *const m)
1080 	{
1081 	mDNSBool        foundav4       = mDNSfalse;
1082 	int             err            = 0;
1083 	struct ifi_info *intfList      = get_ifi_info(AF_INET, mDNStrue);
1084 	struct ifi_info *firstLoopback = NULL;
1085 
1086 	assert(m != NULL);
1087 	debugf("SetupInterfaceList");
1088 
1089 	if (intfList == NULL) err = ENOENT;
1090 
1091 #if HAVE_IPV6
1092 	if (err == 0)		/* Link the IPv6 list to the end of the IPv4 list */
1093 		{
1094 		struct ifi_info **p = &intfList;
1095 		while (*p) p = &(*p)->ifi_next;
1096 		*p = get_ifi_info(AF_INET6, mDNStrue);
1097 		}
1098 #endif
1099 
1100 	if (err == 0)
1101 		{
1102 		struct ifi_info *i = intfList;
1103 		while (i)
1104 			{
1105 			if (     ((i->ifi_addr->sa_family == AF_INET)
1106 #if HAVE_IPV6
1107 					  || (i->ifi_addr->sa_family == AF_INET6)
1108 #endif
1109 				) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) )
1110 				{
1111 				if (i->ifi_flags & IFF_LOOPBACK)
1112 					{
1113 					if (firstLoopback == NULL)
1114 						firstLoopback = i;
1115 					}
1116 				else
1117 					{
1118 					if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
1119 						if (i->ifi_addr->sa_family == AF_INET)
1120 							foundav4 = mDNStrue;
1121 					}
1122 				}
1123 			i = i->ifi_next;
1124 			}
1125 
1126 		// If we found no normal interfaces but we did find a loopback interface, register the
1127 		// loopback interface.  This allows self-discovery if no interfaces are configured.
1128 		// Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1129 		// In the interim, we skip loopback interface only if we found at least one v4 interface to use
1130 		// if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
1131 		if ( !foundav4 && firstLoopback )
1132 			(void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
1133 		}
1134 
1135 	// Clean up.
1136 	if (intfList != NULL) free_ifi_info(intfList);
1137 	return err;
1138 	}
1139 
1140 #if USES_NETLINK
1141 
1142 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1143 
1144 // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)1145 mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
1146 	{
1147 	mStatus					err = mStatus_NoError;
1148 	struct sockaddr_nl		snl;
1149 	int sock;
1150 	int ret;
1151 
1152 	sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1153 	if (sock < 0)
1154 		return errno;
1155 
1156 	// Configure read to be non-blocking because inbound msg size is not known in advance
1157 	(void) fcntl( sock, F_SETFL, O_NONBLOCK);
1158 
1159 	/* Subscribe the socket to Link & IP addr notifications. */
1160 	bzero( &snl, sizeof snl);
1161 	snl.nl_family = AF_NETLINK;
1162 	snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1163 	ret = bind( sock, (struct sockaddr *) &snl, sizeof snl);
1164 	if ( 0 == ret)
1165 		*pFD = sock;
1166 	else
1167 		err = errno;
1168 
1169 	return err;
1170 	}
1171 
1172 #if MDNS_DEBUGMSGS
PrintNetLinkMsg(const struct nlmsghdr * pNLMsg)1173 mDNSlocal void		PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
1174 	{
1175 	const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1176 	const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1177 
1178 	printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
1179 			pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE],
1180 			pNLMsg->nlmsg_flags);
1181 
1182 	if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
1183 		{
1184 		struct ifinfomsg	*pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg);
1185 		printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
1186 				pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
1187 
1188 		}
1189 	else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
1190 		{
1191 		struct ifaddrmsg	*pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg);
1192 		printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
1193 				pIfAddr->ifa_index, pIfAddr->ifa_flags);
1194 		}
1195 	printf( "\n");
1196 	}
1197 #endif
1198 
ProcessRoutingNotification(int sd)1199 mDNSlocal mDNSu32		ProcessRoutingNotification( int sd)
1200 // Read through the messages on sd and if any indicate that any interface records should
1201 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1202 	{
1203 	ssize_t					readCount;
1204 	char					buff[ 4096];
1205 	struct nlmsghdr			*pNLMsg = (struct nlmsghdr*) buff;
1206 	mDNSu32				result = 0;
1207 
1208 	// The structure here is more complex than it really ought to be because,
1209 	// unfortunately, there's no good way to size a buffer in advance large
1210 	// enough to hold all pending data and so avoid message fragmentation.
1211 	// (Note that FIONREAD is not supported on AF_NETLINK.)
1212 
1213 	readCount = read( sd, buff, sizeof buff);
1214 	while ( 1)
1215 		{
1216 		// Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1217 		// If not, discard already-processed messages in buffer and read more data.
1218 		if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) ||	// i.e. *pNLMsg extends off end of buffer
1219 			 ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount)))
1220 			{
1221 			if ( buff < (char*) pNLMsg)		// we have space to shuffle
1222 				{
1223 				// discard processed data
1224 				readCount -= ( (char*) pNLMsg - buff);
1225 				memmove( buff, pNLMsg, readCount);
1226 				pNLMsg = (struct nlmsghdr*) buff;
1227 
1228 				// read more data
1229 				readCount += read( sd, buff + readCount, sizeof buff - readCount);
1230 				continue;					// spin around and revalidate with new readCount
1231 				}
1232 			else
1233 				break;	// Otherwise message does not fit in buffer
1234 			}
1235 
1236 #if MDNS_DEBUGMSGS
1237 		PrintNetLinkMsg( pNLMsg);
1238 #endif
1239 
1240 		// Process the NetLink message
1241 		if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
1242 			result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index;
1243 		else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
1244 			result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index;
1245 
1246 		// Advance pNLMsg to the next message in the buffer
1247 		if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
1248 			{
1249 			ssize_t	len = readCount - ( (char*)pNLMsg - buff);
1250 			pNLMsg = NLMSG_NEXT( pNLMsg, len);
1251 			}
1252 		else
1253 			break;	// all done!
1254 		}
1255 
1256 	return result;
1257 	}
1258 
1259 #else // USES_NETLINK
1260 
1261 // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)1262 mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
1263 	{
1264 	*pFD = socket( AF_ROUTE, SOCK_RAW, 0);
1265 
1266 	if ( *pFD < 0)
1267 		return mStatus_UnknownErr;
1268 
1269 	// Configure read to be non-blocking because inbound msg size is not known in advance
1270 	(void) fcntl( *pFD, F_SETFL, O_NONBLOCK);
1271 
1272 	return mStatus_NoError;
1273 	}
1274 
1275 #if MDNS_DEBUGMSGS
PrintRoutingSocketMsg(const struct ifa_msghdr * pRSMsg)1276 mDNSlocal void		PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
1277 	{
1278 	const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1279 					"RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1280 					"RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1281 
1282 	int		index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
1283 
1284 	printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index);
1285 	}
1286 #endif
1287 
ProcessRoutingNotification(int sd)1288 mDNSlocal mDNSu32		ProcessRoutingNotification( int sd)
1289 // Read through the messages on sd and if any indicate that any interface records should
1290 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1291 	{
1292 	ssize_t					readCount;
1293 	char					buff[ 4096];
1294 	struct ifa_msghdr		*pRSMsg = (struct ifa_msghdr*) buff;
1295 	mDNSu32				result = 0;
1296 
1297 	readCount = read( sd, buff, sizeof buff);
1298 	if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
1299 		return mStatus_UnsupportedErr;		// cannot decipher message
1300 
1301 #if MDNS_DEBUGMSGS
1302 	PrintRoutingSocketMsg( pRSMsg);
1303 #endif
1304 
1305 	// Process the message
1306 	if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
1307 		 pRSMsg->ifam_type == RTM_IFINFO)
1308 		{
1309 		if ( pRSMsg->ifam_type == RTM_IFINFO)
1310 			result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
1311 		else
1312 			result |= 1 << pRSMsg->ifam_index;
1313 		}
1314 
1315 	return result;
1316 	}
1317 
1318 #endif // USES_NETLINK
1319 
1320 // Called when data appears on interface change notification socket
InterfaceChangeCallback(void * context)1321 mDNSlocal void InterfaceChangeCallback( void *context)
1322 	{
1323 	IfChangeRec		*pChgRec = (IfChangeRec*) context;
1324 	fd_set			readFDs;
1325 	mDNSu32		changedInterfaces = 0;
1326 	struct timeval	zeroTimeout = { 0, 0 };
1327 
1328 	FD_ZERO( &readFDs);
1329 	FD_SET( pChgRec->NotifySD, &readFDs);
1330 
1331 	do
1332 	{
1333 		changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD);
1334 	}
1335 	while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
1336 
1337 	// Currently we rebuild the entire interface list whenever any interface change is
1338 	// detected. If this ever proves to be a performance issue in a multi-homed
1339 	// configuration, more care should be paid to changedInterfaces.
1340 	if ( changedInterfaces)
1341 		mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS);
1342 	}
1343 
1344 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
WatchForInterfaceChange(mDNS * const m)1345 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
1346 	{
1347 	mStatus		err;
1348 	IfChangeRec	*pChgRec;
1349 
1350 	pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec);
1351 	if ( pChgRec == NULL)
1352 		return mStatus_NoMemoryErr;
1353 
1354 	pChgRec->mDNS = m;
1355 	err = OpenIfNotifySocket( &pChgRec->NotifySD);
1356 	if ( err == 0)
1357 		err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1358 
1359 	return err;
1360 	}
1361 
1362 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1363 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1364 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
mDNSPlatformInit_CanReceiveUnicast(void)1365 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
1366 	{
1367 	int err;
1368 	int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1369 	struct sockaddr_in s5353;
1370 	s5353.sin_family      = AF_INET;
1371 	s5353.sin_port        = MulticastDNSPort.NotAnInteger;
1372 	s5353.sin_addr.s_addr = 0;
1373 	err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
1374 	close(s);
1375 	if (err) debugf("No unicast UDP responses");
1376 	else     debugf("Unicast UDP responses okay");
1377 	return(err == 0);
1378 	}
1379 
1380 // mDNS core calls this routine to initialise the platform-specific data.
mDNSPlatformInit(mDNS * const m)1381 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1382 	{
1383 	int err = 0;
1384 	struct sockaddr sa;
1385 	assert(m != NULL);
1386 
1387 	if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
1388 
1389 	// Tell mDNS core the names of this machine.
1390 
1391 	// Set up the nice label
1392 	m->nicelabel.c[0] = 0;
1393 	GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
1394 	if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
1395 
1396 	// Set up the RFC 1034-compliant label
1397 	m->hostlabel.c[0] = 0;
1398 	GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
1399 	if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
1400 
1401 	mDNS_SetFQDN(m);
1402 
1403 	sa.sa_family = AF_INET;
1404 	m->p->unicastSocket4 = -1;
1405 	if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
1406 #if HAVE_IPV6
1407 	sa.sa_family = AF_INET6;
1408 	m->p->unicastSocket6 = -1;
1409 	if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
1410 #endif
1411 
1412 	// Tell mDNS core about the network interfaces on this machine.
1413 	if (err == mStatus_NoError) err = SetupInterfaceList(m);
1414 
1415 	// Tell mDNS core about DNS Servers
1416 	if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1417 
1418 	if (err == mStatus_NoError)
1419 		{
1420 		err = WatchForInterfaceChange(m);
1421 		// Failure to observe interface changes is non-fatal.
1422 		if ( err != mStatus_NoError)
1423 			{
1424 			fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
1425 			err = mStatus_NoError;
1426 			}
1427 		}
1428 
1429 	// We don't do asynchronous initialization on the Posix platform, so by the time
1430 	// we get here the setup will already have succeeded or failed.  If it succeeded,
1431 	// we should just call mDNSCoreInitComplete() immediately.
1432 	if (err == mStatus_NoError)
1433 		mDNSCoreInitComplete(m, mStatus_NoError);
1434 
1435 	return PosixErrorToStatus(err);
1436 	}
1437 
1438 // mDNS core calls this routine to clean up the platform-specific data.
1439 // In our case all we need to do is to tear down every network interface.
mDNSPlatformClose(mDNS * const m)1440 mDNSexport void mDNSPlatformClose(mDNS *const m)
1441 	{
1442 	assert(m != NULL);
1443 	ClearInterfaceList(m);
1444 	if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
1445 #if HAVE_IPV6
1446 	if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
1447 #endif
1448 	}
1449 
mDNSPlatformPosixRefreshInterfaceList(mDNS * const m)1450 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
1451 	{
1452 	int err;
1453 	ClearInterfaceList(m);
1454 	err = SetupInterfaceList(m);
1455 	return PosixErrorToStatus(err);
1456 	}
1457 
1458 #if COMPILER_LIKES_PRAGMA_MARK
1459 #pragma mark ***** Locking
1460 #endif
1461 
1462 // On the Posix platform, locking is a no-op because we only ever enter
1463 // mDNS core on the main thread.
1464 
1465 // mDNS core calls this routine when it wants to prevent
1466 // the platform from reentering mDNS core code.
mDNSPlatformLock(const mDNS * const m)1467 mDNSexport void    mDNSPlatformLock   (const mDNS *const m)
1468 	{
1469 	(void) m;	// Unused
1470 	}
1471 
1472 // mDNS core calls this routine when it release the lock taken by
1473 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
mDNSPlatformUnlock(const mDNS * const m)1474 mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
1475 	{
1476 	(void) m;	// Unused
1477 	}
1478 
1479 #if COMPILER_LIKES_PRAGMA_MARK
1480 #pragma mark ***** Strings
1481 #endif
1482 
1483 // mDNS core calls this routine to copy C strings.
1484 // On the Posix platform this maps directly to the ANSI C strcpy.
mDNSPlatformStrCopy(const void * src,void * dst)1485 mDNSexport void    mDNSPlatformStrCopy(const void *src,       void *dst)
1486 	{
1487 	strcpy((char *)dst, (char *)src);
1488 	}
1489 
1490 // mDNS core calls this routine to get the length of a C string.
1491 // On the Posix platform this maps directly to the ANSI C strlen.
mDNSPlatformStrLen(const void * src)1492 mDNSexport mDNSu32  mDNSPlatformStrLen (const void *src)
1493 	{
1494 	return strlen((char*)src);
1495 	}
1496 
1497 // mDNS core calls this routine to copy memory.
1498 // On the Posix platform this maps directly to the ANSI C memcpy.
mDNSPlatformMemCopy(const void * src,void * dst,mDNSu32 len)1499 mDNSexport void    mDNSPlatformMemCopy(const void *src,       void *dst, mDNSu32 len)
1500 	{
1501 	memcpy(dst, src, len);
1502 	}
1503 
1504 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1505 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
mDNSPlatformMemSame(const void * src,const void * dst,mDNSu32 len)1506 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len)
1507 	{
1508 	return memcmp(dst, src, len) == 0;
1509 	}
1510 
1511 // mDNS core calls this routine to clear blocks of memory.
1512 // On the Posix platform this is a simple wrapper around ANSI C memset.
mDNSPlatformMemZero(void * dst,mDNSu32 len)1513 mDNSexport void    mDNSPlatformMemZero(                       void *dst, mDNSu32 len)
1514 	{
1515 	memset(dst, 0, len);
1516 	}
1517 
mDNSPlatformMemAllocate(mDNSu32 len)1518 mDNSexport void *  mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
mDNSPlatformMemFree(void * mem)1519 mDNSexport void    mDNSPlatformMemFree    (void *mem)   { free(mem); }
1520 
mDNSPlatformRandomSeed(void)1521 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
1522 	{
1523 	struct timeval tv;
1524 	gettimeofday(&tv, NULL);
1525 	return(tv.tv_usec);
1526 	}
1527 
1528 mDNSexport mDNSs32  mDNSPlatformOneSecond = 1024;
1529 
mDNSPlatformTimeInit(void)1530 mDNSexport mStatus mDNSPlatformTimeInit(void)
1531 	{
1532 	// No special setup is required on Posix -- we just use gettimeofday();
1533 	// This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1534 	// We should find a better way to do this
1535 	return(mStatus_NoError);
1536 	}
1537 
mDNSPlatformRawTime()1538 mDNSexport mDNSs32  mDNSPlatformRawTime()
1539 	{
1540 	struct timeval tv;
1541 	gettimeofday(&tv, NULL);
1542 	// tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
1543 	// tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
1544 	// We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
1545 	// 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.
1546 	// This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1547 	// and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1548 	return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) );
1549 	}
1550 
mDNSPlatformUTC(void)1551 mDNSexport mDNSs32 mDNSPlatformUTC(void)
1552 	{
1553 	return time(NULL);
1554 	}
1555 
mDNSPosixAddToFDSet(int * nfds,fd_set * readfds,int s)1556 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
1557 	{
1558 	if (*nfds < s + 1) *nfds = s + 1;
1559 	FD_SET(s, readfds);
1560 	}
1561 
mDNSPosixGetFDSet(mDNS * m,int * nfds,fd_set * readfds,struct timeval * timeout)1562 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
1563 	{
1564 	mDNSs32 ticks;
1565 	struct timeval interval;
1566 
1567 	// 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1568 	mDNSs32 nextevent = mDNS_Execute(m);
1569 
1570 	// 2. Build our list of active file descriptors
1571 	PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
1572 	if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
1573 #if HAVE_IPV6
1574 	if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
1575 #endif
1576 	while (info)
1577 		{
1578 		if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
1579 #if HAVE_IPV6
1580 		if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
1581 #endif
1582 		info = (PosixNetworkInterface *)(info->coreIntf.next);
1583 		}
1584 
1585 	// 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
1586 	ticks = nextevent - mDNS_TimeNow(m);
1587 	if (ticks < 1) ticks = 1;
1588 	interval.tv_sec  = ticks >> 10;						// The high 22 bits are seconds
1589 	interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16;	// The low 10 bits are 1024ths
1590 
1591 	// 4. If client's proposed timeout is more than what we want, then reduce it
1592 	if (timeout->tv_sec > interval.tv_sec ||
1593 		(timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
1594 		*timeout = interval;
1595 	}
1596 
mDNSPosixProcessFDSet(mDNS * const m,fd_set * readfds)1597 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
1598 	{
1599 	PosixNetworkInterface *info;
1600 	assert(m       != NULL);
1601 	assert(readfds != NULL);
1602 	info = (PosixNetworkInterface *)(m->HostInterfaces);
1603 
1604 	if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
1605 		{
1606 		FD_CLR(m->p->unicastSocket4, readfds);
1607 		SocketDataReady(m, NULL, m->p->unicastSocket4);
1608 		}
1609 #if HAVE_IPV6
1610 	if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
1611 		{
1612 		FD_CLR(m->p->unicastSocket6, readfds);
1613 		SocketDataReady(m, NULL, m->p->unicastSocket6);
1614 		}
1615 #endif
1616 
1617 	while (info)
1618 		{
1619 		if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
1620 			{
1621 			FD_CLR(info->multicastSocket4, readfds);
1622 			SocketDataReady(m, info, info->multicastSocket4);
1623 			}
1624 #if HAVE_IPV6
1625 		if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
1626 			{
1627 			FD_CLR(info->multicastSocket6, readfds);
1628 			SocketDataReady(m, info, info->multicastSocket6);
1629 			}
1630 #endif
1631 		info = (PosixNetworkInterface *)(info->coreIntf.next);
1632 		}
1633 	}
1634 
1635 // update gMaxFD
DetermineMaxEventFD(void)1636 mDNSlocal void	DetermineMaxEventFD( void )
1637 	{
1638 	PosixEventSource	*iSource;
1639 
1640 	gMaxFD = 0;
1641 	for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1642 		if ( gMaxFD < iSource->fd)
1643 			gMaxFD = iSource->fd;
1644 	}
1645 
1646 // Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
mDNSPosixAddFDToEventLoop(int fd,mDNSPosixEventCallback callback,void * context)1647 mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context)
1648 	{
1649 	PosixEventSource	*newSource;
1650 
1651 	if ( gEventSources.LinkOffset == 0)
1652 		InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next));
1653 
1654 	if ( fd >= (int) FD_SETSIZE || fd < 0)
1655 		return mStatus_UnsupportedErr;
1656 	if ( callback == NULL)
1657 		return mStatus_BadParamErr;
1658 
1659 	newSource = (PosixEventSource*) malloc( sizeof *newSource);
1660 	if ( NULL == newSource)
1661 		return mStatus_NoMemoryErr;
1662 
1663 	newSource->Callback = callback;
1664 	newSource->Context = context;
1665 	newSource->fd = fd;
1666 
1667 	AddToTail( &gEventSources, newSource);
1668 	FD_SET( fd, &gEventFDs);
1669 
1670 	DetermineMaxEventFD();
1671 
1672 	return mStatus_NoError;
1673 	}
1674 
1675 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
mDNSPosixRemoveFDFromEventLoop(int fd)1676 mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
1677 	{
1678 	PosixEventSource	*iSource;
1679 
1680 	for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1681 		{
1682 		if ( fd == iSource->fd)
1683 			{
1684 			FD_CLR( fd, &gEventFDs);
1685 			RemoveFromList( &gEventSources, iSource);
1686 			free( iSource);
1687 			DetermineMaxEventFD();
1688 			return mStatus_NoError;
1689 			}
1690 		}
1691 	return mStatus_NoSuchNameErr;
1692 	}
1693 
1694 // Simply note the received signal in gEventSignals.
NoteSignal(int signum)1695 mDNSlocal void	NoteSignal( int signum)
1696 	{
1697 	sigaddset( &gEventSignals, signum);
1698 	}
1699 
1700 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
mDNSPosixListenForSignalInEventLoop(int signum)1701 mStatus mDNSPosixListenForSignalInEventLoop( int signum)
1702 	{
1703 	struct sigaction	action;
1704 	mStatus				err;
1705 
1706 	bzero( &action, sizeof action);		// more portable than member-wise assignment
1707 	action.sa_handler = NoteSignal;
1708 	err = sigaction( signum, &action, (struct sigaction*) NULL);
1709 
1710 	sigaddset( &gEventSignalSet, signum);
1711 
1712 	return err;
1713 	}
1714 
1715 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
mDNSPosixIgnoreSignalInEventLoop(int signum)1716 mStatus mDNSPosixIgnoreSignalInEventLoop( int signum)
1717 	{
1718 	struct sigaction	action;
1719 	mStatus				err;
1720 
1721 	bzero( &action, sizeof action);		// more portable than member-wise assignment
1722 	action.sa_handler = SIG_DFL;
1723 	err = sigaction( signum, &action, (struct sigaction*) NULL);
1724 
1725 	sigdelset( &gEventSignalSet, signum);
1726 
1727 	return err;
1728 	}
1729 
1730 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
1731 // Return as soon as internal timeout expires, or a signal we're listening for is received.
mDNSPosixRunEventLoopOnce(mDNS * m,const struct timeval * pTimeout,sigset_t * pSignalsReceived,mDNSBool * pDataDispatched)1732 mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout,
1733 									sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
1734 	{
1735 	fd_set			listenFDs = gEventFDs;
1736 	int				fdMax = 0, numReady;
1737 	struct timeval	timeout = *pTimeout;
1738 
1739 	// Include the sockets that are listening to the wire in our select() set
1740 	mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout);	// timeout may get modified
1741 	if ( fdMax < gMaxFD)
1742 		fdMax = gMaxFD;
1743 
1744 	numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
1745 
1746 	// If any data appeared, invoke its callback
1747 	if ( numReady > 0)
1748 		{
1749 		PosixEventSource	*iSource;
1750 
1751 		(void) mDNSPosixProcessFDSet( m, &listenFDs);	// call this first to process wire data for clients
1752 
1753 		for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
1754 			{
1755 			if ( FD_ISSET( iSource->fd, &listenFDs))
1756 				{
1757 				iSource->Callback( iSource->Context);
1758 				break;	// in case callback removed elements from gEventSources
1759 				}
1760 			}
1761 		*pDataDispatched = mDNStrue;
1762 		}
1763 	else
1764 		*pDataDispatched = mDNSfalse;
1765 
1766 	(void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
1767 	*pSignalsReceived = gEventSignals;
1768 	sigemptyset( &gEventSignals);
1769 	(void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
1770 
1771 	return mStatus_NoError;
1772 	}
1773