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