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