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
#include "libc/calls/calls.h"
#include "libc/dns/dns.h"
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
@ -28,7 +30,12 @@
* Implemented because BusyBox's netcat doesn't detect remote close and
* 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[]) {
@ -36,15 +43,26 @@ int main(int argc, char *argv[]) {
size_t i, got;
char buf[1500];
int err, toto, sock;
struct addrinfo *ai = NULL;
struct linger linger = {true, 1};
struct sockaddr_in addr = {AF_INET};
struct pollfd fds[2] = {{-1, POLLIN}, {-1, POLLIN}};
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
if (argc != 3) exit(1);
inet_pton(AF_INET, argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
switch ((rc = getaddrinfo(argv[1], argv[2], &hint, &ai))) {
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");
exit(1);
}
@ -54,7 +72,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
if (connect(sock, &addr, sizeof(addr)) == -1) {
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
perror("connect");
exit(1);
}
@ -108,5 +126,6 @@ int main(int argc, char *argv[]) {
exit(1);
}
freeaddrinfo(ai);
return 0;
}

View File

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/dns/dns.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
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.
* @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;
size_t n = strlen(A);
size_t m = strlen(B);
n = strlen(A);
m = strlen(B);
if (!n || !m || ((A[n - 1] == '.') ^ (B[m - 1] == '.'))) {
if (n && m && A[n - 1] == '.' && strchr(B, '.')) {
--m;
@ -51,9 +54,9 @@ int dnsnamecmp(const char *A, const char *B) {
return A[n ? n - 1 : 0] - B[m ? m - 1 : 0];
}
}
size_t i = n;
size_t j = m;
bool first = true;
i = n;
j = m;
first = true;
for (;;) {
FindDnsLabel(A, &i, &n);
FindDnsLabel(B, &j, &m);
@ -62,8 +65,7 @@ int dnsnamecmp(const char *A, const char *B) {
if (!i && j) 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;
}
if (!i || !j) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,9 +20,9 @@
#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) {
free_s(&(*ht)->entries.p);
free_s(&(*ht)->strings.p);

View File

@ -20,9 +20,9 @@
#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) {
free_s(&(*rvp)->nameservers.p);
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) {
freeaddrinfo(ai);
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) {
memcpy(ai->ai_canonname, canon, min(strlen(canon), DNS_NAME_MAX) + 1);
*res = ai;
return 0;
} else {
rc = resolvedns(getresolvconf(), AF_INET, name, ai->ai_addr,
rc = ResolveDns(GetResolvConf(), AF_INET, name, ai->ai_addr,
sizeof(ai->ai_addr4));
if (rc > 0) {
*res = ai;

View File

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

View File

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

View File

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

View File

@ -1,26 +1,23 @@
#ifndef 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)
COSMOPOLITAN_C_START_
struct FILE;
struct sockaddr;
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 canon; /* &ht->strings.p[he->canon] */
};
struct HostsTxtEntries {
size_t i;
size_t n;
size_t i, n;
struct HostsTxtEntry *p;
};
struct HostsTxtStrings {
size_t i;
size_t n;
size_t i, n;
char *p;
};
@ -29,11 +26,11 @@ struct HostsTxt {
struct HostsTxtStrings strings;
};
const struct HostsTxt *gethoststxt(void) returnsnonnull;
void freehoststxt(struct HostsTxt **) paramsnonnull();
int parsehoststxt(struct HostsTxt *, struct FILE *) paramsnonnull();
void sorthoststxt(struct HostsTxt *) paramsnonnull();
int resolvehoststxt(const struct HostsTxt *, int, const char *,
const struct HostsTxt *GetHostsTxt(void) returnsnonnull;
void FreeHostsTxt(struct HostsTxt **) paramsnonnull();
int ParseHostsTxt(struct HostsTxt *, FILE *) paramsnonnull();
void SortHostsTxt(struct HostsTxt *) paramsnonnull();
int ResolveHostsTxt(const struct HostsTxt *, int, const char *,
struct sockaddr *, uint32_t, const char **)
paramsnonnull((1, 3));

View File

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

View File

@ -41,7 +41,7 @@
* @param f is an open stream with file content
* @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 */
int rc;
char *line;
@ -49,7 +49,7 @@ int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) {
struct sockaddr_in nameserver;
char *directive, *value, *tok, *comment;
rc = 0;
line = NULL;
line = 0;
linesize = 0;
nameserver.sin_family = AF_INET;
nameserver.sin_port = htons(DNS_PORT);

View File

@ -30,7 +30,7 @@
* @param name is a dotted NUL-terminated hostname string
* @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;
if ((namelen = strlen(name)) > DNS_NAME_MAX) return enametoolong();
i = 0;

View File

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

View File

@ -38,7 +38,7 @@
/**
* 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 name can be a local or fully-qualified hostname
* @param addr should point to a struct sockaddr_in; if this function
@ -47,42 +47,40 @@
* @return number of matches found, or -1 w/ errno
* @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) {
size_t msgsize;
int res, fd, rc, rc2;
struct sockaddr_in *addr4;
struct DnsQuestion question;
int rc, fd, n;
struct DnsQuestion q;
struct DnsHeader h, h2;
struct sockaddr_in *a4;
uint8_t *p, *pe, msg[512];
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 (!resolvconf->nameservers.i) return 0;
memset(&header, 0, sizeof(header));
header.id = rand32();
header.bf1 = 1; /* recursion desired */
header.qdcount = 1;
question.qname = name;
question.qtype = DNS_TYPE_A;
question.qclass = DNS_CLASS_IN;
res = -1;
if ((outmsg = malloc(kMsgMax)) && (inmsg = malloc(kMsgMax)) &&
(rc = serializednsheader(outmsg, kMsgMax, header)) != -1 &&
(rc2 = serializednsquestion(outmsg + rc, kMsgMax - rc, question)) != -1) {
msgsize = rc + rc2;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1 &&
sendto(fd, outmsg, msgsize, 0, (void *)&resolvconf->nameservers.p[0],
sizeof(resolvconf->nameservers.p[0])) == msgsize) {
if ((rc = recv(fd, inmsg, kMsgMax, 0)) != -1 &&
(rc2 = deserializednsheader(&response, inmsg, rc)) != -1 &&
response.id == header.id) {
res = 0;
if (response.ancount) {
p = inmsg + rc2;
pe = inmsg + rc;
while (p < pe && response.qdcount) {
memset(&h, 0, sizeof(h));
rc = ebadmsg();
h.id = rand32();
h.bf1 = 1; /* recursion desired */
h.qdcount = 1;
q.qname = name;
q.qtype = DNS_TYPE_A;
q.qclass = DNS_CLASS_IN;
memset(msg, 0, sizeof(msg));
SerializeDnsHeader(msg, &h);
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
if (sendto(fd, msg, 12 + n, 0, resolvconf->nameservers.p,
sizeof(*resolvconf->nameservers.p)) == 12 + n &&
(n = read(fd, msg, 512)) >= 12) {
DeserializeDnsHeader(&h2, msg);
if (h2.id == h.id) {
rc = 0;
if (h2.ancount) {
p = msg + 12;
pe = msg + n;
while (p < pe && h2.qdcount) {
p += strnlen((char *)p, pe - p) + 1 + 4;
response.qdcount--;
h2.qdcount--;
}
if (p + 1 < pe) {
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
@ -97,14 +95,14 @@ int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
rdlength = READ16BE(p), p += 2;
if (p + rdlength <= pe && rdlength == 4 &&
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
res = 1;
rc = 1;
if (addrsize) {
if (addrsize >= kMinSockaddr4Size) {
addr4 = (struct sockaddr_in *)addr;
addr4->sin_family = AF_INET;
memcpy(&addr4->sin_addr.s_addr, p, 4);
a4 = (struct sockaddr_in *)addr;
a4->sin_family = AF_INET;
memcpy(&a4->sin_addr.s_addr, p, 4);
} else {
res = einval();
rc = einval();
}
}
}
@ -113,8 +111,6 @@ int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
}
}
}
res |= close(fd);
}
free(outmsg);
return res;
close(fd);
return rc;
}

View File

@ -27,16 +27,16 @@
static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
const char *strings) {
return dnsnamecmp(node, &strings[entry->name]);
return CompareDnsNames(node, &strings[entry->name]);
}
/**
* 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.
*
* @param ht can be gethoststxt()
* @param ht can be GetHostsTxt()
* @param af can be AF_INET, AF_UNSPEC
* @param name can be a local or fully-qualified hostname
* @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
* @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,
const char **canon) {
struct sockaddr_in *addr4;

View File

@ -26,11 +26,14 @@
* @return number of bytes written
* @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;
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();
buf[wrote + 1] = dq.qtype >> 010, buf[wrote + 2] = dq.qtype >> 000;
buf[wrote + 3] = dq.qclass >> 010, buf[wrote + 4] = dq.qclass >> 000;
buf[wrote + 1] = dq->qtype >> 8;
buf[wrote + 2] = dq->qtype;
buf[wrote + 3] = dq->qclass >> 8;
buf[wrote + 4] = dq->qclass;
return wrote + 5;
}

View File

@ -22,25 +22,26 @@
/**
* Compares hostnames in HOSTS.TXT table.
* @see dnsnamecmp(), parsehoststxt()
* @see CompareDnsNames(), ParseHostsTxt()
*/
static int cmphoststxt(const struct HostsTxtEntry *e1,
const struct HostsTxtEntry *e2, const char *strings) {
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.
*
* 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
* spam you want, in your /etc/hosts file.
*
* The sorted order, defined by dnsnamecmp(), also makes it possible to
* efficiently search for subdomains, once the initial sort is done.
* The sorted order, defined by CompareDnsNames(), also makes it
* 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) {
qsort_r(ht->entries.p, ht->entries.i, sizeof(*ht->entries.p),
(void *)cmphoststxt, ht->strings.p);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,8 +19,10 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"
/**
* Waits for something to happen on multiple file descriptors at once.
@ -34,9 +36,11 @@
* @return fds[𝑖].revents flags can have:
* (fds[𝑖].events & POLL{IN,OUT,PRI,HUP,ERR,NVAL})
* @asyncsignalsafe
* @see ppoll()
*/
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()) {
return sys_poll(fds, nfds, timeout_ms);
} else {

View File

@ -19,6 +19,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
@ -43,6 +44,12 @@
ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) {
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()) {
got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
opt_inout_srcaddrsize);

View File

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
@ -47,6 +48,10 @@
*/
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
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 (!IsBsd() || !opt_addr) {
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/testlib/testlib.h"
TEST(serializednsheader, test) {
TEST(SerializeDnsHeader, test) {
uint8_t buf[12];
struct DnsHeader header;
memset(&header, 0, sizeof(header));
header.id = 255;
header.bf1 = true;
header.qdcount = 1;
uint8_t *buf = malloc(12);
ASSERT_EQ(12, serializednsheader(buf, 12, header));
SerializeDnsHeader(buf, &header);
EXPECT_BINEQ(u" λ☺  ☺      ", buf);
free(buf);
}
TEST(serializednsheader, fuzzSymmetry) {
uint8_t *buf;
struct DnsHeader *in, *out;
buf = gc(malloc(12));
in = rngset(gc(malloc(sizeof(struct DnsHeader))), 12, rand64, -1);
out = rngset(gc(malloc(sizeof(struct DnsHeader))), 12, rand64, -1);
ASSERT_EQ(12, serializednsheader(buf, 12, *in));
ASSERT_EQ(12, deserializednsheader(out, buf, 12));
ASSERT_EQ(0, memcmp(in, out, 12), "%#.*s\n\t%#.*s", 12, in, 12, buf);
TEST(SerializeDnsHeader, fuzzSymmetry) {
uint8_t buf[12];
struct DnsHeader in, out;
rngset(&in, sizeof(in), rand64, -1);
rngset(&out, sizeof(out), rand64, -1);
SerializeDnsHeader(buf, &in);
DeserializeDnsHeader(&out, 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/testlib/testlib.h"
TEST(serializednsquestion, test) {
uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1 + 4);
char *name = strdup("foo.bar");
TEST(SerializeDnsQuestion, test) {
struct DnsQuestion dq;
char name[] = "foo.bar";
uint8_t buf[1 + 3 + 1 + 3 + 1 + 4];
dq.qname = name;
dq.qtype = 0x0201;
dq.qclass = 0x0102;
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);
free(name);
free(buf);
}
TEST(serializednsquestion, testNoSpace) {
uint8_t *buf = malloc(1 + 3 + 1 + 3 + 1 + 3);
char *name = strdup("foo.bar");
TEST(SerializeDnsQuestion, testNoSpace) {
struct DnsQuestion dq;
char name[] = "foo.bar";
uint8_t buf[1 + 3 + 1 + 3 + 1 + 3];
dq.qname = name;
dq.qtype = 0x0201;
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);
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));
}
TEST(parsehoststxt, testEmpty) {
TEST(ParseHostsTxt, testEmpty) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(0, parsehoststxt(ht, f));
ASSERT_EQ(0, ParseHostsTxt(ht, f));
ASSERT_EQ(0, ht->entries.i);
freehoststxt(&ht);
FreeHostsTxt(&ht);
fclose(f);
}
TEST(parsehoststxt, testCorrectlyTokenizesAndSorts) {
TEST(ParseHostsTxt, testCorrectlyTokenizesAndSorts) {
const char kInput[] = "# this is a comment\n"
"# IP HOST1 HOST2\n"
"203.0.113.1 lol.example. lol\n"
@ -47,8 +47,8 @@ TEST(parsehoststxt, testCorrectlyTokenizesAndSorts) {
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f));
rewind(f);
ASSERT_EQ(0, parsehoststxt(ht, f));
sorthoststxt(ht);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
SortHostsTxt(ht);
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].canon]);
@ -62,20 +62,20 @@ TEST(parsehoststxt, testCorrectlyTokenizesAndSorts) {
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("203.0.113.1", ParseIp(ht->entries.p[3].ip));
freehoststxt(&ht);
FreeHostsTxt(&ht);
fclose(f);
}
TEST(parsehoststxt, testIpv6_isIgnored) {
TEST(ParseHostsTxt, testIpv6_isIgnored) {
const char kInput[] = "::1 boop\n"
"203.0.113.2 cat # ignore me\n";
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
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);
EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].name]);
EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].canon]);
EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[0].ip));
freehoststxt(&ht);
FreeHostsTxt(&ht);
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);
}
TEST(parseresolvconf, testEmpty) {
TEST(ParseResolvConf, testEmpty) {
struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf));
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(0, parseresolvconf(rv, f));
ASSERT_EQ(0, ParseResolvConf(rv, f));
ASSERT_EQ(0, rv->nameservers.i);
freeresolvconf(&rv);
FreeResolvConf(&rv);
fclose(f);
}
TEST(parseresolvconf, testCorrectlyTokenizes) {
TEST(ParseResolvConf, testCorrectlyTokenizes) {
const char kInput[] = "# this is a comment\n"
"nameserver 203.0.113.2 \n"
" nameserver 203.0.113.1\n";
struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf));
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);
EXPECT_EQ(AF_INET, rv->nameservers.p[0].sin_family);
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(DNS_PORT, ntohs(rv->nameservers.p[1].sin_port));
EXPECT_STREQ("203.0.113.1", FormatIp(&rv->nameservers.p[1]));
freeresolvconf(&rv);
FreeResolvConf(&rv);
fclose(f);
}
TEST(parseresolvconf, testMulticastDnsThing_getsIgnored) {
TEST(ParseResolvConf, testMulticastDnsThing_getsIgnored) {
const char kInput[] = "search local # boop\n";
struct ResolvConf *rv = calloc(1, sizeof(struct ResolvConf));
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
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);
freeresolvconf(&rv);
FreeResolvConf(&rv);
fclose(f);
}

