]> git.proxmox.com Git - systemd.git/blame - src/resolve/resolved-dns-server.c
Imported Upstream version 227
[systemd.git] / src / resolve / resolved-dns-server.c
CommitLineData
5eef597e
MP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include "siphash24.h"
23
24#include "resolved-dns-server.h"
25
13d276d0
MP
26/* After how much time to repeat classic DNS requests */
27#define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
28#define DNS_TIMEOUT_MAX_USEC (5 * USEC_PER_SEC)
29
5eef597e
MP
30int dns_server_new(
31 Manager *m,
32 DnsServer **ret,
33 DnsServerType type,
34 Link *l,
35 int family,
36 const union in_addr_union *in_addr) {
37
38 DnsServer *s, *tail;
39
40 assert(m);
41 assert((type == DNS_SERVER_LINK) == !!l);
42 assert(in_addr);
43
44 s = new0(DnsServer, 1);
45 if (!s)
46 return -ENOMEM;
47
7035cd9e 48 s->n_ref = 1;
5eef597e
MP
49 s->type = type;
50 s->family = family;
51 s->address = *in_addr;
13d276d0 52 s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
5eef597e
MP
53
54 if (type == DNS_SERVER_LINK) {
55 LIST_FIND_TAIL(servers, l->dns_servers, tail);
56 LIST_INSERT_AFTER(servers, l->dns_servers, tail, s);
57 s->link = l;
58 } else if (type == DNS_SERVER_SYSTEM) {
59 LIST_FIND_TAIL(servers, m->dns_servers, tail);
60 LIST_INSERT_AFTER(servers, m->dns_servers, tail, s);
61 } else if (type == DNS_SERVER_FALLBACK) {
62 LIST_FIND_TAIL(servers, m->fallback_dns_servers, tail);
63 LIST_INSERT_AFTER(servers, m->fallback_dns_servers, tail, s);
64 } else
65 assert_not_reached("Unknown server type");
66
67 s->manager = m;
68
69 /* A new DNS server that isn't fallback is added and the one
70 * we used so far was a fallback one? Then let's try to pick
71 * the new one */
72 if (type != DNS_SERVER_FALLBACK &&
73 m->current_dns_server &&
74 m->current_dns_server->type == DNS_SERVER_FALLBACK)
75 manager_set_dns_server(m, NULL);
76
77 if (ret)
78 *ret = s;
79
80 return 0;
81}
82
7035cd9e 83DnsServer* dns_server_ref(DnsServer *s) {
5eef597e
MP
84 if (!s)
85 return NULL;
86
7035cd9e 87 assert(s->n_ref > 0);
e3bff60a 88
7035cd9e 89 s->n_ref ++;
e3bff60a 90
7035cd9e
MP
91 return s;
92}
93
94static DnsServer* dns_server_free(DnsServer *s) {
95 if (!s)
96 return NULL;
5eef597e 97
7035cd9e
MP
98 if (s->link && s->link->current_dns_server == s)
99 link_set_dns_server(s->link, NULL);
100
101 if (s->manager && s->manager->current_dns_server == s)
102 manager_set_dns_server(s->manager, NULL);
5eef597e 103
5eef597e
MP
104 free(s);
105
106 return NULL;
107}
108
7035cd9e
MP
109DnsServer* dns_server_unref(DnsServer *s) {
110 if (!s)
111 return NULL;
112
113 assert(s->n_ref > 0);
114
115 if (s->n_ref == 1)
116 dns_server_free(s);
117 else
118 s->n_ref --;
119
120 return NULL;
121}
122
13d276d0
MP
123void dns_server_packet_received(DnsServer *s, usec_t rtt) {
124 assert(s);
125
126 if (rtt > s->max_rtt) {
127 s->max_rtt = rtt;
128 s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2),
129 DNS_TIMEOUT_MAX_USEC);
130 }
131}
132
133void dns_server_packet_lost(DnsServer *s, usec_t usec) {
134 assert(s);
135
136 if (s->resend_timeout <= usec)
137 s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
138}
139
6300502b 140static void dns_server_hash_func(const void *p, struct siphash *state) {
5eef597e 141 const DnsServer *s = p;
5eef597e 142
6300502b 143 assert(s);
5eef597e 144
6300502b
MP
145 siphash24_compress(&s->family, sizeof(s->family), state);
146 siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
5eef597e
MP
147}
148
149static int dns_server_compare_func(const void *a, const void *b) {
150 const DnsServer *x = a, *y = b;
151
152 if (x->family < y->family)
153 return -1;
154 if (x->family > y->family)
155 return 1;
156
157 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
158}
159
160const struct hash_ops dns_server_hash_ops = {
161 .hash = dns_server_hash_func,
162 .compare = dns_server_compare_func
163};