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