nss-mdns is an extension to glibc to support resolution of link-local (.local) addresses via GNU Name Service Switch (NSS) which redirects the queries to a running avahi-daemon, which in turn does the resolution via multicast DNS (mdns).
However, this does not work for uClibc, as it does not support NSS. This patch integrates the nss-mdns approach into uClibc's resolver, so getaddrinfo() and getnameinfo() calls get redirected to a running avahi-daemon before trying to resolve via unicast DNS. This increases the size of the library by 50 bytes on ARM. Signed-off-by: Nikolaus Voss <[email protected]> --- extra/Configs/Config.in | 19 +++++ libc/inet/Makefile.in | 1 + libc/inet/avahi.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++ libc/inet/resolv.c | 43 ++++++++++-- 4 files changed, 240 insertions(+), 5 deletions(-) create mode 100644 libc/inet/avahi.c diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in index e41adc4..0846ec2 100644 --- a/extra/Configs/Config.in +++ b/extra/Configs/Config.in @@ -1268,6 +1268,25 @@ config UCLIBC_HAS_EXTRA_COMPAT_RES_STATE Answer Y if selecting UCLIBC_HAS_COMPAT_RES_STATE is not enough. As far as I can say, this should never be needed. +config UCLIBC_HAS_AVAHI_RES + bool "Try to resolve link-local IP addresses via avahi-daemon" + default y + depends on UCLIBC_HAS_SOCKET + help + Answer Y if you want to resolve .local addresses via multicast-dns. + The queries are forwarded to a running avahi-daemon via a domain + socket interface. + Note that this might interfere with a .local domain on your DNS. + Answering N saves around 50 bytes. + +config UCLIBC_AVAHI_SOCKET_PATH + string "Path to avahi unix domain socket" + default "/var/run/avahi-daemon/socket" + depends on UCLIBC_HAS_AVAHI_RES + help + A running avahi-daemon creates a socket to listen for queries. + Enter the path you configured your avahi-daemon to. + config UCLIBC_HAS_LIBRESOLV_STUB bool "Provide libresolv stub" default n diff --git a/libc/inet/Makefile.in b/libc/inet/Makefile.in index d588220..7f436c9 100644 --- a/libc/inet/Makefile.in +++ b/libc/inet/Makefile.in @@ -33,6 +33,7 @@ CSRC-$(findstring y,$(UCLIBC_HAS_IPV4)$(UCLIBC_HAS_IPV6)) += \ dnslookup.c opennameservers.c closenameservers.c \ getnameinfo.c \ gethostent.c gethostent_r.c +CSRC-$(UCLIBC_HAS_AVAHI_RES) += avahi.c CSRC-$(findstring y,$(UCLIBC_HAS_IPV4)$(UCLIBC_HAS_IPV6)) += \ get_hosts_byaddr_r.c get_hosts_byname_r.c \ gethostbyaddr_r.c gethostbyname_r.c gethostbyname2_r.c \ diff --git a/libc/inet/avahi.c b/libc/inet/avahi.c new file mode 100644 index 0000000..83e790f --- /dev/null +++ b/libc/inet/avahi.c @@ -0,0 +1,182 @@ +/* + * + * (C) 2011 Weinmann GmbH, Hamburg, Germany + * + * Author: Nikolaus Voss <[email protected]> + * + * Derived from avahi.c / nss-mdns by Lennart Poettering. + * Copyright 2004-2007 Lennart Poettering <mzaffzqaf (at) 0pointer (dot) de> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * + */ + +#include <arpa/inet.h> +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <unistd.h> + +int __avahi_resolve_name(int af, const char* name, void* data) attribute_hidden; + +int __avahi_resolve_address(int af, const void *data, char* name, + size_t name_len) attribute_hidden; + +#define WHITESPACE " \t" + +static int set_cloexec(int fd) +{ + int n; + + assert(fd >= 0); + + if ((n = fcntl(fd, F_GETFD)) < 0) + return -1; + + if (n & FD_CLOEXEC) + return 0; + + return fcntl(fd, F_SETFD, n|FD_CLOEXEC); +} + +static FILE *open_socket(void) +{ + int fd = -1; + struct sockaddr_un sa; + FILE *f = NULL; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + goto fail; + + set_cloexec(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, __UCLIBC_AVAHI_SOCKET_PATH__, + sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path)-1] = 0; + + if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) + goto fail; + + if (!(f = fdopen(fd, "r+"))) + goto fail; + + return f; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +int attribute_hidden __avahi_resolve_name(int af, const char* name, void* data) +{ + FILE *f = NULL; + char *p; + int ret = -1; + char ln[256]; + + if (af != AF_INET && af != AF_INET6) + goto finish; + + if (!(f = open_socket())) + goto finish; + + fprintf(f, "RESOLVE-HOSTNAME%s %s\n", af == AF_INET ? "-IPV4" : "-IPV6", name); + fflush(f); + + if (!(fgets(ln, sizeof(ln), f))) + goto finish; + + if (ln[0] != '+') { + ret = 1; + goto finish; + } + + p = ln+1; + p += strspn(p, WHITESPACE); + + /* Skip interface */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip protocol */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip host name */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Cut off end of line */ + *(p + strcspn(p, "\n\r\t ")) = 0; + + if (inet_pton(af, p, data) <= 0) + goto finish; + + ret = 0; + +finish: + + if (f) + fclose(f); + + return ret; +} + +int attribute_hidden __avahi_resolve_address(int af, const void *data, + char* name, size_t name_len) +{ + FILE *f = NULL; + char *p; + int ret = -1; + char a[256], ln[256]; + + if (af != AF_INET && af != AF_INET6) + goto finish; + + if (!(f = open_socket())) + goto finish; + + fprintf(f, "RESOLVE-ADDRESS %s\n", inet_ntop(af, data, a, sizeof(a))); + + if (!(fgets(ln, sizeof(ln), f))) + goto finish; + + if (ln[0] != '+') { + ret = 1; + goto finish; + } + + p = ln+1; + p += strspn(p, WHITESPACE); + + /* Skip interface */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip protocol */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Cut off end of line */ + *(p + strcspn(p, "\n\r\t ")) = 0; + + strncpy(name, p, name_len-1); + name[name_len-1] = 0; + + ret = 0; + +finish: + + if (f) + fclose(f); + + return ret; +} diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 021d5bf..e33bf36 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -479,6 +479,14 @@ extern int __encode_answer(struct resolv_answer *a, extern void __open_nameservers(void) attribute_hidden; extern void __close_nameservers(void) attribute_hidden; +#ifdef __UCLIBC_HAS_AVAHI_RES__ +extern int __avahi_resolve_name(int af, const char* name, + void* data) attribute_hidden; + +extern int __avahi_resolve_address(int af, const void *data, char* name, + size_t name_len) attribute_hidden; +#endif + /* * Theory of operation. * @@ -1963,7 +1971,6 @@ DONE: libc_hidden_def(getnameinfo) #endif - #ifdef L_gethostbyname_r /* Bug 671 says: @@ -2073,10 +2080,15 @@ int gethostbyname_r(const char *name, alias[0] = alias0; alias[1] = NULL; - /* maybe it is already an address? */ + /* maybe it is resolvable via avahi or already an address? */ { struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2); - if (inet_aton(name, in)) { +#ifdef __UCLIBC_HAS_AVAHI_RES__ + if (!__avahi_resolve_name(AF_INET, name, in) || +#else + if ( +#endif + inet_aton(name, in)) { addr_list[0] = in; addr_list[1] = NULL; result_buf->h_name = alias0; @@ -2263,8 +2275,13 @@ int gethostbyname2_r(const char *name, strncpy(buf, name, buflen); buf[buflen] = '\0'; - /* maybe it is already an address? */ - if (inet_pton(AF_INET6, name, in)) { + /* maybe it is resolvable via avahi or already an address? */ +#ifdef __UCLIBC_HAS_AVAHI_RES__ + if (!__avahi_resolve_name(AF_INET6, name, in) || +#else + if ( +#endif + inet_pton(AF_INET6, name, in)) { result_buf->h_name = buf; result_buf->h_addrtype = AF_INET6; result_buf->h_length = sizeof(*in); @@ -2425,6 +2442,22 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen, addr_list[1] = NULL; memcpy(in, addr, addrlen); +#ifdef __UCLIBC_HAS_AVAHI_RES__ + // is this a .local address? + if (!__avahi_resolve_address(type, in, alias[0], + sizeof(*addr_list) * 2)) + { + result_buf->h_name = alias[0]; + result_buf->h_addrtype = type; + result_buf->h_length = addrlen; + result_buf->h_addr_list = (char **) addr_list; + result_buf->h_aliases = alias; + *result = result_buf; + *h_errnop = NETDB_SUCCESS; + return NETDB_SUCCESS; + } +#endif + if (0) /* nothing */; #ifdef __UCLIBC_HAS_IPV4__ else IF_HAS_BOTH(if (type == AF_INET)) { -- 1.7.5.4 _______________________________________________ uClibc mailing list [email protected] http://lists.busybox.net/mailman/listinfo/uclibc
