]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
sd-bus: the bus returned should be the first arg
[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
482e2ac1
TG
278 if (n->family == AF_INET6) {
279 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
280 "Broadcast is not valid for IPv6 addresses, "
281 "ignoring assignment: %s", address);
282 return 0;
283 }
284
eb0ea358
TG
285 r = net_parse_inaddr(address, &n->family, &n->broadcast);
286 if (r < 0) {
287 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
288 "Broadcast is invalid, ignoring assignment: %s", address);
289 return 0;
290 }
291
292 n = NULL;
293
294 return 0;
295}
296
f579559b
TG
297int config_parse_address(const char *unit,
298 const char *filename,
299 unsigned line,
300 const char *section,
71a61510 301 unsigned section_line,
f579559b
TG
302 const char *lvalue,
303 int ltype,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
6ae115c1 307 Network *network = userdata;
f579559b
TG
308 _cleanup_address_free_ Address *n = NULL;
309 _cleanup_free_ char *address = NULL;
310 const char *e;
311 int r;
312
313 assert(filename);
6ae115c1 314 assert(section);
f579559b
TG
315 assert(lvalue);
316 assert(rvalue);
317 assert(data);
318
92fe133a
TG
319 if (streq(section, "Network")) {
320 /* we are not in an Address section, so treat
321 * this as the special '0' section */
322 section_line = 0;
323 }
324
f048a16b 325 r = address_new_static(network, section_line, &n);
f579559b
TG
326 if (r < 0)
327 return r;
328
329 /* Address=address/prefixlen */
330
331 /* prefixlen */
332 e = strchr(rvalue, '/');
333 if (e) {
334 unsigned i;
335 r = safe_atou(e + 1, &i);
336 if (r < 0) {
337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
338 "Interface prefix length is invalid, "
339 "ignoring assignment: %s", e + 1);
340 return 0;
341 }
342
343 n->prefixlen = (unsigned char) i;
8cd11a0f 344
f579559b
TG
345 address = strndup(rvalue, e - rvalue);
346 if (!address)
347 return log_oom();
348 } else {
349 address = strdup(rvalue);
350 if (!address)
351 return log_oom();
352 }
353
354 r = net_parse_inaddr(address, &n->family, &n->in_addr);
355 if (r < 0) {
356 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
357 "Address is invalid, ignoring assignment: %s", address);
358 return 0;
359 }
360
eb0ea358
TG
361 if (n->family == AF_INET && !n->broadcast.s_addr)
362 n->broadcast.s_addr = n->in_addr.in.s_addr |
363 htonl(0xfffffffflu >> n->prefixlen);
364
f579559b
TG
365 n = NULL;
366
367 return 0;
368}
6ae115c1
TG
369
370int config_parse_label(const char *unit,
371 const char *filename,
372 unsigned line,
373 const char *section,
374 unsigned section_line,
375 const char *lvalue,
376 int ltype,
377 const char *rvalue,
378 void *data,
379 void *userdata) {
380 Network *network = userdata;
381 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
382 char *label;
383 int r;
384
385 assert(filename);
386 assert(section);
387 assert(lvalue);
388 assert(rvalue);
389 assert(data);
390
f048a16b 391 r = address_new_static(network, section_line, &n);
6ae115c1
TG
392 if (r < 0)
393 return r;
394
395 label = strdup(rvalue);
396 if (!label)
397 return log_oom();
398
399 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
400 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
401 "Interface label is not ASCII clean or is too"
402 " long, ignoring assignment: %s", rvalue);
403 free(label);
404 return 0;
405 }
406
407 free(n->label);
408 if (*label)
409 n->label = label;
410 else {
411 free(label);
412 n->label = NULL;
413 }
414
415 n = NULL;
416
417 return 0;
418}