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
);
74 static void routing_policy_rule_hash_func(const void *b
, struct siphash
*state
) {
75 const RoutingPolicyRule
*rule
= b
;
79 siphash24_compress(&rule
->family
, sizeof(rule
->family
), state
);
81 switch (rule
->family
) {
85 siphash24_compress(&rule
->from
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
86 siphash24_compress(&rule
->from_prefixlen
, sizeof(rule
->from_prefixlen
), state
);
88 siphash24_compress(&rule
->to
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
89 siphash24_compress(&rule
->to_prefixlen
, sizeof(rule
->to_prefixlen
), state
);
91 siphash24_compress(&rule
->tos
, sizeof(rule
->tos
), state
);
92 siphash24_compress(&rule
->fwmark
, sizeof(rule
->fwmark
), state
);
93 siphash24_compress(&rule
->table
, sizeof(rule
->table
), state
);
96 siphash24_compress(&rule
->iif
, strlen(rule
->iif
), state
);
99 siphash24_compress(&rule
->oif
, strlen(rule
->oif
), state
);
103 /* treat any other address family as AF_UNSPEC */
108 static int routing_policy_rule_compare_func(const void *_a
, const void *_b
) {
109 const RoutingPolicyRule
*a
= _a
, *b
= _b
;
112 if (a
->family
< b
->family
)
114 if (a
->family
> b
->family
)
120 if (a
->from_prefixlen
< b
->from_prefixlen
)
122 if (a
->from_prefixlen
> b
->from_prefixlen
)
125 if (a
->to_prefixlen
< b
->to_prefixlen
)
127 if (a
->to_prefixlen
> b
->to_prefixlen
)
135 if (a
->fwmask
< b
->fwmark
)
137 if (a
->fwmask
> b
->fwmark
)
140 if (a
->table
< b
->table
)
142 if (a
->table
> b
->table
)
145 r
= strcmp_ptr(a
->iif
, b
->iif
);
149 r
= strcmp_ptr(a
->oif
, b
->oif
);
153 r
= memcmp(&a
->from
, &b
->from
, FAMILY_ADDRESS_SIZE(a
->family
));
157 return memcmp(&a
->to
, &b
->to
, FAMILY_ADDRESS_SIZE(a
->family
));
160 /* treat any other address family as AF_UNSPEC */
165 const struct hash_ops routing_policy_rule_hash_ops
= {
166 .hash
= routing_policy_rule_hash_func
,
167 .compare
= routing_policy_rule_compare_func
170 int routing_policy_rule_get(Manager
*m
,
172 const union in_addr_union
*from
,
173 uint8_t from_prefixlen
,
174 const union in_addr_union
*to
,
175 uint8_t to_prefixlen
,
181 RoutingPolicyRule
**ret
) {
183 RoutingPolicyRule rule
, *existing
;
185 assert_return(m
, -1);
187 rule
= (RoutingPolicyRule
) {
190 .from_prefixlen
= from_prefixlen
,
192 .to_prefixlen
= to_prefixlen
,
201 existing
= set_get(m
->rules
, &rule
);
209 if (m
->rules_foreign
) {
210 existing
= set_get(m
->rules_foreign
, &rule
);
221 int routing_policy_rule_make_local(Manager
*m
, RoutingPolicyRule
*rule
) {
226 if (set_contains(m
->rules_foreign
, rule
)) {
227 set_remove(m
->rules_foreign
, rule
);
229 r
= set_ensure_allocated(&m
->rules
, &routing_policy_rule_hash_ops
);
233 return set_put(m
->rules
, rule
);
239 static int routing_policy_rule_add_internal(Set
**rules
,
241 const union in_addr_union
*from
,
242 uint8_t from_prefixlen
,
243 const union in_addr_union
*to
,
244 uint8_t to_prefixlen
,
250 RoutingPolicyRule
**ret
) {
252 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
255 assert_return(rules
, -EINVAL
);
257 r
= routing_policy_rule_new(&rule
);
261 rule
->family
= family
;
263 rule
->from_prefixlen
= from_prefixlen
;
265 rule
->to_prefixlen
= to_prefixlen
;
267 rule
->fwmark
= fwmark
;
272 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
276 r
= set_put(*rules
, rule
);
288 int routing_policy_rule_add(Manager
*m
,
290 const union in_addr_union
*from
,
291 uint8_t from_prefixlen
,
292 const union in_addr_union
*to
,
293 uint8_t to_prefixlen
,
299 RoutingPolicyRule
**ret
) {
301 return routing_policy_rule_add_internal(&m
->rules
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
304 int routing_policy_rule_add_foreign(Manager
*m
,
306 const union in_addr_union
*from
,
307 uint8_t from_prefixlen
,
308 const union in_addr_union
*to
,
309 uint8_t to_prefixlen
,
315 RoutingPolicyRule
**ret
) {
316 return routing_policy_rule_add_internal(&m
->rules_foreign
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
319 static int routing_policy_rule_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
320 _cleanup_link_unref_ Link
*link
= userdata
;
325 assert(link
->ifname
);
327 link
->routing_policy_rule_remove_messages
--;
329 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
332 r
= sd_netlink_message_get_errno(m
);
334 log_link_warning_errno(link
, r
, "Could not drop routing policy rule: %m");
339 int routing_policy_rule_remove(RoutingPolicyRule
*routing_policy_rule
, Link
*link
, sd_netlink_message_handler_t callback
) {
340 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
343 assert(routing_policy_rule
);
345 assert(link
->manager
);
346 assert(link
->manager
->rtnl
);
347 assert(link
->ifindex
> 0);
348 assert(IN_SET(routing_policy_rule
->family
, AF_INET
, AF_INET6
));
350 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_DELRULE
, routing_policy_rule
->family
);
352 return log_error_errno(r
, "Could not allocate RTM_DELRULE message: %m");
354 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->from
)) {
355 if (routing_policy_rule
->family
== AF_INET
)
356 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in
);
358 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in6
);
361 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
363 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, routing_policy_rule
->from_prefixlen
);
365 return log_error_errno(r
, "Could not set source prefix length: %m");
368 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->to
)) {
369 if (routing_policy_rule
->family
== AF_INET
)
370 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in
);
372 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in6
);
375 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
377 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, routing_policy_rule
->to_prefixlen
);
379 return log_error_errno(r
, "Could not set destination prefix length: %m");
382 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
384 return log_error_errno(r
, "Could not send rtnetlink message: %m");
391 static int routing_policy_rule_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutingPolicyRule
**ret
) {
392 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
393 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
398 assert(!!filename
== (section_line
> 0));
400 r
= network_config_section_new(filename
, section_line
, &n
);
404 rule
= hashmap_get(network
->rules_by_section
, n
);
412 r
= routing_policy_rule_new(&rule
);
417 rule
->network
= network
;
420 r
= hashmap_put(network
->rules_by_section
, rule
->section
, rule
);
424 LIST_APPEND(rules
, network
->rules
, rule
);
433 int link_routing_policy_rule_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
434 _cleanup_link_unref_ Link
*link
= userdata
;
440 assert(link
->ifname
);
441 assert(link
->routing_policy_rule_messages
> 0);
443 link
->routing_policy_rule_messages
--;
445 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
448 r
= sd_netlink_message_get_errno(m
);
449 if (r
< 0 && r
!= -EEXIST
)
450 log_link_warning_errno(link
, r
, "Could not add routing policy rule: %m");
452 if (link
->routing_policy_rule_messages
== 0) {
453 log_link_debug(link
, "Routing policy rule configured");
454 link
->routing_policy_rules_configured
= true;
455 link_check_ready(link
);
461 int routing_policy_rule_configure(RoutingPolicyRule
*rule
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
462 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
467 assert(link
->ifindex
> 0);
468 assert(link
->manager
);
469 assert(link
->manager
->rtnl
);
471 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_NEWRULE
, rule
->family
);
473 return log_error_errno(r
, "Could not allocate RTM_NEWRULE message: %m");
475 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
476 if (rule
->family
== AF_INET
)
477 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &rule
->from
.in
);
479 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &rule
->from
.in6
);
482 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
484 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, rule
->from_prefixlen
);
486 return log_error_errno(r
, "Could not set source prefix length: %m");
489 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
490 if (rule
->family
== AF_INET
)
491 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &rule
->to
.in
);
493 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &rule
->to
.in6
);
496 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
498 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, rule
->to_prefixlen
);
500 return log_error_errno(r
, "Could not set destination prefix length: %m");
503 r
= sd_netlink_message_append_u32(m
, FRA_PRIORITY
, rule
->priority
);
505 return log_error_errno(r
, "Could not append FRA_PRIORITY attribute: %m");
508 r
= sd_rtnl_message_routing_policy_rule_set_tos(m
, rule
->tos
);
510 return log_error_errno(r
, "Could not set ip rule tos: %m");
513 if (rule
->table
< 256) {
514 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, rule
->table
);
516 return log_error_errno(r
, "Could not set ip rule table: %m");
518 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, RT_TABLE_UNSPEC
);
520 return log_error_errno(r
, "Could not set ip rule table: %m");
522 r
= sd_netlink_message_append_u32(m
, FRA_TABLE
, rule
->table
);
524 return log_error_errno(r
, "Could not append FRA_TABLE attribute: %m");
527 if (rule
->fwmark
> 0) {
528 r
= sd_netlink_message_append_u32(m
, FRA_FWMARK
, rule
->fwmark
);
530 return log_error_errno(r
, "Could not append FRA_FWMARK attribute: %m");
533 if (rule
->fwmask
> 0) {
534 r
= sd_netlink_message_append_u32(m
, FRA_FWMASK
, rule
->fwmask
);
536 return log_error_errno(r
, "Could not append FRA_FWMASK attribute: %m");
540 r
= sd_netlink_message_append_string(m
, FRA_IFNAME
, rule
->iif
);
542 return log_error_errno(r
, "Could not append FRA_IFNAME attribute: %m");
546 r
= sd_netlink_message_append_string(m
, FRA_OIFNAME
, rule
->oif
);
548 return log_error_errno(r
, "Could not append FRA_OIFNAME attribute: %m");
553 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
555 return log_error_errno(r
, "Could not send rtnetlink message: %m");
559 r
= routing_policy_rule_add(link
->manager
, rule
->family
, &rule
->from
, rule
->from_prefixlen
, &rule
->to
,
560 rule
->to_prefixlen
, rule
->tos
, rule
->fwmark
, rule
->table
, rule
->iif
, rule
->oif
, NULL
);
562 return log_error_errno(r
, "Could not add rule : %m");
567 static int parse_fwmark_fwmask(const char *s
, uint32_t *fwmark
, uint32_t *fwmask
) {
568 _cleanup_free_
char *f
= NULL
;
582 r
= safe_atou32(f
, fwmark
);
584 return log_error_errno(r
, "Failed to parse RPDB rule firewall mark, ignoring: %s", f
);
587 r
= safe_atou32(p
, fwmask
);
589 return log_error_errno(r
, "Failed to parse RPDB rule mask, ignoring: %s", f
);
595 int config_parse_routing_policy_rule_tos(
597 const char *filename
,
600 unsigned section_line
,
607 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
608 Network
*network
= userdata
;
617 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
621 r
= safe_atou8(rvalue
, &n
->tos
);
623 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule tos, ignoring: %s", rvalue
);
632 int config_parse_routing_policy_rule_priority(
634 const char *filename
,
637 unsigned section_line
,
644 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
645 Network
*network
= userdata
;
654 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
658 r
= safe_atou32(rvalue
, &n
->priority
);
660 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule priority, ignoring: %s", rvalue
);
669 int config_parse_routing_policy_rule_table(
671 const char *filename
,
674 unsigned section_line
,
681 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
682 Network
*network
= userdata
;
691 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
695 r
= safe_atou32(rvalue
, &n
->table
);
697 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule table, ignoring: %s", rvalue
);
706 int config_parse_routing_policy_rule_fwmark_mask(
708 const char *filename
,
711 unsigned section_line
,
718 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
719 Network
*network
= userdata
;
728 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
732 r
= parse_fwmark_fwmask(rvalue
, &n
->fwmark
, &n
->fwmask
);
734 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue
);
743 int config_parse_routing_policy_rule_prefix(
745 const char *filename
,
748 unsigned section_line
,
755 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
756 Network
*network
= userdata
;
757 union in_addr_union buffer
;
767 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
771 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &buffer
, &prefixlen
);
773 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &buffer
, &prefixlen
);
775 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue
);
779 n
->family
= AF_INET6
;
783 if (streq(lvalue
, "To")) {
785 n
->to_prefixlen
= prefixlen
;
788 n
->from_prefixlen
= prefixlen
;
796 int config_parse_routing_policy_rule_device(
798 const char *filename
,
801 unsigned section_line
,
808 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
809 Network
*network
= userdata
;
818 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
822 if (!ifname_valid(rvalue
)) {
823 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse '%s' interface name, ignoring: %s", lvalue
, rvalue
);
827 if (streq(lvalue
, "IncomingInterface")) {
828 r
= free_and_strdup(&n
->iif
, rvalue
);
832 r
= free_and_strdup(&n
->oif
, rvalue
);
842 static int routing_policy_rule_read_full_file(const char *state_file
, char **ret
) {
843 _cleanup_free_
char *s
= NULL
;
849 r
= read_full_file(state_file
, &s
, &size
);
863 int routing_policy_serialize_rules(Set
*rules
, FILE *f
) {
864 RoutingPolicyRule
*rule
= NULL
;
870 SET_FOREACH(rule
, rules
, i
) {
871 _cleanup_free_
char *from_str
= NULL
, *to_str
= NULL
;
876 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
877 r
= in_addr_to_string(rule
->family
, &rule
->from
, &from_str
);
881 fprintf(f
, "from=%s/%hhu",
882 from_str
, rule
->from_prefixlen
);
886 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
887 r
= in_addr_to_string(rule
->family
, &rule
->to
, &to_str
);
891 fprintf(f
, "%sto=%s/%hhu",
893 to_str
, rule
->to_prefixlen
);
897 if (rule
->tos
!= 0) {
898 fprintf(f
, "%stos=%hhu",
904 if (rule
->fwmark
!= 0) {
905 fprintf(f
, "%sfwmark=%"PRIu32
"/%"PRIu32
,
907 rule
->fwmark
, rule
->fwmask
);
912 fprintf(f
, "%siif=%s",
919 fprintf(f
, "%soif=%s",
925 fprintf(f
, "%stable=%"PRIu32
"\n",
933 int routing_policy_load_rules(const char *state_file
, Set
**rules
) {
934 _cleanup_strv_free_
char **l
= NULL
;
935 _cleanup_free_
char *data
= NULL
;
943 r
= routing_policy_rule_read_full_file(state_file
, &data
);
947 l
= strv_split_newlines(data
);
951 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
956 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
958 p
= startswith(*i
, "RULE=");
962 r
= routing_policy_rule_new(&rule
);
967 _cleanup_free_
char *word
= NULL
, *a
= NULL
, *b
= NULL
;
968 union in_addr_union buffer
;
971 r
= extract_first_word(&p
, &word
, NULL
, 0);
977 r
= split_pair(word
, "=", &a
, &b
);
981 if (STR_IN_SET(a
, "from", "to")) {
983 r
= in_addr_prefix_from_string(b
, AF_INET
, &buffer
, &prefixlen
);
985 r
= in_addr_prefix_from_string(b
, AF_INET6
, &buffer
, &prefixlen
);
987 log_error_errno(r
, "RPDB rule prefix is invalid, ignoring assignment: %s", b
);
991 rule
->family
= AF_INET6
;
993 rule
->family
= AF_INET
;
995 if (streq(a
, "to")) {
997 rule
->to_prefixlen
= prefixlen
;
1000 rule
->from_prefixlen
= prefixlen
;
1002 } else if (streq(a
, "tos")) {
1003 r
= safe_atou8(b
, &rule
->tos
);
1005 log_error_errno(r
, "Failed to parse RPDB rule tos, ignoring: %s", b
);
1008 } else if (streq(a
, "table")) {
1009 r
= safe_atou32(b
, &rule
->table
);
1011 log_error_errno(r
, "Failed to parse RPDB rule table, ignoring: %s", b
);
1014 } else if (streq(a
, "fwmark")) {
1016 r
= parse_fwmark_fwmask(b
, &rule
->fwmark
, &rule
->fwmask
);
1018 log_error_errno(r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a
);
1021 } else if (streq(a
, "iif")) {
1023 if (free_and_strdup(&rule
->iif
, b
) < 0)
1026 } else if (streq(a
, "oif")) {
1028 if (free_and_strdup(&rule
->oif
, b
) < 0)
1033 r
= set_put(*rules
, rule
);
1035 log_warning_errno(r
, "Failed to add RPDB rule to saved DB, ignoring: %s", p
);
1045 void routing_policy_rule_purge(Manager
*m
, Link
*link
) {
1046 RoutingPolicyRule
*rule
, *existing
;
1053 SET_FOREACH(rule
, m
->rules_saved
, i
) {
1054 existing
= set_get(m
->rules_foreign
, rule
);
1057 r
= routing_policy_rule_remove(rule
, link
, routing_policy_rule_remove_handler
);
1059 log_warning_errno(r
, "Could not remove routing policy rules: %m");
1063 link
->routing_policy_rule_remove_messages
++;