[PATCH 0/4] Create DNS API and wire it to dhcp and libc DNS resolver

3 views
Skip to first unread message

Benoît Canet

unread,
Oct 6, 2013, 7:01:13 AM10/6/13
to osv...@googlegroups.com, a...@cloudius-systems.com, Benoît Canet
This patchset is written to close issue #9.
Tests can be done before/after the patchset with tst-dns-resolver.so

Best regards

Benoît

Benoît Canet (4):
dns: add core/dns API
dhcp: wire dhcp and DNS API together
libc: convert __dns.c to __dns.cc
dns: wire OSv DNS API and libc dns lookup code together.

build.mk | 1 +
core/dhcp.cc | 6 +++
core/dns.cc | 16 ++++++
include/dhcp.hh | 4 ++
include/dns.hh | 100 +++++++++++++++++++++++++++++++++++++
libc/network/{__dns.c => __dns.cc} | 60 ++++++++++++++++------
libc/network/{__dns.h => __dns.hh} | 8 +++
libc/network/__ipparse.c | 2 +-
libc/network/getaddrinfo.c | 2 +-
libc/network/getnameinfo.c | 2 +-
10 files changed, 183 insertions(+), 18 deletions(-)
create mode 100644 core/dns.cc
create mode 100644 include/dns.hh
rename libc/network/{__dns.c => __dns.cc} (79%)
rename libc/network/{__dns.h => __dns.hh} (85%)

--
1.8.1.2

Benoît Canet

unread,
Oct 6, 2013, 7:01:14 AM10/6/13
to osv...@googlegroups.com, a...@cloudius-systems.com, Benoît Canet
This API will be used to glue the dhcp server with the libc dns lookup code.

Signed-off-by: Benoit Canet <ben...@irqsave.net>
---
build.mk | 1 +
core/dns.cc | 16 +++++++++
include/dns.hh | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 117 insertions(+)
create mode 100644 core/dns.cc
create mode 100644 include/dns.hh

diff --git a/build.mk b/build.mk
index eaf5449..2010ecf 100644
--- a/build.mk
+++ b/build.mk
@@ -506,6 +506,7 @@ objects += core/percpu.o
objects += core/per-cpu-counter.o
objects += core/percpu-worker.o
objects += core/dhcp.o
+objects += core/dns.o

include $(src)/fs/build.mk
include $(src)/libc/build.mk
diff --git a/core/dns.cc b/core/dns.cc
new file mode 100644
index 0000000..cf98e49
--- /dev/null
+++ b/core/dns.cc
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 Nodalink, SARL.
+ *
+ * author: Benoît Canet <benoit...@irqsave.net>
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <dns.hh>
+
+namespace osv {
+
+dnsconfig* dnsconfig::_instance = nullptr;
+
+}
diff --git a/include/dns.hh b/include/dns.hh
new file mode 100644
index 0000000..ce57df5
--- /dev/null
+++ b/include/dns.hh
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 Nodalink, SARL.
+ *
+ * author: Benoît Canet <benoit...@irqsave.net>
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef __OSV_CORE_DNS_HH__
+#define __OSV_CORE_DNS_HH__
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <osv/mutex.h>
+
+#include <boost/asio/ip/address.hpp>
+
+#define dns_configuration (osv::dnsconfig::instance())
+
+namespace osv {
+
+template <class T> class config {
+public:
+ config() = default;
+
+ void clear() {
+ WITH_LOCK(_lock) {
+ _set.clear();
+ }
+ }
+
+ std::vector<T> get()
+ {
+ WITH_LOCK(_lock) {
+ std::vector<T> result(_set.begin(), _set.end());
+ return result;
+ }
+ }
+
+ void add(T x)
+ {
+ WITH_LOCK(_lock) {
+ _set.insert(x);
+ }
+ }
+
+ void remove(T x)
+ {
+ WITH_LOCK(_lock) {
+ _set.erase(x);
+ }
+ }
+
+ void update(std::vector<T> &remove, std::vector<T> &add)
+ {
+ WITH_LOCK(_lock) {
+ _erase(remove);
+ copy(add.begin(), add.end(), inserter(_set, _set.end()));
+ }
+ }
+
+private:
+ void _erase(std::vector<T> &vect)
+ {
+ // must be called under _lock
+ for(auto it = vect.begin(); it != vect.end(); ++it) {
+ _set.erase(*it);
+ }
+ }
+
+ mutex _lock;
+ std::set<T> _set;
+};
+
+class dnsconfig {
+public:
+ dnsconfig() = default;
+
+ static dnsconfig* instance() {
+ if (_instance == nullptr) {
+ _instance = new dnsconfig();
+ }
+ return (_instance);
+ }
+
+ config<boost::asio::ip::address> nameservers;
+ config<std::string> search_domains;
+
+private:
+ static dnsconfig* _instance;
+};
+
+}
+
+#endif //! __OSV_CORE_DNS_HH__
--
1.8.1.2

