From 1a96de6eda2728c7da90f04685a76a0e3743104e Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 8 Dec 2023 20:03:03 -0800 Subject: [PATCH] Add libresolv from Musl Libc Locally modified to get nameservers from Windows Registry when `\etc\resolv.conf` isn't defined. --- Makefile | 18 +- libc/BUILD.mk | 3 + libc/{dns => calls}/h_errno.c | 12 +- libc/dlopen/dlfcn.h | 2 - libc/dns/ent.h | 4 +- libc/intrin/strace.internal.h | 2 +- libc/intrin/wsarecv.c | 2 +- libc/intrin/wsarecvfrom.c | 7 +- libc/isystem/arpa/nameser.h | 4 + libc/isystem/netinet/in.h | 43 +-- libc/isystem/resolv.h | 5 + libc/sock/in.h | 71 +++++ libc/sock/recvfrom-nt.c | 1 + libc/sock/recvmsg.c | 8 +- libc/sock/sendmsg.c | 4 +- libc/sock/struct/ifreq.h | 12 +- third_party/musl/BUILD.mk | 2 + third_party/musl/dn_comp.c | 139 +++++++++ third_party/musl/dn_expand.c | 65 ++++ third_party/musl/dn_skipname.c | 47 +++ third_party/musl/lookup.internal.h | 52 ++++ third_party/musl/lookup_ipliteral.c | 90 ++++++ third_party/musl/nameser.h | 446 ++++++++++++++++++++++++++++ third_party/musl/ns_parse.c | 201 +++++++++++++ third_party/musl/res_init.c | 6 + third_party/musl/res_mkquery.c | 78 +++++ third_party/musl/res_msend.c | 363 ++++++++++++++++++++++ third_party/musl/res_query.c | 58 ++++ third_party/musl/res_querydomain.c | 46 +++ third_party/musl/res_send.c | 49 +++ third_party/musl/res_state.c | 9 + third_party/musl/resolv.h | 134 +++++++++ third_party/musl/resolv.internal.h | 11 + third_party/musl/resolvconf.c | 196 ++++++++++++ tool/net/BUILD.mk | 2 + tool/net/libresolv_query.c | 194 ++++++++++++ 36 files changed, 2313 insertions(+), 73 deletions(-) rename libc/{dns => calls}/h_errno.c (90%) create mode 100644 libc/isystem/arpa/nameser.h create mode 100644 libc/isystem/resolv.h create mode 100644 libc/sock/in.h create mode 100644 third_party/musl/dn_comp.c create mode 100644 third_party/musl/dn_expand.c create mode 100644 third_party/musl/dn_skipname.c create mode 100644 third_party/musl/lookup.internal.h create mode 100644 third_party/musl/lookup_ipliteral.c create mode 100644 third_party/musl/nameser.h create mode 100644 third_party/musl/ns_parse.c create mode 100644 third_party/musl/res_init.c create mode 100644 third_party/musl/res_mkquery.c create mode 100644 third_party/musl/res_msend.c create mode 100644 third_party/musl/res_query.c create mode 100644 third_party/musl/res_querydomain.c create mode 100644 third_party/musl/res_send.c create mode 100644 third_party/musl/res_state.c create mode 100644 third_party/musl/resolv.h create mode 100644 third_party/musl/resolv.internal.h create mode 100644 third_party/musl/resolvconf.c create mode 100644 tool/net/libresolv_query.c diff --git a/Makefile b/Makefile index 203c0461e..498227f4d 100644 --- a/Makefile +++ b/Makefile @@ -208,20 +208,20 @@ include libc/log/BUILD.mk # │ include third_party/getopt/BUILD.mk # │ include third_party/bzip2/BUILD.mk # │ include dsp/core/BUILD.mk # │ -include third_party/musl/BUILD.mk # │ -include libc/x/BUILD.mk # │ -include third_party/stb/BUILD.mk # │ -include dsp/scale/BUILD.mk # │ -include dsp/mpeg/BUILD.mk # │ -include dsp/BUILD.mk # │ include third_party/zlib/gz/BUILD.mk # │ include third_party/intel/BUILD.mk # │ include third_party/aarch64/BUILD.mk # │ include libc/BUILD.mk #─┘ include libc/sock/BUILD.mk #─┐ -include dsp/tty/BUILD.mk # ├──ONLINE RUNTIME -include libc/dns/BUILD.mk # │ You can communicate with the network -include net/http/BUILD.mk # │ +include libc/dns/BUILD.mk # ├──ONLINE RUNTIME +include net/http/BUILD.mk # │ You can communicate with the network +include third_party/musl/BUILD.mk # │ +include libc/x/BUILD.mk # │ +include dsp/scale/BUILD.mk # │ +include dsp/mpeg/BUILD.mk # │ +include dsp/tty/BUILD.mk # │ +include dsp/BUILD.mk # │ +include third_party/stb/BUILD.mk # │ include third_party/mbedtls/BUILD.mk # │ include third_party/libcxx/BUILD.mk # │ include third_party/ggml/BUILD.mk # │ diff --git a/libc/BUILD.mk b/libc/BUILD.mk index 848598dce..ffb365592 100644 --- a/libc/BUILD.mk +++ b/libc/BUILD.mk @@ -14,6 +14,7 @@ libc/isystem/arm_bf16.h \ libc/isystem/arm_fp16.h \ libc/isystem/arm_neon.h \ libc/isystem/arpa/inet.h \ +libc/isystem/arpa/nameser.h \ libc/isystem/array \ libc/isystem/assert.h \ libc/isystem/atomic \ @@ -98,6 +99,7 @@ libc/isystem/langinfo.h \ libc/isystem/libgen.h \ libc/isystem/limits \ libc/isystem/limits.h \ +libc/isystem/link.h \ libc/isystem/linux/futex.h \ libc/isystem/linux/limits.h \ libc/isystem/linux/param.h \ @@ -154,6 +156,7 @@ libc/isystem/random \ libc/isystem/ratio \ libc/isystem/regex \ libc/isystem/regex.h \ +libc/isystem/resolv.h \ libc/isystem/sched.h \ libc/isystem/scoped_allocator \ libc/isystem/search.h \ diff --git a/libc/dns/h_errno.c b/libc/calls/h_errno.c similarity index 90% rename from libc/dns/h_errno.c rename to libc/calls/h_errno.c index dd172dede..401326c36 100644 --- a/libc/dns/h_errno.c +++ b/libc/calls/h_errno.c @@ -16,9 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/dns/dns.h" +#include "libc/dns/ent.h" -/** - * Error number global for gethostbyname*(), gethostbyaddr*(), etc. - */ -int h_errno; +// error number global for gethostbyname*(), gethostbyaddr*(), etc. +static _Thread_local int __h_errno; + +errno_t *__h_errno_location(void) { + return &__h_errno; +} diff --git a/libc/dlopen/dlfcn.h b/libc/dlopen/dlfcn.h index cf81c110b..c50dcc891 100644 --- a/libc/dlopen/dlfcn.h +++ b/libc/dlopen/dlfcn.h @@ -15,14 +15,12 @@ char *dlerror(void); void *dlopen(const char *, int); void *dlsym(void *, const char *); int dlclose(void *); -int dl_iterate_phdr(int (*)(void *, size_t, void *), void *); #ifdef _COSMO_SOURCE char *cosmo_dlerror(void); void *cosmo_dlopen(const char *, int); void *cosmo_dlsym(void *, const char *); int cosmo_dlclose(void *); -int cosmo_dl_iterate_phdr(int (*)(void *, size_t, void *), void *); #endif COSMOPOLITAN_C_END_ diff --git a/libc/dns/ent.h b/libc/dns/ent.h index 530ebb5c6..4902038ce 100644 --- a/libc/dns/ent.h +++ b/libc/dns/ent.h @@ -39,7 +39,9 @@ struct servent { char *s_proto; /* protocol to use */ }; -extern int h_errno; +#define h_errno (*__h_errno_location()) +errno_t *__h_errno_location(void) dontthrow pureconst; + void herror(const char *); const char *hstrerror(int); diff --git a/libc/intrin/strace.internal.h b/libc/intrin/strace.internal.h index 3c521857f..adda49caa 100644 --- a/libc/intrin/strace.internal.h +++ b/libc/intrin/strace.internal.h @@ -5,7 +5,7 @@ #define SYSDEBUG 0 #endif -#define _NTTRACE 0 /* not configurable w/ flag yet */ +#define _NTTRACE 1 /* not configurable w/ flag yet */ #define _POLLTRACE 0 /* not configurable w/ flag yet */ #define _DATATRACE 1 /* not configurable w/ flag yet */ #define _LOCKTRACE 0 /* not configurable w/ flag yet */ diff --git a/libc/intrin/wsarecv.c b/libc/intrin/wsarecv.c index 899f2e29a..89cad8a1c 100644 --- a/libc/intrin/wsarecv.c +++ b/libc/intrin/wsarecv.c @@ -46,7 +46,7 @@ textwindows int WSARecv( // be NULL only if the lpOverlapped parameter is not NULL. unassert(!opt_out_lpNumberOfBytesRecvd); } -#if defined(SYSDEBUG) && _NTTRACE +#if SYSDEBUG && _NTTRACE uint32_t NumberOfBytesRecvd; if (opt_out_lpNumberOfBytesRecvd) { NumberOfBytesRecvd = *opt_out_lpNumberOfBytesRecvd; diff --git a/libc/intrin/wsarecvfrom.c b/libc/intrin/wsarecvfrom.c index 3ddf576ee..9965974d3 100644 --- a/libc/intrin/wsarecvfrom.c +++ b/libc/intrin/wsarecvfrom.c @@ -22,6 +22,7 @@ #include "libc/intrin/kprintf.h" #include "libc/intrin/likely.h" #include "libc/intrin/strace.internal.h" +#include "libc/nt/runtime.h" #include "libc/nt/thunk/msabi.h" #include "libc/nt/winsock.h" #include "libc/runtime/runtime.h" @@ -39,7 +40,7 @@ textwindows int WSARecvFrom( struct NtOverlapped *opt_inout_lpOverlapped, const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine) { int rc; -#if defined(SYSDEBUG) && _NTTRACE +#if SYSDEBUG && _NTTRACE uint32_t NumberOfBytesRecvd; if (opt_out_lpNumberOfBytesRecvd) { NumberOfBytesRecvd = *opt_out_lpNumberOfBytesRecvd; @@ -55,10 +56,10 @@ textwindows int WSARecvFrom( kprintf(STRACE_PROLOGUE "WSARecvFrom(%lu, [", s); DescribeIovNt(inout_lpBuffers, dwBufferCount, rc != -1 ? NumberOfBytesRecvd : 0); - kprintf("], %u, [%'u], %p, %p, %p, %s, %p) → %d% lm\n", dwBufferCount, + kprintf("], %u, [%'u], %p, %p, %p, %s, %p) → %d %d\n", dwBufferCount, NumberOfBytesRecvd, opt_out_fromsockaddr, opt_inout_fromsockaddrlen, inout_lpFlags, DescribeNtOverlapped(opt_inout_lpOverlapped), - opt_lpCompletionRoutine, rc); + opt_lpCompletionRoutine, rc, GetLastError()); } #else rc = __imp_WSARecvFrom(s, inout_lpBuffers, dwBufferCount, diff --git a/libc/isystem/arpa/nameser.h b/libc/isystem/arpa/nameser.h new file mode 100644 index 000000000..eea507d88 --- /dev/null +++ b/libc/isystem/arpa/nameser.h @@ -0,0 +1,4 @@ +#ifndef _ARPA_NAMESER_H +#define _ARPA_NAMESER_H +#include "third_party/musl/nameser.h" +#endif /* _ARPA_NAMESER_H */ diff --git a/libc/isystem/netinet/in.h b/libc/isystem/netinet/in.h index ffbb80503..67eaac01b 100644 --- a/libc/isystem/netinet/in.h +++ b/libc/isystem/netinet/in.h @@ -1,6 +1,7 @@ #ifndef COSMOPOLITAN_LIBC_ISYSTEM_NETINET_IN_H_ #define COSMOPOLITAN_LIBC_ISYSTEM_NETINET_IN_H_ #include "libc/calls/weirdtypes.h" +#include "libc/sock/in.h" #include "libc/sock/sock.h" #include "libc/sock/struct/in6_pktinfo.h" #include "libc/sock/struct/in_pktinfo.h" @@ -17,46 +18,4 @@ #include "libc/sysv/consts/mcast.h" #include "libc/sysv/consts/pf.h" #include "libc/sysv/consts/sock.h" - -# define IN6_ARE_ADDR_EQUAL(a,b) \ - ((((const uint32_t *) (a))[0] == ((const uint32_t *) (b))[0]) \ - && (((const uint32_t *) (a))[1] == ((const uint32_t *) (b))[1]) \ - && (((const uint32_t *) (a))[2] == ((const uint32_t *) (b))[2]) \ - && (((const uint32_t *) (a))[3] == ((const uint32_t *) (b))[3])) - -# define IN6_IS_ADDR_UNSPECIFIED(a) \ - (((const uint32_t *) (a))[0] == 0 \ - && ((const uint32_t *) (a))[1] == 0 \ - && ((const uint32_t *) (a))[2] == 0 \ - && ((const uint32_t *) (a))[3] == 0) - -# define IN6_IS_ADDR_LOOPBACK(a) \ - (((const uint32_t *) (a))[0] == 0 \ - && ((const uint32_t *) (a))[1] == 0 \ - && ((const uint32_t *) (a))[2] == 0 \ - && ((const uint32_t *) (a))[3] == htonl (1)) - -# define IN6_IS_ADDR_LINKLOCAL(a) \ - ((((const uint32_t *) (a))[0] & htonl (0xffc00000)) \ - == htonl (0xfe800000)) - -# define IN6_IS_ADDR_SITELOCAL(a) \ - ((((const uint32_t *) (a))[0] & htonl (0xffc00000)) \ - == htonl (0xfec00000)) - -# define IN6_IS_ADDR_V4MAPPED(a) \ - ((((const uint32_t *) (a))[0] == 0) \ - && (((const uint32_t *) (a))[1] == 0) \ - && (((const uint32_t *) (a))[2] == htonl (0xffff))) - -# define IN6_IS_ADDR_V4COMPAT(a) \ - ((((const uint32_t *) (a))[0] == 0) \ - && (((const uint32_t *) (a))[1] == 0) \ - && (((const uint32_t *) (a))[2] == 0) \ - && (ntohl (((const uint32_t *) (a))[3]) > 1)) - -#define IN6_IS_ADDR_MULTICAST(a) (((const uint8_t *) (a))[0] == 0xff) - - - #endif /* COSMOPOLITAN_LIBC_ISYSTEM_NETINET_IN_H_ */ diff --git a/libc/isystem/resolv.h b/libc/isystem/resolv.h new file mode 100644 index 000000000..33cf4cdba --- /dev/null +++ b/libc/isystem/resolv.h @@ -0,0 +1,5 @@ +#ifndef _RESOLV_H +#define _RESOLV_H +#include "third_party/musl/nameser.h" +#include "third_party/musl/resolv.h" +#endif /* _RESOLV_H */ diff --git a/libc/sock/in.h b/libc/sock/in.h new file mode 100644 index 000000000..092bebebd --- /dev/null +++ b/libc/sock/in.h @@ -0,0 +1,71 @@ +#ifndef COSMOPOLITAN_LIBC_SOCK_IN_H_ +#define COSMOPOLITAN_LIBC_SOCK_IN_H_ +#include "libc/sock/sock.h" + +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#define IN6_IS_ADDR_UNSPECIFIED(a) \ + (((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \ + ((uint32_t *)(a))[2] == 0 && ((uint32_t *)(a))[3] == 0) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \ + ((uint32_t *)(a))[2] == 0 && ((uint8_t *)(a))[12] == 0 && \ + ((uint8_t *)(a))[13] == 0 && ((uint8_t *)(a))[14] == 0 && \ + ((uint8_t *)(a))[15] == 1) + +#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *)(a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((uint8_t *)(a))[0]) == 0xfe && (((uint8_t *)(a))[1] & 0xc0) == 0x80) + +#define IN6_IS_ADDR_SITELOCAL(a) \ + ((((uint8_t *)(a))[0]) == 0xfe && (((uint8_t *)(a))[1] & 0xc0) == 0xc0) + +#define IN6_IS_ADDR_V4MAPPED(a) \ + (((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \ + ((uint8_t *)(a))[8] == 0 && ((uint8_t *)(a))[9] == 0 && \ + ((uint8_t *)(a))[10] == 0xff && ((uint8_t *)(a))[11] == 0xff) + +#define IN6_IS_ADDR_V4COMPAT(a) \ + (((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \ + ((uint32_t *)(a))[2] == 0 && ((uint8_t *)(a))[15] > 1) + +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0x1)) + +#define IN6_IS_ADDR_MC_LINKLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0x2)) + +#define IN6_IS_ADDR_MC_SITELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0x5)) + +#define IN6_IS_ADDR_MC_ORGLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0x8)) + +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0xe)) + +#define __ARE_4_EQUAL(a, b) \ + (!((0 [a] - 0 [b]) | (1 [a] - 1 [b]) | (2 [a] - 2 [b]) | (3 [a] - 3 [b]))) +#define IN6_ARE_ADDR_EQUAL(a, b) \ + __ARE_4_EQUAL((const uint32_t *)(a), (const uint32_t *)(b)) + +#endif /* COSMOPOLITAN_LIBC_SOCK_IN_H_ */ diff --git a/libc/sock/recvfrom-nt.c b/libc/sock/recvfrom-nt.c index ad1dcfd1a..101277262 100644 --- a/libc/sock/recvfrom-nt.c +++ b/libc/sock/recvfrom-nt.c @@ -23,6 +23,7 @@ #include "libc/nt/struct/iovec.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/struct/sockaddr.h" #include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/consts/msg.h" #include "libc/sysv/consts/o.h" diff --git a/libc/sock/recvmsg.c b/libc/sock/recvmsg.c index 6be567248..caac4fc50 100644 --- a/libc/sock/recvmsg.c +++ b/libc/sock/recvmsg.c @@ -23,6 +23,10 @@ #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.internal.h" #include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/kprintf.h" +#include "libc/intrin/strace.internal.h" +#include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/sock/struct/msghdr.h" #include "libc/sock/struct/msghdr.internal.h" @@ -99,12 +103,12 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) { } END_CANCELATION_POINT; -#if defined(SYSDEBUG) && _DATATRACE +#if SYSDEBUG && _DATATRACE if (__strace > 0 && strace_enabled(0) > 0) { if (!msg || (rc == -1 && errno == EFAULT)) { DATATRACE("recvmsg(%d, %p, %#x) → %'ld% m", fd, msg, flags, rc); } else { - kprintf(STRACE_PROLOGUE "recvmsg(%d, [{"); + kprintf(STRACE_PROLOGUE "recvmsg(%d, [{", fd); if (msg->msg_namelen) kprintf(".name=%#.*hhs, ", msg->msg_namelen, msg->msg_name); if (msg->msg_controllen) diff --git a/libc/sock/sendmsg.c b/libc/sock/sendmsg.c index 00fd4f52f..5fd2dae11 100644 --- a/libc/sock/sendmsg.c +++ b/libc/sock/sendmsg.c @@ -87,10 +87,10 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) { } END_CANCELATION_POINT; -#if defined(SYSDEBUG) && _DATATRACE +#if SYSDEBUG && _DATATRACE // TODO(jart): Write a DescribeMsg() function. if (strace_enabled(0) > 0) { - kprintf(STRACE_PROLOGUE "sendmsg("); + kprintf(STRACE_PROLOGUE "sendmsg(%d, ", fd); if ((!IsAsan() && kisdangerous(msg)) || (IsAsan() && !__asan_is_valid(msg, sizeof(*msg)))) { kprintf("%p", msg); diff --git a/libc/sock/struct/ifreq.h b/libc/sock/struct/ifreq.h index 50d98102c..0f7061f5f 100644 --- a/libc/sock/struct/ifreq.h +++ b/libc/sock/struct/ifreq.h @@ -16,16 +16,18 @@ struct ifreq { struct sockaddr ifru_netmask; /* SIOCGIFNETMASK */ struct sockaddr ifru_broadaddr; /* SIOCGIFBRDADDR */ short ifru_flags; /* SIOCGIFFLAGS */ + int ifru_ivalue; /* todo(jart) */ char ifru_pad[24]; /* ifru_map is the largest, just pad */ } ifr_ifru; }; -#define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define ifr_addr ifr_ifru.ifru_addr /* address */ -#define ifr_netmask ifr_ifru.ifru_netmask /* netmask */ +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* netmask */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ -#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* destination address */ -#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* destination address */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_ifindex ifr_ifru.ifru_ivalue COSMOPOLITAN_C_END_ #endif /* COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_ */ diff --git a/third_party/musl/BUILD.mk b/third_party/musl/BUILD.mk index f87046f25..c0550e2ff 100644 --- a/third_party/musl/BUILD.mk +++ b/third_party/musl/BUILD.mk @@ -22,8 +22,10 @@ THIRD_PARTY_MUSL_A_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_MEM \ LIBC_NEXGEN32E \ + LIBC_NT_ADVAPI32 \ LIBC_PROC \ LIBC_RUNTIME \ + LIBC_SOCK \ LIBC_STDIO \ LIBC_STR \ LIBC_SYSV \ diff --git a/third_party/musl/dn_comp.c b/third_party/musl/dn_comp.c new file mode 100644 index 000000000..f95e27afa --- /dev/null +++ b/third_party/musl/dn_comp.c @@ -0,0 +1,139 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/musl/resolv.h" +#include "libc/str/str.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +/* 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 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>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/third_party/musl/dn_expand.c b/third_party/musl/dn_expand.c new file mode 100644 index 000000000..4112b7b93 --- /dev/null +++ b/third_party/musl/dn_expand.c @@ -0,0 +1,65 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/musl/resolv.internal.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +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-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_reference(__dn_expand, dn_expand); diff --git a/third_party/musl/dn_skipname.c b/third_party/musl/dn_skipname.c new file mode 100644 index 000000000..601d39fa3 --- /dev/null +++ b/third_party/musl/dn_skipname.c @@ -0,0 +1,47 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/musl/resolv.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +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 0) { + if (family == AF_INET6) /* wrong family */ + return EAI_NODATA; + 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_NODATA; + + 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 1 + // todo(jart): do something + return EAI_NONAME; +#else + if (!IN6_IS_ADDR_LINKLOCAL(&a6) && + !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) + return EAI_NONAME; + scopeid = if_nametoindex(p); + if (!scopeid) + return EAI_NONAME; +#endif + } + if (scopeid > UINT_MAX) + return EAI_NONAME; + } + buf[0].scopeid = scopeid; + return 1; +} diff --git a/third_party/musl/nameser.h b/third_party/musl/nameser.h new file mode 100644 index 000000000..54662a56f --- /dev/null +++ b/third_party/musl/nameser.h @@ -0,0 +1,446 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_NAMESER_H_ +#define COSMOPOLITAN_THIRD_PARTY_MUSL_NAMESER_H_ +COSMOPOLITAN_C_START_ + +#define __NAMESER 19991006 +#define NS_PACKETSZ 512 +#define NS_MAXDNAME 1025 +#define NS_MAXMSG 65535 +#define NS_MAXCDNAME 255 +#define NS_MAXLABEL 63 +#define NS_HFIXEDSZ 12 +#define NS_QFIXEDSZ 4 +#define NS_RRFIXEDSZ 10 +#define NS_INT32SZ 4 +#define NS_INT16SZ 2 +#define NS_INT8SZ 1 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#define NS_CMPRSFLGS 0xc0 +#define NS_DEFAULTPORT 53 + +typedef enum __ns_sect { + ns_s_qd = 0, + ns_s_zn = 0, + ns_s_an = 1, + ns_s_pr = 1, + ns_s_ns = 2, + ns_s_ud = 2, + ns_s_ar = 3, + ns_s_max = 4 +} ns_sect; + +typedef struct __ns_msg { + const unsigned char *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max]; + const unsigned char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char *_msg_ptr; +} ns_msg; + +struct _ns_flagdata { int mask, shift; }; +extern const struct _ns_flagdata _ns_flagdata[]; + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) +#define ns_msg_getflag(handle, flag) \ + (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) + +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + const unsigned char *rdata; +} ns_rr; + +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +typedef enum __ns_flag { + ns_f_qr, + ns_f_opcode, + ns_f_aa, + ns_f_tc, + ns_f_rd, + ns_f_ra, + ns_f_z, + ns_f_ad, + ns_f_cd, + ns_f_rcode, + ns_f_max +} ns_flag; + +typedef enum __ns_opcode { + ns_o_query = 0, + ns_o_iquery = 1, + ns_o_status = 2, + ns_o_notify = 4, + ns_o_update = 5, + ns_o_max = 6 +} ns_opcode; + +typedef enum __ns_rcode { + ns_r_noerror = 0, + ns_r_formerr = 1, + ns_r_servfail = 2, + ns_r_nxdomain = 3, + ns_r_notimpl = 4, + ns_r_refused = 5, + ns_r_yxdomain = 6, + ns_r_yxrrset = 7, + ns_r_nxrrset = 8, + ns_r_notauth = 9, + ns_r_notzone = 10, + ns_r_max = 11, + ns_r_badvers = 16, + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +typedef enum __ns_update_operation { + ns_uop_delete = 0, + ns_uop_add = 1, + ns_uop_max = 2 +} ns_update_operation; + +struct ns_tsig_key { + char name[NS_MAXDNAME], alg[NS_MAXDNAME]; + unsigned char *data; + int len; +}; +typedef struct ns_tsig_key ns_tsig_key; + +struct ns_tcp_tsig_state { + int counter; + struct dst_key *key; + void *ctx; + unsigned char sig[NS_PACKETSZ]; + int siglen; +}; +typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; + +#define NS_TSIG_FUDGE 300 +#define NS_TSIG_TCP_COUNT 100 +#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" + +#define NS_TSIG_ERROR_NO_TSIG -10 +#define NS_TSIG_ERROR_NO_SPACE -11 +#define NS_TSIG_ERROR_FORMERR -12 + +typedef enum __ns_type { + ns_t_invalid = 0, + ns_t_a = 1, + ns_t_ns = 2, + ns_t_md = 3, + ns_t_mf = 4, + ns_t_cname = 5, + ns_t_soa = 6, + ns_t_mb = 7, + ns_t_mg = 8, + ns_t_mr = 9, + ns_t_null = 10, + ns_t_wks = 11, + ns_t_ptr = 12, + ns_t_hinfo = 13, + ns_t_minfo = 14, + ns_t_mx = 15, + ns_t_txt = 16, + ns_t_rp = 17, + ns_t_afsdb = 18, + ns_t_x25 = 19, + ns_t_isdn = 20, + ns_t_rt = 21, + ns_t_nsap = 22, + ns_t_nsap_ptr = 23, + ns_t_sig = 24, + ns_t_key = 25, + ns_t_px = 26, + ns_t_gpos = 27, + ns_t_aaaa = 28, + ns_t_loc = 29, + ns_t_nxt = 30, + ns_t_eid = 31, + ns_t_nimloc = 32, + ns_t_srv = 33, + ns_t_atma = 34, + ns_t_naptr = 35, + ns_t_kx = 36, + ns_t_cert = 37, + ns_t_a6 = 38, + ns_t_dname = 39, + ns_t_sink = 40, + ns_t_opt = 41, + ns_t_apl = 42, + ns_t_tkey = 249, + ns_t_tsig = 250, + ns_t_ixfr = 251, + ns_t_axfr = 252, + ns_t_mailb = 253, + ns_t_maila = 254, + ns_t_any = 255, + ns_t_zxfr = 256, + ns_t_max = 65536 +} ns_type; + +#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ + (t) == ns_t_mailb || (t) == ns_t_maila) +#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ + (t) == ns_t_zxfr) + +typedef enum __ns_class { + ns_c_invalid = 0, + ns_c_in = 1, + ns_c_2 = 2, + ns_c_chaos = 3, + ns_c_hs = 4, + ns_c_none = 254, + ns_c_any = 255, + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_key_types { + ns_kt_rsa = 1, + ns_kt_dh = 2, + ns_kt_dsa = 3, + ns_kt_private = 254 +} ns_key_types; + +typedef enum __ns_cert_types { + cert_t_pkix = 1, + cert_t_spki = 2, + cert_t_pgp = 3, + cert_t_url = 253, + cert_t_oid = 254 +} ns_cert_types; + +#define NS_KEY_TYPEMASK 0xC000 +#define NS_KEY_TYPE_AUTH_CONF 0x0000 +#define NS_KEY_TYPE_CONF_ONLY 0x8000 +#define NS_KEY_TYPE_AUTH_ONLY 0x4000 +#define NS_KEY_TYPE_NO_KEY 0xC000 +#define NS_KEY_NO_AUTH 0x8000 +#define NS_KEY_NO_CONF 0x4000 +#define NS_KEY_RESERVED2 0x2000 +#define NS_KEY_EXTENDED_FLAGS 0x1000 +#define NS_KEY_RESERVED4 0x0800 +#define NS_KEY_RESERVED5 0x0400 +#define NS_KEY_NAME_TYPE 0x0300 +#define NS_KEY_NAME_USER 0x0000 +#define NS_KEY_NAME_ENTITY 0x0200 +#define NS_KEY_NAME_ZONE 0x0100 +#define NS_KEY_NAME_RESERVED 0x0300 +#define NS_KEY_RESERVED8 0x0080 +#define NS_KEY_RESERVED9 0x0040 +#define NS_KEY_RESERVED10 0x0020 +#define NS_KEY_RESERVED11 0x0010 +#define NS_KEY_SIGNATORYMASK 0x000F +#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ + NS_KEY_RESERVED4 | \ + NS_KEY_RESERVED5 | \ + NS_KEY_RESERVED8 | \ + NS_KEY_RESERVED9 | \ + NS_KEY_RESERVED10 | \ + NS_KEY_RESERVED11 ) +#define NS_KEY_RESERVED_BITMASK2 0xFFFF +#define NS_ALG_MD5RSA 1 +#define NS_ALG_DH 2 +#define NS_ALG_DSA 3 +#define NS_ALG_DSS NS_ALG_DSA +#define NS_ALG_EXPIRE_ONLY 253 +#define NS_ALG_PRIVATE_OID 254 + +#define NS_KEY_PROT_TLS 1 +#define NS_KEY_PROT_EMAIL 2 +#define NS_KEY_PROT_DNSSEC 3 +#define NS_KEY_PROT_IPSEC 4 +#define NS_KEY_PROT_ANY 255 + +#define NS_MD5RSA_MIN_BITS 512 +#define NS_MD5RSA_MAX_BITS 4096 +#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) +#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) +#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) +#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) + +#define NS_DSA_SIG_SIZE 41 +#define NS_DSA_MIN_SIZE 213 +#define NS_DSA_MAX_BYTES 405 + +#define NS_SIG_TYPE 0 +#define NS_SIG_ALG 2 +#define NS_SIG_LABELS 3 +#define NS_SIG_OTTL 4 +#define NS_SIG_EXPIR 8 +#define NS_SIG_SIGNED 12 +#define NS_SIG_FOOT 16 +#define NS_SIG_SIGNER 18 +#define NS_NXT_BITS 8 +#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_MAX 127 + +#define NS_OPT_DNSSEC_OK 0x8000U +#define NS_OPT_NSID 3 + +#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp)+=2)-2)) +#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp)+=4)-4)) +#define NS_PUT16(s, cp) ns_put16((s), ((cp)+=2)-2) +#define NS_PUT32(l, cp) ns_put32((l), ((cp)+=4)-4) + +unsigned ns_get16(const unsigned char *); +unsigned long ns_get32(const unsigned char *); +void ns_put16(unsigned, unsigned char *); +void ns_put32(unsigned long, unsigned char *); + +int ns_initparse(const unsigned char *, int, ns_msg *); +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); +int ns_skiprr(const unsigned char *, const unsigned char *, ns_sect, int); +int ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); + + +#define __BIND 19950621 + +typedef struct { + unsigned id :16; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned qr: 1; + unsigned opcode: 4; + unsigned aa: 1; + unsigned tc: 1; + unsigned rd: 1; + unsigned ra: 1; + unsigned unused :1; + unsigned ad: 1; + unsigned cd: 1; + unsigned rcode :4; +#else + unsigned rd :1; + unsigned tc :1; + unsigned aa :1; + unsigned opcode :4; + unsigned qr :1; + unsigned rcode :4; + unsigned cd: 1; + unsigned ad: 1; + unsigned unused :1; + unsigned ra :1; +#endif + unsigned qdcount :16; + unsigned ancount :16; + unsigned nscount :16; + unsigned arcount :16; +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INT32SZ NS_INT32SZ +#define INT16SZ NS_INT16SZ +#define INT8SZ NS_INT8SZ +#define INADDRSZ NS_INADDRSZ +#define IN6ADDRSZ NS_IN6ADDRSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define S_ZONE ns_s_zn +#define S_PREREQ ns_s_pr +#define S_UPDATE ns_s_ud +#define S_ADDT ns_s_ar + +#define QUERY ns_o_query +#define IQUERY ns_o_iquery +#define STATUS ns_o_status +#define NS_NOTIFY_OP ns_o_notify +#define NS_UPDATE_OP ns_o_update + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone + +#define DELETE ns_uop_delete +#define ADD ns_uop_add + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_DNAME ns_t_dname +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +COSMOPOLITAN_C_END_ +#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_NAMESER_H_ */ diff --git a/third_party/musl/ns_parse.c b/third_party/musl/ns_parse.c new file mode 100644 index 000000000..784ec2a14 --- /dev/null +++ b/third_party/musl/ns_parse.c @@ -0,0 +1,201 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/errno.h" +#include "third_party/musl/resolv.h" +#include "third_party/musl/nameser.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +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/third_party/musl/res_init.c b/third_party/musl/res_init.c new file mode 100644 index 000000000..d36e1bbfd --- /dev/null +++ b/third_party/musl/res_init.c @@ -0,0 +1,6 @@ +#include "third_party/musl/resolv.h" + +int res_init() +{ + return 0; +} diff --git a/third_party/musl/res_mkquery.c b/third_party/musl/res_mkquery.c new file mode 100644 index 000000000..98f3d2d3d --- /dev/null +++ b/third_party/musl/res_mkquery.c @@ -0,0 +1,78 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/timespec.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/clock.h" +#include "third_party/musl/resolv.internal.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +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--; + if (l && dname[l-1]=='.') return -1; + n = 17+l+!!l; + if (l>253 || buflen15u || 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_reference(__res_mkquery, res_mkquery); diff --git a/third_party/musl/res_msend.c b/third_party/musl/res_msend.c new file mode 100644 index 000000000..cf9ea2825 --- /dev/null +++ b/third_party/musl/res_msend.c @@ -0,0 +1,363 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/sock/struct/pollfd.h" +#include "libc/calls/struct/timespec.h" +#include "libc/sysv/consts/clock.h" +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/sock/struct/msghdr.h" +#include "libc/sysv/consts/poll.h" +#include "libc/sysv/consts/tcp.h" +#include "libc/sysv/consts/msg.h" +#include "libc/sysv/consts/af.h" +#include "libc/thread/thread.h" +#include "libc/str/str.h" +#include "libc/calls/weirdtypes.h" +#include "libc/sysv/consts/sock.h" +#include "libc/sysv/consts/ipproto.h" +#include "libc/sysv/consts/ipv6.h" +#include "lookup.internal.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +static void cleanup(void *p) +{ + struct pollfd *pfd = p; + for (int i=0; pfd[i].fd >= -1; i++) + if (pfd[i].fd >= 0) + close(pfd[i].fd); +} + +static unsigned long mtime() +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS) + clock_gettime(CLOCK_REALTIME, &ts); + return (unsigned long)ts.tv_sec * 1000 + + ts.tv_nsec / 1000000; +} + +static int start_tcp(struct pollfd *pfd, int family, const void *sa, socklen_t sl, const unsigned char *q, int ql) +{ + struct msghdr mh = { + .msg_name = (void *)sa, + .msg_namelen = sl, + .msg_iovlen = 2, + .msg_iov = (struct iovec [2]){ + { .iov_base = (uint8_t[]){ ql>>8, ql }, .iov_len = 2 }, + { .iov_base = (void *)q, .iov_len = ql } } + }; + int r; + int fd = socket(family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + pfd->fd = fd; + pfd->events = POLLOUT; + if (!setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, + &(int){1}, sizeof(int))) { + r = sendmsg(fd, &mh, MSG_FASTOPEN|MSG_NOSIGNAL); + if (r == ql+2) pfd->events = POLLIN; + if (r >= 0) return r; + if (errno == EINPROGRESS) return 0; + } + r = connect(fd, sa, sl); + if (!r || errno == EINPROGRESS) return 0; + close(fd); + pfd->fd = -1; + return -1; +} + +static void step_mh(struct msghdr *mh, size_t n) +{ + /* Adjust iovec in msghdr to skip first n bytes. */ + while (mh->msg_iovlen && n >= mh->msg_iov->iov_len) { + n -= mh->msg_iov->iov_len; + mh->msg_iov++; + mh->msg_iovlen--; + } + if (!mh->msg_iovlen) return; + mh->msg_iov->iov_base = (char *)mh->msg_iov->iov_base + n; + mh->msg_iov->iov_len -= n; +} + +/* Internal contract for __res_msend[_rc]: asize must be >=512, nqueries + * must be sufficiently small to be safe as VLA size. In practice it's + * either 1 or 2, anyway. */ + +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 = 0; + 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[nqueries+2]; + int qpos[nqueries], apos[nqueries]; + unsigned char alen_buf[nqueries][2]; + int r; + unsigned long t0, t1, t2; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + timeout = 1000*conf->timeout; + attempts = conf->attempts; + + for (nns=0; nnsnns; 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 */ + 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) { + for (i=0; ins[nns].family == AF_INET6; i++); + if (i==nns) { + pthread_setcancelstate(cs, 0); + return -1; + } + fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + family = AF_INET; + sl = sizeof sa.sin; + } + + /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ + if (fd >= 0 && family == AF_INET6) { + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); + for (i=0; i= 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. */ + + for (i=0; i0; i++); + if (i==nqueries) break; + + if (t2-t1 >= retry_interval) { + /* Query all configured namservers in parallel */ + for (i=0; i= 0) { + qpos[i] = r; + apos[i] = 0; + } + continue; + } + } + + for (i=0; i>8, qlens[i] }, .iov_len = 2 }, + { .iov_base = (void *)queries[i], .iov_len = qlens[i] } } + }; + step_mh(&mh, qpos[i]); + r = sendmsg(pfd[i].fd, &mh, MSG_NOSIGNAL); + if (r < 0) goto out; + qpos[i] += r; + if (qpos[i] == qlens[i]+2) + pfd[i].events = POLLIN; + } + } + + for (i=0; i 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/third_party/musl/res_send.c b/third_party/musl/res_send.c new file mode 100644 index 000000000..e727996c1 --- /dev/null +++ b/third_party/musl/res_send.c @@ -0,0 +1,49 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/str.h" +#include "third_party/musl/resolv.internal.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen) +{ + int r; + if (anslen < 512) { + unsigned char buf[512]; + r = __res_send(msg, msglen, buf, sizeof buf); + if (r >= 0) memcpy(answer, buf, r < anslen ? r : anslen); + return r; + } + r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); + return r<0 || !anslen ? -1 : anslen; +} + +__weak_reference(__res_send, res_send); diff --git a/third_party/musl/res_state.c b/third_party/musl/res_state.c new file mode 100644 index 000000000..17fc203e7 --- /dev/null +++ b/third_party/musl/res_state.c @@ -0,0 +1,9 @@ +#include "third_party/musl/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/third_party/musl/resolv.h b/third_party/musl/resolv.h new file mode 100644 index 000000000..344b7ac02 --- /dev/null +++ b/third_party/musl/resolv.h @@ -0,0 +1,134 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_RESOLV_H_ +#define COSMOPOLITAN_THIRD_PARTY_MUSL_RESOLV_H_ +#include "libc/sock/struct/sockaddr6.h" +#include "libc/sock/struct/sockaddr.h" +COSMOPOLITAN_C_START_ + +#define MAXNS 3 +#define MAXDFLSRCH 3 +#define MAXDNSRCH 6 +#define LOCALDOMAINPARTS 2 + +#define RES_TIMEOUT 5 +#define MAXRESOLVSORT 10 +#define RES_MAXNDOTS 15 +#define RES_MAXRETRANS 30 +#define RES_MAXRETRY 5 +#define RES_DFLRETRY 2 +#define RES_MAXTIME 65535 + +/* unused; purely for broken apps */ +typedef struct __res_state { + int retrans; + int retry; + unsigned long options; + int nscount; + struct sockaddr_in nsaddr_list[MAXNS]; +# define nsaddr nsaddr_list[0] + unsigned short id; + char *dnsrch[MAXDNSRCH+1]; + char defdname[256]; + unsigned long pfcode; + unsigned ndots:4; + unsigned nsort:4; + unsigned ipv6_unavail:1; + unsigned unused:23; + struct { + struct in_addr addr; + uint32_t mask; + } sort_list[MAXRESOLVSORT]; + void *qhook; + void *rhook; + int res_h_errno; + int _vcsock; + unsigned _flags; + union { + char pad[52]; + struct { + uint16_t nscount; + uint16_t nsmap[MAXNS]; + int nssocks[MAXNS]; + uint16_t nscount6; + uint16_t nsinit; + struct sockaddr_in6 *nsaddrs[MAXNS]; + unsigned int _initstamp[2]; + } _ext; + } _u; +} *res_state; + +#define __RES 19960801 + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +struct res_sym { + int number; + char *name; + char *humanname; +}; + +#define RES_F_VC 0x00000001 +#define RES_F_CONN 0x00000002 +#define RES_F_EDNS0ERR 0x00000004 + +#define RES_EXHAUSTIVE 0x00000001 + +#define RES_INIT 0x00000001 +#define RES_DEBUG 0x00000002 +#define RES_AAONLY 0x00000004 +#define RES_USEVC 0x00000008 +#define RES_PRIMARY 0x00000010 +#define RES_IGNTC 0x00000020 +#define RES_RECURSE 0x00000040 +#define RES_DEFNAMES 0x00000080 +#define RES_STAYOPEN 0x00000100 +#define RES_DNSRCH 0x00000200 +#define RES_INSECURE1 0x00000400 +#define RES_INSECURE2 0x00000800 +#define RES_NOALIASES 0x00001000 +#define RES_USE_INET6 0x00002000 +#define RES_ROTATE 0x00004000 +#define RES_NOCHECKNAME 0x00008000 +#define RES_KEEPTSIG 0x00010000 +#define RES_BLAST 0x00020000 +#define RES_USEBSTRING 0x00040000 +#define RES_NOIP6DOTINT 0x00080000 +#define RES_USE_EDNS0 0x00100000 +#define RES_SNGLKUP 0x00200000 +#define RES_SNGLKUPREOP 0x00400000 +#define RES_USE_DNSSEC 0x00800000 + +#define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH|RES_NOIP6DOTINT) + +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 + +struct __res_state *__res_state(void); +#define _res (*__res_state()) + +int res_init(void); +int res_query(const char *, int, int, unsigned char *, int); +int res_querydomain(const char *, const char *, int, int, unsigned char *, int); +int res_search(const char *, int, int, unsigned char *, int); +int res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int); +int res_send(const unsigned char *, int, unsigned char *, int); +int dn_comp(const char *, unsigned char *, int, unsigned char **, unsigned char **); +int dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); +int dn_skipname(const unsigned char *, const unsigned char *); + +COSMOPOLITAN_C_END_ +#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_RESOLV_H_ */ diff --git a/third_party/musl/resolv.internal.h b/third_party/musl/resolv.internal.h new file mode 100644 index 000000000..cbf0b5e67 --- /dev/null +++ b/third_party/musl/resolv.internal.h @@ -0,0 +1,11 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_RESOLV_INTERNAL_H_ +#define COSMOPOLITAN_THIRD_PARTY_MUSL_RESOLV_INTERNAL_H_ +COSMOPOLITAN_C_START_ + +int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); +int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int); +int __res_send(const unsigned char *, int, unsigned char *, int); +int __res_msend(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int); + +COSMOPOLITAN_C_END_ +#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_RESOLV_INTERNAL_H_ */ diff --git a/third_party/musl/resolvconf.c b/third_party/musl/resolvconf.c new file mode 100644 index 000000000..1ef490071 --- /dev/null +++ b/third_party/musl/resolvconf.c @@ -0,0 +1,196 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│ vi: set noet ft=c ts=8 tw=8 fenc=utf-8 :vi │ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/fmt/conv.h" +#include "libc/nt/enum/keyaccess.h" +#include "libc/nt/enum/reggetvalueflags.h" +#include "libc/nt/registry.h" +#include "libc/nt/runtime.h" +#include "libc/stdio/internal.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "third_party/musl/lookup.internal.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +// TODO(jart): ipv6 nameservers on windows +// TODO(jart): can we polyfill `search` on windows +static dontinline textwindows int __get_resolv_conf_nt(struct resolvconf *conf) +{ + int64_t hkInterfaces; + uint32_t i, keycount; + + if (RegOpenKeyEx( + kNtHkeyLocalMachine, + u"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", + 0, kNtKeyRead, &hkInterfaces)) { + return __winerr(); + } + + if (RegQueryInfoKey(hkInterfaces, 0, 0, 0, &keycount, 0, 0, 0, 0, 0, 0, 0)) { + RegCloseKey(hkInterfaces); + return __winerr(); + } + + for (i = 0; i < keycount; ++i) { + char value8[128]; + uint32_t valuebytes, uuidlen; + char16_t value[128], uuid[64]; + uuidlen = sizeof(uuid); + if (!RegEnumKeyEx(hkInterfaces, i, uuid, &uuidlen, 0, 0, 0, 0) && + ((!RegGetValue(hkInterfaces, uuid, u"DhcpIpAddress", + kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, + ((valuebytes = sizeof(value)), &valuebytes)) && + valuebytes > 2 * sizeof(char16_t)) || + (!RegGetValue(hkInterfaces, uuid, u"IpAddress", + kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, + ((valuebytes = sizeof(value)), &valuebytes)) && + valuebytes > 2 * sizeof(char16_t))) && + ((!RegGetValue(hkInterfaces, uuid, u"DhcpNameServer", + kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, + ((valuebytes = sizeof(value)), &valuebytes)) && + valuebytes > 2 * sizeof(char16_t)) || + (!RegGetValue(hkInterfaces, uuid, u"NameServer", + kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, + ((valuebytes = sizeof(value)), &valuebytes)) && + valuebytes > 2 * sizeof(char16_t)))) { + char *state, *addr, *tmp; + tprecode16to8(value8, sizeof(value8), value); + tmp = value8; + while ((addr = strtok_r(tmp, ", ", &state))) { + uint32_t ip; + if (inet_pton(AF_INET, addr, &ip) == 1) { + if (conf->nns < MAXNS) { + conf->ns[conf->nns].family = AF_INET; + conf->ns[conf->nns].scopeid = 0; + memcpy(conf->ns[conf->nns].addr, &ip, 4); + ++conf->nns; + } + } + tmp = NULL; + } + } + } + + RegCloseKey(hkInterfaces); + return 0; +} + +int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz) +{ + FILE *f; + int nns = 0; + char line[256]; + + conf->ndots = 1; + conf->timeout = 5; + conf->attempts = 2; + if (search) *search = 0; + + f = fopen("/etc/resolv.conf", "rb"); + if (!f) { + if (errno == ENOENT || + errno == ENOTDIR || + errno == EACCES) { + if (IsWindows()) + return __get_resolv_conf_nt(conf); + goto no_resolv_conf; + } else { + 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(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/tool/net/BUILD.mk b/tool/net/BUILD.mk index b1869d369..40c8e1867 100644 --- a/tool/net/BUILD.mk +++ b/tool/net/BUILD.mk @@ -21,6 +21,7 @@ TOOL_NET_COMS = \ o/$(MODE)/tool/net/redbean.com \ o/$(MODE)/tool/net/redbean-demo.com \ o/$(MODE)/tool/net/redbean-static.com \ + o/$(MODE)/tool/net/libresolv_query.com \ o/$(MODE)/tool/net/redbean-unsecure.com \ o/$(MODE)/tool/net/redbean-original.com @@ -62,6 +63,7 @@ TOOL_NET_DIRECTDEPS = \ THIRD_PARTY_LUA \ THIRD_PARTY_LUA_UNIX \ THIRD_PARTY_MAXMIND \ + THIRD_PARTY_MUSL \ THIRD_PARTY_MBEDTLS \ THIRD_PARTY_REGEX \ THIRD_PARTY_SQLITE3 \ diff --git a/tool/net/libresolv_query.c b/tool/net/libresolv_query.c new file mode 100644 index 000000000..956e0c250 --- /dev/null +++ b/tool/net/libresolv_query.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2013 by Wil Tan + * + * Based on dump_dns.c from the dnscap + * originally written by Paul Vixie. + * + * Copyright (c) 2007 by Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "libc/calls/typedef/u.h" +#include "libc/errno.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/sock.h" +#include "libc/stdio/internal.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "third_party/musl/nameser.h" +#include "third_party/musl/resolv.h" + +const char *_res_opcodes[] = { + "QUERY", // + "IQUERY", // + "CQUERYM", // + "CQUERYU", // + "NOTIFY", // + "UPDATE", // + "6", // + "7", // + "8", // + "9", // + "10", // + "11", // + "12", // + "13", // + "ZONEINIT", // + "ZONEREF", // +}; + +#define MY_GET16(s, cp) \ + do { \ + register const u_char *t_cp = (const u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) | ((u_int16_t)t_cp[1]); \ + (cp) += NS_INT16SZ; \ + } while (0) + +#define MY_GET32(l, cp) \ + do { \ + register const u_char *t_cp = (const u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) | ((u_int32_t)t_cp[1] << 16) | \ + ((u_int32_t)t_cp[2] << 8) | ((u_int32_t)t_cp[3]); \ + (cp) += NS_INT32SZ; \ + } while (0) + +static void dump_dns_rr(ns_msg *msg, ns_rr *rr, ns_sect sect, FILE *trace) { + char buf[NS_MAXDNAME]; + u_int class, type; + const u_char *rd; + u_int32_t soa[5]; + u_int16_t mx; + int n; + + class = ns_rr_class(*rr); + type = ns_rr_type(*rr); + fprintf(trace, "%s,%d,%d", ns_rr_name(*rr), class, type); + if (sect == ns_s_qd) return; + fprintf(trace, ",%lu", (u_long)ns_rr_ttl(*rr)); + rd = ns_rr_rdata(*rr); + switch (type) { + case ns_t_soa: + n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg), rd, buf, + sizeof buf); + if (n < 0) goto error; + putc(',', trace); + fputs(buf, trace); + rd += n; + n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg), rd, buf, + sizeof buf); + if (n < 0) goto error; + putc(',', trace); + fputs(buf, trace); + rd += n; + if (ns_msg_end(*msg) - rd < 5 * NS_INT32SZ) goto error; + for (n = 0; n < 5; n++) MY_GET32(soa[n], rd); + sprintf(buf, "%u,%u,%u,%u,%u", soa[0], soa[1], soa[2], soa[3], soa[4]); + break; + case ns_t_a: + inet_ntop(AF_INET, rd, buf, sizeof buf); + break; + case ns_t_aaaa: + inet_ntop(AF_INET6, rd, buf, sizeof buf); + break; + case ns_t_mx: + MY_GET16(mx, rd); + fprintf(trace, ",%u", mx); + /* FALLTHROUGH */ + case ns_t_ns: + case ns_t_ptr: + case ns_t_cname: + n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg), rd, buf, + sizeof buf); + if (n < 0) goto error; + break; + case ns_t_txt: + snprintf(buf, (size_t)rd[0] + 1, "%s", rd + 1); + break; + default: + error: + sprintf(buf, "[%u]", ns_rr_rdlen(*rr)); + } + if (buf[0] != '\0') { + putc(',', trace); + fputs(buf, trace); + } +} + +static void dump_dns_sect(ns_msg *msg, ns_sect sect, FILE *trace, + const char *endline) { + int rrnum, rrmax; + const char *sep; + ns_rr rr; + + rrmax = ns_msg_count(*msg, sect); + if (rrmax == 0) { + fputs(" 0", trace); + return; + } + fprintf(trace, " %s%d", endline, rrmax); + sep = ""; + for (rrnum = 0; rrnum < rrmax; rrnum++) { + if (ns_parserr(msg, sect, rrnum, &rr)) { + fputs(strerror(errno), trace); + return; + } + fprintf(trace, " %s", sep); + dump_dns_rr(msg, &rr, sect, trace); + sep = endline; + } +} + +void dump_dns(const u_char *payload, size_t paylen, FILE *trace, + const char *endline) { + u_int opcode, rcode, id; + const char *sep; + ns_msg msg; + + fprintf(trace, " %sdns ", endline); + if (ns_initparse(payload, paylen, &msg) < 0) { + fputs(strerror(errno), trace); + return; + } + opcode = ns_msg_getflag(msg, ns_f_opcode); + rcode = ns_msg_getflag(msg, ns_f_rcode); + id = ns_msg_id(msg); + fprintf(trace, "%s,%d,%u", _res_opcodes[opcode], rcode, id); + sep = ","; +#define FLAG(t, f) \ + if (ns_msg_getflag(msg, f)) { \ + fprintf(trace, "%s%s", sep, t); \ + sep = "|"; \ + } + FLAG("qr", ns_f_qr); + FLAG("aa", ns_f_aa); + FLAG("tc", ns_f_tc); + FLAG("rd", ns_f_rd); + FLAG("ra", ns_f_ra); + FLAG("z", ns_f_z); + FLAG("ad", ns_f_ad); + FLAG("cd", ns_f_cd); +#undef FLAG + + dump_dns_sect(&msg, ns_s_an, trace, endline); +} + +int main() { + ShowCrashReports(); + u_char answer[1024] = ""; + res_init(); + int rv = res_query("google.com", ns_c_in, ns_t_txt, answer, sizeof(answer)); + // printf("rv=%d\n", rv); + dump_dns(answer, rv, stdout, "\n"); + printf("\n"); +}