Skip to content

Commit

Permalink
Merge remote-tracking branch 'evolvis/dns-things'
Browse files Browse the repository at this point in the history
  • Loading branch information
wbx-github committed Aug 25, 2021
2 parents ca958dc + 0f822af commit 0894e87
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 137 deletions.
2 changes: 1 addition & 1 deletion libc/inet/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CSRC-$(V4_OR_V6) += \
inet_lnaof.c inet_netof.c
# multi source resolv.c
CSRC-$(V4_OR_V6) += \
encodeh.c decodeh.c encoded.c decoded.c \
encodeh.c decodeh.c \
encodeq.c encodea.c \
read_etc_hosts_r.c \
dnslookup.c opennameservers.c closenameservers.c \
Expand Down
8 changes: 0 additions & 8 deletions libc/inet/decoded.c

This file was deleted.

8 changes: 0 additions & 8 deletions libc/inet/encoded.c

This file was deleted.

189 changes: 69 additions & 120 deletions libc/inet/resolv.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/*
* Portions Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
* Portions Copyright © 2021 mirabilos <m@mirbsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -395,14 +396,6 @@ extern int __dns_lookup(const char *name,
int type,
unsigned char **outpacket,
struct resolv_answer *a) attribute_hidden;
extern int __encode_dotted(const char *dotted,
unsigned char *dest,
int maxlen) attribute_hidden;
extern int __decode_dotted(const unsigned char *packet,
int offset,
int packet_len,
char *dest,
int dest_len) attribute_hidden;
extern int __encode_header(struct resolv_header *h,
unsigned char *dest,
int maxlen) attribute_hidden;
Expand All @@ -416,6 +409,13 @@ extern int __encode_answer(struct resolv_answer *a,
int maxlen) attribute_hidden;
extern void __open_nameservers(void) attribute_hidden;
extern void __close_nameservers(void) attribute_hidden;
extern int __hnbad(const char *dotted) attribute_hidden;

#define __encode_dotted(dotted,dest,maxlen) \
dn_comp((dotted), (dest), (maxlen), NULL, NULL)
#define __decode_dotted(packet,offset,packet_len,dest,dest_len) \
dn_expand((packet), (packet) + (packet_len), (packet) + (offset), \
(dest), (dest_len))

/*
* Theory of operation.
Expand Down Expand Up @@ -552,116 +552,6 @@ void __decode_header(unsigned char *data,
#endif /* L_decodeh */


#ifdef L_encoded

/* Encode a dotted string into nameserver transport-level encoding.
This routine is fairly dumb, and doesn't attempt to compress
the data */
int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
{
unsigned used = 0;

while (dotted && *dotted) {
char *c = strchr(dotted, '.');
int l = c ? c - dotted : strlen(dotted);

/* two consecutive dots are not valid */
if (l == 0)
return -1;

if (l >= (maxlen - used - 1))
return -1;

dest[used++] = l;
memcpy(dest + used, dotted, l);
used += l;

if (!c)
break;
dotted = c + 1;
}

if (maxlen < 1)
return -1;

dest[used++] = 0;

return used;
}
#endif /* L_encoded */


#ifdef L_decoded

/* Decode a dotted string from nameserver transport-level encoding.
This routine understands compressed data. */
int __decode_dotted(const unsigned char *packet,
int offset,
int packet_len,
char *dest,
int dest_len)
{
unsigned b;
bool measure = 1;
unsigned total = 0;
unsigned used = 0;
unsigned maxiter = 256;

if (!packet)
return -1;

dest[0] = '\0';
while (--maxiter) {
if (offset >= packet_len)
return -1;
b = packet[offset++];
if (b == 0)
break;

if (measure)
total++;

if ((b & 0xc0) == 0xc0) {
if (offset >= packet_len)
return -1;
if (measure)
total++;
/* compressed item, redirect */
offset = ((b & 0x3f) << 8) | packet[offset];
measure = 0;
continue;
}

if (used + b + 1 >= dest_len)
return -1;
if (offset + b >= packet_len)
return -1;
memcpy(dest + used, packet + offset, b);
offset += b;
used += b;

if (measure)
total += b;

if (packet[offset] != 0)
dest[used++] = '.';
else
dest[used++] = '\0';
}
if (!maxiter)
return -1;

/* The null byte must be counted too */
if (measure)
total++;

DPRINTF("Total decode len = %d\n", total);

return total;
}
#endif /* L_decoded */


