]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/iprule.c
Merge branch 'iproute2-master' into iproute2-next
[mirror_iproute2.git] / ip / iprule.c
index a49753e640d95691619e2e09ba5efe4f6b774d20..9aa411ceb8aa4e1e4f1cf9eab8b7c20dcd1a5843 100644 (file)
@@ -47,6 +47,9 @@ static void usage(void)
                "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"
                "            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
                "            [ uidrange NUMBER-NUMBER ]\n"
+               "            [ ipproto PROTOCOL ]\n"
+               "            [ sport [ NUMBER | NUMBER-NUMBER ]\n"
+               "            [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
                "ACTION := [ table TABLE_ID ]\n"
                "          [ protocol PROTO ]\n"
                "          [ nat ADDRESS ]\n"
@@ -75,6 +78,9 @@ static struct
        inet_prefix dst;
        int protocol;
        int protocolmask;
+       struct fib_rule_port_range sport;
+       struct fib_rule_port_range dport;
+       __u8 ipproto;
 } filter;
 
 static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
@@ -171,6 +177,39 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
                        return false;
        }
 
+       if (filter.ipproto) {
+               __u8 ipproto = 0;
+
+               if (tb[FRA_IP_PROTO])
+                       ipproto = rta_getattr_u8(tb[FRA_IP_PROTO]);
+               if (filter.ipproto != ipproto)
+                       return false;
+       }
+
+       if (filter.sport.start) {
+               const struct fib_rule_port_range *r;
+
+               if (!tb[FRA_SPORT_RANGE])
+                       return false;
+
+               r = RTA_DATA(tb[FRA_SPORT_RANGE]);
+               if (r->start != filter.sport.start ||
+                   r->end != filter.sport.end)
+                       return false;
+       }
+
+       if (filter.dport.start) {
+               const struct fib_rule_port_range *r;
+
+               if (!tb[FRA_DPORT_RANGE])
+                       return false;
+
+               r = RTA_DATA(tb[FRA_DPORT_RANGE]);
+               if (r->start != filter.dport.start ||
+                   r->end != filter.dport.end)
+                       return false;
+       }
+
        table = frh_get_table(frh, tb);
        if (filter.tb > 0 && filter.tb ^ table)
                return false;
@@ -178,7 +217,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
        return true;
 }
 
-int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+int print_rule(struct nlmsghdr *n, void *arg)
 {
        FILE *fp = arg;
        struct fib_rule_hdr *frh = NLMSG_DATA(n);
@@ -236,7 +275,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
                print_string(PRINT_FP, NULL, "to ", NULL);
                print_color_string(PRINT_ANY, ifa_family_color(frh->family),
-                                  "dst", "%s ", dst);
+                                  "dst", "%s", dst);
                if (frh->dst_len != host_len)
                        print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
                else
@@ -306,6 +345,37 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                print_uint(PRINT_ANY, "uid_end", "-%u ", r->end);
        }
 
