options/posix: parse CNAME DNS record

This commit is contained in:
Geert Custers 2020-07-22 14:44:25 +02:00
parent 1729680c1f
commit 05018a7921
3 changed files with 57 additions and 40 deletions

View file

@ -14,6 +14,11 @@
namespace mlibc {
namespace {
constexpr unsigned int RECORD_A = 1;
constexpr unsigned int RECORD_CNAME = 5;
}
static frg::string<MemoryAllocator> read_dns_name(char *buf, char *&it) {
frg::string<MemoryAllocator> res{getAllocator()};
while (true) {
@ -40,7 +45,8 @@ static frg::string<MemoryAllocator> read_dns_name(char *buf, char *&it) {
return res;
}
int lookup_name_dns(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, const char *name) {
int lookup_name_dns(struct lookup_result &buf, const char *name,
frg::string<MemoryAllocator> &canon_name) {
frg::string<MemoryAllocator> request{getAllocator()};
int num_q = 1;
@ -118,19 +124,29 @@ int lookup_name_dns(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, cons
for (int i = 0; i < ntohs(response_header->no_ans); i++) {
struct dns_addr_buf buffer;
auto dns_name = read_dns_name(response, it);
buffer.name = std::move(dns_name);
uint16_t rr_type = (it[0] << 8) | it[1];
uint16_t rr_class = (it[2] << 8) | it[3];
uint16_t rr_length = (it[8] << 8) | it[9];
it += 10;
if (rr_type == 1) {
memcpy(buffer.addr, it, rr_length);
buffer.family = AF_INET;
buf.push_back(std::move(buffer));
switch (rr_type) {
case RECORD_A:
memcpy(buffer.addr, it, rr_length);
it += rr_length;
buffer.family = AF_INET;
buffer.name = std::move(dns_name);
buf.buf.push(std::move(buffer));
break;
case RECORD_CNAME:
canon_name = std::move(read_dns_name(response, it));
buf.aliases.push(std::move(dns_name));
break;
default:
mlibc::infoLogger() << "lookup_name_dns: unknown rr type "
<< rr_type << frg::endlog;
break;
}
it += rr_length;
}
num_ans += ntohs(response_header->no_ans);
@ -139,10 +155,10 @@ int lookup_name_dns(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, cons
}
close(fd);
return buf.size();
return buf.buf.size();
}
int lookup_name_hosts(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, const char *name,
int lookup_name_hosts(struct lookup_result &buf, const char *name,
frg::string<MemoryAllocator> &canon_name) {
auto file = fopen("/etc/hosts", "r");
if (!file) {
@ -189,24 +205,23 @@ int lookup_name_hosts(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, co
buffer.family = AF_INET;
buffer.name = frg::string<MemoryAllocator>{pos,
static_cast<size_t>(end - pos), getAllocator()};
if (!canon_name.size())
canon_name = buffer.name;
canon_name = buffer.name;
buf.push(std::move(buffer));
buf.buf.push(std::move(buffer));
pos = end;
while (pos[1]) {
for (; *pos && isspace(*pos); pos++);
for (end = pos; *end && !isspace(*end); end++);
buffer.name = frg::string<MemoryAllocator>{pos,
auto name = frg::string<MemoryAllocator>{pos,
static_cast<size_t>(end - pos), getAllocator()};
buf.push(std::move(buffer));
buf.aliases.push(std::move(name));
pos = end;
}
}
fclose(file);
return buf.size();
return buf.buf.size();
}
} // namespace mlibc

View file

@ -66,12 +66,12 @@ int getaddrinfo(const char *__restrict node, const char *__restrict service,
if (serv_count < 0)
return -serv_count;
frg::vector<struct mlibc::dns_addr_buf, MemoryAllocator> addr_buf(getAllocator());
struct mlibc::lookup_result addr_buf;
int addr_count = 1;
frg::string<MemoryAllocator> canon{getAllocator()};
if (node) {
if ((addr_count = mlibc::lookup_name_hosts(addr_buf, node, canon)) <= 0)
addr_count = mlibc::lookup_name_dns(addr_buf, node);
addr_count = mlibc::lookup_name_dns(addr_buf, node, canon);
else
addr_count = 1;
if (addr_count < 0)
@ -83,32 +83,30 @@ int getaddrinfo(const char *__restrict node, const char *__restrict service,
auto out = (struct mlibc::ai_buf *) calloc(serv_count * addr_count,
sizeof(struct addrinfo));
if (node && !canon.size()) {
//TODO(geert): this should be part of lookup_name_dns()
if (node && !canon.size())
canon = frg::string<MemoryAllocator>{node, getAllocator()};
}
for (int i = 0, k = 0; i < addr_count; i++) {
for (int j = 0; j < serv_count; j++, k++) {
out[i].ai.ai_family = addr_buf[i].family;
out[i].ai.ai_family = addr_buf.buf[i].family;
out[i].ai.ai_socktype = serv_buf[j].socktype;
out[i].ai.ai_protocol = serv_buf[j].protocol;
out[i].ai.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
out[i].ai.ai_addr = (struct sockaddr *) &out[i].sa;
out[i].ai.ai_canonname = canon.data();
out[i].ai.ai_next = NULL;
switch (addr_buf[i].family) {
switch (addr_buf.buf[i].family) {
case AF_INET:
out[i].ai.ai_addrlen = sizeof(struct sockaddr_in);
out[i].sa.sin.sin_port = serv_buf[j].port;
out[i].sa.sin.sin_family = AF_INET;
memcpy(&out[i].sa.sin.sin_addr, addr_buf[i].addr, 4);
memcpy(&out[i].sa.sin.sin_addr, addr_buf.buf[i].addr, 4);
break;
case AF_INET6:
out[i].ai.ai_addrlen = sizeof(struct sockaddr_in6);
out[i].sa.sin6.sin6_family = serv_buf[j].port;
out[i].sa.sin6.sin6_family = AF_INET6;
memcpy(&out[i].sa.sin6.sin6_addr, addr_buf[i].addr, 16);
memcpy(&out[i].sa.sin6.sin6_addr, addr_buf.buf[i].addr, 16);
break;
}
}
@ -151,11 +149,11 @@ struct hostent *gethostbyname(const char *name) {
return NULL;
}
frg::vector<struct mlibc::dns_addr_buf, MemoryAllocator> buf(getAllocator());
struct mlibc::lookup_result buf;
frg::string<MemoryAllocator> canon{getAllocator()};
int ret = 0;
if ((ret = mlibc::lookup_name_hosts(buf, name, canon)) <= 0)
ret = mlibc::lookup_name_dns(buf, name);
ret = mlibc::lookup_name_dns(buf, name, canon);
if (ret <= 0) {
h_errno = HOST_NOT_FOUND;
return NULL;
@ -181,14 +179,10 @@ struct hostent *gethostbyname(const char *name) {
h.h_name = canon.data();
h.h_aliases = reinterpret_cast<char**>(malloc((ret + 1) * sizeof(char*)));
h.h_aliases = reinterpret_cast<char**>(malloc((buf.aliases.size() + 1)
* sizeof(char*)));
int alias_pos = 0;
for (int i = 0; i < ret; i++) {
auto &buf_name = buf[i].name;
if (buf_name == canon)
continue;
// we have found an entry that is an alias
for (auto &buf_name : buf.aliases) {
h.h_aliases[alias_pos] = buf_name.data();
buf_name.detach();
alias_pos++;
@ -197,7 +191,7 @@ struct hostent *gethostbyname(const char *name) {
canon.detach();
// just pick the first family as the one for all addresses...??
h.h_addrtype = buf[0].family;
h.h_addrtype = buf.buf[0].family;
if (h.h_addrtype != AF_INET && h.h_addrtype != AF_INET6) {
// this is not allowed per spec
h_errno = NO_DATA;
@ -209,10 +203,10 @@ struct hostent *gethostbyname(const char *name) {
h.h_addr_list = reinterpret_cast<char**>(malloc((ret + 1) * sizeof(char*)));
int addr_pos = 0;
for (int i = 0; i < ret; i++) {
if (buf[i].family != h.h_addrtype)
if (buf.buf[i].family != h.h_addrtype)
continue;
h.h_addr_list[addr_pos] = reinterpret_cast<char*>(malloc(h.h_length));
memcpy(h.h_addr_list[addr_pos], buf[i].addr, h.h_length);
memcpy(h.h_addr_list[addr_pos], buf.buf[i].addr, h.h_length);
addr_pos++;
}
h.h_addr_list[addr_pos] = NULL;

View file

@ -11,13 +11,20 @@
namespace mlibc {
struct dns_addr_buf {
dns_addr_buf() : name(getAllocator())
{}
dns_addr_buf()
: name(getAllocator()) {}
frg::string<MemoryAllocator> name;
int family;
uint8_t addr[16];
};
struct lookup_result {
lookup_result()
: buf(getAllocator()), aliases(getAllocator()) {}
frg::vector<struct dns_addr_buf, MemoryAllocator> buf;
frg::vector<frg::string<MemoryAllocator>, MemoryAllocator> aliases;
};
struct dns_header {
uint16_t identification;
uint16_t flags;
@ -35,8 +42,9 @@ struct ai_buf {
} sa;
};
int lookup_name_dns(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, const char *name);
int lookup_name_hosts(frg::vector<struct dns_addr_buf, MemoryAllocator> &buf, const char *name,
int lookup_name_dns(struct lookup_result &buf, const char *name,
frg::string<MemoryAllocator> &canon_name);
int lookup_name_hosts(struct lookup_result &buf, const char *name,
frg::string<MemoryAllocator> &canon_name);
} // namespace mlibc