1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2017 Susant Sahani
9 #include <linux/fib_rules.h>
11 #include "alloc-util.h"
12 #include "conf-parser.h"
14 #include "networkd-routing-policy-rule.h"
15 #include "netlink-util.h"
16 #include "networkd-manager.h"
17 #include "parse-util.h"
18 #include "socket-util.h"
19 #include "string-util.h"
21 int routing_policy_rule_new(RoutingPolicyRule
**ret
) {
22 RoutingPolicyRule
*rule
;
24 rule
= new0(RoutingPolicyRule
, 1);
28 rule
->family
= AF_INET
;
29 rule
->table
= RT_TABLE_MAIN
;
35 void routing_policy_rule_free(RoutingPolicyRule
*rule
) {
41 LIST_REMOVE(rules
, rule
->network
->rules
, rule
);
42 assert(rule
->network
->n_rules
> 0);
43 rule
->network
->n_rules
--;
46 hashmap_remove(rule
->network
->rules_by_section
, rule
->section
);
47 network_config_section_free(rule
->section
);
53 set_remove(rule
->manager
->rules
, rule
);
54 set_remove(rule
->manager
->rules_foreign
, rule
);
62 static void routing_policy_rule_hash_func(const void *b
, struct siphash
*state
) {
63 const RoutingPolicyRule
*rule
= b
;
67 siphash24_compress(&rule
->family
, sizeof(rule
->family
), state
);
69 switch (rule
->family
) {
73 siphash24_compress(&rule
->from
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
74 siphash24_compress(&rule
->from_prefixlen
, sizeof(rule
->from_prefixlen
), state
);
76 siphash24_compress(&rule
->to
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
77 siphash24_compress(&rule
->to_prefixlen
, sizeof(rule
->to_prefixlen
), state
);
79 siphash24_compress(&rule
->tos
, sizeof(rule
->tos
), state
);
80 siphash24_compress(&rule
->fwmark
, sizeof(rule
->fwmark
), state
);
81 siphash24_compress(&rule
->table
, sizeof(rule
->table
), state
);
84 siphash24_compress(&rule
->iif
, strlen(rule
->iif
), state
);
87 siphash24_compress(&rule
->oif
, strlen(rule
->oif
), state
);
91 /* treat any other address family as AF_UNSPEC */
96 static int routing_policy_rule_compare_func(const void *_a
, const void *_b
) {
97 const RoutingPolicyRule
*a
= _a
, *b
= _b
;
100 if (a
->family
< b
->family
)
102 if (a
->family
> b
->family
)
108 if (a
->from_prefixlen
< b
->from_prefixlen
)
110 if (a
->from_prefixlen
> b
->from_prefixlen
)
113 if (a
->to_prefixlen
< b
->to_prefixlen
)
115 if (a
->to_prefixlen
> b
->to_prefixlen
)
123 if (a
->fwmask
< b
->fwmark
)
125 if (a
->fwmask
> b
->fwmark
)
128 if (a
->table
< b
->table
)
130 if (a
->table
> b
->table
)
133 r
= strcmp_ptr(a
->iif
, b
->iif
);
137 r
= strcmp_ptr(a
->oif
, b
->oif
);
141 r
= memcmp(&a
->from
, &b
->from
, FAMILY_ADDRESS_SIZE(a
->family
));
145 return memcmp(&a
->to
, &b
->to
, FAMILY_ADDRESS_SIZE(a
->family
));
148 /* treat any other address family as AF_UNSPEC */
153 const struct hash_ops routing_policy_rule_hash_ops
= {
154 .hash
= routing_policy_rule_hash_func
,
155 .compare
= routing_policy_rule_compare_func
158 int routing_policy_rule_get(Manager
*m
,
160 const union in_addr_union
*from
,
161 uint8_t from_prefixlen
,
162 const union in_addr_union
*to
,
163 uint8_t to_prefixlen
,
169 RoutingPolicyRule
**ret
) {
171 RoutingPolicyRule rule
, *existing
;
173 assert_return(m
, -1);
175 rule
= (RoutingPolicyRule
) {
178 .from_prefixlen
= from_prefixlen
,
180 .to_prefixlen
= to_prefixlen
,
189 existing
= set_get(m
->rules
, &rule
);
197 if (m
->rules_foreign
) {
198 existing
= set_get(m
->rules_foreign
, &rule
);
209 int routing_policy_rule_make_local(Manager
*m
, RoutingPolicyRule
*rule
) {
214 if (set_contains(m
->rules_foreign
, rule
)) {
215 set_remove(m
->rules_foreign
, rule
);
217 r
= set_ensure_allocated(&m
->rules
, &routing_policy_rule_hash_ops
);
221 return set_put(m
->rules
, rule
);
227 static int routing_policy_rule_add_internal(Manager
*m
,
230 const union in_addr_union
*from
,
231 uint8_t from_prefixlen
,
232 const union in_addr_union
*to
,
233 uint8_t to_prefixlen
,
239 RoutingPolicyRule
**ret
) {
241 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
244 assert_return(rules
, -EINVAL
);
246 r
= routing_policy_rule_new(&rule
);
251 rule
->family
= family
;
253 rule
->from_prefixlen
= from_prefixlen
;
255 rule
->to_prefixlen
= to_prefixlen
;
257 rule
->fwmark
= fwmark
;
262 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
266 r
= set_put(*rules
, rule
);
278 int routing_policy_rule_add(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
,
289 RoutingPolicyRule
**ret
) {
291 return routing_policy_rule_add_internal(m
, &m
->rules
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
294 int routing_policy_rule_add_foreign(Manager
*m
,
296 const union in_addr_union
*from
,
297 uint8_t from_prefixlen
,
298 const union in_addr_union
*to
,
299 uint8_t to_prefixlen
,
305 RoutingPolicyRule
**ret
) {
306 return routing_policy_rule_add_internal(m
, &m
->rules_foreign
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
309 static int routing_policy_rule_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
310 _cleanup_link_unref_ Link
*link
= userdata
;
315 assert(link
->ifname
);
317 link
->routing_policy_rule_remove_messages
--;
319 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
322 r
= sd_netlink_message_get_errno(m
);
324 log_link_warning_errno(link
, r
, "Could not drop routing policy rule: %m");
329 int routing_policy_rule_remove(RoutingPolicyRule
*routing_policy_rule
, Link
*link
, sd_netlink_message_handler_t callback
) {
330 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
333 assert(routing_policy_rule
);
335 assert(link
->manager
);
336 assert(link
->manager
->rtnl
);
337 assert(link
->ifindex
> 0);
338 assert(IN_SET(routing_policy_rule
->family
, AF_INET
, AF_INET6
));
340 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_DELRULE
, routing_policy_rule
->family
);
342 return log_error_errno(r
, "Could not allocate RTM_DELRULE message: %m");
344 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->from
)) {
345 if (routing_policy_rule
->family
== AF_INET
)
346 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in
);
348 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in6
);
351 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
353 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, routing_policy_rule
->from_prefixlen
);
355 return log_error_errno(r
, "Could not set source prefix length: %m");
358 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->to
)) {
359 if (routing_policy_rule
->family
== AF_INET
)
360 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in
);
362 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in6
);
365 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
367 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, routing_policy_rule
->to_prefixlen
);
369 return log_error_errno(r
, "Could not set destination prefix length: %m");
372 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
374 return log_error_errno(r
, "Could not send rtnetlink message: %m");
381 static int routing_policy_rule_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutingPolicyRule
**ret
) {
382 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
383 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
388 assert(!!filename
== (section_line
> 0));
390 r
= network_config_section_new(filename
, section_line
, &n
);
394 rule
= hashmap_get(network
->rules_by_section
, n
);
396 *ret
= TAKE_PTR(rule
);
401 r
= routing_policy_rule_new(&rule
);
406 rule
->network
= network
;
409 r
= hashmap_put(network
->rules_by_section
, rule
->section
, rule
);
413 LIST_APPEND(rules
, network
->rules
, rule
);
416 *ret
= TAKE_PTR(rule
);
421 int link_routing_policy_rule_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
422 _cleanup_link_unref_ Link
*link
= userdata
;
428 assert(link
->ifname
);
429 assert(link
->routing_policy_rule_messages
> 0);
431 link
->routing_policy_rule_messages
--;
433 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
436 r
= sd_netlink_message_get_errno(m
);
437 if (r
< 0 && r
!= -EEXIST
)
438 log_link_warning_errno(link
, r
, "Could not add routing policy rule: %m");
440 if (link
->routing_policy_rule_messages
== 0) {
441 log_link_debug(link
, "Routing policy rule configured");
442 link
->routing_policy_rules_configured
= true;
443 link_check_ready(link
);
449 int routing_policy_rule_configure(RoutingPolicyRule
*rule
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
450 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
455 assert(link
->ifindex
> 0);
456 assert(link
->manager
);
457 assert(link
->manager
->rtnl
);
459 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_NEWRULE
, rule
->family
);
461 return log_error_errno(r
, "Could not allocate RTM_NEWRULE message: %m");
463 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
464 if (rule
->family
== AF_INET
)
465 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &rule
->from
.in
);
467 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &rule
->from
.in6
);
470 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
472 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, rule
->from_prefixlen
);
474 return log_error_errno(r
, "Could not set source prefix length: %m");
477 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
478 if (rule
->family
== AF_INET
)
479 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &rule
->to
.in
);
481 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &rule
->to
.in6
);
484 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
486 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, rule
->to_prefixlen
);
488 return log_error_errno(r
, "Could not set destination prefix length: %m");
491 r
= sd_netlink_message_append_u32(m
, FRA_PRIORITY
, rule
->priority
);
493 return log_error_errno(r
, "Could not append FRA_PRIORITY attribute: %m");
496 r
= sd_rtnl_message_routing_policy_rule_set_tos(m
, rule
->tos
);
498 return log_error_errno(r
, "Could not set ip rule tos: %m");
501 if (rule
->table
< 256) {
502 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, rule
->table
);
504 return log_error_errno(r
, "Could not set ip rule table: %m");
506 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, RT_TABLE_UNSPEC
);
508 return log_error_errno(r
, "Could not set ip rule table: %m");
510 r
= sd_netlink_message_append_u32(m
, FRA_TABLE
, rule
->table
);
512 return log_error_errno(r
, "Could not append FRA_TABLE attribute: %m");
515 if (rule
->fwmark
> 0) {
516 r
= sd_netlink_message_append_u32(m
, FRA_FWMARK
, rule
->fwmark
);
518 return log_error_errno(r
, "Could not append FRA_FWMARK attribute: %m");
521 if (rule
->fwmask
> 0) {
522 r
= sd_netlink_message_append_u32(m
, FRA_FWMASK
, rule
->fwmask
);
524 return log_error_errno(r
, "Could not append FRA_FWMASK attribute: %m");
528 r
= sd_netlink_message_append_string(m
, FRA_IFNAME
, rule
->iif
);
530 return log_error_errno(r
, "Could not append FRA_IFNAME attribute: %m");
534 r
= sd_netlink_message_append_string(m
, FRA_OIFNAME
, rule
->oif
);
536 return log_error_errno(r
, "Could not append FRA_OIFNAME attribute: %m");
541 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
543 return log_error_errno(r
, "Could not send rtnetlink message: %m");
547 r
= routing_policy_rule_add(link
->manager
, rule
->family
, &rule
->from
, rule
->from_prefixlen
, &rule
->to
,
548 rule
->to_prefixlen
, rule
->tos
, rule
->fwmark
, rule
->table
, rule
->iif
, rule
->oif
, NULL
);
550 return log_error_errno(r
, "Could not add rule : %m");
555 static int parse_fwmark_fwmask(const char *s
, uint32_t *fwmark
, uint32_t *fwmask
) {
556 _cleanup_free_
char *f
= NULL
;
570 r
= safe_atou32(f
, fwmark
);
572 return log_error_errno(r
, "Failed to parse RPDB rule firewall mark, ignoring: %s", f
);
575 r
= safe_atou32(p
, fwmask
);
577 return log_error_errno(r
, "Failed to parse RPDB rule mask, ignoring: %s", f
);
583 int config_parse_routing_policy_rule_tos(
585 const char *filename
,
588 unsigned section_line
,
595 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
596 Network
*network
= userdata
;
605 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
609 r
= safe_atou8(rvalue
, &n
->tos
);
611 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule tos, ignoring: %s", rvalue
);
620 int config_parse_routing_policy_rule_priority(
622 const char *filename
,
625 unsigned section_line
,
632 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
633 Network
*network
= userdata
;
642 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
646 r
= safe_atou32(rvalue
, &n
->priority
);
648 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule priority, ignoring: %s", rvalue
);
657 int config_parse_routing_policy_rule_table(
659 const char *filename
,
662 unsigned section_line
,
669 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
670 Network
*network
= userdata
;
679 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
683 r
= safe_atou32(rvalue
, &n
->table
);
685 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule table, ignoring: %s", rvalue
);
694 int config_parse_routing_policy_rule_fwmark_mask(
696 const char *filename
,
699 unsigned section_line
,
706 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
707 Network
*network
= userdata
;
716 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
720 r
= parse_fwmark_fwmask(rvalue
, &n
->fwmark
, &n
->fwmask
);
722 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue
);
731 int config_parse_routing_policy_rule_prefix(
733 const char *filename
,
736 unsigned section_line
,
743 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
744 Network
*network
= userdata
;
745 union in_addr_union buffer
;
755 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
759 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &buffer
, &prefixlen
);
761 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &buffer
, &prefixlen
);
763 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue
);
767 n
->family
= AF_INET6
;
771 if (streq(lvalue
, "To")) {
773 n
->to_prefixlen
= prefixlen
;
776 n
->from_prefixlen
= prefixlen
;
784 int config_parse_routing_policy_rule_device(
786 const char *filename
,
789 unsigned section_line
,
796 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
797 Network
*network
= userdata
;
806 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
810 if (!ifname_valid(rvalue
)) {
811 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse '%s' interface name, ignoring: %s", lvalue
, rvalue
);
815 if (streq(lvalue
, "IncomingInterface")) {
816 r
= free_and_strdup(&n
->iif
, rvalue
);
820 r
= free_and_strdup(&n
->oif
, rvalue
);
830 static int routing_policy_rule_read_full_file(const char *state_file
, char **ret
) {
831 _cleanup_free_
char *s
= NULL
;
837 r
= read_full_file(state_file
, &s
, &size
);
850 int routing_policy_serialize_rules(Set
*rules
, FILE *f
) {
851 RoutingPolicyRule
*rule
= NULL
;
857 SET_FOREACH(rule
, rules
, i
) {
858 _cleanup_free_
char *from_str
= NULL
, *to_str
= NULL
;
863 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
864 r
= in_addr_to_string(rule
->family
, &rule
->from
, &from_str
);
868 fprintf(f
, "from=%s/%hhu",
869 from_str
, rule
->from_prefixlen
);
873 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
874 r
= in_addr_to_string(rule
->family
, &rule
->to
, &to_str
);
878 fprintf(f
, "%sto=%s/%hhu",
880 to_str
, rule
->to_prefixlen
);
884 if (rule
->tos
!= 0) {
885 fprintf(f
, "%stos=%hhu",
891 if (rule
->fwmark
!= 0) {
892 fprintf(f
, "%sfwmark=%"PRIu32
"/%"PRIu32
,
894 rule
->fwmark
, rule
->fwmask
);
899 fprintf(f
, "%siif=%s",
906 fprintf(f
, "%soif=%s",
912 fprintf(f
, "%stable=%"PRIu32
"\n",
920 int routing_policy_load_rules(const char *state_file
, Set
**rules
) {
921 _cleanup_strv_free_
char **l
= NULL
;
922 _cleanup_free_
char *data
= NULL
;
930 r
= routing_policy_rule_read_full_file(state_file
, &data
);
934 l
= strv_split_newlines(data
);
938 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
943 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
945 p
= startswith(*i
, "RULE=");
949 r
= routing_policy_rule_new(&rule
);
954 _cleanup_free_
char *word
= NULL
, *a
= NULL
, *b
= NULL
;
955 union in_addr_union buffer
;
958 r
= extract_first_word(&p
, &word
, NULL
, 0);
964 r
= split_pair(word
, "=", &a
, &b
);
968 if (STR_IN_SET(a
, "from", "to")) {
970 r
= in_addr_prefix_from_string(b
, AF_INET
, &buffer
, &prefixlen
);
972 r
= in_addr_prefix_from_string(b
, AF_INET6
, &buffer
, &prefixlen
);
974 log_error_errno(r
, "RPDB rule prefix is invalid, ignoring assignment: %s", b
);
978 rule
->family
= AF_INET6
;
980 rule
->family
= AF_INET
;
982 if (streq(a
, "to")) {
984 rule
->to_prefixlen
= prefixlen
;
987 rule
->from_prefixlen
= prefixlen
;
989 } else if (streq(a
, "tos")) {
990 r
= safe_atou8(b
, &rule
->tos
);
992 log_error_errno(r
, "Failed to parse RPDB rule tos, ignoring: %s", b
);
995 } else if (streq(a
, "table")) {
996 r
= safe_atou32(b
, &rule
->table
);
998 log_error_errno(r
, "Failed to parse RPDB rule table, ignoring: %s", b
);
1001 } else if (streq(a
, "fwmark")) {
1003 r
= parse_fwmark_fwmask(b
, &rule
->fwmark
, &rule
->fwmask
);
1005 log_error_errno(r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a
);
1008 } else if (streq(a
, "iif")) {
1010 if (free_and_strdup(&rule
->iif
, b
) < 0)
1013 } else if (streq(a
, "oif")) {
1015 if (free_and_strdup(&rule
->oif
, b
) < 0)
1020 r
= set_put(*rules
, rule
);
1022 log_warning_errno(r
, "Failed to add RPDB rule to saved DB, ignoring: %s", p
);
1032 void routing_policy_rule_purge(Manager
*m
, Link
*link
) {
1033 RoutingPolicyRule
*rule
, *existing
;
1040 SET_FOREACH(rule
, m
->rules_saved
, i
) {
1041 existing
= set_get(m
->rules_foreign
, rule
);
1044 r
= routing_policy_rule_remove(rule
, link
, routing_policy_rule_remove_handler
);
1046 log_warning_errno(r
, "Could not remove routing policy rules: %m");
1050 link
->routing_policy_rule_remove_messages
++;