resolved-dns-server.c revision f2f1dbe50fea13abadc9c1e845a29031b90b40f3
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* After how much time to repeat classic DNS requests */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering#define DNS_TIMEOUT_MAX_USEC (5 * USEC_PER_SEC)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert((type == DNS_SERVER_LINK) == !!l);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_FIND_TAIL(servers, l->dns_servers, tail);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_INSERT_AFTER(servers, l->dns_servers, tail, s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_FIND_TAIL(servers, m->dns_servers, tail);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_INSERT_AFTER(servers, m->dns_servers, tail, s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else if (type == DNS_SERVER_FALLBACK) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_FIND_TAIL(servers, m->fallback_dns_servers, tail);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_INSERT_AFTER(servers, m->fallback_dns_servers, tail, s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_not_reached("Unknown server type");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* A new DNS server that isn't fallback is added and the one
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * we used so far was a fallback one? Then let's try to pick
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * the new one */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->current_dns_server->type == DNS_SERVER_FALLBACK)
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poetteringstatic DnsServer* dns_server_free(DnsServer *s) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (s->link && s->link->current_dns_server == s)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (s->manager && s->manager->current_dns_server == s)
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering manager_set_dns_server(s->manager, NULL);
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel AndersenDnsServer* dns_server_unref(DnsServer *s) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringvoid dns_server_packet_received(DnsServer *s, usec_t rtt) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringvoid dns_server_packet_lost(DnsServer *s, usec_t usec) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic void dns_server_hash_func(const void *p, struct siphash *state) {
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering siphash24_compress(&s->family, sizeof(s->family), state);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poetteringstatic int dns_server_compare_func(const void *a, const void *b) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering const DnsServer *x = a, *y = b;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringconst struct hash_ops dns_server_hash_ops = {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringvoid manager_flush_dns_servers(Manager *m, DnsServerType type) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering first = type == DNS_SERVER_FALLBACK ? &m->fallback_dns_servers : &m->dns_servers;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringvoid manager_flush_marked_dns_servers(Manager *m, DnsServerType type) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering first = type == DNS_SERVER_FALLBACK ? &m->fallback_dns_servers : &m->dns_servers;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering LIST_FOREACH_SAFE(servers, s, next, *first) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringvoid manager_mark_dns_servers(Manager *m, DnsServerType type) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart PoetteringDnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart PoetteringDnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering in_addr_to_string(s->family, &s->address, &ip);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering log_info("Switching to system DNS server %s.", strna(ip));
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering dns_cache_flush(&m->unicast_scope->cache);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart PoetteringDnsServer *manager_get_dns_server(Manager *m) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* Try to read updates resolv.conf */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* If no DNS server was chose so far, pick the first one */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering manager_set_dns_server(m, m->dns_servers);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* No DNS servers configured, let's see if there are
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * any on any links. If not, we use the fallback
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering manager_set_dns_server(m, m->fallback_dns_servers);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* If there's currently no DNS server set, then the next
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * manager_get_dns_server() will find one */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Change to the next one */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (m->current_dns_server->servers_next) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering manager_set_dns_server(m, m->current_dns_server->servers_next);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If there was no next one, then start from the beginning of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering manager_set_dns_server(m, m->fallback_dns_servers);