summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2005-05-15 17:06:08 +0000
committerLennart Poettering <lennart@poettering.net>2005-05-15 17:06:08 +0000
commit5a62c294114083df5ac4759e8bda232efdf3e025 (patch)
treea1f87e43fb5fb42b59c101ade4e5fcdc6f65bbe2
parenta5fd4fcafaf14f2b741573d935e51a68f1729996 (diff)
* send "legacy unicast" packets instead of normal mDNS packets
* prepare for release 0.4 git-svn-id: file:///home/lennart/svn/public/nss-mdns/trunk@75 0ee8848e-81ea-0310-a63a-f631d1a40d77
-rw-r--r--configure.ac2
-rw-r--r--doc/README.html.in45
-rw-r--r--src/dns.c5
-rw-r--r--src/mdns-test.c8
-rw-r--r--src/query.c154
5 files changed, 129 insertions, 85 deletions
diff --git a/configure.ac b/configure.ac
index f15f54e..e8cc023 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,7 +21,7 @@
# USA.
AC_PREREQ(2.57)
-AC_INIT([nss-mdns],[0.3],[mzaffzqaf (at) 0pointer (dot) de])
+AC_INIT([nss-mdns],[0.4],[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 65955d0..5dc131f 100644
--- a/doc/README.html.in
+++ b/doc/README.html.in
@@ -42,9 +42,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.</p>
<h2><a name="news">News</a></h2>
+<div class="news-date">Sun May 15 2005: </div> <p class="news-text"><a
+href="@PACKAGE_URL@nss-mdns-0.4.tar.gz">Version 0.4</a>
+released. Changes include: small portability fix for big endian
+architectures; send "legacy unicast" packets instead of normal mDNS
+packets (this should reduce traffic and improve response time)</p>
+
<div class="news-date">Jan Sun 16 2005: </div> <p class="news-text"><a
href="@PACKAGE_URL@nss-mdns-0.3.tar.gz">Version 0.3</a>
-released. Changes include: add Debianization, use <tt>ip6.arpa</tt> instead of <tt>ip6.int</tt> for reverse IPv6 lookups.</p>
+released. Changes include: add Debianization; use <tt>ip6.arpa</tt> instead of <tt>ip6.int</tt> for reverse IPv6 lookups.</p>
<div class="news-date">Fri Dec 17 2004: </div> <p class="news-text"><a
href="@PACKAGE_URL@nss-mdns-0.2.tar.gz">Version 0.2</a>
@@ -70,11 +76,12 @@ means that you have to run a mDNS responder daemon seperately
from <tt>nss-mdns</tt> if you want to register the local host name via
mDNS (e.g. <a href="http://www.porchdogsoft.com/products/howl/">HOWL</a>).</p>
-<p><tt>nss-mdns</tt> is very lightweight (22 KByte stripped binary <tt>.so</tt> compiled with
-<tt>-DNDEBUG=1</tt> on i386, <tt>gcc</tt> 3.3), has no dependencies besides the <tt>glibc</tt> and requires only minimal
-configuration.</p>
+<p><tt>nss-mdns</tt> is very lightweight (23 KByte stripped binary
+<tt>.so</tt> compiled with <tt>-DNDEBUG=1</tt> on i386, <tt>gcc</tt>
+3.3), has no dependencies besides the <tt>glibc</tt> and requires only
+minimal configuration.</p>
-<h2><a name="status">Status</a></h2>
+<h2><a name="status">Current Status</a></h2>
<p>It works!</p>
@@ -100,7 +107,8 @@ lookup for IPv4.</p>
<p>To activate one of the NSS modules you have to edit
<tt>/etc/nsswitch.conf</tt> and add <tt>mdns4</tt>
-(resp. <tt>mdns</tt>, <tt>mdns6</tt>) to the line starting with "<tt>hosts:</tt>". On Debian this looks like this:</p>
+(resp. <tt>mdns</tt>, <tt>mdns6</tt>) to the line starting with
+"<tt>hosts:</tt>". On Debian this looks like this:</p>
<pre># /etc/nsswitch.conf
@@ -125,23 +133,24 @@ use <tt>glibc</tt>'s <tt>getent</tt> tool:
<pre>$ getent hosts <i>foo</i>.local
192.168.50.4 foo.local</pre>
-<p>Replace <i>foo</i> whith a host name that has been registered with an mDNS responder.</p>
-
-<p>Due to some traffic suppression algorithms in mDNS responders
-repeated mDNS resolutions are slowed down. Consider installing <tt>glibc</tt>'s name
-service cache daemon <tt>nscd</tt> to work around this limitation.</p>
+<p>Replace <i>foo</i> whith a host name that has been registered with
+an mDNS responder.</p>
-<p>When doing troubleshooting for <tt>nss-mdns</tt>, don't forget to
-disable <tt>nscd</tt> for getting sensible results.</p>
+<p>To reduce the traffic <tt>nss-mdns</tt> is responsible for consider
+installing <tt>glibc</tt>'s name service cache daemon
+<tt>nscd</tt>. However, when doing troubleshooting for
+<tt>nss-mdns</tt>, don't forget to disable <tt>nscd</tt> for getting
+sensible results.</p>
-<p>If you run a firewall, don't forget to allow UDP traffic from and to port 5353
-from and to the the mDNS multicast address <tt>224.0.0.251</tt>.</p>
+<p>If you run a firewall, don't forget to allow UDP traffic to the the
+mDNS multicast address <tt>224.0.0.251</tt> on port 5353.</p>
<h2><a name="requirements">Requirements</a></h2>
-<p>Currently, <tt>nss-mdns</tt> is tested on Linux only. A fairly modern <tt>glibc</tt> installation with development headers (2.0 or newer) is required. Not
-suprisingly <tt>nss-mdns</tt> requires a kernel compiled with IPv4
-multicasting support enabled.</p>
+<p>Currently, <tt>nss-mdns</tt> is tested on Linux only. A fairly
+modern <tt>glibc</tt> installation with development headers (2.0 or
+newer) is required. Not suprisingly <tt>nss-mdns</tt> requires a
+kernel compiled with IPv4 multicasting support enabled.</p>
<p><tt>nss-mdns</tt> was developed and tested on Debian GNU/Linux
"testing" from December 2004, it should work on most other Linux
diff --git a/src/dns.c b/src/dns.c
index c3be024..b32dc2f 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -157,9 +157,6 @@ int dns_packet_check_valid_response(struct dns_packet *p) {
if (!(flags & DNS_FLAG_QR))
return -1;
- if (dns_packet_get_field(p, DNS_FIELD_QDCOUNT) > 0)
- return -1;
-
return 0;
}
@@ -278,7 +275,7 @@ int dns_packet_consume_bytes(struct dns_packet *p, void *ret_data, size_t l) {
}
int dns_packet_consume_seek(struct dns_packet *p, size_t length) {
- assert(p && length >= 0);
+ assert(p);
if (!length)
return 0;
diff --git a/src/mdns-test.c b/src/mdns-test.c
index c8fbdb9..e3c7981 100644
--- a/src/mdns-test.c
+++ b/src/mdns-test.c
@@ -47,10 +47,10 @@ int main(int argc, char *argv[]) {
if ((fd = mdns_open_socket()) < 0)
goto finish;
-/* if (mdns_query_name(fd, argc > 1 ? argv[1] : "ecstasy.local", &ipv4_func, &ipv6_func, NULL) < 0) */
-/* goto finish; */
-
- ipv4.address = inet_addr(argc > 1 ? argv[1] : "192.168.100.1");
+ if (mdns_query_name(fd, argc > 1 ? argv[1] : "cocaine.local", &ipv4_func, &ipv6_func, NULL) < 0)
+ goto finish;
+
+ ipv4.address = inet_addr(argc > 1 ? argv[1] : "192.168.50.1");
if (mdns_query_ipv4(fd, &ipv4, name_func, NULL) < 0)
goto finish;
diff --git a/src/query.c b/src/query.c
index 546d072..1b66df9 100644
--- a/src/query.c
+++ b/src/query.c
@@ -36,15 +36,33 @@
#include <sys/time.h>
#include <net/if.h>
#include <sys/ioctl.h>
+#include <stdlib.h>
#include "dns.h"
#include "util.h"
#include "query.h"
-static const usec_t retry_ms[] = { 200000, 500000, 900000, 1400000, 0 };
+static const usec_t retry_ms[] = { 500000, 1000000, 0 };
+
+static uint16_t get_random_id(void) {
+ uint16_t id = 0;
+ int ok = 0, fd;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) {
+ ok = read(fd, &id, sizeof(id)) == 2;
+ close(fd);
+ }
+
+ if (!ok)
+ ok = random() & 0xFFFF;
+
+ return id;
+}
static void mdns_mcast_group(struct sockaddr_in *ret_sa) {
assert(ret_sa);
+
+ memset(ret_sa, 0, sizeof(struct sockaddr_in));
ret_sa->sin_family = AF_INET;
ret_sa->sin_port = htons(5353);
@@ -52,44 +70,30 @@ static void mdns_mcast_group(struct sockaddr_in *ret_sa) {
}
int mdns_open_socket(void) {
- struct ip_mreqn mreq;
struct sockaddr_in sa;
int fd = -1, ttl, yes;
- mdns_mcast_group(&sa);
-
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
goto fail;
}
-
+
ttl = 255;
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
fprintf(stderr, "IP_MULTICAST_TTL failed: %s\n", strerror(errno));
goto fail;
}
- yes = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
- fprintf(stderr, "SO_REUSEADDR failed: %s\n", strerror(errno));
- goto fail;
- }
-
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ sa.sin_addr.s_addr = INADDR_ANY;
+
if (bind(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
fprintf(stderr, "bind() failed: %s\n", strerror(errno));
goto fail;
}
-
- memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = sa.sin_addr;
- mreq.imr_address.s_addr = htonl(INADDR_ANY);
- mreq.imr_ifindex = 0;
- if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
- fprintf(stderr, "IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
- goto fail;
- }
-
+ yes = 1;
if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
fprintf(stderr, "IP_RECVTTL failed: %s\n", strerror(errno));
goto fail;
@@ -284,7 +288,7 @@ fail:
return ret;
}
-static int send_name_query(int fd, const char *name, int query_ipv4, int query_ipv6) {
+static int send_name_query(int fd, const char *name, uint16_t id, int query_ipv4, int query_ipv6) {
int ret = -1;
struct dns_packet *p = NULL;
uint8_t *prev_name = NULL;
@@ -297,6 +301,7 @@ static int send_name_query(int fd, const char *name, int query_ipv4, int query_i
goto finish;
}
+ dns_packet_set_field(p, DNS_FIELD_ID, id);
dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
#ifndef NSS_IP6_ONLY
@@ -354,7 +359,24 @@ static int domain_cmp(const char *a, const char *b) {
return strncasecmp(a, b, al);
}
-static int process_name_response(int fd, const char *name, usec_t timeout, void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata), void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata), void *userdata) {
+static int skip_questions(struct dns_packet *p) {
+ unsigned i;
+ assert(p);
+
+ for (i = dns_packet_get_field(p, DNS_FIELD_QDCOUNT); i > 0; i--) {
+ char pname[256];
+ uint16_t type, class;
+
+ if (dns_packet_consume_name(p, pname, sizeof(pname)) < 0 ||
+ dns_packet_consume_uint16(p, &type) < 0 ||
+ dns_packet_consume_uint16(p, &class) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int process_name_response(int fd, const char *name, usec_t timeout, uint16_t id, void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata), void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata), void *userdata) {
struct dns_packet *p = NULL;
int done = 0;
struct timeval end;
@@ -374,12 +396,15 @@ static int process_name_response(int fd, const char *name, usec_t timeout, void
return 1;
/* Ignore packets with RFC != 255 */
- if (ttl == 255) {
+ if (/* ttl == 255 && */
+ dns_packet_check_valid_response(p) >= 0 &&
+ dns_packet_get_field(p, DNS_FIELD_ID) == id) {
+
+ unsigned i;
- /* Ignore corrupt packets */
- if (dns_packet_check_valid_response(p) >= 0) {
+ if (skip_questions(p) >= 0)
- for (;;) {
+ for (i = dns_packet_get_field(p, DNS_FIELD_ANCOUNT); i > 0; i--) {
char pname[256];
uint16_t type, class;
uint32_t rr_ttl;
@@ -392,7 +417,7 @@ static int process_name_response(int fd, const char *name, usec_t timeout, void
dns_packet_consume_uint16(p, &rdlength) < 0) {
break;
}
-
+
/* Remove mDNS cache flush bit */
class &= ~0x8000;
@@ -402,27 +427,27 @@ static int process_name_response(int fd, const char *name, usec_t timeout, void
class == DNS_CLASS_IN &&
!domain_cmp(name, pname) &&
rdlength == sizeof(ipv4_address_t)) {
-
+
ipv4_address_t ipv4;
if (dns_packet_consume_bytes(p, &ipv4, sizeof(ipv4)) < 0)
break;
-
+
ipv4_func(&ipv4, userdata);
done = 1;
}
#endif
#if ! defined(NSS_IPV6_ONLY) && ! defined(NSS_IPV4_ONLY)
- else
+/* else */
#endif
#ifndef NSS_IPV4_ONLY
- if (ipv6_func &&
- type == DNS_TYPE_AAAA &&
- class == DNS_CLASS_IN &&
- !domain_cmp(name, pname) &&
- rdlength == sizeof(ipv6_address_t)) {
-
+ if (ipv6_func &&
+ type == DNS_TYPE_AAAA &&
+ class == DNS_CLASS_IN &&
+ !domain_cmp(name, pname) &&
+ rdlength == sizeof(ipv6_address_t)) {
+
ipv6_address_t ipv6;
if (dns_packet_consume_bytes(p, &ipv6, sizeof(ipv6_address_t)) < 0)
@@ -432,35 +457,40 @@ static int process_name_response(int fd, const char *name, usec_t timeout, void
done = 1;
}
#endif
- else {
-
+ else {
+
/* Step over */
if (dns_packet_consume_seek(p, rdlength) < 0)
break;
}
}
- }
}
+
if (p)
dns_packet_free(p);
- }
+ }
+
return 0;
}
int mdns_query_name(int fd, const char *name, void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata), void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata), void *userdata) {
const usec_t *timeout = retry_ms;
+ uint16_t id;
+
assert(fd >= 0 && name && (ipv4_func || ipv6_func));
+ id = get_random_id();
+
while (*timeout > 0) {
int n;
- if (send_name_query(fd, name, !!ipv4_func, !!ipv6_func) < 0)
+ if (send_name_query(fd, name, id, !!ipv4_func, !!ipv6_func) < 0)
return -1;
- if ((n = process_name_response(fd, name, *timeout, ipv4_func, ipv6_func, userdata)) < 0)
+ if ((n = process_name_response(fd, name, *timeout, id, ipv4_func, ipv6_func, userdata)) < 0)
return -1;
if (n == 0)
@@ -474,7 +504,7 @@ int mdns_query_name(int fd, const char *name, void (*ipv4_func)(const ipv4_addre
return -1;
}
-static int send_reverse_query(int fd, const char *name) {
+static int send_reverse_query(int fd, const char *name, uint16_t id) {
int ret = -1;
struct dns_packet *p = NULL;
@@ -485,6 +515,7 @@ static int send_reverse_query(int fd, const char *name) {
goto finish;
}
+ dns_packet_set_field(p, DNS_FIELD_ID, id);
dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
if (!dns_packet_append_name(p, name)) {
@@ -506,7 +537,7 @@ finish:
return ret;
}
-static int process_reverse_response(int fd, const char *name, usec_t timeout, void (*name_func)(const char *name, void *userdata), void *userdata) {
+static int process_reverse_response(int fd, const char *name, usec_t timeout, uint16_t id, void (*name_func)(const char *name, void *userdata), void *userdata) {
struct dns_packet *p = NULL;
int done = 0;
struct timeval end;
@@ -526,12 +557,15 @@ static int process_reverse_response(int fd, const char *name, usec_t timeout, vo
return 1;
/* Ignore packets with RFC != 255 */
- if (ttl == 255) {
+ if (/* ttl == 255 && */
+ dns_packet_check_valid_response(p) >= 0 &&
+ dns_packet_get_field(p, DNS_FIELD_ID) == id) {
- /* Ignore corrupt packets */
- if (dns_packet_check_valid_response(p) >= 0) {
-
- for (;;) {
+ unsigned i;
+
+ if (skip_questions(p) >= 0) {
+
+ for (i = dns_packet_get_field(p, DNS_FIELD_ANCOUNT); i > 0; i--) {
char pname[256];
uint16_t type, class;
uint32_t rr_ttl;
@@ -544,24 +578,24 @@ static int process_reverse_response(int fd, const char *name, usec_t timeout, vo
dns_packet_consume_uint16(p, &rdlength) < 0) {
break;
}
-
+
/* Remove mDNS cache flush bit */
class &= ~0x8000;
if (type == DNS_TYPE_PTR &&
class == DNS_CLASS_IN &&
!domain_cmp(name, pname)) {
-
+
char rname[256];
-
+
if (dns_packet_consume_name(p, rname, sizeof(rname)) < 0)
break;
-
+
name_func(rname, userdata);
done = 1;
} else {
-
+
/* Step over */
if (dns_packet_consume_seek(p, rdlength) < 0)
@@ -580,15 +614,19 @@ static int process_reverse_response(int fd, const char *name, usec_t timeout, vo
static int query_reverse(int fd, const char *name, void (*name_func)(const char *name, void *userdata), void *userdata) {
const usec_t *timeout = retry_ms;
+ uint16_t id;
+
assert(fd >= 0 && name && name_func);
+ id = get_random_id();
+
while (*timeout > 0) {
int n;
- if (send_reverse_query(fd, name) <= 0) /* error or no interface to send data on */
+ if (send_reverse_query(fd, name, id) <= 0) /* error or no interface to send data on */
return -1;
- if ((n = process_reverse_response(fd, name, *timeout, name_func, userdata)) < 0)
+ if ((n = process_reverse_response(fd, name, *timeout, id, name_func, userdata)) < 0)
return -1;
if (n == 0)
@@ -616,7 +654,7 @@ int mdns_query_ipv4(int fd, const ipv4_address_t *ipv4, void (*name_func)(const
#endif
#ifndef NSS_IPV4_ONLY
-static int mdns_query_ipv6(int fd, const ipv6_address_t *ipv6, void (*name_func)(const char *name, void *userdata), void *userdata) {
+int mdns_query_ipv6(int fd, const ipv6_address_t *ipv6, void (*name_func)(const char *name, void *userdata), void *userdata) {
char name[256];
assert(fd >= 0 && ipv6 && name_func);