Benoît Canet

unread,
Oct 6, 2013, 7:01:15 AM10/6/13
to osv...@googlegroups.com, a...@cloudius-systems.com, Benoît Canet
Signed-off-by: Benoit Canet <ben...@irqsave.net>
---
core/dhcp.cc | 6 ++++++
include/dhcp.hh | 4 ++++
2 files changed, 10 insertions(+)

diff --git a/core/dhcp.cc b/core/dhcp.cc
index 8800a17..06acf78 100644
--- a/core/dhcp.cc
+++ b/core/dhcp.cc
@@ -27,6 +27,7 @@

#include <debug.hh>
#include <dhcp.hh>
+#include <dns.hh>
#include <drivers/clock.hh>

using namespace boost::asio;
@@ -497,6 +498,11 @@ namespace dhcp {
"0.0.0.0",
dm.get_router_ip().to_string().c_str());

+ // Communicate DNS IPs to the DNS API
+ _old_dns_ips = _dns_ips;
+ _dns_ips = dm.get_dns_ips();
+ dns_configuration->nameservers.update(_old_dns_ips, _dns_ips);
+
// Send a DHCP Request
_state = DHCP_REQUEST;
dhcp_mbuf dm_req(false);
diff --git a/include/dhcp.hh b/include/dhcp.hh
index 827657f..4d74823 100644
--- a/include/dhcp.hh
+++ b/include/dhcp.hh
@@ -19,6 +19,7 @@
#include <osv/mutex.h>
#include <osv/debug.h>

+#include <boost/asio.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/address_v4.hpp>

@@ -222,6 +223,9 @@ namespace dhcp {
struct ifnet* _ifp;
dhcp_socket* _sock;

+ std::vector<boost::asio::ip::address> _dns_ips;
+ std::vector<boost::asio::ip::address> _old_dns_ips;
+
// Transaction id
u32 _xid;
};
--
1.8.1.2

Benoît Canet

unread,
Oct 6, 2013, 7:01:17 AM10/6/13
to osv...@googlegroups.com, a...@cloudius-systems.com, Benoît Canet
This patch fixes issue #8 "Make Java InetAddress.getHostName() work".

Tests could be done with tst-dns-resolver.so.

Signed-off-by: Benoit Canet <ben...@irqsave.net>
---
libc/network/__dns.cc | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/libc/network/__dns.cc b/libc/network/__dns.cc
index 8986077..9ca110e 100644
--- a/libc/network/__dns.cc
+++ b/libc/network/__dns.cc
@@ -14,6 +14,8 @@
#include "__dns.hh"
#include <stdio.h>

+#include <dns.hh>
+
#define TIMEOUT 5
#define RETRY 1000
#define PACKET_MAX 512
@@ -66,9 +68,35 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
clock_gettime(CLOCK_REALTIME, &ts);
id = (ts.tv_nsec + ts.tv_nsec/65536UL) & 0xffff;

