Line data Source code
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 :
23 : #include "networkd.h"
24 : #include "networkd-link.h"
25 :
26 : #include "util.h"
27 : #include "conf-parser.h"
28 :
29 0 : int route_new_static(Network *network, unsigned section, Route **ret) {
30 0 : _cleanup_route_free_ Route *route = NULL;
31 :
32 0 : if (section) {
33 0 : route = hashmap_get(network->routes_by_section,
34 0 : UINT_TO_PTR(section));
35 0 : if (route) {
36 0 : *ret = route;
37 0 : route = NULL;
38 :
39 0 : return 0;
40 : }
41 : }
42 :
43 0 : route = new0(Route, 1);
44 0 : if (!route)
45 0 : return -ENOMEM;
46 :
47 0 : route->family = AF_UNSPEC;
48 0 : route->scope = RT_SCOPE_UNIVERSE;
49 0 : route->protocol = RTPROT_STATIC;
50 :
51 0 : route->network = network;
52 :
53 0 : LIST_PREPEND(routes, network->static_routes, route);
54 :
55 0 : if (section) {
56 0 : route->section = section;
57 0 : hashmap_put(network->routes_by_section,
58 0 : UINT_TO_PTR(route->section), route);
59 : }
60 :
61 0 : *ret = route;
62 0 : route = NULL;
63 :
64 0 : return 0;
65 : }
66 :
67 0 : int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
68 0 : _cleanup_route_free_ Route *route = NULL;
69 :
70 0 : route = new0(Route, 1);
71 0 : if (!route)
72 0 : return -ENOMEM;
73 :
74 0 : route->family = AF_UNSPEC;
75 0 : route->scope = RT_SCOPE_UNIVERSE;
76 0 : route->protocol = rtm_protocol;
77 :
78 0 : *ret = route;
79 0 : route = NULL;
80 :
81 0 : return 0;
82 : }
83 :
84 0 : void route_free(Route *route) {
85 0 : if (!route)
86 0 : return;
87 :
88 0 : if (route->network) {
89 0 : LIST_REMOVE(routes, route->network->static_routes, route);
90 :
91 0 : if (route->section)
92 0 : hashmap_remove(route->network->routes_by_section,
93 0 : UINT_TO_PTR(route->section));
94 : }
95 :
96 0 : free(route);
97 : }
98 :
99 0 : int route_drop(Route *route, Link *link,
100 : sd_netlink_message_handler_t callback) {
101 0 : _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
102 : int r;
103 :
104 0 : assert(link);
105 0 : assert(link->manager);
106 0 : assert(link->manager->rtnl);
107 0 : assert(link->ifindex > 0);
108 0 : assert(route->family == AF_INET || route->family == AF_INET6);
109 :
110 0 : r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
111 : RTM_DELROUTE, route->family,
112 0 : route->protocol);
113 0 : if (r < 0)
114 0 : return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
115 :
116 0 : if (!in_addr_is_null(route->family, &route->in_addr)) {
117 0 : if (route->family == AF_INET)
118 0 : r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
119 0 : else if (route->family == AF_INET6)
120 0 : r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
121 0 : if (r < 0)
122 0 : return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
123 : }
124 :
125 0 : if (route->dst_prefixlen) {
126 0 : if (route->family == AF_INET)
127 0 : r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
128 0 : else if (route->family == AF_INET6)
129 0 : r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
130 0 : if (r < 0)
131 0 : return log_error_errno(r, "Could not append RTA_DST attribute: %m");
132 :
133 0 : r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
134 0 : if (r < 0)
135 0 : return log_error_errno(r, "Could not set destination prefix length: %m");
136 : }
137 :
138 0 : if (route->src_prefixlen) {
139 0 : if (route->family == AF_INET)
140 0 : r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
141 0 : else if (route->family == AF_INET6)
142 0 : r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
143 0 : if (r < 0)
144 0 : return log_error_errno(r, "Could not append RTA_DST attribute: %m");
145 :
146 0 : r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
147 0 : if (r < 0)
148 0 : return log_error_errno(r, "Could not set source prefix length: %m");
149 : }
150 :
151 0 : if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
152 0 : if (route->family == AF_INET)
153 0 : r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
154 0 : else if (route->family == AF_INET6)
155 0 : r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
156 0 : if (r < 0)
157 0 : return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
158 : }
159 :
160 0 : r = sd_rtnl_message_route_set_scope(req, route->scope);
161 0 : if (r < 0)
162 0 : return log_error_errno(r, "Could not set scope: %m");
163 :
164 0 : r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
165 0 : if (r < 0)
166 0 : return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
167 :
168 0 : r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
169 0 : if (r < 0)
170 0 : return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
171 :
172 0 : r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
173 0 : if (r < 0)
174 0 : return log_error_errno(r, "Could not send rtnetlink message: %m");
175 :
176 0 : link_ref(link);
177 :
178 0 : return 0;
179 : }
180 :
181 0 : int route_configure(Route *route, Link *link,
182 : sd_netlink_message_handler_t callback) {
183 0 : _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
184 : int r;
185 :
186 0 : assert(link);
187 0 : assert(link->manager);
188 0 : assert(link->manager->rtnl);
189 0 : assert(link->ifindex > 0);
190 0 : assert(route->family == AF_INET || route->family == AF_INET6);
191 :
192 0 : r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
193 : RTM_NEWROUTE, route->family,
194 0 : route->protocol);
195 0 : if (r < 0)
196 0 : return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
197 :
198 0 : if (!in_addr_is_null(route->family, &route->in_addr)) {
199 0 : if (route->family == AF_INET)
200 0 : r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
201 0 : else if (route->family == AF_INET6)
202 0 : r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
203 0 : if (r < 0)
204 0 : return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
205 : }
206 :
207 0 : if (route->dst_prefixlen) {
208 0 : if (route->family == AF_INET)
209 0 : r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
210 0 : else if (route->family == AF_INET6)
211 0 : r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
212 0 : if (r < 0)
213 0 : return log_error_errno(r, "Could not append RTA_DST attribute: %m");
214 :
215 0 : r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
216 0 : if (r < 0)
217 0 : return log_error_errno(r, "Could not set destination prefix length: %m");
218 : }
219 :
220 0 : if (route->src_prefixlen) {
221 0 : if (route->family == AF_INET)
222 0 : r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
223 0 : else if (route->family == AF_INET6)
224 0 : r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
225 0 : if (r < 0)
226 0 : return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
227 :
228 0 : r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
229 0 : if (r < 0)
230 0 : return log_error_errno(r, "Could not set source prefix length: %m");
231 : }
232 :
233 0 : if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
234 0 : if (route->family == AF_INET)
235 0 : r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
236 0 : else if (route->family == AF_INET6)
237 0 : r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
238 0 : if (r < 0)
239 0 : return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
240 : }
241 :
242 0 : r = sd_rtnl_message_route_set_scope(req, route->scope);
243 0 : if (r < 0)
244 0 : return log_error_errno(r, "Could not set scope: %m");
245 :
246 0 : r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
247 0 : if (r < 0)
248 0 : return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
249 :
250 0 : r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
251 0 : if (r < 0)
252 0 : return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
253 :
254 0 : r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
255 0 : if (r < 0)
256 0 : return log_error_errno(r, "Could not send rtnetlink message: %m");
257 :
258 0 : link_ref(link);
259 :
260 0 : return 0;
261 : }
262 :
263 0 : int config_parse_gateway(const char *unit,
264 : const char *filename,
265 : unsigned line,
266 : const char *section,
267 : unsigned section_line,
268 : const char *lvalue,
269 : int ltype,
270 : const char *rvalue,
271 : void *data,
272 : void *userdata) {
273 :
274 0 : Network *network = userdata;
275 0 : _cleanup_route_free_ Route *n = NULL;
276 : union in_addr_union buffer;
277 : int r, f;
278 :
279 0 : assert(filename);
280 0 : assert(section);
281 0 : assert(lvalue);
282 0 : assert(rvalue);
283 0 : assert(data);
284 :
285 0 : if (streq(section, "Network")) {
286 : /* we are not in an Route section, so treat
287 : * this as the special '0' section */
288 0 : section_line = 0;
289 : }
290 :
291 0 : r = route_new_static(network, section_line, &n);
292 0 : if (r < 0)
293 0 : return r;
294 :
295 0 : r = in_addr_from_string_auto(rvalue, &f, &buffer);
296 0 : if (r < 0) {
297 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
298 : "Route is invalid, ignoring assignment: %s", rvalue);
299 0 : return 0;
300 : }
301 :
302 0 : n->family = f;
303 0 : n->in_addr = buffer;
304 0 : n = NULL;
305 :
306 0 : return 0;
307 : }
308 :
309 0 : int config_parse_destination(const char *unit,
310 : const char *filename,
311 : unsigned line,
312 : const char *section,
313 : unsigned section_line,
314 : const char *lvalue,
315 : int ltype,
316 : const char *rvalue,
317 : void *data,
318 : void *userdata) {
319 :
320 0 : Network *network = userdata;
321 0 : _cleanup_route_free_ Route *n = NULL;
322 : const char *address, *e;
323 : union in_addr_union buffer;
324 : unsigned char prefixlen;
325 : int r, f;
326 :
327 0 : assert(filename);
328 0 : assert(section);
329 0 : assert(lvalue);
330 0 : assert(rvalue);
331 0 : assert(data);
332 :
333 0 : r = route_new_static(network, section_line, &n);
334 0 : if (r < 0)
335 0 : return r;
336 :
337 : /* Destination|Source=address/prefixlen */
338 :
339 : /* address */
340 0 : e = strchr(rvalue, '/');
341 0 : if (e)
342 0 : address = strndupa(rvalue, e - rvalue);
343 : else
344 0 : address = rvalue;
345 :
346 0 : r = in_addr_from_string_auto(address, &f, &buffer);
347 0 : if (r < 0) {
348 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
349 : "Destination is invalid, ignoring assignment: %s", address);
350 0 : return 0;
351 : }
352 :
353 0 : if (f != AF_INET && f != AF_INET6) {
354 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
355 : "Unknown address family, ignoring assignment: %s", address);
356 0 : return 0;
357 : }
358 :
359 : /* prefixlen */
360 0 : if (e) {
361 0 : r = safe_atou8(e + 1, &prefixlen);
362 0 : if (r < 0) {
363 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
364 : "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
365 0 : return 0;
366 : }
367 : } else {
368 0 : switch (f) {
369 : case AF_INET:
370 0 : prefixlen = 32;
371 0 : break;
372 : case AF_INET6:
373 0 : prefixlen = 128;
374 0 : break;
375 : }
376 : }
377 :
378 0 : n->family = f;
379 0 : if (streq(lvalue, "Destination")) {
380 0 : n->dst_addr = buffer;
381 0 : n->dst_prefixlen = prefixlen;
382 0 : } else if (streq(lvalue, "Source")) {
383 0 : n->src_addr = buffer;
384 0 : n->src_prefixlen = prefixlen;
385 : } else
386 0 : assert_not_reached(lvalue);
387 :
388 0 : n = NULL;
389 :
390 0 : return 0;
391 : }
392 :
393 0 : int config_parse_route_priority(const char *unit,
394 : const char *filename,
395 : unsigned line,
396 : const char *section,
397 : unsigned section_line,
398 : const char *lvalue,
399 : int ltype,
400 : const char *rvalue,
401 : void *data,
402 : void *userdata) {
403 0 : Network *network = userdata;
404 0 : _cleanup_route_free_ Route *n = NULL;
405 : int r;
406 :
407 0 : assert(filename);
408 0 : assert(section);
409 0 : assert(lvalue);
410 0 : assert(rvalue);
411 0 : assert(data);
412 :
413 0 : r = route_new_static(network, section_line, &n);
414 0 : if (r < 0)
415 0 : return r;
416 :
417 0 : r = config_parse_unsigned(unit, filename, line, section,
418 : section_line, lvalue, ltype,
419 0 : rvalue, &n->metrics, userdata);
420 0 : if (r < 0)
421 0 : return r;
422 :
423 0 : n = NULL;
424 :
425 0 : return 0;
426 : }
427 :
428 0 : int config_parse_route_scope(const char *unit,
429 : const char *filename,
430 : unsigned line,
431 : const char *section,
432 : unsigned section_line,
433 : const char *lvalue,
434 : int ltype,
435 : const char *rvalue,
436 : void *data,
437 : void *userdata) {
438 0 : Network *network = userdata;
439 0 : _cleanup_route_free_ Route *n = NULL;
440 : int r;
441 :
442 0 : assert(filename);
443 0 : assert(section);
444 0 : assert(lvalue);
445 0 : assert(rvalue);
446 0 : assert(data);
447 :
448 0 : r = route_new_static(network, section_line, &n);
449 0 : if (r < 0)
450 0 : return r;
451 :
452 0 : if (streq(rvalue, "host"))
453 0 : n->scope = RT_SCOPE_HOST;
454 0 : else if (streq(rvalue, "link"))
455 0 : n->scope = RT_SCOPE_LINK;
456 0 : else if (streq(rvalue, "global"))
457 0 : n->scope = RT_SCOPE_UNIVERSE;
458 : else {
459 0 : log_syntax(unit, LOG_ERR, filename, line, EINVAL,
460 : "Unknown route scope: %s", rvalue);
461 0 : return 0;
462 : }
463 :
464 0 : n = NULL;
465 :
466 0 : return 0;
467 : }
|