From 1e5fd3216a8c73b636ad61e6ebee0c161b6c2063 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 28 Oct 2020 16:54:51 +0900 Subject: [PATCH 1/5] network: set FRA_PROTOCOL to RTPROT_STATIC by default --- src/network/networkd-routing-policy-rule.c | 36 +++++++++++++++------ src/network/networkd-routing-policy-rule.h | 3 +- test/test-network/systemd-networkd-tests.py | 2 +- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 8c9565bda9..4ede16e581 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -66,6 +66,7 @@ static int routing_policy_rule_new(RoutingPolicyRule **ret) { .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, + .protocol = RTPROT_UNSPEC, .type = FR_ACT_TO_TBL, }; @@ -99,6 +100,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename rule->network = network; rule->section = TAKE_PTR(n); + rule->protocol = RTPROT_STATIC; r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops); if (r < 0) @@ -144,6 +146,7 @@ static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule * dest->table = src->table; dest->iif = TAKE_PTR(iif); dest->oif = TAKE_PTR(oif); + dest->ipproto = src->ipproto; dest->protocol = src->protocol; dest->sport = src->sport; dest->dport = src->dport; @@ -177,6 +180,7 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash24_compress(&rule->table, sizeof(rule->table), state); siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state); + siphash24_compress(&rule->ipproto, sizeof(rule->ipproto), state); siphash24_compress(&rule->protocol, sizeof(rule->protocol), state); siphash24_compress(&rule->sport, sizeof(rule->sport), state); siphash24_compress(&rule->dport, sizeof(rule->dport), state); @@ -250,6 +254,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro if (r != 0) return r; + r = CMP(a->ipproto, b->ipproto); + if (r != 0) + return r; + r = CMP(a->protocol, b->protocol); if (r != 0) return r; @@ -458,10 +466,14 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m"); } - r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol); + r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->ipproto); if (r < 0) return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m"); + r = sd_netlink_message_append_u8(m, FRA_PROTOCOL, rule->protocol); + if (r < 0) + return log_link_error_errno(link, r, "Could not append FRA_PROTOCOL attribute: %m"); + if (rule->sport.start != 0 || rule->sport.end != 0) { r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport)); if (r < 0) @@ -852,12 +864,18 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man if (r < 0) return log_oom(); - r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol); + r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->ipproto); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m"); return 0; } + r = sd_netlink_message_read_u8(message, FRA_PROTOCOL, &tmp->protocol); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_PROTOCOL attribute, ignoring: %m"); + return 0; + } + r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m"); @@ -1271,7 +1289,7 @@ int config_parse_routing_policy_rule_ip_protocol( return 0; } - n->protocol = r; + n->ipproto = r; n = NULL; @@ -1599,10 +1617,10 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) { space = true; } - if (rule->protocol != 0) { - fprintf(f, "%sprotocol=%hhu", + if (rule->ipproto != 0) { + fprintf(f, "%sipproto=%hhu", space ? " " : "", - rule->protocol); + rule->ipproto); space = true; } @@ -1777,10 +1795,10 @@ int routing_policy_load_rules(const char *state_file, Set **rules) { if (free_and_strdup(&rule->oif, b) < 0) return log_oom(); - } else if (streq(a, "protocol")) { - r = safe_atou8(b, &rule->protocol); + } else if (streq(a, "ipproto")) { + r = safe_atou8(b, &rule->ipproto); if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b); + log_warning_errno(r, "Failed to parse RPDB rule IP protocol, ignoring: %s", b); continue; } } else if (streq(a, "sourceport")) { diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 1b574452e2..3786eee34b 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -24,7 +24,8 @@ typedef struct RoutingPolicyRule { uint8_t tos; uint8_t type; - uint8_t protocol; + uint8_t ipproto; /* FRA_IP_PROTO */ + uint8_t protocol; /* FRA_PROTOCOL */ uint8_t to_prefixlen; uint8_t from_prefixlen; diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 1c4046d4f2..41d3e7036b 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -3326,7 +3326,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): output = check_output('ip rule list table 100') print(output) - self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100') + self.assertIn('0: from all to 8.8.8.8 lookup 100', output) class NetworkdLLDPTests(unittest.TestCase, Utilities): links = ['veth99'] From 569eeb0c059047601f16b9f6df2bbbc1582793a1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 29 Oct 2020 11:34:36 +0900 Subject: [PATCH 2/5] network: adjust protocol of rules sent from kernel when kernel does not support FRA_PROTOCOL Otherwise, each configured rule is treated as foreign. --- src/network/networkd-routing-policy-rule.c | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 4ede16e581..43f69851c5 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -735,10 +735,29 @@ int link_set_routing_policy_rules(Link *link) { return 0; } +static const RoutingPolicyRule kernel_rules[] = { + { .family = AF_INET, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET, .priority = 32767, .table = RT_TABLE_DEFAULT, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET6, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET6, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, +}; + +static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) { + assert(rule); + + for (size_t i = 0; i < ELEMENTSOF(kernel_rules); i++) + if (routing_policy_rule_equal(rule, &kernel_rules[i])) + return true; + + return false; +} + int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL; RoutingPolicyRule *rule = NULL; const char *iif = NULL, *oif = NULL; + bool adjust_protocol = false; uint32_t suppress_prefixlen; unsigned flags; uint16_t type; @@ -871,7 +890,12 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man } r = sd_netlink_message_read_u8(message, FRA_PROTOCOL, &tmp->protocol); - if (r < 0 && r != -ENODATA) { + if (r == -ENODATA) + /* If FRA_PROTOCOL is supported by kernel, then the attribute is always appended. + * When the received message does not have FRA_PROTOCOL, then we need to adjust the + * protocol of the rule later. */ + adjust_protocol = true; + else if (r < 0) { log_warning_errno(r, "rtnl: could not get FRA_PROTOCOL attribute, ignoring: %m"); return 0; } @@ -902,6 +926,11 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man if (r >= 0) tmp->suppress_prefixlen = (int) suppress_prefixlen; + if (adjust_protocol) + /* As .network files does not have setting to specify protocol, we can assume the + * protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */ + tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC; + (void) routing_policy_rule_get(m, tmp, &rule); switch (type) { From e737dce5445ac2359f4f260aa462056b02d68d54 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 29 Oct 2020 11:55:12 +0900 Subject: [PATCH 3/5] network: treat rule which has l3mdev flag as created by kernel --- src/network/networkd-routing-policy-rule.c | 17 +++++++++++++++++ src/network/networkd-routing-policy-rule.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 43f69851c5..6ad22bd5c8 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -746,6 +746,11 @@ static const RoutingPolicyRule kernel_rules[] = { static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) { assert(rule); + if (rule->l3mdev > 0) + /* Currently, [RoutingPolicyRule] does not explicitly set FRA_L3MDEV. So, if the flag + * is set, it is safe to treat the rule as created by kernel. */ + return true; + for (size_t i = 0; i < ELEMENTSOF(kernel_rules); i++) if (routing_policy_rule_equal(rule, &kernel_rules[i])) return true; @@ -900,6 +905,12 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man return 0; } + r = sd_netlink_message_read_u8(message, FRA_L3MDEV, &tmp->l3mdev); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_L3MDEV attribute, ignoring: %m"); + return 0; + } + r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m"); @@ -1544,6 +1555,12 @@ static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) { if (rule->family == AF_UNSPEC && rule->address_family == ADDRESS_FAMILY_NO) rule->family = AF_INET; + /* Currently, [RoutingPolicyRule] does not have a setting to set FRA_L3MDEV flag. Please also + * update routing_policy_rule_is_created_by_kernel() when a new setting which sets the flag is + * added in the future. */ + if (rule->l3mdev > 0) + assert_not_reached("FRA_L3MDEV flag should not be configured."); + return 0; } diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 3786eee34b..ded312b73e 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -28,6 +28,7 @@ typedef struct RoutingPolicyRule { uint8_t protocol; /* FRA_PROTOCOL */ uint8_t to_prefixlen; uint8_t from_prefixlen; + uint8_t l3mdev; /* FRA_L3MDEV */ uint32_t table; uint32_t fwmark; From 0b81225e5791f660506f7db0ab88078cf296b771 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 28 Oct 2020 20:27:23 +0900 Subject: [PATCH 4/5] network: drop unnecessary routing policy rules networkd already drop foreign address, routes, and nexthops on startup, except those created by kernel. However, previously, routing policy rules were not. The logic of serialization/deserialization of rules only works for rules created by previous invocation of networkd, and does not work for one created by other tools like `ip rule`. This makes networkd drop foreign routing policy rules except created by kernel on startup. Also, remove rules created by networkd when the corresponding links are dropped or networkd is stopping. --- src/network/networkd-link.c | 48 ++++++++++++++-------- src/network/networkd-routing-policy-rule.c | 32 ++++++++++++++- src/network/networkd-routing-policy-rule.h | 7 ++++ 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 7675f266e5..56ae6939a3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1973,37 +1973,51 @@ static int link_enter_join_netdev(Link *link) { } static int link_drop_foreign_config(Link *link) { - int r; + int k, r; + + assert(link); + assert(link->manager); r = link_drop_foreign_addresses(link); - if (r < 0) - return r; - r = link_drop_foreign_neighbors(link); - if (r < 0) - return r; + k = link_drop_foreign_neighbors(link); + if (k < 0 && r >= 0) + r = k; - return link_drop_foreign_routes(link); + k = link_drop_foreign_routes(link); + if (k < 0 && r >= 0) + r = k; + + k = manager_drop_foreign_routing_policy_rules(link->manager); + if (k < 0 && r >= 0) + r = k; + + return r; } static int link_drop_config(Link *link) { - int r; + int k, r; + + assert(link); + assert(link->manager); r = link_drop_addresses(link); - if (r < 0) - return r; - r = link_drop_neighbors(link); - if (r < 0) - return r; + k = link_drop_neighbors(link); + if (k < 0 && r >= 0) + r = k; - r = link_drop_routes(link); - if (r < 0) - return r; + k = link_drop_routes(link); + if (k < 0 && r >= 0) + r = k; + + k = manager_drop_routing_policy_rules(link->manager, link); + if (k < 0 && r >= 0) + r = k; ndisc_flush(link); - return 0; + return r; } int link_configure(Link *link) { diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 6ad22bd5c8..3f6469442e 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -640,7 +640,7 @@ static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link) { return 0; } -static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) { +static bool links_have_routing_policy_rule(const Manager *m, const RoutingPolicyRule *rule, const Link *except) { Link *link; assert(m); @@ -649,6 +649,9 @@ static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule HASHMAP_FOREACH(link, m->links) { RoutingPolicyRule *link_rule; + if (link == except) + continue; + if (!link->network) continue; @@ -660,6 +663,31 @@ static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule return false; } +int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) { + RoutingPolicyRule *rule; + int k, r = 0; + Set *rules; + + assert(m); + + rules = foreign ? m->rules_foreign : m->rules; + SET_FOREACH(rule, rules) { + /* Do not touch rules managed by kernel. */ + if (rule->protocol == RTPROT_KERNEL) + continue; + + /* The rule will be configured later, or already configured by a link. */ + if (links_have_routing_policy_rule(m, rule, except)) + continue; + + k = routing_policy_rule_remove(rule, m); + if (k < 0 && r >= 0) + r = k; + } + + return r; +} + static void routing_policy_rule_purge(Manager *m) { RoutingPolicyRule *rule; int r; @@ -673,7 +701,7 @@ static void routing_policy_rule_purge(Manager *m) { if (!existing) continue; /* Saved rule does not exist anymore. */ - if (manager_links_have_routing_policy_rule(m, existing)) + if (links_have_routing_policy_rule(m, existing, NULL)) continue; /* Existing links have the saved rule. */ /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index ded312b73e..7b7dd43987 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -58,6 +58,13 @@ void network_drop_invalid_routing_policy_rules(Network *network); int link_set_routing_policy_rules(Link *link); int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); +int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except); +static inline int manager_drop_foreign_routing_policy_rules(Manager *m) { + return manager_drop_routing_policy_rules_internal(m, true, NULL); +} +static inline int manager_drop_routing_policy_rules(Manager *m, const Link *except) { + return manager_drop_routing_policy_rules_internal(m, false, except); +} int routing_policy_serialize_rules(Set *rules, FILE *f); int routing_policy_load_rules(const char *state_file, Set **rules); From a9d240f4bfefcd85de22381f6250e1e1ab58ea55 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 28 Oct 2020 17:02:41 +0900 Subject: [PATCH 5/5] network: do not serialize/deserialize routing policy rules We already handle foreign routing policy rules correctly by the previous commit. So, the serialization/deserialization of rules are not necessary anymore. --- src/network/meson.build | 5 - src/network/networkd-manager.c | 7 - src/network/networkd-manager.h | 1 - src/network/networkd-routing-policy-rule.c | 370 --------------------- src/network/networkd-routing-policy-rule.h | 3 - src/network/test-routing-policy-rule.c | 90 ----- 6 files changed, 476 deletions(-) delete mode 100644 src/network/test-routing-policy-rule.c diff --git a/src/network/meson.build b/src/network/meson.build index 805007782c..5cd7613168 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -273,11 +273,6 @@ if conf.get('ENABLE_NETWORKD') == 1 [threads], '', '', [], network_include_dir], - [['src/network/test-routing-policy-rule.c'], - [libnetworkd_core, - libsystemd_network], - [], '', '', [], network_include_dir], - [['src/network/test-network-tables.c', test_tables_h], [libnetworkd_core, diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 4894d235b0..f775a3398a 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -707,10 +707,6 @@ static int manager_save(Manager *m) { ordered_set_print(f, "DOMAINS=", search_domains); ordered_set_print(f, "ROUTE_DOMAINS=", route_domains); - r = routing_policy_serialize_rules(m->rules, f); - if (r < 0) - goto fail; - r = fflush_and_check(f); if (r < 0) goto fail; @@ -851,8 +847,6 @@ int manager_new(Manager **ret) { m->duid.type = DUID_TYPE_EN; - (void) routing_policy_load_rules(m->state_file, &m->rules_saved); - *ret = TAKE_PTR(m); return 0; @@ -887,7 +881,6 @@ void manager_free(Manager *m) { * So, it is necessary to set NULL after the sets are freed. */ m->rules = set_free(m->rules); m->rules_foreign = set_free(m->rules_foreign); - set_free(m->rules_saved); sd_netlink_unref(m->rtnl); sd_netlink_unref(m->genl); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 25fb080dc9..78ba2b0945 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -60,7 +60,6 @@ struct Manager { Set *rules; Set *rules_foreign; - Set *rules_saved; /* Manager stores routes without RTA_OIF attribute. */ Set *routes; diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 3f6469442e..1f1e3e5b76 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -688,36 +688,6 @@ int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const L return r; } -static void routing_policy_rule_purge(Manager *m) { - RoutingPolicyRule *rule; - int r; - - assert(m); - - SET_FOREACH(rule, m->rules_saved) { - RoutingPolicyRule *existing; - - existing = set_get(m->rules_foreign, rule); - if (!existing) - continue; /* Saved rule does not exist anymore. */ - - if (links_have_routing_policy_rule(m, existing, NULL)) - continue; /* Existing links have the saved rule. */ - - /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it - * later when it is requested. */ - - r = routing_policy_rule_remove(existing, m); - if (r < 0) { - log_warning_errno(r, "Could not remove routing policy rules: %m"); - continue; - } - - assert_se(set_remove(m->rules_foreign, existing) == existing); - routing_policy_rule_free(existing); - } -} - int link_set_routing_policy_rules(Link *link) { RoutingPolicyRule *rule; int r; @@ -752,7 +722,6 @@ int link_set_routing_policy_rules(Link *link) { return log_link_warning_errno(link, r, "Could not set routing policy rule: %m"); } - routing_policy_rule_purge(link->manager); if (link->routing_policy_rule_messages == 0) link->routing_policy_rules_configured = true; else { @@ -1601,342 +1570,3 @@ void network_drop_invalid_routing_policy_rules(Network *network) { if (routing_policy_rule_section_verify(rule) < 0) routing_policy_rule_free(rule); } - -int routing_policy_serialize_rules(Set *rules, FILE *f) { - RoutingPolicyRule *rule; - int r; - - assert(f); - - SET_FOREACH(rule, rules) { - const char *family_str; - bool space = false; - - fputs("RULE=", f); - - family_str = af_to_name(rule->family); - if (family_str) { - fprintf(f, "family=%s", - family_str); - space = true; - } - - if (!in_addr_is_null(rule->family, &rule->from)) { - _cleanup_free_ char *str = NULL; - - r = in_addr_to_string(rule->family, &rule->from, &str); - if (r < 0) - return r; - - fprintf(f, "%sfrom=%s/%hhu", - space ? " " : "", - str, rule->from_prefixlen); - space = true; - } - - if (!in_addr_is_null(rule->family, &rule->to)) { - _cleanup_free_ char *str = NULL; - - r = in_addr_to_string(rule->family, &rule->to, &str); - if (r < 0) - return r; - - fprintf(f, "%sto=%s/%hhu", - space ? " " : "", - str, rule->to_prefixlen); - space = true; - } - - if (rule->tos != 0) { - fprintf(f, "%stos=%hhu", - space ? " " : "", - rule->tos); - space = true; - } - - if (rule->type != 0) { - fprintf(f, "%stype=%hhu", - space ? " " : "", - rule->type); - space = true; - } - - if (rule->priority != 0) { - fprintf(f, "%spriority=%"PRIu32, - space ? " " : "", - rule->priority); - space = true; - } - - if (rule->fwmark != 0) { - fprintf(f, "%sfwmark=%"PRIu32, - space ? " " : "", - rule->fwmark); - if (rule->fwmask != UINT32_MAX) - fprintf(f, "/%"PRIu32, rule->fwmask); - space = true; - } - - if (rule->iif) { - fprintf(f, "%siif=%s", - space ? " " : "", - rule->iif); - space = true; - } - - if (rule->oif) { - fprintf(f, "%soif=%s", - space ? " " : "", - rule->oif); - space = true; - } - - if (rule->ipproto != 0) { - fprintf(f, "%sipproto=%hhu", - space ? " " : "", - rule->ipproto); - space = true; - } - - if (rule->sport.start != 0 || rule->sport.end != 0) { - fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16, - space ? " " : "", - rule->sport.start, rule->sport.end); - space = true; - } - - if (rule->dport.start != 0 || rule->dport.end != 0) { - fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16, - space ? " " : "", - rule->dport.start, rule->dport.end); - space = true; - } - - if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) { - assert_cc(sizeof(uid_t) == sizeof(uint32_t)); - fprintf(f, "%suidrange="UID_FMT"-"UID_FMT, - space ? " " : "", - rule->uid_range.start, rule->uid_range.end); - space = true; - } - - if (rule->suppress_prefixlen >= 0) { - fprintf(f, "%ssuppress_prefixlen=%d", - space ? " " : "", - rule->suppress_prefixlen); - space = true; - } - - fprintf(f, "%sinvert_rule=%s table=%"PRIu32"\n", - space ? " " : "", - yes_no(rule->invert_rule), - rule->table); - } - - return 0; -} - -static int routing_policy_rule_read_full_file(const char *state_file, char ***ret) { - _cleanup_strv_free_ char **lines = NULL; - _cleanup_free_ char *s = NULL; - int r; - - assert(state_file); - - r = read_full_file(state_file, &s, NULL); - if (r == -ENOENT) { - *ret = NULL; - return 0; - } - if (r < 0) - return r; - - lines = strv_split_newlines(s); - if (!lines) - return -ENOMEM; - - *ret = TAKE_PTR(lines); - return 0; -} - -int routing_policy_load_rules(const char *state_file, Set **rules) { - _cleanup_strv_free_ char **data = NULL; - char **i; - int r; - - assert(state_file); - assert(rules); - - r = routing_policy_rule_read_full_file(state_file, &data); - if (r < 0) - return log_warning_errno(r, "Failed to read %s, ignoring: %m", state_file); - - STRV_FOREACH(i, data) { - _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL; - const char *p; - - p = startswith(*i, "RULE="); - if (!p) - continue; - - r = routing_policy_rule_new(&rule); - if (r < 0) - return log_oom(); - - for (;;) { - _cleanup_free_ char *a = NULL; - char *b; - - r = extract_first_word(&p, &a, NULL, 0); - if (r < 0) - return log_oom(); - if (r == 0) - break; - - b = strchr(a, '='); - if (!b) { - log_warning_errno(r, "Failed to parse RPDB rule, ignoring: %s", a); - continue; - } - *b++ = '\0'; - - if (streq(a, "family")) { - r = af_from_name(b); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b); - continue; - } - if (rule->family != AF_UNSPEC && rule->family != r) { - log_warning("RPDB rule family is already specified, ignoring assignment: %s", b); - continue; - } - rule->family = r; - } else if (STR_IN_SET(a, "from", "to")) { - union in_addr_union *buffer; - uint8_t *prefixlen; - - if (streq(a, "to")) { - buffer = &rule->to; - prefixlen = &rule->to_prefixlen; - } else { - buffer = &rule->from; - prefixlen = &rule->from_prefixlen; - } - - if (rule->family == AF_UNSPEC) - r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen); - else - r = in_addr_prefix_from_string(b, rule->family, buffer, prefixlen); - if (r < 0) { - log_warning_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b); - continue; - } - } else if (streq(a, "tos")) { - r = safe_atou8(b, &rule->tos); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b); - continue; - } - } else if (streq(a, "type")) { - r = safe_atou8(b, &rule->type); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule type, ignoring: %s", b); - continue; - } - } else if (streq(a, "table")) { - r = safe_atou32(b, &rule->table); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b); - continue; - } - } else if (streq(a, "priority")) { - r = safe_atou32(b, &rule->priority); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b); - continue; - } - } else if (streq(a, "fwmark")) { - r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a); - continue; - } - } else if (streq(a, "iif")) { - if (free_and_strdup(&rule->iif, b) < 0) - return log_oom(); - - } else if (streq(a, "oif")) { - - if (free_and_strdup(&rule->oif, b) < 0) - return log_oom(); - } else if (streq(a, "ipproto")) { - r = safe_atou8(b, &rule->ipproto); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule IP protocol, ignoring: %s", b); - continue; - } - } else if (streq(a, "sourceport")) { - uint16_t low, high; - - r = parse_ip_port_range(b, &low, &high); - if (r < 0) { - log_warning_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b); - continue; - } - - rule->sport.start = low; - rule->sport.end = high; - } else if (streq(a, "destinationport")) { - uint16_t low, high; - - r = parse_ip_port_range(b, &low, &high); - if (r < 0) { - log_warning_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b); - continue; - } - - rule->dport.start = low; - rule->dport.end = high; - } else if (streq(a, "uidrange")) { - uid_t lower, upper; - - r = parse_uid_range(b, &lower, &upper); - if (r < 0) { - log_warning_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b); - continue; - } - - rule->uid_range.start = lower; - rule->uid_range.end = upper; - } else if (streq(a, "suppress_prefixlen")) { - r = parse_ip_prefix_length(b, &rule->suppress_prefixlen); - if (r == -ERANGE) { - log_warning_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b); - continue; - } - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b); - continue; - } - } else if (streq(a, "invert_rule")) { - r = parse_boolean(b); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule invert_rule, ignoring: %s", b); - continue; - } - rule->invert_rule = r; - } else - log_warning("Unknown RPDB rule, ignoring: %s", a); - } - - r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule); - if (r < 0) { - log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", *i); - continue; - } - if (r > 0) - rule = NULL; - } - - return 0; -} diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 7b7dd43987..dbda8c51b0 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -66,9 +66,6 @@ static inline int manager_drop_routing_policy_rules(Manager *m, const Link *exce return manager_drop_routing_policy_rules_internal(m, false, except); } -int routing_policy_serialize_rules(Set *rules, FILE *f); -int routing_policy_load_rules(const char *state_file, Set **rules); - CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_fwmark_mask); diff --git a/src/network/test-routing-policy-rule.c b/src/network/test-routing-policy-rule.c deleted file mode 100644 index 4fed4fe8d9..0000000000 --- a/src/network/test-routing-policy-rule.c +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "fd-util.h" -#include "fileio.h" -#include "networkd-routing-policy-rule.h" -#include "string-util.h" -#include "tests.h" -#include "tmpfile-util.h" - -static void test_rule_serialization(const char *title, const char *ruleset, const char *expected) { - char pattern[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX", - pattern2[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX", - pattern3[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX"; - const char *cmd; - int fd, fd2, fd3; - _cleanup_fclose_ FILE *f = NULL, *f2 = NULL, *f3 = NULL; - Set *rules = NULL; - _cleanup_free_ char *buf = NULL; - size_t buf_size; - - log_info("========== %s ==========", title); - log_info("put:\n%s\n", ruleset); - - fd = mkostemp_safe(pattern); - assert_se(fd >= 0); - assert_se(f = fdopen(fd, "a+")); - assert_se(write_string_stream(f, ruleset, 0) == 0); - - assert_se(routing_policy_load_rules(pattern, &rules) == 0); - - fd2 = mkostemp_safe(pattern2); - assert_se(fd2 >= 0); - assert_se(f2 = fdopen(fd2, "a+")); - - assert_se(routing_policy_serialize_rules(rules, f2) == 0); - assert_se(fflush_and_check(f2) == 0); - - assert_se(read_full_file(pattern2, &buf, &buf_size) == 0); - - log_info("got:\n%s", buf); - - fd3 = mkostemp_safe(pattern3); - assert_se(fd3 >= 0); - assert_se(f3 = fdopen(fd3, "w")); - assert_se(write_string_stream(f3, expected ?: ruleset, 0) == 0); - - cmd = strjoina("diff -u ", pattern3, " ", pattern2); - log_info("$ %s", cmd); - assert_se(system(cmd) == 0); - - set_free(rules); -} - -int main(int argc, char **argv) { - _cleanup_free_ char *p = NULL; - - test_setup_logging(LOG_DEBUG); - - test_rule_serialization("basic parsing", - "RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 type=1 priority=10 fwmark=1/2 invert_rule=yes table=10", NULL); - - test_rule_serialization("ignored values", - "RULE=something=to=ignore from=1.2.3.4/32 from=1.2.3.4/32" - " \t to=2.3.4.5/24 to=2.3.4.5/32 tos=5 type=1 fwmark=2 fwmark=1 table=10 table=20", - "RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 type=1 fwmark=1 invert_rule=no table=20"); - - test_rule_serialization("ipv6", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=yes table=6", NULL); - - assert_se(asprintf(&p, "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=no table=%d", RT_TABLE_MAIN) >= 0); - test_rule_serialization("default table", - "RULE=from=1::2/64 to=2::3/64", p); - - test_rule_serialization("incoming interface", - "RULE=from=1::2/64 to=2::3/64 table=1 iif=lo", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 iif=lo invert_rule=no table=1"); - - test_rule_serialization("outgoing interface", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 oif=eth0 invert_rule=no table=1", NULL); - - test_rule_serialization("freeing interface names", - "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 type=1 iif=e0 iif=e1 oif=e0 oif=e1 table=1", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 iif=e1 oif=e1 invert_rule=no table=1"); - - test_rule_serialization("ignoring invalid family", - "RULE=from=1::2/64 to=2::3/64 family=AF_UNSEPC family=AF_INET table=1", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=no table=1"); - - return 0; -}