+ /* Get nameservers from OSv first, fallback to resolv.conf */
+ auto dns_ips = dns_configuration->nameservers.get();
+ nns = 0;
+ for (auto it = dns_ips.begin(); nns < 3 && it != dns_ips.end(); ++it) {
+ auto ip = (*it);
+ if (ip.is_v4()) {
+ boost::asio::ip::address_v4::bytes_type bytes;
+ bytes = ip.to_v4().to_bytes();
+ memcpy(&ns[nns].sin.sin_addr.s_addr, &bytes,
+ sizeof(bytes));
+ ns[nns].sin.sin_family = family = AF_INET;
+ sl = sizeof sa.sin;
+ } else if (ip.is_v6()) {
+ boost::asio::ip::address_v6::bytes_type bytes;
+ bytes = ip.to_v6().to_bytes();
+ memcpy(&ns[nns].sin6.sin6_addr.s6_addr, &bytes,
+ sizeof(bytes));
+ ns[nns].sin6.sin6_family = family = AF_INET6;
+ sl = sizeof sa.sin6;
+ } else {
+ continue;
+ }
+ ns[nns].sin.sin_port = htons(53);
+ nns++;
+ }
+
/* Get nameservers from resolv.conf, fallback to localhost */
f = fopen("/etc/resolv.conf", "r");
- if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
+ if (f) for (;nns<3 && fgets(line, sizeof line, f); ) {
if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
continue;
for (s=line+11; isspace(*s); s++);
--
1.8.1.2

Benoît Canet

unread,
Oct 6, 2013, 7:01:16 AM10/6/13
to osv...@googlegroups.com, a...@cloudius-systems.com, Benoît Canet
Also convert it's header and change it's caller includes.

This patch is done so the libc resolver will be able to retrieve the dns from
OSv dns API.

Signed-off-by: Benoit Canet <ben...@irqsave.net>
---
libc/network/{__dns.c => __dns.cc} | 30 ++++++++++++++++--------------
libc/network/{__dns.h => __dns.hh} | 8 ++++++++
libc/network/__ipparse.c | 2 +-
libc/network/getaddrinfo.c | 2 +-
libc/network/getnameinfo.c | 2 +-
5 files changed, 27 insertions(+), 17 deletions(-)
rename libc/network/{__dns.c => __dns.cc} (90%)
rename libc/network/{__dns.h => __dns.hh} (85%)

diff --git a/libc/network/__dns.c b/libc/network/__dns.cc
similarity index 90%
rename from libc/network/__dns.c
rename to libc/network/__dns.cc
index 68ef63c..8986077 100644
--- a/libc/network/__dns.c
+++ b/libc/network/__dns.cc
@@ -11,7 +11,7 @@
#include <ctype.h>
#include <unistd.h>
#include <pthread.h>
-#include "__dns.h"
+#include "__dns.hh"
#include <stdio.h>

#define TIMEOUT 5
@@ -33,7 +33,7 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
union {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
- } sa = {0}, ns[3] = {{0}};
+ } sa = {{0}}, ns[3] = {{{0}}};
socklen_t sl = 0;
int nns = 0;
int family = AF_UNSPEC;
@@ -64,7 +64,7 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)

/* Make a reasonably unpredictable id */
clock_gettime(CLOCK_REALTIME, &ts);
- id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff;
+ id = (ts.tv_nsec + ts.tv_nsec/65536UL) & 0xffff;

/* Get nameservers from resolv.conf, fallback to localhost */
f = fopen("/etc/resolv.conf", "r");
@@ -95,7 +95,7 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
//pthread_cleanup_push(cleanup, (void *)(intptr_t)fd);
//pthread_setcancelstate(cs, 0);

- if (bind(fd, (void *)&sa, sl) < 0) {
+ if (bind(fd, (const sockaddr*)&sa, sl) < 0) {
errcode = EAI_SYSTEM;
goto out;
}
@@ -108,10 +108,11 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)

/* Query all configured namservers in parallel */
for (i=0; i<rrcnt; i++) if (rr[i]) for (j=0; j<nns; j++) {
- q[0] = id+i >> 8;
+ q[0] = (id+i) >> 8;
q[1] = id+i;
q[ql-3] = rr[i];
- sendto(fd, q, ql, MSG_NOSIGNAL, (void *)&ns[j], sl);
+ sendto(fd, q, ql, MSG_NOSIGNAL,
+ (const sockaddr*)&ns[j], sl);
}

/* Wait for a response, or until time to retry */
@@ -119,15 +120,16 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)

