]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
networkd: drop routes when lease expires
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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 "networkd.h"
25
26#include "utf8.h"
27#include "util.h"
28#include "conf-parser.h"
c6f7c917 29#include "network-internal.h"
f579559b 30
f048a16b 31int address_new_static(Network *network, unsigned section, Address **ret) {
f579559b
TG
32 _cleanup_address_free_ Address *address = NULL;
33
6ae115c1
TG
34 if (section) {
35 uint64_t key = section;
36 address = hashmap_get(network->addresses_by_section, &key);
37 if (address) {
38 *ret = address;
39 address = NULL;
40
41 return 0;
42 }
43 }
44
f579559b
TG
45 address = new0(Address, 1);
46 if (!address)
47 return -ENOMEM;
48
801bd9e8 49 address->family = AF_UNSPEC;
5c1d3fc9 50 address->scope = RT_SCOPE_UNIVERSE;
801bd9e8 51
f579559b
TG
52 address->network = network;
53
f048a16b 54 LIST_PREPEND(static_addresses, network->static_addresses, address);
f579559b 55
6ae115c1
TG
56 if (section) {
57 address->section = section;
58 hashmap_put(network->addresses_by_section, &address->section, address);
59 }
60
f579559b
TG
61 *ret = address;
62 address = NULL;
63
64 return 0;
65}
66
f048a16b
TG
67int address_new_dynamic(Address **ret) {
68 _cleanup_address_free_ Address *address = NULL;
69
70 address = new0(Address, 1);
71 if (!address)
72 return -ENOMEM;
73
801bd9e8 74 address->family = AF_UNSPEC;
5c1d3fc9 75 address->scope = RT_SCOPE_UNIVERSE;
801bd9e8 76
f048a16b
TG
77 *ret = address;
78 address = NULL;
79
80 return 0;
81}
82
f579559b
TG
83void address_free(Address *address) {
84 if (!address)
85 return;
86
f048a16b
TG
87 if (address->network) {
88 LIST_REMOVE(static_addresses, address->network->static_addresses, address);
f579559b 89
f048a16b
TG
90 if (address->section)
91 hashmap_remove(address->network->addresses_by_section,
92 &address->section);
93 }
6ae115c1 94
f579559b
TG
95 free(address);
96}
97
407fe036
TG
98int address_drop(Address *address, Link *link,
99 sd_rtnl_message_handler_t callback) {
cf6a8911 100 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
407fe036
TG
101 int r;
102
103 assert(address);
104 assert(address->family == AF_INET || address->family == AF_INET6);
105 assert(link);
106 assert(link->ifindex > 0);
107 assert(link->manager);
108 assert(link->manager->rtnl);
109
151b9b96
LP
110 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
111 link->ifindex, address->family);
407fe036
TG
112 if (r < 0) {
113 log_error("Could not allocate RTM_DELADDR message: %s",
114 strerror(-r));
115 return r;
116 }
117
5a723174
TG
118 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
119 if (r < 0) {
120 log_error("Could not set prefixlen: %s", strerror(-r));
121 return r;
122 }
123
407fe036
TG
124 if (address->family == AF_INET)
125 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
126 else if (address->family == AF_INET6)
127 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
128 if (r < 0) {
129 log_error("Could not append IFA_LOCAL attribute: %s",
130 strerror(-r));
131 return r;
132 }
133
134 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
135 if (r < 0) {
136 log_error("Could not send rtnetlink message: %s", strerror(-r));
137 return r;
138 }
139
140 return 0;
141}
142
f882c247
TG
143int address_configure(Address *address, Link *link,
144 sd_rtnl_message_handler_t callback) {
cf6a8911 145 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
146 int r;
147
c166a070
TG
148 assert(address);
149 assert(address->family == AF_INET || address->family == AF_INET6);
150 assert(link);
151 assert(link->ifindex > 0);
f882c247 152 assert(link->manager);
c166a070 153 assert(link->manager->rtnl);
f882c247 154
151b9b96
LP
155 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
156 link->ifindex, address->family);
f579559b
TG
157 if (r < 0) {
158 log_error("Could not allocate RTM_NEWADDR message: %s",
159 strerror(-r));
160 return r;
161 }
162
5a723174
TG
163 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
164 if (r < 0) {
165 log_error("Could not set prefixlen: %s", strerror(-r));
166 return r;
167 }
168
169 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
170 if (r < 0) {
171 log_error("Could not set flags: %s", strerror(-r));
172 return r;
173 }
174
5c1d3fc9 175 r = sd_rtnl_message_addr_set_scope(req, address->scope);
5a723174
TG
176 if (r < 0) {
177 log_error("Could not set scope: %s", strerror(-r));
178 return r;
179 }
180
0a0dc69b
TG
181 if (address->family == AF_INET)
182 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
183 else if (address->family == AF_INET6)
184 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
f579559b
TG
185 if (r < 0) {
186 log_error("Could not append IFA_LOCAL attribute: %s",
187 strerror(-r));
188 return r;
189 }
190
191 if (address->family == AF_INET) {
eb0ea358 192 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
f579559b
TG
193 if (r < 0) {
194 log_error("Could not append IFA_BROADCAST attribute: %s",
195 strerror(-r));
196 return r;
197 }
198 }
199
200 if (address->label) {
0a0dc69b 201 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
f579559b
TG
202 if (r < 0) {
203 log_error("Could not append IFA_LABEL attribute: %s",
204 strerror(-r));
205 return r;
206 }
207 }
208
f882c247 209 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
f579559b 210 if (r < 0) {
f882c247
TG
211 log_error("Could not send rtnetlink message: %s", strerror(-r));
212 return r;
f579559b
TG
213 }
214
f579559b
TG
215 return 0;
216}
217
3bef724f
TG
218int config_parse_dns(const char *unit,
219 const char *filename,
220 unsigned line,
221 const char *section,
222 unsigned section_line,
223 const char *lvalue,
224 int ltype,
225 const char *rvalue,
226 void *data,
227 void *userdata) {
06f021a8 228 Set **dns = data;
3bef724f
TG
229 _cleanup_address_free_ Address *n = NULL;
230 int r;
231
232 assert(filename);
233 assert(section);
234 assert(lvalue);
235 assert(rvalue);
236 assert(data);
237
238 r = address_new_dynamic(&n);
239 if (r < 0)
240 return r;
241
242 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
243 if (r < 0) {
244 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
245 "DNS address is invalid, ignoring assignment: %s", rvalue);
246 return 0;
247 }
248
06f021a8 249 set_put(*dns, n);
3bef724f
TG
250 n = NULL;
251
252 return 0;
253}
254
eb0ea358
TG
255int config_parse_broadcast(const char *unit,
256 const char *filename,
257 unsigned line,
258 const char *section,
259 unsigned section_line,
260 const char *lvalue,
261 int ltype,
262 const char *rvalue,
263 void *data,
264 void *userdata) {
265 Network *network = userdata;
266 _cleanup_address_free_ Address *n = NULL;
267 _cleanup_free_ char *address = NULL;
268 int r;
269
270 assert(filename);
271 assert(section);
272 assert(lvalue);
273 assert(rvalue);
274 assert(data);
275
276 r = address_new_static(network, section_line, &n);
277 if (r < 0)
278 return r;
279
482e2ac1
TG
280 if (n->family == AF_INET6) {
281 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
282 "Broadcast is not valid for IPv6 addresses, "
283 "ignoring assignment: %s", address);
284 return 0;
285 }
286
eb0ea358
TG
287 r = net_parse_inaddr(address, &n->family, &n->broadcast);
288 if (r < 0) {
289 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
290 "Broadcast is invalid, ignoring assignment: %s", address);
291 return 0;
292 }
293
294 n = NULL;
295
296 return 0;
297}
298
f579559b
TG
299int config_parse_address(const char *unit,
300 const char *filename,
301 unsigned line,
302 const char *section,
71a61510 303 unsigned section_line,
f579559b
TG
304 const char *lvalue,
305 int ltype,
306 const char *rvalue,
307 void *data,
308 void *userdata) {
6ae115c1 309 Network *network = userdata;
f579559b
TG
310 _cleanup_address_free_ Address *n = NULL;
311 _cleanup_free_ char *address = NULL;
312 const char *e;
313 int r;
314
315 assert(filename);
6ae115c1 316 assert(section);
f579559b
TG
317 assert(lvalue);
318 assert(rvalue);
319 assert(data);
320
92fe133a
TG
321 if (streq(section, "Network")) {
322 /* we are not in an Address section, so treat
323 * this as the special '0' section */
324 section_line = 0;
325 }
326
f048a16b 327 r = address_new_static(network, section_line, &n);
f579559b
TG
328 if (r < 0)
329 return r;
330
331 /* Address=address/prefixlen */
332
333 /* prefixlen */
334 e = strchr(rvalue, '/');
335 if (e) {
336 unsigned i;
337 r = safe_atou(e + 1, &i);
338 if (r < 0) {
339 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
340 "Interface prefix length is invalid, "
341 "ignoring assignment: %s", e + 1);
342 return 0;
343 }
344
345 n->prefixlen = (unsigned char) i;
8cd11a0f 346
f579559b
TG
347 address = strndup(rvalue, e - rvalue);
348 if (!address)
349 return log_oom();
350 } else {
351 address = strdup(rvalue);
352 if (!address)
353 return log_oom();
354 }
355
356 r = net_parse_inaddr(address, &n->family, &n->in_addr);
357 if (r < 0) {
358 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
359 "Address is invalid, ignoring assignment: %s", address);
360 return 0;
361 }
362
eb0ea358
TG
363 if (n->family == AF_INET && !n->broadcast.s_addr)
364 n->broadcast.s_addr = n->in_addr.in.s_addr |
365 htonl(0xfffffffflu >> n->prefixlen);
366
f579559b
TG
367 n = NULL;
368
369 return 0;
370}
6ae115c1
TG
371
372int config_parse_label(const char *unit,
373 const char *filename,
374 unsigned line,
375 const char *section,
376 unsigned section_line,
377 const char *lvalue,
378 int ltype,
379 const char *rvalue,
380 void *data,
381 void *userdata) {
382 Network *network = userdata;
383 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
384 char *label;
385 int r;
386
387 assert(filename);
388 assert(section);
389 assert(lvalue);
390 assert(rvalue);
391 assert(data);
392
f048a16b 393 r = address_new_static(network, section_line, &n);
6ae115c1
TG
394 if (r < 0)
395 return r;
396
397 label = strdup(rvalue);
398 if (!label)
399 return log_oom();
400
401 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
402 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
403 "Interface label is not ASCII clean or is too"
404 " long, ignoring assignment: %s", rvalue);
405 free(label);
406 return 0;
407 }
408
409 free(n->label);
410 if (*label)
411 n->label = label;
412 else {
413 free(label);
414 n->label = NULL;
415 }
416
417 n = NULL;
418
419 return 0;
420}