]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolved: fix check for mdns names
[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);
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
84int 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
e1c95994
LP
94 r = sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
95 if (r < 0)
96 return r;
97
74b2466e
LP
98 return 0;
99}
100
101static int update_dhcp_dns_servers(Link *l) {
102 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
e1bbf3d1 103 struct in_addr *nameservers = NULL;
74b2466e
LP
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
145clear:
146 while (l->dhcp_dns_servers)
147 dns_server_free(l->dhcp_dns_servers);
148
149 return r;
150}
151
152static 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
205clear:
206 while (l->link_dns_servers)
207 dns_server_free(l->link_dns_servers);
208
209 return r;
210}
211
212int 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
226bool 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
247LinkAddress *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
262DnsServer* 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
279DnsServer *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
290void 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
323int 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
345LinkAddress *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
356int 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
372bool 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}