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
);
66 set_remove(rule
->manager
->rules
, rule
);
67 set_remove(rule
->manager
->rules_foreign
, rule
);
75 static void routing_policy_rule_hash_func(const void *b
, struct siphash
*state
) {
76 const RoutingPolicyRule
*rule
= b
;
80 siphash24_compress(&rule
->family
, sizeof(rule
->family
), state
);
82 switch (rule
->family
) {
86 siphash24_compress(&rule
->from
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
87 siphash24_compress(&rule
->from_prefixlen
, sizeof(rule
->from_prefixlen
), state
);
89 siphash24_compress(&rule
->to
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
90 siphash24_compress(&rule
->to_prefixlen
, sizeof(rule
->to_prefixlen
), state
);
92 siphash24_compress(&rule
->tos
, sizeof(rule
->tos
), state
);
93 siphash24_compress(&rule
->fwmark
, sizeof(rule
->fwmark
), state
);
94 siphash24_compress(&rule
->table
, sizeof(rule
->table
), state
);
97 siphash24_compress(&rule
->iif
, strlen(rule
->iif
), state
);
100 siphash24_compress(&rule
->oif
, strlen(rule
->oif
), state
);
104 /* treat any other address family as AF_UNSPEC */
109 static int routing_policy_rule_compare_func(const void *_a
, const void *_b
) {
110 const RoutingPolicyRule
*a
= _a
, *b
= _b
;
113 if (a
->family
< b
->family
)
115 if (a
->family
> b
->family
)
121 if (a
->from_prefixlen
< b
->from_prefixlen
)
123 if (a
->from_prefixlen
> b
->from_prefixlen
)
126 if (a
->to_prefixlen
< b
->to_prefixlen
)
128 if (a
->to_prefixlen
> b
->to_prefixlen
)
136 if (a
->fwmask
< b
->fwmark
)
138 if (a
->fwmask
> b
->fwmark
)
141 if (a
->table
< b
->table
)
143 if (a
->table
> b
->table
)
146 r
= strcmp_ptr(a
->iif
, b
->iif
);
150 r
= strcmp_ptr(a
->oif
, b
->oif
);
154 r
= memcmp(&a
->from
, &b
->from
, FAMILY_ADDRESS_SIZE(a
->family
));
158 return memcmp(&a
->to
, &b
->to
, FAMILY_ADDRESS_SIZE(a
->family
));
161 /* treat any other address family as AF_UNSPEC */
166 const struct hash_ops routing_policy_rule_hash_ops
= {
167 .hash
= routing_policy_rule_hash_func
,
168 .compare
= routing_policy_rule_compare_func
171 int routing_policy_rule_get(Manager
*m
,
173 const union in_addr_union
*from
,
174 uint8_t from_prefixlen
,
175 const union in_addr_union
*to
,
176 uint8_t to_prefixlen
,
182 RoutingPolicyRule
**ret
) {
184 RoutingPolicyRule rule
, *existing
;
186 assert_return(m
, -1);
188 rule
= (RoutingPolicyRule
) {
191 .from_prefixlen
= from_prefixlen
,
193 .to_prefixlen
= to_prefixlen
,
202 existing
= set_get(m
->rules
, &rule
);
210 if (m
->rules_foreign
) {
211 existing
= set_get(m
->rules_foreign
, &rule
);
222 int routing_policy_rule_make_local(Manager
*m
, RoutingPolicyRule
*rule
) {
227 if (set_contains(m
->rules_foreign
, rule
)) {
228 set_remove(m
->rules_foreign
, rule
);
230 r
= set_ensure_allocated(&m
->rules
, &routing_policy_rule_hash_ops
);
234 return set_put(m
->rules
, rule
);
240 static int routing_policy_rule_add_internal(Manager
*m
,
243 const union in_addr_union
*from
,
244 uint8_t from_prefixlen
,
245 const union in_addr_union
*to
,
246 uint8_t to_prefixlen
,
252 RoutingPolicyRule
**ret
) {
254 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
257 assert_return(rules
, -EINVAL
);
259 r
= routing_policy_rule_new(&rule
);
264 rule
->family
= family
;
266 rule
->from_prefixlen
= from_prefixlen
;
268 rule
->to_prefixlen
= to_prefixlen
;
270 rule
->fwmark
= fwmark
;
275 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
279 r
= set_put(*rules
, rule
);
291 int routing_policy_rule_add(Manager
*m
,
293 const union in_addr_union
*from
,
294 uint8_t from_prefixlen
,
295 const union in_addr_union
*to
,
296 uint8_t to_prefixlen
,
302 RoutingPolicyRule
**ret
) {
304 return routing_policy_rule_add_internal(m
, &m
->rules
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
307 int routing_policy_rule_add_foreign(Manager
*m
,
309 const union in_addr_union
*from
,
310 uint8_t from_prefixlen
,
311 const union in_addr_union
*to
,
312 uint8_t to_prefixlen
,
318 RoutingPolicyRule
**ret
) {
319 return routing_policy_rule_add_internal(m
, &m
->rules_foreign
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, iif
, oif
, ret
);
322 static int routing_policy_rule_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
323 _cleanup_link_unref_ Link
*link
= userdata
;
328 assert(link
->ifname
);
330 link
->routing_policy_rule_remove_messages
--;
332 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
335 r
= sd_netlink_message_get_errno(m
);
337 log_link_warning_errno(link
, r
, "Could not drop routing policy rule: %m");
342 int routing_policy_rule_remove(RoutingPolicyRule
*routing_policy_rule
, Link
*link
, sd_netlink_message_handler_t callback
) {
343 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
346 assert(routing_policy_rule
);
348 assert(link
->manager
);
349 assert(link
->manager
->rtnl
);
350 assert(link
->ifindex
> 0);
351 assert(IN_SET(routing_policy_rule
->family
, AF_INET
, AF_INET6
));
353 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_DELRULE
, routing_policy_rule
->family
);
355 return log_error_errno(r
, "Could not allocate RTM_DELRULE message: %m");
357 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->from
)) {
358 if (routing_policy_rule
->family
== AF_INET
)
359 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in
);
361 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in6
);
364 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
366 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, routing_policy_rule
->from_prefixlen
);
368 return log_error_errno(r
, "Could not set source prefix length: %m");
371 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->to
)) {
372 if (routing_policy_rule
->family
== AF_INET
)
373 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in
);
375 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in6
);
378 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
380 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, routing_policy_rule
->to_prefixlen
);
382 return log_error_errno(r
, "Could not set destination prefix length: %m");
385 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
387 return log_error_errno(r
, "Could not send rtnetlink message: %m");
394 static int routing_policy_rule_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutingPolicyRule
**ret
) {
395 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
396 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
401 assert(!!filename
== (section_line
> 0));
403 r
= network_config_section_new(filename
, section_line
, &n
);
407 rule
= hashmap_get(network
->rules_by_section
, n
);
415 r
= routing_policy_rule_new(&rule
);
420 rule
->network
= network
;
423 r
= hashmap_put(network
->rules_by_section
, rule
->section
, rule
);
427 LIST_APPEND(rules
, network
->rules
, rule
);
436 int link_routing_policy_rule_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
437 _cleanup_link_unref_ Link
*link
= userdata
;
443 assert(link
->ifname
);
444 assert(link
->routing_policy_rule_messages
> 0);
446 link
->routing_policy_rule_messages
--;
448 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
451 r
= sd_netlink_message_get_errno(m
);
452 if (r
< 0 && r
!= -EEXIST
)
453 log_link_warning_errno(link
, r
, "Could not add routing policy rule: %m");
455 if (link
->routing_policy_rule_messages
== 0) {
456 log_link_debug(link
, "Routing policy rule configured");
457 link
->routing_policy_rules_configured
= true;
458 link_check_ready(link
);
464 int routing_policy_rule_configure(RoutingPolicyRule
*rule
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
465 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
470 assert(link
->ifindex
> 0);
471 assert(link
->manager
);
472 assert(link
->manager
->rtnl
);
474 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_NEWRULE
, rule
->family
);
476 return log_error_errno(r
, "Could not allocate RTM_NEWRULE message: %m");
478 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
479 if (rule
->family
== AF_INET
)
480 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &rule
->from
.in
);
482 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &rule
->from
.in6
);
485 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
487 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, rule
->from_prefixlen
);
489 return log_error_errno(r
, "Could not set source prefix length: %m");
492 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
493 if (rule
->family
== AF_INET
)
494 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &rule
->to
.in
);
496 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &rule
->to
.in6
);
499 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
501 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, rule
->to_prefixlen
);
503 return log_error_errno(r
, "Could not set destination prefix length: %m");
506 r
= sd_netlink_message_append_u32(m
, FRA_PRIORITY
, rule
->priority
);
508 return log_error_errno(r
, "Could not append FRA_PRIORITY attribute: %m");
511 r
= sd_rtnl_message_routing_policy_rule_set_tos(m
, rule
->tos
);
513 return log_error_errno(r
, "Could not set ip rule tos: %m");
516 if (rule
->table
< 256) {
517 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, rule
->table
);
519 return log_error_errno(r
, "Could not set ip rule table: %m");
521 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, RT_TABLE_UNSPEC
);
523 return log_error_errno(r
, "Could not set ip rule table: %m");
525 r
= sd_netlink_message_append_u32(m
, FRA_TABLE
, rule
->table
);
527 return log_error_errno(r
, "Could not append FRA_TABLE attribute: %m");
530 if (rule
->fwmark
> 0) {
531 r
= sd_netlink_message_append_u32(m
, FRA_FWMARK
, rule
->fwmark
);
533 return log_error_errno(r
, "Could not append FRA_FWMARK attribute: %m");
536 if (rule
->fwmask
> 0) {
537 r
= sd_netlink_message_append_u32(m
, FRA_FWMASK
, rule
->fwmask
);
539 return log_error_errno(r
, "Could not append FRA_FWMASK attribute: %m");
543 r
= sd_netlink_message_append_string(m
, FRA_IFNAME
, rule
->iif
);
545 return log_error_errno(r
, "Could not append FRA_IFNAME attribute: %m");
549 r
= sd_netlink_message_append_string(m
, FRA_OIFNAME
, rule
->oif
);
551 return log_error_errno(r
, "Could not append FRA_OIFNAME attribute: %m");
556 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
558 return log_error_errno(r
, "Could not send rtnetlink message: %m");
562 r
= routing_policy_rule_add(link
->manager
, rule
->family
, &rule
->from
, rule
->from_prefixlen
, &rule
->to
,
563 rule
->to_prefixlen
, rule
->tos
, rule
->fwmark
, rule
->table
, rule
->iif
, rule
->oif
, NULL
);
565 return log_error_errno(r
, "Could not add rule : %m");
570 static int parse_fwmark_fwmask(const char *s
, uint32_t *fwmark
, uint32_t *fwmask
) {
571 _cleanup_free_
char *f
= NULL
;
585 r
= safe_atou32(f
, fwmark
);
587 return log_error_errno(r
, "Failed to parse RPDB rule firewall mark, ignoring: %s", f
);
590 r
= safe_atou32(p
, fwmask
);
592 return log_error_errno(r
, "Failed to parse RPDB rule mask, ignoring: %s", f
);
598 int config_parse_routing_policy_rule_tos(
600 const char *filename
,
603 unsigned section_line
,
610 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
611 Network
*network
= userdata
;
620 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
624 r
= safe_atou8(rvalue
, &n
->tos
);
626 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule tos, ignoring: %s", rvalue
);
635 int config_parse_routing_policy_rule_priority(
637 const char *filename
,
640 unsigned section_line
,
647 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
648 Network
*network
= userdata
;
657 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
661 r
= safe_atou32(rvalue
, &n
->priority
);
663 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule priority, ignoring: %s", rvalue
);
672 int config_parse_routing_policy_rule_table(
674 const char *filename
,
677 unsigned section_line
,
684 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
685 Network
*network
= userdata
;
694 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
698 r
= safe_atou32(rvalue
, &n
->table
);
700 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule table, ignoring: %s", rvalue
);
709 int config_parse_routing_policy_rule_fwmark_mask(
711 const char *filename
,
714 unsigned section_line
,
721 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
722 Network
*network
= userdata
;
731 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
735 r
= parse_fwmark_fwmask(rvalue
, &n
->fwmark
, &n
->fwmask
);
737 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue
);
746 int config_parse_routing_policy_rule_prefix(
748 const char *filename
,
751 unsigned section_line
,
758 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
759 Network
*network
= userdata
;
760 union in_addr_union buffer
;
770 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
774 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &buffer
, &prefixlen
);
776 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &buffer
, &prefixlen
);
778 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue
);
782 n
->family
= AF_INET6
;
786 if (streq(lvalue
, "To")) {
788 n
->to_prefixlen
= prefixlen
;
791 n
->from_prefixlen
= prefixlen
;
799 int config_parse_routing_policy_rule_device(
801 const char *filename
,
804 unsigned section_line
,
811 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
812 Network
*network
= userdata
;
821 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
825 if (!ifname_valid(rvalue
)) {
826 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse '%s' interface name, ignoring: %s", lvalue
, rvalue
);
830 if (streq(lvalue
, "IncomingInterface")) {
831 r
= free_and_strdup(&n
->iif
, rvalue
);
835 r
= free_and_strdup(&n
->oif
, rvalue
);
845 static int routing_policy_rule_read_full_file(const char *state_file
, char **ret
) {
846 _cleanup_free_
char *s
= NULL
;
852 r
= read_full_file(state_file
, &s
, &size
);
866 int routing_policy_serialize_rules(Set
*rules
, FILE *f
) {
867 RoutingPolicyRule
*rule
= NULL
;
873 SET_FOREACH(rule
, rules
, i
) {
874 _cleanup_free_
char *from_str
= NULL
, *to_str
= NULL
;
879 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
880 r
= in_addr_to_string(rule
->family
, &rule
->from
, &from_str
);
884 fprintf(f
, "from=%s/%hhu",
885 from_str
, rule
->from_prefixlen
);
889 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
890 r
= in_addr_to_string(rule
->family
, &rule
->to
, &to_str
);
894 fprintf(f
, "%sto=%s/%hhu",
896 to_str
, rule
->to_prefixlen
);
900 if (rule
->tos
!= 0) {
901 fprintf(f
, "%stos=%hhu",
907 if (rule
->fwmark
!= 0) {
908 fprintf(f
, "%sfwmark=%"PRIu32
"/%"PRIu32
,
910 rule
->fwmark
, rule
->fwmask
);
915 fprintf(f
, "%siif=%s",
922 fprintf(f
, "%soif=%s",
928 fprintf(f
, "%stable=%"PRIu32
"\n",
936 int routing_policy_load_rules(const char *state_file
, Set
**rules
) {
937 _cleanup_strv_free_
char **l
= NULL
;
938 _cleanup_free_
char *data
= NULL
;
946 r
= routing_policy_rule_read_full_file(state_file
, &data
);
950 l
= strv_split_newlines(data
);
954 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
959 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
961 p
= startswith(*i
, "RULE=");
965 r
= routing_policy_rule_new(&rule
);
970 _cleanup_free_
char *word
= NULL
, *a
= NULL
, *b
= NULL
;
971 union in_addr_union buffer
;
974 r
= extract_first_word(&p
, &word
, NULL
, 0);
980 r
= split_pair(word
, "=", &a
, &b
);
984 if (STR_IN_SET(a
, "from", "to")) {
986 r
= in_addr_prefix_from_string(b
, AF_INET
, &buffer
, &prefixlen
);
988 r
= in_addr_prefix_from_string(b
, AF_INET6
, &buffer
, &prefixlen
);
990 log_error_errno(r
, "RPDB rule prefix is invalid, ignoring assignment: %s", b
);
994 rule
->family
= AF_INET6
;
996 rule
->family
= AF_INET
;
998 if (streq(a
, "to")) {
1000 rule
->to_prefixlen
= prefixlen
;
1002 rule
->from
= buffer
;
1003 rule
->from_prefixlen
= prefixlen
;
1005 } else if (streq(a
, "tos")) {
1006 r
= safe_atou8(b
, &rule
->tos
);
1008 log_error_errno(r
, "Failed to parse RPDB rule tos, ignoring: %s", b
);
1011 } else if (streq(a
, "table")) {
1012 r
= safe_atou32(b
, &rule
->table
);
1014 log_error_errno(r
, "Failed to parse RPDB rule table, ignoring: %s", b
);
1017 } else if (streq(a
, "fwmark")) {
1019 r
= parse_fwmark_fwmask(b
, &rule
->fwmark
, &rule
->fwmask
);
1021 log_error_errno(r
, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a
);
1024 } else if (streq(a
, "iif")) {
1026 if (free_and_strdup(&rule
->iif
, b
) < 0)
1029 } else if (streq(a
, "oif")) {
1031 if (free_and_strdup(&rule
->oif
, b
) < 0)
1036 r
= set_put(*rules
, rule
);
1038 log_warning_errno(r
, "Failed to add RPDB rule to saved DB, ignoring: %s", p
);
1048 void routing_policy_rule_purge(Manager
*m
, Link
*link
) {
1049 RoutingPolicyRule
*rule
, *existing
;
1056 SET_FOREACH(rule
, m
->rules_saved
, i
) {
1057 existing
= set_get(m
->rules_foreign
, rule
);
1060 r
= routing_policy_rule_remove(rule
, link
, routing_policy_rule_remove_handler
);
1062 log_warning_errno(r
, "Could not remove routing policy rules: %m");
1066 link
->routing_policy_rule_remove_messages
++;