]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: Allow to configure unreachable/blackhole RoutingPolicyRule (#17984)
authorSusant Sahani <ssahani@vmware.com>
Fri, 18 Dec 2020 03:21:15 +0000 (08:51 +0530)
committerGitHub <noreply@github.com>
Fri, 18 Dec 2020 03:21:15 +0000 (12:21 +0900)
man/systemd.network.xml
src/network/networkd-network-gperf.gperf
src/network/networkd-routing-policy-rule.c
src/network/networkd-routing-policy-rule.h
src/network/test-routing-policy-rule.c
test/fuzz/fuzz-network-parser/directives.network

index e5647f7dae3b93a7674651c68a763e6c05c94124..e46f506f0f0c26334346a7ef319e0cc273b40731 100644 (file)
@@ -1261,6 +1261,14 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
             unset.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>Type=</varname></term>
+          <listitem>
+            <para>Specifies Routing Policy Database (RPDB) rule type. Takes one of <literal>blackhole</literal>,
+            <literal>unreachable</literal> or <literal>prohibit</literal>.
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect1>
 
index be7c076c619a32d9f2b502c738ab0c7dee8d9dac..ccf7867d4f64acdb62cd5c51afaff17a78da35e9 100644 (file)
@@ -161,6 +161,7 @@ RoutingPolicyRule.InvertRule,                config_parse_routing_policy_rule_in
 RoutingPolicyRule.Family,                    config_parse_routing_policy_rule_family,                  0,                             0
 RoutingPolicyRule.User,                      config_parse_routing_policy_rule_uid_range,               0,                             0
 RoutingPolicyRule.SuppressPrefixLength,      config_parse_routing_policy_rule_suppress_prefixlen,      0,                             0
+RoutingPolicyRule.Type,                      config_parse_routing_policy_rule_type,                    0,                             0
 Route.Gateway,                               config_parse_gateway,                                     0,                             0
 Route.Destination,                           config_parse_destination,                                 0,                             0
 Route.Source,                                config_parse_destination,                                 0,                             0
index 4e4c347c7bd637dc605052500c3a694c692145b6..8c9565bda918626e133865329a0869842f66ec64 100644 (file)
 #include "networkd-util.h"
 #include "parse-util.h"
 #include "socket-util.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "user-util.h"
 
+static const char *const fr_act_type_table[__FR_ACT_MAX] = {
+        [FR_ACT_BLACKHOLE]   = "blackhole",
+        [FR_ACT_UNREACHABLE] = "unreachable",
+        [FR_ACT_PROHIBIT]    = "prohibit",
+};
+
+assert_cc(__FR_ACT_MAX <= UINT8_MAX);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fr_act_type, int);
+
 RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
         if (!rule)
                 return NULL;
@@ -56,6 +66,7 @@ static int routing_policy_rule_new(RoutingPolicyRule **ret) {
                 .uid_range.start = UID_INVALID,
                 .uid_range.end = UID_INVALID,
                 .suppress_prefixlen = -1,
+                .type = FR_ACT_TO_TBL,
         };
 
         *ret = rule;
@@ -126,6 +137,7 @@ static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *
         dest->to_prefixlen = src->to_prefixlen;
         dest->invert_rule = src->invert_rule;
         dest->tos = src->tos;
+        dest->type = src->type;
         dest->fwmark = src->fwmark;
         dest->fwmask = src->fwmask;
         dest->priority = src->priority;
@@ -158,6 +170,7 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct
                 siphash24_compress_boolean(rule->invert_rule, state);
 
                 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
+                siphash24_compress(&rule->type, sizeof(rule->type), state);
                 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
                 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
                 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
@@ -213,6 +226,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
                 if (r != 0)
                         return r;
 
+                r = CMP(a->type, b->type);
+                if (r != 0)
+                        return r;
+
                 r = CMP(a->fwmark, b->fwmark);
                 if (r != 0)
                         return r;
