Whoops, I made some last time changes which broke big-endian systems, spotted by
Mattew.
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 20 Mar 2011 01:32:16 -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 20 Mar 2011 01:32:16 -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 20 Mar 2011 01:32:16 -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 20 Mar 2011 01:32:17 -0000
@@ -52,6 +52,7 @@
*/
#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -65,6 +66,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <poll.h>
#include "thread_private.h"
@@ -400,4 +402,134 @@ 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 ALL_MDNS_DEVICES "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);
+ inet_aton(ALL_MDNS_DEVICES, &msin.sin_addr);
+
+ 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 ALL_MDNS_DEVICES
+#undef MDNS_PORT
}