]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/nss_mdns.c
mDNSResponder-107.5.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 nss_status status;
872
873 if (MDNS_VERBOSE)
874 syslog (LOG_DEBUG,
875 "mdns: Attempting lookup of %s",
876 fullname
877 );
878
879 switch (af)
880 {
881 case AF_INET:
882 rrtype = T_A;
883 result->hostent->h_length = 4;
884 // Length of an A record
885 break;
886
887 case AF_INET6:
888 rrtype = T_AAAA;
889 result->hostent->h_length = 16;
890 // Length of an AAAA record
891 break;
892
893 default:
894 syslog (LOG_WARNING,
895 "mdns: Unsupported address family %d",
896 af
897 );
898 return set_err_bad_hostname (result);
899 }
900 result->hostent->h_addrtype = af;
901
902 errcode =
903 DNSServiceQueryRecord (
904 &sdref,
905 0, // reserved flags field
906 k_mdnsd_intfs_local, // all local interfaces
907 fullname, // full name to query for
908 rrtype, // resource record type
909 C_IN, // internet class records
910 mdns_lookup_callback, // callback
911 result // Context - result buffer
912 );
913
914 if (errcode)
915 {
916 syslog (LOG_WARNING,
917 "mdns: Failed to initialise lookup, error %d",
918 errcode
919 );
920 return set_err_mdns_failed (result);
921 }
922
923 status = handle_events (sdref, result, fullname);
924 DNSServiceRefDeallocate (sdref);
925 return status;
926 }
927
928
929 /*
930 Reverse (PTR) lookup for the specified address.
931
932 Parameters
933 addr
934 Either a struct in_addr or a struct in6_addr
935 addr_len
936 size of the address
937 af
938 Either AF_INET or AF_INET6. Other families are not supported.
939 Must match addr
940 addr_str
941 Address in format suitable for PTR lookup.
942 AF_INET: a.b.c.d -> d.c.b.a.in-addr.arpa
943 AF_INET6: reverse nibble format, x.x.x...x.ip6.arpa
944 result
945 Initialised 'result' data structure.
946 */
947 static nss_status
948 mdns_lookup_addr (
949 const void * addr,
950 socklen_t addr_len,
951 int af,
952 const char * addr_str,
953 result_map_t * result
954 )
955 {
956 DNSServiceErrorType errcode;
957 DNSServiceRef sdref;
958 nss_status status;
959
960 if (MDNS_VERBOSE)
961 syslog (LOG_DEBUG,
962 "mdns: Attempting lookup of %s",
963 addr_str
964 );
965
966 result->hostent->h_addrtype = af;
967 result->hostent->h_length = addr_len;
968
969 // Query address becomes "address" in result.
970 if (! add_address_to_buffer (result, addr, addr_len))
971 {
972 return result->status;
973 }
974
975 result->hostent->h_name [0] = 0;
976
977 errcode =
978 DNSServiceQueryRecord (
979 &sdref,
980 0, // reserved flags field
981 k_mdnsd_intfs_local, // all local interfaces
982 addr_str, // address string to query for
983 T_PTR, // pointer RRs
984 C_IN, // internet class records
985 mdns_lookup_callback, // callback
986 result // Context - result buffer
987 );
988
989 if (errcode)
990 {
991 syslog (LOG_WARNING,
992 "mdns: Failed to initialise mdns lookup, error %d",
993 errcode
994 );
995 return set_err_mdns_failed (result);
996 }
997
998 status = handle_events (sdref, result, addr_str);
999 DNSServiceRefDeallocate (sdref);
1000 return status;
1001 }
1002
1003
1004 /*
1005 Wait on result of callback, and process it when it arrives.
1006
1007 Parameters
1008 sdref
1009 dns-sd reference
1010 result
1011 Initialised 'result' data structure.
1012 str
1013 lookup string, used for status/error reporting.
1014 */
1015 static nss_status
1016 handle_events (DNSServiceRef sdref, result_map_t * result, const char * str)
1017 {
1018 int dns_sd_fd = DNSServiceRefSockFD(sdref);
1019 int nfds = dns_sd_fd + 1;
1020 fd_set readfds;
1021 struct timeval tv;
1022 int select_result;
1023
1024 while (! result->done)
1025 {
1026 FD_ZERO(&readfds);
1027 FD_SET(dns_sd_fd, &readfds);
1028
1029 tv = k_select_time;
1030
1031 select_result =
1032 select (nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1033 if (select_result > 0)
1034 {
1035 if (FD_ISSET(dns_sd_fd, &readfds))
1036 {
1037 if (MDNS_VERBOSE)
1038 syslog (LOG_DEBUG,
1039 "mdns: Reply received for %s",
1040 str
1041 );
1042 DNSServiceProcessResult(sdref);
1043 }
1044 else
1045 {
1046 syslog (LOG_WARNING,
1047 "mdns: Unexpected return from select on lookup of %s",
1048 str
1049 );
1050 }
1051 }
1052 else
1053 {
1054 // Terminate loop due to timer expiry
1055 if (MDNS_VERBOSE)
1056 syslog (LOG_DEBUG,
1057 "mdns: %s not found - timer expired",
1058 str
1059 );
1060 set_err_notfound (result);
1061 break;
1062 }
1063 }
1064
1065 return result->status;
1066 }
1067
1068
1069 /*
1070 Examine incoming data and add to relevant fields in result structure.
1071 This routine is called from DNSServiceProcessResult where appropriate.
1072 */
1073 void
1074 mdns_lookup_callback
1075 (
1076 DNSServiceRef sdref,
1077 DNSServiceFlags flags,
1078 uint32_t interface_index,
1079 DNSServiceErrorType error_code,
1080 const char *fullname,
1081 uint16_t rrtype,
1082 uint16_t rrclass,
1083 uint16_t rdlen,
1084 const void *rdata,
1085 uint32_t ttl,
1086 void *context
1087 )
1088 {
1089 // A single record is received
1090
1091 result_map_t * result = (result_map_t *) context;
1092
1093 (void)sdref; // Unused
1094 (void)interface_index; // Unused
1095 (void)ttl; // Unused
1096
1097 if (! (flags & kDNSServiceFlagsMoreComing) )
1098 {
1099 result->done = 1;
1100 }
1101
1102 if (error_code == kDNSServiceErr_NoError)
1103 {
1104 ns_type_t expected_rr_type =
1105 af_to_rr (result->hostent->h_addrtype);
1106
1107 // Idiot check class
1108 if (rrclass != C_IN)
1109 {
1110 syslog (LOG_WARNING,
1111 "mdns: Received bad RR class: expected %d (%s),"
1112 " got %d (%s), RR type %d (%s)",
1113 C_IN,
1114 ns_class_to_str (C_IN),
1115 rrclass,
1116 ns_class_to_str (rrclass),
1117 rrtype,
1118 ns_type_to_str (rrtype)
1119 );
1120 return;
1121 }
1122
1123 // If a PTR
1124 if (rrtype == T_PTR)
1125 {
1126 if (callback_body_ptr (fullname, result, rdlen, rdata) < 0)
1127 return;
1128 }
1129 else if (rrtype == expected_rr_type)
1130 {
1131 if (!
1132 add_hostname_or_alias (
1133 result,
1134 fullname,
1135 strlen (fullname)
1136 )
1137 )
1138 {
1139 result->done = 1;
1140 return;
1141 // Abort on error
1142 }
1143
1144 if (! add_address_to_buffer (result, rdata, rdlen) )
1145 {
1146 result->done = 1;
1147 return;
1148 // Abort on error
1149 }
1150 }
1151 else
1152 {
1153 syslog (LOG_WARNING,
1154 "mdns: Received bad RR type: expected %d (%s),"
1155 " got %d (%s)",
1156 expected_rr_type,
1157 ns_type_to_str (expected_rr_type),
1158 rrtype,
1159 ns_type_to_str (rrtype)
1160 );
1161 return;
1162 }
1163
1164 if (result->status != NSS_STATUS_SUCCESS)
1165 set_err_success (result);
1166 }
1167 else
1168 {
1169 // For now, dump message to syslog and continue
1170 syslog (LOG_WARNING,
1171 "mdns: callback returned error %d",
1172 error_code
1173 );
1174 }
1175 }
1176
1177 static int
1178 callback_body_ptr (
1179 const char * fullname,
1180 result_map_t * result,
1181 int rdlen,
1182 const void * rdata
1183 )
1184 {
1185 char result_name [k_hostname_maxlen + 1];
1186 int rv;
1187
1188 // Fullname should be .in-addr.arpa or equivalent, which we're
1189 // not interested in. Ignore it.
1190
1191 rv = dns_rdata_to_name (rdata, rdlen, result_name, k_hostname_maxlen);
1192 if (rv < 0)
1193 {
1194 const char * errmsg;
1195
1196 switch (rv)
1197 {
1198 case DNS_RDATA_TO_NAME_BAD_FORMAT:
1199 errmsg = "mdns: PTR '%s' result badly formatted ('%s...')";
1200 break;
1201
1202 case DNS_RDATA_TO_NAME_TOO_LONG:
1203 errmsg = "mdns: PTR '%s' result too long ('%s...')";
1204 break;
1205
1206 case DNS_RDATA_TO_NAME_PTR:
1207 errmsg = "mdns: PTR '%s' result contained pointer ('%s...')";
1208 break;
1209
1210 default:
1211 errmsg = "mdns: PTR '%s' result conversion failed ('%s...')";
1212 }
1213
1214 syslog (LOG_WARNING,
1215 errmsg,
1216 fullname,
1217 result_name
1218 );
1219
1220 return -1;
1221 }
1222
1223 if (MDNS_VERBOSE)
1224 {
1225 syslog (LOG_DEBUG,
1226 "mdns: PTR '%s' resolved to '%s'",
1227 fullname,
1228 result_name
1229 );
1230 }
1231
1232 // Data should be a hostname
1233 if (!
1234 add_hostname_or_alias (
1235 result,
1236 result_name,
1237 rv
1238 )
1239 )
1240 {
1241 result->done = 1;
1242 return -1;
1243 }
1244
1245 return 0;
1246 }
1247
1248
1249 /*
1250 Add an address to the buffer.
1251
1252 Parameter
1253 result
1254 Result structure to write to
1255 data
1256 Incoming address data buffer
1257 Must be 'int' aligned
1258 len
1259 Length of data buffer (in bytes)
1260 Must match data alignment
1261
1262 Result
1263 Pointer to start of newly written data,
1264 or NULL on error.
1265 If address already exists in buffer, returns pointer to that instead.
1266 */
1267 static void *
1268 add_address_to_buffer (result_map_t * result, const void * data, int len)
1269 {
1270 int new_addr;
1271 void * start;
1272 void * temp;
1273
1274 if ((temp = contains_address (result, data, len)))
1275 {
1276 return temp;
1277 }
1278
1279 if (result->addrs_count >= k_addrs_max)
1280 {
1281 // Not enough addr slots
1282 set_err_internal_resource_full (result);
1283 syslog (LOG_ERR,
1284 "mdns: Internal address buffer full; increase size"
1285 );
1286 return NULL;
1287 }
1288
1289 // Idiot check
1290 if (len != result->hostent->h_length)
1291 {
1292 syslog (LOG_WARNING,
1293 "mdns: Unexpected rdata length for address. Expected %d, got %d",
1294 result->hostent->h_length,
1295 len
1296 );
1297 // XXX And continue for now.
1298 }
1299
1300 new_addr = result->addr_idx + len;
1301
1302 if (new_addr > result->alias_idx)
1303 {
1304 // Not enough room
1305 set_err_buf_too_small (result);
1306 if (MDNS_VERBOSE)
1307 syslog (LOG_DEBUG,
1308 "mdns: Ran out of buffer when adding address %d",
1309 result->addrs_count + 1
1310 );
1311 return NULL;
1312 }
1313
1314 start = result->buffer + result->addr_idx;
1315 memcpy (start, data, len);
1316 result->addr_idx = new_addr;
1317 result->header->addrs [result->addrs_count] = start;
1318 result->addrs_count ++;
1319 result->header->addrs [result->addrs_count] = NULL;
1320
1321 return start;
1322 }
1323
1324
1325 static void *
1326 contains_address (result_map_t * result, const void * data, int len)
1327 {
1328 int i;
1329
1330 // Idiot check
1331 if (len != result->hostent->h_length)
1332 {
1333 syslog (LOG_WARNING,
1334 "mdns: Unexpected rdata length for address. Expected %d, got %d",
1335 result->hostent->h_length,
1336 len
1337 );
1338 // XXX And continue for now.
1339 }
1340
1341 for (i = 0; result->header->addrs [i]; i++)
1342 {
1343 if (memcmp (result->header->addrs [i], data, len) == 0)
1344 {
1345 return result->header->addrs [i];
1346 }
1347 }
1348
1349 return NULL;
1350 }
1351
1352
1353 /*
1354 Add an alias to the buffer.
1355
1356 Parameter
1357 result
1358 Result structure to write to
1359 data
1360 Incoming alias (null terminated)
1361 len
1362 Length of data buffer (in bytes), including trailing null
1363
1364 Result
1365 Pointer to start of newly written data,
1366 or NULL on error
1367 If alias already exists in buffer, returns pointer to that instead.
1368 */
1369 static char *
1370 add_alias_to_buffer (result_map_t * result, const char * data, int len)
1371 {
1372 int new_alias;
1373 char * start;
1374 char * temp;
1375
1376 if ((temp = contains_alias (result, data)))
1377 {
1378 return temp;
1379 }
1380
1381 if (result->aliases_count >= k_aliases_max)
1382 {
1383 // Not enough alias slots
1384 set_err_internal_resource_full (result);
1385 syslog (LOG_ERR,
1386 "mdns: Internal alias buffer full; increase size"
1387 );
1388 return NULL;
1389 }
1390
1391 new_alias = result->alias_idx - len;
1392
1393 if (new_alias < result->addr_idx)
1394 {
1395 // Not enough room
1396 set_err_buf_too_small (result);
1397 if (MDNS_VERBOSE)
1398 syslog (LOG_DEBUG,
1399 "mdns: Ran out of buffer when adding alias %d",
1400 result->aliases_count + 1
1401 );
1402 return NULL;
1403 }
1404
1405 start = result->buffer + new_alias;
1406 memcpy (start, data, len);
1407 result->alias_idx = new_alias;
1408 result->header->aliases [result->aliases_count] = start;
1409 result->aliases_count ++;
1410 result->header->aliases [result->aliases_count] = NULL;
1411
1412 return start;
1413 }
1414
1415
1416 static char *
1417 contains_alias (result_map_t * result, const char * alias)
1418 {
1419 int i;
1420
1421 for (i = 0; result->header->aliases [i]; i++)
1422 {
1423 if (strcmp (result->header->aliases [i], alias) == 0)
1424 {
1425 return result->header->aliases [i];
1426 }
1427 }
1428
1429 return NULL;
1430 }
1431
1432
1433 /*
1434 Add fully qualified hostname to result.
1435
1436 Parameter
1437 result
1438 Result structure to write to
1439 fullname
1440 Fully qualified hostname
1441
1442 Result
1443 Pointer to start of hostname buffer,
1444 or NULL on error (usually hostname too long)
1445 */
1446
1447 static char *
1448 add_hostname_len (result_map_t * result, const char * fullname, int len)
1449 {
1450 if (len >= k_hostname_maxlen)
1451 {
1452 set_err_bad_hostname (result);
1453 syslog (LOG_WARNING,
1454 "mdns: Hostname too long '%.*s': len %d, max %d",
1455 len,
1456 fullname,
1457 len,
1458 k_hostname_maxlen
1459 );
1460 return NULL;
1461 }
1462
1463 result->hostent->h_name =
1464 strcpy (result->header->hostname, fullname);
1465
1466 return result->header->hostname;
1467 }
1468
1469
1470 /*
1471 Add fully qualified name as hostname or alias.
1472
1473 If hostname is not fully qualified this is not an error, but the data
1474 returned may be not what the application wanted.
1475
1476 Parameter
1477 result
1478 Result structure to write to
1479 data
1480 Incoming alias (null terminated)
1481 len
1482 Length of data buffer (in bytes), including trailing null
1483
1484 Result
1485 Pointer to start of newly written data,
1486 or NULL on error
1487 If alias or hostname already exists, returns pointer to that instead.
1488 */
1489 static char *
1490 add_hostname_or_alias (result_map_t * result, const char * data, int len)
1491 {
1492 char * hostname = result->hostent->h_name;
1493
1494 if (*hostname)
1495 {
1496 if (strcmp (hostname, data) == 0)
1497 {
1498 return hostname;
1499 }
1500 else
1501 {
1502 return add_alias_to_buffer (result, data, len);
1503 }
1504 }
1505 else
1506 {
1507 return add_hostname_len (result, data, len);
1508 }
1509 }
1510
1511
1512 static int
1513 init_result (
1514 result_map_t * result,
1515 hostent * result_buf,
1516 char * buf,
1517 size_t buflen
1518 )
1519 {
1520 if (buflen < sizeof (buf_header_t))
1521 {
1522 return ERANGE;
1523 }
1524
1525 result->hostent = result_buf;
1526 result->header = (buf_header_t *) buf;
1527 result->header->hostname[0] = 0;
1528 result->aliases_count = 0;
1529 result->header->aliases[0] = NULL;
1530 result->addrs_count = 0;
1531 result->header->addrs[0] = NULL;
1532 result->buffer = buf + sizeof (buf_header_t);
1533 result->addr_idx = 0;
1534 result->alias_idx = buflen - sizeof (buf_header_t);
1535 result->done = 0;
1536 set_err_notfound (result);
1537
1538 // Point hostent to the right buffers
1539 result->hostent->h_name = result->header->hostname;
1540 result->hostent->h_aliases = result->header->aliases;
1541 result->hostent->h_addr_list = result->header->addrs;
1542
1543 return 0;
1544 }
1545
1546 /*
1547 Set the status in the result.
1548
1549 Parameters
1550 result
1551 Result structure to update
1552 status
1553 New nss_status value
1554 err
1555 New errno value
1556 herr
1557 New h_errno value
1558
1559 Returns
1560 New status value
1561 */
1562 static nss_status
1563 set_err (result_map_t * result, nss_status status, int err, int herr)
1564 {
1565 result->status = status;
1566 result->r_errno = err;
1567 result->r_h_errno = herr;
1568
1569 return status;
1570 }
1571
1572 static nss_status
1573 set_err_notfound (result_map_t * result)
1574 {
1575 return set_err (result, NSS_STATUS_NOTFOUND, ENOENT, HOST_NOT_FOUND);
1576 }
1577
1578 static nss_status
1579 set_err_bad_hostname (result_map_t * result)
1580 {
1581 return set_err (result, NSS_STATUS_TRYAGAIN, ENOENT, NO_RECOVERY);
1582 }
1583
1584 static nss_status
1585 set_err_buf_too_small (result_map_t * result)
1586 {
1587 return set_err (result, NSS_STATUS_TRYAGAIN, ERANGE, NETDB_INTERNAL);
1588 }
1589
1590 static nss_status
1591 set_err_internal_resource_full (result_map_t * result)
1592 {
1593 return set_err (result, NSS_STATUS_RETURN, ERANGE, NO_RECOVERY);
1594 }
1595
1596 static nss_status
1597 set_err_system (result_map_t * result)
1598 {
1599 return set_err (result, NSS_STATUS_UNAVAIL, errno, NETDB_INTERNAL);
1600 }
1601
1602 static nss_status
1603 set_err_mdns_failed (result_map_t * result)
1604 {
1605 return set_err (result, NSS_STATUS_TRYAGAIN, EAGAIN, TRY_AGAIN);
1606 }
1607
1608 static nss_status
1609 set_err_success (result_map_t * result)
1610 {
1611 result->status = NSS_STATUS_SUCCESS;
1612 return result->status;
1613 }
1614
1615
1616 /*
1617 Test whether name is applicable for mdns to process, and if so copy into
1618 lookup_name buffer (if non-NULL).
1619
1620 Returns
1621 Pointer to name to lookup up, if applicable, or NULL otherwise.
1622 */
1623 static const char *
1624 is_applicable_name (
1625 result_map_t * result,
1626 const char * name,
1627 char * lookup_name
1628 )
1629 {
1630 int match = config_is_mdns_suffix (name);
1631 if (match > 0)
1632 {
1633 if (lookup_name)
1634 {
1635 strncpy (lookup_name, name, k_hostname_maxlen + 1);
1636 return lookup_name;
1637 }
1638 else
1639 {
1640 return name;
1641 }
1642 }
1643 else
1644 {
1645 if (match < 0)
1646 {
1647 set_err_system (result);
1648 }
1649 return NULL;
1650 }
1651 }
1652
1653 /*
1654 Test whether address is applicable for mdns to process, and if so copy into
1655 addr_str buffer as an address suitable for ptr lookup.
1656
1657 Returns
1658 Pointer to name to lookup up, if applicable, or NULL otherwise.
1659 */
1660 static const char *
1661 is_applicable_addr (
1662 result_map_t * result,
1663 const void * addr,
1664 int af,
1665 char * addr_str
1666 )
1667 {
1668 int match;
1669
1670 if (! format_reverse_addr (af, addr, -1, addr_str))
1671 {
1672 if (MDNS_VERBOSE)
1673 syslog (LOG_DEBUG,
1674 "mdns: Failed to create reverse address"
1675 );
1676 return NULL;
1677 }
1678
1679 if (MDNS_VERBOSE)
1680 syslog (LOG_DEBUG,
1681 "mdns: Reverse address: %s",
1682 addr_str
1683 );
1684
1685 match = config_is_mdns_suffix (addr_str);
1686 if (match > 0)
1687 {
1688 return addr_str;
1689 }
1690 else
1691 {
1692 if (match < 0)
1693 {
1694 set_err_system (result);
1695 }
1696 return NULL;
1697 }
1698 }
1699
1700 //----------
1701 // Types and Constants
1702
1703 const char * k_conf_file = "/etc/nss_mdns.conf";
1704 #define CONF_LINE_SIZE 1024
1705
1706 const char k_comment_char = '#';
1707
1708 const char * k_keyword_domain = "domain";
1709
1710 const char * k_default_domains [] =
1711 {
1712 "local",
1713 "254.169.in-addr.arpa",
1714 "0.8.e.f.ip6.int",
1715 "0.8.e.f.ip6.arpa",
1716 NULL
1717 // Always null terminated
1718 };
1719
1720 // Linked list of domains
1721 typedef struct domain_entry
1722 {
1723 char * domain;
1724 struct domain_entry * next;
1725 } domain_entry_t;
1726
1727
1728 // Config
1729 typedef struct
1730 {
1731 domain_entry_t * domains;
1732 } config_t;
1733
1734 const config_t k_empty_config =
1735 {
1736 NULL
1737 };
1738
1739
1740 // Context - tracks position in config file, used for error reporting
1741 typedef struct
1742 {
1743 const char * filename;
1744 int linenum;
1745 } config_file_context_t;
1746
1747
1748 //----------
1749 // Local prototypes
1750
1751 static errcode_t
1752 load_config (config_t * conf);
1753
1754 static errcode_t
1755 process_config_line (
1756 config_t * conf,
1757 char * line,
1758 config_file_context_t * context
1759 );
1760
1761 static char *
1762 get_next_word (char * input, char **next);
1763
1764 static errcode_t
1765 default_config (config_t * conf);
1766
1767 static errcode_t
1768 add_domain (config_t * conf, const char * domain);
1769
1770 static int
1771 contains_domain (const config_t * conf, const char * domain);
1772
1773 static int
1774 contains_domain_suffix (const config_t * conf, const char * addr);
1775
1776
1777 //----------
1778 // Global variables
1779
1780 static config_t * g_config = NULL;
1781 // Configuration info
1782
1783 pthread_mutex_t g_config_mutex =
1784 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
1785 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
1786 #else
1787 PTHREAD_MUTEX_INITIALIZER;
1788 #endif
1789
1790
1791 //----------
1792 // Configuration functions
1793
1794
1795 /*
1796 Initialise the configuration from the config file.
1797
1798 Returns
1799 0 success
1800 non-zero error code on failure
1801 */
1802 errcode_t
1803 init_config ()
1804 {
1805 if (g_config)
1806 {
1807 /*
1808 Safe to test outside mutex.
1809 If non-zero, initialisation is complete and g_config can be
1810 safely used read-only. If zero, then we do proper mutex
1811 testing before initialisation.
1812 */
1813 return 0;
1814 }
1815 else
1816 {
1817 int errcode = -1;
1818 int presult;
1819 config_t * temp_config;
1820
1821 // Acquire mutex
1822 presult = pthread_mutex_lock (&g_config_mutex);
1823 if (presult)
1824 {
1825 syslog (LOG_ERR,
1826 "mdns: Fatal mutex lock error in nss_mdns:init_config, %s:%d: %d: %s",
1827 __FILE__, __LINE__, presult, strerror (presult)
1828 );
1829 return presult;
1830 }
1831
1832 // Test again now we have mutex, in case initialisation occurred while
1833 // we were waiting
1834 if (! g_config)
1835 {
1836 temp_config = (config_t *) malloc (sizeof (config_t));
1837 if (temp_config)
1838 {
1839 // NOTE: This code will leak memory if initialisation fails
1840 // repeatedly. This should only happen in the case of a memory
1841 // error, so I'm not sure if it's a meaningful problem. - AW
1842 *temp_config = k_empty_config;
1843 errcode = load_config (temp_config);
1844
1845 if (! errcode)
1846 {
1847 g_config = temp_config;
1848 }
1849 }
1850 else
1851 {
1852 syslog (LOG_ERR,
1853 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
1854 __FILE__, __LINE__
1855 );
1856 errcode = errno;
1857 }
1858 }
1859
1860 presult = pthread_mutex_unlock (&g_config_mutex);
1861 if (presult)
1862 {
1863 syslog (LOG_ERR,
1864 "mdns: Fatal mutex unlock error in nss_mdns:init_config, %s:%d: %d: %s",
1865 __FILE__, __LINE__, presult, strerror (presult)
1866 );
1867 errcode = presult;
1868 }
1869
1870 return errcode;
1871 }
1872 }
1873
1874
1875 int
1876 config_is_mdns_suffix (const char * name)
1877 {
1878 int errcode = init_config ();
1879 if (! errcode)
1880 {
1881 return contains_domain_suffix (g_config, name);
1882 }
1883 else
1884 {
1885 errno = errcode;
1886 return -1;
1887 }
1888 }
1889
1890
1891 //----------
1892 // Local functions
1893
1894 static errcode_t
1895 load_config (config_t * conf)
1896 {
1897 FILE * cf;
1898 char line [CONF_LINE_SIZE];
1899 config_file_context_t context;
1900
1901 context.filename = k_conf_file;
1902 context.linenum = 0;
1903
1904
1905 cf = fopen (context.filename, "r");
1906 if (! cf)
1907 {
1908 syslog (LOG_INFO,
1909 "mdns: Couldn't open nss_mdns configuration file %s, using default.",
1910 context.filename
1911 );
1912 return default_config (conf);
1913 }
1914
1915 while (fgets (line, CONF_LINE_SIZE, cf))
1916 {
1917 int errcode;
1918 context.linenum++;
1919 errcode = process_config_line (conf, line, &context);
1920 if (errcode)
1921 {
1922 // Critical error, give up
1923 return errcode;
1924 }
1925 }
1926
1927 return 0;
1928 }
1929
1930
1931 /*
1932 Parse a line of the configuration file.
1933 For each keyword recognised, perform appropriate handling.
1934 If the keyword is not recognised, print a message to syslog
1935 and continue.
1936
1937 Returns
1938 0 success, or recoverable config file error
1939 non-zero serious system error, processing aborted
1940 */
1941 static errcode_t
1942 process_config_line (
1943 config_t * conf,
1944 char * line,
1945 config_file_context_t * context
1946 )
1947 {
1948 char * curr = line;
1949 char * word;
1950
1951 word = get_next_word (curr, &curr);
1952 if (! word || word [0] == k_comment_char)
1953 {
1954 // Nothing interesting on this line
1955 return 0;
1956 }
1957
1958 if (strcmp (word, k_keyword_domain) == 0)
1959 {
1960 word = get_next_word (curr, &curr);
1961 if (word)
1962 {
1963 int errcode = add_domain (conf, word);
1964 if (errcode)
1965 {
1966 // something badly wrong, bail
1967 return errcode;
1968 }
1969
1970 if (get_next_word (curr, NULL))
1971 {
1972 syslog (LOG_WARNING,
1973 "%s, line %d: ignored extra text found after domain",
1974 context->filename,
1975 context->linenum
1976 );
1977 }
1978 }
1979 else
1980 {
1981 syslog (LOG_WARNING,
1982 "%s, line %d: no domain specified",
1983 context->filename,
1984 context->linenum
1985 );
1986 }
1987 }
1988 else
1989 {
1990 syslog (LOG_WARNING,
1991 "%s, line %d: unknown keyword %s - skipping",
1992 context->filename,
1993 context->linenum,
1994 word
1995 );
1996 }
1997
1998 return 0;
1999 }
2000
2001
2002 /*
2003 Get next word (whitespace separated) from input string.
2004 A null character is written into the first whitespace character following
2005 the word.
2006
2007 Parameters
2008 input
2009 Input string. This string is modified by get_next_word.
2010 next
2011 If non-NULL and the result is non-NULL, a pointer to the
2012 character following the end of the word (after the null)
2013 is written to 'next'.
2014 If no word is found, the original value is unchanged.
2015 If the word extended to the end of the string, 'next' points
2016 to the trailling NULL.
2017 It is safe to pass 'str' as 'input' and '&str' as 'next'.
2018 Returns
2019 Pointer to the first non-whitespace character (and thus word) found.
2020 if no word is found, returns NULL.
2021 */
2022 static char *
2023 get_next_word (char * input, char **next)
2024 {
2025 char * curr = input;
2026 char * result;
2027
2028 while (isspace (*curr))
2029 {
2030 curr ++;
2031 }
2032
2033 if (*curr == 0)
2034 {
2035 return NULL;
2036 }
2037
2038 result = curr;
2039 while (*curr && ! isspace (*curr))
2040 {
2041 curr++;
2042 }
2043 if (*curr)
2044 {
2045 *curr = 0;
2046 if (next)
2047 {
2048 *next = curr+1;
2049 }
2050 }
2051 else
2052 {
2053 if (next)
2054 {
2055 *next = curr;
2056 }
2057 }
2058
2059 return result;
2060 }
2061
2062
2063 static errcode_t
2064 default_config (config_t * conf)
2065 {
2066 int i;
2067 for (i = 0; k_default_domains [i]; i++)
2068 {
2069 int errcode =
2070 add_domain (conf, k_default_domains [i]);
2071 if (errcode)
2072 {
2073 // Something has gone (badly) wrong - let's bail
2074 return errcode;
2075 }
2076 }
2077
2078 return 0;
2079 }
2080
2081
2082 static errcode_t
2083 add_domain (config_t * conf, const char * domain)
2084 {
2085 if (! contains_domain (conf, domain))
2086 {
2087 domain_entry_t * d =
2088 (domain_entry_t *) malloc (sizeof (domain_entry_t));
2089 if (! d)
2090 {
2091 syslog (LOG_ERR,
2092 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
2093 __FILE__, __LINE__
2094 );
2095 return ENOMEM;
2096 }
2097
2098 d->domain = strdup (domain);
2099 if (! d->domain)
2100 {
2101 syslog (LOG_ERR,
2102 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
2103 __FILE__, __LINE__
2104 );
2105 free (d);
2106 return ENOMEM;
2107 }
2108 d->next = conf->domains;
2109 conf->domains = d;
2110 }
2111
2112 return 0;
2113 }
2114
2115
2116 static int
2117 contains_domain (const config_t * conf, const char * domain)
2118 {
2119 const domain_entry_t * curr = conf->domains;
2120
2121 while (curr != NULL)
2122 {
2123 if (strcasecmp (curr->domain, domain) == 0)
2124 {
2125 return 1;
2126 }
2127
2128 curr = curr->next;
2129 }
2130
2131 return 0;
2132 }
2133
2134
2135 static int
2136 contains_domain_suffix (const config_t * conf, const char * addr)
2137 {
2138 const domain_entry_t * curr = conf->domains;
2139
2140 while (curr != NULL)
2141 {
2142 if (cmp_dns_suffix (addr, curr->domain) > 0)
2143 {
2144 return 1;
2145 }
2146
2147 curr = curr->next;
2148 }
2149
2150 return 0;
2151 }
2152
2153 //----------
2154 // Types and Constants
2155
2156 static const char * k_local_suffix = "local";
2157 static const char k_dns_separator = '.';
2158
2159 static const int k_label_maxlen = DNS_LABEL_MAXLEN;
2160 // Label entries longer than this are actually pointers.
2161
2162 typedef struct
2163 {
2164 int value;
2165 const char * name;
2166 const char * comment;
2167 } table_entry_t;
2168
2169 static const table_entry_t k_table_af [] =
2170 {
2171 { AF_UNSPEC, NULL, NULL },
2172 { AF_LOCAL, "LOCAL", NULL },
2173 { AF_UNIX, "UNIX", NULL },
2174 { AF_INET, "INET", NULL },
2175 { AF_INET6, "INET6", NULL }
2176 };
2177 static const int k_table_af_size =
2178 sizeof (k_table_af) / sizeof (* k_table_af);
2179
2180 static const char * k_table_ns_class [] =
2181 {
2182 NULL,
2183 "IN"
2184 };
2185 static const int k_table_ns_class_size =
2186 sizeof (k_table_ns_class) / sizeof (* k_table_ns_class);
2187
2188 static const char * k_table_ns_type [] =
2189 {
2190 NULL,
2191 "A",
2192 "NS",
2193 "MD",
2194 "MF",
2195 "CNAME",
2196 "SOA",
2197 "MB",
2198 "MG",
2199 "MR",
2200 "NULL",
2201 "WKS",
2202 "PTR",
2203 "HINFO",
2204 "MINFO",
2205 "MX",
2206 "TXT",
2207 "RP",
2208 "AFSDB",
2209 "X25",
2210 "ISDN",
2211 "RT",
2212 "NSAP",
2213 NULL,
2214 "SIG",
2215 "KEY",
2216 "PX",
2217 "GPOS",
2218 "AAAA",
2219 "LOC",
2220 "NXT",
2221 "EID",
2222 "NIMLOC",
2223 "SRV",
2224 "ATMA",
2225 "NAPTR",
2226 "KX",
2227 "CERT",
2228 "A6",
2229 "DNAME",
2230 "SINK",
2231 "OPT"
2232 };
2233 static const int k_table_ns_type_size =
2234 sizeof (k_table_ns_type) / sizeof (* k_table_ns_type);
2235
2236
2237 //----------
2238 // Local prototypes
2239
2240 static int
2241 simple_table_index (const char * table [], int size, const char * str);
2242
2243 static int
2244 table_index_name (const table_entry_t table [], int size, const char * str);
2245
2246 static int
2247 table_index_value (const table_entry_t table [], int size, int n);
2248
2249
2250 //----------
2251 // Global variables
2252
2253
2254 //----------
2255 // Util functions
2256
2257 int
2258 count_dots (const char * name)
2259 {
2260 int count = 0;
2261 int i;
2262 for (i = 0; name[i]; i++)
2263 {
2264 if (name [i] == k_dns_separator)
2265 count++;
2266 }
2267
2268 return count;
2269 }
2270
2271
2272 int
2273 islocal (const char * name)
2274 {
2275 return cmp_dns_suffix (name, k_local_suffix) > 0;
2276 }
2277
2278
2279 int
2280 rr_to_af (ns_type_t rrtype)
2281 {
2282 switch (rrtype)
2283 {
2284 case T_A:
2285 return AF_INET;
2286
2287 case T_AAAA:
2288 return AF_INET6;
2289
2290 default:
2291 return AF_UNSPEC;
2292 }
2293 }
2294
2295
2296 ns_type_t
2297 af_to_rr (int af)
2298 {
2299 switch (af)
2300 {
2301 case AF_INET:
2302 return T_A;
2303
2304 case AF_INET6:
2305 return T_AAAA;
2306
2307 default:
2308 //return ns_t_invalid;
2309 return 0;
2310 }
2311 }
2312
2313
2314 int
2315 str_to_af (const char * str)
2316 {
2317 int result =
2318 table_index_name (k_table_af, k_table_af_size, str);
2319 if (result < 0)
2320 result = 0;
2321
2322 return k_table_af [result].value;
2323 }
2324
2325
2326 ns_class_t
2327 str_to_ns_class (const char * str)
2328 {
2329 return (ns_class_t)
2330 simple_table_index (k_table_ns_class, k_table_ns_class_size, str);
2331 }
2332
2333
2334 ns_type_t
2335 str_to_ns_type (const char * str)
2336 {
2337 return (ns_type_t)
2338 simple_table_index (k_table_ns_type, k_table_ns_type_size, str);
2339 }
2340
2341
2342 const char *
2343 af_to_str (int in)
2344 {
2345 int result =
2346 table_index_value (k_table_af, k_table_af_size, in);
2347 if (result < 0)
2348 result = 0;
2349
2350 return k_table_af [result].name;
2351 }
2352
2353
2354 const char *
2355 ns_class_to_str (ns_class_t in)
2356 {
2357 if (in < k_table_ns_class_size)
2358 return k_table_ns_class [in];
2359 else
2360 return NULL;
2361 }
2362
2363
2364 const char *
2365 ns_type_to_str (ns_type_t in)
2366 {
2367 if (in < k_table_ns_type_size)
2368 return k_table_ns_type [in];
2369 else
2370 return NULL;
2371 }
2372
2373
2374 char *
2375 format_reverse_addr_in (
2376 const struct in_addr * addr,
2377 int prefixlen,
2378 char * buf
2379 )
2380 {
2381 char * curr = buf;
2382 int i;
2383
2384 const uint8_t * in_addr_a = (uint8_t *) addr;
2385
2386 if (prefixlen > 32)
2387 return NULL;
2388 if (prefixlen < 0)
2389 prefixlen = 32;
2390
2391 i = (prefixlen + 7) / 8;
2392 // divide prefixlen into bytes, rounding up
2393
2394 while (i > 0)
2395 {
2396 i--;
2397 curr += sprintf (curr, "%d.", in_addr_a [i]);
2398 }
2399 sprintf (curr, "in-addr.arpa");
2400
2401 return buf;
2402 }
2403
2404
2405 char *
2406 format_reverse_addr_in6 (
2407 const struct in6_addr * addr,
2408 int prefixlen,
2409 char * buf
2410 )
2411 {
2412 char * curr = buf;
2413 int i;
2414
2415 const uint8_t * in_addr_a = (uint8_t *) addr;
2416
2417 if (prefixlen > 128)
2418 return NULL;
2419 if (prefixlen < 0)
2420 prefixlen = 128;
2421
2422 i = (prefixlen + 3) / 4;
2423 // divide prefixlen into nibbles, rounding up
2424
2425 // Special handling for first
2426 if (i / 2)
2427 {
2428 curr += sprintf (curr, "%d.", (in_addr_a [i] >> 4) & 0x0F);
2429 }
2430 i >>= 1;
2431 // Convert i to bytes (divide by 2)
2432
2433 while (i > 0)
2434 {
2435 uint8_t val;
2436
2437 i--;
2438 val = in_addr_a [i];
2439 curr += sprintf (curr, "%x.%x.", val & 0x0F, (val >> 4) & 0x0F);
2440 }
2441 sprintf (curr, "ip6.arpa");
2442
2443 return buf;
2444 }
2445
2446
2447 char *
2448 format_reverse_addr (
2449 int af,
2450 const void * addr,
2451 int prefixlen,
2452 char * buf
2453 )
2454 {
2455 switch (af)
2456 {
2457 case AF_INET:
2458 return
2459 format_reverse_addr_in (
2460 (struct in_addr *) addr, prefixlen, buf
2461 );
2462 break;
2463
2464 case AF_INET6:
2465 return
2466 format_reverse_addr_in6 (
2467 (struct in6_addr *) addr, prefixlen, buf
2468 );
2469 break;
2470
2471 default:
2472 return NULL;
2473 }
2474 }
2475
2476
2477 int
2478 cmp_dns_suffix (const char * name, const char * domain)
2479 {
2480 const char * nametail;
2481 const char * domaintail;
2482
2483 // Idiot checks
2484 if (*name == 0 || *name == k_dns_separator)
2485 {
2486 // Name can't be empty or start with separator
2487 return CMP_DNS_SUFFIX_BAD_NAME;
2488 }
2489
2490 if (*domain == 0)
2491 {
2492 return CMP_DNS_SUFFIX_SUCCESS;
2493 // trivially true
2494 }
2495
2496 if (*domain == k_dns_separator)
2497 {
2498 // drop leading separator from domain
2499 domain++;
2500 if (*domain == k_dns_separator)
2501 {
2502 return CMP_DNS_SUFFIX_BAD_DOMAIN;
2503 }
2504 }
2505
2506 // Find ends of strings
2507 for (nametail = name; *nametail; nametail++)
2508 ;
2509 for (domaintail = domain; *domaintail; domaintail++)
2510 ;
2511
2512 // Shuffle back to last real character, and drop any trailing '.'
2513 // while we're at it.
2514 nametail --;
2515 if (*nametail == k_dns_separator)
2516 {
2517 nametail --;
2518 if (*nametail == k_dns_separator)
2519 {
2520 return CMP_DNS_SUFFIX_BAD_NAME;
2521 }
2522 }
2523 domaintail --;
2524 if (*domaintail == k_dns_separator)
2525 {
2526 domaintail --;
2527 if (*domaintail == k_dns_separator)
2528 {
2529 return CMP_DNS_SUFFIX_BAD_DOMAIN;
2530 }
2531 }
2532
2533 // Compare.
2534 while (
2535 nametail >= name
2536 && domaintail >= domain
2537 && tolower(*nametail) == tolower(*domaintail))
2538 {
2539 nametail--;
2540 domaintail--;
2541 }
2542
2543 /* A successful finish will be one of the following:
2544 (leading and trailing . ignored)
2545
2546 name : domain2.domain1
2547 domain: domain2.domain1
2548 ^
2549
2550 name : domain3.domain2.domain1
2551 domain: domain2.domain1
2552 ^
2553 */
2554 if (
2555 domaintail < domain
2556 && (nametail < name || *nametail == k_dns_separator)
2557 )
2558 {
2559 return CMP_DNS_SUFFIX_SUCCESS;
2560 }
2561 else
2562 {
2563 return CMP_DNS_SUFFIX_FAILURE;
2564 }
2565 }
2566
2567
2568 int
2569 dns_rdata_to_name (const char * rdata, int rdlen, char * name, int name_len)
2570 {
2571 int i = 0;
2572 // Index into 'name'
2573 const char * rdata_curr = rdata;
2574
2575 // drop any leading whitespace rubbish
2576 while (isspace (*rdata_curr))
2577 {
2578 rdata_curr ++;
2579 if (rdata_curr > rdata + rdlen)
2580 {
2581 return DNS_RDATA_TO_NAME_BAD_FORMAT;
2582 }
2583 }
2584
2585 /*
2586 In RDATA, a DNS name is stored as a series of labels.
2587 Each label consists of a length octet (max value 63)
2588 followed by the data for that label.
2589 The series is terminated with a length 0 octet.
2590 A length octet beginning with bits 11 is a pointer to
2591 somewhere else in the payload, but we don't support these
2592 since we don't have access to the entire payload.
2593
2594 See RFC1034 section 3.1 and RFC1035 section 3.1.
2595 */
2596 while (1)
2597 {
2598 int term_len = *rdata_curr;
2599 rdata_curr++;
2600
2601 if (term_len == 0)
2602 {
2603 break;
2604 // 0 length record terminates label
2605 }
2606 else if (term_len > k_label_maxlen)
2607 {
2608 name [i] = 0;
2609 return DNS_RDATA_TO_NAME_PTR;
2610 }
2611 else if (rdata_curr + term_len > rdata + rdlen)
2612 {
2613 name [i] = 0;
2614 return DNS_RDATA_TO_NAME_BAD_FORMAT;
2615 }
2616
2617 if (name_len < i + term_len + 1)
2618 // +1 is separator
2619 {
2620 name [i] = 0;
2621 return DNS_RDATA_TO_NAME_TOO_LONG;
2622 }
2623
2624 memcpy (name + i, rdata_curr, term_len);
2625
2626 i += term_len;
2627 rdata_curr += term_len;
2628
2629 name [i] = k_dns_separator;
2630 i++;
2631 }
2632
2633 name [i] = 0;
2634 return i;
2635 }
2636
2637
2638 //----------
2639 // Local functions
2640
2641 /*
2642 Find the index of an string entry in a table. A case insenitive match
2643 is performed. If no entry is found, 0 is returned.
2644
2645 Parameters
2646 table
2647 Lookup table
2648 Table entries may be NULL. NULL entries will never match.
2649 size
2650 number of entries in table
2651 str
2652 lookup string
2653
2654 Result
2655 index of first matching entry, or 0 if no matches
2656 */
2657 static int
2658 simple_table_index (const char * table [], int size, const char * str)
2659 {
2660 int i;
2661 for (i = 0; i < size; i++)
2662 {
2663 if (
2664 table [i]
2665 && (strcasecmp (table [i], str) == 0)
2666 )
2667 {
2668 return i;
2669 }
2670 }
2671
2672 return 0;
2673 }
2674
2675
2676 /*
2677 Find the index of a name in a table.
2678
2679 Parameters
2680 table
2681 array of table_entry_t records. The name field is compared
2682 (ignoring case) to the input string.
2683 size
2684 number of entries in table
2685 str
2686 lookup string
2687
2688 Result
2689 index of first matching entry, or -1 if no matches
2690 */
2691 static int
2692 table_index_name (const table_entry_t table [], int size, const char * str)
2693 {
2694 int i;
2695 for (i = 0; i < size; i++)
2696 {
2697 if (
2698 table [i].name
2699 && (strcasecmp (table [i].name, str) == 0)
2700 )
2701 {
2702 return i;
2703 }
2704 }
2705
2706 return -1;
2707 }
2708
2709
2710 /*
2711 Find the index of a value a table.
2712
2713 Parameters
2714 table
2715 array of table_entry_t records. The value field is compared to
2716 the input value
2717 size
2718 number of entries in table
2719 n
2720 lookup value
2721
2722 Result
2723 index of first matching entry, or -1 if no matches
2724 */
2725 static int
2726 table_index_value (const table_entry_t table [], int size, int n)
2727 {
2728 int i;
2729 for (i = 0; i < size; i++)
2730 {
2731 if (table [i].value == n)
2732 {
2733 return i;
2734 }
2735 }
2736
2737 return -1;
2738 }