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       
 }

Reply via email to