X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ip%2Fiprule.c;h=e1a943a2b60f8fd6f27d0fbb79e7aa1dc02938c2;hb=7132284647c15ca30d942926bc506d6019d3b61c;hp=ccf699ffeb1c108142bf6ac23d732d72b878f3a6;hpb=105da95218c9d30375efc43f9edd8ef32998fedb;p=iproute2.git diff --git a/ip/iprule.c b/ip/iprule.c index ccf699f..e1a943a 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -24,9 +24,11 @@ #include #include #include +#include #include "rt_names.h" #include "utils.h" +#include "ip_common.h" extern struct rtnl_handle rth; @@ -35,34 +37,35 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { fprintf(stderr, "Usage: ip rule [ list | add | del | flush ] SELECTOR ACTION\n"); - fprintf(stderr, "SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n"); + fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); fprintf(stderr, " [ dev STRING ] [ pref NUMBER ]\n"); fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); fprintf(stderr, " [ prohibit | reject | unreachable ]\n"); fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); + fprintf(stderr, " [ goto NUMBER ]\n"); fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n"); exit(-1); } -static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, - void *arg) +int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; int host_len = -1; - struct rtattr * tb[RTA_MAX+1]; + __u32 table; + struct rtattr * tb[FRA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); - if (n->nlmsg_type != RTM_NEWRULE) + if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; - parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); if (r->rtm_family == AF_INET) host_len = 32; @@ -73,23 +76,29 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, else if (r->rtm_family == AF_IPX) host_len = 80; - if (tb[RTA_PRIORITY]) - fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])); + if (n->nlmsg_type == RTM_DELRULE) + fprintf(fp, "Deleted "); + + if (tb[FRA_PRIORITY]) + fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY])); else fprintf(fp, "0:\t"); - if (tb[RTA_SRC]) { + if (r->rtm_flags & FIB_RULE_INVERT) + fprintf(fp, "not "); + + if (tb[FRA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]), + RTA_PAYLOAD(tb[FRA_SRC]), + RTA_DATA(tb[FRA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]), + RTA_PAYLOAD(tb[FRA_SRC]), + RTA_DATA(tb[FRA_SRC]), abuf, sizeof(abuf)) ); } @@ -99,18 +108,18 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, fprintf(fp, "from all "); } - if (tb[RTA_DST]) { + if (tb[FRA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST]), + RTA_PAYLOAD(tb[FRA_DST]), + RTA_DATA(tb[FRA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "to %s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST]), + RTA_PAYLOAD(tb[FRA_DST]), + RTA_DATA(tb[FRA_DST]), abuf, sizeof(abuf))); } } else if (r->rtm_dst_len) { @@ -121,19 +130,32 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } - if (tb[RTA_PROTOINFO]) { - fprintf(fp, "fwmark %#x ", *(__u32*)RTA_DATA(tb[RTA_PROTOINFO])); + + if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { + __u32 mark = 0, mask = 0; + + if (tb[FRA_FWMARK]) + mark = *(__u32*)RTA_DATA(tb[FRA_FWMARK]); + + if (tb[FRA_FWMASK] && + (mask = *(__u32*)RTA_DATA(tb[FRA_FWMASK])) != 0xFFFFFFFF) + fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask); + else + fprintf(fp, "fwmark 0x%x ", mark); } - if (tb[RTA_IIF]) { - fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[RTA_IIF])); + if (tb[FRA_IFNAME]) { + fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[FRA_IFNAME])); + if (r->rtm_flags & FIB_RULE_DEV_DETACHED) + fprintf(fp, "[detached] "); } - if (r->rtm_table) - fprintf(fp, "lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1))); + table = rtm_get_table(r, tb); + if (table) + fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); - if (tb[RTA_FLOW]) { - __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]); + if (tb[FRA_FLOW]) { + __u32 to = *(__u32*)RTA_DATA(tb[FRA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; if (from) { @@ -146,14 +168,24 @@ static int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, if (r->rtm_type == RTN_NAT) { if (tb[RTA_GATEWAY]) { - fprintf(fp, "map-to %s ", + fprintf(fp, "map-to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } else fprintf(fp, "masquerade"); - } else if (r->rtm_type != RTN_UNICAST) + } else if (r->rtm_type == FR_ACT_GOTO) { + fprintf(fp, "goto "); + if (tb[FRA_GOTO]) + fprintf(fp, "%u", *(__u32 *) RTA_DATA(tb[FRA_GOTO])); + else + fprintf(fp, "none"); + if (r->rtm_flags & FIB_RULE_UNRESOLVED) + fprintf(fp, " [unresolved]"); + } else if (r->rtm_type == FR_ACT_NOP) + fprintf(fp, "nop"); + else if (r->rtm_type != RTN_UNICAST) fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); fprintf(fp, "\n"); @@ -206,6 +238,7 @@ static int iprule_modify(int cmd, int argc, char **argv) req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_table = 0; req.r.rtm_type = RTN_UNSPEC; + req.r.rtm_flags = 0; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; @@ -213,18 +246,20 @@ static int iprule_modify(int cmd, int argc, char **argv) } while (argc > 0) { - if (strcmp(*argv, "from") == 0) { + if (strcmp(*argv, "not") == 0) { + req.r.rtm_flags |= FIB_RULE_INVERT; + } else if (strcmp(*argv, "from") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_src_len = dst.bitlen; - addattr_l(&req.n, sizeof(req), RTA_SRC, &dst.data, dst.bytelen); + addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); } else if (strcmp(*argv, "to") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_dst_len = dst.bitlen; - addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); + addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); } else if (matches(*argv, "preference") == 0 || matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { @@ -232,7 +267,7 @@ static int iprule_modify(int cmd, int argc, char **argv) NEXT_ARG(); if (get_u32(&pref, *argv, 0)) invarg("preference value is invalid\n", *argv); - addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref); + addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref); } else if (strcmp(*argv, "tos") == 0) { __u32 tos; NEXT_ARG(); @@ -240,29 +275,42 @@ static int iprule_modify(int cmd, int argc, char **argv) invarg("TOS value is invalid\n", *argv); req.r.rtm_tos = tos; } else if (strcmp(*argv, "fwmark") == 0) { - __u32 fwmark; + char *slash; + __u32 fwmark, fwmask; NEXT_ARG(); + if ((slash = strchr(*argv, '/')) != NULL) + *slash = '\0'; if (get_u32(&fwmark, *argv, 0)) invarg("fwmark value is invalid\n", *argv); - addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark); + addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); + if (slash) { + if (get_u32(&fwmask, slash+1, 0)) + invarg("fwmask value is invalid\n", slash+1); + addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); + } } else if (matches(*argv, "realms") == 0) { __u32 realm; NEXT_ARG(); if (get_rt_realms(&realm, *argv)) invarg("invalid realms\n", *argv); - addattr32(&req.n, sizeof(req), RTA_FLOW, realm); + addattr32(&req.n, sizeof(req), FRA_FLOW, realm); } else if (matches(*argv, "table") == 0 || strcmp(*argv, "lookup") == 0) { __u32 tid; NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("invalid table ID\n", *argv); - req.r.rtm_table = tid; + if (tid < 256) + req.r.rtm_table = tid; + else { + req.r.rtm_table = RT_TABLE_UNSPEC; + addattr32(&req.n, sizeof(req), FRA_TABLE, tid); + } table_ok = 1; } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "iif") == 0) { NEXT_ARG(); - addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1); + addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); } else if (strcmp(*argv, "nat") == 0 || matches(*argv, "map-to") == 0) { NEXT_ARG(); @@ -277,9 +325,19 @@ static int iprule_modify(int cmd, int argc, char **argv) } if (matches(*argv, "help") == 0) usage(); - if (rtnl_rtntype_a2n(&type, *argv)) + else if (matches(*argv, "goto") == 0) { + __u32 target; + type = FR_ACT_GOTO; + NEXT_ARG(); + if (get_u32(&target, *argv, 0)) + invarg("invalid target\n", *argv); + addattr32(&req.n, sizeof(req), FRA_GOTO, target); + } else if (matches(*argv, "nop") == 0) + type = FR_ACT_NOP; + else if (rtnl_rtntype_a2n(&type, *argv)) invarg("Failed to parse rule type", *argv); req.r.rtm_type = type; + table_ok = 1; } argc--; argv++; @@ -303,15 +361,15 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *a struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr * tb[FRA_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; - parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); - if (tb[RTA_PRIORITY]) { + if (tb[FRA_PRIORITY]) { n->nlmsg_type = RTM_DELRULE; n->nlmsg_flags = NLM_F_REQUEST;