From 6dc69c9a94e128f6703ddfcc38c253f0c8cc9d7b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jun 2005 00:36:49 +0000 Subject: * add support for using an avahi daemon if available git-svn-id: file:///home/lennart/svn/public/nss-mdns/trunk@81 0ee8848e-81ea-0310-a63a-f631d1a40d77 --- configure.ac | 17 +++++++ src/Makefile.am | 11 +++-- src/avahi-test.c | 48 ++++++++++++++++++ src/avahi.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/avahi.h | 33 +++++++++++++ src/nss.c | 103 +++++++++++++++++++++++++++------------ src/query.c | 2 +- 7 files changed, 324 insertions(+), 35 deletions(-) create mode 100644 src/avahi-test.c create mode 100644 src/avahi.c create mode 100644 src/avahi.h diff --git a/configure.ac b/configure.ac index 2f41827..e8d42ce 100644 --- a/configure.ac +++ b/configure.ac @@ -83,5 +83,22 @@ fi AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) +AC_ARG_ENABLE(avahi, + AC_HELP_STRING([--enable-avahi],[use Avahi (default=yes)]), + [case "${enableval}" in + yes) ENABLE_AVAHI=yes ;; + no) ENABLE_AVAHI=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-avahi) ;; + esac], + [ENABLE_AVAHI=yes]) dnl Default value + + +AM_CONDITIONAL([ENABLE_AVAHI], [test "x$ENABLE_AVAHI" = "xyes"]) + +if test "x$ENABLE_AVAHI" = "xyes" ; then + AC_DEFINE(ENABLE_AVAHI, [1], [Try to make use of a running avahi mDNS server before resolving on our own behalf]) +fi + + AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile doc/README.html ]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 032ee3f..ac24af2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,6 @@ AM_CFLAGS=-D_GNU_SOURCE -DMDNS_ALLOW_FILE=\"$(sysconfdir)/mdns.allow\" AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' noinst_PROGRAMS = nss-test mdns-test - lib_LTLIBRARIES = libnss_mdns.la libnss_mdns4.la libnss_mdns6.la mdns_test_SOURCES = query.c dns.c util.c mdns-test.c \ @@ -32,12 +31,16 @@ mdns_test_SOURCES = query.c dns.c util.c mdns-test.c \ nss_test_SOURCES = nss-test.c -libnss_mdns_la_SOURCES = query.c dns.c util.c nss.c \ - query.h dns.h util.h - +libnss_mdns_la_SOURCES = query.c dns.c util.c nss.c query.h dns.h util.h libnss_mdns_la_CFLAGS=$(AM_CFLAGS) libnss_mdns_la_LDFLAGS=-avoid-version -module -export-dynamic -shrext .so.2 +if ENABLE_AVAHI +noinst_PROGRAMS += avahi-test +avahi_test_SOURCES = avahi.c util.c avahi.h util.h avahi-test.c +libnss_mdns_la_SOURCES += avahi.c avahi.h +endif + libnss_mdns4_la_SOURCES=$(libnss_mdns_la_SOURCES) libnss_mdns4_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 libnss_mdns4_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) diff --git a/src/avahi-test.c b/src/avahi-test.c new file mode 100644 index 0000000..e66421e --- /dev/null +++ b/src/avahi-test.c @@ -0,0 +1,48 @@ +/* $Id$ */ + +/*** + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "avahi.h" + +int main(int argc, char *argv[]) { + uint8_t data[64]; + char t[256]; + int r; + + if ((r = avahi_resolve_name(AF_INET, argc >= 2 ? argv[1] : "whiskey.local", data)) == 0) + printf("AF_INET: %s\n", inet_ntop(AF_INET, data, t, sizeof(t))); + else + printf("AF_INET: failed (%i).\n", r); + + if ((r = avahi_resolve_name(AF_INET6, argc >= 2 ? argv[1] : "whiskey.local", data)) == 0) + printf("AF_INET6: %s\n", inet_ntop(AF_INET6, data, t, sizeof(t))); + else + printf("AF_INET6: failed (%i).\n", r); + + if ((r = avahi_resolve_address(AF_INET6, data, t, sizeof(t))) == 0) + printf("REVERSE: %s\n", t); + else + printf("REVERSE: failed (%i).\n", r); + + return 0; +} diff --git a/src/avahi.c b/src/avahi.c new file mode 100644 index 0000000..cd4db00 --- /dev/null +++ b/src/avahi.c @@ -0,0 +1,145 @@ +/* $Id$ */ + +/*** + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avahi.h" +#include "util.h" + +#define AVAHI_SOCKET "/var/run/avahi/socket" + +static FILE *open_socket(void) { + int fd = -1; + struct sockaddr_un sa; + FILE *f; + + 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, AVAHI_SOCKET, 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 avahi_resolve_name(int af, const char* name, void* data) { + FILE *f; + char *e, *p; + int ret = -1; + char ln[256]; + + assert(af == AF_INET || af == AF_INET6); + + 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, "\t "); + e = p + strcspn(p, "\n\r\t "); + *e = 0; + + if (inet_pton(af, p, data) <= 0) + goto finish; + + ret = 0; + +finish: + + if (f) + fclose(f); + + return ret; +} + +int avahi_resolve_address(int af, const void *data, char* name, size_t name_len) { + FILE *f; + char *e, *p; + int ret = -1; + char a[256], ln[256]; + + assert(af == AF_INET || af == AF_INET6); + + 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, "\t "); + e = p + strcspn(p, "\n\r\t "); + *e = 0; + + strncpy(name, p, name_len-1); + name[name_len-1] = 0; + + ret = 0; + +finish: + + if (f) + fclose(f); + + return ret; +} diff --git a/src/avahi.h b/src/avahi.h new file mode 100644 index 0000000..79d1c86 --- /dev/null +++ b/src/avahi.h @@ -0,0 +1,33 @@ +#ifndef fooavahihfoo +#define fooavahihfoo + +/* $Id$ */ + +/*** + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + + +#include +#include + +int avahi_resolve_name(int af, const char* name, void* data); + +int avahi_resolve_address(int af, const void *data, char* name, size_t name_len); + +#endif diff --git a/src/nss.c b/src/nss.c index 7802b09..c54db7b 100644 --- a/src/nss.c +++ b/src/nss.c @@ -34,6 +34,10 @@ #include "query.h" +#ifdef ENABLE_AVAHI +#include "avahi.h" +#endif + #define MAX_ENTRIES 16 #ifdef NSS_IPV4_ONLY @@ -161,6 +165,10 @@ enum nss_status _nss_mdns_gethostbyname2_r( void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata); void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata); +#ifdef ENABLE_AVAHI + uint8_t data[128]; +#endif + /* DEBUG_TRAP; */ #ifdef NSS_IPV4_ONLY @@ -195,39 +203,56 @@ enum nss_status _nss_mdns_gethostbyname2_r( goto finish; } - if ((fd = mdns_open_socket()) < 0) { - - *errnop = errno; - *h_errnop = NO_RECOVERY; - goto finish; - } - u.count = 0; u.data_len = 0; -#ifndef NSS_IPV6_ONLY - ipv4_func = af == AF_INET ? ipv4_callback : NULL; -#else +#ifdef NSS_IPV6_ONLY ipv4_func = NULL; +#else + ipv4_func = af == AF_INET ? ipv4_callback : NULL; #endif -#ifndef NSS_IPV4_ONLY - ipv6_func = af == AF_INET6 ? ipv6_callback : NULL; -#else +#ifdef NSS_IPV4_ONLY ipv6_func = NULL; +#else + ipv6_func = af == AF_INET6 ? ipv6_callback : NULL; #endif - - if ((r = mdns_query_name(fd, name, ipv4_func, ipv6_func, &u)) < 0) { + +#ifdef ENABLE_AVAHI + + if ((r = avahi_resolve_name(af, name, data)) == 0) { + if (af == AF_INET && ipv4_func) + ipv4_func((ipv4_address_t*) data, &u); + if (af == AF_INET6 && ipv4_func) + ipv6_func((ipv6_address_t*)data, &u); + } else if (r > 0) { *errnop = ETIMEDOUT; *h_errnop = HOST_NOT_FOUND; goto finish; } + +#endif + if (u.count == 0) { + if ((fd = mdns_open_socket()) < 0) { + + *errnop = errno; + *h_errnop = NO_RECOVERY; + goto finish; + } + + if ((r = mdns_query_name(fd, name, ipv4_func, ipv6_func, &u)) < 0) { + *errnop = ETIMEDOUT; + *h_errnop = HOST_NOT_FOUND; + goto finish; + } + } + /* Alias names */ *((char**) buffer) = NULL; result->h_aliases = (char**) buffer; index = sizeof(char*); - + /* Official name */ strcpy(buffer+index, name); result->h_name = buffer+index; @@ -235,7 +260,7 @@ enum nss_status _nss_mdns_gethostbyname2_r( result->h_addrtype = af; result->h_length = address_length; - + /* Check if there's enough space for the addresses */ if (buflen < index+u.data_len+sizeof(char*)*(u.count+1)) { *errnop = ERANGE; @@ -302,6 +327,9 @@ enum nss_status _nss_mdns_gethostbyaddr_r( enum nss_status status = NSS_STATUS_UNAVAIL; int fd = -1, r; size_t address_length, index, astart; +#ifdef ENABLE_AVAHI + char t[256]; +#endif *errnop = EINVAL; *h_errnop = NO_RECOVERY; @@ -335,31 +363,46 @@ enum nss_status _nss_mdns_gethostbyaddr_r( goto finish; } - - if ((fd = mdns_open_socket()) < 0) { - *errnop = errno; - *h_errnop = NO_RECOVERY; +#ifdef ENABLE_AVAHI + + if ((r = avahi_resolve_address(af, addr, t, sizeof(t))) == 0) { + name_callback(t, &u); + } else if (r > 0) { + *errnop = ETIMEDOUT; + *h_errnop = HOST_NOT_FOUND; goto finish; } +#endif + + if (u.count == 0) { + + if ((fd = mdns_open_socket()) < 0) { + + *errnop = errno; + *h_errnop = NO_RECOVERY; + goto finish; + } + #if ! defined(NSS_IPV6_ONLY) && ! defined(NSS_IPV4_ONLY) - if (af == AF_INET) + if (af == AF_INET) #endif #ifndef NSS_IPV6_ONLY - r = mdns_query_ipv4(fd, (ipv4_address_t*) addr, name_callback, &u); + r = mdns_query_ipv4(fd, (ipv4_address_t*) addr, name_callback, &u); #endif #if ! defined(NSS_IPV6_ONLY) && ! defined(NSS_IPV4_ONLY) - else + else #endif #ifndef NSS_IPV4_ONLY - r = mdns_query_ipv6(fd, (ipv6_address_t*) addr, name_callback, &u); + r = mdns_query_ipv6(fd, (ipv6_address_t*) addr, name_callback, &u); #endif - - if (r < 0) { - *errnop = ETIMEDOUT; - *h_errnop = HOST_NOT_FOUND; - goto finish; + + if (r < 0) { + *errnop = ETIMEDOUT; + *h_errnop = HOST_NOT_FOUND; + goto finish; + } } /* Alias names */ diff --git a/src/query.c b/src/query.c index b59513e..32401fc 100644 --- a/src/query.c +++ b/src/query.c @@ -220,7 +220,7 @@ static int send_dns_packet(int fd, struct dns_packet *p) { return n_sent; } -static int recv_dns_packet(int fd, struct dns_packet **ret_packet, uint8_t* ret_ttl, struct timeval *end) { +static int recv_dns_packet(int fd, struct dns_packet **ret_packet, uint8_t *ret_ttl, struct timeval *end) { struct dns_packet *p= NULL; struct msghdr msg; struct iovec io; -- cgit