1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
22 #include "siphash24.h"
24 #include "resolved-dns-server.h"
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)
36 const union in_addr_union
*in_addr
) {
41 assert((type
== DNS_SERVER_LINK
) == !!l
);
44 s
= new0(DnsServer
, 1);
51 s
->address
= *in_addr
;
52 s
->resend_timeout
= DNS_TIMEOUT_MIN_USEC
;
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
);
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
);
65 assert_not_reached("Unknown server type");
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
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
);
83 DnsServer
* dns_server_ref(DnsServer
*s
) {
94 static DnsServer
* dns_server_free(DnsServer
*s
) {
98 if (s
->link
&& s
->link
->current_dns_server
== s
)
99 link_set_dns_server(s
->link
, NULL
);
101 if (s
->manager
&& s
->manager
->current_dns_server
== s
)
102 manager_set_dns_server(s
->manager
, NULL
);
109 DnsServer
* dns_server_unref(DnsServer
*s
) {
113 assert(s
->n_ref
> 0);
123 void dns_server_packet_received(DnsServer
*s
, usec_t rtt
) {
126 if (rtt
> s
->max_rtt
) {
128 s
->resend_timeout
= MIN(MAX(DNS_TIMEOUT_MIN_USEC
, s
->max_rtt
* 2),
129 DNS_TIMEOUT_MAX_USEC
);
133 void dns_server_packet_lost(DnsServer
*s
, usec_t usec
) {
136 if (s
->resend_timeout
<= usec
)
137 s
->resend_timeout
= MIN(s
->resend_timeout
* 2, DNS_TIMEOUT_MAX_USEC
);
140 static unsigned long dns_server_hash_func(const void *p
, const uint8_t hash_key
[HASH_KEY_SIZE
]) {
141 const DnsServer
*s
= p
;
144 siphash24((uint8_t*) &u
, &s
->address
, FAMILY_ADDRESS_SIZE(s
->family
), hash_key
);
145 u
= u
* hash_key
[0] + u
+ s
->family
;
150 static int dns_server_compare_func(const void *a
, const void *b
) {
151 const DnsServer
*x
= a
, *y
= b
;
153 if (x
->family
< y
->family
)
155 if (x
->family
> y
->family
)
158 return memcmp(&x
->address
, &y
->address
, FAMILY_ADDRESS_SIZE(x
->family
));
161 const struct hash_ops dns_server_hash_ops
= {
162 .hash
= dns_server_hash_func
,
163 .compare
= dns_server_compare_func