+       if (tb[FRA_IP_PROTO]) {
+               SPRINT_BUF(pbuf);
+               print_string(PRINT_ANY, "ipproto", "ipproto %s ",
+                            inet_proto_n2a(rta_getattr_u8(tb[FRA_IP_PROTO]),
+                                           pbuf, sizeof(pbuf)));
+       }
+
+       if (tb[FRA_SPORT_RANGE]) {
+               struct fib_rule_port_range *r = RTA_DATA(tb[FRA_SPORT_RANGE]);
+
+               if (r->start == r->end) {
+                       print_uint(PRINT_ANY, "sport", "sport %u ", r->start);
+               } else {
+                       print_uint(PRINT_ANY, "sport_start", "sport %u",
+                                  r->start);
+                       print_uint(PRINT_ANY, "sport_end", "-%u ", r->end);
+               }
+       }
+
+       if (tb[FRA_DPORT_RANGE]) {
+               struct fib_rule_port_range *r = RTA_DATA(tb[FRA_DPORT_RANGE]);
+
+               if (r->start == r->end) {
+                       print_uint(PRINT_ANY, "dport", "dport %u ", r->start);
+               } else {
+                       print_uint(PRINT_ANY, "dport_start", "dport %u",
+                                  r->start);
+                       print_uint(PRINT_ANY, "dport_end", "-%u ", r->end);
+               }
+       }
+
        table = frh_get_table(frh, tb);
        if (table) {
                print_string(PRINT_ANY, "table",
@@ -408,8 +478,7 @@ static int save_rule_prep(void)
        return 0;
 }
 
-static int save_rule(const struct sockaddr_nl *who,
-                    struct nlmsghdr *n, void *arg)
+static int save_rule(struct nlmsghdr *n, void *arg)
 {
        int ret;
 
@@ -422,13 +491,13 @@ static int save_rule(const struct sockaddr_nl *who,
        return ret == n->nlmsg_len ? 0 : ret;
 }
 
-static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
-                     void *arg)
+static int flush_rule(struct nlmsghdr *n, void *arg)
 {
        struct rtnl_handle rth2;
        struct fib_rule_hdr *frh = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[FRA_MAX+1];
+       int host_len = -1;
 
        len -= NLMSG_LENGTH(sizeof(*frh));
        if (len < 0)
@@ -436,6 +505,10 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
        parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
+       host_len = af_bit_len(frh->family);
+       if (!filter_nlmsg(n, tb, host_len))
+               return 0;
+
        if (tb[FRA_PROTOCOL]) {
                __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
 
@@ -570,6 +643,36 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
                                filter.protocolmask = 0;
                        }
                        filter.protocol = prot;
+               } else if (strcmp(*argv, "ipproto") == 0) {
+                       int ipproto;
+
+                       NEXT_ARG();
+                       ipproto = inet_proto_a2n(*argv);
+                       if (ipproto < 0)
+                               invarg("Invalid \"ipproto\" value\n", *argv);
+                       filter.ipproto = ipproto;
+               } else if (strcmp(*argv, "sport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid port range\n", *argv);
+                       filter.sport = r;
+               } else if (strcmp(*argv, "dport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid dport range\n", *argv);
+                       filter.dport = r;
                } else{
                        if (matches(*argv, "dst") == 0 ||
                            matches(*argv, "to") == 0) {
@@ -581,7 +684,7 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
                argc--; argv++;
        }
 
-       if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) {
+       if (rtnl_ruledump_req(&rth, af) < 0) {
                perror("Cannot send dump request");
                return 1;
        }
@@ -616,8 +719,7 @@ static int rule_dump_check_magic(void)
        return 0;
 }
 
-static int restore_handler(const struct sockaddr_nl *nl,
-                          struct rtnl_ctrl_data *ctrl,
+static int restore_handler(struct rtnl_ctrl_data *ctrl,
                           struct nlmsghdr *n, void *arg)
 {
        int ret;
@@ -660,6 +762,11 @@ static int iprule_modify(int cmd, int argc, char **argv)
        };
 
        if (cmd == RTM_NEWRULE) {
+               if (argc == 0) {
+                       fprintf(stderr,
+                               "\"ip rule add\" requires arguments.\n");
+                       return -1;
+               }
                req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
                req.frh.action = FR_ACT_TO_TBL;
        }
@@ -802,6 +909,39 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        addattr32(&req.n, sizeof(req), RTA_GATEWAY,
                                  get_addr32(*argv));
                        req.frh.action = RTN_NAT;
+               } else if (strcmp(*argv, "ipproto") == 0) {
+                       int ipproto;
+
+                       NEXT_ARG();
+                       ipproto = inet_proto_a2n(*argv);
+                       if (ipproto < 0)
+                               invarg("Invalid \"ipproto\" value\n",
+                                      *argv);
+                       addattr8(&req.n, sizeof(req), FRA_IP_PROTO, ipproto);
+               } else if (strcmp(*argv, "sport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret = 0;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid port range\n", *argv);
+                       addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &r,
+                                 sizeof(r));
+               } else if (strcmp(*argv, "dport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret = 0;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid dport range\n", *argv);
+                       addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &r,
+                                 sizeof(r));
                } else {
                        int type;