- Support adding, deleting and showing IP rules with UID ranges.
- Support querying per-UID routes via "ip route get uid <UID>".

UID range routing was added to net-next in 4fb7450683 ("Merge
branch 'uid-routing'")

Signed-off-by: Lorenzo Colitti <lore...@google.com>
---
 include/linux/fib_rules.h |  6 ++++++
 include/linux/rtnetlink.h |  1 +
 ip/iproute.c              | 12 ++++++++++++
 ip/iprule.c               | 35 ++++++++++++++++++++++++++++++++++-
 4 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
index 14404b3..bbf02a6 100644
--- a/include/linux/fib_rules.h
+++ b/include/linux/fib_rules.h
@@ -29,6 +29,11 @@ struct fib_rule_hdr {
        __u32           flags;
 };
 
+struct fib_rule_uid_range {
+       __u32           start;
+       __u32           end;
+};
+
 enum {
        FRA_UNSPEC,
        FRA_DST,        /* destination address */
@@ -51,6 +56,7 @@ enum {
        FRA_OIFNAME,
        FRA_PAD,
        FRA_L3MDEV,     /* iif or oif is l3mdev goto its table */
+       FRA_UID_RANGE,  /* UID range */
        __FRA_MAX
 };
 
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 2d2e3e6..066cfa7 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -318,6 +318,7 @@ enum rtattr_type_t {
        RTA_ENCAP,
        RTA_EXPIRES,
        RTA_PAD,
+       RTA_UID,
        __RTA_MAX
 };
 
diff --git a/ip/iproute.c b/ip/iproute.c
index 98bfad6..15273be 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -68,6 +68,7 @@ static void usage(void)
        fprintf(stderr, "       ip route get ADDRESS [ from ADDRESS iif STRING 
]\n");
        fprintf(stderr, "                            [ oif STRING ] [ tos TOS 
]\n");
        fprintf(stderr, "                            [ mark NUMBER ] [ vrf NAME 
]\n");
+       fprintf(stderr, "                            [ uid NUMBER ]\n");
        fprintf(stderr, "       ip route { add | del | change | append | 
replace } ROUTE\n");
        fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact 
PREFIX ]\n");
        fprintf(stderr, "            [ table TABLE_ID ] [ vrf NAME ] [ proto 
RTPROTO ]\n");
@@ -471,6 +472,10 @@ int print_route(const struct sockaddr_nl *who, struct 
nlmsghdr *n, void *arg)
                fprintf(fp, "%s ",
                        rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
        }
+
+       if (tb[RTA_UID])
+               fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
+
        if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
                __u32 flags = r->rtm_flags&~0xFFFF;
                int first = 1;
@@ -1684,6 +1689,13 @@ static int iproute_get(int argc, char **argv)
                        if (!name_is_vrf(*argv))
                                invarg("Invalid VRF\n", *argv);
                        odev = *argv;
+               } else if (matches(*argv, "uid") == 0) {
+                       uid_t uid;
+
+                       NEXT_ARG();
+                       if (get_unsigned(&uid, *argv, 0))
+                               invarg("invalid UID\n", *argv);
+                       addattr32(&req.n, sizeof(req), RTA_UID, uid);
                } else {
                        inet_prefix addr;
 
diff --git a/ip/iprule.c b/ip/iprule.c
index e61127e..8313138 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -46,6 +46,7 @@ static void usage(void)
                "       ip rule [ list [ SELECTOR ]]\n"
                "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] 
[ fwmark FWMARK[/MASK] ]\n"
                "            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ 
l3mdev ]\n"
+               "            [ uidrange NUMBER-NUMBER ]\n"
                "ACTION := [ table TABLE_ID ]\n"
                "          [ nat ADDRESS ]\n"
                "          [ realms [SRCREALM/]DSTREALM ]\n"
@@ -61,13 +62,14 @@ static struct
 {
        int not;
        int l3mdev;
-       int iifmask, oifmask;
+       int iifmask, oifmask, uidrange;
        unsigned int tb;
        unsigned int tos, tosmask;
        unsigned int pref, prefmask;
        unsigned int fwmark, fwmask;
        char iif[IFNAMSIZ];
        char oif[IFNAMSIZ];
+       struct fib_rule_uid_range range;
        inet_prefix src;
        inet_prefix dst;
 } filter;
@@ -151,6 +153,15 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr 
**tb, int host_len)
        if (filter.l3mdev && !(tb[FRA_L3MDEV] && 
rta_getattr_u8(tb[FRA_L3MDEV])))
                return false;
 
+       if (filter.uidrange) {
+               struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
+
+               if (!tb[FRA_UID_RANGE] ||
+                   r->start != filter.range.start ||
+                   r->end != filter.range.end)
+                       return false;
+       }
+
        table = rtm_get_table(r, tb);
        if (filter.tb > 0 && filter.tb ^ table)
                return false;
@@ -259,6 +270,12 @@ int print_rule(const struct sockaddr_nl *who, struct 
nlmsghdr *n, void *arg)
                        fprintf(fp, "lookup [l3mdev-table] ");
        }
 
+       if (tb[FRA_UID_RANGE]) {
+               struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
+
+               fprintf(fp, "uidrange %u-%u ", r->start, r->end);
+       }
+
        table = rtm_get_table(r, tb);
        if (table) {
                fprintf(fp, "lookup %s ",
@@ -463,6 +480,14 @@ static int iprule_list_flush_or_save(int argc, char 
**argv, int action)
                        filter.oifmask = 1;
                } else if (strcmp(*argv, "l3mdev") == 0) {
                        filter.l3mdev = 1;
+               } else if (strcmp(*argv, "uidrange") == 0) {
+                       NEXT_ARG();
+                       filter.uidrange = 1;
+                       if (sscanf(*argv, "%u-%u",
+                                  &filter.range.start,
+                                  &filter.range.end) != 2)
+                               invarg("invalid UID range\n", *argv);
+
                } else if (matches(*argv, "lookup") == 0 ||
                           matches(*argv, "table") == 0) {
                        __u32 tid;
@@ -680,6 +705,14 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1);
                        table_ok = 1;
                        l3mdev_rule = 1;
+               } else if (strcmp(*argv, "uidrange") == 0) {
+                       struct fib_rule_uid_range r;
+
+                       NEXT_ARG();
+                       if (sscanf(*argv, "%u-%u", &r.start, &r.end) != 2)
+                               invarg("invalid UID range\n", *argv);
+                       addattr_l(&req.n, sizeof(req), FRA_UID_RANGE, &r,
+                                 sizeof(r));
                } else if (strcmp(*argv, "nat") == 0 ||
                           matches(*argv, "map-to") == 0) {
                        NEXT_ARG();
-- 
2.8.0.rc3.226.g39d4020

Reply via email to