[PATCH] Make link-local addresses resolvable via running avahi-daemon.
Nikolaus Voss
n.voss at weinmann.de
Wed Nov 23 13:31:33 UTC 2011
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 <n.voss at weinmann.de>
---
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 <n.voss at weinmann.de>
+ *
+ * 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
More information about the uClibc
mailing list