Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mdns minimal mode #89

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,17 @@ addresses via mDNS, most people will want to use
`libnss_mdns.so.2` or `libnss_mdns6.so.2` in such a
situation causes long timeouts when resolving hosts since most modern
Unix/Linux applications check for IPv6 addresses first, followed by a
lookup for IPv4.
lookup for IPv4. When these plugins cannot open mdns.allow config file,
they will behave like minimal version below.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention the downside of having mdns.allow as well.


`libnss_mdns{4,6,}_minimal.so` (new in version 0.8) is mostly
identical to the versions without `_minimal`. However, they differ in
one way. The minimal versions will always deny to resolve host names
that don't end in `.local` or addresses that aren't in the range
`169.254.x.x` (the range used by
[IPV4LL/APIPA/RFC3927](http://files.zeroconf.org/rfc3927.txt).)
[IPV4LL/APIPA/RFC3927](https://www.rfc-editor.org/rfc/rfc3927)) or
`fe80::/10`
([IPv6 link-local](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.6)).
Combining the `_minimal` and the normal NSS modules allows us to make
mDNS authoritative for Zeroconf host names and addresses (and thus
creating no extra burden on DNS servers with always failing requests)
Expand Down
47 changes: 29 additions & 18 deletions src/nss.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@
#include "util.h"
#include "nss.h"

#ifdef MDNS_MINIMAL
#ifdef MDNS_ALLOW_FILE
# undef MDNS_ALLOW_FILE
#endif
#define MDNS_ALLOW_FILE NULL
#endif

static avahi_resolve_result_t do_avahi_resolve_name(int af, const char* name,
userdata_t* userdata) {
bool ipv4_found = false;
Expand Down Expand Up @@ -84,8 +91,6 @@ static avahi_resolve_result_t do_avahi_resolve_name(int af, const char* name,
enum nss_status _nss_mdns_gethostbyname_impl(const char* name, int af,
userdata_t* u, int* errnop,
int* h_errnop) {

FILE* mdns_allow_file = NULL;
use_name_result_t result;

#ifdef NSS_IPV4_ONLY
Expand Down Expand Up @@ -115,16 +120,8 @@ enum nss_status _nss_mdns_gethostbyname_impl(const char* name, int af,

u->count = 0;

#ifndef MDNS_MINIMAL
mdns_allow_file = fopen(MDNS_ALLOW_FILE, "r");
#endif
result = verify_name_allowed_with_soa(name, mdns_allow_file,
result = verify_name_allowed_with_soa(name, MDNS_ALLOW_FILE,
TEST_LOCAL_SOA_AUTO);
#ifndef MDNS_MINIMAL
if (mdns_allow_file)
fclose(mdns_allow_file);
#endif

if (result == USE_NAME_RESULT_SKIP) {
*errnop = EINVAL;
*h_errnop = NO_RECOVERY;
Expand Down Expand Up @@ -224,6 +221,23 @@ enum nss_status _nss_mdns_gethostbyname_r(const char* name,
errnop, h_errnop);
}

/* Reverse addresses are not supported in config file.
* They just check if config is missing to enable minimal mode
* from non-minimal plugins. */
static int avahi_is_file_present(const char *path) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about rather call it _nss_mdns_file_exists() and _nss_mdns_is_link_local() (and switch logic in the function to match the name) . They are static functions for this module with no relevance to avahi.

if (!path)
return 0;
return (access(path, R_OK) == 0);
}

static int avahi_is_not_link_local(const void *addr, int af) {
return
((af == AF_INET &&
((ntohl(*(const uint32_t*)addr) & 0xFFFF0000UL) != 0xA9FE0000UL)) ||
(af == AF_INET6 && !(((const uint8_t*)addr)[0] == 0xFE &&
(((const uint8_t*)addr)[1] >> 6) == 2)));
}

enum nss_status _nss_mdns_gethostbyaddr_r(const void* addr, int len, int af,
struct hostent* result, char* buffer,
size_t buflen, int* errnop,
Expand All @@ -250,17 +264,14 @@ enum nss_status _nss_mdns_gethostbyaddr_r(const void* addr, int len, int af,
return NSS_STATUS_UNAVAIL;
}

#ifdef MDNS_MINIMAL
/* Only query for 169.254.0.0/16 IPv4 in minimal mode */
if ((af == AF_INET &&
((ntohl(*(const uint32_t*)addr) & 0xFFFF0000UL) != 0xA9FE0000UL)) ||
(af == AF_INET6 && !(((const uint8_t*)addr)[0] == 0xFE &&
(((const uint8_t*)addr)[1] >> 6) == 2))) {
/* Only query for 169.254.0.0/16 IPv4 in minimal mode.
* Assume minimal mode if the config file is missing. */
if (!avahi_is_file_present(MDNS_ALLOW_FILE) &&
avahi_is_not_link_local(addr, af)) {
*errnop = EINVAL;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
#endif

/* Lookup using Avahi */
buffer_t buf;
Expand Down
13 changes: 11 additions & 2 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,18 @@ int ends_with(const char* name, const char* suffix) {
}

use_name_result_t verify_name_allowed_with_soa(const char* name,
FILE* mdns_allow_file,
const char* mdns_allow_path,
test_local_soa_t test) {
switch (verify_name_allowed(name, mdns_allow_file)) {
FILE* mdns_allow_file = NULL;
verify_name_result_t result;

if (mdns_allow_path && test == TEST_LOCAL_SOA_AUTO)
mdns_allow_file = fopen(mdns_allow_path, "r");
result = verify_name_allowed(name, mdns_allow_file);
if (mdns_allow_file)
fclose(mdns_allow_file);

switch (result) {
case VERIFY_NAME_RESULT_NOT_ALLOWED:
return USE_NAME_RESULT_SKIP;
case VERIFY_NAME_RESULT_ALLOWED:
Expand Down
4 changes: 2 additions & 2 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ typedef enum {

// Returns true if we should try to resolve the name with mDNS.
//
// If mdns_allow_file is NULL, then this implements the "local" SOA
// If mdns_allow_path is NULL, then this implements the "local" SOA
// check and two-label name checks 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", or if the
Expand All @@ -84,7 +84,7 @@ typedef enum {
// The two heuristics described above are disabled if mdns_allow_file
// is not NULL.
use_name_result_t verify_name_allowed_with_soa(const char* name,
FILE* mdns_allow_file,
const char* mdns_allow_path,
test_local_soa_t test);

typedef enum {
Expand Down