@@ -475,6 +492,12 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n
                         return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m");
         }
 
+        if (rule->type != FR_ACT_TO_TBL) {
+                r = sd_rtnl_message_routing_policy_rule_set_fib_type(m, rule->type);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FIB rule type attribute: %m");
+        }
+
         return 0;
 }
 
@@ -801,7 +824,13 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
 
         r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
         if (r < 0 && r != -ENODATA) {
-                log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
+                log_warning_errno(r, "rtnl: could not get FIB rule TOS, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_routing_policy_rule_get_fib_type(message, &tmp->type);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FIB rule type, ignoring: %m");
                 return 0;
         }
 
@@ -1415,6 +1444,45 @@ int config_parse_routing_policy_rule_suppress_prefixlen(
         return 0;
 }
 
+int config_parse_routing_policy_rule_type(
+                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;
+        int r, t;
+
+        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 log_oom();
+
+        t = fr_act_type_from_string(rvalue);
+        if (t < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Could not parse FIB rule type \"%s\", ignoring assignment: %m", rvalue);
+                return 0;
+        }
+
+        n->type = (uint8_t) t;
+        n = NULL;
+
+        return 0;
+}
+
 static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
         if (section_is_invalid(rule->section))
                 return -EINVAL;
@@ -1494,6 +1562,13 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
                         space = true;
                 }
 
+                if (rule->type != 0) {
+                        fprintf(f, "%stype=%hhu",
+                                space ? " " : "",
+                                rule->type);
+                        space = true;
+                }
+
                 if (rule->priority != 0) {
                         fprintf(f, "%spriority=%"PRIu32,
                                 space ? " " : "",
@@ -1670,6 +1745,12 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
                                         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) {
index baf086f25e9ddfddffd0506f9695688714044471..1b574452e2e388e9e1975e667ac386a208454b45 100644 (file)
@@ -23,7 +23,10 @@ typedef struct RoutingPolicyRule {
         bool invert_rule;
 
         uint8_t tos;
+        uint8_t type;
         uint8_t protocol;
+        uint8_t to_prefixlen;
+        uint8_t from_prefixlen;
 
         uint32_t table;
         uint32_t fwmark;
@@ -32,8 +35,6 @@ typedef struct RoutingPolicyRule {
 
         AddressFamily address_family; /* Specified by Family= */
         int family; /* Automatically determined by From= or To= */
-        unsigned char to_prefixlen;
-        unsigned char from_prefixlen;
 
         char *iif;
         char *oif;
@@ -71,3 +72,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_invert);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_family);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_uid_range);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_suppress_prefixlen);
+CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_type);
index 8d87cdf9c9e34288826460c182c8b605cc4ab082..4fed4fe8d9f2b83206325ae3fb9c1469baf6d8a7 100644 (file)
@@ -57,34 +57,34 @@ int main(int argc, char **argv) {
         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 priority=10 fwmark=1/2 invert_rule=yes table=10", NULL);
+                                "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 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 fwmark=1 invert_rule=no table=20");
+                                "   \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 invert_rule=yes table=6", NULL);
+                                "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 invert_rule=no table=%d", RT_TABLE_MAIN) >= 0);
+        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 iif=lo invert_rule=no table=1");
+                                "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 oif=eth0 invert_rule=no table=1", NULL);
+                                "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 iif=e0 iif=e1 oif=e0 oif=e1 table=1",
-                                "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 iif=e1 oif=e1 invert_rule=no table=1");
+                                "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 invert_rule=no table=1");
+                                "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=no table=1");
 
         return 0;
 }
index 611d5bb7f7c397f7b540d7ad3342552161e3990f..a4da64bd0085b4c77660e45164013a278a4a7cba 100644 (file)
@@ -275,6 +275,7 @@ InvertRule=
 Family=
 SuppressPrefixLength=
 User=
+Type=
 [IPv6SendRA]
 RouterPreference=
 DNSLifetimeSec=