chiark / gitweb /
resolved: fix check for mdns names
[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         r = sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
95         if (r < 0)
96                 return r;
97
98         return 0;
99 }
100
101 static int update_dhcp_dns_servers(Link *l) {
102         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
103         struct in_addr *nameservers = NULL;
104         DnsServer *s, *nx;
105         unsigned i;
106         size_t n;
107         int r;
108
109         assert(l);
110
111         r = sd_network_dhcp_use_dns(l->ifindex);
112         if (r <= 0)
113                 goto clear;
114
115         r = sd_network_get_dhcp_lease(l->ifindex, &lease);
116         if (r < 0)
117                 goto clear;
118
119         LIST_FOREACH(servers, s, l->dhcp_dns_servers)
120                 s->marked = true;
121
122         r = sd_dhcp_lease_get_dns(lease, &nameservers, &n);
123         if (r < 0)
124                 goto clear;
125
126         for (i = 0; i < n; i++) {
127                 union in_addr_union a = { .in = nameservers[i] };
128
129                 s = link_find_dns_server(l, DNS_SERVER_DHCP, AF_INET, &a);
130                 if (s)
131                         s->marked = false;
132                 else {
133                         r = dns_server_new(l->manager, NULL, DNS_SERVER_DHCP, l, AF_INET, &a);
134                         if (r < 0)
135                                 goto clear;
136                 }
137         }
138
139         LIST_FOREACH_SAFE(servers, s, nx, l->dhcp_dns_servers)
140                 if (s->marked)
141                         dns_server_free(s);
142
143         return 0;
144
145 clear:
146         while (l->dhcp_dns_servers)
147                 dns_server_free(l->dhcp_dns_servers);
148
149         return r;
150 }
151
152 static int update_link_dns_servers(Link *l) {
153         _cleanup_free_ struct in_addr *nameservers = NULL;
154         _cleanup_free_ struct in6_addr *nameservers6 = NULL;
155         DnsServer *s, *nx;
156         unsigned i;
157         size_t n;
158         int r;
159
160         assert(l);
161
162         LIST_FOREACH(servers, s, l->link_dns_servers)
163                 s->marked = true;
164
165         r = sd_network_get_dns(l->ifindex, &nameservers, &n);
166         if (r < 0)
167                 goto clear;
168
169         for (i = 0; i < n; i++) {
170                 union in_addr_union a = { .in = nameservers[i] };
171
172                 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
173                 if (s)
174                         s->marked = false;
175                 else {
176                         r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
177                         if (r < 0)
178                                 goto clear;
179                 }
180         }
181
182         r = sd_network_get_dns6(l->ifindex, &nameservers6, &n);
183         if (r < 0)
184                 goto clear;
185
186         for (i = 0; i < n; i++) {
187                 union in_addr_union a = { .in6 = nameservers6[i] };
188
189                 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
190                 if (s)
191                         s->marked = false;
192                 else {
193                         r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
194                         if (r < 0)
195                                 goto clear;
196                 }
197         }
198
199         LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
200                 if (s->marked)
201                         dns_server_free(s);
202
203         return 0;
204
205 clear:
206         while (l->link_dns_servers)
207                 dns_server_free(l->link_dns_servers);
208
209         return r;
210 }
211
212 int link_update_monitor(Link *l) {
213         assert(l);
214
215         free(l->operational_state);
216         l->operational_state = NULL;
217
218         sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
219
220         update_dhcp_dns_servers(l);
221         update_link_dns_servers(l);
222
223         return 0;
224 }
225
226 bool link_relevant(Link *l) {
227         LinkAddress *a;
228
229         assert(l);
230
231         /* A link is relevant if it isn't a loopback device and has at
232          * least one relevant IP address */
233
234         if (l->flags & IFF_LOOPBACK)
235                 return false;
236
237         if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
238                 return false;
239
240         LIST_FOREACH(addresses, a, l->addresses)
241                 if (link_address_relevant(a))
242                         return true;
243
244         return false;
245 }
246
247 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
248         LinkAddress *a;
249
250         assert(l);
251
252         LIST_FOREACH(addresses, a, l->addresses) {
253
254                 if (a->family == family &&
255                     in_addr_equal(family, &a->in_addr, in_addr))
256                         return a;
257         }
258
259         return NULL;
260 }
261
262 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
263         DnsServer *first, *s;
264
265         assert(l);
266
267         first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
268
269         LIST_FOREACH(servers, s, first) {
270
271                 if (s->family == family &&
272                     in_addr_equal(family, &s->address, in_addr))
273                         return s;
274         }
275
276         return NULL;
277 }
278
279 DnsServer *link_get_dns_server(Link *l) {
280         assert(l);
281
282         if (!l->current_dns_server)
283                 l->current_dns_server = l->link_dns_servers;
284         if (!l->current_dns_server)
285                 l->current_dns_server = l->dhcp_dns_servers;
286
287         return l->current_dns_server;
288 }
289
290 void link_next_dns_server(Link *l) {
291         assert(l);
292
293         /* Switch to the next DNS server */
294
295         if (!l->current_dns_server) {
296                 l->current_dns_server = l->link_dns_servers;
297                 if (l->current_dns_server)
298                         return;
299         }
300
301         if (!l->current_dns_server) {
302                 l->current_dns_server = l->dhcp_dns_servers;
303                 if (l->current_dns_server)
304                         return;
305         }
306
307         if (!l->current_dns_server)
308                 return;
309
310         if (l->current_dns_server->servers_next) {
311                 l->current_dns_server = l->current_dns_server->servers_next;
312                 return;
313         }
314
315         if (l->current_dns_server->source == DNS_SERVER_LINK)
316                 l->current_dns_server = l->dhcp_dns_servers;
317         else {
318                 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
319                 l->current_dns_server = l->link_dns_servers;
320         }
321 }
322
323 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
324         LinkAddress *a;
325
326         assert(l);
327         assert(in_addr);
328
329         a = new0(LinkAddress, 1);
330         if (!a)
331                 return -ENOMEM;
332
333         a->family = family;
334         a->in_addr = *in_addr;
335
336         a->link = l;
337         LIST_PREPEND(addresses, l->addresses, a);
338
339         if (ret)
340                 *ret = a;
341
342         return 0;
343 }
344
345 LinkAddress *link_address_free(LinkAddress *a) {
346         if (!a)
347                 return NULL;
348
349         if (a->link)
350                 LIST_REMOVE(addresses, a->link->addresses, a);
351
352         free(a);
353         return NULL;
354 }
355
356 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
357         int r;
358         assert(a);
359         assert(m);
360
361         r = sd_rtnl_message_addr_get_flags(m, &a->flags);
362         if (r < 0)
363                 return r;
364
365         r = sd_rtnl_message_addr_get_scope(m, &a->scope);
366         if (r < 0)
367                 return r;
368
369         return 0;
370 }
371
372 bool link_address_relevant(LinkAddress *a) {
373         assert(a);
374
375         if (a->flags & IFA_F_DEPRECATED)
376                 return false;
377
378         if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
379                 return false;
380
381         return true;
382 }