Skip to content

Commit

Permalink
Check for "local" SOA unicast records before doing an mDNS lookup
Browse files Browse the repository at this point in the history
If a DNS operator has records for "local" they probably don't want
mDNS to override them. The standard way to tell this is by doing an SOA
lookup for "local" and refusing to do an mDNS lookup if unicast DNS
claims authority.

This change allows avahi to always run and perform service discovery
while continuing to allow unicast DNS servers to return A and AAAA
records for "local" names.

Problematic boot time detection is no longer required, and since SOA
resolution is done as needed, clients will dynamically react to
configuration updates of unicast "local" resolution.

See Apple's description of their implementation of this functionality:
https://support.apple.com/en-us/HT201275
  • Loading branch information
agoode committed Aug 14, 2016
1 parent d953939 commit ae3a907
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ AC_HEADER_TIME
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_SELECT_ARGTYPES
AC_SEARCH_LIBS([__res_nquery], [resolv])
AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn])

# FreeBSD has a slightly different NSS interface
Expand Down
36 changes: 34 additions & 2 deletions src/nss.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include <nss.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>


#include "avahi.h"

Expand Down Expand Up @@ -131,13 +135,41 @@ static int ends_with(const char *name, const char* suffix) {
return strcasecmp(name+ln-ls, suffix) == 0;
}

// Returns true if a DNS server claims authority over "local".
static int local_soa(void) {
struct __res_state state;
int result;
unsigned char answer[NS_MAXMSG];

result = res_ninit(&state);
if (result == -1)
return 0;
result = res_nquery(&state, "local", ns_c_in, ns_t_soa,
answer, sizeof answer);
res_nclose(&state);
return result > 0;
}

// Returns true if we should try to resolve the name with mDNS.
//
// Implements the "local" SOA check similarly to the algorithm described at
// https://support.apple.com/en-us/HT201275.
// This means that if a unicast DNS server claims authority on "local",
// we will not do mDNS resolution on these names.
//
// We will always do mDNS resolution on non-"local" names if they are listed
// in MDNS_ALLOW_FILE.
static int verify_name_allowed(const char *name) {
#ifndef MDNS_MINIMAL
FILE *f;
#endif
int ends_with_local;

assert(name);

ends_with_local =
ends_with(name, ".local") || ends_with(name, ".local.");

#ifndef MDNS_MINIMAL
if ((f = fopen(MDNS_ALLOW_FILE, "r"))) {
int valid = 0;
Expand Down Expand Up @@ -171,11 +203,11 @@ static int verify_name_allowed(const char *name) {
}

fclose(f);
return valid;
return valid && (!ends_with_local || !local_soa());
}
#endif

return ends_with(name, ".local") || ends_with(name, ".local.");
return ends_with_local && !local_soa();
}

enum nss_status _nss_mdns_gethostbyname2_r(
Expand Down

0 comments on commit ae3a907

Please sign in to comment.