]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
api: in constructor function calls, always put the returned object pointer first...
[thirdparty/systemd.git] / src / network / networkd-address.c
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
31 int address_new_static(Network *network, unsigned section, Address **ret) {
32 _cleanup_address_free_ Address *address = NULL;
33
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
45 address = new0(Address, 1);
46 if (!address)
47 return -ENOMEM;
48
49 address->family = AF_UNSPEC;
50
51 address->network = network;
52
53 LIST_PREPEND(static_addresses, network->static_addresses, address);
54
55 if (section) {
56 address->section = section;
57 hashmap_put(network->addresses_by_section, &address->section, address);
58 }
59
60 *ret = address;
61 address = NULL;
62
63 return 0;
64 }
65
66 int 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
73 address->family = AF_UNSPEC;
74
75 *ret = address;
76 address = NULL;
77
78 return 0;
79 }
80
81 void address_free(Address *address) {
82 if (!address)
83 return;
84
85 if (address->network) {
86 LIST_REMOVE(static_addresses, address->network->static_addresses, address);
87
88 if (address->section)
89 hashmap_remove(address->network->addresses_by_section,
90 &address->section);
91 }
92
93 free(address);
94 }
95
96 int address_drop(Address *address, Link *link,
97 sd_rtnl_message_handler_t callback) {
98 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
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
108 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
109 link->ifindex, address->family);
110 if (r < 0) {
111 log_error("Could not allocate RTM_DELADDR message: %s",
112 strerror(-r));
113 return r;
114 }
115
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
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
141 int address_configure(Address *address, Link *link,
142 sd_rtnl_message_handler_t callback) {
143 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
144 int r;
145
146 assert(address);
147 assert(address->family == AF_INET || address->family == AF_INET6);
148 assert(link);
149 assert(link->ifindex > 0);
150 assert(link->manager);
151 assert(link->manager->rtnl);
152
153 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
154 link->ifindex, address->family);
155 if (r < 0) {
156 log_error("Could not allocate RTM_NEWADDR message: %s",
157 strerror(-r));
158 return r;
159 }
160
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
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);
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) {
190 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
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) {
199 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
200 if (r < 0) {
201 log_error("Could not append IFA_LABEL attribute: %s",
202 strerror(-r));
203 return r;
204 }
205 }
206
207 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
208 if (r < 0) {
209 log_error("Could not send rtnetlink message: %s", strerror(-r));
210 return r;
211 }
212
213 return 0;
214 }
215
216 int 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
253 int 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 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
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
297 int config_parse_address(const char *unit,
298 const char *filename,
299 unsigned line,
300 const char *section,
301 unsigned section_line,
302 const char *lvalue,
303 int ltype,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
307 Network *network = userdata;
308 _cleanup_address_free_ Address *n = NULL;
309 _cleanup_free_ char *address = NULL;
310 const char *e;
311 int r;
312
313 assert(filename);
314 assert(section);
315 assert(lvalue);
316 assert(rvalue);
317 assert(data);
318
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
325 r = address_new_static(network, section_line, &n);
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;
344
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
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
365 n = NULL;
366
367 return 0;
368 }
369
370 int 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;
382 char *label;
383 int r;
384
385 assert(filename);
386 assert(section);
387 assert(lvalue);
388 assert(rvalue);
389 assert(data);
390
391 r = address_new_static(network, section_line, &n);
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 }