View File

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

View File

@ -27,7 +27,7 @@
static const char *EzIp4Lookup(const struct HostsTxt *ht, const char *name) {
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) {
static char g_ipbuf[16];
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) {
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"
"203.0.113.1 lol.example. lol\n"
"203.0.113.2 cat.example. cat\n";
TEST(resolvehoststxt, testBasicLookups) {
TEST(ResolveHostsTxt, testBasicLookups) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, parsehoststxt(ht, f));
sorthoststxt(ht);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
SortHostsTxt(ht);
ASSERT_EQ(5, ht->entries.i);
EXPECT_STREQ("127.0.0.1", EzIp4Lookup(ht, "localhost"));
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.example."));
EXPECT_EQ(NULL, EzIp4Lookup(ht, "boop"));
freehoststxt(&ht);
FreeHostsTxt(&ht);
fclose(f);
}
TEST(resolvehoststxt, testCanonicalize) {
TEST(ResolveHostsTxt, testCanonicalize) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, parsehoststxt(ht, f));
sorthoststxt(ht);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
SortHostsTxt(ht);
ASSERT_EQ(5, ht->entries.i);
EXPECT_STREQ("localhost", EzCanonicalize(ht, "localhost"));
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.example."));
EXPECT_EQ(NULL, EzCanonicalize(ht, "boop"));
freehoststxt(&ht);
FreeHostsTxt(&ht);
fclose(f);
}

View File

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

View File

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