1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2017 Susant Sahani
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/fib_rules.h>
24 #include "alloc-util.h"
25 #include "conf-parser.h"
27 #include "networkd-routing-policy-rule.h"
28 #include "netlink-util.h"
29 #include "networkd-manager.h"
30 #include "parse-util.h"
31 #include "socket-util.h"
32 #include "string-util.h"
34 int routing_policy_rule_new(RoutingPolicyRule
**ret
) {
35 RoutingPolicyRule
*rule
;
37 rule
= new0(RoutingPolicyRule
, 1);
41 rule
->family
= AF_INET
;
42 rule
->table
= RT_TABLE_MAIN
;
48 void routing_policy_rule_free(RoutingPolicyRule
*rule
) {
54 LIST_REMOVE(rules
, rule
->network
->rules
, rule
);
55 assert(rule
->network
->n_rules
> 0);
56 rule
->network
->n_rules
--;
59 hashmap_remove(rule
->network
->rules_by_section
, rule
->section
);
60 network_config_section_free(rule
->section
);
63 if (rule
->network
->manager
) {
64 set_remove(rule
->network
->manager
->rules
, rule
);
65 set_remove(rule
->network
->manager
->rules_foreign
, rule
);
72 static void routing_policy_rule_hash_func(const void *b
, struct siphash
*state
) {
73 const RoutingPolicyRule
*rule
= b
;
77 siphash24_compress(&rule
->family
, sizeof(rule
->family
), state
);
79 switch (rule
->family
) {
83 siphash24_compress(&rule
->from
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
84 siphash24_compress(&rule
->from_prefixlen
, sizeof(rule
->from_prefixlen
), state
);
86 siphash24_compress(&rule
->to
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
87 siphash24_compress(&rule
->to_prefixlen
, sizeof(rule
->to_prefixlen
), state
);
89 siphash24_compress(&rule
->tos
, sizeof(rule
->tos
), state
);
90 siphash24_compress(&rule
->fwmark
, sizeof(rule
->fwmark
), state
);
91 siphash24_compress(&rule
->table
, sizeof(rule
->table
), state
);
95 /* treat any other address family as AF_UNSPEC */
100 static int routing_policy_rule_compare_func(const void *_a
, const void *_b
) {
101 const RoutingPolicyRule
*a
= _a
, *b
= _b
;
104 if (a
->family
< b
->family
)
106 if (a
->family
> b
->family
)
112 if (a
->from_prefixlen
< b
->from_prefixlen
)
114 if (a
->from_prefixlen
> b
->from_prefixlen
)
117 if (a
->to_prefixlen
< b
->to_prefixlen
)
119 if (a
->to_prefixlen
> b
->to_prefixlen
)
127 if (a
->fwmask
< b
->fwmark
)
129 if (a
->fwmask
> b
->fwmark
)
132 if (a
->table
< b
->table
)
134 if (a
->table
> b
->table
)
137 r
= memcmp(&a
->from
, &b
->from
, FAMILY_ADDRESS_SIZE(a
->family
));
141 return memcmp(&a
->to
, &b
->to
, FAMILY_ADDRESS_SIZE(a
->family
));
144 /* treat any other address family as AF_UNSPEC */
149 const struct hash_ops routing_policy_rule_hash_ops
= {
150 .hash
= routing_policy_rule_hash_func
,
151 .compare
= routing_policy_rule_compare_func
154 int routing_policy_rule_get(Manager
*m
,
156 const union in_addr_union
*from
,
157 uint8_t from_prefixlen
,
158 const union in_addr_union
*to
,
159 uint8_t to_prefixlen
,
163 RoutingPolicyRule
**ret
) {
165 RoutingPolicyRule rule
, *existing
;
167 assert_return(m
, -1);
169 rule
= (RoutingPolicyRule
) {
172 .from_prefixlen
= from_prefixlen
,
174 .to_prefixlen
= to_prefixlen
,
181 existing
= set_get(m
->rules
, &rule
);
189 if (m
->rules_foreign
) {
190 existing
= set_get(m
->rules_foreign
, &rule
);
201 int routing_policy_rule_make_local(Manager
*m
, RoutingPolicyRule
*rule
) {
206 if (set_contains(m
->rules_foreign
, rule
)) {
207 set_remove(m
->rules_foreign
, rule
);
209 r
= set_ensure_allocated(&m
->rules
, &routing_policy_rule_hash_ops
);
213 return set_put(m
->rules
, rule
);
219 static int routing_policy_rule_add_internal(Set
**rules
,
221 const union in_addr_union
*from
,
222 uint8_t from_prefixlen
,
223 const union in_addr_union
*to
,
224 uint8_t to_prefixlen
,
228 RoutingPolicyRule
**ret
) {
230 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
233 assert_return(rules
, -EINVAL
);
235 r
= routing_policy_rule_new(&rule
);
239 rule
->family
= family
;
241 rule
->from_prefixlen
= from_prefixlen
;
243 rule
->to_prefixlen
= to_prefixlen
;
245 rule
->fwmark
= fwmark
;
248 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
252 r
= set_put(*rules
, rule
);
264 int routing_policy_rule_add(Manager
*m
,
266 const union in_addr_union
*from
,
267 uint8_t from_prefixlen
,
268 const union in_addr_union
*to
,
269 uint8_t to_prefixlen
,
273 RoutingPolicyRule
**ret
) {
275 return routing_policy_rule_add_internal(&m
->rules
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, ret
);
278 int routing_policy_rule_add_foreign(Manager
*m
,
280 const union in_addr_union
*from
,
281 uint8_t from_prefixlen
,
282 const union in_addr_union
*to
,
283 uint8_t to_prefixlen
,
287 RoutingPolicyRule
**ret
) {
288 return routing_policy_rule_add_internal(&m
->rules_foreign
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, ret
);
291 static int routing_policy_rule_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
292 _cleanup_link_unref_ Link
*link
= userdata
;
297 assert(link
->ifname
);
299 link
->link_messages
--;
301 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
304 r
= sd_netlink_message_get_errno(m
);
306 log_link_warning_errno(link
, r
, "Could not drop routing policy rule: %m");
311 int routing_policy_rule_remove(RoutingPolicyRule
*routing_policy_rule
, Link
*link
, sd_netlink_message_handler_t callback
) {
312 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
315 assert(routing_policy_rule
);
317 assert(link
->manager
);
318 assert(link
->manager
->rtnl
);
319 assert(link
->ifindex
> 0);
320 assert(IN_SET(routing_policy_rule
->family
, AF_INET
, AF_INET6
));
322 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_DELRULE
, routing_policy_rule
->family
);
324 return log_error_errno(r
, "Could not allocate RTM_DELRULE message: %m");
326 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->from
)) {
327 if (routing_policy_rule
->family
== AF_INET
)
328 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in
);
330 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in6
);
333 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
335 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, routing_policy_rule
->from_prefixlen
);
337 return log_error_errno(r
, "Could not set source prefix length: %m");
340 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->to
)) {
341 if (routing_policy_rule
->family
== AF_INET
)
342 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in
);
344 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in6
);
347 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
349 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, routing_policy_rule
->to_prefixlen
);
351 return log_error_errno(r
, "Could not set destination prefix length: %m");
354 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
356 return log_error_errno(r
, "Could not send rtnetlink message: %m");
363 static int routing_policy_rule_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutingPolicyRule
**ret
) {
364 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
365 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
370 assert(!!filename
== (section_line
> 0));
372 r
= network_config_section_new(filename
, section_line
, &n
);
376 rule
= hashmap_get(network
->rules_by_section
, n
);
384 r
= routing_policy_rule_new(&rule
);
389 rule
->network
= network
;
392 r
= hashmap_put(network
->rules_by_section
, rule
->section
, rule
);
396 LIST_APPEND(rules
, network
->rules
, rule
);
405 int link_routing_policy_rule_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
406 _cleanup_link_unref_ Link
*link
= userdata
;
412 assert(link
->ifname
);
413 assert(link
->link_messages
> 0);
415 link
->link_messages
--;
417 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
420 r
= sd_netlink_message_get_errno(m
);
421 if (r
< 0 && r
!= -EEXIST
)
422 log_link_warning_errno(link
, r
, "Could not add routing policy rule: %m");
424 if (link
->link_messages
== 0)
425 log_link_debug(link
, "Routing policy rule configured");
430 int routing_policy_rule_configure(RoutingPolicyRule
*rule
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
431 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
436 assert(link
->ifindex
> 0);
437 assert(link
->manager
);
438 assert(link
->manager
->rtnl
);
440 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_NEWRULE
, rule
->family
);
442 return log_error_errno(r
, "Could not allocate RTM_NEWRULE message: %m");
444 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
445 if (rule
->family
== AF_INET
)
446 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &rule
->from
.in
);
448 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &rule
->from
.in6
);
451 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
453 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, rule
->from_prefixlen
);
455 return log_error_errno(r
, "Could not set source prefix length: %m");
458 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
459 if (rule
->family
== AF_INET
)
460 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &rule
->to
.in
);
462 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &rule
->to
.in6
);
465 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
467 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, rule
->to_prefixlen
);
469 return log_error_errno(r
, "Could not set destination prefix length: %m");
472 r
= sd_netlink_message_append_u32(m
, FRA_PRIORITY
, rule
->priority
);
474 return log_error_errno(r
, "Could not append FRA_PRIORITY attribute: %m");
477 r
= sd_rtnl_message_routing_policy_rule_set_tos(m
, rule
->tos
);
479 return log_error_errno(r
, "Could not set ip rule tos: %m");
482 if (rule
->table
< 256) {
483 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, rule
->table
);
485 return log_error_errno(r
, "Could not set ip rule table: %m");
487 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, RT_TABLE_UNSPEC
);
489 return log_error_errno(r
, "Could not set ip rule table: %m");
491 r
= sd_netlink_message_append_u32(m
, FRA_TABLE
, rule
->table
);
493 return log_error_errno(r
, "Could not append FRA_TABLE attribute: %m");
496 if (rule
->fwmark
> 0) {
497 r
= sd_netlink_message_append_u32(m
, FRA_FWMARK
, rule
->fwmark
);
499 return log_error_errno(r
, "Could not append FRA_FWMARK attribute: %m");
502 if (rule
->fwmask
> 0) {
503 r
= sd_netlink_message_append_u32(m
, FRA_FWMASK
, rule
->fwmask
);
505 return log_error_errno(r
, "Could not append FRA_FWMASK attribute: %m");
510 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
512 return log_error_errno(r
, "Could not send rtnetlink message: %m");
516 r
= routing_policy_rule_add(link
->manager
, rule
->family
, &rule
->from
, rule
->from_prefixlen
, &rule
->to
,
517 rule
->to_prefixlen
, rule
->tos
, rule
->fwmark
, rule
->table
, NULL
);
519 return log_error_errno(r
, "Could not add rule : %m");
524 static int parse_fwmark_fwmask(const char *s
, uint32_t *fwmark
, uint32_t *fwmask
) {
525 _cleanup_free_
char *f
= NULL
;
539 r
= safe_atou32(f
, fwmark
);
541 return log_error_errno(r
, "Failed to parse RPDB rule firewall mark, ignoring: %s", f
);
544 r
= safe_atou32(p
, fwmask
);
546 return log_error_errno(r
, "Failed to parse RPDB rule mask, ignoring: %s", f
);
552 int config_parse_routing_policy_rule_tos(
554 const char *filename
,
557 unsigned section_line
,
564 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
565 Network
*network
= userdata
;
574 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
578 r
= safe_atou8(rvalue
, &n
->tos
);
580 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule tos, ignoring: %s", rvalue
);
589 int config_parse_routing_policy_rule_priority(
591 const char *filename
,
594 unsigned section_line
,
601 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
602 Network
*network
= userdata
;
611 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
615 r
= safe_atou32(rvalue
, &n
->priority
);
617 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule priority, ignoring: %s", rvalue
);
626 int config_parse_routing_policy_rule_table(
628 const char *filename
,
631 unsigned section_line
,
638 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
639 Network
*network
= userdata
;
648 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
652 r
= safe_atou32(rvalue
, &n
->table
);
654 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule table, ignoring: %s", rvalue
);
663 int config_parse_routing_policy_rule_fwmark_mask(
665 const char *filename
,
668 unsigned section_line
,
675 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
676 Network
*network
= userdata
;
685 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
689 r
= parse_fwmark_fwmask(rvalue
, &n
->fwmark
, &n
->fwmask
);
691 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue
);
700 int config_parse_routing_policy_rule_prefix(
702 const char *filename
,
705 unsigned section_line
,
712 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
713 Network
*network
= userdata
;
714 union in_addr_union buffer
;
724 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
728 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &buffer
, &prefixlen
);
730 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &buffer
, &prefixlen
);
732 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue
);
736 n
->family
= AF_INET6
;
740 if (streq(lvalue
, "To")) {
742 n
->to_prefixlen
= prefixlen
;
745 n
->from_prefixlen
= prefixlen
;
753 static int routing_policy_rule_read_full_file(char *state_file
, char **ret
) {
754 _cleanup_free_
char *s
= NULL
;
760 r
= read_full_file(state_file
, &s
, &size
);
774 int routing_policy_rule_load(Manager
*m
) {
775 _cleanup_strv_free_
char **l
= NULL
;
776 _cleanup_free_
char *data
= NULL
;
783 r
= routing_policy_rule_read_full_file(m
->state_file
, &data
);
787 l
= strv_split_newlines(data
);
791 r
= set_ensure_allocated(&m
->rules_saved
, &routing_policy_rule_hash_ops
);
796 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
798 p
= startswith(*i
, "RULE=");
805 r
= routing_policy_rule_new(&rule
);
810 _cleanup_free_
char *word
= NULL
, *a
= NULL
, *b
= NULL
;
811 union in_addr_union buffer
;
814 r
= extract_first_word(&p
, &word
, NULL
, 0);
820 r
= split_pair(word
, "=", &a
, &b
);
824 if (STR_IN_SET(a
, "from", "to")) {
826 r
= in_addr_prefix_from_string(b
, AF_INET
, &buffer
, &prefixlen
);
828 r
= in_addr_prefix_from_string(b
, AF_INET6
, &buffer
, &prefixlen
);
830 log_error_errno(r
, "RPDB rule prefix is invalid, ignoring assignment: %s", b
);
834 rule
->family
= AF_INET6
;
836 rule
->family
= AF_INET
;
838 if (streq(a
, "to")) {
840 rule
->to_prefixlen
= prefixlen
;
843 rule
->from_prefixlen
= prefixlen
;
845 } else if (streq(a
, "tos")) {
846 r
= safe_atou8(b
, &rule
->tos
);
848 log_error_errno(r
, "Failed to parse RPDB rule tos, ignoring: %s", b
);
851 } else if (streq(a
, "table")) {
852 r
= safe_atou32(b
, &rule
->table
);
854 log_error_errno(r
, "Failed to parse RPDB rule table, ignoring: %s", b
);
857 } else if (streq(a
, "fwmark")) {
859 r
= parse_fwmark_fwmask(a
, &rule
->fwmark
, &rule
->fwmask
);
861 log_error_errno(r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a
);
867 r
= set_put(m
->rules_saved
, rule
);
869 log_warning_errno(r
, "Failed to add RPDB rule to saved DB, ignoring: %s", p
);
879 void routing_policy_rule_purge(Manager
*m
, Link
*link
) {
880 RoutingPolicyRule
*rule
, *existing
;
887 SET_FOREACH(rule
, m
->rules_saved
, i
) {
888 existing
= set_get(m
->rules_foreign
, rule
);
891 r
= routing_policy_rule_remove(rule
, link
, routing_policy_rule_remove_handler
);
893 log_warning_errno(r
, "Could not remove routing policy rules: %m");
897 link
->link_messages
++;