From 037c635eee994f6b29fc82931490e831d4a2ead2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 10 Dec 2007 11:34:40 -0800 Subject: [PATCH 1/7] Fix off by one in nested attribute management. Fixes segv in: tc qdisc show dev eth1 due to uninitialized attribute table. Signed-off-by: Stephen Hemminger --- lib/libnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 12883fe1..d13596fa 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -632,6 +632,6 @@ int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rt rta = RTA_DATA(rta) + RTA_ALIGN(len); return parse_rtattr_nested(tb, max, rta); } - memset(tb, 0, sizeof(struct rtattr *) * max); + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); return 0; } From fc2d02069b52e0e1fce9045572bd22d197dd91d5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 12 Oct 2007 17:08:40 +0800 Subject: [PATCH 2/7] Add NAT action Here's a patch to add support for the nat action which is now in the kernel. Thanks, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt -- Signed-off-by: Stephen Hemminger --- tc/Makefile | 1 + tc/m_nat.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 tc/m_nat.c diff --git a/tc/Makefile b/tc/Makefile index a7155667..0facc880 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -27,6 +27,7 @@ TCMODULES += q_htb.o TCMODULES += m_gact.o TCMODULES += m_mirred.o TCMODULES += m_ipt.o +TCMODULES += m_nat.o TCMODULES += m_pedit.o TCMODULES += p_ip.o TCMODULES += p_icmp.o diff --git a/tc/m_nat.c b/tc/m_nat.c new file mode 100644 index 00000000..6e7fd055 --- /dev/null +++ b/tc/m_nat.c @@ -0,0 +1,213 @@ +/* + * m_nat.c NAT module + * + * This program is free software; you can distribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Herbert Xu + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "tc_util.h" +#include + +static void +explain(void) +{ + fprintf(stderr, "Usage: ... nat NAT\n" + "NAT := DIRECTION OLD NEW\n" + "DIRECTION := { ingress | egress }\n" + "OLD := PREFIX\n" + "NEW := ADDRESS\n"); +} + +static void +usage(void) +{ + explain(); + exit(-1); +} + +static int +parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel) +{ + int argc = *argc_p; + char **argv = *argv_p; + inet_prefix addr; + + if (argc <= 0) + return -1; + + if (matches(*argv, "egress") == 0) + sel->flags |= TCA_NAT_FLAG_EGRESS; + else if (matches(*argv, "ingress") != 0) + goto bad_val; + + NEXT_ARG(); + + if (get_prefix_1(&addr, *argv, AF_INET)) + goto bad_val; + + sel->old_addr = addr.data[0]; + sel->mask = htonl(~0u << (32 - addr.bitlen)); + + NEXT_ARG(); + + if (get_prefix_1(&addr, *argv, AF_INET)) + goto bad_val; + + sel->new_addr = addr.data[0]; + + argc--; + argv++; + + *argc_p = argc; + *argv_p = argv; + return 0; + +bad_val: + return -1; +} + +static int +parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +{ + struct tc_nat sel; + + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct rtattr *tail; + + memset(&sel, 0, sizeof(sel)); + + while (argc > 0) { + if (matches(*argv, "nat") == 0) { + NEXT_ARG(); + if (parse_nat_args(&argc, &argv, &sel)) { + fprintf(stderr, "Illegal nat construct (%s) \n", + *argv); + explain(); + return -1; + } + ok++; + continue; + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + break; + } + + } + + if (!ok) { + explain(); + return -1; + } + + if (argc) { + if (matches(*argv, "reclassify") == 0) { + sel.action = TC_ACT_RECLASSIFY; + argc--; + argv++; + } else if (matches(*argv, "pipe") == 0) { + sel.action = TC_ACT_PIPE; + argc--; + argv++; + } else if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + sel.action = TC_ACT_SHOT; + argc--; + argv++; + } else if (matches(*argv, "continue") == 0) { + sel.action = TC_ACT_UNSPEC; + argc--; + argv++; + } else if (matches(*argv, "pass") == 0) { + sel.action = TC_ACT_OK; + argc--; + argv++; + } + } + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&sel.index, *argv, 10)) { + fprintf(stderr, "Pedit: Illegal \"index\"\n"); + return -1; + } + argc--; + argv++; + } + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel)); + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int +print_nat(struct action_util *au,FILE * f, struct rtattr *arg) +{ + struct tc_nat *sel; + struct rtattr *tb[TCA_NAT_MAX + 1]; + char buf1[256]; + char buf2[256]; + SPRINT_BUF(buf3); + int len; + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_NAT_MAX, arg); + + if (tb[TCA_NAT_PARMS] == NULL) { + fprintf(f, "[NULL nat parameters]"); + return -1; + } + sel = RTA_DATA(tb[TCA_NAT_PARMS]); + + len = ffs(sel->mask); + len = len ? 33 - len : 0; + + fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ? + "egress" : "ingress", + format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), + len, + format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), + action_n2a(sel->action, buf3, sizeof (buf3))); + + if (show_stats) { + if (tb[TCA_NAT_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]); + print_tm(f,tm); + } + } + + return 0; +} + +struct action_util nat_action_util = { + .id = "nat", + .parse_aopt = parse_nat, + .print_aopt = print_nat, +}; From ec30dcce718ebe13f6396cb560283d3cbcca7354 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 12 Oct 2007 17:08:40 +0800 Subject: [PATCH 3/7] Add NAT action Here's a patch to add support for the nat action which is now in the kernel. Thanks, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt -- Signed-off-by: Stephen Hemminger --- include/linux/tc_act/tc_nat.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 include/linux/tc_act/tc_nat.h diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h new file mode 100644 index 00000000..e7cf31e8 --- /dev/null +++ b/include/linux/tc_act/tc_nat.h @@ -0,0 +1,29 @@ +#ifndef __LINUX_TC_NAT_H +#define __LINUX_TC_NAT_H + +#include +#include + +#define TCA_ACT_NAT 9 + +enum +{ + TCA_NAT_UNSPEC, + TCA_NAT_PARMS, + TCA_NAT_TM, + __TCA_NAT_MAX +}; +#define TCA_NAT_MAX (__TCA_NAT_MAX - 1) + +#define TCA_NAT_FLAG_EGRESS 1 + +struct tc_nat +{ + tc_gen; + __be32 old_addr; + __be32 new_addr; + __be32 mask; + __u32 flags; +}; + +#endif From e17b7337f1ce0c7367215fe73b4722524ec1bdf3 Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Tue, 20 Nov 2007 15:38:21 +0100 Subject: [PATCH 4/7] Correct documentation regarding PROMISC and ALLMULTI. The ip util would happily change these flags, it's just not recommended. Reflect that in the doc. The behaviour of ifconfig is exactly the same as of ip, delete the note about it. Signed-off-by: Tomas Janousek Signed-off-by: Stephen Hemminger --- doc/ip-cref.tex | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/doc/ip-cref.tex b/doc/ip-cref.tex index 5eaa4a89..fe38f998 100644 --- a/doc/ip-cref.tex +++ b/doc/ip-cref.tex @@ -298,9 +298,9 @@ Do not use it, if you do not understand what this operation really does. \vskip 1mm \begin{NB} -The {\tt ip} utility does not change the \verb|PROMISC| -or \verb|ALLMULTI| flags. These flags are considered -obsolete and should not be changed administratively. +The \verb|PROMISC| and \verb|ALLMULTI| flags are considered +obsolete and should not be changed administratively, though +the {\tt ip} utility will allow that. \end{NB} \paragraph{Warning:} If multiple parameter changes are requested, @@ -450,13 +450,6 @@ or not implemented (\verb|DEBUG|) or specific to some devices (\verb|MASTER|, \verb|AUTOMEDIA| and \verb|PORTSEL|). We do not discuss them here. \end{NB} -\begin{NB} -The values of \verb|PROMISC| and \verb|ALLMULTI| flags -shown by the \verb|ifconfig| utility and by the \verb|ip| utility -are {\em different\/}. \verb|ip link ls| shows the true device state, -while \verb|ifconfig| shows the virtual state which was set with -\verb|ifconfig| itself. -\end{NB} The second line contains information on the link layer addresses From e22b42a2c1f088c09cae071b77b3a57069f196b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Delawarde?= Date: Mon, 26 Nov 2007 18:13:24 +0100 Subject: [PATCH 5/7] tc mask patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hello Stephen, As the current maintainer of iproute2 package, you could be interested in including the attached patch that allow using masks in the fw filter of the tc utility (very useful at least for me). AFAK, it works at least from iproute2 version 2.6.20-?. Feel free to make the appropriate cleaning changes if necessary, or contact me if you see any trouble. Best regards, François Delawarde. Signed-off-by: Stephen Hemminger --- tc/f_fw.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tc/f_fw.c b/tc/f_fw.c index 046f6146..6d1490b4 100644 --- a/tc/f_fw.c +++ b/tc/f_fw.c @@ -40,19 +40,30 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a memset(&tp, 0, sizeof(tp)); + tail = NLMSG_TAIL(n); + addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); + if (handle) { + char *slash; + __u32 mask = 0; + if ((slash = strchr(handle, '/')) != NULL) + *slash = '\0'; if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); return -1; } + if (slash) { + if (get_u32(&mask, slash+1, 0)) { + fprintf(stderr, "Illegal \"handle\" mask\n"); + return -1; + } + addattr32(n, MAX_MSG, TCA_FW_MASK, mask); + } } if (argc == 0) return 0; - tail = NLMSG_TAIL(n); - addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); - while (argc > 0) { if (matches(*argv, "classid") == 0 || matches(*argv, "flowid") == 0) { @@ -111,8 +122,16 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u parse_rtattr_nested(tb, TCA_FW_MAX, opt); - if (handle) - fprintf(f, "handle 0x%x ", handle); + if (handle || tb[TCA_FW_MASK]) { + __u32 mark = 0, mask = 0; + if(handle) + mark = handle; + if(tb[TCA_FW_MASK] && + (mask = *(__u32*)RTA_DATA(tb[TCA_FW_MASK])) != 0xFFFFFFFF) + fprintf(f, "handle 0x%x/0x%x ", mark, mask); + else + fprintf(f, "handle 0x%x ", handle); + } if (tb[TCA_FW_CLASSID]) { SPRINT_BUF(b1); From 5a0d1cbf69269bfcb510a8b861b8a83aed0f6b85 Mon Sep 17 00:00:00 2001 From: Andreas Henriksson Date: Sat, 8 Dec 2007 00:41:34 +0100 Subject: [PATCH 6/7] iproute2: support dotted-quad netmask notation. On tor, 2007-12-06 at 11:53 -0800, Stephen Hemminger wrote: > On Tue, 4 Dec 2007 14:58:18 +0100 > Andreas Henriksson wrote: > > > Suggested patch for allowing netmask to be specified in dotted quad format. > > See http://bugs.debian.org/357172 > > > > (Known problem: this will not prevent some invalid syntaxes, > > ie. "255.0.255.0" will be treated as "255.255.255.0") > > > > Comments? Suggestions? Improvements? > > Fix the bug you mentioned? > > [... snip example code ...] Updated patch, added your netmask validation code but without the check that made 0.0.0.0 (default) and 255.255.255.255 (one address) invalid netmasks as they are permitted in CIDR format. Signed-off-by: Andreas Henriksson Signed-off-by: Stephen Hemminger --- lib/utils.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/utils.c b/lib/utils.c index ffef6fed..eb8e312c 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -47,6 +47,41 @@ int get_integer(int *val, const char *arg, int base) return 0; } +/* a valid netmask must be 2^n - 1 (n = 1..31) */ +static int is_valid_netmask(const inet_prefix *addr) +{ + uint32_t host; + + if (addr->family != AF_INET) + return 0; + + host = ~ntohl(addr->data[0]); + + return (host & (host + 1)) == 0; +} + +static int get_netmask(unsigned *val, const char *arg, int base) +{ + inet_prefix addr; + + if (!get_unsigned(val, arg, base)) + return 0; + + /* try coverting dotted quad to CIDR */ + if (!get_addr_1(&addr, arg, AF_INET)) { + u_int32_t mask; + + *val=0; + for (mask = addr.data[0]; mask; mask >>= 1) + (*val)++; + + if (is_valid_netmask(&addr)) + return 0; + } + + return -1; +} + int get_unsigned(unsigned *val, const char *arg, int base) { unsigned long res; @@ -304,7 +339,8 @@ int get_prefix_1(inet_prefix *dst, char *arg, int family) dst->bitlen = 32; } if (slash) { - if (get_unsigned(&plen, slash+1, 0) || plen > dst->bitlen) { + if (get_netmask(&plen, slash+1, 0) + || plen > dst->bitlen) { err = -1; goto done; } From 4b270b172a6e570f4e9fa1ebb4bc67b0e715ee48 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 11 Dec 2007 10:03:28 -0800 Subject: [PATCH 7/7] Fix dotted quad for bit order Signed-off-by: Stephen Hemminger --- lib/utils.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/utils.c b/lib/utils.c index eb8e312c..84948513 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -47,7 +47,7 @@ int get_integer(int *val, const char *arg, int base) return 0; } -/* a valid netmask must be 2^n - 1 (n = 1..31) */ +/* a valid netmask must be 2^n - 1 */ static int is_valid_netmask(const inet_prefix *addr) { uint32_t host; @@ -60,6 +60,17 @@ static int is_valid_netmask(const inet_prefix *addr) return (host & (host + 1)) == 0; } +static unsigned cidr(const inet_prefix *addr) +{ + unsigned bits = 0; + u_int32_t mask; + + for (mask = ntohl(addr->data[0]); mask; mask <<= 1) + ++bits; + + return bits; +} + static int get_netmask(unsigned *val, const char *arg, int base) { inet_prefix addr; @@ -69,14 +80,10 @@ static int get_netmask(unsigned *val, const char *arg, int base) /* try coverting dotted quad to CIDR */ if (!get_addr_1(&addr, arg, AF_INET)) { - u_int32_t mask; - - *val=0; - for (mask = addr.data[0]; mask; mask >>= 1) - (*val)++; - if (is_valid_netmask(&addr)) return 0; + + *val = cidr(&addr); } return -1;