From 0aabccc87dd054ee21dc0372648200808f69c5c2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 2 Aug 2019 05:07:40 +0900 Subject: [PATCH 1/7] network: refuse the case To= and From= are in different address family --- src/network/networkd-network.c | 2 +- src/network/networkd-routing-policy-rule.c | 16 ++++++++++++++-- src/network/networkd-routing-policy-rule.h | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 9d3c383378..191e766a92 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -281,7 +281,7 @@ int network_verify(Network *network) { prefix_free(prefix); LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules) - if (section_is_invalid(rule->section)) + if (routing_policy_rule_section_verify(rule) < 0) routing_policy_rule_free(rule); return 0; diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 1864a5a376..857b01468f 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -23,7 +23,6 @@ int routing_policy_rule_new(RoutingPolicyRule **ret) { return -ENOMEM; *rule = (RoutingPolicyRule) { - .family = AF_INET, .table = RT_TABLE_MAIN, }; @@ -555,6 +554,16 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl return 1; } +int routing_policy_rule_section_verify(RoutingPolicyRule *rule) { + if (section_is_invalid(rule->section)) + return -EINVAL; + + if (rule->family == AF_UNSPEC) + rule->family = AF_INET; + + return 0; +} + static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) { _cleanup_free_ char *f = NULL; char *p; @@ -767,7 +776,10 @@ int config_parse_routing_policy_rule_prefix( prefixlen = &n->from_prefixlen; } - r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen); + if (n->family == AF_UNSPEC) + r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen); + else + r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue); return 0; diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 512af3dfdd..8ddb85307c 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -56,6 +56,7 @@ int routing_policy_rule_new(RoutingPolicyRule **ret); void routing_policy_rule_free(RoutingPolicyRule *rule); DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free); +int routing_policy_rule_section_verify(RoutingPolicyRule *rule); int routing_policy_rule_configure(RoutingPolicyRule *address, Link *link, link_netlink_message_handler_t callback); int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback); From 43e08c78c7eb1c1f0c0a4c96ba53a19ebb345f10 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 2 Aug 2019 05:19:26 +0900 Subject: [PATCH 2/7] network: serialize/deserialize address family --- src/network/networkd-routing-policy-rule.c | 15 +++++++++++++++ src/network/test-routing-policy-rule.c | 16 ++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 857b01468f..8386d214b8 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -3,6 +3,7 @@ #include #include +#include "af-list.h" #include "alloc-util.h" #include "conf-parser.h" #include "fileio.h" @@ -989,6 +990,7 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) { SET_FOREACH(rule, rules, i) { _cleanup_free_ char *from_str = NULL, *to_str = NULL; bool space = false; + const char *family_str; fputs("RULE=", f); @@ -1013,6 +1015,12 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) { space = true; } + family_str = af_to_name(rule->family); + if (family_str) + fprintf(f, "%sfamily=%s", + space ? " " : "", + family_str); + if (rule->tos != 0) { fprintf(f, "%stos=%hhu", space ? " " : "", @@ -1135,6 +1143,13 @@ int routing_policy_load_rules(const char *state_file, Set **rules) { continue; } + } else if (streq(a, "family")) { + r = af_from_name(b); + if (r < 0) { + log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b); + continue; + } + rule->family = r; } else if (streq(a, "tos")) { r = safe_atou8(b, &rule->tos); if (r < 0) { diff --git a/src/network/test-routing-policy-rule.c b/src/network/test-routing-policy-rule.c index 57bfb6af68..0319b6db09 100644 --- a/src/network/test-routing-policy-rule.c +++ b/src/network/test-routing-policy-rule.c @@ -62,31 +62,31 @@ int main(int argc, char **argv) { test_setup_logging(LOG_DEBUG); test_rule_serialization("basic parsing", - "RULE=from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1/2 table=10", NULL); + "RULE=from=1.2.3.4/32 to=2.3.4.5/32 family=AF_INET tos=5 fwmark=1/2 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 fwmark=2 fwmark=1 table=10 table=20", "RULE=from=1.2.3.4/32" - " to=2.3.4.5/32 tos=5 fwmark=1/0 table=20"); + " to=2.3.4.5/32 family=AF_INET tos=5 fwmark=1/0 table=20"); test_rule_serialization("ipv6", - "RULE=from=1::2/64 to=2::3/64 table=6", NULL); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 table=6", NULL); - assert_se(asprintf(&p, "RULE=from=1::2/64 to=2::3/64 table=%d", RT_TABLE_MAIN) >= 0); + assert_se(asprintf(&p, "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 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=from=1::2/64 to=2::3/64 iif=lo table=1"); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=lo table=1"); test_rule_serialization("outgoing interface", - "RULE=from=1::2/64 to=2::3/64 oif=eth0 table=1", NULL); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 oif=eth0 table=1", NULL); test_rule_serialization("freeing interface names", - "RULE=from=1::2/64 to=2::3/64 iif=e0 iif=e1 oif=e0 oif=e1 table=1", - "RULE=from=1::2/64 to=2::3/64 iif=e1 oif=e1 table=1"); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=e0 iif=e1 oif=e0 oif=e1 table=1", + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=e1 oif=e1 table=1"); return 0; } From ec863cdc200f35ce0fc76d07f984ca476fcd8ad3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 2 Aug 2019 04:22:44 +0900 Subject: [PATCH 3/7] network: add missing entry in serialization/deserialization --- src/network/networkd-routing-policy-rule.c | 10 ++++++++++ src/network/test-routing-policy-rule.c | 14 +++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 8386d214b8..f6859f886f 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -1028,6 +1028,10 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) { space = true; } + fprintf(f, "%spriority=%"PRIu32, + space ? " " : "", + rule->priority); + if (rule->fwmark != 0) { fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32, space ? " " : "", @@ -1162,6 +1166,12 @@ int routing_policy_load_rules(const char *state_file, Set **rules) { log_error_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_error_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); diff --git a/src/network/test-routing-policy-rule.c b/src/network/test-routing-policy-rule.c index 0319b6db09..d441099b5a 100644 --- a/src/network/test-routing-policy-rule.c +++ b/src/network/test-routing-policy-rule.c @@ -62,31 +62,31 @@ int main(int argc, char **argv) { test_setup_logging(LOG_DEBUG); test_rule_serialization("basic parsing", - "RULE=from=1.2.3.4/32 to=2.3.4.5/32 family=AF_INET tos=5 fwmark=1/2 table=10", NULL); + "RULE=from=1.2.3.4/32 to=2.3.4.5/32 family=AF_INET tos=5 priority=0 fwmark=1/2 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 fwmark=2 fwmark=1 table=10 table=20", "RULE=from=1.2.3.4/32" - " to=2.3.4.5/32 family=AF_INET tos=5 fwmark=1/0 table=20"); + " to=2.3.4.5/32 family=AF_INET tos=5 priority=0 fwmark=1/0 table=20"); test_rule_serialization("ipv6", - "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 table=6", NULL); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 table=6", NULL); - assert_se(asprintf(&p, "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 table=%d", RT_TABLE_MAIN) >= 0); + assert_se(asprintf(&p, "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 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=from=1::2/64 to=2::3/64 family=AF_INET6 iif=lo table=1"); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 iif=lo table=1"); test_rule_serialization("outgoing interface", - "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 oif=eth0 table=1", NULL); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 oif=eth0 table=1", NULL); test_rule_serialization("freeing interface names", "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=e0 iif=e1 oif=e0 oif=e1 table=1", - "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=e1 oif=e1 table=1"); + "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 iif=e1 oif=e1 table=1"); return 0; } From 2d79289525ce2a85c22c6be6290f876b96b1bc0a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 4 Aug 2019 05:09:08 +0900 Subject: [PATCH 4/7] network: rename AddressFamilyBoolean -> AddressFamily We usually do not call an extended boolean as XxxBoolean. --- src/network/networkd-dhcp-common.c | 8 ++++---- src/network/networkd-ipv4ll.c | 6 +++--- src/network/networkd-link.c | 6 +++--- src/network/networkd-link.h | 2 +- src/network/networkd-network-gperf.gperf | 4 ++-- src/network/networkd-network.c | 2 +- src/network/networkd-network.h | 6 +++--- src/network/networkd-util.c | 18 +++++++++--------- src/network/networkd-util.h | 20 ++++++++++---------- src/network/test-network-tables.c | 2 +- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index d958d11d01..626b975839 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -18,7 +18,7 @@ int config_parse_dhcp( void *data, void *userdata) { - AddressFamilyBoolean *dhcp = data, s; + AddressFamily *dhcp = data, s; assert(filename); assert(lvalue); @@ -26,10 +26,10 @@ int config_parse_dhcp( assert(data); /* Note that this is mostly like - * config_parse_address_family_boolean(), except that it + * config_parse_address_family(), except that it * understands some old names for the enum values */ - s = address_family_boolean_from_string(rvalue); + s = address_family_from_string(rvalue); if (s < 0) { /* Previously, we had a slightly different enum here, @@ -51,7 +51,7 @@ int config_parse_dhcp( log_syntax(unit, LOG_WARNING, filename, line, 0, "DHCP=%s is deprecated, please use DHCP=%s instead.", - rvalue, address_family_boolean_to_string(s)); + rvalue, address_family_to_string(s)); } *dhcp = s; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 71f6af6af2..e50a3150df 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -251,7 +251,7 @@ int config_parse_ipv4ll( void *data, void *userdata) { - AddressFamilyBoolean *link_local = data; + AddressFamily *link_local = data; int r; assert(filename); @@ -260,7 +260,7 @@ int config_parse_ipv4ll( assert(data); /* Note that this is mostly like - * config_parse_address_family_boolean(), except that it + * config_parse_address_family(), except that it * applies only to IPv4 */ r = parse_boolean(rvalue); @@ -276,7 +276,7 @@ int config_parse_ipv4ll( log_syntax(unit, LOG_WARNING, filename, line, 0, "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.", - lvalue, rvalue, address_family_boolean_to_string(*link_local)); + lvalue, rvalue, address_family_to_string(*link_local)); return 0; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 3749b979f9..47d4d08aee 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -150,7 +150,7 @@ static bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -bool link_ipv4ll_enabled(Link *link, AddressFamilyBoolean mask) { +bool link_ipv4ll_enabled(Link *link, AddressFamily mask) { assert(link); assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0); @@ -242,7 +242,7 @@ static bool link_ipv4_forward_enabled(Link *link) { if (!link->network) return false; - if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID) return false; return link->network->ip_forward & ADDRESS_FAMILY_IPV4; @@ -260,7 +260,7 @@ static bool link_ipv6_forward_enabled(Link *link) { if (!link->network) return false; - if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID) return false; if (link_sysctl_ipv6_enabled(link) == 0) diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 5c9d0327ef..d077dfe772 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -188,7 +188,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address); int link_set_mtu(Link *link, uint32_t mtu); -bool link_ipv4ll_enabled(Link *link, AddressFamilyBoolean mask); +bool link_ipv4ll_enabled(Link *link, AddressFamily mask); int link_stop_clients(Link *link, bool may_keep_dhcp); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index e55228af38..8c7e5db4bb 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -59,7 +59,7 @@ Network.Xfrm, config_parse_stacked_netdev, Network.VRF, config_parse_ifname, 0, offsetof(Network, vrf_name) Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) -Network.LinkLocalAddressing, config_parse_link_local_address_family_boolean, 0, offsetof(Network, link_local) +Network.LinkLocalAddressing, config_parse_link_local_address_family, 0, offsetof(Network, link_local) Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.DefaultRouteOnDevice, config_parse_bool, 0, offsetof(Network, default_route_on_device) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) @@ -76,7 +76,7 @@ Network.DNSOverTLS, config_parse_dns_over_tls_mode, Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode) Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, 0 Network.NTP, config_parse_ntp, 0, offsetof(Network, ntp) -Network.IPForward, config_parse_address_family_boolean_with_kernel, 0, offsetof(Network, ip_forward) +Network.IPForward, config_parse_address_family_with_kernel, 0, offsetof(Network, ip_forward) Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 191e766a92..6a8766ce68 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -395,7 +395,7 @@ int network_load_one(Manager *manager, const char *filename) { .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID, /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */ - .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID, + .link_local = _ADDRESS_FAMILY_INVALID, .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, .ipv6_accept_ra = -1, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 0fa800841c..f8894f86dd 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -77,7 +77,7 @@ struct Network { Hashmap *stacked_netdev_names; /* DHCP Client Support */ - AddressFamilyBoolean dhcp; + AddressFamily dhcp; DHCPClientIdentifier dhcp_client_identifier; char *dhcp_vendor_class_identifier; char **dhcp_user_class; @@ -123,7 +123,7 @@ struct Network { uint32_t dhcp_server_pool_size; /* IPV4LL Support */ - AddressFamilyBoolean link_local; + AddressFamily link_local; bool ipv4ll_route; bool default_route_on_device; @@ -171,7 +171,7 @@ struct Network { usec_t can_restart_us; int can_triple_sampling; - AddressFamilyBoolean ip_forward; + AddressFamily ip_forward; bool ip_masquerade; int ipv6_accept_ra; diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index d01de53f7b..2f56b4c7f1 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -8,14 +8,14 @@ #include "string-util.h" #include "util.h" -static const char * const address_family_boolean_table[_ADDRESS_FAMILY_BOOLEAN_MAX] = { +static const char * const address_family_table[_ADDRESS_FAMILY_MAX] = { [ADDRESS_FAMILY_NO] = "no", [ADDRESS_FAMILY_YES] = "yes", [ADDRESS_FAMILY_IPV4] = "ipv4", [ADDRESS_FAMILY_IPV6] = "ipv6", }; -static const char * const link_local_address_family_boolean_table[_ADDRESS_FAMILY_BOOLEAN_MAX] = { +static const char * const link_local_address_family_table[_ADDRESS_FAMILY_MAX] = { [ADDRESS_FAMILY_NO] = "no", [ADDRESS_FAMILY_YES] = "yes", [ADDRESS_FAMILY_IPV4] = "ipv4", @@ -24,12 +24,12 @@ static const char * const link_local_address_family_boolean_table[_ADDRESS_FAMIL [ADDRESS_FAMILY_FALLBACK_IPV4] = "ipv4-fallback", }; -DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family_boolean, AddressFamilyBoolean, ADDRESS_FAMILY_YES); -DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family_boolean, AddressFamilyBoolean, ADDRESS_FAMILY_YES); -DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family_boolean, link_local_address_family_boolean, - AddressFamilyBoolean, "Failed to parse option"); +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES); +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family, AddressFamily, ADDRESS_FAMILY_YES); +DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family, + AddressFamily, "Failed to parse option"); -int config_parse_address_family_boolean_with_kernel( +int config_parse_address_family_with_kernel( const char* unit, const char *filename, unsigned line, @@ -41,7 +41,7 @@ int config_parse_address_family_boolean_with_kernel( void *data, void *userdata) { - AddressFamilyBoolean *fwd = data, s; + AddressFamily *fwd = data, s; assert(filename); assert(lvalue); @@ -56,7 +56,7 @@ int config_parse_address_family_boolean_with_kernel( * is gone, hence silently accept the old setting, but turn it * to "no". */ - s = address_family_boolean_from_string(rvalue); + s = address_family_from_string(rvalue); if (s < 0) { if (streq(rvalue, "kernel")) s = ADDRESS_FAMILY_NO; diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index aafbac7df6..c96c2fd9fa 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -5,7 +5,7 @@ #include "hash-funcs.h" #include "macro.h" -typedef enum AddressFamilyBoolean { +typedef enum AddressFamily { /* This is a bitmask, though it usually doesn't feel that way! */ ADDRESS_FAMILY_NO = 0, ADDRESS_FAMILY_IPV4 = 1 << 0, @@ -13,9 +13,9 @@ typedef enum AddressFamilyBoolean { ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6, ADDRESS_FAMILY_FALLBACK_IPV4 = 1 << 2, ADDRESS_FAMILY_FALLBACK = ADDRESS_FAMILY_FALLBACK_IPV4 | ADDRESS_FAMILY_IPV6, - _ADDRESS_FAMILY_BOOLEAN_MAX, - _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, -} AddressFamilyBoolean; + _ADDRESS_FAMILY_MAX, + _ADDRESS_FAMILY_INVALID = -1, +} AddressFamily; typedef struct NetworkConfigSection { unsigned line; @@ -23,14 +23,14 @@ typedef struct NetworkConfigSection { char filename[]; } NetworkConfigSection; -CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family_boolean); -CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean_with_kernel); +CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family); +CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel); -const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; -AddressFamilyBoolean address_family_boolean_from_string(const char *s) _pure_; +const char *address_family_to_string(AddressFamily b) _const_; +AddressFamily address_family_from_string(const char *s) _pure_; -const char *link_local_address_family_boolean_to_string(AddressFamilyBoolean b) _const_; -AddressFamilyBoolean link_local_address_family_boolean_from_string(const char *s) _pure_; +const char *link_local_address_family_to_string(AddressFamily b) _const_; +AddressFamily link_local_address_family_from_string(const char *s) _pure_; int kernel_route_expiration_supported(void); diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index 711954e4a2..56932ba15c 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -41,7 +41,7 @@ int main(int argc, char **argv) { test_table_sparse(ipvlan_mode, NETDEV_IPVLAN_MODE); test_table_sparse(macvlan_mode, NETDEV_MACVLAN_MODE); - test_table_sparse(address_family_boolean, ADDRESS_FAMILY_BOOLEAN); + test_table_sparse(address_family, ADDRESS_FAMILY); return EXIT_SUCCESS; } From 01fc8e4f4337752558a53d22303177dc1d966e4f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 4 Aug 2019 05:16:43 +0900 Subject: [PATCH 5/7] network: split out copying logic from routing_policy_rule_add_internal() --- src/network/networkd-routing-policy-rule.c | 71 +++++++++++++--------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index f6859f886f..1494727ead 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -58,6 +58,44 @@ void routing_policy_rule_free(RoutingPolicyRule *rule) { free(rule); } +static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) { + _cleanup_free_ char *iif = NULL, *oif = NULL; + + assert(dest); + assert(src); + + if (src->iif) { + iif = strdup(src->iif); + if (!iif) + return -ENOMEM; + } + + if (src->oif) { + oif = strdup(src->oif); + if (!oif) + return -ENOMEM; + } + + dest->family = src->family; + dest->from = src->from; + dest->from_prefixlen = src->from_prefixlen; + dest->to = src->to; + dest->to_prefixlen = src->to_prefixlen; + dest->invert_rule = src->invert_rule; + dest->tos = src->tos; + dest->fwmark = src->fwmark; + dest->fwmask = src->fwmask; + dest->priority = src->priority; + dest->table = src->table; + dest->iif = TAKE_PTR(iif); + dest->oif = TAKE_PTR(oif); + dest->protocol = src->protocol; + dest->sport = src->sport; + dest->dport = src->dport; + + return 0; +} + static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) { assert(rule); @@ -221,46 +259,21 @@ int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) { static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) { _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL; - _cleanup_free_ char *iif = NULL, *oif = NULL; int r; assert(m); assert(rules); assert(in); - if (in->iif) { - iif = strdup(in->iif); - if (!iif) - return -ENOMEM; - } - - if (in->oif) { - oif = strdup(in->oif); - if (!oif) - return -ENOMEM; - } - r = routing_policy_rule_new(&rule); if (r < 0) return r; rule->manager = m; - rule->family = in->family; - rule->from = in->from; - rule->from_prefixlen = in->from_prefixlen; - rule->to = in->to; - rule->to_prefixlen = in->to_prefixlen; - rule->invert_rule = in->invert_rule; - rule->tos = in->tos; - rule->fwmark = in->fwmark; - rule->fwmask = in->fwmask; - rule->priority = in->priority; - rule->table = in->table; - rule->iif = TAKE_PTR(iif); - rule->oif = TAKE_PTR(oif); - rule->protocol = in->protocol; - rule->sport = in->sport; - rule->dport = in->dport; + + r = routing_policy_rule_copy(rule, in); + if (r < 0) + return r; r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops); if (r < 0) From f6c6ff97f5c0f31d38fcf373f3b25033cb23e1af Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 1 Aug 2019 07:41:36 +0900 Subject: [PATCH 6/7] network: add RoutingPolicyRule.Family= setting Closes #13233. --- man/systemd.network.xml | 10 +++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-routing-policy-rule.c | 77 ++++++++++++++++++- src/network/networkd-routing-policy-rule.h | 4 +- src/network/networkd-util.c | 7 ++ src/network/networkd-util.h | 3 + .../fuzz-network-parser/directives.network | 1 + 7 files changed, 101 insertions(+), 2 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index accc824e4d..95c56b0ae3 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1139,6 +1139,16 @@ A boolean. Specifies whether the rule to be inverted. Defaults to false. + + Family= + + Takes a special value ipv4, ipv6, or + both. By default, the address family is determined by the address + specified in To= or From=. If neither + To= nor From= are specified, then defaults to + ipv4. + + diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 8c7e5db4bb..d4d108ad25 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -122,6 +122,7 @@ RoutingPolicyRule.IPProtocol, config_parse_routing_policy_rule_ip_prot RoutingPolicyRule.SourcePort, config_parse_routing_policy_rule_port_range, 0, 0 RoutingPolicyRule.DestinationPort, config_parse_routing_policy_rule_port_range, 0, 0 RoutingPolicyRule.InvertRule, config_parse_routing_policy_rule_invert, 0, 0 +RoutingPolicyRule.Family, config_parse_routing_policy_rule_family, 0, 0 Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 Route.Source, config_parse_destination, 0, 0 diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 1494727ead..5edc2444a7 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -11,6 +11,7 @@ #include "networkd-routing-policy-rule.h" #include "netlink-util.h" #include "networkd-manager.h" +#include "networkd-util.h" #include "parse-util.h" #include "socket-util.h" #include "string-util.h" @@ -569,11 +570,45 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl } int routing_policy_rule_section_verify(RoutingPolicyRule *rule) { + int r; + if (section_is_invalid(rule->section)) return -EINVAL; - if (rule->family == AF_UNSPEC) + if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) || + (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4))) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: address family specified by Family= conflicts with the address " + "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.", + rule->section->filename, rule->section->line); + + if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) { + _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL; + + assert(rule->family == AF_UNSPEC); + + /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */ + + r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6); + if (r < 0) + return r; + + r = routing_policy_rule_copy(rule6, rule); + if (r < 0) + return r; + rule->family = AF_INET; + rule6->family = AF_INET6; + + TAKE_PTR(rule6); + } + + if (rule->family == AF_UNSPEC) { + if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) + rule->family = AF_INET6; + else + rule->family = AF_INET; + } return 0; } @@ -973,6 +1008,46 @@ int config_parse_routing_policy_rule_invert( return 0; } +int config_parse_routing_policy_rule_family( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL; + Network *network = userdata; + AddressFamily a; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = routing_policy_rule_new_static(network, filename, section_line, &n); + if (r < 0) + return r; + + a = routing_policy_rule_address_family_from_string(rvalue); + if (a < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid address family '%s', ignoring.", rvalue); + return 0; + } + + n->address_family = a; + n = NULL; + + return 0; +} + static int routing_policy_rule_read_full_file(const char *state_file, char **ret) { _cleanup_free_ char *s = NULL; size_t size; diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 8ddb85307c..6b8e310227 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -36,7 +36,8 @@ struct RoutingPolicyRule { uint32_t fwmask; uint32_t priority; - int family; + AddressFamily address_family; /* Specified by Family= */ + int family; /* Automatically determined by From= or To= */ unsigned char to_prefixlen; unsigned char from_prefixlen; @@ -77,3 +78,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_device); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_port_range); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_ip_protocol); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_invert); +CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_family); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index 2f56b4c7f1..3fd26836c6 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -24,8 +24,15 @@ static const char * const link_local_address_family_table[_ADDRESS_FAMILY_MAX] = [ADDRESS_FAMILY_FALLBACK_IPV4] = "ipv4-fallback", }; +static const char * const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = { + [ADDRESS_FAMILY_YES] = "both", + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", +}; + DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES); DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family, AddressFamily, ADDRESS_FAMILY_YES); +DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily); DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family, AddressFamily, "Failed to parse option"); diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index c96c2fd9fa..3a57819f39 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -32,6 +32,9 @@ AddressFamily address_family_from_string(const char *s) _pure_; const char *link_local_address_family_to_string(AddressFamily b) _const_; AddressFamily link_local_address_family_from_string(const char *s) _pure_; +const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_; +AddressFamily routing_policy_rule_address_family_from_string(const char *s) _pure_; + int kernel_route_expiration_supported(void); int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s); diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 7be38b0f34..848d4bd187 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -208,6 +208,7 @@ SourcePort= DestinationPort= IPProtocol= InvertRule= +Family= [IPv6PrefixDelegation] RouterPreference= DNSLifetimeSec= From 65c24cd087d0aa718ca12f870a7591c92d7c67d0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 31 Jul 2019 12:09:03 +0900 Subject: [PATCH 7/7] test-network: add tests for RoutingPolicyRule.Family=ipv6 and both --- .../conf/routing-policy-rule-test1.network | 12 +++++++++ test/test-network/systemd-networkd-tests.py | 27 ++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/test/test-network/conf/routing-policy-rule-test1.network b/test/test-network/conf/routing-policy-rule-test1.network index 46b87c5a9a..ffcedc99a2 100644 --- a/test/test-network/conf/routing-policy-rule-test1.network +++ b/test/test-network/conf/routing-policy-rule-test1.network @@ -8,3 +8,15 @@ From= 192.168.100.18 Priority=111 IncomingInterface=test1 OutgoingInterface=test1 + +[RoutingPolicyRule] +IncomingInterface=test1 +Table=8 +Priority=100 +Family=ipv6 + +[RoutingPolicyRule] +IncomingInterface=test1 +Table=9 +Priority=101 +Family=both diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 593a9c976a..cde79817c8 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1439,7 +1439,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): 'routing-policy-rule-dummy98.network', 'routing-policy-rule-test1.network'] - routing_policy_rule_tables = ['7', '8'] + routing_policy_rule_tables = ['7', '8', '9'] routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']] def setUp(self): @@ -1520,15 +1520,36 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): start_networkd() self.wait_online(['test1:degraded']) - output = check_output('ip rule') + output = check_output('ip rule list iif test1 priority 111') print(output) - self.assertRegex(output, '111') + self.assertRegex(output, '111:') self.assertRegex(output, 'from 192.168.100.18') self.assertRegex(output, r'tos (?:0x08|throughput)\s') self.assertRegex(output, 'iif test1') self.assertRegex(output, 'oif test1') self.assertRegex(output, 'lookup 7') + output = check_output('ip rule list iif test1 priority 101') + print(output) + self.assertRegex(output, '101:') + self.assertRegex(output, 'from all') + self.assertRegex(output, 'iif test1') + self.assertRegex(output, 'lookup 9') + + output = check_output('ip -6 rule list iif test1 priority 100') + print(output) + self.assertRegex(output, '100:') + self.assertRegex(output, 'from all') + self.assertRegex(output, 'iif test1') + self.assertRegex(output, 'lookup 8') + + output = check_output('ip -6 rule list iif test1 priority 101') + print(output) + self.assertRegex(output, '101:') + self.assertRegex(output, 'from all') + self.assertRegex(output, 'iif test1') + self.assertRegex(output, 'lookup 9') + def test_routing_policy_rule_issue_11280(self): copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev', 'routing-policy-rule-dummy98.network', '12-dummy.netdev')