From e0d7d87d0a583785385478617ff2ff4a34ba007e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Dec 2004 01:20:43 +0000 Subject: * bump version number * update README * send mDNS queries on all local interfaces that support multicasts git-svn-id: file:///home/lennart/svn/public/nss-mdns/trunk@64 0ee8848e-81ea-0310-a63a-f631d1a40d77 --- configure.ac | 2 +- doc/README.html.in | 14 ++++++- src/query.c | 118 +++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 110 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 65ae43c..848645e 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ # USA. AC_PREREQ(2.57) -AC_INIT([nss-mdns],[0.1],[mzaffzqaf (at) 0pointer (dot) de]) +AC_INIT([nss-mdns],[0.2],[mzaffzqaf (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/query.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) diff --git a/doc/README.html.in b/doc/README.html.in index 532b508..c9d1493 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -42,6 +42,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

News

+
Mon Dec 17 2004:

Version 0.2 +released. Changes include: send mDNS queries on every interface that +supports multicasts, instead of only the one with the default route, +making nss-mdns more robust on multi-homed hosts; gcc 2.95 +compatiblity.

+
Mon Dec 6 2004:

Version 0.1 released

@@ -59,8 +66,8 @@ means that you have to run a mDNS responder daemon seperately from nss-mdns if you want to register the local host name via mDNS (e.g. HOWL).

-

nss-mdns is very lightweight (18 KByte stripped binary .so compiled with --DNDEBUG=1), has no dependencies besides the glibc and requires only minimal +

nss-mdns is very lightweight (22 KByte stripped binary .so compiled with +-DNDEBUG=1 on i386, gcc 3.3), has no dependencies besides the glibc and requires only minimal configuration.

Status

@@ -120,6 +127,9 @@ use glibc's getent tool: repeated mDNS resolutions are slowed down. Consider installing glibc's name service cache daemon nscd to work around this limitation.

+

When doing troubleshooting for nss-mdns, don't forget to +disable nscd for getting sensible results.

+

Requirements

Currently, nss-mdns is tested on Linux only. A fairly modern glibc installation with development headers (2.0 or newer) is required. Not diff --git a/src/query.c b/src/query.c index b534433..6f5900c 100644 --- a/src/query.c +++ b/src/query.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "dns.h" #include "util.h" @@ -89,7 +91,12 @@ int mdns_open_socket(void) { } if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) { - fprintf(stderr, "O_RECVTTL failed: %s\n", strerror(errno)); + fprintf(stderr, "IP_RECVTTL failed: %s\n", strerror(errno)); + goto fail; + } + + if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) { + fprintf(stderr, "IP_PKTINFO failed: %s\n", strerror(errno)); goto fail; } @@ -114,24 +121,99 @@ fail: static int send_dns_packet(int fd, struct dns_packet *p) { struct sockaddr_in sa; - assert(fd >= 0 && p); + struct msghdr msg; + struct iovec io; + struct cmsghdr *cmsg; + struct in_pktinfo *pkti; + uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)]; + int i, n; + struct ifreq ifreq[32]; + struct ifconf ifconf; + int n_sent = 0; + assert(fd >= 0 && p); assert(dns_packet_check_valid(p) >= 0); mdns_mcast_group(&sa); - for (;;) { - if (sendto(fd, p->data, p->size, 0, (struct sockaddr*) &sa, sizeof(sa)) >= 0) - return 0; + memset(&io, 0, sizeof(io)); + io.iov_base = p->data; + io.iov_len = p->size; - if (errno != EAGAIN) { - fprintf(stderr, "sendto() failed: %s\n", strerror(errno)); - return -1; - } + memset(cmsg_data, 0, sizeof(cmsg_data)); + cmsg = (struct cmsghdr*) cmsg_data; + cmsg->cmsg_len = sizeof(cmsg_data); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + + pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr)); + pkti->ipi_ifindex = 0; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = cmsg_data; + msg.msg_controllen = sizeof(cmsg_data); + msg.msg_flags = 0; + + ifconf.ifc_req = ifreq; + ifconf.ifc_len = sizeof(ifreq); + + if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) { + fprintf(stderr, "SIOCGIFCONF failed: %s\n", strerror(errno)); + return -1; + } + + for (i = 0, n = ifconf.ifc_len/sizeof(struct ifreq); i < n; i++) { + struct sockaddr_in *sa; + u_int32_t s_addr; + + /* Check if this is the loopback device or any other invalid interface */ + sa = (struct sockaddr_in*) &ifreq[i].ifr_addr; + s_addr = htonl(sa->sin_addr.s_addr); + if (sa->sin_family != AF_INET || + s_addr == INADDR_LOOPBACK || + s_addr == INADDR_ANY || + s_addr == INADDR_BROADCAST) + continue; + + if (ioctl(fd, SIOCGIFFLAGS, &ifreq[i]) < 0) + continue; /* Since SIOCGIFCONF and this call is not + * issued in a transaction, we ignore errors + * here, since the interface may have vanished + * since that call */ + + /* Check whether this network interface supports multicasts and is up and running */ + if (!(ifreq[i].ifr_flags & IFF_MULTICAST) || + !(ifreq[i].ifr_flags & IFF_UP) || + !(ifreq[i].ifr_flags & IFF_RUNNING)) + continue; + + if (ioctl(fd, SIOCGIFINDEX, &ifreq[i]) < 0) + continue; /* See above why we ignore this error */ + + pkti->ipi_ifindex = ifreq[i].ifr_ifindex; + + for (;;) { - if (wait_for_write(fd, NULL) < 0) - return -1; + if (sendmsg(fd, &msg, MSG_DONTROUTE) >= 0) + break; + + if (errno != EAGAIN) { + fprintf(stderr, "sendmsg() failed: %s\n", strerror(errno)); + return -1; + } + + if (wait_for_write(fd, NULL) < 0) + return -1; + } + + n_sent++; } + + return n_sent; } static int recv_dns_packet(int fd, struct dns_packet **ret_packet, uint8_t* ret_ttl, struct timeval *end) { @@ -139,7 +221,7 @@ static int recv_dns_packet(int fd, struct dns_packet **ret_packet, uint8_t* ret_ struct msghdr msg; struct iovec io; int ret = -1; - uint8_t aux[16]; + uint8_t aux[64]; assert(fd >= 0); p = dns_packet_new(); @@ -245,10 +327,7 @@ static int send_name_query(int fd, const char *name, int query_ipv4, int query_i dns_packet_set_field(p, DNS_FIELD_QDCOUNT, qdcount); - if (send_dns_packet(fd, p) < 0) - goto finish; - - ret = 0; + ret = send_dns_packet(fd, p); finish: if (p) @@ -418,10 +497,7 @@ static int send_reverse_query(int fd, const char *name) { dns_packet_set_field(p, DNS_FIELD_QDCOUNT, 1); - if (send_dns_packet(fd, p) < 0) - goto finish; - - ret = 0; + ret = send_dns_packet(fd, p); finish: if (p) @@ -509,7 +585,7 @@ static int query_reverse(int fd, const char *name, void (*name_func)(const char while (*timeout > 0) { int n; - if (send_reverse_query(fd, name) < 0) + if (send_reverse_query(fd, name) <= 0) /* error or no interface to send data on */ return -1; if ((n = process_reverse_response(fd, name, *timeout, name_func, userdata)) < 0) -- cgit