chiark / gitweb /
resolved: make TXT RR generation and parsing more in-line with RFC 6763, section 6.1
[elogind.git] / src / resolve / resolved-dns-server.c
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
26 int dns_server_new(
27                 Manager *m,
28                 DnsServer **ret,
29                 DnsServerType type,
30                 Link *l,
31                 int family,
32                 const union in_addr_union *in_addr) {
33
34         DnsServer *s, *tail;
35
36         assert(m);
37         assert((type == DNS_SERVER_LINK) == !!l);
38         assert(in_addr);
39
40         s = new0(DnsServer, 1);
41         if (!s)
42                 return -ENOMEM;
43
44         s->type = type;
45         s->family = family;
46         s->address = *in_addr;
47
48         if (type == DNS_SERVER_LINK) {
49                 LIST_FIND_TAIL(servers, l->dns_servers, tail);
50                 LIST_INSERT_AFTER(servers, l->dns_servers, tail, s);
51                 s->link = l;
52         } else if (type == DNS_SERVER_SYSTEM) {
53                 LIST_FIND_TAIL(servers, m->dns_servers, tail);
54                 LIST_INSERT_AFTER(servers, m->dns_servers, tail, s);
55         } else if (type == DNS_SERVER_FALLBACK) {
56                 LIST_FIND_TAIL(servers, m->fallback_dns_servers, tail);
57                 LIST_INSERT_AFTER(servers, m->fallback_dns_servers, tail, s);
58         } else
59                 assert_not_reached("Unknown server type");
60
61         s->manager = m;
62
63         /* A new DNS server that isn't fallback is added and the one
64          * we used so far was a fallback one? Then let's try to pick
65          * the new one */
66         if (type != DNS_SERVER_FALLBACK &&
67             m->current_dns_server &&
68             m->current_dns_server->type == DNS_SERVER_FALLBACK)
69                 manager_set_dns_server(m, NULL);
70
71         if (ret)
72                 *ret = s;
73
74         return 0;
75 }
76
77 DnsServer* dns_server_free(DnsServer *s)  {
78         if (!s)
79                 return NULL;
80
81         if (s->manager) {
82                 if (s->type == DNS_SERVER_LINK)
83                         LIST_REMOVE(servers, s->link->dns_servers, s);
84                 else if (s->type == DNS_SERVER_SYSTEM)
85                         LIST_REMOVE(servers, s->manager->dns_servers, s);
86                 else if (s->type == DNS_SERVER_FALLBACK)
87                         LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
88                 else
89                         assert_not_reached("Unknown server type");
90
91                 if (s->manager->current_dns_server == s)
92                         manager_set_dns_server(s->manager, NULL);
93         }
94
95         if (s->link && s->link->current_dns_server == s)
96                 link_set_dns_server(s->link, NULL);
97
98         free(s);
99
100         return NULL;
101 }
102
103 static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
104         const DnsServer *s = p;
105         uint64_t u;
106
107         siphash24((uint8_t*) &u, &s->address, FAMILY_ADDRESS_SIZE(s->family), hash_key);
108         u = u * hash_key[0] + u + s->family;
109
110         return u;
111 }
112
113 static int dns_server_compare_func(const void *a, const void *b) {
114         const DnsServer *x = a, *y = b;
115
116         if (x->family < y->family)
117                 return -1;
118         if (x->family > y->family)
119                 return 1;
120
121         return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
122 }
123
124 const struct hash_ops dns_server_hash_ops = {
125         .hash = dns_server_hash_func,
126         .compare = dns_server_compare_func
127 };