1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <linux/fib_rules.h>
6 #include "alloc-util.h"
7 #include "conf-parser.h"
9 #include "networkd-routing-policy-rule.h"
10 #include "netlink-util.h"
11 #include "networkd-manager.h"
12 #include "parse-util.h"
13 #include "socket-util.h"
14 #include "string-util.h"
17 int routing_policy_rule_new(RoutingPolicyRule
**ret
) {
18 RoutingPolicyRule
*rule
;
20 rule
= new(RoutingPolicyRule
, 1);
24 *rule
= (RoutingPolicyRule
) {
26 .table
= RT_TABLE_MAIN
,
33 void routing_policy_rule_free(RoutingPolicyRule
*rule
) {
39 LIST_REMOVE(rules
, rule
->network
->rules
, rule
);
40 assert(rule
->network
->n_rules
> 0);
41 rule
->network
->n_rules
--;
44 hashmap_remove(rule
->network
->rules_by_section
, rule
->section
);
45 network_config_section_free(rule
->section
);
51 set_remove(rule
->manager
->rules
, rule
);
52 set_remove(rule
->manager
->rules_foreign
, rule
);
60 static void routing_policy_rule_hash_func(const void *b
, struct siphash
*state
) {
61 const RoutingPolicyRule
*rule
= b
;
65 siphash24_compress(&rule
->family
, sizeof(rule
->family
), state
);
67 switch (rule
->family
) {
71 siphash24_compress(&rule
->from
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
72 siphash24_compress(&rule
->from_prefixlen
, sizeof(rule
->from_prefixlen
), state
);
74 siphash24_compress(&rule
->to
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
75 siphash24_compress(&rule
->to_prefixlen
, sizeof(rule
->to_prefixlen
), state
);
77 siphash24_compress(&rule
->tos
, sizeof(rule
->tos
), state
);
78 siphash24_compress(&rule
->fwmark
, sizeof(rule
->fwmark
), state
);
79 siphash24_compress(&rule
->table
, sizeof(rule
->table
), state
);
82 siphash24_compress(&rule
->iif
, strlen(rule
->iif
), state
);
85 siphash24_compress(&rule
->oif
, strlen(rule
->oif
), state
);
89 /* treat any other address family as AF_UNSPEC */
94 static int routing_policy_rule_compare_func(const void *_a
, const void *_b
) {
95 const RoutingPolicyRule
*a
= _a
, *b
= _b
;
98 r
= CMP(a
->family
, b
->family
);
105 r
= CMP(a
->from_prefixlen
, b
->from_prefixlen
);
109 r
= CMP(a
->to_prefixlen
, b
->to_prefixlen
);
113 r
= CMP(a
->tos
, b
->tos
);
117 r
= CMP(a
->fwmask
, b
->fwmask
);
121 r
= CMP(a
->table
, b
->table
);
125 r
= strcmp_ptr(a
->iif
, b
->iif
);
129 r
= strcmp_ptr(a
->oif
, b
->oif
);
133 r
= memcmp(&a
->from
, &b
->from
, FAMILY_ADDRESS_SIZE(a
->family
));
137 return memcmp(&a
->to
, &b
->to
, FAMILY_ADDRESS_SIZE(a
->family
));
140 /* treat any other address family as AF_UNSPEC */
145 const struct hash_ops routing_policy_rule_hash_ops
= {
146 .hash
= routing_policy_rule_hash_func
,
147 .compare
= routing_policy_rule_compare_func
150 int routing_policy_rule_get(Manager
*m
,
152 const union in_addr_union
*from
,
153 uint8_t from_prefixlen
,
154 const union in_addr_union
*to
,
155 uint8_t to_prefixlen
,
161 RoutingPolicyRule
**ret
) {
163 RoutingPolicyRule rule
, *existing
;
165 assert_return(m
, -1);
167 rule
= (RoutingPolicyRule
) {
170 .from_prefixlen
= from_prefixlen
,
172 .to_prefixlen
= to_prefixlen
,
180 existing
= set_get(m
->rules
, &rule
);
187 existing
= set_get(m
->rules_foreign
, &rule
);
197 int routing_policy_rule_make_local(Manager
*m
, RoutingPolicyRule
*rule
) {
202 if (set_contains(m
->rules_foreign
, rule
)) {
203 set_remove(m
->rules_foreign
, rule
);
205 r
= set_ensure_allocated(&m
->rules
, &routing_policy_rule_hash_ops
);
209 return set_put(m
->rules
, rule
);
215 static int routing_policy_rule_add_internal(Manager
*m
,
218 const union in_addr_union
*from
,
219 uint8_t from_prefixlen
,
220 const union in_addr_union
*to
,
221 uint8_t to_prefixlen
,
227 RoutingPolicyRule
**ret
) {
229 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*rule
= NULL
;
230 _cleanup_free_
char *iif
= NULL
, *oif
= NULL
;
233 assert_return(rules
, -EINVAL
);
247 r
= routing_policy_rule_new(&rule
);
252 rule
->family
= family
;
254 rule
->from_prefixlen
= from_prefixlen
;
256 rule
->to_prefixlen
= to_prefixlen
;
258 rule
->fwmark
= fwmark
;
260 rule
->iif
= TAKE_PTR(iif
);
261 rule
->oif
= TAKE_PTR(oif
);
263 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
267 r
= set_put(*rules
, rule
);
279 int routing_policy_rule_add(Manager
*m
,
281 const union in_addr_union
*from
,
282 uint8_t from_prefixlen
,
283 const union in_addr_union
*to
,
284 uint8_t to_prefixlen
,
290 RoutingPolicyRule
**ret
) {
292 return routing_policy_rule_add_internal(m
, &m
->rules
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
295 int routing_policy_rule_add_foreign(Manager
*m
,
297 const union in_addr_union
*from
,
298 uint8_t from_prefixlen
,
299 const union in_addr_union
*to
,
300 uint8_t to_prefixlen
,
306 RoutingPolicyRule
**ret
) {
307 return routing_policy_rule_add_internal(m
, &m
->rules_foreign
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
310 static int routing_policy_rule_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
311 Link
*link
= userdata
;
316 assert(link
->ifname
);
318 link
->routing_policy_rule_remove_messages
--;
320 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
323 r
= sd_netlink_message_get_errno(m
);
325 log_link_warning_errno(link
, r
, "Could not drop routing policy rule: %m");
330 int routing_policy_rule_remove(RoutingPolicyRule
*routing_policy_rule
, Link
*link
, sd_netlink_message_handler_t callback
) {
331 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
334 assert(routing_policy_rule
);
336 assert(link
->manager
);
337 assert(link
->manager
->rtnl
);
338 assert(link
->ifindex
> 0);
339 assert(IN_SET(routing_policy_rule
->family
, AF_INET
, AF_INET6
));
341 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_DELRULE
, routing_policy_rule
->family
);
343 return log_error_errno(r
, "Could not allocate RTM_DELRULE message: %m");
345 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->from
)) {
346 if (routing_policy_rule
->family
== AF_INET
)
347 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in
);
349 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in6
);
352 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
354 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, routing_policy_rule
->from_prefixlen
);
356 return log_error_errno(r
, "Could not set source prefix length: %m");
359 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->to
)) {
360 if (routing_policy_rule
->family
== AF_INET
)
361 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in
);
363 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in6
);
366 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
368 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, routing_policy_rule
->to_prefixlen
);
370 return log_error_errno(r
, "Could not set destination prefix length: %m");
373 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
,
374 link_netlink_destroy_callback
, link
, 0, NULL
);
376 return log_error_errno(r
, "Could not send rtnetlink message: %m");
383 static int routing_policy_rule_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutingPolicyRule
**ret
) {
384 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*rule
= NULL
;
385 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
390 assert(!!filename
== (section_line
> 0));
392 r
= network_config_section_new(filename
, section_line
, &n
);
396 rule
= hashmap_get(network
->rules_by_section
, n
);
398 *ret
= TAKE_PTR(rule
);
403 r
= routing_policy_rule_new(&rule
);
407 rule
->section
= TAKE_PTR(n
);
408 rule
->network
= network
;
410 r
= hashmap_put(network
->rules_by_section
, rule
->section
, rule
);
414 LIST_APPEND(rules
, network
->rules
, rule
);
417 *ret
= TAKE_PTR(rule
);
422 int link_routing_policy_rule_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
423 Link
*link
= userdata
;
429 assert(link
->ifname
);
430 assert(link
->routing_policy_rule_messages
> 0);
432 link
->routing_policy_rule_messages
--;
434 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
437 r
= sd_netlink_message_get_errno(m
);
438 if (r
< 0 && r
!= -EEXIST
)
439 log_link_warning_errno(link
, r
, "Could not add routing policy rule: %m");
441 if (link
->routing_policy_rule_messages
== 0) {
442 log_link_debug(link
, "Routing policy rule configured");
443 link
->routing_policy_rules_configured
= true;
444 link_check_ready(link
);
450 int routing_policy_rule_configure(RoutingPolicyRule
*rule
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
451 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
456 assert(link
->ifindex
> 0);
457 assert(link
->manager
);
458 assert(link
->manager
->rtnl
);
460 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_NEWRULE
, rule
->family
);
462 return log_error_errno(r
, "Could not allocate RTM_NEWRULE message: %m");
464 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
465 if (rule
->family
== AF_INET
)
466 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &rule
->from
.in
);
468 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &rule
->from
.in6
);
471 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
473 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, rule
->from_prefixlen
);
475 return log_error_errno(r
, "Could not set source prefix length: %m");
478 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
479 if (rule
->family
== AF_INET
)
480 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &rule
->to
.in
);
482 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &rule
->to
.in6
);
485 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
487 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, rule
->to_prefixlen
);
489 return log_error_errno(r
, "Could not set destination prefix length: %m");
492 r
= sd_netlink_message_append_u32(m
, FRA_PRIORITY
, rule
->priority
);
494 return log_error_errno(r
, "Could not append FRA_PRIORITY attribute: %m");
497 r
= sd_rtnl_message_routing_policy_rule_set_tos(m
, rule
->tos
);
499 return log_error_errno(r
, "Could not set ip rule tos: %m");
502 if (rule
->table
< 256) {
503 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, rule
->table
);
505 return log_error_errno(r
, "Could not set ip rule table: %m");
507 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, RT_TABLE_UNSPEC
);
509 return log_error_errno(r
, "Could not set ip rule table: %m");
511 r
= sd_netlink_message_append_u32(m
, FRA_TABLE
, rule
->table
);
513 return log_error_errno(r
, "Could not append FRA_TABLE attribute: %m");
516 if (rule
->fwmark
> 0) {
517 r
= sd_netlink_message_append_u32(m
, FRA_FWMARK
, rule
->fwmark
);
519 return log_error_errno(r
, "Could not append FRA_FWMARK attribute: %m");
522 if (rule
->fwmask
> 0) {
523 r
= sd_netlink_message_append_u32(m
, FRA_FWMASK
, rule
->fwmask
);
525 return log_error_errno(r
, "Could not append FRA_FWMASK attribute: %m");
529 r
= sd_netlink_message_append_string(m
, FRA_IFNAME
, rule
->iif
);
531 return log_error_errno(r
, "Could not append FRA_IFNAME attribute: %m");
535 r
= sd_netlink_message_append_string(m
, FRA_OIFNAME
, rule
->oif
);
537 return log_error_errno(r
, "Could not append FRA_OIFNAME attribute: %m");
542 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
,
543 link_netlink_destroy_callback
, link
, 0, NULL
);
545 return log_error_errno(r
, "Could not send rtnetlink message: %m");
549 r
= routing_policy_rule_add(link
->manager
, rule
->family
, &rule
->from
, rule
->from_prefixlen
, &rule
->to
,
550 rule
->to_prefixlen
, rule
->tos
, rule
->fwmark
, rule
->table
, rule
->iif
, rule
->oif
, NULL
);
552 return log_error_errno(r
, "Could not add rule : %m");
557 static int parse_fwmark_fwmask(const char *s
, uint32_t *fwmark
, uint32_t *fwmask
) {
558 _cleanup_free_
char *f
= NULL
;
572 r
= safe_atou32(f
, fwmark
);
574 return log_error_errno(r
, "Failed to parse RPDB rule firewall mark, ignoring: %s", f
);
577 r
= safe_atou32(p
, fwmask
);
579 return log_error_errno(r
, "Failed to parse RPDB rule mask, ignoring: %s", f
);
585 int config_parse_routing_policy_rule_tos(
587 const char *filename
,
590 unsigned section_line
,
597 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*n
= NULL
;
598 Network
*network
= userdata
;
607 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
611 r
= safe_atou8(rvalue
, &n
->tos
);
613 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule tos, ignoring: %s", rvalue
);
622 int config_parse_routing_policy_rule_priority(
624 const char *filename
,
627 unsigned section_line
,
634 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*n
= NULL
;
635 Network
*network
= userdata
;
644 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
648 r
= safe_atou32(rvalue
, &n
->priority
);
650 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule priority, ignoring: %s", rvalue
);
659 int config_parse_routing_policy_rule_table(
661 const char *filename
,
664 unsigned section_line
,
671 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*n
= NULL
;
672 Network
*network
= userdata
;
681 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
685 r
= safe_atou32(rvalue
, &n
->table
);
687 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule table, ignoring: %s", rvalue
);
696 int config_parse_routing_policy_rule_fwmark_mask(
698 const char *filename
,
701 unsigned section_line
,
708 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*n
= NULL
;
709 Network
*network
= userdata
;
718 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
722 r
= parse_fwmark_fwmask(rvalue
, &n
->fwmark
, &n
->fwmask
);
724 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue
);
733 int config_parse_routing_policy_rule_prefix(
735 const char *filename
,
738 unsigned section_line
,
745 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*n
= NULL
;
746 Network
*network
= userdata
;
747 union in_addr_union buffer
;
757 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
761 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &buffer
, &prefixlen
);
763 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &buffer
, &prefixlen
);
765 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue
);
769 n
->family
= AF_INET6
;
773 if (streq(lvalue
, "To")) {
775 n
->to_prefixlen
= prefixlen
;
778 n
->from_prefixlen
= prefixlen
;
786 int config_parse_routing_policy_rule_device(
788 const char *filename
,
791 unsigned section_line
,
798 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*n
= NULL
;
799 Network
*network
= userdata
;
808 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
812 if (!ifname_valid(rvalue
)) {
813 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse '%s' interface name, ignoring: %s", lvalue
, rvalue
);
817 if (streq(lvalue
, "IncomingInterface")) {
818 r
= free_and_strdup(&n
->iif
, rvalue
);
822 r
= free_and_strdup(&n
->oif
, rvalue
);
832 static int routing_policy_rule_read_full_file(const char *state_file
, char **ret
) {
833 _cleanup_free_
char *s
= NULL
;
839 r
= read_full_file(state_file
, &s
, &size
);
852 int routing_policy_serialize_rules(Set
*rules
, FILE *f
) {
853 RoutingPolicyRule
*rule
= NULL
;
859 SET_FOREACH(rule
, rules
, i
) {
860 _cleanup_free_
char *from_str
= NULL
, *to_str
= NULL
;
865 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
866 r
= in_addr_to_string(rule
->family
, &rule
->from
, &from_str
);
870 fprintf(f
, "from=%s/%hhu",
871 from_str
, rule
->from_prefixlen
);
875 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
876 r
= in_addr_to_string(rule
->family
, &rule
->to
, &to_str
);
880 fprintf(f
, "%sto=%s/%hhu",
882 to_str
, rule
->to_prefixlen
);
886 if (rule
->tos
!= 0) {
887 fprintf(f
, "%stos=%hhu",
893 if (rule
->fwmark
!= 0) {
894 fprintf(f
, "%sfwmark=%"PRIu32
"/%"PRIu32
,
896 rule
->fwmark
, rule
->fwmask
);
901 fprintf(f
, "%siif=%s",
908 fprintf(f
, "%soif=%s",
914 fprintf(f
, "%stable=%"PRIu32
"\n",
922 int routing_policy_load_rules(const char *state_file
, Set
**rules
) {
923 _cleanup_strv_free_
char **l
= NULL
;
924 _cleanup_free_
char *data
= NULL
;
932 r
= routing_policy_rule_read_full_file(state_file
, &data
);
936 l
= strv_split_newlines(data
);
940 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
945 _cleanup_(routing_policy_rule_freep
) RoutingPolicyRule
*rule
= NULL
;
947 p
= startswith(*i
, "RULE=");
951 r
= routing_policy_rule_new(&rule
);
956 _cleanup_free_
char *word
= NULL
, *a
= NULL
, *b
= NULL
;
957 union in_addr_union buffer
;
960 r
= extract_first_word(&p
, &word
, NULL
, 0);
966 r
= split_pair(word
, "=", &a
, &b
);
970 if (STR_IN_SET(a
, "from", "to")) {
972 r
= in_addr_prefix_from_string(b
, AF_INET
, &buffer
, &prefixlen
);
974 r
= in_addr_prefix_from_string(b
, AF_INET6
, &buffer
, &prefixlen
);
976 log_error_errno(r
, "RPDB rule prefix is invalid, ignoring assignment: %s", b
);
980 rule
->family
= AF_INET6
;
982 rule
->family
= AF_INET
;
984 if (streq(a
, "to")) {
986 rule
->to_prefixlen
= prefixlen
;
989 rule
->from_prefixlen
= prefixlen
;
991 } else if (streq(a
, "tos")) {
992 r
= safe_atou8(b
, &rule
->tos
);
994 log_error_errno(r
, "Failed to parse RPDB rule tos, ignoring: %s", b
);
997 } else if (streq(a
, "table")) {
998 r
= safe_atou32(b
, &rule
->table
);
1000 log_error_errno(r
, "Failed to parse RPDB rule table, ignoring: %s", b
);
1003 } else if (streq(a
, "fwmark")) {
1005 r
= parse_fwmark_fwmask(b
, &rule
->fwmark
, &rule
->fwmask
);
1007 log_error_errno(r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a
);
1010 } else if (streq(a
, "iif")) {
1012 if (free_and_strdup(&rule
->iif
, b
) < 0)
1015 } else if (streq(a
, "oif")) {
1017 if (free_and_strdup(&rule
->oif
, b
) < 0)
1022 r
= set_put(*rules
, rule
);
1024 log_warning_errno(r
, "Failed to add RPDB rule to saved DB, ignoring: %s", p
);
1034 void routing_policy_rule_purge(Manager
*m
, Link
*link
) {
1035 RoutingPolicyRule
*rule
, *existing
;
1042 SET_FOREACH(rule
, m
->rules_saved
, i
) {
1043 existing
= set_get(m
->rules_foreign
, rule
);
1046 r
= routing_policy_rule_remove(rule
, link
, routing_policy_rule_remove_handler
);
1048 log_warning_errno(r
, "Could not remove routing policy rules: %m");
1052 link
->routing_policy_rule_remove_messages
++;