]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
networkd: merge DNS and NTP entries when exporting
[thirdparty/systemd.git] / src / resolve / resolved-link.c
CommitLineData
74b2466e
LP
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
29int 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
59Link *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);
1716f6dc
LP
71 dns_scope_free(l->llmnr_ipv4_scope);
72 dns_scope_free(l->llmnr_ipv6_scope);
74b2466e
LP
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;
1716f6dc
LP
82}
83
84static void link_allocate_scopes(Link *l) {
85 int r;
86
87 assert(l);
88
89 if (l->link_dns_servers || l->dhcp_dns_servers) {
90 if (!l->unicast_scope) {
91 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
92 if (r < 0)
93 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
94 }
95 } else
96 l->unicast_scope = dns_scope_free(l->unicast_scope);
97
98 if (link_relevant(l, AF_INET) && l->manager->use_llmnr) {
99 if (!l->llmnr_ipv4_scope) {
100 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
101 if (r < 0)
102 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
103 }
104 } else
105 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
106
107 if (link_relevant(l, AF_INET6) && l->manager->use_llmnr) {
108 if (!l->llmnr_ipv6_scope) {
109 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
110 if (r < 0)
111 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
112 }
113 } else
114 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
115}
74b2466e
LP
116
117int link_update_rtnl(Link *l, sd_rtnl_message *m) {
1716f6dc 118 const char *n = NULL;
74b2466e
LP
119 int r;
120
121 assert(l);
122 assert(m);
123
124 r = sd_rtnl_message_link_get_flags(m, &l->flags);
125 if (r < 0)
126 return r;
127
c5ed9316 128 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
1716f6dc
LP
129
130 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
131 strncpy(l->name, n, sizeof(l->name));
132 char_array_0(l->name);
133 }
134
135 link_allocate_scopes(l);
74b2466e
LP
136 return 0;
137}
138
1716f6dc 139static int link_update_link_dns_servers(Link *l) {
74b2466e
LP
140 _cleanup_free_ struct in_addr *nameservers = NULL;
141 _cleanup_free_ struct in6_addr *nameservers6 = NULL;
142 DnsServer *s, *nx;
a2ba62c7 143 int r, n, i;
74b2466e
LP
144
145 assert(l);
146
147 LIST_FOREACH(servers, s, l->link_dns_servers)
148 s->marked = true;
149
a2ba62c7
LP
150 n = sd_network_get_dns(l->ifindex, &nameservers);
151 if (n < 0) {
152 r = n;
74b2466e 153 goto clear;
a2ba62c7 154 }
74b2466e
LP
155
156 for (i = 0; i < n; i++) {
157 union in_addr_union a = { .in = nameservers[i] };
158
159 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
160 if (s)
161 s->marked = false;
162 else {
163 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
164 if (r < 0)
165 goto clear;
166 }
167 }
168
a2ba62c7
LP
169 n = sd_network_get_dns6(l->ifindex, &nameservers6);
170 if (n < 0) {
171 r = n;
74b2466e 172 goto clear;
a2ba62c7 173 }
74b2466e
LP
174
175 for (i = 0; i < n; i++) {
176 union in_addr_union a = { .in6 = nameservers6[i] };
177
178 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
179 if (s)
180 s->marked = false;
181 else {
182 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
183 if (r < 0)
184 goto clear;
185 }
186 }
187
188 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
189 if (s->marked)
190 dns_server_free(s);
191
192 return 0;
193
194clear:
195 while (l->link_dns_servers)
196 dns_server_free(l->link_dns_servers);
197
198 return r;
199}
200
201int link_update_monitor(Link *l) {
202 assert(l);
203
1716f6dc
LP
204 link_update_link_dns_servers(l);
205 link_allocate_scopes(l);
74b2466e
LP
206
207 return 0;
208}
209
0dd25fb9 210bool link_relevant(Link *l, int family) {
1716f6dc 211 _cleanup_free_ char *state = NULL;
74b2466e
LP
212 LinkAddress *a;
213
214 assert(l);
215
216 /* A link is relevant if it isn't a loopback device and has at
217 * least one relevant IP address */
218
219 if (l->flags & IFF_LOOPBACK)
220 return false;
221
1716f6dc
LP
222 sd_network_get_link_operational_state(l->ifindex, &state);
223 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
224 return false;
225
226 LIST_FOREACH(addresses, a, l->addresses)
1716f6dc 227 if (a->family == family && link_address_relevant(a))
74b2466e
LP
228 return true;
229
230 return false;
231}
232
0dd25fb9 233LinkAddress *link_find_address(Link *l, int family, union in_addr_union *in_addr) {
74b2466e
LP
234 LinkAddress *a;
235
236 assert(l);
237
1716f6dc
LP
238 LIST_FOREACH(addresses, a, l->addresses)
239 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 240 return a;
74b2466e
LP
241
242 return NULL;
243}
244
0dd25fb9 245DnsServer* link_find_dns_server(Link *l, DnsServerSource source, int family, union in_addr_union *in_addr) {
74b2466e
LP
246 DnsServer *first, *s;
247
248 assert(l);
249
250 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
251
1716f6dc
LP
252 LIST_FOREACH(servers, s, first)
253 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
74b2466e 254 return s;
74b2466e
LP
255
256 return NULL;
257}
258
259DnsServer *link_get_dns_server(Link *l) {
260 assert(l);
261
262 if (!l->current_dns_server)
263 l->current_dns_server = l->link_dns_servers;
264 if (!l->current_dns_server)
265 l->current_dns_server = l->dhcp_dns_servers;
266
267 return l->current_dns_server;
268}
269
270void link_next_dns_server(Link *l) {
271 assert(l);
272
273 /* Switch to the next DNS server */
274
275 if (!l->current_dns_server) {
276 l->current_dns_server = l->link_dns_servers;
277 if (l->current_dns_server)
278 return;
279 }
280
281 if (!l->current_dns_server) {
282 l->current_dns_server = l->dhcp_dns_servers;
283 if (l->current_dns_server)
284 return;
285 }
286
287 if (!l->current_dns_server)
288 return;
289
290 if (l->current_dns_server->servers_next) {
291 l->current_dns_server = l->current_dns_server->servers_next;
292 return;
293 }
294
295 if (l->current_dns_server->source == DNS_SERVER_LINK)
296 l->current_dns_server = l->dhcp_dns_servers;
297 else {
298 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
299 l->current_dns_server = l->link_dns_servers;
300 }
301}
302
0dd25fb9 303int link_address_new(Link *l, LinkAddress **ret, int family, union in_addr_union *in_addr) {
74b2466e
LP
304 LinkAddress *a;
305
306 assert(l);
307 assert(in_addr);
308
309 a = new0(LinkAddress, 1);
310 if (!a)
311 return -ENOMEM;
312
313 a->family = family;
314 a->in_addr = *in_addr;
315
316 a->link = l;
317 LIST_PREPEND(addresses, l->addresses, a);
318
319 if (ret)
320 *ret = a;
321
322 return 0;
323}
324
325LinkAddress *link_address_free(LinkAddress *a) {
326 if (!a)
327 return NULL;
328
329 if (a->link)
330 LIST_REMOVE(addresses, a->link->addresses, a);
331
332 free(a);
333 return NULL;
334}
335
336int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
337 int r;
338 assert(a);
339 assert(m);
340
341 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
342 if (r < 0)
343 return r;
344
1716f6dc 345 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 346
1716f6dc 347 link_allocate_scopes(a->link);
74b2466e
LP
348 return 0;
349}
350
351bool link_address_relevant(LinkAddress *a) {
352 assert(a);
353
354 if (a->flags & IFA_F_DEPRECATED)
355 return false;
356
357 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
358 return false;
359
360 return true;
361}