#ifdef L_encodeq

int __encode_question(const struct resolv_question *q,
Expand Down Expand Up @@ -1204,6 +1094,7 @@ int __dns_lookup(const char *name,
bool ends_with_dot;
bool contains_dot;
sockaddr46_t sa;
int num_answers;

fd = -1;
lookup = NULL;
Expand Down Expand Up @@ -1446,6 +1337,7 @@ int __dns_lookup(const char *name,
goto fail1;
}
pos = HFIXEDSZ;
/*XXX TODO: check that question matches query (and qdcount==1?) */
for (j = 0; j < h.qdcount; j++) {
DPRINTF("Skipping question %d at %d\n", j, pos);
i = __length_question(packet + pos, packet_len - pos);
Expand All @@ -1460,19 +1352,23 @@ int __dns_lookup(const char *name,
DPRINTF("Decoding answer at pos %d\n", pos);

first_answer = 1;
num_answers = 0;
a->dotted = NULL;
for (j = 0; j < h.ancount; j++) {
i = __decode_answer(packet, pos, packet_len, &ma);
if (i < 0) {
DPRINTF("failed decode %d\n", i);
/* If the message was truncated but we have
* decoded some answers, pretend it's OK */
if (j && h.tc)
if (num_answers && h.tc)
break;
goto try_next_server;
}
pos += i;

if (__hnbad(ma.dotted))
break;
++num_answers;
if (first_answer) {
ma.buf = a->buf;
ma.buflen = a->buflen;
Expand Down Expand Up @@ -1502,6 +1398,10 @@ int __dns_lookup(const char *name,
++a->add_count;
}
}
if (!num_answers) {
h_errno = NO_RECOVERY;
goto fail1;
}

/* Success! */
DPRINTF("Answer name = |%s|\n", a->dotted);
Expand Down Expand Up @@ -2468,7 +2368,7 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen,
/* Decode CNAME into buf, feed it to __dns_lookup() again */
i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
free(packet);
if (i < 0) {
if (i < 0 || __hnbad(buf)) {
*h_errnop = NO_RECOVERY;
return -1;
}
Expand All @@ -2477,6 +2377,10 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen,
if (a.atype == T_PTR) { /* ADDRESS */
i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
free(packet);
if (__hnbad(buf)) {
*h_errnop = NO_RECOVERY;
return -1;
}
result_buf->h_name = buf;
result_buf->h_addrtype = type;
result_buf->h_length = addrlen;
Expand Down Expand Up @@ -3041,6 +2945,51 @@ int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
}
libc_hidden_def(ns_name_pton)

/*
* __hnbad(dotted)
* Check whether a name is valid enough for DNS. The rules, as
* laid down by glibc, are:
* - printable input string
* - converts to label notation
* - each label only contains [0-9a-zA-Z_-], up to 63 octets
* - first label doesn’t begin with ‘-’
* This both is weaker than Unix hostnames (e.g. it allows
* underscores and leading/trailing hyphen-minus) and stronger
* than general (e.g. a leading “*.” is valid sometimes), take care.
* return:
* 0 if the name is ok
*/
int __hnbad(const char *dotted)
{
unsigned char c, n, *cp;
unsigned char buf[NS_MAXCDNAME];

cp = (unsigned char *)dotted;
while ((c = *cp++))
if (c < 0x21 || c > 0x7E)
return (1);
if (ns_name_pton(dotted, buf, sizeof(buf)) < 0)
return (2);
if (buf[0] > 0 && buf[1] == '-')
return (3);
cp = buf;
while ((n = *cp++)) {
if (n > 63)
return (4);
while (n--) {
c = *cp++;
if (c < '-' ||
(c > '-' && c < '0') ||
(c > '9' && c < 'A') ||
(c > 'Z' && c < '_') ||
(c > '_' && c < 'a') ||
c > 'z')
return (5);
}
}
return (0);
}

/*
* ns_name_unpack(msg, eom, src, dst, dstsiz)
* Unpack a domain name from a message, source may be compressed.
Expand Down

0 comments on commit 0894e87

Please sign in to comment.