chiark / gitweb /
resolve-host: use the usual log message when encountering a dbus parse failure
[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 "strv.h"
26 #include "resolved-link.h"
27
28 /* RFC 4795 Section 2.8. suggests a TTL of 30s by default */
29 #define LLMNR_DEFAULT_TTL (30)
30
31 static void link_address_add_rrs(LinkAddress *a);
32
33 int link_new(Manager *m, Link **ret, int ifindex) {
34         _cleanup_(link_freep) Link *l = NULL;
35         int r;
36
37         assert(m);
38         assert(ifindex > 0);
39
40         r = hashmap_ensure_allocated(&m->links, NULL, NULL);
41         if (r < 0)
42                 return r;
43
44         l = new0(Link, 1);
45         if (!l)
46                 return -ENOMEM;
47
48         l->ifindex = ifindex;
49
50         r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
51         if (r < 0)
52                 return r;
53
54         l->manager = m;
55
56         if (ret)
57                 *ret = l;
58         l = NULL;
59
60         return 0;
61 }
62
63 Link *link_free(Link *l) {
64
65         if (!l)
66                 return NULL;
67
68         while (l->addresses)
69                 link_address_free(l->addresses);
70
71         if (l->manager)
72                 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
73
74         dns_scope_free(l->unicast_scope);
75         dns_scope_free(l->llmnr_ipv4_scope);
76         dns_scope_free(l->llmnr_ipv6_scope);
77
78         while (l->dns_servers)
79                 dns_server_free(l->dns_servers);
80
81         free(l);
82         return NULL;
83 }
84
85 static void link_allocate_scopes(Link *l) {
86         int r;
87
88         assert(l);
89
90         if (l->dns_servers) {
91                 if (!l->unicast_scope) {
92                         r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
93                         if (r < 0)
94                                 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
95                 }
96         } else
97                 l->unicast_scope = dns_scope_free(l->unicast_scope);
98
99         if (link_relevant(l, AF_INET) && (l->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
100                 if (!l->llmnr_ipv4_scope) {
101                         r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
102                         if (r < 0)
103                                 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
104                 }
105         } else
106                 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
107
108         if (link_relevant(l, AF_INET6) && (l->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
109                 if (!l->llmnr_ipv6_scope) {
110                         r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
111                         if (r < 0)
112                                 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
113                 }
114         } else
115                 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
116 }
117
118 static void link_add_rrs(Link *l) {
119         LinkAddress *a;
120
121         LIST_FOREACH(addresses, a, l->addresses)
122                 link_address_add_rrs(a);
123 }
124
125 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
126         const char *n = NULL;
127         int r;
128
129         assert(l);
130         assert(m);
131
132         r = sd_rtnl_message_link_get_flags(m, &l->flags);
133         if (r < 0)
134                 return r;
135
136         sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
137
138         if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
139                 strncpy(l->name, n, sizeof(l->name));
140                 char_array_0(l->name);
141         }
142
143         link_allocate_scopes(l);
144         link_add_rrs(l);
145
146         return 0;
147 }
148
149 static int link_update_dns_servers(Link *l) {
150         _cleanup_strv_free_ char **nameservers = NULL;
151         char **nameserver;
152         DnsServer *s, *nx;
153         int r;
154
155         assert(l);
156
157         LIST_FOREACH(servers, s, l->dns_servers)
158                 s->marked = true;
159
160         r = sd_network_get_dns(l->ifindex, &nameservers);
161         if (r < 0)
162                 goto clear;
163
164         STRV_FOREACH(nameserver, nameservers) {
165                 union in_addr_union a;
166                 int family;
167
168                 r = in_addr_from_string_auto(*nameserver, &family, &a);
169                 if (r < 0)
170                         goto clear;
171
172                 s = link_find_dns_server(l, family, &a);
173                 if (s)
174                         s->marked = false;
175                 else {
176                         r = dns_server_new(l->manager, NULL, l, family, &a);
177                         if (r < 0)
178                                 goto clear;
179                 }
180         }
181
182         LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
183                 if (s->marked)
184                         dns_server_free(s);
185
186         return 0;
187
188 clear:
189         while (l->dns_servers)
190                 dns_server_free(l->dns_servers);
191
192         return r;
193 }
194
195 int link_update_monitor(Link *l) {
196         assert(l);
197
198         link_update_dns_servers(l);
199         link_allocate_scopes(l);
200         link_add_rrs(l);
201
202         return 0;
203 }
204
205 bool link_relevant(Link *l, int family) {
206         _cleanup_free_ char *state = NULL;
207         LinkAddress *a;
208
209         assert(l);
210
211         /* A link is relevant if it isn't a loopback device and has at
212          * least one relevant IP address */
213
214         if (l->flags & IFF_LOOPBACK)
215                 return false;
216
217         sd_network_get_link_operational_state(l->ifindex, &state);
218         if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
219                 return false;
220
221         LIST_FOREACH(addresses, a, l->addresses)
222                 if (a->family == family && link_address_relevant(a))
223                         return true;
224
225         return false;
226 }
227
228 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
229         LinkAddress *a;
230
231         assert(l);
232
233         LIST_FOREACH(addresses, a, l->addresses)
234                 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
235                         return a;
236
237         return NULL;
238 }
239
240 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
241         DnsServer *s;
242
243         assert(l);
244
245         LIST_FOREACH(servers, s, l->dns_servers)
246                 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
247                         return s;
248         return NULL;
249 }
250
251 DnsServer *link_get_dns_server(Link *l) {
252         assert(l);
253
254         if (!l->current_dns_server)
255                 l->current_dns_server = l->dns_servers;
256
257         return l->current_dns_server;
258 }
259
260 void link_next_dns_server(Link *l) {
261         assert(l);
262
263         /* Switch to the next DNS server */
264
265         if (!l->current_dns_server) {
266                 l->current_dns_server = l->dns_servers;
267                 if (l->current_dns_server)
268                         return;
269         }
270
271         if (!l->current_dns_server)
272                 return;
273
274         if (l->current_dns_server->servers_next) {
275                 l->current_dns_server = l->current_dns_server->servers_next;
276                 return;
277         }
278
279         l->current_dns_server = l->dns_servers;
280 }
281
282 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
283         LinkAddress *a;
284
285         assert(l);
286         assert(in_addr);
287
288         a = new0(LinkAddress, 1);
289         if (!a)
290                 return -ENOMEM;
291
292         a->family = family;
293         a->in_addr = *in_addr;
294
295         a->link = l;
296         LIST_PREPEND(addresses, l->addresses, a);
297
298         if (ret)
299                 *ret = a;
300
301         return 0;
302 }
303
304 LinkAddress *link_address_free(LinkAddress *a) {
305         if (!a)
306                 return NULL;
307
308         if (a->link) {
309                 LIST_REMOVE(addresses, a->link->addresses, a);
310
311                 if (a->llmnr_address_rr) {
312
313                         if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
314                                 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
315                         else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
316                                 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
317
318                         dns_resource_record_unref(a->llmnr_address_rr);
319                 }
320
321                 if (a->llmnr_ptr_rr) {
322                         if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
323                                 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
324                         else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
325                                 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
326
327                         dns_resource_record_unref(a->llmnr_ptr_rr);
328                 }
329         }
330
331         free(a);
332         return NULL;
333 }
334
335 static void link_address_add_rrs(LinkAddress *a) {
336         int r;
337
338         assert(a);
339
340         if (a->family == AF_INET && a->link->llmnr_ipv4_scope) {
341
342                 if (!a->link->manager->host_ipv4_key) {
343                         a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
344                         if (!a->link->manager->host_ipv4_key) {
345                                 r = -ENOMEM;
346                                 goto fail;
347                         }
348                 }
349
350                 if (!a->llmnr_address_rr) {
351                         a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
352                         if (!a->llmnr_address_rr) {
353                                 r = -ENOMEM;
354                                 goto fail;
355                         }
356
357                         a->llmnr_address_rr->a.in_addr = a->in_addr.in;
358                         a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
359                 }
360
361                 if (!a->llmnr_ptr_rr) {
362                         r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
363                         if (r < 0)
364                                 goto fail;
365
366                         a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
367                 }
368
369                 if (link_address_relevant(a)) {
370                         r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
371                         if (r < 0)
372                                 goto fail;
373
374                         r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
375                         if (r < 0)
376                                 goto fail;
377                 } else {
378                         dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
379                         dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
380                 }
381         }
382
383         if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope) {
384
385                 if (!a->link->manager->host_ipv6_key) {
386                         a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
387                         if (!a->link->manager->host_ipv6_key) {
388                                 r = -ENOMEM;
389                                 goto fail;
390                         }
391                 }
392
393                 if (!a->llmnr_address_rr) {
394                         a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
395                         if (!a->llmnr_address_rr) {
396                                 r = -ENOMEM;
397                                 goto fail;
398                         }
399
400                         a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
401                         a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
402                 }
403
404                 if (!a->llmnr_ptr_rr) {
405                         r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
406                         if (r < 0)
407                                 goto fail;
408
409                         a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
410                 }
411
412                 if (link_address_relevant(a)) {
413                         r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
414                         if (r < 0)
415                                 goto fail;
416
417                         r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
418                         if (r < 0)
419                                 goto fail;
420                 } else {
421                         dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
422                         dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
423                 }
424         }
425
426         return;
427
428 fail:
429         log_debug("Failed to update address RRs: %s", strerror(-r));
430 }
431
432 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
433         int r;
434         assert(a);
435         assert(m);
436
437         r = sd_rtnl_message_addr_get_flags(m, &a->flags);
438         if (r < 0)
439                 return r;
440
441         sd_rtnl_message_addr_get_scope(m, &a->scope);
442
443         link_allocate_scopes(a->link);
444         link_add_rrs(a->link);
445
446         return 0;
447 }
448
449 bool link_address_relevant(LinkAddress *a) {
450         assert(a);
451
452         if (a->flags & IFA_F_DEPRECATED)
453                 return false;
454
455         if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
456                 return false;
457
458         return true;
459 }