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