]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/nss_mdns.c
mDNSResponder-107.3.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / nss_mdns.c
1 /*
2 NICTA Public Software Licence
3 Version 1.0
4
5 Copyright © 2004 National ICT Australia Ltd
6
7 All rights reserved.
8
9 By this licence, National ICT Australia Ltd (NICTA) grants permission,
10 free of charge, to any person who obtains a copy of this software
11 and any associated documentation files ("the Software") to use and
12 deal with the Software in source code and binary forms without
13 restriction, with or without modification, and to permit persons
14 to whom the Software is furnished to do so, provided that the
15 following conditions are met:
16
17 - Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimers.
19 - Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimers in
21 the documentation and/or other materials provided with the
22 distribution.
23 - The name of NICTA may not be used to endorse or promote products
24 derived from this Software without specific prior written permission.
25
26 EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
27 PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND
28 NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY
29 KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
30 REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS
31 OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS
32 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT
33 OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR
34 NOT DISCOVERABLE.
35
36 TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL
37 NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
38 NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT
39 LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR
40 CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS,
41 OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS;
42 OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
43 EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE,
44 THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN
45 ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
46
47 If applicable legislation implies warranties or conditions, or
48 imposes obligations or liability on NICTA in respect of the Software
49 that cannot be wholly or partly excluded, restricted or modified,
50 NICTA's liability is limited, to the full extent permitted by the
51 applicable legislation, at its option, to:
52
53 a. in the case of goods, any one or more of the following:
54 i. the replacement of the goods or the supply of equivalent goods;
55 ii. the repair of the goods;
56 iii. the payment of the cost of replacing the goods or of acquiring
57 equivalent goods;
58 iv. the payment of the cost of having the goods repaired; or
59 b. in the case of services:
60 i. the supplying of the services again; or
61 ii. the payment of the cost of having the services supplied
62 again.
63 */
64
65 /*
66 NSSwitch Implementation of mDNS interface.
67
68 Andrew White (Andrew.White@nicta.com.au)
69 May 2004
70 */
71
72 #include <stdlib.h>
73 #include <stdio.h>
74 #include <string.h>
75 #include <errno.h>
76 #include <syslog.h>
77 #include <pthread.h>
78 #include <ctype.h>
79
80 #include <sys/types.h>
81 #include <sys/time.h>
82 #include <sys/socket.h>
83
84 #include <netinet/in.h>
85
86 #include <arpa/inet.h>
87 #define BIND_8_COMPAT 1
88 #include <arpa/nameser.h>
89
90 #include <dns_sd.h>
91
92
93 //----------
94 // Public functions
95
96 /*
97 Count the number of dots in a name string.
98 */
99 int
100 count_dots (const char * name);
101
102
103 /*
104 Test whether a domain name is local.
105
106 Returns
107 1 if name ends with ".local" or ".local."
108 0 otherwise
109 */
110 int
111 islocal (const char * name);
112
113
114 /*
115 Format an address structure as a string appropriate for DNS reverse (PTR)
116 lookup, based on address type.
117
118 Parameters
119 prefixlen
120 Prefix length, in bits. When formatting, this will be rounded up
121 to the nearest appropriate size. If -1, assume maximum.
122 buf
123 Output buffer. Must be long enough to hold largest possible
124 output.
125 Returns
126 Pointer to (first character of) output buffer,
127 or NULL on error.
128 */
129 char *
130 format_reverse_addr (int af, const void * addr, int prefixlen, char * buf);
131
132
133 /*
134 Format an address structure as a string appropriate for DNS reverse (PTR)
135 lookup for AF_INET. Output is in .in-addr.arpa domain.
136
137 Parameters
138 prefixlen
139 Prefix length, in bits. When formatting, this will be rounded up
140 to the nearest byte (8). If -1, assume 32.
141 buf
142 Output buffer. Must be long enough to hold largest possible
143 output. For AF_INET, this is 29 characters (including null).
144 Returns
145 Pointer to (first character of) output buffer,
146 or NULL on error.
147 */
148 char *
149 format_reverse_addr_in (
150 const struct in_addr * addr,
151 int prefixlen,
152 char * buf
153 );
154 #define DNS_PTR_AF_INET_SIZE 29
155
156 /*
157 Format an address structure as a string appropriate for DNS reverse (PTR)
158 lookup for AF_INET6. Output is in .ip6.int domain.
159
160 Parameters
161 prefixlen
162 Prefix length, in bits. When formatting, this will be rounded up
163 to the nearest nibble (4). If -1, assume 128.
164 buf
165 Output buffer. Must be long enough to hold largest possible
166 output. For AF_INET6, this is 72 characters (including null).
167 Returns
168 Pointer to (first character of) output buffer,
169 or NULL on error.
170 */
171 char *
172 format_reverse_addr_in6 (
173 const struct in6_addr * addr,
174 int prefixlen,
175 char * buf
176 );
177 #define DNS_PTR_AF_INET6_SIZE 72
178
179
180 /*
181 Compare whether the given dns name has the given domain suffix.
182 A single leading '.' on the name or leading or trailing '.' on the
183 domain is ignored for the purposes of the comparison.
184 Multiple leading or trailing '.'s are an error. Other DNS syntax
185 errors are not checked for. The comparison is case insensitive.
186
187 Returns
188 1 on success (match)
189 0 on failure (no match)
190 < 0 on error
191 */
192 int
193 cmp_dns_suffix (const char * name, const char * domain);
194 enum
195 {
196 CMP_DNS_SUFFIX_SUCCESS = 1,
197 CMP_DNS_SUFFIX_FAILURE = 0,
198 CMP_DNS_SUFFIX_BAD_NAME = 1,
199 CMP_DNS_SUFFIX_BAD_DOMAIN = -2
200 };
201
202 typedef int ns_type_t;
203 typedef int ns_class_t;
204
205 /*
206 Convert a DNS resource record (RR) code to an address family (AF) code.
207
208 Parameters
209 rrtype
210 resource record type (from nameser.h)
211
212 Returns
213 Appropriate AF code (from socket.h), or AF_UNSPEC if an appropriate
214 mapping couldn't be determined
215 */
216 int
217 rr_to_af (ns_type_t rrtype);
218
219
220 /*
221 Convert an address family (AF) code to a DNS resource record (RR) code.
222
223 Parameters
224 int
225 address family code (from socket.h)
226 Returns
227 Appropriate RR code (from nameser.h), or ns_t_invalid if an appropriate
228 mapping couldn't be determined
229 */
230 ns_type_t
231 af_to_rr (int af);
232
233
234 /*
235 Convert a string to an address family (case insensitive).
236
237 Returns
238 Matching AF code, or AF_UNSPEC if no match found.
239 */
240 int
241 str_to_af (const char * str);
242
243
244 /*
245 Convert a string to an ns_class_t (case insensitive).
246
247 Returns
248 Matching ns_class_t, or ns_c_invalid if no match found.
249 */
250 ns_class_t
251 str_to_ns_class (const char * str);
252
253
254 /*
255 Convert a string to an ns_type_t (case insensitive).
256
257 Returns
258 Matching ns_type_t, or ns_t_invalid if no match found.
259 */
260 ns_type_t
261 str_to_ns_type (const char * str);
262
263
264 /*
265 Convert an address family code to a string.
266
267 Returns
268 String representation of AF,
269 or NULL if address family unrecognised or invalid.
270 */
271 const char *
272 af_to_str (int in);
273
274
275 /*
276 Convert an ns_class_t code to a string.
277
278 Returns
279 String representation of ns_class_t,
280 or NULL if ns_class_t unrecognised or invalid.
281 */
282 const char *
283 ns_class_to_str (ns_class_t in);
284
285
286 /*
287 Convert an ns_type_t code to a string.
288
289 Returns
290 String representation of ns_type_t,
291 or NULL if ns_type_t unrecognised or invalid.
292 */
293 const char *
294 ns_type_to_str (ns_type_t in);
295
296
297 /*
298 Convert DNS rdata in label format (RFC1034, RFC1035) to a name.
299
300 On error, partial data is written to name (as much as was successfully
301 processed) and an error code is returned. Errors include a name too
302 long for the buffer and a pointer in the label (which cannot be
303 resolved).
304
305 Parameters
306 rdata
307 Rdata formatted as series of labels.
308 rdlen
309 Length of rdata buffer.
310 name
311 Buffer to store fully qualified result in.
312 By RFC1034 section 3.1, a 255 character buffer (256 characters
313 including null) is long enough for any legal name.
314 name_len
315 Number of characters available in name buffer, not including
316 trailing null.
317
318 Returns
319 Length of name buffer (not including trailing null).
320 < 0 on error.
321 A return of 0 implies the empty domain.
322 */
323 int
324 dns_rdata_to_name (const char * rdata, int rdlen, char * name, int name_len);
325 enum
326 {
327 DNS_RDATA_TO_NAME_BAD_FORMAT = -1,
328 // Format is broken. Usually because we ran out of data
329 // (according to rdata) before the labels said we should.
330 DNS_RDATA_TO_NAME_TOO_LONG = -2,
331 // The converted rdata is longer than the name buffer.
332 DNS_RDATA_TO_NAME_PTR = -3,
333 // The rdata contains a pointer.
334 };
335
336 #define DNS_LABEL_MAXLEN 63
337 // Maximum length of a single DNS label
338 #define DNS_NAME_MAXLEN 255
339 // Maximum length of a DNS name
340
341 //----------
342 // Public types
343
344 typedef int errcode_t;
345 // Used for 0 = success, non-zero = error code functions
346
347
348 //----------
349 // Public functions
350
351 /*
352 Test whether a domain name is in a domain covered by nss_mdns.
353 The name is assumed to be fully qualified (trailing dot optional);
354 unqualified names will be processed but may return unusual results
355 if the unqualified prefix happens to match a domain suffix.
356
357 Returns
358 1 success
359 0 failure
360 -1 error, check errno
361 */
362 int
363 config_is_mdns_suffix (const char * name);
364
365
366 /*
367 Loads all relevant data from configuration file. Other code should
368 rarely need to call this function, since all other public configuration
369 functions do so implicitly. Once loaded, configuration info doesn't
370 change.
371
372 Returns
373 0 configuration ready
374 non-zero configuration error code
375 */
376 errcode_t
377 init_config ();
378
379 #define ENTNAME hostent
380 #define DATABASE "hosts"
381
382 #include <nss.h>
383 // For nss_status
384 #include <netdb.h>
385 // For hostent
386 #include <sys/types.h>
387 // For size_t
388
389 typedef enum nss_status nss_status;
390 typedef struct hostent hostent;
391
392 /*
393 gethostbyname implementation
394
395 name:
396 name to look up
397 result_buf:
398 resulting entry
399 buf:
400 auxillary buffer
401 buflen:
402 length of auxillary buffer
403 errnop:
404 pointer to errno
405 h_errnop:
406 pointer to h_errno
407 */
408 nss_status
409 _nss_mdns_gethostbyname_r (
410 const char *name,
411 hostent * result_buf,
412 char *buf,
413 size_t buflen,
414 int *errnop,
415 int *h_errnop
416 );
417
418
419 /*
420 gethostbyname2 implementation
421
422 name:
423 name to look up
424 af:
425 address family
426 result_buf:
427 resulting entry
428 buf:
429 auxillary buffer
430 buflen:
431 length of auxillary buffer
432 errnop:
433 pointer to errno
434 h_errnop:
435 pointer to h_errno
436 */
437 nss_status
438 _nss_mdns_gethostbyname2_r (
439 const char *name,
440 int af,
441 hostent * result_buf,
442 char *buf,
443 size_t buflen,
444 int *errnop,
445 int *h_errnop
446 );
447
448
449 /*
450 gethostbyaddr implementation
451
452 addr:
453 address structure to look up
454 len:
455 length of address structure
456 af:
457 address family
458 result_buf:
459 resulting entry
460 buf:
461 auxillary buffer
462 buflen:
463 length of auxillary buffer
464 errnop:
465 pointer to errno
466 h_errnop:
467 pointer to h_errno
468 */
469 nss_status
470 _nss_mdns_gethostbyaddr_r (
471 const void *addr,
472 socklen_t len,
473 int af,
474 hostent * result_buf,
475 char *buf,
476 size_t buflen,
477 int *errnop,
478 int *h_errnop
479 );
480
481
482 //----------
483 // Types and Constants
484
485 const int MDNS_VERBOSE = 0;
486 // This enables verbose syslog messages
487 // If zero, only "imporant" messages will appear in syslog
488
489 #define k_hostname_maxlen 255
490 // As per RFC1034 and RFC1035
491 #define k_aliases_max 15
492 #define k_addrs_max 15
493
494 const int k_mdnsd_intfs_local = 0;
495 // Tell mdnsd to perform lookups only using link-local interfaces.
496 /*
497 Currently, this feature is buggy. 0 will actually cause mdnsd to
498 do what it thinks is best. Unfortunately, this is to lookup 'local'
499 addresses locally and remote addresses via the DNS. Thus, lookups
500 for non-"local" addresses via mdns will not work correctly.
501
502 Apple is currently modifying mdnsd to allow a special interface id
503 (expected value -2) to mean "always lookup locally". This constant
504 should be changed once the change is made.
505
506 AW - 16 June 2004
507 */
508
509
510 typedef struct buf_header
511 {
512 char hostname [k_hostname_maxlen + 1];
513 char * aliases [k_aliases_max + 1];
514 char * addrs [k_addrs_max + 1];
515 } buf_header_t;
516
517 typedef struct result_map
518 {
519 int done;
520 nss_status status;
521 hostent * hostent;
522 buf_header_t * header;
523 int aliases_count;
524 int addrs_count;
525 char * buffer;
526 int addr_idx;
527 // Index for addresses - grow from low end
528 // Index points to first empty space
529 int alias_idx;
530 // Index for aliases - grow from high end
531 // Index points to lowest entry
532 int r_errno;
533 int r_h_errno;
534 } result_map_t;
535
536 static const struct timeval
537 k_select_time = { 0, 500000 };
538 // 0 seconds, 500 milliseconds
539
540 //----------
541 // Local prototypes
542
543 static nss_status
544 mdns_gethostbyname2 (
545 const char *name,
546 int af,
547 hostent * result_buf,
548 char *buf,
549 size_t buflen,
550 int *errnop,
551 int *h_errnop
552 );
553
554
555 /*
556 Lookup name using mDNS server
557 */
558 static nss_status
559 mdns_lookup_name (
560 const char * fullname,
561 int af,
562 result_map_t * result
563 );
564
565 /*
566 Lookup address using mDNS server
567 */
568 static nss_status
569 mdns_lookup_addr (
570 const void * addr,
571 socklen_t len,
572 int af,
573 const char * addr_str,
574 result_map_t * result
575 );
576
577
578 /*
579 Handle incoming MDNS events
580 */
581 static nss_status
582 handle_events (DNSServiceRef sdref, result_map_t * result, const char * str);
583
584
585 // Callback for mdns_lookup operations
586 //DNSServiceQueryRecordReply mdns_lookup_callback;
587 typedef void
588 mdns_lookup_callback_t
589 (
590 DNSServiceRef sdref,
591 DNSServiceFlags flags,
592 uint32_t interface_index,
593 DNSServiceErrorType error_code,
594 const char *fullname,
595 uint16_t rrtype,
596 uint16_t rrclass,
597 uint16_t rdlen,
598 const void *rdata,
599 uint32_t ttl,
600 void *context
601 );
602
603 mdns_lookup_callback_t mdns_lookup_callback;
604
605
606 static int
607 init_result (
608 result_map_t * result,
609 hostent * result_buf,
610 char * buf,
611 size_t buflen
612 );
613
614 static int
615 callback_body_ptr (
616 const char * fullname,
617 result_map_t * result,
618 int rdlen,
619 const void * rdata
620 );
621
622 static void *
623 add_address_to_buffer (result_map_t * result, const void * data, int len);
624 static char *
625 add_alias_to_buffer (result_map_t * result, const char * data, int len);
626 static char *
627 add_hostname_len (result_map_t * result, const char * fullname, int len);
628 static char *
629 add_hostname_or_alias (result_map_t * result, const char * data, int len);
630
631 static void *
632 contains_address (result_map_t * result, const void * data, int len);
633 static char *
634 contains_alias (result_map_t * result, const char * data);
635
636
637 static const char *
638 is_applicable_name (
639 result_map_t * result,
640 const char * name,
641 char * lookup_name
642 );
643
644 static const char *
645 is_applicable_addr (
646 result_map_t * result,
647 const void * addr,
648 int af,
649 char * addr_str
650 );
651
652
653 // Error code functions
654
655 static nss_status
656 set_err (result_map_t * result, nss_status status, int err, int herr);
657
658 static nss_status set_err_notfound (result_map_t * result);
659 static nss_status set_err_bad_hostname (result_map_t * result);
660 static nss_status set_err_buf_too_small (result_map_t * result);
661 static nss_status set_err_internal_resource_full (result_map_t * result);
662 static nss_status set_err_system (result_map_t * result);
663 static nss_status set_err_mdns_failed (result_map_t * result);
664 static nss_status set_err_success (result_map_t * result);
665
666
667 //----------
668 // Global variables
669
670
671 //----------
672 // NSS functions
673
674 nss_status
675 _nss_mdns_gethostbyname_r (
676 const char *name,
677 hostent * result_buf,
678 char *buf,
679 size_t buflen,
680 int *errnop,
681 int *h_errnop
682 )
683 {
684 if (MDNS_VERBOSE)
685 syslog (LOG_DEBUG,
686 "mdns: Called nss_mdns_gethostbyname with %s",
687 name
688 );
689
690 return
691 mdns_gethostbyname2 (
692 name, AF_INET, result_buf, buf, buflen, errnop, h_errnop
693 );
694 }
695
696
697 nss_status
698 _nss_mdns_gethostbyname2_r (
699 const char *name,
700 int af,
701 hostent * result_buf,
702 char *buf,
703 size_t buflen,
704 int *errnop,
705 int *h_errnop
706 )
707 {
708 if (MDNS_VERBOSE)
709 syslog (LOG_DEBUG,
710 "mdns: Called nss_mdns_gethostbyname2 with %s",
711 name
712 );
713
714 return
715 mdns_gethostbyname2 (
716 name, af, result_buf, buf, buflen, errnop, h_errnop
717 );
718 }
719
720
721 nss_status
722 _nss_mdns_gethostbyaddr_r (
723 const void *addr,
724 socklen_t len,
725 int af,
726 hostent * result_buf,
727 char *buf,
728 size_t buflen,
729 int *errnop,
730 int *h_errnop
731 )
732 {
733 char addr_str [NI_MAXHOST + 1];
734 result_map_t result;
735 int err_status;
736
737 if (inet_ntop (af, addr, addr_str, NI_MAXHOST) == NULL)
738 {
739 const char * family = af_to_str (af);
740 if (family == NULL)
741 {
742 family = "Unknown";
743 }
744
745 syslog (LOG_WARNING,
746 "mdns: Couldn't covert address, family %d (%s) in nss_mdns_gethostbyaddr: %s",
747 af,
748 family,
749 strerror (errno)
750 );
751
752 // This address family never applicable to us, so return NOT_FOUND
753
754 *errnop = ENOENT;
755 *h_errnop = HOST_NOT_FOUND;
756 return NSS_STATUS_NOTFOUND;
757 }
758 if (MDNS_VERBOSE)
759 {
760 syslog (LOG_DEBUG,
761 "mdns: Called nss_mdns_gethostbyaddr with %s",
762 addr_str
763 );
764 }
765
766 // Initialise result
767 err_status = init_result (&result, result_buf, buf, buflen);
768 if (err_status)
769 {
770 *errnop = err_status;
771 *h_errnop = NETDB_INTERNAL;
772 return NSS_STATUS_TRYAGAIN;
773 }
774
775 if (is_applicable_addr (&result, addr, af, addr_str))
776 {
777 nss_status rv;
778
779 rv = mdns_lookup_addr (addr, len, af, addr_str, &result);
780 if (rv == NSS_STATUS_SUCCESS)
781 {
782 return rv;
783 }
784 }
785
786 // Return current error status (defaults to NOT_FOUND)
787
788 *errnop = result.r_errno;
789 *h_errnop = result.r_h_errno;
790 return result.status;
791 }
792
793
794 //----------
795 // Local functions
796
797 nss_status
798 mdns_gethostbyname2 (
799 const char *name,
800 int af,
801 hostent * result_buf,
802 char *buf,
803 size_t buflen,
804 int *errnop,
805 int *h_errnop
806 )
807 {
808 char lookup_name [k_hostname_maxlen + 1];
809 result_map_t result;
810 int err_status;
811
812 // Initialise result
813 err_status = init_result (&result, result_buf, buf, buflen);
814 if (err_status)
815 {
816 *errnop = err_status;
817 *h_errnop = NETDB_INTERNAL;
818 return NSS_STATUS_TRYAGAIN;
819 }
820
821 if (is_applicable_name (&result, name, lookup_name))
822 {
823 // Try using mdns
824 nss_status rv;
825
826 if (MDNS_VERBOSE)
827 syslog (LOG_DEBUG,
828 "mdns: Local name: %s",
829 name
830 );
831
832 rv = mdns_lookup_name (name, af, &result);
833 if (rv == NSS_STATUS_SUCCESS)
834 {
835 return rv;
836 }
837 }
838
839 // Return current error status (defaults to NOT_FOUND)
840
841 *errnop = result.r_errno;
842 *h_errnop = result.r_h_errno;
843 return result.status;
844 }
845
846
847 /*
848 Lookup a fully qualified hostname using the default record type
849 for the specified address family.
850
851 Parameters
852 fullname
853 Fully qualified hostname. If not fully qualified the code will
854 still 'work', but the lookup is unlikely to succeed.
855 af
856 Either AF_INET or AF_INET6. Other families are not supported.
857 result
858 Initialised 'result' data structure.
859 */
860 static nss_status
861 mdns_lookup_name (
862 const char * fullname,
863 int af,
864 result_map_t * result
865 )
866 {
867 // Lookup using mDNS.
868 DNSServiceErrorType errcode;
869 DNSServiceRef sdref;
870 ns_type_t rrtype;
871
872 if (MDNS_VERBOSE)
873 syslog (LOG_DEBUG,
874 "mdns: Attempting lookup of %s",
875 fullname
876 );
877
878 switch (af)
879 {
880 case AF_INET:
881 rrtype = T_A;
882 result->hostent->h_length = 4;
883 // Length of an A record
884 break;
885
886 case AF_INET6:
887 rrtype = T_AAAA;
888 result->hostent->h_length = 16;
889 // Length of an AAAA record
890 break;
891
892 default:
893 syslog (LOG_WARNING,
894 "mdns: Unsupported address family %d",
895 af
896 );
897 return set_err_bad_hostname (result);
898 }
899 result->hostent->h_addrtype = af;
900
901 errcode =
902 DNSServiceQueryRecord (
903 &sdref,
904 0, // reserved flags field
905 k_mdnsd_intfs_local, // all local interfaces
906 fullname, // full name to query for
907 rrtype, // resource record type
908 C_IN, // internet class records
909 mdns_lookup_callback, // callback
910 result // Context - result buffer
911 );
912
913 if (errcode)
914 {
915 syslog (LOG_WARNING,
916 "mdns: Failed to initialise lookup, error %d",
917 errcode
918 );
919 return set_err_mdns_failed (result);
920 }
921
922 return handle_events (sdref, result, fullname);
923 }
924
925
926 /*
927 Reverse (PTR) lookup for the specified address.
928
929 Parameters
930 addr
931 Either a struct in_addr or a struct in6_addr
932 addr_len
933 size of the address
934 af
935 Either AF_INET or AF_INET6. Other families are not supported.
936 Must match addr
937 addr_str
938 Address in format suitable for PTR lookup.
939 AF_INET: a.b.c.d -> d.c.b.a.in-addr.arpa
940 AF_INET6: reverse nibble format, x.x.x...x.ip6.arpa
941 result
942 Initialised 'result' data structure.
943 */
944 static nss_status
945 mdns_lookup_addr (
946 const void * addr,
947 socklen_t addr_len,
948 int af,
949 const char * addr_str,
950 result_map_t * result
951 )
952 {
953 DNSServiceErrorType errcode;
954 DNSServiceRef sdref;
955
956 if (MDNS_VERBOSE)
957 syslog (LOG_DEBUG,
958 "mdns: Attempting lookup of %s",
959 addr_str
960 );
961
962 result->hostent->h_addrtype = af;
963 result->hostent->h_length = addr_len;
964
965 // Query address becomes "address" in result.
966 if (! add_address_to_buffer (result, addr, addr_len))
967 {
968 return result->status;
969 }
970
971 result->hostent->h_name [0] = 0;
972
973 errcode =
974 DNSServiceQueryRecord (
975 &sdref,
976 0, // reserved flags field
977 k_mdnsd_intfs_local, // all local interfaces
978 addr_str, // address string to query for
979 T_PTR, // pointer RRs
980 C_IN, // internet class records
981 mdns_lookup_callback, // callback
982 result // Context - result buffer
983 );
984
985 if (errcode)
986 {
987 syslog (LOG_WARNING,
988 "mdns: Failed to initialise mdns lookup, error %d",
989 errcode
990 );
991 return set_err_mdns_failed (result);
992 }
993
994 return handle_events (sdref, result, addr_str);
995 }
996
997
998 /*
999 Wait on result of callback, and process it when it arrives.
1000
1001 Parameters
1002 sdref
1003 dns-sd reference
1004 result
1005 Initialised 'result' data structure.
1006 str
1007 lookup string, used for status/error reporting.
1008 */
1009 static nss_status
1010 handle_events (DNSServiceRef sdref, result_map_t * result, const char * str)
1011 {
1012 int dns_sd_fd = DNSServiceRefSockFD(sdref);
1013 int nfds = dns_sd_fd + 1;
1014 fd_set readfds;
1015 struct timeval tv;
1016 int select_result;
1017
1018 while (! result->done)
1019 {
1020 FD_ZERO(&readfds);
1021 FD_SET(dns_sd_fd, &readfds);
1022
1023 tv = k_select_time;
1024
1025 select_result =
1026 select (nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1027 if (select_result > 0)
1028 {
1029 if (FD_ISSET(dns_sd_fd, &readfds))
1030 {
1031 if (MDNS_VERBOSE)
1032 syslog (LOG_DEBUG,
1033 "mdns: Reply received for %s",
1034 str
1035 );
1036 DNSServiceProcessResult(sdref);
1037 }
1038 else
1039 {
1040 syslog (LOG_WARNING,
1041 "mdns: Unexpected return from select on lookup of %s",
1042 str
1043 );
1044 }
1045 }
1046 else
1047 {
1048 // Terminate loop due to timer expiry
1049 if (MDNS_VERBOSE)
1050 syslog (LOG_DEBUG,
1051 "mdns: %s not found - timer expired",
1052 str
1053 );
1054 set_err_notfound (result);
1055 break;
1056 }
1057 }
1058
1059 return result->status;
1060 }
1061
1062
1063 /*
1064 Examine incoming data and add to relevant fields in result structure.
1065 This routine is called from DNSServiceProcessResult where appropriate.
1066 */
1067 void
1068 mdns_lookup_callback
1069 (
1070 DNSServiceRef sdref,
1071 DNSServiceFlags flags,
1072 uint32_t interface_index,
1073 DNSServiceErrorType error_code,
1074 const char *fullname,
1075 uint16_t rrtype,
1076 uint16_t rrclass,
1077 uint16_t rdlen,
1078 const void *rdata,
1079 uint32_t ttl,
1080 void *context
1081 )
1082 {
1083 // A single record is received
1084
1085 result_map_t * result = (result_map_t *) context;
1086
1087 (void)sdref; // Unused
1088 (void)interface_index; // Unused
1089 (void)ttl; // Unused
1090
1091 if (! (flags & kDNSServiceFlagsMoreComing) )
1092 {
1093 result->done = 1;
1094 }
1095
1096 if (error_code == kDNSServiceErr_NoError)
1097 {
1098 ns_type_t expected_rr_type =
1099 af_to_rr (result->hostent->h_addrtype);
1100
1101 // Idiot check class
1102 if (rrclass != C_IN)
1103 {
1104 syslog (LOG_WARNING,
1105 "mdns: Received bad RR class: expected %d (%s),"
1106 " got %d (%s), RR type %d (%s)",
1107 C_IN,
1108 ns_class_to_str (C_IN),
1109 rrclass,
1110 ns_class_to_str (rrclass),
1111 rrtype,
1112 ns_type_to_str (rrtype)
1113 );
1114 return;
1115 }
1116
1117 // If a PTR
1118 if (rrtype == T_PTR)
1119 {
1120 if (callback_body_ptr (fullname, result, rdlen, rdata) < 0)
1121 return;
1122 }
1123 else if (rrtype == expected_rr_type)
1124 {
1125 if (!
1126 add_hostname_or_alias (
1127 result,
1128 fullname,
1129 strlen (fullname)
1130 )
1131 )
1132 {
1133 result->done = 1;
1134 return;
1135 // Abort on error
1136 }
1137
1138 if (! add_address_to_buffer (result, rdata, rdlen) )
1139 {
1140 result->done = 1;
1141 return;
1142 // Abort on error
1143 }
1144 }
1145 else
1146 {
1147 syslog (LOG_WARNING,
1148 "mdns: Received bad RR type: expected %d (%s),"
1149 " got %d (%s)",
1150 expected_rr_type,
1151 ns_type_to_str (expected_rr_type),
1152 rrtype,
1153 ns_type_to_str (rrtype)
1154 );
1155 return;
1156 }
1157
1158 if (result->status != NSS_STATUS_SUCCESS)
1159 set_err_success (result);
1160 }
1161 else
1162 {
1163 // For now, dump message to syslog and continue
1164 syslog (LOG_WARNING,
1165 "mdns: callback returned error %d",
1166 error_code
1167 );
1168 }
1169 }
1170
1171 static int
1172 callback_body_ptr (
1173 const char * fullname,
1174 result_map_t * result,
1175 int rdlen,
1176 const void * rdata
1177 )
1178 {
1179 char result_name [k_hostname_maxlen + 1];
1180 int rv;
1181
1182 // Fullname should be .in-addr.arpa or equivalent, which we're
1183 // not interested in. Ignore it.
1184
1185 rv = dns_rdata_to_name (rdata, rdlen, result_name, k_hostname_maxlen);
1186 if (rv < 0)
1187 {
1188 const char * errmsg;
1189
1190 switch (rv)
1191 {
1192 case DNS_RDATA_TO_NAME_BAD_FORMAT:
1193 errmsg = "mdns: PTR '%s' result badly formatted ('%s...')";
1194 break;
1195
1196 case DNS_RDATA_TO_NAME_TOO_LONG:
1197 errmsg = "mdns: PTR '%s' result too long ('%s...')";
1198 break;
1199
1200 case DNS_RDATA_TO_NAME_PTR:
1201 errmsg = "mdns: PTR '%s' result contained pointer ('%s...')";
1202 break;
1203
1204 default:
1205 errmsg = "mdns: PTR '%s' result conversion failed ('%s...')";
1206 }
1207
1208 syslog (LOG_WARNING,
1209 errmsg,
1210 fullname,
1211 result_name
1212 );
1213
1214 return -1;
1215 }
1216
1217 if (MDNS_VERBOSE)
1218 {
1219 syslog (LOG_DEBUG,
1220 "mdns: PTR '%s' resolved to '%s'",
1221 fullname,
1222 result_name
1223 );
1224 }
1225
1226 // Data should be a hostname
1227 if (!
1228 add_hostname_or_alias (
1229 result,
1230 result_name,
1231 rv
1232 )
1233 )
1234 {
1235 result->done = 1;
1236 return -1;
1237 }
1238
1239 return 0;
1240 }
1241
1242
1243 /*
1244 Add an address to the buffer.
1245
1246 Parameter
1247 result
1248 Result structure to write to
1249 data
1250 Incoming address data buffer
1251 Must be 'int' aligned
1252 len
1253 Length of data buffer (in bytes)
1254 Must match data alignment
1255
1256 Result
1257 Pointer to start of newly written data,
1258 or NULL on error.
1259 If address already exists in buffer, returns pointer to that instead.
1260 */
1261 static void *
1262 add_address_to_buffer (result_map_t * result, const void * data, int len)
1263 {
1264 int new_addr;
1265 void * start;
1266 void * temp;
1267
1268 if ((temp = contains_address (result, data, len)))
1269 {
1270 return temp;
1271 }
1272
1273 if (result->addrs_count >= k_addrs_max)
1274 {
1275 // Not enough addr slots
1276 set_err_internal_resource_full (result);
1277 syslog (LOG_ERR,
1278 "mdns: Internal address buffer full; increase size"
1279 );
1280 return NULL;
1281 }
1282
1283 // Idiot check
1284 if (len != result->hostent->h_length)
1285 {
1286 syslog (LOG_WARNING,
1287 "mdns: Unexpected rdata length for address. Expected %d, got %d",
1288 result->hostent->h_length,
1289 len
1290 );
1291 // XXX And continue for now.
1292 }
1293
1294 new_addr = result->addr_idx + len;
1295
1296 if (new_addr > result->alias_idx)
1297 {
1298 // Not enough room
1299 set_err_buf_too_small (result);
1300 if (MDNS_VERBOSE)
1301 syslog (LOG_DEBUG,
1302 "mdns: Ran out of buffer when adding address %d",
1303 result->addrs_count + 1
1304 );
1305 return NULL;
1306 }
1307
1308 start = result->buffer + result->addr_idx;
1309 memcpy (start, data, len);
1310 result->addr_idx = new_addr;
1311 result->header->addrs [result->addrs_count] = start;
1312 result->addrs_count ++;
1313 result->header->addrs [result->addrs_count] = NULL;
1314
1315 return start;
1316 }
1317
1318
1319 static void *
1320 contains_address (result_map_t * result, const void * data, int len)
1321 {
1322 int i;
1323
1324 // Idiot check
1325 if (len != result->hostent->h_length)
1326 {
1327 syslog (LOG_WARNING,
1328 "mdns: Unexpected rdata length for address. Expected %d, got %d",
1329 result->hostent->h_length,
1330 len
1331 );
1332 // XXX And continue for now.
1333 }
1334
1335 for (i = 0; result->header->addrs [i]; i++)
1336 {
1337 if (memcmp (result->header->addrs [i], data, len) == 0)
1338 {
1339 return result->header->addrs [i];
1340 }
1341 }
1342
1343 return NULL;
1344 }
1345
1346
1347 /*
1348 Add an alias to the buffer.
1349
1350 Parameter
1351 result
1352 Result structure to write to
1353 data
1354 Incoming alias (null terminated)
1355 len
1356 Length of data buffer (in bytes), including trailing null
1357
1358 Result
1359 Pointer to start of newly written data,
1360 or NULL on error
1361 If alias already exists in buffer, returns pointer to that instead.
1362 */
1363 static char *
1364 add_alias_to_buffer (result_map_t * result, const char * data, int len)
1365 {
1366 int new_alias;
1367 char * start;
1368 char * temp;
1369
1370 if ((temp = contains_alias (result, data)))
1371 {
1372 return temp;
1373 }
1374
1375 if (result->aliases_count >= k_aliases_max)
1376 {
1377 // Not enough alias slots
1378 set_err_internal_resource_full (result);
1379 syslog (LOG_ERR,
1380 "mdns: Internal alias buffer full; increase size"
1381 );
1382 return NULL;
1383 }
1384
1385 new_alias = result->alias_idx - len;
1386
1387 if (new_alias < result->addr_idx)
1388 {
1389 // Not enough room
1390 set_err_buf_too_small (result);
1391 if (MDNS_VERBOSE)
1392 syslog (LOG_DEBUG,
1393 "mdns: Ran out of buffer when adding alias %d",
1394 result->aliases_count + 1
1395 );
1396 return NULL;
1397 }
1398
1399 start = result->buffer + new_alias;
1400 memcpy (start, data, len);
1401 result->alias_idx = new_alias;
1402 result->header->aliases [result->aliases_count] = start;
1403 result->aliases_count ++;
1404 result->header->aliases [result->aliases_count] = NULL;
1405
1406 return start;
1407 }
1408
1409
1410 static char *
1411 contains_alias (result_map_t * result, const char * alias)
1412 {
1413 int i;
1414
1415 for (i = 0; result->header->aliases [i]; i++)
1416 {
1417 if (strcmp (result->header->aliases [i], alias) == 0)
1418 {
1419 return result->header->aliases [i];
1420 }
1421 }
1422
1423 return NULL;
1424 }
1425
1426
1427 /*
1428 Add fully qualified hostname to result.
1429
1430 Parameter
1431 result
1432 Result structure to write to
1433 fullname
1434 Fully qualified hostname
1435
1436 Result
1437 Pointer to start of hostname buffer,
1438 or NULL on error (usually hostname too long)
1439 */
1440
1441 static char *
1442 add_hostname_len (result_map_t * result, const char * fullname, int len)
1443 {
1444 if (len >= k_hostname_maxlen)
1445 {
1446 set_err_bad_hostname (result);
1447 syslog (LOG_WARNING,
1448 "mdns: Hostname too long '%.*s': len %d, max %d",
1449 len,
1450 fullname,
1451 len,
1452 k_hostname_maxlen
1453 );
1454 return NULL;
1455 }
1456
1457 result->hostent->h_name =
1458 strcpy (result->header->hostname, fullname);
1459
1460 return result->header->hostname;
1461 }
1462
1463
1464 /*
1465 Add fully qualified name as hostname or alias.
1466
1467 If hostname is not fully qualified this is not an error, but the data
1468 returned may be not what the application wanted.
1469
1470 Parameter
1471 result
1472 Result structure to write to
1473 data
1474 Incoming alias (null terminated)
1475 len
1476 Length of data buffer (in bytes), including trailing null
1477
1478 Result
1479 Pointer to start of newly written data,
1480 or NULL on error
1481 If alias or hostname already exists, returns pointer to that instead.
1482 */
1483 static char *
1484 add_hostname_or_alias (result_map_t * result, const char * data, int len)
1485 {
1486 char * hostname = result->hostent->h_name;
1487
1488 if (*hostname)
1489 {
1490 if (strcmp (hostname, data) == 0)
1491 {
1492 return hostname;
1493 }
1494 else
1495 {
1496 return add_alias_to_buffer (result, data, len);
1497 }
1498 }
1499 else
1500 {
1501 return add_hostname_len (result, data, len);
1502 }
1503 }
1504
1505
1506 static int
1507 init_result (
1508 result_map_t * result,
1509 hostent * result_buf,
1510 char * buf,
1511 size_t buflen
1512 )
1513 {
1514 if (buflen < sizeof (buf_header_t))
1515 {
1516 return ERANGE;
1517 }
1518
1519 result->hostent = result_buf;
1520 result->header = (buf_header_t *) buf;
1521 result->header->hostname[0] = 0;
1522 result->aliases_count = 0;
1523 result->header->aliases[0] = NULL;
1524 result->addrs_count = 0;
1525 result->header->addrs[0] = NULL;
1526 result->buffer = buf + sizeof (buf_header_t);
1527 result->addr_idx = 0;
1528 result->alias_idx = buflen - sizeof (buf_header_t);
1529 result->done = 0;
1530 set_err_notfound (result);
1531
1532 // Point hostent to the right buffers
1533 result->hostent->h_name = result->header->hostname;
1534 result->hostent->h_aliases = result->header->aliases;
1535 result->hostent->h_addr_list = result->header->addrs;
1536
1537 return 0;
1538 }
1539
1540 /*
1541 Set the status in the result.
1542
1543 Parameters
1544 result
1545 Result structure to update
1546 status
1547 New nss_status value
1548 err
1549 New errno value
1550 herr
1551 New h_errno value
1552
1553 Returns
1554 New status value
1555 */
1556 static nss_status
1557 set_err (result_map_t * result, nss_status status, int err, int herr)
1558 {
1559 result->status = status;
1560 result->r_errno = err;
1561 result->r_h_errno = herr;
1562
1563 return status;
1564 }
1565
1566 static nss_status
1567 set_err_notfound (result_map_t * result)
1568 {
1569 return set_err (result, NSS_STATUS_NOTFOUND, ENOENT, HOST_NOT_FOUND);
1570 }
1571
1572 static nss_status
1573 set_err_bad_hostname (result_map_t * result)
1574 {
1575 return set_err (result, NSS_STATUS_TRYAGAIN, ENOENT, NO_RECOVERY);
1576 }
1577
1578 static nss_status
1579 set_err_buf_too_small (result_map_t * result)
1580 {
1581 return set_err (result, NSS_STATUS_TRYAGAIN, ERANGE, NETDB_INTERNAL);
1582 }
1583
1584 static nss_status
1585 set_err_internal_resource_full (result_map_t * result)
1586 {
1587 return set_err (result, NSS_STATUS_RETURN, ERANGE, NO_RECOVERY);
1588 }
1589
1590 static nss_status
1591 set_err_system (result_map_t * result)
1592 {
1593 return set_err (result, NSS_STATUS_UNAVAIL, errno, NETDB_INTERNAL);
1594 }
1595
1596 static nss_status
1597 set_err_mdns_failed (result_map_t * result)
1598 {
1599 return set_err (result, NSS_STATUS_TRYAGAIN, EAGAIN, TRY_AGAIN);
1600 }
1601
1602 static nss_status
1603 set_err_success (result_map_t * result)
1604 {
1605 result->status = NSS_STATUS_SUCCESS;
1606 return result->status;
1607 }
1608
1609
1610 /*
1611 Test whether name is applicable for mdns to process, and if so copy into
1612 lookup_name buffer (if non-NULL).
1613
1614 Returns
1615 Pointer to name to lookup up, if applicable, or NULL otherwise.
1616 */
1617 static const char *
1618 is_applicable_name (
1619 result_map_t * result,
1620 const char * name,
1621 char * lookup_name
1622 )
1623 {
1624 int match = config_is_mdns_suffix (name);
1625 if (match > 0)
1626 {
1627 if (lookup_name)
1628 {
1629 strncpy (lookup_name, name, k_hostname_maxlen + 1);
1630 return lookup_name;
1631 }
1632 else
1633 {
1634 return name;
1635 }
1636 }
1637 else
1638 {
1639 if (match < 0)
1640 {
1641 set_err_system (result);
1642 }
1643 return NULL;
1644 }
1645 }
1646
1647 /*
1648 Test whether address is applicable for mdns to process, and if so copy into
1649 addr_str buffer as an address suitable for ptr lookup.
1650
1651 Returns
1652 Pointer to name to lookup up, if applicable, or NULL otherwise.
1653 */
1654 static const char *
1655 is_applicable_addr (
1656 result_map_t * result,
1657 const void * addr,
1658 int af,
1659 char * addr_str
1660 )
1661 {
1662 int match;
1663
1664 if (! format_reverse_addr (af, addr, -1, addr_str))
1665 {
1666 if (MDNS_VERBOSE)
1667 syslog (LOG_DEBUG,
1668 "mdns: Failed to create reverse address"
1669 );
1670 return NULL;
1671 }
1672
1673 if (MDNS_VERBOSE)
1674 syslog (LOG_DEBUG,
1675 "mdns: Reverse address: %s",
1676 addr_str
1677 );
1678
1679 match = config_is_mdns_suffix (addr_str);
1680 if (match > 0)
1681 {
1682 return addr_str;
1683 }
1684 else
1685 {
1686 if (match < 0)
1687 {
1688 set_err_system (result);
1689 }
1690 return NULL;
1691 }
1692 }
1693
1694 //----------
1695 // Types and Constants
1696
1697 const char * k_conf_file = "/etc/nss_mdns.conf";
1698 #define CONF_LINE_SIZE 1024
1699
1700 const char k_comment_char = '#';
1701
1702 const char * k_keyword_domain = "domain";
1703
1704 const char * k_default_domains [] =
1705 {
1706 "local",
1707 "254.169.in-addr.arpa",
1708 "0.8.e.f.ip6.int",
1709 "0.8.e.f.ip6.arpa",
1710 NULL
1711 // Always null terminated
1712 };
1713
1714 // Linked list of domains
1715 typedef struct domain_entry
1716 {
1717 char * domain;
1718 struct domain_entry * next;
1719 } domain_entry_t;
1720
1721
1722 // Config
1723 typedef struct
1724 {
1725 domain_entry_t * domains;
1726 } config_t;
1727
1728 const config_t k_empty_config =
1729 {
1730 NULL
1731 };
1732
1733
1734 // Context - tracks position in config file, used for error reporting
1735 typedef struct
1736 {
1737 const char * filename;
1738 int linenum;
1739 } config_file_context_t;
1740
1741
1742 //----------
1743 // Local prototypes
1744
1745 static errcode_t
1746 load_config (config_t * conf);
1747
1748 static errcode_t
1749 process_config_line (
1750 config_t * conf,
1751 char * line,
1752 config_file_context_t * context
1753 );
1754
1755 static char *
1756 get_next_word (char * input, char **next);
1757
1758 static errcode_t
1759 default_config (config_t * conf);
1760
1761 static errcode_t
1762 add_domain (config_t * conf, const char * domain);
1763
1764 static int
1765 contains_domain (const config_t * conf, const char * domain);
1766
1767 static int
1768 contains_domain_suffix (const config_t * conf, const char * addr);
1769
1770
1771 //----------
1772 // Global variables
1773
1774 static config_t * g_config = NULL;
1775 // Configuration info
1776
1777 pthread_mutex_t g_config_mutex =
1778 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
1779 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
1780 #else
1781 PTHREAD_MUTEX_INITIALIZER;
1782 #endif
1783
1784
1785 //----------
1786 // Configuration functions
1787
1788
1789 /*
1790 Initialise the configuration from the config file.
1791
1792 Returns
1793 0 success
1794 non-zero error code on failure
1795 */
1796 errcode_t
1797 init_config ()
1798 {
1799 if (g_config)
1800 {
1801 /*
1802 Safe to test outside mutex.
1803 If non-zero, initialisation is complete and g_config can be
1804 safely used read-only. If zero, then we do proper mutex
1805 testing before initialisation.
1806 */
1807 return 0;
1808 }
1809 else
1810 {
1811 int errcode = -1;
1812 int presult;
1813 config_t * temp_config;
1814
1815 // Acquire mutex
1816 presult = pthread_mutex_lock (&g_config_mutex);
1817 if (presult)
1818 {
1819 syslog (LOG_ERR,
1820 "mdns: Fatal mutex lock error in nss_mdns:init_config, %s:%d: %d: %s",
1821 __FILE__, __LINE__, presult, strerror (presult)
1822 );
1823 return presult;
1824 }
1825
1826 // Test again now we have mutex, in case initialisation occurred while
1827 // we were waiting
1828 if (! g_config)
1829 {
1830 temp_config = (config_t *) malloc (sizeof (config_t));
1831 if (temp_config)
1832 {
1833 // NOTE: This code will leak memory if initialisation fails
1834 // repeatedly. This should only happen in the case of a memory
1835 // error, so I'm not sure if it's a meaningful problem. - AW
1836 *temp_config = k_empty_config;
1837 errcode = load_config (temp_config);
1838
1839 if (! errcode)
1840 {
1841 g_config = temp_config;
1842 }
1843 }
1844 else
1845 {
1846 syslog (LOG_ERR,
1847 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
1848 __FILE__, __LINE__
1849 );
1850 errcode = errno;
1851 }
1852 }
1853
1854 presult = pthread_mutex_unlock (&g_config_mutex);
1855 if (presult)
1856 {
1857 syslog (LOG_ERR,
1858 "mdns: Fatal mutex unlock error in nss_mdns:init_config, %s:%d: %d: %s",
1859 __FILE__, __LINE__, presult, strerror (presult)
1860 );
1861 errcode = presult;
1862 }
1863
1864 return errcode;
1865 }
1866 }
1867
1868
1869 int
1870 config_is_mdns_suffix (const char * name)
1871 {
1872 int errcode = init_config ();
1873 if (! errcode)
1874 {
1875 return contains_domain_suffix (g_config, name);
1876 }
1877 else
1878 {
1879 errno = errcode;
1880 return -1;
1881 }
1882 }
1883
1884
1885 //----------
1886 // Local functions
1887
1888 static errcode_t
1889 load_config (config_t * conf)
1890 {
1891 FILE * cf;
1892 char line [CONF_LINE_SIZE];
1893 config_file_context_t context;
1894
1895 context.filename = k_conf_file;
1896 context.linenum = 0;
1897
1898
1899 cf = fopen (context.filename, "r");
1900 if (! cf)
1901 {
1902 syslog (LOG_INFO,
1903 "mdns: Couldn't open nss_mdns configuration file %s, using default.",
1904 context.filename
1905 );
1906 return default_config (conf);
1907 }
1908
1909 while (fgets (line, CONF_LINE_SIZE, cf))
1910 {
1911 int errcode;
1912 context.linenum++;
1913 errcode = process_config_line (conf, line, &context);
1914 if (errcode)
1915 {
1916 // Critical error, give up
1917 return errcode;
1918 }
1919 }
1920
1921 return 0;
1922 }
1923
1924
1925 /*
1926 Parse a line of the configuration file.
1927 For each keyword recognised, perform appropriate handling.
1928 If the keyword is not recognised, print a message to syslog
1929 and continue.
1930
1931 Returns
1932 0 success, or recoverable config file error
1933 non-zero serious system error, processing aborted
1934 */
1935 static errcode_t
1936 process_config_line (
1937 config_t * conf,
1938 char * line,
1939 config_file_context_t * context
1940 )
1941 {
1942 char * curr = line;
1943 char * word;
1944
1945 word = get_next_word (curr, &curr);
1946 if (! word || word [0] == k_comment_char)
1947 {
1948 // Nothing interesting on this line
1949 return 0;
1950 }
1951
1952 if (strcmp (word, k_keyword_domain) == 0)
1953 {
1954 word = get_next_word (curr, &curr);
1955 if (word)
1956 {
1957 int errcode = add_domain (conf, word);
1958 if (errcode)
1959 {
1960 // something badly wrong, bail
1961 return errcode;
1962 }
1963
1964 if (get_next_word (curr, NULL))
1965 {
1966 syslog (LOG_WARNING,
1967 "%s, line %d: ignored extra text found after domain",
1968 context->filename,
1969 context->linenum
1970 );
1971 }
1972 }
1973 else
1974 {
1975 syslog (LOG_WARNING,
1976 "%s, line %d: no domain specified",
1977 context->filename,
1978 context->linenum
1979 );
1980 }
1981 }
1982 else
1983 {
1984 syslog (LOG_WARNING,
1985 "%s, line %d: unknown keyword %s - skipping",
1986 context->filename,
1987 context->linenum,
1988 word
1989 );
1990 }
1991
1992 return 0;
1993 }
1994
1995
1996 /*
1997 Get next word (whitespace separated) from input string.
1998 A null character is written into the first whitespace character following
1999 the word.
2000
2001 Parameters
2002 input
2003 Input string. This string is modified by get_next_word.
2004 next
2005 If non-NULL and the result is non-NULL, a pointer to the
2006 character following the end of the word (after the null)
2007 is written to 'next'.
2008 If no word is found, the original value is unchanged.
2009 If the word extended to the end of the string, 'next' points
2010 to the trailling NULL.
2011 It is safe to pass 'str' as 'input' and '&str' as 'next'.
2012 Returns
2013 Pointer to the first non-whitespace character (and thus word) found.
2014 if no word is found, returns NULL.
2015 */
2016 static char *
2017 get_next_word (char * input, char **next)
2018 {
2019 char * curr = input;
2020 char * result;
2021
2022 while (isspace (*curr))
2023 {
2024 curr ++;
2025 }
2026
2027 if (*curr == 0)
2028 {
2029 return NULL;
2030 }
2031
2032 result = curr;
2033 while (*curr && ! isspace (*curr))
2034 {
2035 curr++;
2036 }
2037 if (*curr)
2038 {
2039 *curr = 0;
2040 if (next)
2041 {
2042 *next = curr+1;
2043 }
2044 }
2045 else
2046 {
2047 if (next)
2048 {
2049 *next = curr;
2050 }
2051 }
2052
2053 return result;
2054 }
2055
2056
2057 static errcode_t
2058 default_config (config_t * conf)
2059 {
2060 int i;
2061 for (i = 0; k_default_domains [i]; i++)
2062 {
2063 int errcode =
2064 add_domain (conf, k_default_domains [i]);
2065 if (errcode)
2066 {
2067 // Something has gone (badly) wrong - let's bail
2068 return errcode;
2069 }
2070 }
2071
2072 return 0;
2073 }
2074
2075
2076 static errcode_t
2077 add_domain (config_t * conf, const char * domain)
2078 {
2079 if (! contains_domain (conf, domain))
2080 {
2081 domain_entry_t * d =
2082 (domain_entry_t *) malloc (sizeof (domain_entry_t));
2083 if (! d)
2084 {
2085 syslog (LOG_ERR,
2086 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
2087 __FILE__, __LINE__
2088 );
2089 return ENOMEM;
2090 }
2091
2092 d->domain = strdup (domain);
2093 if (! d->domain)
2094 {
2095 syslog (LOG_ERR,
2096 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
2097 __FILE__, __LINE__
2098 );
2099 free (d);
2100 return ENOMEM;
2101 }
2102 d->next = conf->domains;
2103 conf->domains = d;
2104 }
2105
2106 return 0;
2107 }
2108
2109
2110 static int
2111 contains_domain (const config_t * conf, const char * domain)
2112 {
2113 const domain_entry_t * curr = conf->domains;
2114
2115 while (curr != NULL)
2116 {
2117 if (strcasecmp (curr->domain, domain) == 0)
2118 {
2119 return 1;
2120 }
2121
2122 curr = curr->next;
2123 }
2124
2125 return 0;
2126 }
2127
2128
2129 static int
2130 contains_domain_suffix (const config_t * conf, const char * addr)
2131 {
2132 const domain_entry_t * curr = conf->domains;
2133
2134 while (curr != NULL)
2135 {
2136 if (cmp_dns_suffix (addr, curr->domain) > 0)
2137 {
2138 return 1;
2139 }
2140
2141 curr = curr->next;
2142 }
2143
2144 return 0;
2145 }
2146
2147 //----------
2148 // Types and Constants
2149
2150 static const char * k_local_suffix = "local";
2151 static const char k_dns_separator = '.';
2152
2153 static const int k_label_maxlen = DNS_LABEL_MAXLEN;
2154 // Label entries longer than this are actually pointers.
2155
2156 typedef struct
2157 {
2158 int value;
2159 const char * name;
2160 const char * comment;
2161 } table_entry_t;
2162
2163 static const table_entry_t k_table_af [] =
2164 {
2165 { AF_UNSPEC, NULL, NULL },
2166 { AF_LOCAL, "LOCAL", NULL },
2167 { AF_UNIX, "UNIX", NULL },
2168 { AF_INET, "INET", NULL },
2169 { AF_INET6, "INET6", NULL }
2170 };
2171 static const int k_table_af_size =
2172 sizeof (k_table_af) / sizeof (* k_table_af);
2173
2174 static const char * k_table_ns_class [] =
2175 {
2176 NULL,
2177 "IN"
2178 };
2179 static const int k_table_ns_class_size =
2180 sizeof (k_table_ns_class) / sizeof (* k_table_ns_class);
2181
2182 static const char * k_table_ns_type [] =
2183 {
2184 NULL,
2185 "A",
2186 "NS",
2187 "MD",
2188 "MF",
2189 "CNAME",
2190 "SOA",
2191 "MB",
2192 "MG",
2193 "MR",
2194 "NULL",
2195 "WKS",
2196 "PTR",
2197 "HINFO",
2198 "MINFO",
2199 "MX",
2200 "TXT",
2201 "RP",
2202 "AFSDB",
2203 "X25",
2204 "ISDN",
2205 "RT",
2206 "NSAP",
2207 NULL,
2208 "SIG",
2209 "KEY",
2210 "PX",
2211 "GPOS",
2212 "AAAA",
2213 "LOC",
2214 "NXT",
2215 "EID",
2216 "NIMLOC",
2217 "SRV",
2218 "ATMA",
2219 "NAPTR",
2220 "KX",
2221 "CERT",
2222 "A6",
2223 "DNAME",
2224 "SINK",
2225 "OPT"
2226 };
2227 static const int k_table_ns_type_size =
2228 sizeof (k_table_ns_type) / sizeof (* k_table_ns_type);
2229
2230
2231 //----------
2232 // Local prototypes
2233
2234 static int
2235 simple_table_index (const char * table [], int size, const char * str);
2236
2237 static int
2238 table_index_name (const table_entry_t table [], int size, const char * str);
2239
2240 static int
2241 table_index_value (const table_entry_t table [], int size, int n);
2242
2243
2244 //----------
2245 // Global variables
2246
2247
2248 //----------
2249 // Util functions
2250
2251 int
2252 count_dots (const char * name)
2253 {
2254 int count = 0;
2255 int i;
2256 for (i = 0; name[i]; i++)
2257 {
2258 if (name [i] == k_dns_separator)
2259 count++;
2260 }
2261
2262 return count;
2263 }
2264
2265
2266 int
2267 islocal (const char * name)
2268 {
2269 return cmp_dns_suffix (name, k_local_suffix) > 0;
2270 }
2271
2272
2273 int
2274 rr_to_af (ns_type_t rrtype)
2275 {
2276 switch (rrtype)
2277 {
2278 case T_A:
2279 return AF_INET;
2280
2281 case T_AAAA:
2282 return AF_INET6;
2283
2284 default:
2285 return AF_UNSPEC;
2286 }
2287 }
2288
2289
2290 ns_type_t
2291 af_to_rr (int af)
2292 {
2293 switch (af)
2294 {
2295 case AF_INET:
2296 return T_A;
2297
2298 case AF_INET6:
2299 return T_AAAA;
2300
2301 default:
2302 //return ns_t_invalid;
2303 return 0;
2304 }
2305 }
2306
2307
2308 int
2309 str_to_af (const char * str)
2310 {
2311 int result =
2312 table_index_name (k_table_af, k_table_af_size, str);
2313 if (result < 0)
2314 result = 0;
2315
2316 return k_table_af [result].value;
2317 }
2318
2319
2320 ns_class_t
2321 str_to_ns_class (const char * str)
2322 {
2323 return (ns_class_t)
2324 simple_table_index (k_table_ns_class, k_table_ns_class_size, str);
2325 }
2326
2327
2328 ns_type_t
2329 str_to_ns_type (const char * str)
2330 {
2331 return (ns_type_t)
2332 simple_table_index (k_table_ns_type, k_table_ns_type_size, str);
2333 }
2334
2335
2336 const char *
2337 af_to_str (int in)
2338 {
2339 int result =
2340 table_index_value (k_table_af, k_table_af_size, in);
2341 if (result < 0)
2342 result = 0;
2343
2344 return k_table_af [result].name;
2345 }
2346
2347
2348 const char *
2349 ns_class_to_str (ns_class_t in)
2350 {
2351 if (in < k_table_ns_class_size)
2352 return k_table_ns_class [in];
2353 else
2354 return NULL;
2355 }
2356
2357
2358 const char *
2359 ns_type_to_str (ns_type_t in)
2360 {
2361 if (in < k_table_ns_type_size)
2362 return k_table_ns_type [in];
2363 else
2364 return NULL;
2365 }
2366
2367
2368 char *
2369 format_reverse_addr_in (
2370 const struct in_addr * addr,
2371 int prefixlen,
2372 char * buf
2373 )
2374 {
2375 char * curr = buf;
2376 int i;
2377
2378 const uint8_t * in_addr_a = (uint8_t *) addr;
2379
2380 if (prefixlen > 32)
2381 return NULL;
2382 if (prefixlen < 0)
2383 prefixlen = 32;
2384
2385 i = (prefixlen + 7) / 8;
2386 // divide prefixlen into bytes, rounding up
2387
2388 while (i > 0)
2389 {
2390 i--;
2391 curr += sprintf (curr, "%d.", in_addr_a [i]);
2392 }
2393 sprintf (curr, "in-addr.arpa");
2394
2395 return buf;
2396 }
2397
2398
2399 char *
2400 format_reverse_addr_in6 (
2401 const struct in6_addr * addr,
2402 int prefixlen,
2403 char * buf
2404 )
2405 {
2406 char * curr = buf;
2407 int i;
2408
2409 const uint8_t * in_addr_a = (uint8_t *) addr;
2410
2411 if (prefixlen > 128)
2412 return NULL;
2413 if (prefixlen < 0)
2414 prefixlen = 128;
2415
2416 i = (prefixlen + 3) / 4;
2417 // divide prefixlen into nibbles, rounding up
2418
2419 // Special handling for first
2420 if (i / 2)
2421 {
2422 curr += sprintf (curr, "%d.", (in_addr_a [i] >> 4) & 0x0F);
2423 }
2424 i >>= 1;
2425 // Convert i to bytes (divide by 2)
2426
2427 while (i > 0)
2428 {
2429 uint8_t val;
2430
2431 i--;
2432 val = in_addr_a [i];
2433 curr += sprintf (curr, "%x.%x.", val & 0x0F, (val >> 4) & 0x0F);
2434 }
2435 sprintf (curr, "ip6.arpa");
2436
2437 return buf;
2438 }
2439
2440
2441 char *
2442 format_reverse_addr (
2443 int af,
2444 const void * addr,
2445 int prefixlen,
2446 char * buf
2447 )
2448 {
2449 switch (af)
2450 {
2451 case AF_INET:
2452 return
2453 format_reverse_addr_in (
2454 (struct in_addr *) addr, prefixlen, buf
2455 );
2456 break;
2457
2458 case AF_INET6:
2459 return
2460 format_reverse_addr_in6 (
2461 (struct in6_addr *) addr, prefixlen, buf
2462 );
2463 break;
2464
2465 default:
2466 return NULL;
2467 }
2468 }
2469
2470
2471 int
2472 cmp_dns_suffix (const char * name, const char * domain)
2473 {
2474 const char * nametail;
2475 const char * domaintail;
2476
2477 // Idiot checks
2478 if (*name == 0 || *name == k_dns_separator)
2479 {
2480 // Name can't be empty or start with separator
2481 return CMP_DNS_SUFFIX_BAD_NAME;
2482 }
2483
2484 if (*domain == 0)
2485 {
2486 return CMP_DNS_SUFFIX_SUCCESS;
2487 // trivially true
2488 }
2489
2490 if (*domain == k_dns_separator)
2491 {
2492 // drop leading separator from domain
2493 domain++;
2494 if (*domain == k_dns_separator)
2495 {
2496 return CMP_DNS_SUFFIX_BAD_DOMAIN;
2497 }
2498 }
2499
2500 // Find ends of strings
2501 for (nametail = name; *nametail; nametail++)
2502 ;
2503 for (domaintail = domain; *domaintail; domaintail++)
2504 ;
2505
2506 // Shuffle back to last real character, and drop any trailing '.'
2507 // while we're at it.
2508 nametail --;
2509 if (*nametail == k_dns_separator)
2510 {
2511 nametail --;
2512 if (*nametail == k_dns_separator)
2513 {
2514 return CMP_DNS_SUFFIX_BAD_NAME;
2515 }
2516 }
2517 domaintail --;
2518 if (*domaintail == k_dns_separator)
2519 {
2520 domaintail --;
2521 if (*domaintail == k_dns_separator)
2522 {
2523 return CMP_DNS_SUFFIX_BAD_DOMAIN;
2524 }
2525 }
2526
2527 // Compare.
2528 while (
2529 nametail >= name
2530 && domaintail >= domain
2531 && tolower(*nametail) == tolower(*domaintail))
2532 {
2533 nametail--;
2534 domaintail--;
2535 }
2536
2537 /* A successful finish will be one of the following:
2538 (leading and trailing . ignored)
2539
2540 name : domain2.domain1
2541 domain: domain2.domain1
2542 ^
2543
2544 name : domain3.domain2.domain1
2545 domain: domain2.domain1
2546 ^
2547 */
2548 if (
2549 domaintail < domain
2550 && (nametail < name || *nametail == k_dns_separator)
2551 )
2552 {
2553 return CMP_DNS_SUFFIX_SUCCESS;
2554 }
2555 else
2556 {
2557 return CMP_DNS_SUFFIX_FAILURE;
2558 }
2559 }
2560
2561
2562 int
2563 dns_rdata_to_name (const char * rdata, int rdlen, char * name, int name_len)
2564 {
2565 int i = 0;
2566 // Index into 'name'
2567 const char * rdata_curr = rdata;
2568
2569 // drop any leading whitespace rubbish
2570 while (isspace (*rdata_curr))
2571 {
2572 rdata_curr ++;
2573 if (rdata_curr > rdata + rdlen)
2574 {
2575 return DNS_RDATA_TO_NAME_BAD_FORMAT;
2576 }
2577 }
2578
2579 /*
2580 In RDATA, a DNS name is stored as a series of labels.
2581 Each label consists of a length octet (max value 63)
2582 followed by the data for that label.
2583 The series is terminated with a length 0 octet.
2584 A length octet beginning with bits 11 is a pointer to
2585 somewhere else in the payload, but we don't support these
2586 since we don't have access to the entire payload.
2587
2588 See RFC1034 section 3.1 and RFC1035 section 3.1.
2589 */
2590 while (1)
2591 {
2592 int term_len = *rdata_curr;
2593 rdata_curr++;
2594
2595 if (term_len == 0)
2596 {
2597 break;
2598 // 0 length record terminates label
2599 }
2600 else if (term_len > k_label_maxlen)
2601 {
2602 name [i] = 0;
2603 return DNS_RDATA_TO_NAME_PTR;
2604 }
2605 else if (rdata_curr + term_len > rdata + rdlen)
2606 {
2607 name [i] = 0;
2608 return DNS_RDATA_TO_NAME_BAD_FORMAT;
2609 }
2610
2611 if (name_len < i + term_len + 1)
2612 // +1 is separator
2613 {
2614 name [i] = 0;
2615 return DNS_RDATA_TO_NAME_TOO_LONG;
2616 }
2617
2618 memcpy (name + i, rdata_curr, term_len);
2619
2620 i += term_len;
2621 rdata_curr += term_len;
2622
2623 name [i] = k_dns_separator;
2624 i++;
2625 }
2626
2627 name [i] = 0;
2628 return i;
2629 }
2630
2631
2632 //----------
2633 // Local functions
2634
2635 /*
2636 Find the index of an string entry in a table. A case insenitive match
2637 is performed. If no entry is found, 0 is returned.
2638
2639 Parameters
2640 table
2641 Lookup table
2642 Table entries may be NULL. NULL entries will never match.
2643 size
2644 number of entries in table
2645 str
2646 lookup string
2647
2648 Result
2649 index of first matching entry, or 0 if no matches
2650 */
2651 static int
2652 simple_table_index (const char * table [], int size, const char * str)
2653 {
2654 int i;
2655 for (i = 0; i < size; i++)
2656 {
2657 if (
2658 table [i]
2659 && (strcasecmp (table [i], str) == 0)
2660 )
2661 {
2662 return i;
2663 }
2664 }
2665
2666 return 0;
2667 }
2668
2669
2670 /*
2671 Find the index of a name in a table.
2672
2673 Parameters
2674 table
2675 array of table_entry_t records. The name field is compared
2676 (ignoring case) to the input string.
2677 size
2678 number of entries in table
2679 str
2680 lookup string
2681
2682 Result
2683 index of first matching entry, or -1 if no matches
2684 */
2685 static int
2686 table_index_name (const table_entry_t table [], int size, const char * str)
2687 {
2688 int i;
2689 for (i = 0; i < size; i++)
2690 {
2691 if (
2692 table [i].name
2693 && (strcasecmp (table [i].name, str) == 0)
2694 )
2695 {
2696 return i;
2697 }
2698 }
2699
2700 return -1;
2701 }
2702
2703
2704 /*
2705 Find the index of a value a table.
2706
2707 Parameters
2708 table
2709 array of table_entry_t records. The value field is compared to
2710 the input value
2711 size
2712 number of entries in table
2713 n
2714 lookup value
2715
2716 Result
2717 index of first matching entry, or -1 if no matches
2718 */
2719 static int
2720 table_index_value (const table_entry_t table [], int size, int n)
2721 {
2722 int i;
2723 for (i = 0; i < size; i++)
2724 {
2725 if (table [i].value == n)
2726 {
2727 return i;
2728 }
2729 }
2730
2731 return -1;
2732 }