summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/accept4.c4
-rw-r--r--src/network/dns_parse.c11
-rw-r--r--src/network/getifaddrs.c14
-rw-r--r--src/network/getnameinfo.c9
-rw-r--r--src/network/getservbyport_r.c4
-rw-r--r--src/network/lookup.h2
-rw-r--r--src/network/lookup_name.c7
-rw-r--r--src/network/res_msend.c36
8 files changed, 49 insertions, 38 deletions
diff --git a/src/network/accept4.c b/src/network/accept4.c
index 59ab1726..765a38ed 100644
--- a/src/network/accept4.c
+++ b/src/network/accept4.c
@@ -9,6 +9,10 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int
if (!flg) return accept(fd, addr, len);
int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0);
if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret;
+ if (flg & ~(SOCK_CLOEXEC|SOCK_NONBLOCK)) {
+ errno = EINVAL;
+ return -1;
+ }
ret = accept(fd, addr, len);
if (ret<0) return ret;
if (flg & SOCK_CLOEXEC)
diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c
index e6ee19d9..09813112 100644
--- a/src/network/dns_parse.c
+++ b/src/network/dns_parse.c
@@ -1,7 +1,7 @@
#include <string.h>
#include "lookup.h"
-int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx)
+int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *, int), void *ctx)
{
int qdcount, ancount;
const unsigned char *p;
@@ -12,21 +12,20 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c
p = r+12;
qdcount = r[4]*256 + r[5];
ancount = r[6]*256 + r[7];
- if (qdcount+ancount > 64) return -1;
while (qdcount--) {
while (p-r < rlen && *p-1U < 127) p++;
- if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+ if (p>r+rlen-6)
return -1;
p += 5 + !!*p;
}
while (ancount--) {
while (p-r < rlen && *p-1U < 127) p++;
- if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+ if (p>r+rlen-12)
return -1;
p += 1 + !!*p;
len = p[8]*256 + p[9];
- if (p+len > r+rlen) return -1;
- if (callback(ctx, p[1], p+10, len, r) < 0) return -1;
+ if (len+10 > r+rlen-p) return -1;
+ if (callback(ctx, p[1], p+10, len, r, rlen) < 0) return -1;
p += 10 + len;
}
return 0;
diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c
index fed75bd8..74df4d6c 100644
--- a/src/network/getifaddrs.c
+++ b/src/network/getifaddrs.c
@@ -39,8 +39,8 @@ struct ifaddrs_storage {
};
struct ifaddrs_ctx {
- struct ifaddrs_storage *first;
- struct ifaddrs_storage *last;
+ struct ifaddrs *first;
+ struct ifaddrs *last;
struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
};
@@ -195,9 +195,9 @@ static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
}
if (ifs->ifa.ifa_name) {
- if (!ctx->first) ctx->first = ifs;
- if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa;
- ctx->last = ifs;
+ if (!ctx->first) ctx->first = &ifs->ifa;
+ if (ctx->last) ctx->last->ifa_next = &ifs->ifa;
+ ctx->last = &ifs->ifa;
} else {
free(ifs);
}
@@ -210,7 +210,7 @@ int getifaddrs(struct ifaddrs **ifap)
int r;
memset(ctx, 0, sizeof *ctx);
r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
- if (r == 0) *ifap = &ctx->first->ifa;
- else freeifaddrs(&ctx->first->ifa);
+ if (r == 0) *ifap = ctx->first;
+ else freeifaddrs(ctx->first);
return r;
}
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
index 949e1811..133c15b3 100644
--- a/src/network/getnameinfo.c
+++ b/src/network/getnameinfo.c
@@ -58,6 +58,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i
if ((p=strchr(line, '#'))) *p++='\n', *p=0;
for (p=line; *p && !isspace(*p); p++);
+ if (!*p) continue;
*p++ = 0;
if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0)
continue;
@@ -108,10 +109,10 @@ static void reverse_services(char *buf, int port, int dgram)
__fclose_ca(f);
}
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
{
if (rr != RR_PTR) return 0;
- if (__dn_expand(packet, (const unsigned char *)packet + 512,
+ if (__dn_expand(packet, (const unsigned char *)packet + plen,
data, c, 256) <= 0)
*(char *)c = 0;
return 0;
@@ -161,8 +162,10 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
query[3] = 0; /* don't need AD flag */
int rlen = __res_send(query, qlen, reply, sizeof reply);
buf[0] = 0;
- if (rlen > 0)
+ if (rlen > 0) {
+ if (rlen > sizeof reply) rlen = sizeof reply;
__dns_parse(reply, rlen, dns_parse_callback, buf);
+ }
}
if (!*buf) {
if (flags & NI_NAMEREQD) return EAI_NONAME;
diff --git a/src/network/getservbyport_r.c b/src/network/getservbyport_r.c
index b7f21c6b..e4cc3079 100644
--- a/src/network/getservbyport_r.c
+++ b/src/network/getservbyport_r.c
@@ -26,7 +26,7 @@ int getservbyport_r(int port, const char *prots,
/* Align buffer */
i = (uintptr_t)buf & sizeof(char *)-1;
if (!i) i = sizeof(char *);
- if (buflen < 3*sizeof(char *)-i)
+ if (buflen <= 3*sizeof(char *)-i)
return ERANGE;
buf += sizeof(char *)-i;
buflen -= sizeof(char *)-i;
@@ -46,6 +46,8 @@ int getservbyport_r(int port, const char *prots,
case EAI_MEMORY:
case EAI_SYSTEM:
return ENOMEM;
+ case EAI_OVERFLOW:
+ return ERANGE;
default:
return ENOENT;
case 0:
diff --git a/src/network/lookup.h b/src/network/lookup.h
index ef662725..54b2f8b5 100644
--- a/src/network/lookup.h
+++ b/src/network/lookup.h
@@ -50,6 +50,6 @@ hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, in
hidden int __get_resolv_conf(struct resolvconf *, char *, size_t);
hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *);
-hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
+hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *);
#endif
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
index 5f6867cb..35218185 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -109,15 +109,15 @@ struct dpc_ctx {
#define RR_CNAME 5
#define RR_AAAA 28
-#define ABUF_SIZE 768
+#define ABUF_SIZE 4800
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
{
char tmp[256];
int family;
struct dpc_ctx *ctx = c;
if (rr == RR_CNAME) {
- if (__dn_expand(packet, (const unsigned char *)packet + ABUF_SIZE,
+ if (__dn_expand(packet, (const unsigned char *)packet + plen,
data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
strcpy(ctx->canon, tmp);
return 0;
@@ -179,6 +179,7 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
for (i=nq-1; i>=0; i--) {
ctx.rrtype = qtypes[i];
+ if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i];
__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
}
diff --git a/src/network/res_msend.c b/src/network/res_msend.c
index 11c6aa0e..86c2fcf4 100644
--- a/src/network/res_msend.c
+++ b/src/network/res_msend.c
@@ -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];