fix rejection of dns responses with pointers past 512 byte offset
[musl] / src / network / res_msend.c
index 11c6aa0..86c2fcf 100644 (file)
@@ -25,7 +25,8 @@ static void cleanup(void *p)
 static unsigned long mtime()
 {
        struct timespec ts;
-       clock_gettime(CLOCK_REALTIME, &ts);
+       if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS)
+               clock_gettime(CLOCK_REALTIME, &ts);
        return (unsigned long)ts.tv_sec * 1000
                + ts.tv_nsec / 1000000;
 }
@@ -132,6 +133,22 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
                family = AF_INET;
                sl = sizeof sa.sin;
        }
+
+       /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
+       if (fd >= 0 && family == AF_INET6) {
+               setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
+               for (i=0; i<nns; i++) {
+                       if (ns[i].sin.sin_family != AF_INET) continue;
+                       memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
+                               &ns[i].sin.sin_addr, 4);
+                       memcpy(ns[i].sin6.sin6_addr.s6_addr,
+                               "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+                       ns[i].sin6.sin6_family = AF_INET6;
+                       ns[i].sin6.sin6_flowinfo = 0;
+                       ns[i].sin6.sin6_scope_id = 0;
+               }
+       }
+
        sa.sin.sin_family = family;
        if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
                if (fd >= 0) close(fd);
@@ -151,21 +168,6 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
        pthread_cleanup_push(cleanup, pfd);
        pthread_setcancelstate(cs, 0);
 
-       /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
-       if (family == AF_INET6) {
-               setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
-               for (i=0; i<nns; i++) {
-                       if (ns[i].sin.sin_family != AF_INET) continue;
-                       memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
-                               &ns[i].sin.sin_addr, 4);
-                       memcpy(ns[i].sin6.sin6_addr.s6_addr,
-                               "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
-                       ns[i].sin6.sin6_family = AF_INET6;
-                       ns[i].sin6.sin6_flowinfo = 0;
-                       ns[i].sin6.sin6_scope_id = 0;
-               }
-       }
-
        memset(alens, 0, sizeof *alens * nqueries);
 
        retry_interval = timeout / attempts;
@@ -286,7 +288,7 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
                        };
                        step_mh(&mh, apos[i]);
                        r = recvmsg(pfd[i].fd, &mh, 0);
-                       if (r < 0) goto out;
+                       if (r <= 0) goto out;
                        apos[i] += r;
                        if (apos[i] < 2) continue;
                        int alen = alen_buf[i][0]*256 + alen_buf[i][1];