]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: support UID based routing policy
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 26 Jan 2020 13:22:38 +0000 (22:22 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 2 Feb 2020 13:43:38 +0000 (22:43 +0900)
Closes #14666.

man/systemd.network.xml
src/network/networkd-manager.c
src/network/networkd-network-gperf.gperf
src/network/networkd-routing-policy-rule.c
src/network/networkd-routing-policy-rule.h
test/fuzz/fuzz-network-parser/directives.network

index 6ff4fb2440e82ad6d6c41ec2094af9f7b7ade0c0..ed5abeff6c14ac74c5b6ec614f630c711baa194c 100644 (file)
             <literal>ipv4</literal>.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>User=</varname></term>
+          <listitem>
+            <para>Takes a username, a user ID, or a range of user IDs separated by a dash. Defaults to
+            unset.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect1>
 
index 90f734a03c5c52720a063284dea7676dd09c6c82..2528fb52676cbfd45466e36132d1742e52230211 100644 (file)
@@ -1138,6 +1138,12 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
                 return 0;
         }
 
+        r = sd_netlink_message_read(message, FRA_UID_RANGE, sizeof(tmp->uid_range), &tmp->uid_range);
+        if (r < 0 && r != -ENODATA) {
+                log_warning_errno(r, "rtnl: could not get FRA_UID_RANGE attribute, ignoring: %m");
+                return 0;
+        }
+
         (void) routing_policy_rule_get(m, tmp, &rule);
 
         if (DEBUG_LOGGING) {
index 2a7c223129c07100b904423cef841b48b0c5b4f4..699691dc87a010d1494104e7d7c41c844e0f850c 100644 (file)
@@ -130,6 +130,7 @@ RoutingPolicyRule.SourcePort,           config_parse_routing_policy_rule_port_ra
 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
+RoutingPolicyRule.User,                 config_parse_routing_policy_rule_uid_range,      0,                             0
 Route.Gateway,                          config_parse_gateway,                            0,                             0
 Route.Destination,                      config_parse_destination,                        0,                             0
 Route.Source,                           config_parse_destination,                        0,                             0
index e7d09c4ad94a0689efba763565580cc2e8a08135..52f25209d05d4923ed991093a4af7e43835d8e83 100644 (file)
@@ -7,6 +7,7 @@
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "fileio.h"
+#include "format-util.h"
 #include "ip-protocol-list.h"
 #include "networkd-routing-policy-rule.h"
 #include "netlink-util.h"
@@ -16,6 +17,7 @@
 #include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
 
 int routing_policy_rule_new(RoutingPolicyRule **ret) {
         RoutingPolicyRule *rule;
@@ -26,6 +28,8 @@ int routing_policy_rule_new(RoutingPolicyRule **ret) {
 
         *rule = (RoutingPolicyRule) {
                 .table = RT_TABLE_MAIN,
+                .uid_range.start = UID_INVALID,
+                .uid_range.end = UID_INVALID,
         };
 
         *ret = rule;
@@ -93,6 +97,7 @@ static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *
         dest->protocol = src->protocol;
         dest->sport = src->sport;
         dest->dport = src->dport;
+        dest->uid_range = src->uid_range;
 
         return 0;
 }
@@ -122,6 +127,7 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct
                 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
                 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
                 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
+                siphash24_compress(&rule->uid_range, sizeof(rule->uid_range), state);
 
                 if (rule->iif)
                         siphash24_compress(rule->iif, strlen(rule->iif), state);
@@ -198,6 +204,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
                 if (r != 0)
                         return r;
 
+                r = memcmp(&a->uid_range, &b->uid_range, sizeof(a->uid_range));
+                if (r != 0)
+                        return r;
+
                 r = strcmp_ptr(a->iif, b->iif);
                 if (r != 0)
                         return r;
@@ -554,6 +564,12 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
                         return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
         }
 
+        if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
+                r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append FRA_UID_RANGE attribute: %m");
+        }
+
         if (rule->invert_rule) {
                 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
                 if (r < 0)
@@ -1056,6 +1072,51 @@ int config_parse_routing_policy_rule_family(
         return 0;
 }
 
+int config_parse_routing_policy_rule_uid_range(
+                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;
+        uid_t start, end;
+        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;
+
+        r = get_user_creds(&rvalue, &start, NULL, NULL, NULL, 0);
+        if (r >= 0)
+                end = start;
+        else {
+                r = parse_uid_range(rvalue, &start, &end);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Invalid uid or uid range '%s', ignoring: %m", rvalue);
+                        return 0;
+                }
+        }
+
+        n->uid_range.start = start;
+        n->uid_range.end = end;
+        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;
@@ -1170,6 +1231,14 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
                         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;
+                }
+
                 fprintf(f, "%stable=%"PRIu32 "\n",
                         space ? " " : "",
                         rule->table);
@@ -1294,7 +1363,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
                                 r = parse_ip_port_range(b, &low, &high);
                                 if (r < 0) {
-                                        log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
+                                        log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
                                         continue;
                                 }
 
@@ -1305,12 +1374,24 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
 
                                 r = parse_ip_port_range(b, &low, &high);
                                 if (r < 0) {
-                                        log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
+                                        log_error_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_error_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
+                                        continue;
+                                }
+
+                                rule->uid_range.start = lower;
+                                rule->uid_range.end = upper;
                         }
                 }
 
index 6b8e3102275e48611f154224a66a872cf977e2c8..2afd8f75a6cf94c2b8d2bc3a3e81c9fd98010096 100644 (file)
@@ -49,6 +49,7 @@ struct RoutingPolicyRule {
 
         struct fib_rule_port_range sport;
         struct fib_rule_port_range dport;
+        struct fib_rule_uid_range uid_range;
 
         LIST_FIELDS(RoutingPolicyRule, rules);
 };
@@ -79,3 +80,4 @@ 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);
+CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_uid_range);
index 0e3adac5ce1b6c45f61c7d502978d0ca5fc4c9e5..8a953b75d923e4d10bf0d0598cd88305cc9c90d6 100644 (file)
@@ -225,6 +225,7 @@ DestinationPort=
 IPProtocol=
 InvertRule=
 Family=
+User=
 [IPv6PrefixDelegation]
 RouterPreference=
 DNSLifetimeSec=