/* Process any and all replies */
while (got+failed < rrcnt && (rlen = recvfrom(fd, r, 512, 0,
- (void *)&sa, (socklen_t[1]){sl})) >= 2)
+ (sockaddr*)&sa, (socklen_t *)&sl)) >= 2)
{
/* Ignore replies from addresses we didn't send to */
for (i=0; i<nns; i++) if (!memcmp(ns+i, &sa, sl)) break;
if (i==nns) continue;

/* Compute index of the query from id */
- i = r[0]*256+r[1] - id & 0xffff;
- if ((unsigned)i >= rrcnt || !rr[i]) continue;
+ i = (r[0]*256+r[1] - id) & 0xffff;
+ if ((unsigned int)i >= (unsigned int) rrcnt || !rr[i])
+ continue;

/* Interpret the result code */
switch (r[3] & 15) {
@@ -181,8 +183,8 @@ int __dns_query(unsigned char *r, const void *a, int family, int ptr)
int rr[2], rrcnt = 1;

if (ptr) {
- if (family == AF_INET6) mkptr6(buf, a);
- else mkptr4(buf, a);
+ if (family == AF_INET6) mkptr6(buf, (unsigned char *) a);
+ else mkptr4(buf, (unsigned char *) a);
rr[0] = RR_PTR;
a = buf;
} else if (family == AF_INET6) {
@@ -192,7 +194,7 @@ int __dns_query(unsigned char *r, const void *a, int family, int ptr)
if (family != AF_INET) rr[rrcnt++] = RR_AAAA;
}

- return __dns_doqueries(r, a, rr, rrcnt);
+ return __dns_doqueries(r, (const char *)a, rr, rrcnt);
}


@@ -248,10 +250,10 @@ int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const u
p += 1 + !!*p;
len = p[8]*256 + p[9];
if (p+len > r+512) return -1;
- if (p[1]==rr && len <= maxlen) {
+ if (p[1]==rr && (size_t)len <= maxlen) {
if (dec && decname(tmp, r, p+10)<0) return -1;
if (dest && limit) {
- if (dec) strcpy(dest, tmp);
+ if (dec) strcpy((char *)dest, tmp);
else memcpy(dest, p+10, len);
dest = (char *)dest + stride;
limit--;
diff --git a/libc/network/__dns.h b/libc/network/__dns.hh
similarity index 85%
rename from libc/network/__dns.h
rename to libc/network/__dns.hh
index 9a3f740..b9b3945 100644
--- a/libc/network/__dns.h
+++ b/libc/network/__dns.hh
@@ -5,6 +5,10 @@
#define RR_PTR 12
#define RR_AAAA 28

+#ifdef __cplusplus
+extern "C" {
+#endif
+
int __dns_count_addrs(const unsigned char *, int);
int __dns_get_rr(void *, size_t, size_t, size_t, const unsigned char *, int, int);

@@ -12,3 +16,7 @@ int __dns_query(unsigned char *, const void *, int, int);
int __ipparse(void *, int, const char *);

int __dns_doqueries(unsigned char *, const char *, int *, int);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libc/network/__ipparse.c b/libc/network/__ipparse.c
index b0647aa..0e3c0a4 100644
--- a/libc/network/__ipparse.c
+++ b/libc/network/__ipparse.c
@@ -3,7 +3,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "__dns.h"
+#include "__dns.hh"
#include <stdio.h>

int __ipparse(void *dest, int family, const char *s0)
diff --git a/libc/network/getaddrinfo.c b/libc/network/getaddrinfo.c
index 749b60f..b0d10e0 100644
--- a/libc/network/getaddrinfo.c
+++ b/libc/network/getaddrinfo.c
@@ -6,7 +6,7 @@
#include <unistd.h>
#include <string.h>
#include <ctype.h>
-#include "__dns.h"
+#include "__dns.hh"
#include <stdio.h>

static int is_valid(const char *host)
diff --git a/libc/network/getnameinfo.c b/libc/network/getnameinfo.c
index b756e6e..fc5acf6 100644
--- a/libc/network/getnameinfo.c
+++ b/libc/network/getnameinfo.c
@@ -8,7 +8,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "__dns.h"
+#include "__dns.hh"

int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
char *restrict node, socklen_t nodelen,
--
1.8.1.2

Avi Kivity

unread,
Oct 6, 2013, 8:11:13 AM10/6/13
to Benoît Canet, osv...@googlegroups.com
On 10/06/2013 02:01 PM, Benoît Canet wrote:
> This API will be used to glue the dhcp server with the libc dns lookup code.
>
This is too heavyweight IMO. A simple set_dns_config(vector<ip::address>
nameservers, vector<string> search_domains) is easier to use. Also, you
can put it straight in __dns.cc, no need for a third party. This way you
don't need a public read API, just write.

Benoît Canet

unread,
Oct 6, 2013, 8:19:18 AM10/6/13
to Avi Kivity, osv...@googlegroups.com
Le Sunday 06 Oct 2013 � 15:11:13 (+0300), Avi Kivity a �crit :
> On 10/06/2013 02:01 PM, Beno�t Canet wrote:
> >This API will be used to glue the dhcp server with the libc dns lookup code.
> >
> >@@ -0,0 +1,16 @@
> >+/*
> >+ * Copyright (C) 2013 Nodalink, SARL.
> >+ *
> >+ * author: Beno�t Canet <benoit...@irqsave.net>
> >+ *
> >+ * This work is open source software, licensed under the terms of the
> >+ * BSD license as described in the LICENSE file in the top-level directory.
> >+ */
> >+
> >+#include <dns.hh>
> >+
> >+namespace osv {
> >+
> >+dnsconfig* dnsconfig::_instance = nullptr;
> >+
> >+}
> >diff --git a/include/dns.hh b/include/dns.hh
> >new file mode 100644
> >index 0000000..ce57df5
> >--- /dev/null
> >+++ b/include/dns.hh
> >@@ -0,0 +1,100 @@
> >+/*
> >+ * Copyright (C) 2013 Nodalink, SARL.
> >+ *
> >+ * author: Beno�t Canet <benoit...@irqsave.net>
There is still the need to arbitrate between dhcpv4,dhcpv6 and the cli.

What do you think about it ?

Best regards

Beno�t

Avi Kivity

unread,
Oct 6, 2013, 8:47:26 AM10/6/13
to Benoît Canet, osv...@googlegroups.com
On 10/06/2013 03:19 PM, Beno�t Canet wrote:
> This is too heavyweight IMO. A simple
> set_dns_config(vector<ip::address> nameservers, vector<string>
> search_domains) is easier to use. Also, you can put it straight in
> __dns.cc, no need for a third party. This way you don't need a
> public read API, just write.
>
> There is still the need to arbitrate between dhcpv4,dhcpv6 and the cli.
>
> What do you think about it ?
>

Is it meaningful to have dhcpv4 and dhcpv6 (or SLAAC) at the same time
giving different results?

Note that


+ // Communicate DNS IPs to the DNS API
+ _old_dns_ips = _dns_ips;
+ _dns_ips = dm.get_dns_ips();
+ dns_configuration->nameservers.update(_old_dns_ips, _dns_ips);
+

fails if _dns_ips match something from a different source. So let's stick with single updater for now, when we have actual problems we can investigate the best API.

You are right about the CLI; so we need a reader API as well. But I think vector<> get_nameserver() is sufficient.

Commit Bot

unread,
Oct 7, 2013, 5:27:06 AM10/7/13
to osv...@googlegroups.com
From: Benoît Canet <ben...@irqsave.net>

libc: convert __dns.c to __dns.cc

Also convert it's header and change it's caller includes.

This patch is done so the libc resolver will be able to retrieve the dns
from
OSv dns API.

Signed-off-by: Benoit Canet <ben...@irqsave.net>
Signed-off-by: Avi Kivity <a...@cloudius-systems.com>

---
diff --git a/libc/network/__dns.cc b/libc/network/__dns.cc
--- a/libc/network/__dns.cc
limit--;diff --git a/libc/network/__dns.hh b/libc/network/__dns.hh
--- a/libc/network/__dns.hh
+++ b/libc/network/__dns.hh
@@ -5,6 +5,10 @@
#define RR_PTR 12
#define RR_AAAA 28

+#ifdef __cplusplus
+extern "C" {
+#endif
+
int __dns_count_addrs(const unsigned char *, int);
int __dns_get_rr(void *, size_t, size_t, size_t, const unsigned char *,
int, int);

@@ -12,3 +16,7 @@
int __ipparse(void *, int, const char *);

int __dns_doqueries(unsigned char *, const char *, int *, int);
+
+#ifdef __cplusplus
+}
+#endifdiff --git a/libc/network/__ipparse.c b/libc/network/__ipparse.c
--- a/libc/network/__ipparse.c
+++ b/libc/network/__ipparse.c
@@ -3,7 +3,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "__dns.h"
+#include "__dns.hh"
#include <stdio.h>

int __ipparse(void *dest, int family, const char *s0)diff --git
a/libc/network/getaddrinfo.c b/libc/network/getaddrinfo.c
--- a/libc/network/getaddrinfo.c
+++ b/libc/network/getaddrinfo.c
@@ -6,7 +6,7 @@
#include <unistd.h>
#include <string.h>
#include <ctype.h>
-#include "__dns.h"
+#include "__dns.hh"
#include <stdio.h>

static int is_valid(const char *host)diff --git
a/libc/network/getnameinfo.c b/libc/network/getnameinfo.c
Reply all
Reply to author
Forward
0 new messages