On Tue, Mar 15, 2011 at 01:06:21AM -0300, Christiano F. Haesbaert wrote: > Hi, > > The following adds legacy MDNS lookups to libc. > > It adds the keyword 'mdns' to 'lookup' in /etc/resolv.conf, only names in the > .local (MDNS domain) are looked up. > > A legacy lookup is how MDNS calls a simple unicast lookup sent to the mcast > addr > 224.0.0.251, the MDNS responder is responsible for identifying the legacy > query > and answering it via unicast, like a normal unicast domain server would do. > > In order to *answer* the queries you need a proper MDNS daemon running, > OpenMDNS > is now in ports and works fine. You could also run avahi or bonjour, but > please > try OpenMDNS instead :-). http://www.haesbaert.org/openmdns > > This approach is different from linux+avahi and netbsd+bonjour, in which they > route the queries to the daemon in order to use standard MDNS queries. > > I've been using this in i386 and sparc64 for about a week, support for both > getaddrinfo(3) and gethostbyname(3), AF_INET and AF_INET6, no support for > reverse lookups yet. > > I'm still unfamiliar with the libc resolv code, so if I'm doing something > wrong > please correct me, I've tried to keep the code apart from the rest of the > resolver. > > Index: net/getaddrinfo.c > =================================================================== > RCS file: /cvs/src/lib/libc/net/getaddrinfo.c,v > retrieving revision 1.71 > diff -d -u -p -w -r1.71 getaddrinfo.c > --- net/getaddrinfo.c 18 Nov 2009 07:43:22 -0000 1.71 > +++ net/getaddrinfo.c 15 Mar 2011 00:56:20 -0000 > @@ -235,6 +235,8 @@ static int res_searchN(const char *, str > static int res_querydomainN(const char *, const char *, struct res_target *); > static struct addrinfo *_dns_getaddrinfo(const char *, const struct addrinfo > *, > const struct __res_state *); > +static struct addrinfo *_mcast_getaddrinfo(const char *, > + const struct addrinfo *, const struct __res_state *); > > > /* XXX macros that make external reference is BAD. */ > @@ -523,6 +525,9 @@ explore_fqdn(const struct addrinfo *pai, > case 'f': > result = _files_getaddrinfo(hostname, pai); > break; > + case 'm': > + result = _mcast_getaddrinfo(hostname, pai, _resp); > + break; > } > } > _THREAD_PRIVATE_MUTEX_UNLOCK(_explore_mutex); > @@ -1209,6 +1214,99 @@ _dns_getaddrinfo(const char *name, const > free(buf); > free(buf2); > return NULL; > + } > + ai = getanswer(buf, q.n, q.name, q.qtype, pai); > + if (ai) { > + cur->ai_next = ai; > + while (cur && cur->ai_next) > + cur = cur->ai_next; > + } > + if (q.next) { > + ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); > + if (ai) > + cur->ai_next = ai; > + } > + free(buf); > + free(buf2); > + return sentinel.ai_next; > +} > + > +static struct addrinfo * > +_mcast_getaddrinfo(const char *name, const struct addrinfo *pai, > + const struct __res_state *_resp) > +{ > + struct addrinfo *ai; > + querybuf *buf, *buf2; > + struct addrinfo sentinel, *cur; > + struct res_target q, q2; > + > + memset(&q, 0, sizeof(q)); > + memset(&q2, 0, sizeof(q2)); > + memset(&sentinel, 0, sizeof(sentinel)); > + cur = &sentinel; > + > + buf = malloc(sizeof(*buf)); > + if (buf == NULL) { > + h_errno = NETDB_INTERNAL; > + return NULL; > + } > + buf2 = malloc(sizeof(*buf2)); > + if (buf2 == NULL) { > + free(buf); > + h_errno = NETDB_INTERNAL; > + return NULL; > + } > + > + switch (pai->ai_family) { > + case AF_UNSPEC: > + /* respect user supplied order */ > + q.qclass = C_IN; > + q.qtype = (_resp->family[0] == AF_INET6) ? T_AAAA : T_A; > + q.answer = buf->buf; > + q.anslen = sizeof(buf->buf); > + q.next = &q2; > + > + if (_resp->family[1] == -1) { > + /* stop here if only one family was given */ > + q.next = NULL; > + break; > + } > + > + q2.qclass = C_IN; > + q2.qtype = (_resp->family[1] == AF_INET6) ? T_AAAA : T_A; > + q2.answer = buf2->buf; > + q2.anslen = sizeof(buf2->buf); > + break; > + case AF_INET: > + q.qclass = C_IN; > + q.qtype = T_A; > + q.answer = buf->buf; > + q.anslen = sizeof(buf->buf); > + break; > + case AF_INET6: > + q.qclass = C_IN; > + q.qtype = T_AAAA; > + q.answer = buf->buf; > + q.anslen = sizeof(buf->buf); > + break; > + default: > + free(buf); > + free(buf2); > + return NULL; > + } > + if ((q.n = res_search_mcast(name, > + q.qclass, q.qtype, q.answer, q.anslen)) < 0) { > + free(buf); > + free(buf2); > + return (NULL); > + } > + if (q.next != NULL) { > + if ((q2.n = res_search_mcast(name, > + q2.qclass, q2.qtype, q2.answer, q2.anslen)) < 0) { > + free(buf); > + free(buf2); > + return (NULL); > + } > } > ai = getanswer(buf, q.n, q.name, q.qtype, pai); > if (ai) { > Index: net/gethostnamadr.c > =================================================================== > RCS file: /cvs/src/lib/libc/net/gethostnamadr.c,v > retrieving revision 1.73 > diff -d -u -p -w -r1.73 gethostnamadr.c > --- net/gethostnamadr.c 18 Nov 2009 07:43:22 -0000 1.73 > +++ net/gethostnamadr.c 15 Mar 2011 00:56:20 -0000 > @@ -606,6 +606,7 @@ gethostbyname2(const char *name, int af) > > hp = (struct hostent *)NULL; > for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) { > + size_t nlen; > switch (lookups[i]) { > #ifdef YP > case 'y': > @@ -615,9 +616,10 @@ gethostbyname2(const char *name, int af) > break; > #endif > case 'b': > - buf = malloc(sizeof(*buf)); > - if (buf == NULL) > + if ((buf = malloc(sizeof(*buf))) == NULL) { > + h_errno = NETDB_INTERNAL; > break; > + } > if ((n = res_search(name, C_IN, type, buf->buf, > sizeof(buf->buf))) < 0) { > free(buf); > @@ -633,6 +635,23 @@ gethostbyname2(const char *name, int af) > case 'f': > hp = _gethtbyname2(name, af); > break; > + case 'm': > + if ((buf = malloc(sizeof(*buf))) == NULL) { > + h_errno = NETDB_INTERNAL; > + break; > + } > + if ((n = res_search_mcast(name, C_IN, type, buf->buf, > + sizeof(buf->buf))) < 0) { > + free(buf); > +#ifdef DEBUG > + if (_resp->options & RES_DEBUG) > + printf("res_search_mcast failed\n"); > +#endif > + break; > + } > + hp = getanswer(buf, n, name, type); > + free(buf); > + break; > } > } > /* XXX h_errno not correct in all cases... */ > Index: net/res_init.c > =================================================================== > RCS file: /cvs/src/lib/libc/net/res_init.c,v > retrieving revision 1.40 > diff -d -u -p -w -r1.40 res_init.c > --- net/res_init.c 5 Jun 2009 09:52:26 -0000 1.40 > +++ net/res_init.c 15 Mar 2011 00:56:20 -0000 > @@ -361,14 +361,16 @@ _res_init(int usercall) > break; > if ((*cp == '\0') || (*cp == '\n')) { > if (sp) { > - if (*sp=='y' || *sp=='b' || > *sp=='f') > + if (*sp=='y' || *sp=='b' || > + *sp=='f' || *sp=='m') > _resp->lookups[n++] = *sp; > sp = NULL; > } > break; > } else if ((*cp == ' ') || (*cp == '\t') || (*cp == > ',')) { > if (sp) { > - if (*sp=='y' || *sp=='b' || > *sp=='f') > + if (*sp=='y' || *sp=='b' || > + *sp=='f' || *sp=='m') > _resp->lookups[n++] = *sp; > sp = NULL; > } > Index: net/res_query.c > =================================================================== > RCS file: /cvs/src/lib/libc/net/res_query.c,v > retrieving revision 1.26 > diff -d -u -p -w -r1.26 res_query.c > --- net/res_query.c 29 Jun 2010 21:08:54 -0000 1.26 > +++ net/res_query.c 15 Mar 2011 00:56:21 -0000 > @@ -65,6 +65,7 @@ > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > +#include <poll.h> > > #include "thread_private.h" > > @@ -400,4 +401,133 @@ hostalias(const char *name) > } > fclose(fp); > return (NULL); > +} > + > +int > +res_search_mcast(const char *name, > + int class, /* domain name */ > + int type, /* class and type of query */ > + u_char *answer, /* buffer to put answer */ > + int anslen) /* size of answer */ > +{ > +#define MDNS_ADDRT 0xFB0000E0 /* 224.0.0.251 */ > +#define MDNS_PORT 5353 > + union { > + HEADER hdr; > + u_char buf[MAXPACKET]; > + } buf; > + struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res); > + struct sockaddr_in msin, from; > + socklen_t msinlen, fromlen; > + size_t resplen, nlen; > + struct pollfd pfd; > + int timeout, try; > + int msock; > + int n; > + HEADER *hp = &buf.hdr; > + HEADER *anhp = (HEADER *) answer; > + > + /* > + * Only names in the .local domain should be looked up in the mdns > + * network. > + */ > + nlen = strlen(name); > + if (nlen < 7 || (strcmp(&name[nlen - 6], ".local") != 0)) > + return (0); > + > + if (_res_init(0) == -1) { > + h_errno = NETDB_INTERNAL; > + return (-1); > + } > + h_errno = HOST_NOT_FOUND; > + > + n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, > + buf.buf, sizeof(buf.buf)); > + if (n <= 0) { > + h_errno = NO_RECOVERY; > +#ifdef DEBUG > + if (_resp->options & RES_DEBUG) > + printf(";; res_query: mkquery failed\n"); > +#endif > + return (n); > + } > + > + bzero(&msin, sizeof(msin)); > + bzero(&from, sizeof(from)); > + msinlen = fromlen = sizeof(struct sockaddr_in); > + /* Initialize msin to send to mcast */ > + msin.sin_family = AF_INET; > + msin.sin_port = htons(MDNS_PORT); > + msin.sin_addr.s_addr = MDNS_ADDRT; > + > + if ((msock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { > + h_errno = TRY_AGAIN; > + return (-1); > + } > + if (sendto(msock, buf.buf, n, 0, > + (struct sockaddr *)&msin, msinlen) != n) { > + h_errno = TRY_AGAIN; > + close(msock); > + return (-1); > + } > + /* > + * Wait for reply > + */ > + try = 3; > + timeout = 3000; > +wait: > + if (try-- == 0) { > + close(msock); > + h_errno = HOST_NOT_FOUND; > + return (-1); > + } > + pfd.fd = msock; > + pfd.events = POLLIN; > + n = poll(&pfd, 1, timeout); > + if (n < 0) { > + if (errno == EINTR) > + goto wait; > + h_errno = TRY_AGAIN; > + close(msock); > + return (-1); > + } > + if (n == 0) { > + /* > + * timeout > + */ > + h_errno = HOST_NOT_FOUND; > + close(msock); > + return (0); > + } > + /* Got an answer */ > + h_errno = NETDB_SUCCESS; > + resplen = recvfrom(msock, answer, anslen, 0, > + (struct sockaddr *)&from, &fromlen); > + if (resplen <= 0) { > + h_errno = TRY_AGAIN; > + close(msock); > + return (-1); > + } > + /* Make sure this is the answer for our question */ > + if (hp->id != anhp->id) { > + /* > + * response from old query, ignore it. > + * XXX - potential security hazard could > + * be detected here. > + */ > + goto wait; > + } > + if (!res_queriesmatch(buf.buf, buf.buf + sizeof(buf.buf), > + answer, answer + anslen)) { > + /* > + * response contains wrong query? ignore it. > + * XXX - potential security hazard could > + * be detected here. > + */ > + goto wait; > + } > + > + return (resplen); > +#undef MDNS_ADDRT > +#undef MDNS_PORT > }
Hi, Any feedback on this ? -- Christiano Farina HAESBAERT Do NOT send me html mail.