diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 13:54:38 +0000 |
commit | 8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch) | |
tree | df55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-top-half/musl/src/network | |
parent | Initial commit. (diff) | |
download | wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.tar.xz wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.zip |
Adding upstream version 0.0~git20221206.8b7148f.upstream/0.0_git20221206.8b7148f
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
79 files changed, 3545 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/network/accept.c b/libc-top-half/musl/src/network/accept.c new file mode 100644 index 0000000..a92406f --- /dev/null +++ b/libc-top-half/musl/src/network/accept.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int accept(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) +{ + return socketcall_cp(accept, fd, addr, len, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/accept4.c b/libc-top-half/musl/src/network/accept4.c new file mode 100644 index 0000000..59ab172 --- /dev/null +++ b/libc-top-half/musl/src/network/accept4.c @@ -0,0 +1,19 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <errno.h> +#include <fcntl.h> +#include "syscall.h" + +int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int flg) +{ + 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; + ret = accept(fd, addr, len); + if (ret<0) return ret; + if (flg & SOCK_CLOEXEC) + __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC); + if (flg & SOCK_NONBLOCK) + __syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK); + return ret; +} diff --git a/libc-top-half/musl/src/network/bind.c b/libc-top-half/musl/src/network/bind.c new file mode 100644 index 0000000..07bb669 --- /dev/null +++ b/libc-top-half/musl/src/network/bind.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int bind(int fd, const struct sockaddr *addr, socklen_t len) +{ + return socketcall(bind, fd, addr, len, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/connect.c b/libc-top-half/musl/src/network/connect.c new file mode 100644 index 0000000..289127b --- /dev/null +++ b/libc-top-half/musl/src/network/connect.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int connect(int fd, const struct sockaddr *addr, socklen_t len) +{ + return socketcall_cp(connect, fd, addr, len, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/dn_comp.c b/libc-top-half/musl/src/network/dn_comp.c new file mode 100644 index 0000000..f0ccd16 --- /dev/null +++ b/libc-top-half/musl/src/network/dn_comp.c @@ -0,0 +1,107 @@ +#include <string.h> +#include <resolv.h> + +/* RFC 1035 message compression */ + +/* label start offsets of a compressed domain name s */ +static int getoffs(short *offs, const unsigned char *base, const unsigned char *s) +{ + int i=0; + for (;;) { + while (*s & 0xc0) { + if ((*s & 0xc0) != 0xc0) return 0; + s = base + ((s[0]&0x3f)<<8 | s[1]); + } + if (!*s) return i; + if (s-base >= 0x4000) return 0; + offs[i++] = s-base; + s += *s + 1; + } +} + +/* label lengths of an ascii domain name s */ +static int getlens(unsigned char *lens, const char *s, int l) +{ + int i=0,j=0,k=0; + for (;;) { + for (; j<l && s[j]!='.'; j++); + if (j-k-1u > 62) return 0; + lens[i++] = j-k; + if (j==l) return i; + k = ++j; + } +} + +/* longest suffix match of an ascii domain with a compressed domain name dn */ +static int match(int *offset, const unsigned char *base, const unsigned char *dn, + const char *end, const unsigned char *lens, int nlen) +{ + int l, o, m=0; + short offs[128]; + int noff = getoffs(offs, base, dn); + if (!noff) return 0; + for (;;) { + l = lens[--nlen]; + o = offs[--noff]; + end -= l; + if (l != base[o] || memcmp(base+o+1, end, l)) + return m; + *offset = o; + m += l; + if (nlen) m++; + if (!nlen || !noff) return m; + end--; + } +} + +int dn_comp(const char *src, unsigned char *dst, int space, unsigned char **dnptrs, unsigned char **lastdnptr) +{ + int i, j, n, m=0, offset, bestlen=0, bestoff; + unsigned char lens[127]; + unsigned char **p; + const char *end; + size_t l = strnlen(src, 255); + if (l && src[l-1] == '.') l--; + if (l>253 || space<=0) return -1; + if (!l) { + *dst = 0; + return 1; + } + end = src+l; + n = getlens(lens, src, l); + if (!n) return -1; + + p = dnptrs; + if (p && *p) for (p++; *p; p++) { + m = match(&offset, *dnptrs, *p, end, lens, n); + if (m > bestlen) { + bestlen = m; + bestoff = offset; + if (m == l) + break; + } + } + + /* encode unmatched part */ + if (space < l-bestlen+2+(bestlen-1 < l-1)) return -1; + memcpy(dst+1, src, l-bestlen); + for (i=j=0; i<l-bestlen; i+=lens[j++]+1) + dst[i] = lens[j]; + + /* add tail */ + if (bestlen) { + dst[i++] = 0xc0 | bestoff>>8; + dst[i++] = bestoff; + } else + dst[i++] = 0; + + /* save dst pointer */ + if (i>2 && lastdnptr && dnptrs && *dnptrs) { + while (*p) p++; + if (p+1 < lastdnptr) { + *p++ = dst; + *p=0; + } + } + return i; +} diff --git a/libc-top-half/musl/src/network/dn_expand.c b/libc-top-half/musl/src/network/dn_expand.c new file mode 100644 index 0000000..eac343a --- /dev/null +++ b/libc-top-half/musl/src/network/dn_expand.c @@ -0,0 +1,33 @@ +#include <resolv.h> + +int __dn_expand(const unsigned char *base, const unsigned char *end, const unsigned char *src, char *dest, int space) +{ + const unsigned char *p = src; + char *dend, *dbegin = dest; + int len = -1, i, j; + if (p==end || space <= 0) return -1; + dend = dest + (space > 254 ? 254 : space); + /* detect reference loop using an iteration counter */ + for (i=0; i < end-base; i+=2) { + /* loop invariants: p<end, dest<dend */ + if (*p & 0xc0) { + if (p+1==end) return -1; + j = ((p[0] & 0x3f) << 8) | p[1]; + if (len < 0) len = p+2-src; + if (j >= end-base) return -1; + p = base+j; + } else if (*p) { + if (dest != dbegin) *dest++ = '.'; + j = *p++; + if (j >= end-p || j >= dend-dest) return -1; + while (j--) *dest++ = *p++; + } else { + *dest = 0; + if (len < 0) len = p+1-src; + return len; + } + } + return -1; +} + +weak_alias(__dn_expand, dn_expand); diff --git a/libc-top-half/musl/src/network/dn_skipname.c b/libc-top-half/musl/src/network/dn_skipname.c new file mode 100644 index 0000000..eba65bb --- /dev/null +++ b/libc-top-half/musl/src/network/dn_skipname.c @@ -0,0 +1,15 @@ +#include <resolv.h> + +int dn_skipname(const unsigned char *s, const unsigned char *end) +{ + const unsigned char *p = s; + while (p < end) + if (!*p) return p-s+1; + else if (*p>=192) + if (p+1<end) return p-s+2; + else break; + else + if (end-p<*p+1) break; + else p += *p + 1; + return -1; +} diff --git a/libc-top-half/musl/src/network/dns_parse.c b/libc-top-half/musl/src/network/dns_parse.c new file mode 100644 index 0000000..e6ee19d --- /dev/null +++ b/libc-top-half/musl/src/network/dns_parse.c @@ -0,0 +1,33 @@ +#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 qdcount, ancount; + const unsigned char *p; + int len; + + if (rlen<12) return -1; + if ((r[3]&15)) return 0; + 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) + 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) + 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; + p += 10 + len; + } + return 0; +} diff --git a/libc-top-half/musl/src/network/ent.c b/libc-top-half/musl/src/network/ent.c new file mode 100644 index 0000000..c6e0123 --- /dev/null +++ b/libc-top-half/musl/src/network/ent.c @@ -0,0 +1,22 @@ +#include <netdb.h> + +void sethostent(int x) +{ +} + +struct hostent *gethostent() +{ + return 0; +} + +struct netent *getnetent() +{ + return 0; +} + +void endhostent(void) +{ +} + +weak_alias(sethostent, setnetent); +weak_alias(endhostent, endnetent); diff --git a/libc-top-half/musl/src/network/ether.c b/libc-top-half/musl/src/network/ether.c new file mode 100644 index 0000000..4304a97 --- /dev/null +++ b/libc-top-half/musl/src/network/ether.c @@ -0,0 +1,58 @@ +#include <stdlib.h> +#include <netinet/ether.h> +#include <stdio.h> + +struct ether_addr *ether_aton_r (const char *x, struct ether_addr *p_a) +{ + struct ether_addr a; + char *y; + for (int ii = 0; ii < 6; ii++) { + unsigned long int n; + if (ii != 0) { + if (x[0] != ':') return 0; /* bad format */ + else x++; + } + n = strtoul (x, &y, 16); + x = y; + if (n > 0xFF) return 0; /* bad byte */ + a.ether_addr_octet[ii] = n; + } + if (x[0] != 0) return 0; /* bad format */ + *p_a = a; + return p_a; +} + +struct ether_addr *ether_aton (const char *x) +{ + static struct ether_addr a; + return ether_aton_r (x, &a); +} + +char *ether_ntoa_r (const struct ether_addr *p_a, char *x) { + char *y; + y = x; + for (int ii = 0; ii < 6; ii++) { + x += sprintf (x, ii == 0 ? "%.2X" : ":%.2X", p_a->ether_addr_octet[ii]); + } + return y; +} + +char *ether_ntoa (const struct ether_addr *p_a) { + static char x[18]; + return ether_ntoa_r (p_a, x); +} + +int ether_line(const char *l, struct ether_addr *e, char *hostname) +{ + return -1; +} + +int ether_ntohost(char *hostname, const struct ether_addr *e) +{ + return -1; +} + +int ether_hostton(const char *hostname, struct ether_addr *e) +{ + return -1; +} diff --git a/libc-top-half/musl/src/network/freeaddrinfo.c b/libc-top-half/musl/src/network/freeaddrinfo.c new file mode 100644 index 0000000..62241c2 --- /dev/null +++ b/libc-top-half/musl/src/network/freeaddrinfo.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <stddef.h> +#include <netdb.h> +#include "lookup.h" +#include "lock.h" + +void freeaddrinfo(struct addrinfo *p) +{ + size_t cnt; + for (cnt=1; p->ai_next; cnt++, p=p->ai_next); + struct aibuf *b = (void *)((char *)p - offsetof(struct aibuf, ai)); + b -= b->slot; + LOCK(b->lock); + if (!(b->ref -= cnt)) free(b); + else UNLOCK(b->lock); +} diff --git a/libc-top-half/musl/src/network/gai_strerror.c b/libc-top-half/musl/src/network/gai_strerror.c new file mode 100644 index 0000000..9596580 --- /dev/null +++ b/libc-top-half/musl/src/network/gai_strerror.c @@ -0,0 +1,25 @@ +#include <netdb.h> +#include "locale_impl.h" + +static const char msgs[] = + "Invalid flags\0" + "Name does not resolve\0" + "Try again\0" + "Non-recoverable error\0" + "Unknown error\0" + "Unrecognized address family or invalid length\0" + "Unrecognized socket type\0" + "Unrecognized service\0" + "Unknown error\0" + "Out of memory\0" + "System error\0" + "Overflow\0" + "\0Unknown error"; + +const char *gai_strerror(int ecode) +{ + const char *s; + for (s=msgs, ecode++; ecode && *s; ecode++, s++) for (; *s; s++); + if (!*s) s++; + return LCTRANS_CUR(s); +} diff --git a/libc-top-half/musl/src/network/getaddrinfo.c b/libc-top-half/musl/src/network/getaddrinfo.c new file mode 100644 index 0000000..efaab30 --- /dev/null +++ b/libc-top-half/musl/src/network/getaddrinfo.c @@ -0,0 +1,135 @@ +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> +#include <endian.h> +#include <errno.h> +#include "lookup.h" + +int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) +{ + struct service ports[MAXSERVS]; + struct address addrs[MAXADDRS]; + char canon[256], *outcanon; + int nservs, naddrs, nais, canon_len, i, j, k; + int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; + struct aibuf *out; + + if (!host && !serv) return EAI_NONAME; + + if (hint) { + family = hint->ai_family; + flags = hint->ai_flags; + proto = hint->ai_protocol; + socktype = hint->ai_socktype; + + const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | + AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; + if ((flags & mask) != flags) + return EAI_BADFLAGS; + + switch (family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + break; + default: + return EAI_FAMILY; + } + } + + if (flags & AI_ADDRCONFIG) { + /* Define the "an address is configured" condition for address + * families via ability to create a socket for the family plus + * routability of the loopback address for the family. */ + static const struct sockaddr_in lo4 = { + .sin_family = AF_INET, .sin_port = 65535, + .sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN + ? 0x7f000001 : 0x0100007f + }; + static const struct sockaddr_in6 lo6 = { + .sin6_family = AF_INET6, .sin6_port = 65535, + .sin6_addr = IN6ADDR_LOOPBACK_INIT + }; + int tf[2] = { AF_INET, AF_INET6 }; + const void *ta[2] = { &lo4, &lo6 }; + socklen_t tl[2] = { sizeof lo4, sizeof lo6 }; + for (i=0; i<2; i++) { + if (family==tf[1-i]) continue; + int s = socket(tf[i], SOCK_CLOEXEC|SOCK_DGRAM, + IPPROTO_UDP); + if (s>=0) { + int cs; + pthread_setcancelstate( + PTHREAD_CANCEL_DISABLE, &cs); + int r = connect(s, ta[i], tl[i]); + pthread_setcancelstate(cs, 0); + close(s); + if (!r) continue; + } + switch (errno) { + case EADDRNOTAVAIL: + case EAFNOSUPPORT: + case EHOSTUNREACH: + case ENETDOWN: + case ENETUNREACH: + break; + default: + return EAI_SYSTEM; + } + if (family == tf[i]) return EAI_NONAME; + family = tf[1-i]; + } + } + + nservs = __lookup_serv(ports, serv, proto, socktype, flags); + if (nservs < 0) return nservs; + + naddrs = __lookup_name(addrs, canon, host, family, flags); + if (naddrs < 0) return naddrs; + + nais = nservs * naddrs; + canon_len = strlen(canon); + out = calloc(1, nais * sizeof(*out) + canon_len + 1); + if (!out) return EAI_MEMORY; + + if (canon_len) { + outcanon = (void *)&out[nais]; + memcpy(outcanon, canon, canon_len+1); + } else { + outcanon = 0; + } + + for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) { + out[k].slot = k; + out[k].ai = (struct addrinfo){ + .ai_family = addrs[i].family, + .ai_socktype = ports[j].socktype, + .ai_protocol = ports[j].proto, + .ai_addrlen = addrs[i].family == AF_INET + ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6), + .ai_addr = (void *)&out[k].sa, + .ai_canonname = outcanon }; + if (k) out[k-1].ai.ai_next = &out[k].ai; + switch (addrs[i].family) { + case AF_INET: + out[k].sa.sin.sin_family = AF_INET; + out[k].sa.sin.sin_port = htons(ports[j].port); + memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4); + break; + case AF_INET6: + out[k].sa.sin6.sin6_family = AF_INET6; + out[k].sa.sin6.sin6_port = htons(ports[j].port); + out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid; + memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16); + break; + } + } + out[0].ref = nais; + *res = &out->ai; + return 0; +} diff --git a/libc-top-half/musl/src/network/gethostbyaddr.c b/libc-top-half/musl/src/network/gethostbyaddr.c new file mode 100644 index 0000000..598e224 --- /dev/null +++ b/libc-top-half/musl/src/network/gethostbyaddr.c @@ -0,0 +1,24 @@ +#define _GNU_SOURCE + +#include <netdb.h> +#include <errno.h> +#include <stdlib.h> + +struct hostent *gethostbyaddr(const void *a, socklen_t l, int af) +{ + static struct hostent *h; + size_t size = 63; + struct hostent *res; + int err; + do { + free(h); + h = malloc(size+=size+1); + if (!h) { + h_errno = NO_RECOVERY; + return 0; + } + err = gethostbyaddr_r(a, l, af, h, + (void *)(h+1), size-sizeof *h, &res, &h_errno); + } while (err == ERANGE); + return err ? 0 : h; +} diff --git a/libc-top-half/musl/src/network/gethostbyaddr_r.c b/libc-top-half/musl/src/network/gethostbyaddr_r.c new file mode 100644 index 0000000..0f1e61a --- /dev/null +++ b/libc-top-half/musl/src/network/gethostbyaddr_r.c @@ -0,0 +1,71 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> +#include <errno.h> +#include <inttypes.h> + +int gethostbyaddr_r(const void *a, socklen_t l, int af, + struct hostent *h, char *buf, size_t buflen, + struct hostent **res, int *err) +{ + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa = { .sin.sin_family = af }; + socklen_t sl = af==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; + int i; + + *res = 0; + + /* Load address argument into sockaddr structure */ + if (af==AF_INET6 && l==16) memcpy(&sa.sin6.sin6_addr, a, 16); + else if (af==AF_INET && l==4) memcpy(&sa.sin.sin_addr, a, 4); + else { + *err = NO_RECOVERY; + return EINVAL; + } + + /* Align buffer and check for space for pointers and ip address */ + i = (uintptr_t)buf & sizeof(char *)-1; + if (!i) i = sizeof(char *); + if (buflen <= 5*sizeof(char *)-i + l) return ERANGE; + buf += sizeof(char *)-i; + buflen -= 5*sizeof(char *)-i + l; + + h->h_addr_list = (void *)buf; + buf += 2*sizeof(char *); + h->h_aliases = (void *)buf; + buf += 2*sizeof(char *); + + h->h_addr_list[0] = buf; + memcpy(h->h_addr_list[0], a, l); + buf += l; + h->h_addr_list[1] = 0; + h->h_aliases[0] = buf; + h->h_aliases[1] = 0; + + switch (getnameinfo((void *)&sa, sl, buf, buflen, 0, 0, 0)) { + case EAI_AGAIN: + *err = TRY_AGAIN; + return EAGAIN; + case EAI_OVERFLOW: + return ERANGE; + default: + case EAI_MEMORY: + case EAI_SYSTEM: + case EAI_FAIL: + *err = NO_RECOVERY; + return errno; + case 0: + break; + } + + h->h_addrtype = af; + h->h_length = l; + h->h_name = h->h_aliases[0]; + *res = h; + return 0; +} diff --git a/libc-top-half/musl/src/network/gethostbyname.c b/libc-top-half/musl/src/network/gethostbyname.c new file mode 100644 index 0000000..bfedf52 --- /dev/null +++ b/libc-top-half/musl/src/network/gethostbyname.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> + +struct hostent *gethostbyname(const char *name) +{ + return gethostbyname2(name, AF_INET); +} diff --git a/libc-top-half/musl/src/network/gethostbyname2.c b/libc-top-half/musl/src/network/gethostbyname2.c new file mode 100644 index 0000000..dc9d662 --- /dev/null +++ b/libc-top-half/musl/src/network/gethostbyname2.c @@ -0,0 +1,25 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <errno.h> +#include <stdlib.h> + +struct hostent *gethostbyname2(const char *name, int af) +{ + static struct hostent *h; + size_t size = 63; + struct hostent *res; + int err; + do { + free(h); + h = malloc(size+=size+1); + if (!h) { + h_errno = NO_RECOVERY; + return 0; + } + err = gethostbyname2_r(name, af, h, + (void *)(h+1), size-sizeof *h, &res, &h_errno); + } while (err == ERANGE); + return err ? 0 : h; +} diff --git a/libc-top-half/musl/src/network/gethostbyname2_r.c b/libc-top-half/musl/src/network/gethostbyname2_r.c new file mode 100644 index 0000000..fc89487 --- /dev/null +++ b/libc-top-half/musl/src/network/gethostbyname2_r.c @@ -0,0 +1,80 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> +#include <errno.h> +#include <stdint.h> +#include "lookup.h" + +int gethostbyname2_r(const char *name, int af, + struct hostent *h, char *buf, size_t buflen, + struct hostent **res, int *err) +{ + struct address addrs[MAXADDRS]; + char canon[256]; + int i, cnt; + size_t align, need; + + *res = 0; + cnt = __lookup_name(addrs, canon, name, af, AI_CANONNAME); + if (cnt<0) switch (cnt) { + case EAI_NONAME: + *err = HOST_NOT_FOUND; + return ENOENT; + case EAI_AGAIN: + *err = TRY_AGAIN; + return EAGAIN; + default: + case EAI_FAIL: + *err = NO_RECOVERY; + return EBADMSG; + case EAI_MEMORY: + case EAI_SYSTEM: + *err = NO_RECOVERY; + return errno; + } + + h->h_addrtype = af; + h->h_length = af==AF_INET6 ? 16 : 4; + + /* Align buffer */ + align = -(uintptr_t)buf & sizeof(char *)-1; + + need = 4*sizeof(char *); + need += (cnt + 1) * (sizeof(char *) + h->h_length); + need += strlen(name)+1; + need += strlen(canon)+1; + need += align; + + if (need > buflen) return ERANGE; + + buf += align; + h->h_aliases = (void *)buf; + buf += 3*sizeof(char *); + h->h_addr_list = (void *)buf; + buf += (cnt+1)*sizeof(char *); + + for (i=0; i<cnt; i++) { + h->h_addr_list[i] = (void *)buf; + buf += h->h_length; + memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length); + } + h->h_addr_list[i] = 0; + + h->h_name = h->h_aliases[0] = buf; + strcpy(h->h_name, canon); + buf += strlen(h->h_name)+1; + + if (strcmp(h->h_name, name)) { + h->h_aliases[1] = buf; + strcpy(h->h_aliases[1], name); + buf += strlen(h->h_aliases[1])+1; + } else h->h_aliases[1] = 0; + + h->h_aliases[2] = 0; + + *res = h; + return 0; +} diff --git a/libc-top-half/musl/src/network/gethostbyname_r.c b/libc-top-half/musl/src/network/gethostbyname_r.c new file mode 100644 index 0000000..cd87254 --- /dev/null +++ b/libc-top-half/musl/src/network/gethostbyname_r.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> + +int gethostbyname_r(const char *name, + struct hostent *h, char *buf, size_t buflen, + struct hostent **res, int *err) +{ + return gethostbyname2_r(name, AF_INET, h, buf, buflen, res, err); +} diff --git a/libc-top-half/musl/src/network/getifaddrs.c b/libc-top-half/musl/src/network/getifaddrs.c new file mode 100644 index 0000000..fed75bd --- /dev/null +++ b/libc-top-half/musl/src/network/getifaddrs.c @@ -0,0 +1,216 @@ +#define _GNU_SOURCE +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <ifaddrs.h> +#include <syscall.h> +#include <net/if.h> +#include <netinet/in.h> +#include "netlink.h" + +#define IFADDRS_HASH_SIZE 64 + +/* getifaddrs() reports hardware addresses with PF_PACKET that implies + * struct sockaddr_ll. But e.g. Infiniband socket address length is + * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct + * to extend ssl_addr - callers should be able to still use it. */ +struct sockaddr_ll_hack { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[24]; +}; + +union sockany { + struct sockaddr sa; + struct sockaddr_ll_hack ll; + struct sockaddr_in v4; + struct sockaddr_in6 v6; +}; + +struct ifaddrs_storage { + struct ifaddrs ifa; + struct ifaddrs_storage *hash_next; + union sockany addr, netmask, ifu; + unsigned int index; + char name[IFNAMSIZ+1]; +}; + +struct ifaddrs_ctx { + struct ifaddrs_storage *first; + struct ifaddrs_storage *last; + struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; +}; + +void freeifaddrs(struct ifaddrs *ifp) +{ + struct ifaddrs *n; + while (ifp) { + n = ifp->ifa_next; + free(ifp); + ifp = n; + } +} + +static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex) +{ + uint8_t *dst; + int len; + + switch (af) { + case AF_INET: + dst = (uint8_t*) &sa->v4.sin_addr; + len = 4; + break; + case AF_INET6: + dst = (uint8_t*) &sa->v6.sin6_addr; + len = 16; + if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) + sa->v6.sin6_scope_id = ifindex; + break; + default: + return; + } + if (addrlen < len) return; + sa->sa.sa_family = af; + memcpy(dst, addr, len); + *r = &sa->sa; +} + +static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen) +{ + uint8_t addr[16] = {0}; + int i; + + if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr); + i = prefixlen / 8; + memset(addr, 0xff, i); + if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8)); + copy_addr(r, af, sa, addr, sizeof(addr), 0); +} + +static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype) +{ + if (addrlen > sizeof(sa->ll.sll_addr)) return; + sa->ll.sll_family = AF_PACKET; + sa->ll.sll_ifindex = ifindex; + sa->ll.sll_hatype = hatype; + sa->ll.sll_halen = addrlen; + memcpy(sa->ll.sll_addr, addr, addrlen); + *r = &sa->sa; +} + +static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) +{ + struct ifaddrs_ctx *ctx = pctx; + struct ifaddrs_storage *ifs, *ifs0; + struct ifinfomsg *ifi = NLMSG_DATA(h); + struct ifaddrmsg *ifa = NLMSG_DATA(h); + struct rtattr *rta; + int stats_len = 0; + + if (h->nlmsg_type == RTM_NEWLINK) { + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != IFLA_STATS) continue; + stats_len = RTA_DATALEN(rta); + break; + } + } else { + for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next) + if (ifs0->index == ifa->ifa_index) + break; + if (!ifs0) return 0; + } + + ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len); + if (ifs == 0) return -1; + + if (h->nlmsg_type == RTM_NEWLINK) { + ifs->index = ifi->ifi_index; + ifs->ifa.ifa_flags = ifi->ifi_flags; + + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + case IFLA_ADDRESS: + copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_BROADCAST: + copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_STATS: + ifs->ifa.ifa_data = (void*)(ifs+1); + memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta)); + break; + } + } + if (ifs->ifa.ifa_name) { + unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE; + ifs->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ifs; + } + } else { + ifs->ifa.ifa_name = ifs0->ifa.ifa_name; + ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; + for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFA_ADDRESS: + /* If ifa_addr is already set we, received an IFA_LOCAL before + * so treat this as destination address */ + if (ifs->ifa.ifa_addr) + copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + else + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_BROADCAST: + copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LOCAL: + /* If ifa_addr is set and we get IFA_LOCAL, assume we have + * a point-to-point network. Move address to correct field. */ + if (ifs->ifa.ifa_addr) { + ifs->ifu = ifs->addr; + ifs->ifa.ifa_dstaddr = &ifs->ifu.sa; + memset(&ifs->addr, 0, sizeof(ifs->addr)); + } + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LABEL: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + } + } + if (ifs->ifa.ifa_addr) + gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen); + } + + if (ifs->ifa.ifa_name) { + if (!ctx->first) ctx->first = ifs; + if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa; + ctx->last = ifs; + } else { + free(ifs); + } + return 0; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + struct ifaddrs_ctx _ctx, *ctx = &_ctx; + 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); + return r; +} diff --git a/libc-top-half/musl/src/network/getnameinfo.c b/libc-top-half/musl/src/network/getnameinfo.c new file mode 100644 index 0000000..949e181 --- /dev/null +++ b/libc-top-half/musl/src/network/getnameinfo.c @@ -0,0 +1,200 @@ +#include <netdb.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <ctype.h> +#include <resolv.h> +#include "lookup.h" +#include "stdio_impl.h" + +#define PTR_MAX (64 + sizeof ".in-addr.arpa") +#define RR_PTR 12 + +static char *itoa(char *p, unsigned x) { + p += 3*sizeof(int); + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +static void mkptr4(char *s, const unsigned char *ip) +{ + sprintf(s, "%d.%d.%d.%d.in-addr.arpa", + ip[3], ip[2], ip[1], ip[0]); +} + +static void mkptr6(char *s, const unsigned char *ip) +{ + static const char xdigits[] = "0123456789abcdef"; + int i; + for (i=15; i>=0; i--) { + *s++ = xdigits[ip[i]&15]; *s++ = '.'; + *s++ = xdigits[ip[i]>>4]; *s++ = '.'; + } + strcpy(s, "ip6.arpa"); +} + +static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, int family) +{ + char line[512], *p, *z; + unsigned char _buf[1032], atmp[16]; + struct address iplit; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) return; + if (family == AF_INET) { + memcpy(atmp+12, a, 4); + memcpy(atmp, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + a = atmp; + } + while (fgets(line, sizeof line, f)) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + for (p=line; *p && !isspace(*p); p++); + *p++ = 0; + if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0) + continue; + + if (iplit.family == AF_INET) { + memcpy(iplit.addr+12, iplit.addr, 4); + memcpy(iplit.addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + iplit.scopeid = 0; + } + + if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid) + continue; + + for (; *p && isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z = 0; + if (z-p < 256) { + memcpy(buf, p, z-p+1); + break; + } + } + __fclose_ca(f); +} + +static void reverse_services(char *buf, int port, int dgram) +{ + unsigned long svport; + char line[128], *p, *z; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) return; + while (fgets(line, sizeof line, f)) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + for (p=line; *p && !isspace(*p); p++); + if (!*p) continue; + *p++ = 0; + svport = strtoul(p, &z, 10); + + if (svport != port || z==p) continue; + if (dgram && strncmp(z, "/udp", 4)) continue; + if (!dgram && strncmp(z, "/tcp", 4)) continue; + if (p-line > 32) continue; + + memcpy(buf, line, p-line); + break; + } + __fclose_ca(f); +} + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +{ + if (rr != RR_PTR) return 0; + if (__dn_expand(packet, (const unsigned char *)packet + 512, + data, c, 256) <= 0) + *(char *)c = 0; + return 0; + +} + +int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, + char *restrict node, socklen_t nodelen, + char *restrict serv, socklen_t servlen, + int flags) +{ + char ptr[PTR_MAX]; + char buf[256], num[3*sizeof(int)+1]; + int af = sa->sa_family; + unsigned char *a; + unsigned scopeid; + + switch (af) { + case AF_INET: + a = (void *)&((struct sockaddr_in *)sa)->sin_addr; + if (sl < sizeof(struct sockaddr_in)) return EAI_FAMILY; + mkptr4(ptr, a); + scopeid = 0; + break; + case AF_INET6: + a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr; + if (sl < sizeof(struct sockaddr_in6)) return EAI_FAMILY; + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12)) + mkptr6(ptr, a); + else + mkptr4(ptr, a+12); + scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id; + break; + default: + return EAI_FAMILY; + } + + if (node && nodelen) { + buf[0] = 0; + if (!(flags & NI_NUMERICHOST)) { + reverse_hosts(buf, a, scopeid, af); + } + if (!*buf && !(flags & NI_NUMERICHOST)) { + unsigned char query[18+PTR_MAX], reply[512]; + int qlen = __res_mkquery(0, ptr, 1, RR_PTR, + 0, 0, 0, query, sizeof query); + query[3] = 0; /* don't need AD flag */ + int rlen = __res_send(query, qlen, reply, sizeof reply); + buf[0] = 0; + if (rlen > 0) + __dns_parse(reply, rlen, dns_parse_callback, buf); + } + if (!*buf) { + if (flags & NI_NAMEREQD) return EAI_NONAME; + inet_ntop(af, a, buf, sizeof buf); + if (scopeid) { + char *p = 0, tmp[IF_NAMESIZE+1]; + if (!(flags & NI_NUMERICSCOPE) && + (IN6_IS_ADDR_LINKLOCAL(a) || + IN6_IS_ADDR_MC_LINKLOCAL(a))) + p = if_indextoname(scopeid, tmp+1); + if (!p) + p = itoa(num, scopeid); + *--p = '%'; + strcat(buf, p); + } + } + if (strlen(buf) >= nodelen) return EAI_OVERFLOW; + strcpy(node, buf); + } + + if (serv && servlen) { + char *p = buf; + int port = ntohs(((struct sockaddr_in *)sa)->sin_port); + buf[0] = 0; + if (!(flags & NI_NUMERICSERV)) + reverse_services(buf, port, flags & NI_DGRAM); + if (!*p) + p = itoa(num, port); + if (strlen(p) >= servlen) + return EAI_OVERFLOW; + strcpy(serv, p); + } + + return 0; +} diff --git a/libc-top-half/musl/src/network/getpeername.c b/libc-top-half/musl/src/network/getpeername.c new file mode 100644 index 0000000..6567b45 --- /dev/null +++ b/libc-top-half/musl/src/network/getpeername.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int getpeername(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) +{ + return socketcall(getpeername, fd, addr, len, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/getservbyname.c b/libc-top-half/musl/src/network/getservbyname.c new file mode 100644 index 0000000..dd30376 --- /dev/null +++ b/libc-top-half/musl/src/network/getservbyname.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include <netdb.h> + +struct servent *getservbyname(const char *name, const char *prots) +{ + static struct servent se; + static char *buf[2]; + struct servent *res; + if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res)) + return 0; + return &se; +} diff --git a/libc-top-half/musl/src/network/getservbyname_r.c b/libc-top-half/musl/src/network/getservbyname_r.c new file mode 100644 index 0000000..cad6317 --- /dev/null +++ b/libc-top-half/musl/src/network/getservbyname_r.c @@ -0,0 +1,55 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <inttypes.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include "lookup.h" + +#define ALIGN (sizeof(struct { char a; char *b; }) - sizeof(char *)) + +int getservbyname_r(const char *name, const char *prots, + struct servent *se, char *buf, size_t buflen, struct servent **res) +{ + struct service servs[MAXSERVS]; + int cnt, proto, align; + + *res = 0; + + /* Don't treat numeric port number strings as service records. */ + char *end = ""; + strtoul(name, &end, 10); + if (!*end) return ENOENT; + + /* Align buffer */ + align = -(uintptr_t)buf & ALIGN-1; + if (buflen < 2*sizeof(char *)+align) + return ERANGE; + buf += align; + + if (!prots) proto = 0; + else if (!strcmp(prots, "tcp")) proto = IPPROTO_TCP; + else if (!strcmp(prots, "udp")) proto = IPPROTO_UDP; + else return EINVAL; + + cnt = __lookup_serv(servs, name, proto, 0, 0); + if (cnt<0) switch (cnt) { + case EAI_MEMORY: + case EAI_SYSTEM: + return ENOMEM; + default: + return ENOENT; + } + + se->s_name = (char *)name; + se->s_aliases = (void *)buf; + se->s_aliases[0] = se->s_name; + se->s_aliases[1] = 0; + se->s_port = htons(servs[0].port); + se->s_proto = servs[0].proto == IPPROTO_TCP ? "tcp" : "udp"; + + *res = se; + return 0; +} diff --git a/libc-top-half/musl/src/network/getservbyport.c b/libc-top-half/musl/src/network/getservbyport.c new file mode 100644 index 0000000..c9ecbb1 --- /dev/null +++ b/libc-top-half/musl/src/network/getservbyport.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include <netdb.h> + +struct servent *getservbyport(int port, const char *prots) +{ + static struct servent se; + static long buf[32/sizeof(long)]; + struct servent *res; + if (getservbyport_r(port, prots, &se, (void *)buf, sizeof buf, &res)) + return 0; + return &se; +} diff --git a/libc-top-half/musl/src/network/getservbyport_r.c b/libc-top-half/musl/src/network/getservbyport_r.c new file mode 100644 index 0000000..b7f21c6 --- /dev/null +++ b/libc-top-half/musl/src/network/getservbyport_r.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <inttypes.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +int getservbyport_r(int port, const char *prots, + struct servent *se, char *buf, size_t buflen, struct servent **res) +{ + int i; + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_port = port, + }; + + if (!prots) { + int r = getservbyport_r(port, "tcp", se, buf, buflen, res); + if (r) r = getservbyport_r(port, "udp", se, buf, buflen, res); + return r; + } + *res = 0; + + /* Align buffer */ + i = (uintptr_t)buf & sizeof(char *)-1; + if (!i) i = sizeof(char *); + if (buflen < 3*sizeof(char *)-i) + return ERANGE; + buf += sizeof(char *)-i; + buflen -= sizeof(char *)-i; + + if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return EINVAL; + + se->s_port = port; + se->s_proto = (char *)prots; + se->s_aliases = (void *)buf; + buf += 2*sizeof(char *); + buflen -= 2*sizeof(char *); + se->s_aliases[1] = 0; + se->s_aliases[0] = se->s_name = buf; + + switch (getnameinfo((void *)&sin, sizeof sin, 0, 0, buf, buflen, + strcmp(prots, "udp") ? 0 : NI_DGRAM)) { + case EAI_MEMORY: + case EAI_SYSTEM: + return ENOMEM; + default: + return ENOENT; + case 0: + break; + } + + /* A numeric port string is not a service record. */ + if (strtol(buf, 0, 10)==ntohs(port)) return ENOENT; + + *res = se; + return 0; +} diff --git a/libc-top-half/musl/src/network/getsockname.c b/libc-top-half/musl/src/network/getsockname.c new file mode 100644 index 0000000..7885fc1 --- /dev/null +++ b/libc-top-half/musl/src/network/getsockname.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int getsockname(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) +{ + return socketcall(getsockname, fd, addr, len, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/getsockopt.c b/libc-top-half/musl/src/network/getsockopt.c new file mode 100644 index 0000000..d3640d9 --- /dev/null +++ b/libc-top-half/musl/src/network/getsockopt.c @@ -0,0 +1,41 @@ +#include <sys/socket.h> +#include <sys/time.h> +#include <errno.h> +#include "syscall.h" + +int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen) +{ + long tv32[2]; + struct timeval *tv; + + int r = __socketcall(getsockopt, fd, level, optname, optval, optlen, 0); + + if (r==-ENOPROTOOPT) switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_RCVTIMEO: + case SO_SNDTIMEO: + if (SO_RCVTIMEO == SO_RCVTIMEO_OLD) break; + if (*optlen < sizeof *tv) return __syscall_ret(-EINVAL); + if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD; + if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD; + r = __socketcall(getsockopt, fd, level, optname, + tv32, (socklen_t[]){sizeof tv32}, 0); + if (r<0) break; + tv = optval; + tv->tv_sec = tv32[0]; + tv->tv_usec = tv32[1]; + *optlen = sizeof *tv; + break; + case SO_TIMESTAMP: + case SO_TIMESTAMPNS: + if (SO_TIMESTAMP == SO_TIMESTAMP_OLD) break; + if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD; + if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD; + r = __socketcall(getsockopt, fd, level, + optname, optval, optlen, 0); + break; + } + } + return __syscall_ret(r); +} diff --git a/libc-top-half/musl/src/network/h_errno.c b/libc-top-half/musl/src/network/h_errno.c new file mode 100644 index 0000000..638f771 --- /dev/null +++ b/libc-top-half/musl/src/network/h_errno.c @@ -0,0 +1,11 @@ +#include <netdb.h> +#include "pthread_impl.h" + +#undef h_errno +int h_errno; + +int *__h_errno_location(void) +{ + if (!__pthread_self()->stack) return &h_errno; + return &__pthread_self()->h_errno_val; +} diff --git a/libc-top-half/musl/src/network/herror.c b/libc-top-half/musl/src/network/herror.c new file mode 100644 index 0000000..87f8cff --- /dev/null +++ b/libc-top-half/musl/src/network/herror.c @@ -0,0 +1,8 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <netdb.h> + +void herror(const char *msg) +{ + fprintf(stderr, "%s%s%s\n", msg?msg:"", msg?": ":"", hstrerror(h_errno)); +} diff --git a/libc-top-half/musl/src/network/hstrerror.c b/libc-top-half/musl/src/network/hstrerror.c new file mode 100644 index 0000000..a4d001c --- /dev/null +++ b/libc-top-half/musl/src/network/hstrerror.c @@ -0,0 +1,18 @@ +#define _GNU_SOURCE +#include <netdb.h> +#include "locale_impl.h" + +static const char msgs[] = + "Host not found\0" + "Try again\0" + "Non-recoverable error\0" + "Address not available\0" + "\0Unknown error"; + +const char *hstrerror(int ecode) +{ + const char *s; + for (s=msgs, ecode--; ecode && *s; ecode--, s++) for (; *s; s++); + if (!*s) s++; + return LCTRANS_CUR(s); +} diff --git a/libc-top-half/musl/src/network/htonl.c b/libc-top-half/musl/src/network/htonl.c new file mode 100644 index 0000000..6622d16 --- /dev/null +++ b/libc-top-half/musl/src/network/htonl.c @@ -0,0 +1,8 @@ +#include <netinet/in.h> +#include <byteswap.h> + +uint32_t htonl(uint32_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_32(n) : n; +} diff --git a/libc-top-half/musl/src/network/htons.c b/libc-top-half/musl/src/network/htons.c new file mode 100644 index 0000000..03a3a1d --- /dev/null +++ b/libc-top-half/musl/src/network/htons.c @@ -0,0 +1,8 @@ +#include <netinet/in.h> +#include <byteswap.h> + +uint16_t htons(uint16_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_16(n) : n; +} diff --git a/libc-top-half/musl/src/network/if_freenameindex.c b/libc-top-half/musl/src/network/if_freenameindex.c new file mode 100644 index 0000000..89bafcc --- /dev/null +++ b/libc-top-half/musl/src/network/if_freenameindex.c @@ -0,0 +1,7 @@ +#include <net/if.h> +#include <stdlib.h> + +void if_freenameindex(struct if_nameindex *idx) +{ + free(idx); +} diff --git a/libc-top-half/musl/src/network/if_indextoname.c b/libc-top-half/musl/src/network/if_indextoname.c new file mode 100644 index 0000000..3b368bf --- /dev/null +++ b/libc-top-half/musl/src/network/if_indextoname.c @@ -0,0 +1,23 @@ +#define _GNU_SOURCE +#include <net/if.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <string.h> +#include <errno.h> +#include "syscall.h" + +char *if_indextoname(unsigned index, char *name) +{ + struct ifreq ifr; + int fd, r; + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) return 0; + ifr.ifr_ifindex = index; + r = ioctl(fd, SIOCGIFNAME, &ifr); + __syscall(SYS_close, fd); + if (r < 0) { + if (errno == ENODEV) errno = ENXIO; + return 0; + } + return strncpy(name, ifr.ifr_name, IF_NAMESIZE); +} diff --git a/libc-top-half/musl/src/network/if_nameindex.c b/libc-top-half/musl/src/network/if_nameindex.c new file mode 100644 index 0000000..2deaef7 --- /dev/null +++ b/libc-top-half/musl/src/network/if_nameindex.c @@ -0,0 +1,114 @@ +#define _GNU_SOURCE +#include <net/if.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include "netlink.h" + +#define IFADDRS_HASH_SIZE 64 + +struct ifnamemap { + unsigned int hash_next; + unsigned int index; + unsigned char namelen; + char name[IFNAMSIZ]; +}; + +struct ifnameindexctx { + unsigned int num, allocated, str_bytes; + struct ifnamemap *list; + unsigned int hash[IFADDRS_HASH_SIZE]; +}; + +static int netlink_msg_to_nameindex(void *pctx, struct nlmsghdr *h) +{ + struct ifnameindexctx *ctx = pctx; + struct ifnamemap *map; + struct rtattr *rta; + unsigned int i; + int index, type, namelen, bucket; + + if (h->nlmsg_type == RTM_NEWLINK) { + struct ifinfomsg *ifi = NLMSG_DATA(h); + index = ifi->ifi_index; + type = IFLA_IFNAME; + rta = NLMSG_RTA(h, sizeof(*ifi)); + } else { + struct ifaddrmsg *ifa = NLMSG_DATA(h); + index = ifa->ifa_index; + type = IFA_LABEL; + rta = NLMSG_RTA(h, sizeof(*ifa)); + } + for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != type) continue; + + namelen = RTA_DATALEN(rta) - 1; + if (namelen > IFNAMSIZ) return 0; + + /* suppress duplicates */ + bucket = index % IFADDRS_HASH_SIZE; + i = ctx->hash[bucket]; + while (i) { + map = &ctx->list[i-1]; + if (map->index == index && + map->namelen == namelen && + memcmp(map->name, RTA_DATA(rta), namelen) == 0) + return 0; + i = map->hash_next; + } + + if (ctx->num >= ctx->allocated) { + size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8; + if (a > SIZE_MAX/sizeof *map) return -1; + map = realloc(ctx->list, a * sizeof *map); + if (!map) return -1; + ctx->list = map; + ctx->allocated = a; + } + map = &ctx->list[ctx->num]; + map->index = index; + map->namelen = namelen; + memcpy(map->name, RTA_DATA(rta), namelen); + ctx->str_bytes += namelen + 1; + ctx->num++; + map->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ctx->num; + return 0; + } + return 0; +} + +struct if_nameindex *if_nameindex() +{ + struct ifnameindexctx _ctx, *ctx = &_ctx; + struct if_nameindex *ifs = 0, *d; + struct ifnamemap *s; + char *p; + int i; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + memset(ctx, 0, sizeof(*ctx)); + if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, netlink_msg_to_nameindex, ctx) < 0) goto err; + + ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes); + if (!ifs) goto err; + + p = (char*)(ifs + ctx->num + 1); + for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) { + d->if_index = s->index; + d->if_name = p; + memcpy(p, s->name, s->namelen); + p += s->namelen; + *p++ = 0; + } + d->if_index = 0; + d->if_name = 0; +err: + pthread_setcancelstate(cs, 0); + free(ctx->list); + errno = ENOBUFS; + return ifs; +} diff --git a/libc-top-half/musl/src/network/if_nametoindex.c b/libc-top-half/musl/src/network/if_nametoindex.c new file mode 100644 index 0000000..331413c --- /dev/null +++ b/libc-top-half/musl/src/network/if_nametoindex.c @@ -0,0 +1,18 @@ +#define _GNU_SOURCE +#include <net/if.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <string.h> +#include "syscall.h" + +unsigned if_nametoindex(const char *name) +{ + struct ifreq ifr; + int fd, r; + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) return 0; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + r = ioctl(fd, SIOCGIFINDEX, &ifr); + __syscall(SYS_close, fd); + return r < 0 ? 0 : ifr.ifr_ifindex; +} diff --git a/libc-top-half/musl/src/network/in6addr_any.c b/libc-top-half/musl/src/network/in6addr_any.c new file mode 100644 index 0000000..995387f --- /dev/null +++ b/libc-top-half/musl/src/network/in6addr_any.c @@ -0,0 +1,3 @@ +#include <netinet/in.h> + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; diff --git a/libc-top-half/musl/src/network/in6addr_loopback.c b/libc-top-half/musl/src/network/in6addr_loopback.c new file mode 100644 index 0000000..b96005b --- /dev/null +++ b/libc-top-half/musl/src/network/in6addr_loopback.c @@ -0,0 +1,3 @@ +#include <netinet/in.h> + +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; diff --git a/libc-top-half/musl/src/network/inet_addr.c b/libc-top-half/musl/src/network/inet_addr.c new file mode 100644 index 0000000..11ece3d --- /dev/null +++ b/libc-top-half/musl/src/network/inet_addr.c @@ -0,0 +1,10 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +in_addr_t inet_addr(const char *p) +{ + struct in_addr a; + if (!__inet_aton(p, &a)) return -1; + return a.s_addr; +} diff --git a/libc-top-half/musl/src/network/inet_aton.c b/libc-top-half/musl/src/network/inet_aton.c new file mode 100644 index 0000000..c65f7c2 --- /dev/null +++ b/libc-top-half/musl/src/network/inet_aton.c @@ -0,0 +1,41 @@ +#include <ctype.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> + +int __inet_aton(const char *s0, struct in_addr *dest) +{ + const char *s = s0; + unsigned char *d = (void *)dest; + unsigned long a[4] = { 0 }; + char *z; + int i; + + for (i=0; i<4; i++) { + a[i] = strtoul(s, &z, 0); + if (z==s || (*z && *z != '.') || !isdigit(*s)) + return 0; + if (!*z) break; + s=z+1; + } + if (i==4) return 0; + switch (i) { + case 0: + a[1] = a[0] & 0xffffff; + a[0] >>= 24; + case 1: + a[2] = a[1] & 0xffff; + a[1] >>= 16; + case 2: + a[3] = a[2] & 0xff; + a[2] >>= 8; + } + for (i=0; i<4; i++) { + if (a[i] > 255) return 0; + d[i] = a[i]; + } + return 1; +} + +weak_alias(__inet_aton, inet_aton); diff --git a/libc-top-half/musl/src/network/inet_legacy.c b/libc-top-half/musl/src/network/inet_legacy.c new file mode 100644 index 0000000..621b47b --- /dev/null +++ b/libc-top-half/musl/src/network/inet_legacy.c @@ -0,0 +1,32 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +in_addr_t inet_network(const char *p) +{ + return ntohl(inet_addr(p)); +} + +struct in_addr inet_makeaddr(in_addr_t n, in_addr_t h) +{ + if (n < 256) h |= n<<24; + else if (n < 65536) h |= n<<16; + else h |= n<<8; + return (struct in_addr){ h }; +} + +in_addr_t inet_lnaof(struct in_addr in) +{ + uint32_t h = in.s_addr; + if (h>>24 < 128) return h & 0xffffff; + if (h>>24 < 192) return h & 0xffff; + return h & 0xff; +} + +in_addr_t inet_netof(struct in_addr in) +{ + uint32_t h = in.s_addr; + if (h>>24 < 128) return h >> 24; + if (h>>24 < 192) return h >> 16; + return h >> 8; +} diff --git a/libc-top-half/musl/src/network/inet_ntoa.c b/libc-top-half/musl/src/network/inet_ntoa.c new file mode 100644 index 0000000..71411e0 --- /dev/null +++ b/libc-top-half/musl/src/network/inet_ntoa.c @@ -0,0 +1,10 @@ +#include <arpa/inet.h> +#include <stdio.h> + +char *inet_ntoa(struct in_addr in) +{ + static char buf[16]; + unsigned char *a = (void *)∈ + snprintf(buf, sizeof buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); + return buf; +} diff --git a/libc-top-half/musl/src/network/inet_ntop.c b/libc-top-half/musl/src/network/inet_ntop.c new file mode 100644 index 0000000..4bfef2c --- /dev/null +++ b/libc-top-half/musl/src/network/inet_ntop.c @@ -0,0 +1,54 @@ +#include <sys/socket.h> +#include <arpa/inet.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +const char *inet_ntop(int af, const void *restrict a0, char *restrict s, socklen_t l) +{ + const unsigned char *a = a0; + int i, j, max, best; + char buf[100]; + + switch (af) { + case AF_INET: + if (snprintf(s, l, "%d.%d.%d.%d", a[0],a[1],a[2],a[3]) < l) + return s; + break; + case AF_INET6: + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12)) + snprintf(buf, sizeof buf, + "%x:%x:%x:%x:%x:%x:%x:%x", + 256*a[0]+a[1],256*a[2]+a[3], + 256*a[4]+a[5],256*a[6]+a[7], + 256*a[8]+a[9],256*a[10]+a[11], + 256*a[12]+a[13],256*a[14]+a[15]); + else + snprintf(buf, sizeof buf, + "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", + 256*a[0]+a[1],256*a[2]+a[3], + 256*a[4]+a[5],256*a[6]+a[7], + 256*a[8]+a[9],256*a[10]+a[11], + a[12],a[13],a[14],a[15]); + /* Replace longest /(^0|:)[:0]{2,}/ with "::" */ + for (i=best=0, max=2; buf[i]; i++) { + if (i && buf[i] != ':') continue; + j = strspn(buf+i, ":0"); + if (j>max) best=i, max=j; + } + if (max>3) { + buf[best] = buf[best+1] = ':'; + memmove(buf+best+2, buf+best+max, i-best-max+1); + } + if (strlen(buf) < l) { + strcpy(s, buf); + return s; + } + break; + default: + errno = EAFNOSUPPORT; + return 0; + } + errno = ENOSPC; + return 0; +} diff --git a/libc-top-half/musl/src/network/inet_pton.c b/libc-top-half/musl/src/network/inet_pton.c new file mode 100644 index 0000000..d36c368 --- /dev/null +++ b/libc-top-half/musl/src/network/inet_pton.c @@ -0,0 +1,71 @@ +#include <sys/socket.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> + +static int hexval(unsigned c) +{ + if (c-'0'<10) return c-'0'; + c |= 32; + if (c-'a'<6) return c-'a'+10; + return -1; +} + +int inet_pton(int af, const char *restrict s, void *restrict a0) +{ + uint16_t ip[8]; + unsigned char *a = a0; + int i, j, v, d, brk=-1, need_v4=0; + + if (af==AF_INET) { + for (i=0; i<4; i++) { + for (v=j=0; j<3 && isdigit(s[j]); j++) + v = 10*v + s[j]-'0'; + if (j==0 || (j>1 && s[0]=='0') || v>255) return 0; + a[i] = v; + if (s[j]==0 && i==3) return 1; + if (s[j]!='.') return 0; + s += j+1; + } + return 0; + } else if (af!=AF_INET6) { + errno = EAFNOSUPPORT; + return -1; + } + + if (*s==':' && *++s!=':') return 0; + + for (i=0; ; i++) { + if (s[0]==':' && brk<0) { + brk=i; + ip[i&7]=0; + if (!*++s) break; + if (i==7) return 0; + continue; + } + for (v=j=0; j<4 && (d=hexval(s[j]))>=0; j++) + v=16*v+d; + if (j==0) return 0; + ip[i&7] = v; + if (!s[j] && (brk>=0 || i==7)) break; + if (i==7) return 0; + if (s[j]!=':') { + if (s[j]!='.' || (i<6 && brk<0)) return 0; + need_v4=1; + i++; + break; + } + s += j+1; + } + if (brk>=0) { + memmove(ip+brk+7-i, ip+brk, 2*(i+1-brk)); + for (j=0; j<7-i; j++) ip[brk+j] = 0; + } + for (j=0; j<8; j++) { + *a++ = ip[j]>>8; + *a++ = ip[j]; + } + if (need_v4 && inet_pton(AF_INET, (void *)s, a-4) <= 0) return 0; + return 1; +} diff --git a/libc-top-half/musl/src/network/listen.c b/libc-top-half/musl/src/network/listen.c new file mode 100644 index 0000000..f84ad03 --- /dev/null +++ b/libc-top-half/musl/src/network/listen.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int listen(int fd, int backlog) +{ + return socketcall(listen, fd, backlog, 0, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/lookup.h b/libc-top-half/musl/src/network/lookup.h new file mode 100644 index 0000000..ef66272 --- /dev/null +++ b/libc-top-half/musl/src/network/lookup.h @@ -0,0 +1,55 @@ +#ifndef LOOKUP_H +#define LOOKUP_H + +#include <stdint.h> +#include <stddef.h> +#include <features.h> +#include <netinet/in.h> +#include <netdb.h> + +struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + volatile int lock[1]; + short slot, ref; +}; + +struct address { + int family; + unsigned scopeid; + uint8_t addr[16]; + int sortkey; +}; + +struct service { + uint16_t port; + unsigned char proto, socktype; +}; + +#define MAXNS 3 + +struct resolvconf { + struct address ns[MAXNS]; + unsigned nns, attempts, ndots; + unsigned timeout; +}; + +/* The limit of 48 results is a non-sharp bound on the number of addresses + * that can fit in one 512-byte DNS packet full of v4 results and a second + * packet full of v6 results. Due to headers, the actual limit is lower. */ +#define MAXADDRS 48 +#define MAXSERVS 2 + +hidden int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags); +hidden int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags); +hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, int family); + +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 *); + +#endif diff --git a/libc-top-half/musl/src/network/lookup_ipliteral.c b/libc-top-half/musl/src/network/lookup_ipliteral.c new file mode 100644 index 0000000..2fddab7 --- /dev/null +++ b/libc-top-half/musl/src/network/lookup_ipliteral.c @@ -0,0 +1,55 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "lookup.h" + +int __lookup_ipliteral(struct address buf[static 1], const char *name, int family) +{ + struct in_addr a4; + struct in6_addr a6; + if (__inet_aton(name, &a4) > 0) { + if (family == AF_INET6) /* wrong family */ + return EAI_NONAME; + memcpy(&buf[0].addr, &a4, sizeof a4); + buf[0].family = AF_INET; + buf[0].scopeid = 0; + return 1; + } + + char tmp[64]; + char *p = strchr(name, '%'), *z; + unsigned long long scopeid = 0; + if (p && p-name < 64) { + memcpy(tmp, name, p-name); + tmp[p-name] = 0; + name = tmp; + } + + if (inet_pton(AF_INET6, name, &a6) <= 0) + return 0; + if (family == AF_INET) /* wrong family */ + return EAI_NONAME; + + memcpy(&buf[0].addr, &a6, sizeof a6); + buf[0].family = AF_INET6; + if (p) { + if (isdigit(*++p)) scopeid = strtoull(p, &z, 10); + else z = p-1; + if (*z) { + if (!IN6_IS_ADDR_LINKLOCAL(&a6) && + !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) + return EAI_NONAME; + scopeid = if_nametoindex(p); + if (!scopeid) return EAI_NONAME; + } + if (scopeid > UINT_MAX) return EAI_NONAME; + } + buf[0].scopeid = scopeid; + return 1; +} diff --git a/libc-top-half/musl/src/network/lookup_name.c b/libc-top-half/musl/src/network/lookup_name.c new file mode 100644 index 0000000..aa558c1 --- /dev/null +++ b/libc-top-half/musl/src/network/lookup_name.c @@ -0,0 +1,425 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <pthread.h> +#include <errno.h> +#include <resolv.h> +#include "lookup.h" +#include "stdio_impl.h" +#include "syscall.h" + +static int is_valid_hostname(const char *host) +{ + const unsigned char *s; + if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0; + for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); + return !*s; +} + +static int name_from_null(struct address buf[static 2], const char *name, int family, int flags) +{ + int cnt = 0; + if (name) return 0; + if (flags & AI_PASSIVE) { + if (family != AF_INET6) + buf[cnt++] = (struct address){ .family = AF_INET }; + if (family != AF_INET) + buf[cnt++] = (struct address){ .family = AF_INET6 }; + } else { + if (family != AF_INET6) + buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } }; + if (family != AF_INET) + buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } }; + } + return cnt; +} + +static int name_from_numeric(struct address buf[static 1], const char *name, int family) +{ + return __lookup_ipliteral(buf, name, family); +} + +static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) +{ + char line[512]; + size_t l = strlen(name); + int cnt = 0, badfam = 0, have_canon = 0; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return 0; + default: + return EAI_SYSTEM; + } + while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { + char *p, *z; + + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + for(p=line+1; (p=strstr(p, name)) && + (!isspace(p[-1]) || !isspace(p[l])); p++); + if (!p) continue; + + /* Isolate IP address to parse */ + for (p=line; *p && !isspace(*p); p++); + *p++ = 0; + switch (name_from_numeric(buf+cnt, line, family)) { + case 1: + cnt++; + break; + case 0: + continue; + default: + badfam = EAI_NONAME; + break; + } + + if (have_canon) continue; + + /* Extract first name as canonical name */ + for (; *p && isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z = 0; + if (is_valid_hostname(p)) { + have_canon = 1; + memcpy(canon, p, z-p+1); + } + } + __fclose_ca(f); + return cnt ? cnt : badfam; +} + +struct dpc_ctx { + struct address *addrs; + char *canon; + int cnt; +}; + +#define RR_A 1 +#define RR_CNAME 5 +#define RR_AAAA 28 + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +{ + char tmp[256]; + struct dpc_ctx *ctx = c; + if (ctx->cnt >= MAXADDRS) return -1; + switch (rr) { + case RR_A: + if (len != 4) return -1; + ctx->addrs[ctx->cnt].family = AF_INET; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); + break; + case RR_AAAA: + if (len != 16) return -1; + ctx->addrs[ctx->cnt].family = AF_INET6; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); + break; + case RR_CNAME: + if (__dn_expand(packet, (const unsigned char *)packet + 512, + data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) + strcpy(ctx->canon, tmp); + break; + } + return 0; +} + +static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf) +{ + unsigned char qbuf[2][280], abuf[2][512]; + const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; + unsigned char *ap[2] = { abuf[0], abuf[1] }; + int qlens[2], alens[2]; + int i, nq = 0; + struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; + static const struct { int af; int rr; } afrr[2] = { + { .af = AF_INET6, .rr = RR_A }, + { .af = AF_INET, .rr = RR_AAAA }, + }; + + for (i=0; i<2; i++) { + if (family != afrr[i].af) { + qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr, + 0, 0, 0, qbuf[nq], sizeof *qbuf); + if (qlens[nq] == -1) + return EAI_NONAME; + qbuf[nq][3] = 0; /* don't need AD flag */ + nq++; + } + } + + if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) + return EAI_SYSTEM; + + for (i=0; i<nq; i++) { + if (alens[i] < 4 || (abuf[i][3] & 15) == 2) return EAI_AGAIN; + if ((abuf[i][3] & 15) == 3) return 0; + if ((abuf[i][3] & 15) != 0) return EAI_FAIL; + } + + for (i=0; i<nq; i++) + __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); + + if (ctx.cnt) return ctx.cnt; + return EAI_NONAME; +} + +static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) +{ + char search[256]; + struct resolvconf conf; + size_t l, dots; + char *p, *z; + + if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; + + /* Count dots, suppress search when >=ndots or name ends in + * a dot, which is an explicit request for global scope. */ + for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; + if (dots >= conf.ndots || name[l-1]=='.') *search = 0; + + /* Strip final dot for canon, fail if multiple trailing dots. */ + if (name[l-1]=='.') l--; + if (!l || name[l-1]=='.') return EAI_NONAME; + + /* This can never happen; the caller already checked length. */ + if (l >= 256) return EAI_NONAME; + + /* Name with search domain appended is setup in canon[]. This both + * provides the desired default canonical name (if the requested + * name is not a CNAME record) and serves as a buffer for passing + * the full requested name to name_from_dns. */ + memcpy(canon, name, l); + canon[l] = '.'; + + for (p=search; *p; p=z) { + for (; isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + if (z==p) break; + if (z-p < 256 - l - 1) { + memcpy(canon+l+1, p, z-p); + canon[z-p+1+l] = 0; + int cnt = name_from_dns(buf, canon, canon, family, &conf); + if (cnt) return cnt; + } + } + + canon[l] = 0; + return name_from_dns(buf, canon, name, family, &conf); +} + +static const struct policy { + unsigned char addr[16]; + unsigned char len, mask; + unsigned char prec, label; +} defpolicy[] = { + { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 }, + { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 }, + { "\x20\2", 1, 0xff, 30, 2 }, + { "\x20\1", 3, 0xff, 5, 5 }, + { "\xfc", 0, 0xfe, 3, 13 }, +#if 0 + /* These are deprecated and/or returned to the address + * pool, so despite the RFC, treating them as special + * is probably wrong. */ + { "", 11, 0xff, 1, 3 }, + { "\xfe\xc0", 1, 0xc0, 1, 11 }, + { "\x3f\xfe", 1, 0xff, 1, 12 }, +#endif + /* Last rule must match all addresses to stop loop. */ + { "", 0, 0, 40, 1 }, +}; + +static const struct policy *policyof(const struct in6_addr *a) +{ + int i; + for (i=0; ; i++) { + if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) + continue; + if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) + != defpolicy[i].addr[defpolicy[i].len]) + continue; + return defpolicy+i; + } +} + +static int labelof(const struct in6_addr *a) +{ + return policyof(a)->label; +} + +static int scopeof(const struct in6_addr *a) +{ + if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15; + if (IN6_IS_ADDR_LINKLOCAL(a)) return 2; + if (IN6_IS_ADDR_LOOPBACK(a)) return 2; + if (IN6_IS_ADDR_SITELOCAL(a)) return 5; + return 14; +} + +static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d) +{ + /* FIXME: The common prefix length should be limited to no greater + * than the nominal length of the prefix portion of the source + * address. However the definition of the source prefix length is + * not clear and thus this limiting is not yet implemented. */ + unsigned i; + for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++); + return i; +} + +#define DAS_USABLE 0x40000000 +#define DAS_MATCHINGSCOPE 0x20000000 +#define DAS_MATCHINGLABEL 0x10000000 +#define DAS_PREC_SHIFT 20 +#define DAS_SCOPE_SHIFT 16 +#define DAS_PREFIX_SHIFT 8 +#define DAS_ORDER_SHIFT 0 + +static int addrcmp(const void *_a, const void *_b) +{ + const struct address *a = _a, *b = _b; + return b->sortkey - a->sortkey; +} + +int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags) +{ + int cnt = 0, i, j; + + *canon = 0; + if (name) { + /* reject empty name and check len so it fits into temp bufs */ + size_t l = strnlen(name, 255); + if (l-1 >= 254) + return EAI_NONAME; + memcpy(canon, name, l+1); + } + + /* Procedurally, a request for v6 addresses with the v4-mapped + * flag set is like a request for unspecified family, followed + * by filtering of the results. */ + if (flags & AI_V4MAPPED) { + if (family == AF_INET6) family = AF_UNSPEC; + else flags -= AI_V4MAPPED; + } + + /* Try each backend until there's at least one result. */ + cnt = name_from_null(buf, name, family, flags); + if (!cnt) cnt = name_from_numeric(buf, name, family); + if (!cnt && !(flags & AI_NUMERICHOST)) { + cnt = name_from_hosts(buf, canon, name, family); + if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); + } + if (cnt<=0) return cnt ? cnt : EAI_NONAME; + + /* Filter/transform results for v4-mapped lookup, if requested. */ + if (flags & AI_V4MAPPED) { + if (!(flags & AI_ALL)) { + /* If any v6 results exist, remove v4 results. */ + for (i=0; i<cnt && buf[i].family != AF_INET6; i++); + if (i<cnt) { + for (j=0; i<cnt; i++) { + if (buf[i].family == AF_INET6) + buf[j++] = buf[i]; + } + cnt = i = j; + } + } + /* Translate any remaining v4 results to v6 */ + for (i=0; i<cnt; i++) { + if (buf[i].family != AF_INET) continue; + memcpy(buf[i].addr+12, buf[i].addr, 4); + memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + buf[i].family = AF_INET6; + } + } + + /* No further processing is needed if there are fewer than 2 + * results or if there are only IPv4 results. */ + if (cnt<2 || family==AF_INET) return cnt; + for (i=0; i<cnt; i++) if (buf[i].family != AF_INET) break; + if (i==cnt) return cnt; + + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + /* The following implements a subset of RFC 3484/6724 destination + * address selection by generating a single 31-bit sort key for + * each address. Rules 3, 4, and 7 are omitted for having + * excessive runtime and code size cost and dubious benefit. + * So far the label/precedence table cannot be customized. */ + for (i=0; i<cnt; i++) { + int family = buf[i].family; + int key = 0; + struct sockaddr_in6 sa6 = { 0 }, da6 = { + .sin6_family = AF_INET6, + .sin6_scope_id = buf[i].scopeid, + .sin6_port = 65535 + }; + struct sockaddr_in sa4 = { 0 }, da4 = { + .sin_family = AF_INET, + .sin_port = 65535 + }; + void *sa, *da; + socklen_t salen, dalen; + if (family == AF_INET6) { + memcpy(da6.sin6_addr.s6_addr, buf[i].addr, 16); + da = &da6; dalen = sizeof da6; + sa = &sa6; salen = sizeof sa6; + } else { + memcpy(sa6.sin6_addr.s6_addr, + "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4); + memcpy(da6.sin6_addr.s6_addr, + "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4); + memcpy(&da4.sin_addr, buf[i].addr, 4); + da = &da4; dalen = sizeof da4; + sa = &sa4; salen = sizeof sa4; + } + const struct policy *dpolicy = policyof(&da6.sin6_addr); + int dscope = scopeof(&da6.sin6_addr); + int dlabel = dpolicy->label; + int dprec = dpolicy->prec; + int prefixlen = 0; + int fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP); + if (fd >= 0) { + if (!connect(fd, da, dalen)) { + key |= DAS_USABLE; + if (!getsockname(fd, sa, &salen)) { + if (family == AF_INET) memcpy( + sa6.sin6_addr.s6_addr+12, + &sa4.sin_addr, 4); + if (dscope == scopeof(&sa6.sin6_addr)) + key |= DAS_MATCHINGSCOPE; + if (dlabel == labelof(&sa6.sin6_addr)) + key |= DAS_MATCHINGLABEL; + prefixlen = prefixmatch(&sa6.sin6_addr, + &da6.sin6_addr); + } + } + close(fd); + } + key |= dprec << DAS_PREC_SHIFT; + key |= (15-dscope) << DAS_SCOPE_SHIFT; + key |= prefixlen << DAS_PREFIX_SHIFT; + key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; + buf[i].sortkey = key; + } + qsort(buf, cnt, sizeof *buf, addrcmp); + + pthread_setcancelstate(cs, 0); + + return cnt; +} diff --git a/libc-top-half/musl/src/network/lookup_serv.c b/libc-top-half/musl/src/network/lookup_serv.c new file mode 100644 index 0000000..ae38277 --- /dev/null +++ b/libc-top-half/musl/src/network/lookup_serv.c @@ -0,0 +1,114 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include "lookup.h" +#include "stdio_impl.h" + +int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags) +{ + char line[128]; + int cnt = 0; + char *p, *z = ""; + unsigned long port = 0; + + switch (socktype) { + case SOCK_STREAM: + switch (proto) { + case 0: + proto = IPPROTO_TCP; + case IPPROTO_TCP: + break; + default: + return EAI_SERVICE; + } + break; + case SOCK_DGRAM: + switch (proto) { + case 0: + proto = IPPROTO_UDP; + case IPPROTO_UDP: + break; + default: + return EAI_SERVICE; + } + case 0: + break; + default: + if (name) return EAI_SERVICE; + buf[0].port = 0; + buf[0].proto = proto; + buf[0].socktype = socktype; + return 1; + } + + if (name) { + if (!*name) return EAI_SERVICE; + port = strtoul(name, &z, 10); + } + if (!*z) { + if (port > 65535) return EAI_SERVICE; + if (proto != IPPROTO_UDP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + if (proto != IPPROTO_TCP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + return cnt; + } + + if (flags & AI_NUMERICSERV) return EAI_NONAME; + + size_t l = strlen(name); + + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return EAI_SERVICE; + default: + return EAI_SYSTEM; + } + + while (fgets(line, sizeof line, f) && cnt < MAXSERVS) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + /* Find service name */ + for(p=line; (p=strstr(p, name)); p++) { + if (p>line && !isspace(p[-1])) continue; + if (p[l] && !isspace(p[l])) continue; + break; + } + if (!p) continue; + + /* Skip past canonical name at beginning of line */ + for (p=line; *p && !isspace(*p); p++); + + port = strtoul(p, &z, 10); + if (port > 65535 || z==p) continue; + if (!strncmp(z, "/udp", 4)) { + if (proto == IPPROTO_TCP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + if (!strncmp(z, "/tcp", 4)) { + if (proto == IPPROTO_UDP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + } + __fclose_ca(f); + return cnt > 0 ? cnt : EAI_SERVICE; +} diff --git a/libc-top-half/musl/src/network/netlink.c b/libc-top-half/musl/src/network/netlink.c new file mode 100644 index 0000000..94dba7f --- /dev/null +++ b/libc-top-half/musl/src/network/netlink.c @@ -0,0 +1,52 @@ +#include <errno.h> +#include <string.h> +#include <syscall.h> +#include <sys/socket.h> +#include "netlink.h" + +static int __netlink_enumerate(int fd, unsigned int seq, int type, int af, + int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + struct nlmsghdr *h; + union { + uint8_t buf[8192]; + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct nlmsghdr reply; + } u; + int r, ret; + + memset(&u.req, 0, sizeof(u.req)); + u.req.nlh.nlmsg_len = sizeof(u.req); + u.req.nlh.nlmsg_type = type; + u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + u.req.nlh.nlmsg_seq = seq; + u.req.g.rtgen_family = af; + r = send(fd, &u.req, sizeof(u.req), 0); + if (r < 0) return r; + + while (1) { + r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); + if (r <= 0) return -1; + for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) { + if (h->nlmsg_type == NLMSG_DONE) return 0; + if (h->nlmsg_type == NLMSG_ERROR) return -1; + ret = cb(ctx, h); + if (ret) return ret; + } + } +} + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + int fd, r; + + fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE); + if (fd < 0) return -1; + r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx); + if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx); + __syscall(SYS_close,fd); + return r; +} diff --git a/libc-top-half/musl/src/network/netlink.h b/libc-top-half/musl/src/network/netlink.h new file mode 100644 index 0000000..38acb17 --- /dev/null +++ b/libc-top-half/musl/src/network/netlink.h @@ -0,0 +1,94 @@ +#include <stdint.h> + +/* linux/netlink.h */ + +#define NETLINK_ROUTE 0 + +struct nlmsghdr { + uint32_t nlmsg_len; + uint16_t nlmsg_type; + uint16_t nlmsg_flags; + uint32_t nlmsg_seq; + uint32_t nlmsg_pid; +}; + +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 + +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +#define NLMSG_NOOP 0x1 +#define NLMSG_ERROR 0x2 +#define NLMSG_DONE 0x3 +#define NLMSG_OVERRUN 0x4 + +/* linux/rtnetlink.h */ + +#define RTM_NEWLINK 16 +#define RTM_GETLINK 18 +#define RTM_NEWADDR 20 +#define RTM_GETADDR 22 + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; + int ifi_index; + unsigned ifi_flags; + unsigned ifi_change; +}; + +/* linux/if_link.h */ + +#define IFLA_ADDRESS 1 +#define IFLA_BROADCAST 2 +#define IFLA_IFNAME 3 +#define IFLA_STATS 7 + +/* linux/if_addr.h */ + +struct ifaddrmsg { + uint8_t ifa_family; + uint8_t ifa_prefixlen; + uint8_t ifa_flags; + uint8_t ifa_scope; + uint32_t ifa_index; +}; + +#define IFA_ADDRESS 1 +#define IFA_LOCAL 2 +#define IFA_LABEL 3 +#define IFA_BROADCAST 4 + +/* musl */ + +#define NETLINK_ALIGN(len) (((len)+3) & ~3) +#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr))) +#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr)) +#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len) +#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len)) +#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr)) + +#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr))) +#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr)) +#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len) +#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len)) +#define RTA_OK(nlh,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr)) + +#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len))) +#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh)) + +hidden int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx); diff --git a/libc-top-half/musl/src/network/netname.c b/libc-top-half/musl/src/network/netname.c new file mode 100644 index 0000000..ba6e665 --- /dev/null +++ b/libc-top-half/musl/src/network/netname.c @@ -0,0 +1,12 @@ +#include <netdb.h> + +struct netent *getnetbyaddr(uint32_t net, int type) +{ + return 0; +} + +struct netent *getnetbyname(const char *name) +{ + return 0; +} + diff --git a/libc-top-half/musl/src/network/ns_parse.c b/libc-top-half/musl/src/network/ns_parse.c new file mode 100644 index 0000000..d01da47 --- /dev/null +++ b/libc-top-half/musl/src/network/ns_parse.c @@ -0,0 +1,171 @@ +#define _BSD_SOURCE +#include <errno.h> +#include <stddef.h> +#include <resolv.h> +#include <arpa/nameser.h> + +const struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, + { 0x7800, 11 }, + { 0x0400, 10 }, + { 0x0200, 9 }, + { 0x0100, 8 }, + { 0x0080, 7 }, + { 0x0040, 6 }, + { 0x0020, 5 }, + { 0x0010, 4 }, + { 0x000f, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, +}; + +unsigned ns_get16(const unsigned char *cp) +{ + return cp[0]<<8 | cp[1]; +} + +unsigned long ns_get32(const unsigned char *cp) +{ + return (unsigned)cp[0]<<24 | cp[1]<<16 | cp[2]<<8 | cp[3]; +} + +void ns_put16(unsigned s, unsigned char *cp) +{ + *cp++ = s>>8; + *cp++ = s; +} + +void ns_put32(unsigned long l, unsigned char *cp) +{ + *cp++ = l>>24; + *cp++ = l>>16; + *cp++ = l>>8; + *cp++ = l; +} + +int ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle) +{ + int i, r; + + handle->_msg = msg; + handle->_eom = msg + msglen; + if (msglen < (2 + ns_s_max) * NS_INT16SZ) goto bad; + NS_GET16(handle->_id, msg); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) NS_GET16(handle->_counts[i], msg); + for (i = 0; i < ns_s_max; i++) { + if (handle->_counts[i]) { + handle->_sections[i] = msg; + r = ns_skiprr(msg, handle->_eom, i, handle->_counts[i]); + if (r < 0) return -1; + msg += r; + } else { + handle->_sections[i] = NULL; + } + } + if (msg != handle->_eom) goto bad; + handle->_sect = ns_s_max; + handle->_rrnum = -1; + handle->_msg_ptr = NULL; + return 0; +bad: + errno = EMSGSIZE; + return -1; +} + +int ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count) +{ + const unsigned char *p = ptr; + int r; + + while (count--) { + r = dn_skipname(p, eom); + if (r < 0) goto bad; + if (r + 2 * NS_INT16SZ > eom - p) goto bad; + p += r + 2 * NS_INT16SZ; + if (section != ns_s_qd) { + if (NS_INT32SZ + NS_INT16SZ > eom - p) goto bad; + p += NS_INT32SZ; + NS_GET16(r, p); + if (r > eom - p) goto bad; + p += r; + } + } + return p - ptr; +bad: + errno = EMSGSIZE; + return -1; +} + +int ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) +{ + int r; + + if (section < 0 || section >= ns_s_max) goto bad; + if (section != handle->_sect) { + handle->_sect = section; + handle->_rrnum = 0; + handle->_msg_ptr = handle->_sections[section]; + } + if (rrnum == -1) rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[section]) goto bad; + if (rrnum < handle->_rrnum) { + handle->_rrnum = 0; + handle->_msg_ptr = handle->_sections[section]; + } + if (rrnum > handle->_rrnum) { + r = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum); + if (r < 0) return -1; + handle->_msg_ptr += r; + handle->_rrnum = rrnum; + } + r = ns_name_uncompress(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (r < 0) return -1; + handle->_msg_ptr += r; + if (2 * NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size; + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section != ns_s_qd) { + if (NS_INT32SZ + NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size; + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (rr->rdlength > handle->_eom - handle->_msg_ptr) goto size; + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } else { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } + handle->_rrnum++; + if (handle->_rrnum > handle->_counts[section]) { + handle->_sect = section + 1; + if (handle->_sect == ns_s_max) { + handle->_rrnum = -1; + handle->_msg_ptr = NULL; + } else { + handle->_rrnum = 0; + } + } + return 0; +bad: + errno = ENODEV; + return -1; +size: + errno = EMSGSIZE; + return -1; +} + +int ns_name_uncompress(const unsigned char *msg, const unsigned char *eom, + const unsigned char *src, char *dst, size_t dstsiz) +{ + int r; + r = dn_expand(msg, eom, src, dst, dstsiz); + if (r < 0) errno = EMSGSIZE; + return r; +} + diff --git a/libc-top-half/musl/src/network/ntohl.c b/libc-top-half/musl/src/network/ntohl.c new file mode 100644 index 0000000..d6fce45 --- /dev/null +++ b/libc-top-half/musl/src/network/ntohl.c @@ -0,0 +1,8 @@ +#include <netinet/in.h> +#include <byteswap.h> + +uint32_t ntohl(uint32_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_32(n) : n; +} diff --git a/libc-top-half/musl/src/network/ntohs.c b/libc-top-half/musl/src/network/ntohs.c new file mode 100644 index 0000000..745cef4 --- /dev/null +++ b/libc-top-half/musl/src/network/ntohs.c @@ -0,0 +1,8 @@ +#include <netinet/in.h> +#include <byteswap.h> + +uint16_t ntohs(uint16_t n) +{ + union { int i; char c; } u = { 1 }; + return u.c ? bswap_16(n) : n; +} diff --git a/libc-top-half/musl/src/network/proto.c b/libc-top-half/musl/src/network/proto.c new file mode 100644 index 0000000..c4fd34e --- /dev/null +++ b/libc-top-half/musl/src/network/proto.c @@ -0,0 +1,84 @@ +#include <netdb.h> +#include <string.h> + +/* do we really need all these?? */ + +static int idx; +static const unsigned char protos[] = { + "\000ip\0" + "\001icmp\0" + "\002igmp\0" + "\003ggp\0" + "\004ipencap\0" + "\005st\0" + "\006tcp\0" + "\010egp\0" + "\014pup\0" + "\021udp\0" + "\024hmp\0" + "\026xns-idp\0" + "\033rdp\0" + "\035iso-tp4\0" + "\044xtp\0" + "\045ddp\0" + "\046idpr-cmtp\0" + "\051ipv6\0" + "\053ipv6-route\0" + "\054ipv6-frag\0" + "\055idrp\0" + "\056rsvp\0" + "\057gre\0" + "\062esp\0" + "\063ah\0" + "\071skip\0" + "\072ipv6-icmp\0" + "\073ipv6-nonxt\0" + "\074ipv6-opts\0" + "\111rspf\0" + "\121vmtp\0" + "\131ospf\0" + "\136ipip\0" + "\142encap\0" + "\147pim\0" + "\377raw" +}; + +void endprotoent(void) +{ + idx = 0; +} + +void setprotoent(int stayopen) +{ + idx = 0; +} + +struct protoent *getprotoent(void) +{ + static struct protoent p; + static const char *aliases; + if (idx >= sizeof protos) return NULL; + p.p_proto = protos[idx]; + p.p_name = (char *)&protos[idx+1]; + p.p_aliases = (char **)&aliases; + idx += strlen(p.p_name) + 2; + return &p; +} + +struct protoent *getprotobyname(const char *name) +{ + struct protoent *p; + endprotoent(); + do p = getprotoent(); + while (p && strcmp(name, p->p_name)); + return p; +} + +struct protoent *getprotobynumber(int num) +{ + struct protoent *p; + endprotoent(); + do p = getprotoent(); + while (p && p->p_proto != num); + return p; +} diff --git a/libc-top-half/musl/src/network/recv.c b/libc-top-half/musl/src/network/recv.c new file mode 100644 index 0000000..5970048 --- /dev/null +++ b/libc-top-half/musl/src/network/recv.c @@ -0,0 +1,6 @@ +#include <sys/socket.h> + +ssize_t recv(int fd, void *buf, size_t len, int flags) +{ + return recvfrom(fd, buf, len, flags, 0, 0); +} diff --git a/libc-top-half/musl/src/network/recvfrom.c b/libc-top-half/musl/src/network/recvfrom.c new file mode 100644 index 0000000..6191166 --- /dev/null +++ b/libc-top-half/musl/src/network/recvfrom.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +ssize_t recvfrom(int fd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict addr, socklen_t *restrict alen) +{ + return socketcall_cp(recvfrom, fd, buf, len, flags, addr, alen); +} diff --git a/libc-top-half/musl/src/network/recvmmsg.c b/libc-top-half/musl/src/network/recvmmsg.c new file mode 100644 index 0000000..2978e2f --- /dev/null +++ b/libc-top-half/musl/src/network/recvmmsg.c @@ -0,0 +1,39 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <limits.h> +#include <errno.h> +#include <time.h> +#include "syscall.h" + +#define IS32BIT(x) !((x)+0x80000000ULL>>32) +#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) + +hidden void __convert_scm_timestamps(struct msghdr *, socklen_t); + +int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout) +{ +#if LONG_MAX > INT_MAX + struct mmsghdr *mh = msgvec; + unsigned int i; + for (i = vlen; i; i--, mh++) + mh->msg_hdr.__pad1 = mh->msg_hdr.__pad2 = 0; +#endif +#ifdef SYS_recvmmsg_time64 + time_t s = timeout ? timeout->tv_sec : 0; + long ns = timeout ? timeout->tv_nsec : 0; + int r = __syscall_cp(SYS_recvmmsg_time64, fd, msgvec, vlen, flags, + timeout ? ((long long[]){s, ns}) : 0); + if (SYS_recvmmsg == SYS_recvmmsg_time64 || r!=-ENOSYS) + return __syscall_ret(r); + if (vlen > IOV_MAX) vlen = IOV_MAX; + socklen_t csize[vlen]; + for (int i=0; i<vlen; i++) csize[i] = msgvec[i].msg_hdr.msg_controllen; + r = __syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, + timeout ? ((long[]){CLAMP(s), ns}) : 0); + for (int i=0; i<r; i++) + __convert_scm_timestamps(&msgvec[i].msg_hdr, csize[i]); + return __syscall_ret(r); +#else + return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout); +#endif +} diff --git a/libc-top-half/musl/src/network/recvmsg.c b/libc-top-half/musl/src/network/recvmsg.c new file mode 100644 index 0000000..0364162 --- /dev/null +++ b/libc-top-half/musl/src/network/recvmsg.c @@ -0,0 +1,68 @@ +#include <sys/socket.h> +#include <limits.h> +#include <time.h> +#include <sys/time.h> +#include <string.h> +#include "syscall.h" + +hidden void __convert_scm_timestamps(struct msghdr *, socklen_t); + +void __convert_scm_timestamps(struct msghdr *msg, socklen_t csize) +{ + if (SCM_TIMESTAMP == SCM_TIMESTAMP_OLD) return; + if (!msg->msg_control || !msg->msg_controllen) return; + + struct cmsghdr *cmsg, *last=0; + long tmp; + long long tvts[2]; + int type = 0; + + for (cmsg=CMSG_FIRSTHDR(msg); cmsg; cmsg=CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level==SOL_SOCKET) switch (cmsg->cmsg_type) { + case SCM_TIMESTAMP_OLD: + if (type) break; + type = SCM_TIMESTAMP; + goto common; + case SCM_TIMESTAMPNS_OLD: + type = SCM_TIMESTAMPNS; + common: + memcpy(&tmp, CMSG_DATA(cmsg), sizeof tmp); + tvts[0] = tmp; + memcpy(&tmp, CMSG_DATA(cmsg) + sizeof tmp, sizeof tmp); + tvts[1] = tmp; + break; + } + last = cmsg; + } + if (!last || !type) return; + if (CMSG_SPACE(sizeof tvts) > csize-msg->msg_controllen) { + msg->msg_flags |= MSG_CTRUNC; + return; + } + msg->msg_controllen += CMSG_SPACE(sizeof tvts); + cmsg = CMSG_NXTHDR(msg, last); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = type; + cmsg->cmsg_len = CMSG_LEN(sizeof tvts); + memcpy(CMSG_DATA(cmsg), &tvts, sizeof tvts); +} + +ssize_t recvmsg(int fd, struct msghdr *msg, int flags) +{ + ssize_t r; + socklen_t orig_controllen = msg->msg_controllen; +#if LONG_MAX > INT_MAX + struct msghdr h, *orig = msg; + if (msg) { + h = *msg; + h.__pad1 = h.__pad2 = 0; + msg = &h; + } +#endif + r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0); + if (r >= 0) __convert_scm_timestamps(msg, orig_controllen); +#if LONG_MAX > INT_MAX + if (orig) *orig = h; +#endif + return r; +} diff --git a/libc-top-half/musl/src/network/res_init.c b/libc-top-half/musl/src/network/res_init.c new file mode 100644 index 0000000..5dba9df --- /dev/null +++ b/libc-top-half/musl/src/network/res_init.c @@ -0,0 +1,6 @@ +#include <resolv.h> + +int res_init() +{ + return 0; +} diff --git a/libc-top-half/musl/src/network/res_mkquery.c b/libc-top-half/musl/src/network/res_mkquery.c new file mode 100644 index 0000000..33f50cb --- /dev/null +++ b/libc-top-half/musl/src/network/res_mkquery.c @@ -0,0 +1,44 @@ +#include <resolv.h> +#include <string.h> +#include <time.h> + +int __res_mkquery(int op, const char *dname, int class, int type, + const unsigned char *data, int datalen, + const unsigned char *newrr, unsigned char *buf, int buflen) +{ + int id, i, j; + unsigned char q[280]; + struct timespec ts; + size_t l = strnlen(dname, 255); + int n; + + if (l && dname[l-1]=='.') l--; + n = 17+l+!!l; + if (l>253 || buflen<n || op>15u || class>255u || type>255u) + return -1; + + /* Construct query template - ID will be filled later */ + memset(q, 0, n); + q[2] = op*8 + 1; + q[3] = 32; /* AD */ + q[5] = 1; + memcpy((char *)q+13, dname, l); + for (i=13; q[i]; i=j+1) { + for (j=i; q[j] && q[j] != '.'; j++); + if (j-i-1u > 62u) return -1; + q[i-1] = j-i; + } + q[i+1] = type; + q[i+3] = class; + + /* Make a reasonably unpredictable id */ + clock_gettime(CLOCK_REALTIME, &ts); + id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff; + q[0] = id/256; + q[1] = id; + + memcpy(buf, q, n); + return n; +} + +weak_alias(__res_mkquery, res_mkquery); diff --git a/libc-top-half/musl/src/network/res_msend.c b/libc-top-half/musl/src/network/res_msend.c new file mode 100644 index 0000000..3e01800 --- /dev/null +++ b/libc-top-half/musl/src/network/res_msend.c @@ -0,0 +1,188 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <stdint.h> +#include <string.h> +#include <poll.h> +#include <time.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include "stdio_impl.h" +#include "syscall.h" +#include "lookup.h" + +static void cleanup(void *p) +{ + __syscall(SYS_close, (intptr_t)p); +} + +static unsigned long mtime() +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (unsigned long)ts.tv_sec * 1000 + + ts.tv_nsec / 1000000; +} + +int __res_msend_rc(int nqueries, const unsigned char *const *queries, + const int *qlens, unsigned char *const *answers, int *alens, int asize, + const struct resolvconf *conf) +{ + int fd; + int timeout, attempts, retry_interval, servfail_retry; + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa = {0}, ns[MAXNS] = {{0}}; + socklen_t sl = sizeof sa.sin; + int nns = 0; + int family = AF_INET; + int rlen; + int next; + int i, j; + int cs; + struct pollfd pfd; + unsigned long t0, t1, t2; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + timeout = 1000*conf->timeout; + attempts = conf->attempts; + + for (nns=0; nns<conf->nns; nns++) { + const struct address *iplit = &conf->ns[nns]; + if (iplit->family == AF_INET) { + memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4); + ns[nns].sin.sin_port = htons(53); + ns[nns].sin.sin_family = AF_INET; + } else { + sl = sizeof sa.sin6; + memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16); + ns[nns].sin6.sin6_port = htons(53); + ns[nns].sin6.sin6_scope_id = iplit->scopeid; + ns[nns].sin6.sin6_family = family = AF_INET6; + } + } + + /* Get local address and open/bind a socket */ + sa.sin.sin_family = family; + fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + + /* Handle case where system lacks IPv6 support */ + if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { + fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + family = AF_INET; + } + if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { + if (fd >= 0) close(fd); + pthread_setcancelstate(cs, 0); + return -1; + } + + /* Past this point, there are no errors. Each individual query will + * yield either no reply (indicated by zero length) or an answer + * packet which is up to the caller to interpret. */ + + pthread_cleanup_push(cleanup, (void *)(intptr_t)fd); + 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); + + pfd.fd = fd; + pfd.events = POLLIN; + retry_interval = timeout / attempts; + next = 0; + t0 = t2 = mtime(); + t1 = t2 - retry_interval; + + for (; t2-t0 < timeout; t2=mtime()) { + if (t2-t1 >= retry_interval) { + /* Query all configured namservers in parallel */ + for (i=0; i<nqueries; i++) + if (!alens[i]) + for (j=0; j<nns; j++) + sendto(fd, queries[i], + qlens[i], MSG_NOSIGNAL, + (void *)&ns[j], sl); + t1 = t2; + servfail_retry = 2 * nqueries; + } + + /* Wait for a response, or until time to retry */ + if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue; + + while ((rlen = recvfrom(fd, answers[next], asize, 0, + (void *)&sa, (socklen_t[1]){sl})) >= 0) { + + /* Ignore non-identifiable packets */ + if (rlen < 4) continue; + + /* Ignore replies from addresses we didn't send to */ + for (j=0; j<nns && memcmp(ns+j, &sa, sl); j++); + if (j==nns) continue; + + /* Find which query this answer goes with, if any */ + for (i=next; i<nqueries && ( + answers[next][0] != queries[i][0] || + answers[next][1] != queries[i][1] ); i++); + if (i==nqueries) continue; + if (alens[i]) continue; + + /* Only accept positive or negative responses; + * retry immediately on server failure, and ignore + * all other codes such as refusal. */ + switch (answers[next][3] & 15) { + case 0: + case 3: + break; + case 2: + if (servfail_retry && servfail_retry--) + sendto(fd, queries[i], + qlens[i], MSG_NOSIGNAL, + (void *)&ns[j], sl); + default: + continue; + } + + /* Store answer in the right slot, or update next + * available temp slot if it's already in place. */ + alens[i] = rlen; + if (i == next) + for (; next<nqueries && alens[next]; next++); + else + memcpy(answers[i], answers[next], rlen); + + if (next == nqueries) goto out; + } + } +out: + pthread_cleanup_pop(1); + + return 0; +} + +int __res_msend(int nqueries, const unsigned char *const *queries, + const int *qlens, unsigned char *const *answers, int *alens, int asize) +{ + struct resolvconf conf; + if (__get_resolv_conf(&conf, 0, 0) < 0) return -1; + return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &conf); +} diff --git a/libc-top-half/musl/src/network/res_query.c b/libc-top-half/musl/src/network/res_query.c new file mode 100644 index 0000000..506dc23 --- /dev/null +++ b/libc-top-half/musl/src/network/res_query.c @@ -0,0 +1,26 @@ +#define _BSD_SOURCE +#include <resolv.h> +#include <netdb.h> + +int res_query(const char *name, int class, int type, unsigned char *dest, int len) +{ + unsigned char q[280]; + int ql = __res_mkquery(0, name, class, type, 0, 0, 0, q, sizeof q); + if (ql < 0) return ql; + int r = __res_send(q, ql, dest, len); + if (r<12) { + h_errno = TRY_AGAIN; + return -1; + } + if ((dest[3] & 15) == 3) { + h_errno = HOST_NOT_FOUND; + return -1; + } + if ((dest[3] & 15) == 0 && !dest[6] && !dest[7]) { + h_errno = NO_DATA; + return -1; + } + return r; +} + +weak_alias(res_query, res_search); diff --git a/libc-top-half/musl/src/network/res_querydomain.c b/libc-top-half/musl/src/network/res_querydomain.c new file mode 100644 index 0000000..727e6f6 --- /dev/null +++ b/libc-top-half/musl/src/network/res_querydomain.c @@ -0,0 +1,14 @@ +#include <resolv.h> +#include <string.h> + +int res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *dest, int len) +{ + char tmp[255]; + size_t nl = strnlen(name, 255); + size_t dl = strnlen(domain, 255); + if (nl+dl+1 > 254) return -1; + memcpy(tmp, name, nl); + tmp[nl] = '.'; + memcpy(tmp+nl+1, domain, dl+1); + return res_query(tmp, class, type, dest, len); +} diff --git a/libc-top-half/musl/src/network/res_send.c b/libc-top-half/musl/src/network/res_send.c new file mode 100644 index 0000000..ee4abf1 --- /dev/null +++ b/libc-top-half/musl/src/network/res_send.c @@ -0,0 +1,9 @@ +#include <resolv.h> + +int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen) +{ + int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); + return r<0 || !anslen ? -1 : anslen; +} + +weak_alias(__res_send, res_send); diff --git a/libc-top-half/musl/src/network/res_state.c b/libc-top-half/musl/src/network/res_state.c new file mode 100644 index 0000000..5c42cda --- /dev/null +++ b/libc-top-half/musl/src/network/res_state.c @@ -0,0 +1,9 @@ +#include <resolv.h> + +/* This is completely unused, and exists purely to satisfy broken apps. */ + +struct __res_state *__res_state() +{ + static struct __res_state res; + return &res; +} diff --git a/libc-top-half/musl/src/network/resolvconf.c b/libc-top-half/musl/src/network/resolvconf.c new file mode 100644 index 0000000..ceabf08 --- /dev/null +++ b/libc-top-half/musl/src/network/resolvconf.c @@ -0,0 +1,94 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <netinet/in.h> + +int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz) +{ + char line[256]; + unsigned char _buf[256]; + FILE *f, _f; + int nns = 0; + + conf->ndots = 1; + conf->timeout = 5; + conf->attempts = 2; + if (search) *search = 0; + + f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + goto no_resolv_conf; + default: + return -1; + } + + while (fgets(line, sizeof line, f)) { + char *p, *z; + if (!strchr(line, '\n') && !feof(f)) { + /* Ignore lines that get truncated rather than + * potentially misinterpreting them. */ + int c; + do c = getc(f); + while (c != '\n' && c != EOF); + continue; + } + if (!strncmp(line, "options", 7) && isspace(line[7])) { + p = strstr(line, "ndots:"); + if (p && isdigit(p[6])) { + p += 6; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->ndots = x > 15 ? 15 : x; + } + p = strstr(line, "attempts:"); + if (p && isdigit(p[9])) { + p += 9; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->attempts = x > 10 ? 10 : x; + } + p = strstr(line, "timeout:"); + if (p && (isdigit(p[8]) || p[8]=='.')) { + p += 8; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->timeout = x > 60 ? 60 : x; + } + continue; + } + if (!strncmp(line, "nameserver", 10) && isspace(line[10])) { + if (nns >= MAXNS) continue; + for (p=line+11; isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z=0; + if (__lookup_ipliteral(conf->ns+nns, p, AF_UNSPEC) > 0) + nns++; + continue; + } + + if (!search) continue; + if ((strncmp(line, "domain", 6) && strncmp(line, "search", 6)) + || !isspace(line[6])) + continue; + for (p=line+7; isspace(*p); p++); + size_t l = strlen(p); + /* This can never happen anyway with chosen buffer sizes. */ + if (l >= search_sz) continue; + memcpy(search, p, l+1); + } + + __fclose_ca(f); + +no_resolv_conf: + if (!nns) { + __lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC); + nns = 1; + } + + conf->nns = nns; + + return 0; +} diff --git a/libc-top-half/musl/src/network/send.c b/libc-top-half/musl/src/network/send.c new file mode 100644 index 0000000..9f10497 --- /dev/null +++ b/libc-top-half/musl/src/network/send.c @@ -0,0 +1,6 @@ +#include <sys/socket.h> + +ssize_t send(int fd, const void *buf, size_t len, int flags) +{ + return sendto(fd, buf, len, flags, 0, 0); +} diff --git a/libc-top-half/musl/src/network/sendmmsg.c b/libc-top-half/musl/src/network/sendmmsg.c new file mode 100644 index 0000000..eeae1d0 --- /dev/null +++ b/libc-top-half/musl/src/network/sendmmsg.c @@ -0,0 +1,30 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <limits.h> +#include <errno.h> +#include "syscall.h" + +int sendmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags) +{ +#if LONG_MAX > INT_MAX + /* Can't use the syscall directly because the kernel has the wrong + * idea for the types of msg_iovlen, msg_controllen, and cmsg_len, + * and the cmsg blocks cannot be modified in-place. */ + int i; + if (vlen > IOV_MAX) vlen = IOV_MAX; /* This matches the kernel. */ + if (!vlen) return 0; + for (i=0; i<vlen; i++) { + /* As an unfortunate inconsistency, the sendmmsg API uses + * unsigned int for the resulting msg_len, despite sendmsg + * returning ssize_t. However Linux limits the total bytes + * sent by sendmsg to INT_MAX, so the assignment is safe. */ + ssize_t r = sendmsg(fd, &msgvec[i].msg_hdr, flags); + if (r < 0) goto error; + msgvec[i].msg_len = r; + } +error: + return i ? i : -1; +#else + return syscall_cp(SYS_sendmmsg, fd, msgvec, vlen, flags); +#endif +} diff --git a/libc-top-half/musl/src/network/sendmsg.c b/libc-top-half/musl/src/network/sendmsg.c new file mode 100644 index 0000000..80cc5f4 --- /dev/null +++ b/libc-top-half/musl/src/network/sendmsg.c @@ -0,0 +1,29 @@ +#include <sys/socket.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include "syscall.h" + +ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) +{ +#if LONG_MAX > INT_MAX + struct msghdr h; + struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c; + if (msg) { + h = *msg; + h.__pad1 = h.__pad2 = 0; + msg = &h; + if (h.msg_controllen) { + if (h.msg_controllen > 1024) { + errno = ENOMEM; + return -1; + } + memcpy(chbuf, h.msg_control, h.msg_controllen); + h.msg_control = chbuf; + for (c=CMSG_FIRSTHDR(&h); c; c=CMSG_NXTHDR(&h,c)) + c->__pad1 = 0; + } + } +#endif + return socketcall_cp(sendmsg, fd, msg, flags, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/sendto.c b/libc-top-half/musl/src/network/sendto.c new file mode 100644 index 0000000..c598797 --- /dev/null +++ b/libc-top-half/musl/src/network/sendto.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen) +{ + return socketcall_cp(sendto, fd, buf, len, flags, addr, alen); +} diff --git a/libc-top-half/musl/src/network/serv.c b/libc-top-half/musl/src/network/serv.c new file mode 100644 index 0000000..41424e8 --- /dev/null +++ b/libc-top-half/musl/src/network/serv.c @@ -0,0 +1,14 @@ +#include <netdb.h> + +void endservent(void) +{ +} + +void setservent(int stayopen) +{ +} + +struct servent *getservent(void) +{ + return 0; +} diff --git a/libc-top-half/musl/src/network/setsockopt.c b/libc-top-half/musl/src/network/setsockopt.c new file mode 100644 index 0000000..612a194 --- /dev/null +++ b/libc-top-half/musl/src/network/setsockopt.c @@ -0,0 +1,46 @@ +#include <sys/socket.h> +#include <sys/time.h> +#include <errno.h> +#include "syscall.h" + +#define IS32BIT(x) !((x)+0x80000000ULL>>32) +#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) + +int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +{ + const struct timeval *tv; + time_t s; + suseconds_t us; + + int r = __socketcall(setsockopt, fd, level, optname, optval, optlen, 0); + + if (r==-ENOPROTOOPT) switch (level) { + case SOL_SOCKET: + switch (optname) { + case SO_RCVTIMEO: + case SO_SNDTIMEO: + if (SO_RCVTIMEO == SO_RCVTIMEO_OLD) break; + if (optlen < sizeof *tv) return __syscall_ret(-EINVAL); + tv = optval; + s = tv->tv_sec; + us = tv->tv_usec; + if (!IS32BIT(s)) return __syscall_ret(-ENOTSUP); + + if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD; + if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD; + + r = __socketcall(setsockopt, fd, level, optname, + ((long[]){s, CLAMP(us)}), 2*sizeof(long), 0); + break; + case SO_TIMESTAMP: + case SO_TIMESTAMPNS: + if (SO_TIMESTAMP == SO_TIMESTAMP_OLD) break; + if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD; + if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD; + r = __socketcall(setsockopt, fd, level, + optname, optval, optlen, 0); + break; + } + } + return __syscall_ret(r); +} diff --git a/libc-top-half/musl/src/network/shutdown.c b/libc-top-half/musl/src/network/shutdown.c new file mode 100644 index 0000000..10ca21a --- /dev/null +++ b/libc-top-half/musl/src/network/shutdown.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include "syscall.h" + +int shutdown(int fd, int how) +{ + return socketcall(shutdown, fd, how, 0, 0, 0, 0); +} diff --git a/libc-top-half/musl/src/network/sockatmark.c b/libc-top-half/musl/src/network/sockatmark.c new file mode 100644 index 0000000..f474551 --- /dev/null +++ b/libc-top-half/musl/src/network/sockatmark.c @@ -0,0 +1,10 @@ +#include <sys/socket.h> +#include <sys/ioctl.h> + +int sockatmark(int s) +{ + int ret; + if (ioctl(s, SIOCATMARK, &ret) < 0) + return -1; + return ret; +} diff --git a/libc-top-half/musl/src/network/socket.c b/libc-top-half/musl/src/network/socket.c new file mode 100644 index 0000000..afa1a7f --- /dev/null +++ b/libc-top-half/musl/src/network/socket.c @@ -0,0 +1,21 @@ +#include <sys/socket.h> +#include <fcntl.h> +#include <errno.h> +#include "syscall.h" + +int socket(int domain, int type, int protocol) +{ + int s = __socketcall(socket, domain, type, protocol, 0, 0, 0); + if ((s==-EINVAL || s==-EPROTONOSUPPORT) + && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { + s = __socketcall(socket, domain, + type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), + protocol, 0, 0, 0); + if (s < 0) return __syscall_ret(s); + if (type & SOCK_CLOEXEC) + __syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC); + if (type & SOCK_NONBLOCK) + __syscall(SYS_fcntl, s, F_SETFL, O_NONBLOCK); + } + return __syscall_ret(s); +} diff --git a/libc-top-half/musl/src/network/socketpair.c b/libc-top-half/musl/src/network/socketpair.c new file mode 100644 index 0000000..f348962 --- /dev/null +++ b/libc-top-half/musl/src/network/socketpair.c @@ -0,0 +1,25 @@ +#include <sys/socket.h> +#include <fcntl.h> +#include <errno.h> +#include "syscall.h" + +int socketpair(int domain, int type, int protocol, int fd[2]) +{ + int r = socketcall(socketpair, domain, type, protocol, fd, 0, 0); + if (r<0 && (errno==EINVAL || errno==EPROTONOSUPPORT) + && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { + r = socketcall(socketpair, domain, + type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), + protocol, fd, 0, 0); + if (r < 0) return r; + if (type & SOCK_CLOEXEC) { + __syscall(SYS_fcntl, fd[0], F_SETFD, FD_CLOEXEC); + __syscall(SYS_fcntl, fd[1], F_SETFD, FD_CLOEXEC); + } + if (type & SOCK_NONBLOCK) { + __syscall(SYS_fcntl, fd[0], F_SETFL, O_NONBLOCK); + __syscall(SYS_fcntl, fd[1], F_SETFL, O_NONBLOCK); + } + } + return r; +} |