2 NICTA Public Software Licence
5 Copyright © 2004 National ICT Australia Ltd
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:
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
23 - The name of NICTA may not be used to endorse or promote products
24 derived from this Software without specific prior written permission.
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
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.
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:
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
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
66 NSSwitch Implementation of mDNS interface.
68 Andrew White (Andrew.White@nicta.com.au)
80 #include <sys/types.h>
82 #include <sys/socket.h>
84 #include <netinet/in.h>
86 #include <arpa/inet.h>
87 #define BIND_8_COMPAT 1
88 #include <arpa/nameser.h>
97 Count the number of dots in a name string.
100 count_dots (const char * name
);
104 Test whether a domain name is local.
107 1 if name ends with ".local" or ".local."
111 islocal (const char * name
);
115 Format an address structure as a string appropriate for DNS reverse (PTR)
116 lookup, based on address type.
120 Prefix length, in bits. When formatting, this will be rounded up
121 to the nearest appropriate size. If -1, assume maximum.
123 Output buffer. Must be long enough to hold largest possible
126 Pointer to (first character of) output buffer,
130 format_reverse_addr (int af
, const void * addr
, int prefixlen
, char * buf
);
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.
139 Prefix length, in bits. When formatting, this will be rounded up
140 to the nearest byte (8). If -1, assume 32.
142 Output buffer. Must be long enough to hold largest possible
143 output. For AF_INET, this is 29 characters (including null).
145 Pointer to (first character of) output buffer,
149 format_reverse_addr_in (
150 const struct in_addr
* addr
,
154 #define DNS_PTR_AF_INET_SIZE 29
157 Format an address structure as a string appropriate for DNS reverse (PTR)
158 lookup for AF_INET6. Output is in .ip6.int domain.
162 Prefix length, in bits. When formatting, this will be rounded up
163 to the nearest nibble (4). If -1, assume 128.
165 Output buffer. Must be long enough to hold largest possible
166 output. For AF_INET6, this is 72 characters (including null).
168 Pointer to (first character of) output buffer,
172 format_reverse_addr_in6 (
173 const struct in6_addr
* addr
,
177 #define DNS_PTR_AF_INET6_SIZE 72
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.
189 0 on failure (no match)
193 cmp_dns_suffix (const char * name
, const char * domain
);
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
202 typedef int ns_type_t
;
203 typedef int ns_class_t
;
206 Convert a DNS resource record (RR) code to an address family (AF) code.
210 resource record type (from nameser.h)
213 Appropriate AF code (from socket.h), or AF_UNSPEC if an appropriate
214 mapping couldn't be determined
217 rr_to_af (ns_type_t rrtype
);
221 Convert an address family (AF) code to a DNS resource record (RR) code.
225 address family code (from socket.h)
227 Appropriate RR code (from nameser.h), or ns_t_invalid if an appropriate
228 mapping couldn't be determined
235 Convert a string to an address family (case insensitive).
238 Matching AF code, or AF_UNSPEC if no match found.
241 str_to_af (const char * str
);
245 Convert a string to an ns_class_t (case insensitive).
248 Matching ns_class_t, or ns_c_invalid if no match found.
251 str_to_ns_class (const char * str
);
255 Convert a string to an ns_type_t (case insensitive).
258 Matching ns_type_t, or ns_t_invalid if no match found.
261 str_to_ns_type (const char * str
);
265 Convert an address family code to a string.
268 String representation of AF,
269 or NULL if address family unrecognised or invalid.
276 Convert an ns_class_t code to a string.
279 String representation of ns_class_t,
280 or NULL if ns_class_t unrecognised or invalid.
283 ns_class_to_str (ns_class_t in
);
287 Convert an ns_type_t code to a string.
290 String representation of ns_type_t,
291 or NULL if ns_type_t unrecognised or invalid.
294 ns_type_to_str (ns_type_t in
);
298 Convert DNS rdata in label format (RFC1034, RFC1035) to a name.
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
307 Rdata formatted as series of labels.
309 Length of rdata buffer.
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.
315 Number of characters available in name buffer, not including
319 Length of name buffer (not including trailing null).
321 A return of 0 implies the empty domain.
324 dns_rdata_to_name (const char * rdata
, int rdlen
, char * name
, int name_len
);
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.
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
344 typedef int errcode_t
;
345 // Used for 0 = success, non-zero = error code functions
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.
360 -1 error, check errno
363 config_is_mdns_suffix (const char * name
);
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
373 0 configuration ready
374 non-zero configuration error code
379 #define ENTNAME hostent
380 #define DATABASE "hosts"
386 #include <sys/types.h>
389 typedef enum nss_status nss_status
;
390 typedef struct hostent hostent
;
393 gethostbyname implementation
402 length of auxillary buffer
409 _nss_mdns_gethostbyname_r (
411 hostent
* result_buf
,
420 gethostbyname2 implementation
431 length of auxillary buffer
438 _nss_mdns_gethostbyname2_r (
441 hostent
* result_buf
,
450 gethostbyaddr implementation
453 address structure to look up
455 length of address structure
463 length of auxillary buffer
470 _nss_mdns_gethostbyaddr_r (
474 hostent
* result_buf
,
483 // Types and Constants
485 const int MDNS_VERBOSE
= 0;
486 // This enables verbose syslog messages
487 // If zero, only "imporant" messages will appear in syslog
489 #define k_hostname_maxlen 255
490 // As per RFC1034 and RFC1035
491 #define k_aliases_max 15
492 #define k_addrs_max 15
494 const int k_mdnsd_intfs_local
= 0;
495 // Tell mdnsd to perform lookups only using link-local interfaces.
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.
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.
510 typedef struct buf_header
512 char hostname
[k_hostname_maxlen
+ 1];
513 char * aliases
[k_aliases_max
+ 1];
514 char * addrs
[k_addrs_max
+ 1];
517 typedef struct result_map
522 buf_header_t
* header
;
527 // Index for addresses - grow from low end
528 // Index points to first empty space
530 // Index for aliases - grow from high end
531 // Index points to lowest entry
536 static const struct timeval
537 k_select_time
= { 0, 500000 };
538 // 0 seconds, 500 milliseconds
544 mdns_gethostbyname2 (
547 hostent
* result_buf
,
556 Lookup name using mDNS server
560 const char * fullname
,
562 result_map_t
* result
566 Lookup address using mDNS server
573 const char * addr_str
,
574 result_map_t
* result
579 Handle incoming MDNS events
582 handle_events (DNSServiceRef sdref
, result_map_t
* result
, const char * str
);
585 // Callback for mdns_lookup operations
586 //DNSServiceQueryRecordReply mdns_lookup_callback;
588 mdns_lookup_callback_t
591 DNSServiceFlags flags
,
592 uint32_t interface_index
,
593 DNSServiceErrorType error_code
,
594 const char *fullname
,
603 mdns_lookup_callback_t mdns_lookup_callback
;
608 result_map_t
* result
,
609 hostent
* result_buf
,
616 const char * fullname
,
617 result_map_t
* result
,
623 add_address_to_buffer (result_map_t
* result
, const void * data
, int len
);
625 add_alias_to_buffer (result_map_t
* result
, const char * data
, int len
);
627 add_hostname_len (result_map_t
* result
, const char * fullname
, int len
);
629 add_hostname_or_alias (result_map_t
* result
, const char * data
, int len
);
632 contains_address (result_map_t
* result
, const void * data
, int len
);
634 contains_alias (result_map_t
* result
, const char * data
);
639 result_map_t
* result
,
646 result_map_t
* result
,
653 // Error code functions
656 set_err (result_map_t
* result
, nss_status status
, int err
, int herr
);
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
);
675 _nss_mdns_gethostbyname_r (
677 hostent
* result_buf
,
686 "mdns: Called nss_mdns_gethostbyname with %s",
691 mdns_gethostbyname2 (
692 name
, AF_INET
, result_buf
, buf
, buflen
, errnop
, h_errnop
698 _nss_mdns_gethostbyname2_r (
701 hostent
* result_buf
,
710 "mdns: Called nss_mdns_gethostbyname2 with %s",
715 mdns_gethostbyname2 (
716 name
, af
, result_buf
, buf
, buflen
, errnop
, h_errnop
722 _nss_mdns_gethostbyaddr_r (
726 hostent
* result_buf
,
733 char addr_str
[NI_MAXHOST
+ 1];
737 if (inet_ntop (af
, addr
, addr_str
, NI_MAXHOST
) == NULL
)
739 const char * family
= af_to_str (af
);
746 "mdns: Couldn't covert address, family %d (%s) in nss_mdns_gethostbyaddr: %s",
752 // This address family never applicable to us, so return NOT_FOUND
755 *h_errnop
= HOST_NOT_FOUND
;
756 return NSS_STATUS_NOTFOUND
;
761 "mdns: Called nss_mdns_gethostbyaddr with %s",
767 err_status
= init_result (&result
, result_buf
, buf
, buflen
);
770 *errnop
= err_status
;
771 *h_errnop
= NETDB_INTERNAL
;
772 return NSS_STATUS_TRYAGAIN
;
775 if (is_applicable_addr (&result
, addr
, af
, addr_str
))
779 rv
= mdns_lookup_addr (addr
, len
, af
, addr_str
, &result
);
780 if (rv
== NSS_STATUS_SUCCESS
)
786 // Return current error status (defaults to NOT_FOUND)
788 *errnop
= result
.r_errno
;
789 *h_errnop
= result
.r_h_errno
;
790 return result
.status
;
798 mdns_gethostbyname2 (
801 hostent
* result_buf
,
808 char lookup_name
[k_hostname_maxlen
+ 1];
813 err_status
= init_result (&result
, result_buf
, buf
, buflen
);
816 *errnop
= err_status
;
817 *h_errnop
= NETDB_INTERNAL
;
818 return NSS_STATUS_TRYAGAIN
;
821 if (is_applicable_name (&result
, name
, lookup_name
))
828 "mdns: Local name: %s",
832 rv
= mdns_lookup_name (name
, af
, &result
);
833 if (rv
== NSS_STATUS_SUCCESS
)
839 // Return current error status (defaults to NOT_FOUND)
841 *errnop
= result
.r_errno
;
842 *h_errnop
= result
.r_h_errno
;
843 return result
.status
;
848 Lookup a fully qualified hostname using the default record type
849 for the specified address family.
853 Fully qualified hostname. If not fully qualified the code will
854 still 'work', but the lookup is unlikely to succeed.
856 Either AF_INET or AF_INET6. Other families are not supported.
858 Initialised 'result' data structure.
862 const char * fullname
,
864 result_map_t
* result
867 // Lookup using mDNS.
868 DNSServiceErrorType errcode
;
874 "mdns: Attempting lookup of %s",
882 result
->hostent
->h_length
= 4;
883 // Length of an A record
888 result
->hostent
->h_length
= 16;
889 // Length of an AAAA record
894 "mdns: Unsupported address family %d",
897 return set_err_bad_hostname (result
);
899 result
->hostent
->h_addrtype
= af
;
902 DNSServiceQueryRecord (
904 0, // reserved flags field
905 k_mdnsd_intfs_local
, // all local interfaces
906 fullname
, // full name to query for
907 rrtype
, // resource record type
908 C_IN
, // internet class records
909 mdns_lookup_callback
, // callback
910 result
// Context - result buffer
916 "mdns: Failed to initialise lookup, error %d",
919 return set_err_mdns_failed (result
);
922 return handle_events (sdref
, result
, fullname
);
927 Reverse (PTR) lookup for the specified address.
931 Either a struct in_addr or a struct in6_addr
935 Either AF_INET or AF_INET6. Other families are not supported.
938 Address in format suitable for PTR lookup.
939 AF_INET: a.b.c.d -> d.c.b.a.in-addr.arpa
940 AF_INET6: reverse nibble format, x.x.x...x.ip6.arpa
942 Initialised 'result' data structure.
949 const char * addr_str
,
950 result_map_t
* result
953 DNSServiceErrorType errcode
;
958 "mdns: Attempting lookup of %s",
962 result
->hostent
->h_addrtype
= af
;
963 result
->hostent
->h_length
= addr_len
;
965 // Query address becomes "address" in result.
966 if (! add_address_to_buffer (result
, addr
, addr_len
))
968 return result
->status
;
971 result
->hostent
->h_name
[0] = 0;
974 DNSServiceQueryRecord (
976 0, // reserved flags field
977 k_mdnsd_intfs_local
, // all local interfaces
978 addr_str
, // address string to query for
979 T_PTR
, // pointer RRs
980 C_IN
, // internet class records
981 mdns_lookup_callback
, // callback
982 result
// Context - result buffer
988 "mdns: Failed to initialise mdns lookup, error %d",
991 return set_err_mdns_failed (result
);
994 return handle_events (sdref
, result
, addr_str
);
999 Wait on result of callback, and process it when it arrives.
1005 Initialised 'result' data structure.
1007 lookup string, used for status/error reporting.
1010 handle_events (DNSServiceRef sdref
, result_map_t
* result
, const char * str
)
1012 int dns_sd_fd
= DNSServiceRefSockFD(sdref
);
1013 int nfds
= dns_sd_fd
+ 1;
1018 while (! result
->done
)
1021 FD_SET(dns_sd_fd
, &readfds
);
1026 select (nfds
, &readfds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1027 if (select_result
> 0)
1029 if (FD_ISSET(dns_sd_fd
, &readfds
))
1033 "mdns: Reply received for %s",
1036 DNSServiceProcessResult(sdref
);
1040 syslog (LOG_WARNING
,
1041 "mdns: Unexpected return from select on lookup of %s",
1048 // Terminate loop due to timer expiry
1051 "mdns: %s not found - timer expired",
1054 set_err_notfound (result
);
1059 return result
->status
;
1064 Examine incoming data and add to relevant fields in result structure.
1065 This routine is called from DNSServiceProcessResult where appropriate.
1068 mdns_lookup_callback
1070 DNSServiceRef sdref
,
1071 DNSServiceFlags flags
,
1072 uint32_t interface_index
,
1073 DNSServiceErrorType error_code
,
1074 const char *fullname
,
1083 // A single record is received
1085 result_map_t
* result
= (result_map_t
*) context
;
1087 (void)sdref
; // Unused
1088 (void)interface_index
; // Unused
1089 (void)ttl
; // Unused
1091 if (! (flags
& kDNSServiceFlagsMoreComing
) )
1096 if (error_code
== kDNSServiceErr_NoError
)
1098 ns_type_t expected_rr_type
=
1099 af_to_rr (result
->hostent
->h_addrtype
);
1101 // Idiot check class
1102 if (rrclass
!= C_IN
)
1104 syslog (LOG_WARNING
,
1105 "mdns: Received bad RR class: expected %d (%s),"
1106 " got %d (%s), RR type %d (%s)",
1108 ns_class_to_str (C_IN
),
1110 ns_class_to_str (rrclass
),
1112 ns_type_to_str (rrtype
)
1118 if (rrtype
== T_PTR
)
1120 if (callback_body_ptr (fullname
, result
, rdlen
, rdata
) < 0)
1123 else if (rrtype
== expected_rr_type
)
1126 add_hostname_or_alias (
1138 if (! add_address_to_buffer (result
, rdata
, rdlen
) )
1147 syslog (LOG_WARNING
,
1148 "mdns: Received bad RR type: expected %d (%s),"
1151 ns_type_to_str (expected_rr_type
),
1153 ns_type_to_str (rrtype
)
1158 if (result
->status
!= NSS_STATUS_SUCCESS
)
1159 set_err_success (result
);
1163 // For now, dump message to syslog and continue
1164 syslog (LOG_WARNING
,
1165 "mdns: callback returned error %d",
1173 const char * fullname
,
1174 result_map_t
* result
,
1179 char result_name
[k_hostname_maxlen
+ 1];
1182 // Fullname should be .in-addr.arpa or equivalent, which we're
1183 // not interested in. Ignore it.
1185 rv
= dns_rdata_to_name (rdata
, rdlen
, result_name
, k_hostname_maxlen
);
1188 const char * errmsg
;
1192 case DNS_RDATA_TO_NAME_BAD_FORMAT
:
1193 errmsg
= "mdns: PTR '%s' result badly formatted ('%s...')";
1196 case DNS_RDATA_TO_NAME_TOO_LONG
:
1197 errmsg
= "mdns: PTR '%s' result too long ('%s...')";
1200 case DNS_RDATA_TO_NAME_PTR
:
1201 errmsg
= "mdns: PTR '%s' result contained pointer ('%s...')";
1205 errmsg
= "mdns: PTR '%s' result conversion failed ('%s...')";
1208 syslog (LOG_WARNING
,
1220 "mdns: PTR '%s' resolved to '%s'",
1226 // Data should be a hostname
1228 add_hostname_or_alias (
1244 Add an address to the buffer.
1248 Result structure to write to
1250 Incoming address data buffer
1251 Must be 'int' aligned
1253 Length of data buffer (in bytes)
1254 Must match data alignment
1257 Pointer to start of newly written data,
1259 If address already exists in buffer, returns pointer to that instead.
1262 add_address_to_buffer (result_map_t
* result
, const void * data
, int len
)
1268 if ((temp
= contains_address (result
, data
, len
)))
1273 if (result
->addrs_count
>= k_addrs_max
)
1275 // Not enough addr slots
1276 set_err_internal_resource_full (result
);
1278 "mdns: Internal address buffer full; increase size"
1284 if (len
!= result
->hostent
->h_length
)
1286 syslog (LOG_WARNING
,
1287 "mdns: Unexpected rdata length for address. Expected %d, got %d",
1288 result
->hostent
->h_length
,
1291 // XXX And continue for now.
1294 new_addr
= result
->addr_idx
+ len
;
1296 if (new_addr
> result
->alias_idx
)
1299 set_err_buf_too_small (result
);
1302 "mdns: Ran out of buffer when adding address %d",
1303 result
->addrs_count
+ 1
1308 start
= result
->buffer
+ result
->addr_idx
;
1309 memcpy (start
, data
, len
);
1310 result
->addr_idx
= new_addr
;
1311 result
->header
->addrs
[result
->addrs_count
] = start
;
1312 result
->addrs_count
++;
1313 result
->header
->addrs
[result
->addrs_count
] = NULL
;
1320 contains_address (result_map_t
* result
, const void * data
, int len
)
1325 if (len
!= result
->hostent
->h_length
)
1327 syslog (LOG_WARNING
,
1328 "mdns: Unexpected rdata length for address. Expected %d, got %d",
1329 result
->hostent
->h_length
,
1332 // XXX And continue for now.
1335 for (i
= 0; result
->header
->addrs
[i
]; i
++)
1337 if (memcmp (result
->header
->addrs
[i
], data
, len
) == 0)
1339 return result
->header
->addrs
[i
];
1348 Add an alias to the buffer.
1352 Result structure to write to
1354 Incoming alias (null terminated)
1356 Length of data buffer (in bytes), including trailing null
1359 Pointer to start of newly written data,
1361 If alias already exists in buffer, returns pointer to that instead.
1364 add_alias_to_buffer (result_map_t
* result
, const char * data
, int len
)
1370 if ((temp
= contains_alias (result
, data
)))
1375 if (result
->aliases_count
>= k_aliases_max
)
1377 // Not enough alias slots
1378 set_err_internal_resource_full (result
);
1380 "mdns: Internal alias buffer full; increase size"
1385 new_alias
= result
->alias_idx
- len
;
1387 if (new_alias
< result
->addr_idx
)
1390 set_err_buf_too_small (result
);
1393 "mdns: Ran out of buffer when adding alias %d",
1394 result
->aliases_count
+ 1
1399 start
= result
->buffer
+ new_alias
;
1400 memcpy (start
, data
, len
);
1401 result
->alias_idx
= new_alias
;
1402 result
->header
->aliases
[result
->aliases_count
] = start
;
1403 result
->aliases_count
++;
1404 result
->header
->aliases
[result
->aliases_count
] = NULL
;
1411 contains_alias (result_map_t
* result
, const char * alias
)
1415 for (i
= 0; result
->header
->aliases
[i
]; i
++)
1417 if (strcmp (result
->header
->aliases
[i
], alias
) == 0)
1419 return result
->header
->aliases
[i
];
1428 Add fully qualified hostname to result.
1432 Result structure to write to
1434 Fully qualified hostname
1437 Pointer to start of hostname buffer,
1438 or NULL on error (usually hostname too long)
1442 add_hostname_len (result_map_t
* result
, const char * fullname
, int len
)
1444 if (len
>= k_hostname_maxlen
)
1446 set_err_bad_hostname (result
);
1447 syslog (LOG_WARNING
,
1448 "mdns: Hostname too long '%.*s': len %d, max %d",
1457 result
->hostent
->h_name
=
1458 strcpy (result
->header
->hostname
, fullname
);
1460 return result
->header
->hostname
;
1465 Add fully qualified name as hostname or alias.
1467 If hostname is not fully qualified this is not an error, but the data
1468 returned may be not what the application wanted.
1472 Result structure to write to
1474 Incoming alias (null terminated)
1476 Length of data buffer (in bytes), including trailing null
1479 Pointer to start of newly written data,
1481 If alias or hostname already exists, returns pointer to that instead.
1484 add_hostname_or_alias (result_map_t
* result
, const char * data
, int len
)
1486 char * hostname
= result
->hostent
->h_name
;
1490 if (strcmp (hostname
, data
) == 0)
1496 return add_alias_to_buffer (result
, data
, len
);
1501 return add_hostname_len (result
, data
, len
);
1508 result_map_t
* result
,
1509 hostent
* result_buf
,
1514 if (buflen
< sizeof (buf_header_t
))
1519 result
->hostent
= result_buf
;
1520 result
->header
= (buf_header_t
*) buf
;
1521 result
->header
->hostname
[0] = 0;
1522 result
->aliases_count
= 0;
1523 result
->header
->aliases
[0] = NULL
;
1524 result
->addrs_count
= 0;
1525 result
->header
->addrs
[0] = NULL
;
1526 result
->buffer
= buf
+ sizeof (buf_header_t
);
1527 result
->addr_idx
= 0;
1528 result
->alias_idx
= buflen
- sizeof (buf_header_t
);
1530 set_err_notfound (result
);
1532 // Point hostent to the right buffers
1533 result
->hostent
->h_name
= result
->header
->hostname
;
1534 result
->hostent
->h_aliases
= result
->header
->aliases
;
1535 result
->hostent
->h_addr_list
= result
->header
->addrs
;
1541 Set the status in the result.
1545 Result structure to update
1547 New nss_status value
1557 set_err (result_map_t
* result
, nss_status status
, int err
, int herr
)
1559 result
->status
= status
;
1560 result
->r_errno
= err
;
1561 result
->r_h_errno
= herr
;
1567 set_err_notfound (result_map_t
* result
)
1569 return set_err (result
, NSS_STATUS_NOTFOUND
, ENOENT
, HOST_NOT_FOUND
);
1573 set_err_bad_hostname (result_map_t
* result
)
1575 return set_err (result
, NSS_STATUS_TRYAGAIN
, ENOENT
, NO_RECOVERY
);
1579 set_err_buf_too_small (result_map_t
* result
)
1581 return set_err (result
, NSS_STATUS_TRYAGAIN
, ERANGE
, NETDB_INTERNAL
);
1585 set_err_internal_resource_full (result_map_t
* result
)
1587 return set_err (result
, NSS_STATUS_RETURN
, ERANGE
, NO_RECOVERY
);
1591 set_err_system (result_map_t
* result
)
1593 return set_err (result
, NSS_STATUS_UNAVAIL
, errno
, NETDB_INTERNAL
);
1597 set_err_mdns_failed (result_map_t
* result
)
1599 return set_err (result
, NSS_STATUS_TRYAGAIN
, EAGAIN
, TRY_AGAIN
);
1603 set_err_success (result_map_t
* result
)
1605 result
->status
= NSS_STATUS_SUCCESS
;
1606 return result
->status
;
1611 Test whether name is applicable for mdns to process, and if so copy into
1612 lookup_name buffer (if non-NULL).
1615 Pointer to name to lookup up, if applicable, or NULL otherwise.
1618 is_applicable_name (
1619 result_map_t
* result
,
1624 int match
= config_is_mdns_suffix (name
);
1629 strncpy (lookup_name
, name
, k_hostname_maxlen
+ 1);
1641 set_err_system (result
);
1648 Test whether address is applicable for mdns to process, and if so copy into
1649 addr_str buffer as an address suitable for ptr lookup.
1652 Pointer to name to lookup up, if applicable, or NULL otherwise.
1655 is_applicable_addr (
1656 result_map_t
* result
,
1664 if (! format_reverse_addr (af
, addr
, -1, addr_str
))
1668 "mdns: Failed to create reverse address"
1675 "mdns: Reverse address: %s",
1679 match
= config_is_mdns_suffix (addr_str
);
1688 set_err_system (result
);
1695 // Types and Constants
1697 const char * k_conf_file
= "/etc/nss_mdns.conf";
1698 #define CONF_LINE_SIZE 1024
1700 const char k_comment_char
= '#';
1702 const char * k_keyword_domain
= "domain";
1704 const char * k_default_domains
[] =
1707 "254.169.in-addr.arpa",
1711 // Always null terminated
1714 // Linked list of domains
1715 typedef struct domain_entry
1718 struct domain_entry
* next
;
1725 domain_entry_t
* domains
;
1728 const config_t k_empty_config
=
1734 // Context - tracks position in config file, used for error reporting
1737 const char * filename
;
1739 } config_file_context_t
;
1746 load_config (config_t
* conf
);
1749 process_config_line (
1752 config_file_context_t
* context
1756 get_next_word (char * input
, char **next
);
1759 default_config (config_t
* conf
);
1762 add_domain (config_t
* conf
, const char * domain
);
1765 contains_domain (const config_t
* conf
, const char * domain
);
1768 contains_domain_suffix (const config_t
* conf
, const char * addr
);
1774 static config_t
* g_config
= NULL
;
1775 // Configuration info
1777 pthread_mutex_t g_config_mutex
=
1778 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
1779 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
1781 PTHREAD_MUTEX_INITIALIZER
;
1786 // Configuration functions
1790 Initialise the configuration from the config file.
1794 non-zero error code on failure
1802 Safe to test outside mutex.
1803 If non-zero, initialisation is complete and g_config can be
1804 safely used read-only. If zero, then we do proper mutex
1805 testing before initialisation.
1813 config_t
* temp_config
;
1816 presult
= pthread_mutex_lock (&g_config_mutex
);
1820 "mdns: Fatal mutex lock error in nss_mdns:init_config, %s:%d: %d: %s",
1821 __FILE__
, __LINE__
, presult
, strerror (presult
)
1826 // Test again now we have mutex, in case initialisation occurred while
1830 temp_config
= (config_t
*) malloc (sizeof (config_t
));
1833 // NOTE: This code will leak memory if initialisation fails
1834 // repeatedly. This should only happen in the case of a memory
1835 // error, so I'm not sure if it's a meaningful problem. - AW
1836 *temp_config
= k_empty_config
;
1837 errcode
= load_config (temp_config
);
1841 g_config
= temp_config
;
1847 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
1854 presult
= pthread_mutex_unlock (&g_config_mutex
);
1858 "mdns: Fatal mutex unlock error in nss_mdns:init_config, %s:%d: %d: %s",
1859 __FILE__
, __LINE__
, presult
, strerror (presult
)
1870 config_is_mdns_suffix (const char * name
)
1872 int errcode
= init_config ();
1875 return contains_domain_suffix (g_config
, name
);
1889 load_config (config_t
* conf
)
1892 char line
[CONF_LINE_SIZE
];
1893 config_file_context_t context
;
1895 context
.filename
= k_conf_file
;
1896 context
.linenum
= 0;
1899 cf
= fopen (context
.filename
, "r");
1903 "mdns: Couldn't open nss_mdns configuration file %s, using default.",
1906 return default_config (conf
);
1909 while (fgets (line
, CONF_LINE_SIZE
, cf
))
1913 errcode
= process_config_line (conf
, line
, &context
);
1916 // Critical error, give up
1926 Parse a line of the configuration file.
1927 For each keyword recognised, perform appropriate handling.
1928 If the keyword is not recognised, print a message to syslog
1932 0 success, or recoverable config file error
1933 non-zero serious system error, processing aborted
1936 process_config_line (
1939 config_file_context_t
* context
1945 word
= get_next_word (curr
, &curr
);
1946 if (! word
|| word
[0] == k_comment_char
)
1948 // Nothing interesting on this line
1952 if (strcmp (word
, k_keyword_domain
) == 0)
1954 word
= get_next_word (curr
, &curr
);
1957 int errcode
= add_domain (conf
, word
);
1960 // something badly wrong, bail
1964 if (get_next_word (curr
, NULL
))
1966 syslog (LOG_WARNING
,
1967 "%s, line %d: ignored extra text found after domain",
1975 syslog (LOG_WARNING
,
1976 "%s, line %d: no domain specified",
1984 syslog (LOG_WARNING
,
1985 "%s, line %d: unknown keyword %s - skipping",
1997 Get next word (whitespace separated) from input string.
1998 A null character is written into the first whitespace character following
2003 Input string. This string is modified by get_next_word.
2005 If non-NULL and the result is non-NULL, a pointer to the
2006 character following the end of the word (after the null)
2007 is written to 'next'.
2008 If no word is found, the original value is unchanged.
2009 If the word extended to the end of the string, 'next' points
2010 to the trailling NULL.
2011 It is safe to pass 'str' as 'input' and '&str' as 'next'.
2013 Pointer to the first non-whitespace character (and thus word) found.
2014 if no word is found, returns NULL.
2017 get_next_word (char * input
, char **next
)
2019 char * curr
= input
;
2022 while (isspace (*curr
))
2033 while (*curr
&& ! isspace (*curr
))
2058 default_config (config_t
* conf
)
2061 for (i
= 0; k_default_domains
[i
]; i
++)
2064 add_domain (conf
, k_default_domains
[i
]);
2067 // Something has gone (badly) wrong - let's bail
2077 add_domain (config_t
* conf
, const char * domain
)
2079 if (! contains_domain (conf
, domain
))
2081 domain_entry_t
* d
=
2082 (domain_entry_t
*) malloc (sizeof (domain_entry_t
));
2086 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
2092 d
->domain
= strdup (domain
);
2096 "mdns: Can't allocate memory in nss_mdns:init_config, %s:%d",
2102 d
->next
= conf
->domains
;
2111 contains_domain (const config_t
* conf
, const char * domain
)
2113 const domain_entry_t
* curr
= conf
->domains
;
2115 while (curr
!= NULL
)
2117 if (strcasecmp (curr
->domain
, domain
) == 0)
2130 contains_domain_suffix (const config_t
* conf
, const char * addr
)
2132 const domain_entry_t
* curr
= conf
->domains
;
2134 while (curr
!= NULL
)
2136 if (cmp_dns_suffix (addr
, curr
->domain
) > 0)
2148 // Types and Constants
2150 static const char * k_local_suffix
= "local";
2151 static const char k_dns_separator
= '.';
2153 static const int k_label_maxlen
= DNS_LABEL_MAXLEN
;
2154 // Label entries longer than this are actually pointers.
2160 const char * comment
;
2163 static const table_entry_t k_table_af
[] =
2165 { AF_UNSPEC
, NULL
, NULL
},
2166 { AF_LOCAL
, "LOCAL", NULL
},
2167 { AF_UNIX
, "UNIX", NULL
},
2168 { AF_INET
, "INET", NULL
},
2169 { AF_INET6
, "INET6", NULL
}
2171 static const int k_table_af_size
=
2172 sizeof (k_table_af
) / sizeof (* k_table_af
);
2174 static const char * k_table_ns_class
[] =
2179 static const int k_table_ns_class_size
=
2180 sizeof (k_table_ns_class
) / sizeof (* k_table_ns_class
);
2182 static const char * k_table_ns_type
[] =
2227 static const int k_table_ns_type_size
=
2228 sizeof (k_table_ns_type
) / sizeof (* k_table_ns_type
);
2235 simple_table_index (const char * table
[], int size
, const char * str
);
2238 table_index_name (const table_entry_t table
[], int size
, const char * str
);
2241 table_index_value (const table_entry_t table
[], int size
, int n
);
2252 count_dots (const char * name
)
2256 for (i
= 0; name
[i
]; i
++)
2258 if (name
[i
] == k_dns_separator
)
2267 islocal (const char * name
)
2269 return cmp_dns_suffix (name
, k_local_suffix
) > 0;
2274 rr_to_af (ns_type_t rrtype
)
2302 //return ns_t_invalid;
2309 str_to_af (const char * str
)
2312 table_index_name (k_table_af
, k_table_af_size
, str
);
2316 return k_table_af
[result
].value
;
2321 str_to_ns_class (const char * str
)
2324 simple_table_index (k_table_ns_class
, k_table_ns_class_size
, str
);
2329 str_to_ns_type (const char * str
)
2332 simple_table_index (k_table_ns_type
, k_table_ns_type_size
, str
);
2340 table_index_value (k_table_af
, k_table_af_size
, in
);
2344 return k_table_af
[result
].name
;
2349 ns_class_to_str (ns_class_t in
)
2351 if (in
< k_table_ns_class_size
)
2352 return k_table_ns_class
[in
];
2359 ns_type_to_str (ns_type_t in
)
2361 if (in
< k_table_ns_type_size
)
2362 return k_table_ns_type
[in
];
2369 format_reverse_addr_in (
2370 const struct in_addr
* addr
,
2378 const uint8_t * in_addr_a
= (uint8_t *) addr
;
2385 i
= (prefixlen
+ 7) / 8;
2386 // divide prefixlen into bytes, rounding up
2391 curr
+= sprintf (curr
, "%d.", in_addr_a
[i
]);
2393 sprintf (curr
, "in-addr.arpa");
2400 format_reverse_addr_in6 (
2401 const struct in6_addr
* addr
,
2409 const uint8_t * in_addr_a
= (uint8_t *) addr
;
2411 if (prefixlen
> 128)
2416 i
= (prefixlen
+ 3) / 4;
2417 // divide prefixlen into nibbles, rounding up
2419 // Special handling for first
2422 curr
+= sprintf (curr
, "%d.", (in_addr_a
[i
] >> 4) & 0x0F);
2425 // Convert i to bytes (divide by 2)
2432 val
= in_addr_a
[i
];
2433 curr
+= sprintf (curr
, "%x.%x.", val
& 0x0F, (val
>> 4) & 0x0F);
2435 sprintf (curr
, "ip6.arpa");
2442 format_reverse_addr (
2453 format_reverse_addr_in (
2454 (struct in_addr
*) addr
, prefixlen
, buf
2460 format_reverse_addr_in6 (
2461 (struct in6_addr
*) addr
, prefixlen
, buf
2472 cmp_dns_suffix (const char * name
, const char * domain
)
2474 const char * nametail
;
2475 const char * domaintail
;
2478 if (*name
== 0 || *name
== k_dns_separator
)
2480 // Name can't be empty or start with separator
2481 return CMP_DNS_SUFFIX_BAD_NAME
;
2486 return CMP_DNS_SUFFIX_SUCCESS
;
2490 if (*domain
== k_dns_separator
)
2492 // drop leading separator from domain
2494 if (*domain
== k_dns_separator
)
2496 return CMP_DNS_SUFFIX_BAD_DOMAIN
;
2500 // Find ends of strings
2501 for (nametail
= name
; *nametail
; nametail
++)
2503 for (domaintail
= domain
; *domaintail
; domaintail
++)
2506 // Shuffle back to last real character, and drop any trailing '.'
2507 // while we're at it.
2509 if (*nametail
== k_dns_separator
)
2512 if (*nametail
== k_dns_separator
)
2514 return CMP_DNS_SUFFIX_BAD_NAME
;
2518 if (*domaintail
== k_dns_separator
)
2521 if (*domaintail
== k_dns_separator
)
2523 return CMP_DNS_SUFFIX_BAD_DOMAIN
;
2530 && domaintail
>= domain
2531 && tolower(*nametail
) == tolower(*domaintail
))
2537 /* A successful finish will be one of the following:
2538 (leading and trailing . ignored)
2540 name : domain2.domain1
2541 domain: domain2.domain1
2544 name : domain3.domain2.domain1
2545 domain: domain2.domain1
2550 && (nametail
< name
|| *nametail
== k_dns_separator
)
2553 return CMP_DNS_SUFFIX_SUCCESS
;
2557 return CMP_DNS_SUFFIX_FAILURE
;
2563 dns_rdata_to_name (const char * rdata
, int rdlen
, char * name
, int name_len
)
2566 // Index into 'name'
2567 const char * rdata_curr
= rdata
;
2569 // drop any leading whitespace rubbish
2570 while (isspace (*rdata_curr
))
2573 if (rdata_curr
> rdata
+ rdlen
)
2575 return DNS_RDATA_TO_NAME_BAD_FORMAT
;
2580 In RDATA, a DNS name is stored as a series of labels.
2581 Each label consists of a length octet (max value 63)
2582 followed by the data for that label.
2583 The series is terminated with a length 0 octet.
2584 A length octet beginning with bits 11 is a pointer to
2585 somewhere else in the payload, but we don't support these
2586 since we don't have access to the entire payload.
2588 See RFC1034 section 3.1 and RFC1035 section 3.1.
2592 int term_len
= *rdata_curr
;
2598 // 0 length record terminates label
2600 else if (term_len
> k_label_maxlen
)
2603 return DNS_RDATA_TO_NAME_PTR
;
2605 else if (rdata_curr
+ term_len
> rdata
+ rdlen
)
2608 return DNS_RDATA_TO_NAME_BAD_FORMAT
;
2611 if (name_len
< i
+ term_len
+ 1)
2615 return DNS_RDATA_TO_NAME_TOO_LONG
;
2618 memcpy (name
+ i
, rdata_curr
, term_len
);
2621 rdata_curr
+= term_len
;
2623 name
[i
] = k_dns_separator
;
2636 Find the index of an string entry in a table. A case insenitive match
2637 is performed. If no entry is found, 0 is returned.
2642 Table entries may be NULL. NULL entries will never match.
2644 number of entries in table
2649 index of first matching entry, or 0 if no matches
2652 simple_table_index (const char * table
[], int size
, const char * str
)
2655 for (i
= 0; i
< size
; i
++)
2659 && (strcasecmp (table
[i
], str
) == 0)
2671 Find the index of a name in a table.
2675 array of table_entry_t records. The name field is compared
2676 (ignoring case) to the input string.
2678 number of entries in table
2683 index of first matching entry, or -1 if no matches
2686 table_index_name (const table_entry_t table
[], int size
, const char * str
)
2689 for (i
= 0; i
< size
; i
++)
2693 && (strcasecmp (table
[i
].name
, str
) == 0)
2705 Find the index of a value a table.
2709 array of table_entry_t records. The value field is compared to
2712 number of entries in table
2717 index of first matching entry, or -1 if no matches
2720 table_index_value (const table_entry_t table
[], int size
, int n
)
2723 for (i
= 0; i
< size
; i
++)
2725 if (table
[i
].value
== n
)