2 This file is part of systemd.
4 Copyright 2017 Susant Sahani
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/fib_rules.h>
23 #include "alloc-util.h"
24 #include "conf-parser.h"
26 #include "networkd-routing-policy-rule.h"
27 #include "netlink-util.h"
28 #include "networkd-manager.h"
29 #include "parse-util.h"
30 #include "socket-util.h"
31 #include "string-util.h"
33 int routing_policy_rule_new(RoutingPolicyRule
**ret
) {
34 RoutingPolicyRule
*rule
;
36 rule
= new0(RoutingPolicyRule
, 1);
40 rule
->family
= AF_INET
;
41 rule
->table
= RT_TABLE_MAIN
;
47 void routing_policy_rule_free(RoutingPolicyRule
*rule
) {
53 LIST_REMOVE(rules
, rule
->network
->rules
, rule
);
54 assert(rule
->network
->n_rules
> 0);
55 rule
->network
->n_rules
--;
58 hashmap_remove(rule
->network
->rules_by_section
, rule
->section
);
59 network_config_section_free(rule
->section
);
62 if (rule
->network
->manager
) {
63 set_remove(rule
->network
->manager
->rules
, rule
);
64 set_remove(rule
->network
->manager
->rules_foreign
, rule
);
71 static void routing_policy_rule_hash_func(const void *b
, struct siphash
*state
) {
72 const RoutingPolicyRule
*rule
= b
;
76 siphash24_compress(&rule
->family
, sizeof(rule
->family
), state
);
78 switch (rule
->family
) {
82 siphash24_compress(&rule
->from
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
83 siphash24_compress(&rule
->from_prefixlen
, sizeof(rule
->from_prefixlen
), state
);
85 siphash24_compress(&rule
->to
, FAMILY_ADDRESS_SIZE(rule
->family
), state
);
86 siphash24_compress(&rule
->to_prefixlen
, sizeof(rule
->to_prefixlen
), state
);
88 siphash24_compress(&rule
->tos
, sizeof(rule
->tos
), state
);
89 siphash24_compress(&rule
->fwmark
, sizeof(rule
->fwmark
), state
);
90 siphash24_compress(&rule
->table
, sizeof(rule
->table
), state
);
94 /* treat any other address family as AF_UNSPEC */
99 static int routing_policy_rule_compare_func(const void *_a
, const void *_b
) {
100 const RoutingPolicyRule
*a
= _a
, *b
= _b
;
103 if (a
->family
< b
->family
)
105 if (a
->family
> b
->family
)
111 if (a
->from_prefixlen
< b
->from_prefixlen
)
113 if (a
->from_prefixlen
> b
->from_prefixlen
)
116 if (a
->to_prefixlen
< b
->to_prefixlen
)
118 if (a
->to_prefixlen
> b
->to_prefixlen
)
126 if (a
->fwmask
< b
->fwmark
)
128 if (a
->fwmask
> b
->fwmark
)
131 if (a
->table
< b
->table
)
133 if (a
->table
> b
->table
)
136 r
= memcmp(&a
->from
, &b
->from
, FAMILY_ADDRESS_SIZE(a
->family
));
140 return memcmp(&a
->to
, &b
->to
, FAMILY_ADDRESS_SIZE(a
->family
));
143 /* treat any other address family as AF_UNSPEC */
148 const struct hash_ops routing_policy_rule_hash_ops
= {
149 .hash
= routing_policy_rule_hash_func
,
150 .compare
= routing_policy_rule_compare_func
153 int routing_policy_rule_get(Manager
*m
,
155 const union in_addr_union
*from
,
156 uint8_t from_prefixlen
,
157 const union in_addr_union
*to
,
158 uint8_t to_prefixlen
,
162 RoutingPolicyRule
**ret
) {
164 RoutingPolicyRule rule
, *existing
;
166 assert_return(m
, -1);
168 rule
= (RoutingPolicyRule
) {
171 .from_prefixlen
= from_prefixlen
,
173 .to_prefixlen
= to_prefixlen
,
180 existing
= set_get(m
->rules
, &rule
);
188 if (m
->rules_foreign
) {
189 existing
= set_get(m
->rules_foreign
, &rule
);
200 int routing_policy_rule_make_local(Manager
*m
, RoutingPolicyRule
*rule
) {
205 if (set_contains(m
->rules_foreign
, rule
)) {
206 set_remove(m
->rules_foreign
, rule
);
208 r
= set_ensure_allocated(&m
->rules
, &routing_policy_rule_hash_ops
);
212 return set_put(m
->rules
, rule
);
218 static int routing_policy_rule_add_internal(Set
**rules
,
220 const union in_addr_union
*from
,
221 uint8_t from_prefixlen
,
222 const union in_addr_union
*to
,
223 uint8_t to_prefixlen
,
227 RoutingPolicyRule
**ret
) {
229 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
232 assert_return(rules
, -EINVAL
);
234 r
= routing_policy_rule_new(&rule
);
238 rule
->family
= family
;
240 rule
->from_prefixlen
= from_prefixlen
;
242 rule
->to_prefixlen
= to_prefixlen
;
244 rule
->fwmark
= fwmark
;
247 r
= set_ensure_allocated(rules
, &routing_policy_rule_hash_ops
);
251 r
= set_put(*rules
, rule
);
263 int routing_policy_rule_add(Manager
*m
,
265 const union in_addr_union
*from
,
266 uint8_t from_prefixlen
,
267 const union in_addr_union
*to
,
268 uint8_t to_prefixlen
,
272 RoutingPolicyRule
**ret
) {
274 return routing_policy_rule_add_internal(&m
->rules
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, ret
);
277 int routing_policy_rule_add_foreign(Manager
*m
,
279 const union in_addr_union
*from
,
280 uint8_t from_prefixlen
,
281 const union in_addr_union
*to
,
282 uint8_t to_prefixlen
,
286 RoutingPolicyRule
**ret
) {
287 return routing_policy_rule_add_internal(&m
->rules_foreign
, family
, from
, from_prefixlen
, to
, to_prefixlen
, tos
, fwmark
, table
, ret
);
290 static int routing_policy_rule_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
291 _cleanup_link_unref_ Link
*link
= userdata
;
296 assert(link
->ifname
);
298 link
->link_messages
--;
300 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
303 r
= sd_netlink_message_get_errno(m
);
305 log_link_warning_errno(link
, r
, "Could not drop routing policy rule: %m");
310 int routing_policy_rule_remove(RoutingPolicyRule
*routing_policy_rule
, Link
*link
, sd_netlink_message_handler_t callback
) {
311 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
314 assert(routing_policy_rule
);
316 assert(link
->manager
);
317 assert(link
->manager
->rtnl
);
318 assert(link
->ifindex
> 0);
319 assert(IN_SET(routing_policy_rule
->family
, AF_INET
, AF_INET6
));
321 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_DELRULE
, routing_policy_rule
->family
);
323 return log_error_errno(r
, "Could not allocate RTM_DELRULE message: %m");
325 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->from
)) {
326 if (routing_policy_rule
->family
== AF_INET
)
327 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in
);
329 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &routing_policy_rule
->from
.in6
);
332 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
334 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, routing_policy_rule
->from_prefixlen
);
336 return log_error_errno(r
, "Could not set source prefix length: %m");
339 if (!in_addr_is_null(routing_policy_rule
->family
, &routing_policy_rule
->to
)) {
340 if (routing_policy_rule
->family
== AF_INET
)
341 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in
);
343 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &routing_policy_rule
->to
.in6
);
346 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
348 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, routing_policy_rule
->to_prefixlen
);
350 return log_error_errno(r
, "Could not set destination prefix length: %m");
353 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
355 return log_error_errno(r
, "Could not send rtnetlink message: %m");
362 static int routing_policy_rule_new_static(Network
*network
, const char *filename
, unsigned section_line
, RoutingPolicyRule
**ret
) {
363 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*rule
= NULL
;
364 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
369 assert(!!filename
== (section_line
> 0));
371 r
= network_config_section_new(filename
, section_line
, &n
);
375 rule
= hashmap_get(network
->rules_by_section
, n
);
383 r
= routing_policy_rule_new(&rule
);
388 rule
->network
= network
;
391 r
= hashmap_put(network
->rules_by_section
, rule
->section
, rule
);
395 LIST_APPEND(rules
, network
->rules
, rule
);
404 int link_routing_policy_rule_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
405 _cleanup_link_unref_ Link
*link
= userdata
;
411 assert(link
->ifname
);
412 assert(link
->link_messages
> 0);
414 link
->link_messages
--;
416 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
419 r
= sd_netlink_message_get_errno(m
);
420 if (r
< 0 && r
!= -EEXIST
)
421 log_link_warning_errno(link
, r
, "Could not add routing policy rule: %m");
423 if (link
->link_messages
== 0)
424 log_link_debug(link
, "Routing policy rule configured");
429 int routing_policy_rule_configure(RoutingPolicyRule
*rule
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
430 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
435 assert(link
->ifindex
> 0);
436 assert(link
->manager
);
437 assert(link
->manager
->rtnl
);
439 r
= sd_rtnl_message_new_routing_policy_rule(link
->manager
->rtnl
, &m
, RTM_NEWRULE
, rule
->family
);
441 return log_error_errno(r
, "Could not allocate RTM_NEWRULE message: %m");
443 if (!in_addr_is_null(rule
->family
, &rule
->from
)) {
444 if (rule
->family
== AF_INET
)
445 r
= sd_netlink_message_append_in_addr(m
, FRA_SRC
, &rule
->from
.in
);
447 r
= sd_netlink_message_append_in6_addr(m
, FRA_SRC
, &rule
->from
.in6
);
450 return log_error_errno(r
, "Could not append FRA_SRC attribute: %m");
452 r
= sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m
, rule
->from_prefixlen
);
454 return log_error_errno(r
, "Could not set source prefix length: %m");
457 if (!in_addr_is_null(rule
->family
, &rule
->to
)) {
458 if (rule
->family
== AF_INET
)
459 r
= sd_netlink_message_append_in_addr(m
, FRA_DST
, &rule
->to
.in
);
461 r
= sd_netlink_message_append_in6_addr(m
, FRA_DST
, &rule
->to
.in6
);
464 return log_error_errno(r
, "Could not append FRA_DST attribute: %m");
466 r
= sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m
, rule
->to_prefixlen
);
468 return log_error_errno(r
, "Could not set destination prefix length: %m");
471 r
= sd_netlink_message_append_u32(m
, FRA_PRIORITY
, rule
->priority
);
473 return log_error_errno(r
, "Could not append FRA_PRIORITY attribute: %m");
476 r
= sd_rtnl_message_routing_policy_rule_set_tos(m
, rule
->tos
);
478 return log_error_errno(r
, "Could not set ip rule tos: %m");
481 if (rule
->table
< 256) {
482 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, rule
->table
);
484 return log_error_errno(r
, "Could not set ip rule table: %m");
486 r
= sd_rtnl_message_routing_policy_rule_set_table(m
, RT_TABLE_UNSPEC
);
488 return log_error_errno(r
, "Could not set ip rule table: %m");
490 r
= sd_netlink_message_append_u32(m
, FRA_TABLE
, rule
->table
);
492 return log_error_errno(r
, "Could not append FRA_TABLE attribute: %m");
495 if (rule
->fwmark
> 0) {
496 r
= sd_netlink_message_append_u32(m
, FRA_FWMARK
, rule
->fwmark
);
498 return log_error_errno(r
, "Could not append FRA_FWMARK attribute: %m");
501 if (rule
->fwmask
> 0) {
502 r
= sd_netlink_message_append_u32(m
, FRA_FWMASK
, rule
->fwmask
);
504 return log_error_errno(r
, "Could not append FRA_FWMASK attribute: %m");
509 r
= sd_netlink_call_async(link
->manager
->rtnl
, m
, callback
, link
, 0, NULL
);
511 return log_error_errno(r
, "Could not send rtnetlink message: %m");
515 r
= routing_policy_rule_add(link
->manager
, rule
->family
, &rule
->from
, rule
->from_prefixlen
, &rule
->to
,
516 rule
->to_prefixlen
, rule
->tos
, rule
->fwmark
, rule
->table
, NULL
);
518 return log_error_errno(r
, "Could not add rule : %m");
523 static int parse_fwmark_fwmask(const char *s
, uint32_t *fwmark
, uint32_t *fwmask
) {
524 _cleanup_free_
char *f
= NULL
;
538 r
= safe_atou32(f
, fwmark
);
540 return log_error_errno(r
, "Failed to parse RPDB rule firewall mark, ignoring: %s", f
);
543 r
= safe_atou32(p
, fwmask
);
545 return log_error_errno(r
, "Failed to parse RPDB rule mask, ignoring: %s", f
);
551 int config_parse_routing_policy_rule_tos(
553 const char *filename
,
556 unsigned section_line
,
563 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
564 Network
*network
= userdata
;
573 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
577 r
= safe_atou8(rvalue
, &n
->tos
);
579 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule tos, ignoring: %s", rvalue
);
588 int config_parse_routing_policy_rule_priority(
590 const char *filename
,
593 unsigned section_line
,
600 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
601 Network
*network
= userdata
;
610 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
614 r
= safe_atou32(rvalue
, &n
->priority
);
616 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule priority, ignoring: %s", rvalue
);
625 int config_parse_routing_policy_rule_table(
627 const char *filename
,
630 unsigned section_line
,
637 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
638 Network
*network
= userdata
;
647 r
= routing_policy_rule_new_static(network
, filename
, section_line
, &n
);
651 r
= safe_atou32(rvalue
, &n
->table
);
653 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse RPDB rule table, ignoring: %s", rvalue
);
662 int config_parse_routing_policy_rule_fwmark_mask(
664 const char *filename
,
667 unsigned section_line
,
674 _cleanup_routing_policy_rule_free_ RoutingPolicyRule
*n
= NULL
;
675 _cleanup_free_
char *fwmark
= 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
, *p
= 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
++;