chiark / gitweb /
dns-domain: never allow labels that are larger than 63 chars
[elogind.git] / src / resolve / resolved-link.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 <net/if.h>
23
24 #include "sd-network.h"
25 #include "dhcp-lease-internal.h"
26 #include "strv.h"
27 #include "resolved-link.h"
28
29 int link_new(Manager *m, Link **ret, int ifindex) {
30         _cleanup_(link_freep) Link *l = NULL;
31         int r;
32
33         assert(m);
34         assert(ifindex > 0);
35
36         r = hashmap_ensure_allocated(&m->links, NULL, NULL);
37         if (r < 0)
38                 return r;
39
40         l = new0(Link, 1);
41         if (!l)
42                 return -ENOMEM;
43
44         l->ifindex = ifindex;
45
46         r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
47         if (r < 0)
48                 return r;
49
50         l->manager = m;
51
52         if (ret)
53                 *ret = l;
54         l = NULL;
55
56         return 0;
57 }
58
59 Link *link_free(Link *l) {
60
61         if (!l)
62                 return NULL;
63
64         while (l->addresses)
65                 link_address_free(l->addresses);
66
67         if (l->manager)
68                 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
69
70         dns_scope_free(l->unicast_scope);
71         dns_scope_free(l->mdns_ipv4_scope);
72         dns_scope_free(l->mdns_ipv6_scope);
73
74         while (l->dhcp_dns_servers)
75                 dns_server_free(l->dhcp_dns_servers);
76
77         while (l->link_dns_servers)
78                 dns_server_free(l->link_dns_servers);
79
80         free(l);
81         return NULL;
82  }
83
84 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
85         int r;
86
87         assert(l);
88         assert(m);
89
90         r = sd_rtnl_message_link_get_flags(m, &l->flags);
91         if (r < 0)
92                 return r;
93
94         return 0;
95 }
96
97 static int update_dhcp_dns_servers(Link *l) {
98         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
99         _cleanup_free_ struct in_addr *nameservers = NULL;
100         DnsServer *s, *nx;
101         unsigned i;
102         size_t n;
103         int r;
104
105         assert(l);
106
107         r = sd_network_dhcp_use_dns(l->ifindex);
108         if (r <= 0)
109                 goto clear;
110
111         r = sd_network_get_dhcp_lease(l->ifindex, &lease);
112         if (r < 0)
113                 goto clear;
114
115         LIST_FOREACH(servers, s, l->dhcp_dns_servers)
116                 s->marked = true;
117
118         r = sd_dhcp_lease_get_dns(lease, &nameservers, &n);
119         if (r < 0)
120                 goto clear;
121
122         for (i = 0; i < n; i++) {
123                 union in_addr_union a = { .in = nameservers[i] };
124
125                 s = link_find_dns_server(l, DNS_SERVER_DHCP, AF_INET, &a);
126                 if (s)
127                         s->marked = false;
128                 else {
129                         r = dns_server_new(l->manager, NULL, DNS_SERVER_DHCP, l, AF_INET, &a);
130                         if (r < 0)
131                                 goto clear;
132                 }
133         }
134
135         LIST_FOREACH_SAFE(servers, s, nx, l->dhcp_dns_servers)
136                 if (s->marked)
137                         dns_server_free(s);
138
139         return 0;
140
141 clear:
142         while (l->dhcp_dns_servers)
143                 dns_server_free(l->dhcp_dns_servers);
144
145         return r;
146 }
147
148 static int update_link_dns_servers(Link *l) {
149         _cleanup_free_ struct in_addr *nameservers = NULL;
150         _cleanup_free_ struct in6_addr *nameservers6 = NULL;
151         DnsServer *s, *nx;
152         unsigned i;
153         size_t n;
154         int r;
155
156         assert(l);
157
158         LIST_FOREACH(servers, s, l->link_dns_servers)
159                 s->marked = true;
160
161         r = sd_network_get_dns(l->ifindex, &nameservers, &n);
162         if (r < 0)
163                 goto clear;
164
165         for (i = 0; i < n; i++) {
166                 union in_addr_union a = { .in = nameservers[i] };
167
168                 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
169                 if (s)
170                         s->marked = false;
171                 else {
172                         r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
173                         if (r < 0)
174                                 goto clear;
175                 }
176         }
177
178         r = sd_network_get_dns6(l->ifindex, &nameservers6, &n);
179         if (r < 0)
180                 goto clear;
181
182         for (i = 0; i < n; i++) {
183                 union in_addr_union a = { .in6 = nameservers6[i] };
184
185                 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
186                 if (s)
187                         s->marked = false;
188                 else {
189                         r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
190                         if (r < 0)
191                                 goto clear;
192                 }
193         }
194
195         LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
196                 if (s->marked)
197                         dns_server_free(s);
198
199         return 0;
200
201 clear:
202         while (l->link_dns_servers)
203                 dns_server_free(l->link_dns_servers);
204
205         return r;
206 }
207
208 int link_update_monitor(Link *l) {
209         assert(l);
210
211         free(l->operational_state);
212         l->operational_state = NULL;
213
214         sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
215
216         update_dhcp_dns_servers(l);
217         update_link_dns_servers(l);
218
219         return 0;
220 }
221
222 bool link_relevant(Link *l) {
223         LinkAddress *a;
224
225         assert(l);
226
227         /* A link is relevant if it isn't a loopback device and has at
228          * least one relevant IP address */
229
230         if (l->flags & IFF_LOOPBACK)
231                 return false;
232
233         if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
234                 return false;
235
236         LIST_FOREACH(addresses, a, l->addresses)
237                 if (link_address_relevant(a))
238                         return true;
239
240         return false;
241 }
242
243 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
244         LinkAddress *a;
245
246         assert(l);
247
248         LIST_FOREACH(addresses, a, l->addresses) {
249
250                 if (a->family == family &&
251                     in_addr_equal(family, &a->in_addr, in_addr))
252                         return a;
253         }
254
255         return NULL;
256 }
257
258 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
259         DnsServer *first, *s;
260
261         assert(l);
262
263         first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
264
265         LIST_FOREACH(servers, s, first) {
266
267                 if (s->family == family &&
268                     in_addr_equal(family, &s->address, in_addr))
269                         return s;
270         }
271
272         return NULL;
273 }
274
275 DnsServer *link_get_dns_server(Link *l) {
276         assert(l);
277
278         if (!l->current_dns_server)
279                 l->current_dns_server = l->link_dns_servers;
280         if (!l->current_dns_server)
281                 l->current_dns_server = l->dhcp_dns_servers;
282
283         return l->current_dns_server;
284 }
285
286 void link_next_dns_server(Link *l) {
287         assert(l);
288
289         /* Switch to the next DNS server */
290
291         if (!l->current_dns_server) {
292                 l->current_dns_server = l->link_dns_servers;
293                 if (l->current_dns_server)
294                         return;
295         }
296
297         if (!l->current_dns_server) {
298                 l->current_dns_server = l->dhcp_dns_servers;
299                 if (l->current_dns_server)
300                         return;
301         }
302
303         if (!l->current_dns_server)
304                 return;
305
306         if (l->current_dns_server->servers_next) {
307                 l->current_dns_server = l->current_dns_server->servers_next;
308                 return;
309         }
310
311         if (l->current_dns_server->source == DNS_SERVER_LINK)
312                 l->current_dns_server = l->dhcp_dns_servers;
313         else {
314                 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
315                 l->current_dns_server = l->link_dns_servers;
316         }
317 }
318
319 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
320         LinkAddress *a;
321
322         assert(l);
323         assert(in_addr);
324
325         a = new0(LinkAddress, 1);
326         if (!a)
327                 return -ENOMEM;
328
329         a->family = family;
330         a->in_addr = *in_addr;
331
332         a->link = l;
333         LIST_PREPEND(addresses, l->addresses, a);
334
335         if (ret)
336                 *ret = a;
337
338         return 0;
339 }
340
341 LinkAddress *link_address_free(LinkAddress *a) {
342         if (!a)
343                 return NULL;
344
345         if (a->link)
346                 LIST_REMOVE(addresses, a->link->addresses, a);
347
348         free(a);
349         return NULL;
350 }
351
352 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
353         int r;
354         assert(a);
355         assert(m);
356
357         r = sd_rtnl_message_addr_get_flags(m, &a->flags);
358         if (r < 0)
359                 return r;
360
361         r = sd_rtnl_message_addr_get_scope(m, &a->scope);
362         if (r < 0)
363                 return r;
364
365         return 0;
366 }
367
368 bool link_address_relevant(LinkAddress *a) {
369         assert(a);
370
371         if (a->flags & IFA_F_DEPRECATED)
372                 return false;
373
374         if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
375                 return false;
376
377         return true;
378 }