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) */
uint32_t name; /* &ht->strings.p[he->name] */
uint32_t canon; /* &ht->strings.p[he->canon] */
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,65 +47,62 @@
* @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) {
p += strnlen((char *)p, pe - p) + 1 + 4;
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;
h2.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[0] & 0b11000000) == 0b11000000) { /* name pointer */
p += 2;
} else {
p += strnlen((char *)p, pe - p) + 1;
}
if (p + 2 + 2 + 4 + 2 < pe) {
rtype = READ16BE(p), p += 2;
rclass = READ16BE(p), p += 2;
/* ttl */ p += 4;
rdlength = READ16BE(p), p += 2;
if (p + rdlength <= pe && rdlength == 4 &&
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
res = 1;
if (addrsize) {
if (addrsize >= kMinSockaddr4Size) {
addr4 = (struct sockaddr_in *)addr;
addr4->sin_family = AF_INET;
memcpy(&addr4->sin_addr.s_addr, p, 4);
} else {
res = einval();
}
if (p + 2 + 2 + 4 + 2 < pe) {
rtype = READ16BE(p), p += 2;
rclass = READ16BE(p), p += 2;
/* ttl */ p += 4;
rdlength = READ16BE(p), p += 2;
if (p + rdlength <= pe && rdlength == 4 &&
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
rc = 1;
if (addrsize) {
if (addrsize >= kMinSockaddr4Size) {
a4 = (struct sockaddr_in *)addr;
a4->sin_family = AF_INET;
memcpy(&a4->sin_addr.s_addr, p, 4);
} else {
rc = einval();
}
}
}
@ -113,8 +110,7 @@ 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;
}