net: dns client, support for A records
[quarnos.git] / services / dns_client.h
blob0b039c83749ae5eac2e7d96cff548b877278bd05
1 #ifndef _DNS_CLIENT_H_
2 #define _DNS_CLIENT_H_
4 #include "resources/net/client_socket.h"
5 #include "resources/net/udp.h"
6 #include "resources/net/ipv4_addr.h"
8 namespace services {
9 class dns_client {
10 private:
11 struct packet {
12 u16 id;
13 u16 flags;
14 u16 questions;
15 u16 answers;
16 u16 auth_rr;
17 u16 add_rr;
20 struct dns_answer {
21 u16 name;
22 u16 a_type;
23 u16 a_class;
24 u32 ttl;
25 u16 length;
26 u32 answer;
27 } __attribute__((packed));
29 enum {
30 dns_no_such_name = 3,
31 dns_non_auth_ok = 0x10,
32 dns_recursion = 0x100,
33 dns_truncated = 0x200,
34 dns_standard_query = 0,
35 dns_question = 0
39 struct dns_query {
40 u16 q_type;
41 u16 q_class;
44 enum dns_q_types {
45 dns_A = 1
48 enum dns_q_class {
49 dns_IN = 1
52 p<net::udp> u;
53 public:
54 void set(p<net::udp> _u) {
55 u = _u;
58 net::ipv4_addr get_ipv4(const string &host) {
59 p<packet> pkg = new packet;
60 pkg->id = to_be16(0xbeef);
61 pkg->flags = to_be16(dns_question | dns_standard_query | dns_recursion);
62 pkg->questions = to_be16(1);
63 pkg->answers = 0;
64 pkg->auth_rr = 0;
65 pkg->add_rr = 0;
67 buffer buf = buffer::to_mem(pkg);
69 list<string> subs = host.split('.');
70 for (int i = 0; i < subs.get_count(); i++) {
71 buffer size(1);
72 size[0] = subs[i].length();
73 buf += size;
74 buf += subs[i].to_mem().get_next(subs[i].length());
77 buffer nul(1);
78 nul[0] = 0;
79 buf += nul;
81 p<dns_query> q = new dns_query;
82 q->q_type = to_be16(dns_A);
83 q->q_class = to_be16(dns_IN);
85 buf += buffer::to_mem(q);
87 p<net::client_socket> client = u->create_client();
88 client->connect(net::ipv4_addr::from_le(62 << 24 | 148 << 16 | 87 << 8 | 180), 53);
89 client->write(buf);
91 buffer answer;
92 client->read(answer);
93 client->close();
95 if (answer.cast<packet>()->flags & dns_no_such_name)
96 return net::ipv4_addr::from_le(0);
98 answer = answer.cut_first(sizeof(packet));
99 int i;
100 for (i = 0; answer[i] && i < answer.get_size(); i++);
101 answer = answer.cut_first(i + 1 + sizeof(u16) * 2);
103 if (from_be16(answer.cast<dns_answer>()->a_type) != dns_A)
104 return net::ipv4_addr::from_le(0);
106 return net::ipv4_addr::from_be(answer.cast<dns_answer>()->answer);
111 #endif