Make minor improvements

This commit is contained in:
Justine Tunney 2021-05-15 21:53:26 -07:00
parent 221817e537
commit 4864565198
41 changed files with 394 additions and 367 deletions

View file

@ -8,11 +8,13 @@
*/ */
#endif #endif
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dns/dns.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/ipproto.h"
@ -28,7 +30,12 @@
* Implemented because BusyBox's netcat doesn't detect remote close and * Implemented because BusyBox's netcat doesn't detect remote close and
* lingers in the CLOSE_WAIT wait possibly due to file descriptor leaks * lingers in the CLOSE_WAIT wait possibly due to file descriptor leaks
* *
* Once upon time we called this command "Telnet" * Here's an example usage:
*
* make -j8 o//examples/nc.com
* printf 'GET /\r\n\r\n' | o//examples/nc.com justine.lol 80
*
* Once upon time we called this command "telnet"
*/ */
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -36,15 +43,26 @@ int main(int argc, char *argv[]) {
size_t i, got; size_t i, got;
char buf[1500]; char buf[1500];
int err, toto, sock; int err, toto, sock;
struct addrinfo *ai = NULL;
struct linger linger = {true, 1}; struct linger linger = {true, 1};
struct sockaddr_in addr = {AF_INET};
struct pollfd fds[2] = {{-1, POLLIN}, {-1, POLLIN}}; struct pollfd fds[2] = {{-1, POLLIN}, {-1, POLLIN}};
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
if (argc != 3) exit(1); if (argc != 3) exit(1);
inet_pton(AF_INET, argv[1], &addr.sin_addr); switch ((rc = getaddrinfo(argv[1], argv[2], &hint, &ai))) {
addr.sin_port = htons(atoi(argv[2])); case EAI_SUCCESS:
break;
case EAI_SYSTEM:
perror("getaddrinfo");
exit(1);
default:
fputs("EAI_", stderr);
fputs(gai_strerror(rc), stderr);
fputs("\n", stderr);
exit(1);
}
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { if ((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) {
perror("socket"); perror("socket");
exit(1); exit(1);
} }
@ -54,7 +72,7 @@ int main(int argc, char *argv[]) {
exit(1); exit(1);
} }
if (connect(sock, &addr, sizeof(addr)) == -1) { if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
perror("connect"); perror("connect");
exit(1); exit(1);
} }
@ -108,5 +126,6 @@ int main(int argc, char *argv[]) {
exit(1); exit(1);
} }
freeaddrinfo(ai);
return 0; return 0;
} }

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/safemacros.internal.h"
#include "libc/dns/dns.h" #include "libc/dns/dns.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) { forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) {
@ -36,12 +36,15 @@ forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) {
/** /**
* Compares DNS hostnames in reverse lexicographical asciibetical order. * Compares DNS hostnames in reverse lexicographical asciibetical order.
* @return <0, 0, or >0 * @return <0, 0, or >0
* @see test/libc/dns/dnsnamecmp_test.c (the code that matters) * @see test/libc/dns/comparednsnames_test.c (the code that matters)
*/ */
int dnsnamecmp(const char *A, const char *B) { int CompareDnsNames(const char *A, const char *B) {
int res;
bool first;
size_t n, m, i, j;
if (A == B) return 0; if (A == B) return 0;
size_t n = strlen(A); n = strlen(A);
size_t m = strlen(B); m = strlen(B);
if (!n || !m || ((A[n - 1] == '.') ^ (B[m - 1] == '.'))) { if (!n || !m || ((A[n - 1] == '.') ^ (B[m - 1] == '.'))) {
if (n && m && A[n - 1] == '.' && strchr(B, '.')) { if (n && m && A[n - 1] == '.' && strchr(B, '.')) {
--m; --m;
@ -51,9 +54,9 @@ int dnsnamecmp(const char *A, const char *B) {
return A[n ? n - 1 : 0] - B[m ? m - 1 : 0]; return A[n ? n - 1 : 0] - B[m ? m - 1 : 0];
} }
} }
size_t i = n; i = n;
size_t j = m; j = m;
bool first = true; first = true;
for (;;) { for (;;) {
FindDnsLabel(A, &i, &n); FindDnsLabel(A, &i, &n);
FindDnsLabel(B, &j, &m); FindDnsLabel(B, &j, &m);
@ -62,8 +65,7 @@ int dnsnamecmp(const char *A, const char *B) {
if (!i && j) return 1; if (!i && j) return 1;
if (!j && i) return -1; if (!j && i) return -1;
} }
int res; if ((res = strncasecmp(&A[i], &B[j], MIN(n - i + 1, m - j + 1)))) {
if ((res = strncasecmp(&A[i], &B[j], min(n - i + 1, m - j + 1)))) {
return res; return res;
} }
if (!i || !j) { if (!i || !j) {

View file

@ -57,9 +57,9 @@ int getaddrinfo(const char *, const char *, const struct addrinfo *,
struct addrinfo **) paramsnonnull((4)); struct addrinfo **) paramsnonnull((4));
int freeaddrinfo(struct addrinfo *); int freeaddrinfo(struct addrinfo *);
const char *gai_strerror(int); const char *gai_strerror(int);
int dnsnamecmp(const char *, const char *) paramsnonnull(); int CompareDnsNames(const char *, const char *) paramsnonnull();
int pascalifydnsname(uint8_t *, size_t, const char *) paramsnonnull(); int PascalifyDnsName(uint8_t *, size_t, const char *) paramsnonnull();
int resolvedns(const struct ResolvConf *, int, const char *, struct sockaddr *, int ResolveDns(const struct ResolvConf *, int, const char *, struct sockaddr *,
uint32_t) paramsnonnull(); uint32_t) paramsnonnull();
struct addrinfo *newaddrinfo(uint16_t); struct addrinfo *newaddrinfo(uint16_t);

View file

@ -21,43 +21,37 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
* Serializes DNS message header to wire. * Serializes DNS message h to wire.
* *
* @return number of bytes written (always 12) or -1 w/ errno * @return number of bytes written (always 12) or -1 w/ errno
* @see pascalifydnsname() * @see pascalifydnsname()
*/ */
int serializednsheader(uint8_t *buf, size_t size, void SerializeDnsHeader(uint8_t p[restrict 12], const struct DnsHeader *h) {
const struct DnsHeader header) { p[0x0] = h->id >> 8;
if (size < 12) return enospc(); p[0x1] = h->id;
buf[0x0] = header.id >> 010u; p[0x2] = h->bf1;
buf[0x1] = header.id >> 000u; p[0x3] = h->bf2;
buf[0x2] = header.bf1; p[0x4] = h->qdcount >> 8;
buf[0x3] = header.bf2; p[0x5] = h->qdcount;
buf[0x4] = header.qdcount >> 010u; p[0x6] = h->ancount >> 8;
buf[0x5] = header.qdcount >> 000u; p[0x7] = h->ancount;
buf[0x6] = header.ancount >> 010u; p[0x8] = h->nscount >> 8;
buf[0x7] = header.ancount >> 000u; p[0x9] = h->nscount;
buf[0x8] = header.nscount >> 010u; p[0xa] = h->arcount >> 8;
buf[0x9] = header.nscount >> 000u; p[0xb] = h->arcount;
buf[0xa] = header.arcount >> 010u;
buf[0xb] = header.arcount >> 000u;
return 12;
} }
/** /**
* Serializes DNS message header to wire. * Serializes DNS message h to wire.
* *
* @return number of bytes read (always 12) or -1 w/ errno * @return number of bytes read (always 12) or -1 w/ errno
*/ */
int deserializednsheader(struct DnsHeader *header, const uint8_t *buf, void DeserializeDnsHeader(struct DnsHeader *h, const uint8_t p[restrict 12]) {
size_t size) { h->id = READ16BE(p);
if (size < 12) return ebadmsg(); h->bf1 = p[2];
header->id = READ16BE(buf + 0); h->bf2 = p[3];
header->bf1 = buf[2]; h->qdcount = READ16BE(p + 4);
header->bf2 = buf[3]; h->ancount = READ16BE(p + 6);
header->qdcount = READ16BE(buf + 4); h->nscount = READ16BE(p + 8);
header->ancount = READ16BE(buf + 6); h->arcount = READ16BE(p + 10);
header->nscount = READ16BE(buf + 8);
header->arcount = READ16BE(buf + 10);
return 12;
} }

View file

@ -13,8 +13,8 @@ struct DnsHeader {
uint16_t arcount; /* additional record count */ uint16_t arcount; /* additional record count */
}; };
int serializednsheader(uint8_t *, size_t, const struct DnsHeader); void SerializeDnsHeader(uint8_t[restrict 12], const struct DnsHeader *);
int deserializednsheader(struct DnsHeader *, const uint8_t *, size_t); void DeserializeDnsHeader(struct DnsHeader *, const uint8_t[restrict 12]);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -9,7 +9,7 @@ struct DnsQuestion {
uint16_t qclass; uint16_t qclass;
}; };
int serializednsquestion(uint8_t *, size_t, struct DnsQuestion); int SerializeDnsQuestion(uint8_t *, size_t, const struct DnsQuestion *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -22,13 +22,13 @@
/** /**
* Frees addresses returned by getaddrinfo(). * Frees addresses returned by getaddrinfo().
*/ */
int freeaddrinfo(struct addrinfo *addrs) { int freeaddrinfo(struct addrinfo *ai) {
struct addrinfo *next; struct addrinfo *next;
while (addrs) { while (ai) {
/* we assume ai_addr and ai_canonname are shoehorned */ /* we assume ai_addr and ai_canonname are shoehorned */
next = addrs->ai_next; next = ai->ai_next;
free(addrs); free(ai);
addrs = next; ai = next;
} }
return 0; return 0;
} }

View file

@ -20,9 +20,9 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
/** /**
* Frees HOSTS.TXT data structure populated by parsehoststxt(). * Frees HOSTS.TXT data structure populated by ParseHostsTxt().
*/ */
void freehoststxt(struct HostsTxt **ht) { void FreeHostsTxt(struct HostsTxt **ht) {
if (*ht) { if (*ht) {
free_s(&(*ht)->entries.p); free_s(&(*ht)->entries.p);
free_s(&(*ht)->strings.p); free_s(&(*ht)->strings.p);

View file

@ -20,9 +20,9 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
/** /**
* Frees resolv.conf data structure populated by parseresolvconf(). * Frees resolv.conf data structure populated by ParseResolvConf().
*/ */
void freeresolvconf(struct ResolvConf **rvp) { void FreeResolvConf(struct ResolvConf **rvp) {
if (*rvp) { if (*rvp) {
free_s(&(*rvp)->nameservers.p); free_s(&(*rvp)->nameservers.p);
free_s(rvp); free_s(rvp);

View file

@ -67,13 +67,13 @@ int getaddrinfo(const char *name, const char *service,
} else if (hints && (hints->ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST) { } else if (hints && (hints->ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST) {
freeaddrinfo(ai); freeaddrinfo(ai);
return EAI_NONAME; return EAI_NONAME;
} else if (resolvehoststxt(gethoststxt(), AF_INET, name, ai->ai_addr, } else if (ResolveHostsTxt(GetHostsTxt(), AF_INET, name, ai->ai_addr,
sizeof(ai->ai_addr4), &canon) > 0) { sizeof(ai->ai_addr4), &canon) > 0) {
memcpy(ai->ai_canonname, canon, min(strlen(canon), DNS_NAME_MAX) + 1); memcpy(ai->ai_canonname, canon, min(strlen(canon), DNS_NAME_MAX) + 1);
*res = ai; *res = ai;
return 0; return 0;
} else { } else {
rc = resolvedns(getresolvconf(), AF_INET, name, ai->ai_addr, rc = ResolveDns(GetResolvConf(), AF_INET, name, ai->ai_addr,
sizeof(ai->ai_addr4)); sizeof(ai->ai_addr4));
if (rc > 0) { if (rc > 0) {
*res = ai; *res = ai;

View file

@ -53,7 +53,7 @@ static textwindows noinline char *getnthoststxtpath(char *pathbuf,
* *
* @note yoinking realloc() ensures there's no size limits * @note yoinking realloc() ensures there's no size limits
*/ */
const struct HostsTxt *gethoststxt(void) { const struct HostsTxt *GetHostsTxt(void) {
FILE *f; FILE *f;
const char *path; const char *path;
char pathbuf[PATH_MAX]; char pathbuf[PATH_MAX];
@ -65,16 +65,16 @@ const struct HostsTxt *gethoststxt(void) {
init->ht.entries.p = init->entries; init->ht.entries.p = init->entries;
init->ht.strings.n = pushpop(ARRAYLEN(init->strings)); init->ht.strings.n = pushpop(ARRAYLEN(init->strings));
init->ht.strings.p = init->strings; init->ht.strings.p = init->strings;
__cxa_atexit(freehoststxt, &g_hoststxt, NULL); __cxa_atexit(FreeHostsTxt, &g_hoststxt, NULL);
path = "/etc/hosts"; path = "/etc/hosts";
if (IsWindows()) { if (IsWindows()) {
path = firstnonnull(getnthoststxtpath(pathbuf, ARRAYLEN(pathbuf)), path); path = firstnonnull(getnthoststxtpath(pathbuf, ARRAYLEN(pathbuf)), path);
} }
if (!(f = fopen(path, "r")) || parsehoststxt(g_hoststxt, f) == -1) { if (!(f = fopen(path, "r")) || ParseHostsTxt(g_hoststxt, f) == -1) {
/* TODO(jart): Elevate robustness. */ /* TODO(jart): Elevate robustness. */
} }
fclose(f); fclose(f);
sorthoststxt(g_hoststxt); SortHostsTxt(g_hoststxt);
} }
return g_hoststxt; return g_hoststxt;
} }

View file

@ -38,41 +38,39 @@
* this function will append * this function will append
* @return number of nameservers appended, or -1 w/ errno * @return number of nameservers appended, or -1 w/ errno
*/ */
textwindows int getntnameservers(struct ResolvConf *resolv) { textwindows int GetNtNameServers(struct ResolvConf *resolv) {
int rc; int rc;
char value8[128]; char value8[128];
int64_t hkInterfaces; int64_t hkInterfaces;
struct sockaddr_in nameserver; struct sockaddr_in nameserver;
char16_t value[128], ifaceuuid[64]; char16_t value[128], uuid[64];
uint32_t i, keycount, valuebytes, ifaceuuidlen; uint32_t i, keycount, valuebytes, uuidlen;
keycount = 0; keycount = 0;
hkInterfaces = kNtInvalidHandleValue; hkInterfaces = kNtInvalidHandleValue;
if (!RegOpenKeyEx( if (!RegOpenKeyEx(
kNtHkeyLocalMachine, kNtHkeyLocalMachine,
u"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", u"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
0, kNtKeyRead, &hkInterfaces) && 0, kNtKeyRead, &hkInterfaces) &&
!RegQueryInfoKey(hkInterfaces, NULL, NULL, NULL, &keycount, NULL, NULL, !RegQueryInfoKey(hkInterfaces, 0, 0, 0, &keycount, 0, 0, 0, 0, 0, 0, 0)) {
NULL, NULL, NULL, NULL, NULL)) {
nameserver.sin_family = AF_INET; nameserver.sin_family = AF_INET;
nameserver.sin_port = htons(DNS_PORT); nameserver.sin_port = htons(DNS_PORT);
rc = 0; rc = 0;
for (i = 0; i < keycount; ++i) { for (i = 0; i < keycount; ++i) {
ifaceuuidlen = sizeof(ifaceuuid); uuidlen = sizeof(uuid);
if (!RegEnumKeyEx(hkInterfaces, i, ifaceuuid, &ifaceuuidlen, NULL, NULL, if (!RegEnumKeyEx(hkInterfaces, i, uuid, &uuidlen, 0, 0, 0, 0) &&
NULL, NULL) && ((!RegGetValue(hkInterfaces, uuid, u"DhcpIpAddress",
((!RegGetValue(hkInterfaces, ifaceuuid, u"DhcpIpAddress",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) && ((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t)) || valuebytes > 2 * sizeof(char16_t)) ||
(!RegGetValue(hkInterfaces, ifaceuuid, u"IpAddress", (!RegGetValue(hkInterfaces, uuid, u"IpAddress",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) && ((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t))) && valuebytes > 2 * sizeof(char16_t))) &&
((!RegGetValue(hkInterfaces, ifaceuuid, u"DhcpNameServer", ((!RegGetValue(hkInterfaces, uuid, u"DhcpNameServer",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) && ((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t)) || valuebytes > 2 * sizeof(char16_t)) ||
(!RegGetValue(hkInterfaces, ifaceuuid, u"NameServer", (!RegGetValue(hkInterfaces, uuid, u"NameServer",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value, kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) && ((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t)))) { valuebytes > 2 * sizeof(char16_t)))) {

View file

@ -34,7 +34,7 @@ static struct ResolvConfInitialStaticMemory {
/** /**
* Returns singleton with DNS server address. * Returns singleton with DNS server address.
*/ */
const struct ResolvConf *getresolvconf(void) { const struct ResolvConf *GetResolvConf(void) {
int rc; int rc;
FILE *f; FILE *f;
struct ResolvConfInitialStaticMemory *init; struct ResolvConfInitialStaticMemory *init;
@ -43,16 +43,16 @@ const struct ResolvConf *getresolvconf(void) {
g_resolvconf = &init->rv; g_resolvconf = &init->rv;
pushmov(&init->rv.nameservers.n, ARRAYLEN(init->nameservers)); pushmov(&init->rv.nameservers.n, ARRAYLEN(init->nameservers));
init->rv.nameservers.p = init->nameservers; init->rv.nameservers.p = init->nameservers;
__cxa_atexit(freeresolvconf, &g_resolvconf, NULL); __cxa_atexit(FreeResolvConf, &g_resolvconf, NULL);
if (!IsWindows()) { if (!IsWindows()) {
if ((f = fopen("/etc/resolv.conf", "r"))) { if ((f = fopen("/etc/resolv.conf", "r"))) {
rc = parseresolvconf(g_resolvconf, f); rc = ParseResolvConf(g_resolvconf, f);
} else { } else {
rc = -1; rc = -1;
} }
fclose(f); fclose(f);
} else { } else {
rc = getntnameservers(g_resolvconf); rc = GetNtNameServers(g_resolvconf);
} }
if (rc == -1 && !IsTiny()) { if (rc == -1 && !IsTiny()) {
/* TODO(jart): Elevate robustness. */ /* TODO(jart): Elevate robustness. */

View file

@ -1,26 +1,23 @@
#ifndef COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_ #ifndef COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_
#define COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_ #define COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
struct FILE;
struct sockaddr;
struct HostsTxtEntry { struct HostsTxtEntry {
unsigned char ip[4]; /* inet_ntop(AF_INET, he->ip, buf, size) */ uint8_t ip[4]; /* inet_ntop(AF_INET, he->ip, buf, size) */
uint32_t name; /* &ht->strings.p[he->name] */ uint32_t name; /* &ht->strings.p[he->name] */
uint32_t canon; /* &ht->strings.p[he->canon] */ uint32_t canon; /* &ht->strings.p[he->canon] */
}; };
struct HostsTxtEntries { struct HostsTxtEntries {
size_t i; size_t i, n;
size_t n;
struct HostsTxtEntry *p; struct HostsTxtEntry *p;
}; };
struct HostsTxtStrings { struct HostsTxtStrings {
size_t i; size_t i, n;
size_t n;
char *p; char *p;
}; };
@ -29,11 +26,11 @@ struct HostsTxt {
struct HostsTxtStrings strings; struct HostsTxtStrings strings;
}; };
const struct HostsTxt *gethoststxt(void) returnsnonnull; const struct HostsTxt *GetHostsTxt(void) returnsnonnull;
void freehoststxt(struct HostsTxt **) paramsnonnull(); void FreeHostsTxt(struct HostsTxt **) paramsnonnull();
int parsehoststxt(struct HostsTxt *, struct FILE *) paramsnonnull(); int ParseHostsTxt(struct HostsTxt *, FILE *) paramsnonnull();
void sorthoststxt(struct HostsTxt *) paramsnonnull(); void SortHostsTxt(struct HostsTxt *) paramsnonnull();
int resolvehoststxt(const struct HostsTxt *, int, const char *, int ResolveHostsTxt(const struct HostsTxt *, int, const char *,
struct sockaddr *, uint32_t, const char **) struct sockaddr *, uint32_t, const char **)
paramsnonnull((1, 3)); paramsnonnull((1, 3));

View file

@ -43,7 +43,7 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @see hoststxtsort() which is the logical next step * @see hoststxtsort() which is the logical next step
*/ */
int parsehoststxt(struct HostsTxt *ht, FILE *f) { int ParseHostsTxt(struct HostsTxt *ht, FILE *f) {
char *line; char *line;
size_t linesize; size_t linesize;
struct HostsTxtEntry entry; struct HostsTxtEntry entry;

View file

@ -41,7 +41,7 @@
* @param f is an open stream with file content * @param f is an open stream with file content
* @return number of nameservers appended, or -1 w/ errno * @return number of nameservers appended, or -1 w/ errno
*/ */
int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) { int ParseResolvConf(struct ResolvConf *resolv, struct FILE *f) {
/* TODO(jart): options ndots:5 */ /* TODO(jart): options ndots:5 */
int rc; int rc;
char *line; char *line;
@ -49,7 +49,7 @@ int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) {
struct sockaddr_in nameserver; struct sockaddr_in nameserver;
char *directive, *value, *tok, *comment; char *directive, *value, *tok, *comment;
rc = 0; rc = 0;
line = NULL; line = 0;
linesize = 0; linesize = 0;
nameserver.sin_family = AF_INET; nameserver.sin_family = AF_INET;
nameserver.sin_port = htons(DNS_PORT); nameserver.sin_port = htons(DNS_PORT);

View file

@ -30,7 +30,7 @@
* @param name is a dotted NUL-terminated hostname string * @param name is a dotted NUL-terminated hostname string
* @return bytes written (excluding NUL) or -1 w/ errno * @return bytes written (excluding NUL) or -1 w/ errno
*/ */
int pascalifydnsname(uint8_t *buf, size_t size, const char *name) { int PascalifyDnsName(uint8_t *buf, size_t size, const char *name) {
size_t i, j, k, namelen; size_t i, j, k, namelen;
if ((namelen = strlen(name)) > DNS_NAME_MAX) return enametoolong(); if ((namelen = strlen(name)) > DNS_NAME_MAX) return enametoolong();
i = 0; i = 0;

View file

@ -14,10 +14,10 @@ struct ResolvConf {
struct Nameservers nameservers; struct Nameservers nameservers;
}; };
const struct ResolvConf *getresolvconf(void) returnsnonnull; const struct ResolvConf *GetResolvConf(void) returnsnonnull;
int parseresolvconf(struct ResolvConf *, struct FILE *) paramsnonnull(); int ParseResolvConf(struct ResolvConf *, struct FILE *) paramsnonnull();
void freeresolvconf(struct ResolvConf **) paramsnonnull(); void FreeResolvConf(struct ResolvConf **) paramsnonnull();
int getntnameservers(struct ResolvConf *) paramsnonnull(); int GetNtNameServers(struct ResolvConf *) paramsnonnull();
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -38,7 +38,7 @@
/** /**
* Queries Domain Name System for address associated with name. * Queries Domain Name System for address associated with name.
* *
* @param resolvconf can be getresolvconf() * @param resolvconf can be GetResolvConf()
* @param af can be AF_INET, AF_UNSPEC * @param af can be AF_INET, AF_UNSPEC
* @param name can be a local or fully-qualified hostname * @param name can be a local or fully-qualified hostname
* @param addr should point to a struct sockaddr_in; if this function * @param addr should point to a struct sockaddr_in; if this function
@ -47,65 +47,62 @@
* @return number of matches found, or -1 w/ errno * @return number of matches found, or -1 w/ errno
* @error EAFNOSUPPORT. ENETDOWN, ENAMETOOLONG, EBADMSG * @error EAFNOSUPPORT. ENETDOWN, ENAMETOOLONG, EBADMSG
*/ */
int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name, int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
struct sockaddr *addr, uint32_t addrsize) { struct sockaddr *addr, uint32_t addrsize) {
size_t msgsize; int rc, fd, n;
int res, fd, rc, rc2; struct DnsQuestion q;
struct sockaddr_in *addr4; struct DnsHeader h, h2;
struct DnsQuestion question; struct sockaddr_in *a4;
uint8_t *p, *pe, msg[512];
uint16_t rtype, rclass, rdlength; uint16_t rtype, rclass, rdlength;
uint8_t *p, *pe, *outmsg, *inmsg;
struct DnsHeader header, response;
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport(); if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
if (!resolvconf->nameservers.i) return 0; if (!resolvconf->nameservers.i) return 0;
memset(&header, 0, sizeof(header)); memset(&h, 0, sizeof(h));
header.id = rand32(); rc = ebadmsg();
header.bf1 = 1; /* recursion desired */ h.id = rand32();
header.qdcount = 1; h.bf1 = 1; /* recursion desired */
question.qname = name; h.qdcount = 1;
question.qtype = DNS_TYPE_A; q.qname = name;
question.qclass = DNS_CLASS_IN; q.qtype = DNS_TYPE_A;
res = -1; q.qclass = DNS_CLASS_IN;
if ((outmsg = malloc(kMsgMax)) && (inmsg = malloc(kMsgMax)) && memset(msg, 0, sizeof(msg));
(rc = serializednsheader(outmsg, kMsgMax, header)) != -1 && SerializeDnsHeader(msg, &h);
(rc2 = serializednsquestion(outmsg + rc, kMsgMax - rc, question)) != -1) { if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
msgsize = rc + rc2; if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1 && if (sendto(fd, msg, 12 + n, 0, resolvconf->nameservers.p,
sendto(fd, outmsg, msgsize, 0, (void *)&resolvconf->nameservers.p[0], sizeof(*resolvconf->nameservers.p)) == 12 + n &&
sizeof(resolvconf->nameservers.p[0])) == msgsize) { (n = read(fd, msg, 512)) >= 12) {
if ((rc = recv(fd, inmsg, kMsgMax, 0)) != -1 && DeserializeDnsHeader(&h2, msg);
(rc2 = deserializednsheader(&response, inmsg, rc)) != -1 && if (h2.id == h.id) {
response.id == header.id) { rc = 0;
res = 0; if (h2.ancount) {
if (response.ancount) { p = msg + 12;
p = inmsg + rc2; pe = msg + n;
pe = inmsg + rc; while (p < pe && h2.qdcount) {
while (p < pe && response.qdcount) { p += strnlen((char *)p, pe - p) + 1 + 4;
p += strnlen((char *)p, pe - p) + 1 + 4; h2.qdcount--;
response.qdcount--; }
if (p + 1 < pe) {
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
p += 2;
} else {
p += strnlen((char *)p, pe - p) + 1;
} }
if (p + 1 < pe) { if (p + 2 + 2 + 4 + 2 < pe) {
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */ rtype = READ16BE(p), p += 2;
p += 2; rclass = READ16BE(p), p += 2;
} else { /* ttl */ p += 4;
p += strnlen((char *)p, pe - p) + 1; rdlength = READ16BE(p), p += 2;
} if (p + rdlength <= pe && rdlength == 4 &&
if (p + 2 + 2 + 4 + 2 < pe) { (rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
rtype = READ16BE(p), p += 2; rc = 1;
rclass = READ16BE(p), p += 2; if (addrsize) {
/* ttl */ p += 4; if (addrsize >= kMinSockaddr4Size) {
rdlength = READ16BE(p), p += 2; a4 = (struct sockaddr_in *)addr;
if (p + rdlength <= pe && rdlength == 4 && a4->sin_family = AF_INET;
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) { memcpy(&a4->sin_addr.s_addr, p, 4);
res = 1; } else {
if (addrsize) { rc = einval();
if (addrsize >= kMinSockaddr4Size) {
addr4 = (struct sockaddr_in *)addr;
addr4->sin_family = AF_INET;
memcpy(&addr4->sin_addr.s_addr, p, 4);
} else {
res = einval();
}
} }
} }
} }
@ -113,8 +110,7 @@ int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
} }
} }
} }
res |= close(fd);
} }
free(outmsg); close(fd);
return res; return rc;
} }

View file

@ -27,16 +27,16 @@
static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry, static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
const char *strings) { const char *strings) {
return dnsnamecmp(node, &strings[entry->name]); return CompareDnsNames(node, &strings[entry->name]);
} }
/** /**
* Finds address associated with name in HOSTS.TXT table. * Finds address associated with name in HOSTS.TXT table.
* *
* This function performs binary search, so sorthoststxt() must be * This function performs binary search, so SortHostsTxt() must be
* called on the table beforehand. * called on the table beforehand.
* *
* @param ht can be gethoststxt() * @param ht can be GetHostsTxt()
* @param af can be AF_INET, AF_UNSPEC * @param af can be AF_INET, AF_UNSPEC
* @param name can be a local or fully-qualified hostname * @param name can be a local or fully-qualified hostname
* @param addr should point to a struct sockaddr_in; if this function * @param addr should point to a struct sockaddr_in; if this function
@ -46,7 +46,7 @@ static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
* @return number of matches found, or -1 w/ errno * @return number of matches found, or -1 w/ errno
* @error EAFNOSUPPORT * @error EAFNOSUPPORT
*/ */
int resolvehoststxt(const struct HostsTxt *ht, int af, const char *name, int ResolveHostsTxt(const struct HostsTxt *ht, int af, const char *name,
struct sockaddr *addr, uint32_t addrsize, struct sockaddr *addr, uint32_t addrsize,
const char **canon) { const char **canon) {
struct sockaddr_in *addr4; struct sockaddr_in *addr4;

View file

@ -26,11 +26,14 @@
* @return number of bytes written * @return number of bytes written
* @see pascalifydnsname() * @see pascalifydnsname()
*/ */
int serializednsquestion(uint8_t *buf, size_t size, struct DnsQuestion dq) { int SerializeDnsQuestion(uint8_t *buf, size_t size,
const struct DnsQuestion *dq) {
int wrote; int wrote;
if ((wrote = pascalifydnsname(buf, size, dq.qname)) == -1) return -1; if ((wrote = PascalifyDnsName(buf, size, dq->qname)) == -1) return -1;
if (wrote + 1 + 4 > size) return enospc(); if (wrote + 1 + 4 > size) return enospc();
buf[wrote + 1] = dq.qtype >> 010, buf[wrote + 2] = dq.qtype >> 000; buf[wrote + 1] = dq->qtype >> 8;
buf[wrote + 3] = dq.qclass >> 010, buf[wrote + 4] = dq.qclass >> 000; buf[wrote + 2] = dq->qtype;
buf[wrote + 3] = dq->qclass >> 8;
buf[wrote + 4] = dq->qclass;
return wrote + 5; return wrote + 5;
} }

View file

@ -22,25 +22,26 @@
/** /**
* Compares hostnames in HOSTS.TXT table. * Compares hostnames in HOSTS.TXT table.
* @see dnsnamecmp(), parsehoststxt() * @see CompareDnsNames(), ParseHostsTxt()
*/ */
static int cmphoststxt(const struct HostsTxtEntry *e1, static int cmphoststxt(const struct HostsTxtEntry *e1,
const struct HostsTxtEntry *e2, const char *strings) { const struct HostsTxtEntry *e2, const char *strings) {
if (e1 == e2) return 0; if (e1 == e2) return 0;
return dnsnamecmp(&strings[e1->name], &strings[e2->name]); return CompareDnsNames(&strings[e1->name], &strings[e2->name]);
} }
/** /**
* Sorts entries in HOSTS.TXT table. * Sorts entries in HOSTS.TXT table.
* *
* This function enables resolvehoststxt() to be called so hard-coded * This function enables ResolveHostsTxt() to be called so hard-coded
* hostname lookups take logarithmic time; you can blackhole all the * hostname lookups take logarithmic time; you can blackhole all the
* spam you want, in your /etc/hosts file. * spam you want, in your /etc/hosts file.
* *
* The sorted order, defined by dnsnamecmp(), also makes it possible to * The sorted order, defined by CompareDnsNames(), also makes it
* efficiently search for subdomains, once the initial sort is done. * possible to efficiently search for subdomains, once the initial sort
* is done.
*/ */
void sorthoststxt(struct HostsTxt *ht) { void SortHostsTxt(struct HostsTxt *ht) {
if (ht->entries.p) { if (ht->entries.p) {
qsort_r(ht->entries.p, ht->entries.i, sizeof(*ht->entries.p), qsort_r(ht->entries.p, ht->entries.i, sizeof(*ht->entries.p),
(void *)cmphoststxt, ht->strings.p); (void *)cmphoststxt, ht->strings.p);

View file

@ -17,12 +17,8 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/** /**
* Writes error messages to standard error. * Writes error messages to standard error.

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -36,6 +37,7 @@
int accept4(int fd, void *out_addr, uint32_t *inout_addrsize, int flags) { int accept4(int fd, void *out_addr, uint32_t *inout_addrsize, int flags) {
if (!out_addr) return efault(); if (!out_addr) return efault();
if (!inout_addrsize) return efault(); if (!inout_addrsize) return efault();
if (IsAsan() && !__asan_is_valid(out_addr, *inout_addrsize)) return efault();
if (!IsWindows()) { if (!IsWindows()) {
return sys_accept4(fd, out_addr, inout_addrsize, flags); return sys_accept4(fd, out_addr, inout_addrsize, flags);
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {

View file

@ -19,6 +19,7 @@
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -36,12 +37,14 @@
*/ */
int bind(int fd, const void *addr, uint32_t addrsize) { int bind(int fd, const void *addr, uint32_t addrsize) {
if (!addr) return efault(); if (!addr) return efault();
if (IsAsan() && !__asan_is_valid(addr, addrsize)) return efault();
if (addrsize == sizeof(struct sockaddr_in)) { if (addrsize == sizeof(struct sockaddr_in)) {
if (!IsWindows()) { if (!IsWindows()) {
if (!IsBsd()) { if (!IsBsd()) {
return sys_bind(fd, addr, addrsize); return sys_bind(fd, addr, addrsize);
} else { } else {
char addr2[sizeof(struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */ char addr2[sizeof(
struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */
assert(addrsize <= sizeof(addr2)); assert(addrsize <= sizeof(addr2));
memcpy(&addr2, addr, addrsize); memcpy(&addr2, addr, addrsize);
sockaddr2bsd(&addr2[0]); sockaddr2bsd(&addr2[0]);

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -34,6 +35,7 @@
*/ */
int connect(int fd, const void *addr, uint32_t addrsize) { int connect(int fd, const void *addr, uint32_t addrsize) {
if (!addr) return efault(); if (!addr) return efault();
if (IsAsan() && !__asan_is_valid(addr, addrsize)) return efault();
if (!IsWindows()) { if (!IsWindows()) {
return sys_connect(fd, addr, addrsize); return sys_connect(fd, addr, addrsize);
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -28,6 +29,7 @@
* @see getsockname() * @see getsockname()
*/ */
int getpeername(int fd, void *out_addr, uint32_t *out_addrsize) { int getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
if (IsAsan() && !__asan_is_valid(out_addr, *out_addrsize)) return efault();
if (!IsWindows()) { if (!IsWindows()) {
return sys_getpeername(fd, out_addr, out_addrsize); return sys_getpeername(fd, out_addr, out_addrsize);
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -28,6 +29,7 @@
* @see getpeername() * @see getpeername()
*/ */
int getsockname(int fd, void *out_addr, uint32_t *out_addrsize) { int getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
if (IsAsan() && !__asan_is_valid(out_addr, *out_addrsize)) return efault();
if (!IsWindows()) { if (!IsWindows()) {
return sys_getsockname(fd, out_addr, out_addrsize); return sys_getsockname(fd, out_addr, out_addrsize);
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {

View file

@ -19,8 +19,10 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"
/** /**
* Waits for something to happen on multiple file descriptors at once. * Waits for something to happen on multiple file descriptors at once.
@ -34,9 +36,11 @@
* @return fds[𝑖].revents flags can have: * @return fds[𝑖].revents flags can have:
* (fds[𝑖].events & POLL{IN,OUT,PRI,HUP,ERR,NVAL}) * (fds[𝑖].events & POLL{IN,OUT,PRI,HUP,ERR,NVAL})
* @asyncsignalsafe * @asyncsignalsafe
* @see ppoll()
*/ */
int poll(struct pollfd *fds, uint64_t nfds, int32_t timeout_ms) { int poll(struct pollfd *fds, uint64_t nfds, int32_t timeout_ms) {
if (IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd))) {
return efault();
}
if (!IsWindows()) { if (!IsWindows()) {
return sys_poll(fds, nfds, timeout_ms); return sys_poll(fds, nfds, timeout_ms);
} else { } else {

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
@ -43,6 +44,12 @@
ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags, ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) { void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) {
ssize_t got; ssize_t got;
if (IsAsan() &&
(!__asan_is_valid(buf, size) ||
(opt_out_srcaddr &&
!__asan_is_valid(opt_out_srcaddr, *opt_inout_srcaddrsize)))) {
return efault();
}
if (!IsWindows()) { if (!IsWindows()) {
got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr, got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
opt_inout_srcaddrsize); opt_inout_srcaddrsize);

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -47,6 +48,10 @@
*/ */
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags, ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
const void *opt_addr, uint32_t addrsize) { const void *opt_addr, uint32_t addrsize) {
if (IsAsan() && (!__asan_is_valid(buf, size) ||
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
return efault();
}
if (!IsWindows()) { if (!IsWindows()) {
if (!IsBsd() || !opt_addr) { if (!IsBsd() || !opt_addr) {
return sys_sendto(fd, buf, size, flags, opt_addr, addrsize); return sys_sendto(fd, buf, size, flags, opt_addr, addrsize);

View file

@ -0,0 +1,105 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
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 THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR 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/dns/dns.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
TEST(CompareDnsNames, testEmpty) {
char *A = strcpy(malloc(1), "");
char *B = strcpy(malloc(1), "");
EXPECT_EQ(CompareDnsNames(A, B), 0);
EXPECT_EQ(CompareDnsNames(A, A), 0);
free(B);
free(A);
}
TEST(CompareDnsNames, testDotless_caseInsensitiveBehavior) {
char *A = malloc(2);
char *B = malloc(2);
EXPECT_EQ(CompareDnsNames(strcpy(A, "a"), strcpy(B, "a")), 0);
EXPECT_EQ(CompareDnsNames(A, A), 0);
EXPECT_EQ(CompareDnsNames(strcpy(A, "a"), strcpy(B, "A")), 0);
EXPECT_EQ(CompareDnsNames(strcpy(A, "A"), strcpy(B, "a")), 0);
EXPECT_LT(CompareDnsNames(strcpy(A, "a"), strcpy(B, "b")), 0);
EXPECT_LT(CompareDnsNames(strcpy(A, "a"), strcpy(B, "B")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "d"), strcpy(B, "a")), 0);
free(B);
free(A);
}
TEST(CompareDnsNames, testMultiLabel_lexiReverse) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_EQ(CompareDnsNames(strcpy(A, "a.example"), strcpy(B, "a.example")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "b.example"), strcpy(B, "a.example")), 0);
EXPECT_LT(CompareDnsNames(strcpy(A, "b.example"), strcpy(B, "a.examplz")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "a.zxample"), strcpy(B, "a.examplz")), 0);
EXPECT_EQ(CompareDnsNames(strcpy(A, "c.a.example"), strcpy(B, "c.a.example")),
0);
EXPECT_GT(CompareDnsNames(strcpy(A, "d.a.example"), strcpy(B, "c.a.example")),
0);
EXPECT_LT(CompareDnsNames(strcpy(A, "cat.example"), strcpy(B, "lol.example")),
0);
free(B);
free(A);
}
TEST(CompareDnsNames, testTldDotQualifier_canBeEqualToDottedNames) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_EQ(
CompareDnsNames(strcpy(B, "aaa.example."), strcpy(A, "aaa.example")), 0);
free(B);
free(A);
}
TEST(CompareDnsNames, testFullyQualified_alwaysComesFirst) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_LT(CompareDnsNames(strcpy(B, "aaa.example."), strcpy(A, "zzz")), 0);
EXPECT_LT(CompareDnsNames(strcpy(B, "zzz.example."), strcpy(A, "aaa")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "zzz"), strcpy(B, "aaa.example.")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "aaa"), strcpy(B, "zzz.example.")), 0);
free(B);
free(A);
}
TEST(CompareDnsNames, testLikelySld_alwaysComesBeforeLocalName) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_LT(CompareDnsNames(strcpy(B, "z.e"), strcpy(A, "a")), 0);
EXPECT_LT(CompareDnsNames(strcpy(B, "aaa.example"), strcpy(A, "zzz")), 0);
EXPECT_LT(CompareDnsNames(strcpy(B, "zzz.example"), strcpy(A, "aaa")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "zzz"), strcpy(B, "aaa.example")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "aaa"), strcpy(B, "zzz.example")), 0);
free(B);
free(A);
}
TEST(CompareDnsNames, testLikelySubdomain_alwaysComesAfterSld) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_LT(CompareDnsNames(strcpy(B, "a.e"), strcpy(A, "z.a.e")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "z.a.e"), strcpy(B, "a.e")), 0);
EXPECT_LT(CompareDnsNames(strcpy(B, "b.e"), strcpy(A, "a.b.e")), 0);
EXPECT_GT(CompareDnsNames(strcpy(A, "a.b.e"), strcpy(B, "b.e")), 0);
free(B);
free(A);
}

View file

@ -25,25 +25,23 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(serializednsheader, test) { TEST(SerializeDnsHeader, test) {
uint8_t buf[12];
struct DnsHeader header; struct DnsHeader header;
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
header.id = 255; header.id = 255;
header.bf1 = true; header.bf1 = true;
header.qdcount = 1; header.qdcount = 1;
uint8_t *buf = malloc(12); SerializeDnsHeader(buf, &header);
ASSERT_EQ(12, serializednsheader(buf, 12, header));
EXPECT_BINEQ(u" λ☺  ☺      ", buf); EXPECT_BINEQ(u" λ☺  ☺      ", buf);
free(buf);
} }
TEST(serializednsheader, fuzzSymmetry) { TEST(SerializeDnsHeader, fuzzSymmetry) {
uint8_t *buf; uint8_t buf[12];
struct DnsHeader *in, *out; struct DnsHeader in, out;
buf = gc(malloc(12)); rngset(&in, sizeof(in), rand64, -1);
in = rngset(gc(malloc(sizeof(struct DnsHeader))), 12, rand64, -1); rngset(&out, sizeof(out), rand64, -1);
out = rngset(gc(malloc(sizeof(struct DnsHeader))), 12, rand64, -1); SerializeDnsHeader(buf, &in);
ASSERT_EQ(12, serializednsheader(buf, 12, *in)); DeserializeDnsHeader(&out, buf);
ASSERT_EQ(12, deserializednsheader(out, buf, 12)); ASSERT_EQ(0, memcmp(&in, &out, 12), "%#.*s\n\t%#.*s", 12, in, 12, buf);
ASSERT_EQ(0, memcmp(in, out, 12), "%#.*s\n\t%#.*s", 12, in, 12, buf);
} }

View file

@ -1,101 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
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 THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR 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/dns/dns.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
TEST(dnsnamecmp, testEmpty) {
char *A = strcpy(malloc(1), "");
char *B = strcpy(malloc(1), "");
EXPECT_EQ(dnsnamecmp(A, B), 0);
EXPECT_EQ(dnsnamecmp(A, A), 0);
free(B);
free(A);
}
TEST(dnsnamecmp, testDotless_caseInsensitiveBehavior) {
char *A = malloc(2);
char *B = malloc(2);
EXPECT_EQ(dnsnamecmp(strcpy(A, "a"), strcpy(B, "a")), 0);
EXPECT_EQ(dnsnamecmp(A, A), 0);
EXPECT_EQ(dnsnamecmp(strcpy(A, "a"), strcpy(B, "A")), 0);
EXPECT_EQ(dnsnamecmp(strcpy(A, "A"), strcpy(B, "a")), 0);
EXPECT_LT(dnsnamecmp(strcpy(A, "a"), strcpy(B, "b")), 0);
EXPECT_LT(dnsnamecmp(strcpy(A, "a"), strcpy(B, "B")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "d"), strcpy(B, "a")), 0);
free(B);
free(A);
}
TEST(dnsnamecmp, testMultiLabel_lexiReverse) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_EQ(dnsnamecmp(strcpy(A, "a.example"), strcpy(B, "a.example")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "b.example"), strcpy(B, "a.example")), 0);
EXPECT_LT(dnsnamecmp(strcpy(A, "b.example"), strcpy(B, "a.examplz")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "a.zxample"), strcpy(B, "a.examplz")), 0);
EXPECT_EQ(dnsnamecmp(strcpy(A, "c.a.example"), strcpy(B, "c.a.example")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "d.a.example"), strcpy(B, "c.a.example")), 0);
EXPECT_LT(dnsnamecmp(strcpy(A, "cat.example"), strcpy(B, "lol.example")), 0);
free(B);
free(A);
}
TEST(dnsnamecmp, testTldDotQualifier_canBeEqualToDottedNames) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_EQ(dnsnamecmp(strcpy(B, "aaa.example."), strcpy(A, "aaa.example")), 0);
free(B);
free(A);
}
TEST(dnsnamecmp, testFullyQualified_alwaysComesFirst) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_LT(dnsnamecmp(strcpy(B, "aaa.example."), strcpy(A, "zzz")), 0);
EXPECT_LT(dnsnamecmp(strcpy(B, "zzz.example."), strcpy(A, "aaa")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "zzz"), strcpy(B, "aaa.example.")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "aaa"), strcpy(B, "zzz.example.")), 0);
free(B);
free(A);
}
TEST(dnsnamecmp, testLikelySld_alwaysComesBeforeLocalName) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_LT(dnsnamecmp(strcpy(B, "z.e"), strcpy(A, "a")), 0);
EXPECT_LT(dnsnamecmp(strcpy(B, "aaa.example"), strcpy(A, "zzz")), 0);
EXPECT_LT(dnsnamecmp(strcpy(B, "zzz.example"), strcpy(A, "aaa")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "zzz"), strcpy(B, "aaa.example")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "aaa"), strcpy(B, "zzz.example")), 0);
free(B);
free(A);
}
TEST(dnsnamecmp, testLikelySubdomain_alwaysComesAfterSld) {
char *A = malloc(16);
char *B = malloc(16);
EXPECT_LT(dnsnamecmp(strcpy(B, "a.e"), strcpy(A, "z.a.e")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "z.a.e"), strcpy(B, "a.e")), 0);
EXPECT_LT(dnsnamecmp(strcpy(B, "b.e"), strcpy(A, "a.b.e")), 0);
EXPECT_GT(dnsnamecmp(strcpy(A, "a.b.e"), strcpy(B, "b.e")), 0);
free(B);
free(A);
}

View file

@ -22,29 +22,25 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(serializednsquestion, test) { TEST(SerializeDnsQuestion, test) {
uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1 + 4);
char *name = strdup("foo.bar");
struct DnsQuestion dq; struct DnsQuestion dq;
char name[] = "foo.bar";
uint8_t buf[1 + 3 + 1 + 3 + 1 + 4];
dq.qname = name; dq.qname = name;
dq.qtype = 0x0201; dq.qtype = 0x0201;
dq.qclass = 0x0102; dq.qclass = 0x0102;
EXPECT_EQ(1 + 3 + 1 + 3 + 1 + 4, EXPECT_EQ(1 + 3 + 1 + 3 + 1 + 4,
serializednsquestion(buf, 1 + 3 + 1 + 3 + 1 + 4, dq)); SerializeDnsQuestion(buf, 1 + 3 + 1 + 3 + 1 + 4, &dq));
EXPECT_BINEQ(u"♥foo♥bar ☻☺☺☻", buf); EXPECT_BINEQ(u"♥foo♥bar ☻☺☺☻", buf);
free(name);
free(buf);
} }
TEST(serializednsquestion, testNoSpace) { TEST(SerializeDnsQuestion, testNoSpace) {
uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1 + 3);
char *name = strdup("foo.bar");
struct DnsQuestion dq; struct DnsQuestion dq;
char name[] = "foo.bar";
uint8_t buf[1 + 3 + 1 + 3 + 1 + 3];
dq.qname = name; dq.qname = name;
dq.qtype = 0x0201; dq.qtype = 0x0201;
dq.qclass = 0x0102; dq.qclass = 0x0102;
EXPECT_EQ(-1, serializednsquestion(buf, 1 + 3 + 1 + 3 + 1 + 3, dq)); EXPECT_EQ(-1, SerializeDnsQuestion(buf, 1 + 3 + 1 + 3 + 1 + 3, &dq));
EXPECT_EQ(ENOSPC, errno); EXPECT_EQ(ENOSPC, errno);
free(name);
free(buf);
} }

View file

@ -29,16 +29,16 @@ static const char *ParseIp(unsigned char ip[4]) {
return inet_ntop(AF_INET, ip, g_ipbuf, sizeof(g_ipbuf)); return inet_ntop(AF_INET, ip, g_ipbuf, sizeof(g_ipbuf));
} }
TEST(parsehoststxt, testEmpty) { TEST(ParseHostsTxt, testEmpty) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt)); struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(NULL, BUFSIZ, "r+"); FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(0, parsehoststxt(ht, f)); ASSERT_EQ(0, ParseHostsTxt(ht, f));
ASSERT_EQ(0, ht->entries.i); ASSERT_EQ(0, ht->entries.i);
freehoststxt(&ht); FreeHostsTxt(&ht);
fclose(f); fclose(f);
} }
TEST(parsehoststxt, testCorrectlyTokenizesAndSorts) { TEST(ParseHostsTxt, testCorrectlyTokenizesAndSorts) {
const char kInput[] = "# this is a comment\n" const char kInput[] = "# this is a comment\n"
"# IP HOST1 HOST2\n" "# IP HOST1 HOST2\n"
"203.0.113.1 lol.example. lol\n" "203.0.113.1 lol.example. lol\n"
@ -47,8 +47,8 @@ TEST(parsehoststxt, testCorrectlyTokenizesAndSorts) {
FILE *f = fmemopen(NULL, BUFSIZ, "r+"); FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f)); ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f));
rewind(f); rewind(f);
ASSERT_EQ(0, parsehoststxt(ht, f)); ASSERT_EQ(0, ParseHostsTxt(ht, f));
sorthoststxt(ht); SortHostsTxt(ht);
ASSERT_EQ(4, ht->entries.i); ASSERT_EQ(4, ht->entries.i);
EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[0].name]); EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[0].name]);
EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[0].canon]); EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[0].canon]);
@ -62,20 +62,20 @@ TEST(parsehoststxt, testCorrectlyTokenizesAndSorts) {
EXPECT_STREQ("lol", &ht->strings.p[ht->entries.p[3].name]); EXPECT_STREQ("lol", &ht->strings.p[ht->entries.p[3].name]);
EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[3].canon]); EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[3].canon]);
EXPECT_STREQ("203.0.113.1", ParseIp(ht->entries.p[3].ip)); EXPECT_STREQ("203.0.113.1", ParseIp(ht->entries.p[3].ip));
freehoststxt(&ht); FreeHostsTxt(&ht);
fclose(f); fclose(f);
} }
TEST(parsehoststxt, testIpv6_isIgnored) { TEST(ParseHostsTxt, testIpv6_isIgnored) {
const char kInput[] = "::1 boop\n" const char kInput[] = "::1 boop\n"
"203.0.113.2 cat # ignore me\n"; "203.0.113.2 cat # ignore me\n";
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt)); struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+"); FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, parsehoststxt(ht, f)); ASSERT_EQ(0, ParseHostsTxt(ht, f));
ASSERT_EQ(1, ht->entries.i); ASSERT_EQ(1, ht->entries.i);
EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].name]); EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].name]);
EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].canon]); EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].canon]);
EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[0].ip)); EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[0].ip));
freehoststxt(&ht); FreeHostsTxt(&ht);
fclose(f); fclose(f);
} }

View file

@ -31,22 +31,22 @@ static const char *FormatIp(struct sockaddr_in *ip) {
return inet_ntop(ip->sin_family, &ip->sin_addr.s_addr, g_ipbuf, 16); return inet_ntop(ip->sin_family, &ip->sin_addr.s_addr, g_ipbuf, 16);
} }
TEST(parseresolvconf, testEmpty) { TEST(ParseResolvConf, testEmpty) {
struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf)); struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf));
FILE *f = fmemopen(NULL, BUFSIZ, "r+"); FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(0, parseresolvconf(rv, f)); ASSERT_EQ(0, ParseResolvConf(rv, f));
ASSERT_EQ(0, rv->nameservers.i); ASSERT_EQ(0, rv->nameservers.i);
freeresolvconf(&rv); FreeResolvConf(&rv);
fclose(f); fclose(f);
} }
TEST(parseresolvconf, testCorrectlyTokenizes) { TEST(ParseResolvConf, testCorrectlyTokenizes) {
const char kInput[] = "# this is a comment\n" const char kInput[] = "# this is a comment\n"
"nameserver 203.0.113.2 \n" "nameserver 203.0.113.2 \n"
" nameserver 203.0.113.1\n"; " nameserver 203.0.113.1\n";
struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf)); struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf));
FILE *f = fmemopen(kInput, strlen(kInput), "r+"); FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(2, parseresolvconf(rv, f)); ASSERT_EQ(2, ParseResolvConf(rv, f));
ASSERT_EQ(2, rv->nameservers.i); ASSERT_EQ(2, rv->nameservers.i);
EXPECT_EQ(AF_INET, rv->nameservers.p[0].sin_family); EXPECT_EQ(AF_INET, rv->nameservers.p[0].sin_family);
EXPECT_EQ(DNS_PORT, ntohs(rv->nameservers.p[0].sin_port)); EXPECT_EQ(DNS_PORT, ntohs(rv->nameservers.p[0].sin_port));
@ -54,17 +54,17 @@ TEST(parseresolvconf, testCorrectlyTokenizes) {
EXPECT_EQ(AF_INET, rv->nameservers.p[1].sin_family); EXPECT_EQ(AF_INET, rv->nameservers.p[1].sin_family);
EXPECT_EQ(DNS_PORT, ntohs(rv->nameservers.p[1].sin_port)); EXPECT_EQ(DNS_PORT, ntohs(rv->nameservers.p[1].sin_port));
EXPECT_STREQ("203.0.113.1", FormatIp(&rv->nameservers.p[1])); EXPECT_STREQ("203.0.113.1", FormatIp(&rv->nameservers.p[1]));
freeresolvconf(&rv); FreeResolvConf(&rv);
fclose(f); fclose(f);
} }
TEST(parseresolvconf, testMulticastDnsThing_getsIgnored) { TEST(ParseResolvConf, testMulticastDnsThing_getsIgnored) {
const char kInput[] = "search local # boop\n"; const char kInput[] = "search local # boop\n";
struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf)); struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf));
FILE *f = fmemopen(NULL, BUFSIZ, "r+"); FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(strlen(kInput), fwrite(kInput, 1, strlen(kInput), f)); ASSERT_EQ(strlen(kInput), fwrite(kInput, 1, strlen(kInput), f));
ASSERT_EQ(0, parseresolvconf(rv, f)); ASSERT_EQ(0, ParseResolvConf(rv, f));
ASSERT_EQ(0, rv->nameservers.i); ASSERT_EQ(0, rv->nameservers.i);
freeresolvconf(&rv); FreeResolvConf(&rv);
fclose(f); fclose(f);
} }

