]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-server.c
Merge pull request #1048 from poettering/resolved-man
[thirdparty/systemd.git] / src / resolve / resolved-dns-server.c
CommitLineData
74b2466e
LP
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
87f5a193
LP
22#include "siphash24.h"
23
74b2466e
LP
24#include "resolved-dns-server.h"
25
9df3ba6c
TG
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
74b2466e
LP
30int dns_server_new(
31 Manager *m,
32 DnsServer **ret,
4e945a6f 33 DnsServerType type,
74b2466e 34 Link *l,
0dd25fb9 35 int family,
3c0cf502 36 const union in_addr_union *in_addr) {
74b2466e
LP
37
38 DnsServer *s, *tail;
39
40 assert(m);
4e945a6f 41 assert((type == DNS_SERVER_LINK) == !!l);
74b2466e 42 assert(in_addr);
74b2466e
LP
43
44 s = new0(DnsServer, 1);
45 if (!s)
46 return -ENOMEM;
47
91b14d6f 48 s->n_ref = 1;
4e945a6f 49 s->type = type;
74b2466e
LP
50 s->family = family;
51 s->address = *in_addr;
9df3ba6c 52 s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
74b2466e 53
4e945a6f 54 if (type == DNS_SERVER_LINK) {
6073b6f2
TG
55 LIST_FIND_TAIL(servers, l->dns_servers, tail);
56 LIST_INSERT_AFTER(servers, l->dns_servers, tail, s);
74b2466e 57 s->link = l;
4e945a6f 58 } else if (type == DNS_SERVER_SYSTEM) {
74b2466e
LP
59 LIST_FIND_TAIL(servers, m->dns_servers, tail);
60 LIST_INSERT_AFTER(servers, m->dns_servers, tail, s);
4e945a6f
LP
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");
74b2466e
LP
66
67 s->manager = m;
68
4e945a6f
LP
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 &&
3e684349
LP
73 m->current_dns_server &&
74 m->current_dns_server->type == DNS_SERVER_FALLBACK)
75 manager_set_dns_server(m, NULL);
4e945a6f 76
74b2466e
LP
77 if (ret)
78 *ret = s;
79
80 return 0;
81}
82
91b14d6f 83DnsServer* dns_server_ref(DnsServer *s) {
74b2466e
LP
84 if (!s)
85 return NULL;
86
91b14d6f 87 assert(s->n_ref > 0);
cab5b059 88
91b14d6f 89 s->n_ref ++;
cab5b059 90
91b14d6f
TG
91 return s;
92}
93
94static DnsServer* dns_server_free(DnsServer *s) {
95 if (!s)
96 return NULL;
3e684349 97
91b14d6f
TG
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);
74b2466e 103
74b2466e
LP
104 free(s);
105
106 return NULL;
107}
87f5a193 108
91b14d6f
TG
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
9df3ba6c
TG
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
d5099efc 140static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
87f5a193
LP
141 const DnsServer *s = p;
142 uint64_t u;
143
144 siphash24((uint8_t*) &u, &s->address, FAMILY_ADDRESS_SIZE(s->family), hash_key);
145 u = u * hash_key[0] + u + s->family;
146
147 return u;
148}
149
d5099efc 150static int dns_server_compare_func(const void *a, const void *b) {
87f5a193
LP
151 const DnsServer *x = a, *y = b;
152
153 if (x->family < y->family)
154 return -1;
155 if (x->family > y->family)
156 return 1;
157
158 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
159}
d5099efc
MS
160
161const struct hash_ops dns_server_hash_ops = {
162 .hash = dns_server_hash_func,
163 .compare = dns_server_compare_func
164};