View file

@ -22,57 +22,57 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(pascalifydnsname, testEmpty) { TEST(PascalifyDnsName, testEmpty) {
uint8_t *buf = malloc(1); uint8_t *buf = malloc(1);
char *name = strdup(""); char *name = strdup("");
EXPECT_EQ(0, pascalifydnsname(buf, 1, name)); EXPECT_EQ(0, PascalifyDnsName(buf, 1, name));
EXPECT_BINEQ(u" ", buf); EXPECT_BINEQ(u" ", buf);
free(name); free(name);
free(buf); free(buf);
} }
TEST(pascalifydnsname, testOneLabel) { TEST(PascalifyDnsName, testOneLabel) {
uint8_t *buf = malloc(1 + 3 + 1); uint8_t *buf = malloc(1 + 3 + 1);
char *name = strdup("foo"); char *name = strdup("foo");
EXPECT_EQ(1 + 3, pascalifydnsname(buf, 1 + 3 + 1, name)); EXPECT_EQ(1 + 3, PascalifyDnsName(buf, 1 + 3 + 1, name));
EXPECT_BINEQ(u"♥foo ", buf); EXPECT_BINEQ(u"♥foo ", buf);
free(name); free(name);
free(buf); free(buf);
} }
TEST(pascalifydnsname, testTwoLabels) { TEST(PascalifyDnsName, testTwoLabels) {
uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1); uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1);
char *name = strdup("foo.bar"); char *name = strdup("foo.bar");
EXPECT_EQ(1 + 3 + 1 + 3, pascalifydnsname(buf, 1 + 3 + 1 + 3 + 1, name)); EXPECT_EQ(1 + 3 + 1 + 3, PascalifyDnsName(buf, 1 + 3 + 1 + 3 + 1, name));
EXPECT_BINEQ(u"♥foo♥bar ", buf); EXPECT_BINEQ(u"♥foo♥bar ", buf);
free(name); free(name);
free(buf); free(buf);
} }
TEST(pascalifydnsname, testFqdnDot_isntIncluded) { TEST(PascalifyDnsName, testFqdnDot_isntIncluded) {
uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1); uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1);
char *name = strdup("foo.bar."); char *name = strdup("foo.bar.");
EXPECT_EQ(1 + 3 + 1 + 3, pascalifydnsname(buf, 1 + 3 + 1 + 3 + 1, name)); EXPECT_EQ(1 + 3 + 1 + 3, PascalifyDnsName(buf, 1 + 3 + 1 + 3 + 1, name));
EXPECT_BINEQ(u"♥foo♥bar ", buf); EXPECT_BINEQ(u"♥foo♥bar ", buf);
free(name); free(name);
free(buf); free(buf);
} }
TEST(pascalifydnsname, testTooLong) { TEST(PascalifyDnsName, testTooLong) {
uint8_t *buf = malloc(1); uint8_t *buf = malloc(1);
char *name = malloc(1000); char *name = malloc(1000);
memset(name, '.', 999); memset(name, '.', 999);
name[999] = '\0'; name[999] = '\0';
EXPECT_EQ(-1, pascalifydnsname(buf, 1, name)); EXPECT_EQ(-1, PascalifyDnsName(buf, 1, name));
EXPECT_EQ(ENAMETOOLONG, errno); EXPECT_EQ(ENAMETOOLONG, errno);
free(name); free(name);
free(buf); free(buf);
} }
TEST(pascalifydnsname, testNoSpace) { TEST(PascalifyDnsName, testNoSpace) {
uint8_t *buf = malloc(1); uint8_t *buf = malloc(1);
char *name = strdup("foo"); char *name = strdup("foo");
EXPECT_EQ(-1, pascalifydnsname(buf, 1, name)); EXPECT_EQ(-1, PascalifyDnsName(buf, 1, name));
EXPECT_EQ(ENOSPC, errno); EXPECT_EQ(ENOSPC, errno);
free(name); free(name);
free(buf); free(buf);

View file

@ -27,7 +27,7 @@
static const char *EzIp4Lookup(const struct HostsTxt *ht, const char *name) { static const char *EzIp4Lookup(const struct HostsTxt *ht, const char *name) {
struct sockaddr_in addr4; struct sockaddr_in addr4;
if (resolvehoststxt(ht, AF_INET, name, (void *)&addr4, if (ResolveHostsTxt(ht, AF_INET, name, (void *)&addr4,
sizeof(struct sockaddr_in), NULL) > 0) { sizeof(struct sockaddr_in), NULL) > 0) {
static char g_ipbuf[16]; static char g_ipbuf[16];
return inet_ntop(AF_INET, &addr4.sin_addr, g_ipbuf, sizeof(g_ipbuf)); return inet_ntop(AF_INET, &addr4.sin_addr, g_ipbuf, sizeof(g_ipbuf));
@ -38,18 +38,18 @@ static const char *EzIp4Lookup(const struct HostsTxt *ht, const char *name) {
static const char *EzCanonicalize(const struct HostsTxt *ht, const char *name) { static const char *EzCanonicalize(const struct HostsTxt *ht, const char *name) {
const char *res; const char *res;
return resolvehoststxt(ht, AF_INET, name, NULL, 0, &res) > 0 ? res : NULL; return ResolveHostsTxt(ht, AF_INET, name, NULL, 0, &res) > 0 ? res : NULL;
} }
static const char kInput[] = "127.0.0.1 localhost\n" static const char kInput[] = "127.0.0.1 localhost\n"
"203.0.113.1 lol.example. lol\n" "203.0.113.1 lol.example. lol\n"
"203.0.113.2 cat.example. cat\n"; "203.0.113.2 cat.example. cat\n";
TEST(resolvehoststxt, testBasicLookups) { TEST(ResolveHostsTxt, testBasicLookups) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt)); struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+"); FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, parsehoststxt(ht, f)); ASSERT_EQ(0, ParseHostsTxt(ht, f));
sorthoststxt(ht); SortHostsTxt(ht);
ASSERT_EQ(5, ht->entries.i); ASSERT_EQ(5, ht->entries.i);
EXPECT_STREQ("127.0.0.1", EzIp4Lookup(ht, "localhost")); EXPECT_STREQ("127.0.0.1", EzIp4Lookup(ht, "localhost"));
EXPECT_STREQ("203.0.113.1", EzIp4Lookup(ht, "lol")); EXPECT_STREQ("203.0.113.1", EzIp4Lookup(ht, "lol"));
@ -58,15 +58,15 @@ TEST(resolvehoststxt, testBasicLookups) {
EXPECT_STREQ("203.0.113.2", EzIp4Lookup(ht, "cat")); EXPECT_STREQ("203.0.113.2", EzIp4Lookup(ht, "cat"));
EXPECT_STREQ("203.0.113.2", EzIp4Lookup(ht, "cat.example.")); EXPECT_STREQ("203.0.113.2", EzIp4Lookup(ht, "cat.example."));
EXPECT_EQ(NULL, EzIp4Lookup(ht, "boop")); EXPECT_EQ(NULL, EzIp4Lookup(ht, "boop"));
freehoststxt(&ht); FreeHostsTxt(&ht);
fclose(f); fclose(f);
} }
TEST(resolvehoststxt, testCanonicalize) { TEST(ResolveHostsTxt, testCanonicalize) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt)); struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+"); FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, parsehoststxt(ht, f)); ASSERT_EQ(0, ParseHostsTxt(ht, f));
sorthoststxt(ht); SortHostsTxt(ht);
ASSERT_EQ(5, ht->entries.i); ASSERT_EQ(5, ht->entries.i);
EXPECT_STREQ("localhost", EzCanonicalize(ht, "localhost")); EXPECT_STREQ("localhost", EzCanonicalize(ht, "localhost"));
EXPECT_STREQ("lol.example.", EzCanonicalize(ht, "lol")); EXPECT_STREQ("lol.example.", EzCanonicalize(ht, "lol"));
@ -75,6 +75,6 @@ TEST(resolvehoststxt, testCanonicalize) {
EXPECT_STREQ("cat.example.", EzCanonicalize(ht, "cat")); EXPECT_STREQ("cat.example.", EzCanonicalize(ht, "cat"));
EXPECT_STREQ("cat.example.", EzCanonicalize(ht, "cat.example.")); EXPECT_STREQ("cat.example.", EzCanonicalize(ht, "cat.example."));
EXPECT_EQ(NULL, EzCanonicalize(ht, "boop")); EXPECT_EQ(NULL, EzCanonicalize(ht, "boop"));
freehoststxt(&ht); FreeHostsTxt(&ht);
fclose(f); fclose(f);
} }

View file

@ -31,12 +31,9 @@
void lookup(const char *name) { void lookup(const char *name) {
int rc; int rc;
struct addrinfo hints = (struct addrinfo){.ai_family = AF_INET, struct addrinfo *ai = NULL;
.ai_socktype = SOCK_STREAM, struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
.ai_protocol = IPPROTO_TCP, switch ((rc = getaddrinfo(name, "80", &hint, &ai))) {
.ai_flags = AI_NUMERICSERV};
struct addrinfo *addrs = NULL;
switch ((rc = getaddrinfo(name, "80", &hints, &addrs))) {
case EAI_SUCCESS: case EAI_SUCCESS:
break; break;
case EAI_SYSTEM: case EAI_SYSTEM:
@ -47,8 +44,8 @@ void lookup(const char *name) {
gai_strerror(rc)); gai_strerror(rc));
exit(1); exit(1);
} }
if (addrs) { if (ai) {
for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) { for (struct addrinfo *addr = ai; addr; addr = addr->ai_next) {
const unsigned char *ip = const unsigned char *ip =
addr->ai_family == AF_INET addr->ai_family == AF_INET
? (const unsigned char *)&((struct sockaddr_in *)addr->ai_addr) ? (const unsigned char *)&((struct sockaddr_in *)addr->ai_addr)
@ -70,7 +67,7 @@ void lookup(const char *name) {
ip[3]); ip[3]);
printf("%-12s = %s\n", "ai_canonname", addr->ai_canonname); printf("%-12s = %s\n", "ai_canonname", addr->ai_canonname);
} }
freeaddrinfo(addrs); freeaddrinfo(ai);
} else { } else {
fprintf(stderr, "%s: %s\n", name, "no results"); fprintf(stderr, "%s: %s\n", name, "no results");
} }

View file

@ -202,7 +202,6 @@ static const struct ContentTypeExtension {
{"z", "application/zlib"}, // {"z", "application/zlib"}, //
{"zip", "application/zip"}, // {"zip", "application/zip"}, //
{"zst", "application/zstd"}, // {"zst", "application/zstd"}, //
{"zst", "application/zstd"}, //
}; };
static const char kRegCode[][8] = { static const char kRegCode[][8] = {
@ -1941,7 +1940,7 @@ td { padding-right: 3em; }\r\n\
} }
static const char *MergeNames(const char *a, const char *b) { static const char *MergeNames(const char *a, const char *b) {
return FreeLater(xasprintf("%s.ru_utime", a)); return FreeLater(xasprintf("%s.%s", a, b));
} }
static void AppendLong1(const char *a, long x) { static void AppendLong1(const char *a, long x) {
@ -2212,7 +2211,7 @@ static int LuaRoute(lua_State *L) {
return 1; return 1;
} }
static int LuaRespond(lua_State *L, char *respond(unsigned, const char *)) { static int LuaRespond(lua_State *L, char *R(unsigned, const char *)) {
char *p; char *p;
int code; int code;
size_t reasonlen; size_t reasonlen;
@ -2223,11 +2222,11 @@ static int LuaRespond(lua_State *L, char *respond(unsigned, const char *)) {
unreachable; unreachable;
} }
if (lua_isnoneornil(L, 2)) { if (lua_isnoneornil(L, 2)) {
luaheaderp = respond(code, GetHttpReason(code)); luaheaderp = R(code, GetHttpReason(code));
} else { } else {
reason = lua_tolstring(L, 2, &reasonlen); reason = lua_tolstring(L, 2, &reasonlen);
if (reasonlen < 128 && (p = EncodeHttpHeaderValue(reason, reasonlen, 0))) { if (reasonlen < 128 && (p = EncodeHttpHeaderValue(reason, reasonlen, 0))) {
luaheaderp = respond(code, p); luaheaderp = R(code, p);
free(p); free(p);
} else { } else {
luaL_argerror(L, 2, "invalid"); luaL_argerror(L, 2, "invalid");
@ -2802,7 +2801,7 @@ static int LuaSetHeader(lua_State *L) {
} }
switch (h) { switch (h) {
case kHttpConnection: case kHttpConnection:
if (evallen != 5 || memcasecmp(eval, "close", 5)) { if (SlicesEqualCase(eval, evallen, "close", 5)) {
luaL_argerror(L, 2, "unsupported"); luaL_argerror(L, 2, "unsupported");
unreachable; unreachable;
} }
@ -3017,11 +3016,11 @@ static int LuaHasControlCodes(lua_State *L) {
return 1; return 1;
} }
static int LuaIsValid(lua_State *L, bool IsValid(const char *, size_t)) { static int LuaIsValid(lua_State *L, bool V(const char *, size_t)) {
size_t size; size_t size;
const char *data; const char *data;
data = luaL_checklstring(L, 1, &size); data = luaL_checklstring(L, 1, &size);
lua_pushboolean(L, IsValid(data, size)); lua_pushboolean(L, V(data, size));
return 1; return 1;
} }