From d432d8041a1e20ec5dc6ef519632a8fdd5e51e50 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 08:50:10 +0200 Subject: [PATCH 1/9] IPMARK: import 20080304 code base With truly minimal changes to make it compile. --- extensions/Kbuild | 1 + extensions/Mbuild | 1 + extensions/libxt_IPMARK.c | 159 +++++++++++++++++++++++++++++++++++ extensions/libxt_IPMARK.man | 45 ++++++++++ extensions/xt_IPMARK.Kconfig | 12 +++ extensions/xt_IPMARK.c | 59 +++++++++++++ extensions/xt_IPMARK.h | 13 +++ mconfig | 1 + 8 files changed, 291 insertions(+) create mode 100644 extensions/libxt_IPMARK.c create mode 100644 extensions/libxt_IPMARK.man create mode 100644 extensions/xt_IPMARK.Kconfig create mode 100644 extensions/xt_IPMARK.c create mode 100644 extensions/xt_IPMARK.h diff --git a/extensions/Kbuild b/extensions/Kbuild index 82dd141..9207126 100644 --- a/extensions/Kbuild +++ b/extensions/Kbuild @@ -8,6 +8,7 @@ obj-m += compat_xtables.o obj-${build_CHAOS} += xt_CHAOS.o obj-${build_DELUDE} += xt_DELUDE.o obj-${build_ECHO} += xt_ECHO.o +obj-${build_IPMARK} += xt_IPMARK.o obj-${build_LOGMARK} += xt_LOGMARK.o obj-${build_TARPIT} += xt_TARPIT.o obj-${build_TEE} += xt_TEE.o diff --git a/extensions/Mbuild b/extensions/Mbuild index 7f8a019..0ab79bc 100644 --- a/extensions/Mbuild +++ b/extensions/Mbuild @@ -1,6 +1,7 @@ obj-${build_CHAOS} += libxt_CHAOS.so obj-${build_DELUDE} += libxt_DELUDE.so obj-${build_ECHO} += libxt_ECHO.so +obj-${build_IPMARK} += libxt_IPMARK.so obj-${build_LOGMARK} += libxt_LOGMARK.so obj-${build_TARPIT} += libxt_TARPIT.so obj-${build_TEE} += libxt_TEE.so diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c new file mode 100644 index 0000000..4503347 --- /dev/null +++ b/extensions/libxt_IPMARK.c @@ -0,0 +1,159 @@ +/* Shared library add-on to iptables to add IPMARK target support. + * (C) 2003 by Grzegorz Janoszka + * + * based on original MARK target + * + * This program is distributed under the terms of GNU GPL + */ +#include +#include +#include +#include + +#include +#include "xt_IPMARK.h" + +#define IPT_ADDR_USED 1 +#define IPT_AND_MASK_USED 2 +#define IPT_OR_MASK_USED 4 + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"IPMARK target options:\n" +" --addr src/dst use source or destination ip address\n" +" --and-mask value logical AND ip address with this value becomes MARK\n" +" --or-mask value logical OR ip address with this value becomes MARK\n" +"\n"); +} + +static struct option opts[] = { + { "addr", 1, 0, '1' }, + { "and-mask", 1, 0, '2' }, + { "or-mask", 1, 0, '3' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct xt_entry_target *t) +{ + struct ipt_ipmark_target_info *ipmarkinfo = + (struct ipt_ipmark_target_info *)t->data; + + ipmarkinfo->andmask=0xffffffff; + ipmarkinfo->ormask=0; + +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) +{ + struct ipt_ipmark_target_info *ipmarkinfo + = (struct ipt_ipmark_target_info *)(*target)->data; + + switch (c) { + char *end; + case '1': + if(!strcmp(optarg, "src")) ipmarkinfo->addr=IPT_IPMARK_SRC; + else if(!strcmp(optarg, "dst")) ipmarkinfo->addr=IPT_IPMARK_DST; + else exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg); + if (*flags & IPT_ADDR_USED) + exit_error(PARAMETER_PROBLEM, + "IPMARK target: Can't specify --addr twice"); + *flags |= IPT_ADDR_USED; + break; + + case '2': + ipmarkinfo->andmask = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad and-mask value `%s'", optarg); + if (*flags & IPT_AND_MASK_USED) + exit_error(PARAMETER_PROBLEM, + "IPMARK target: Can't specify --and-mask twice"); + *flags |= IPT_AND_MASK_USED; + break; + case '3': + ipmarkinfo->ormask = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad or-mask value `%s'", optarg); + if (*flags & IPT_OR_MASK_USED) + exit_error(PARAMETER_PROBLEM, + "IPMARK target: Can't specify --or-mask twice"); + *flags |= IPT_OR_MASK_USED; + break; + + default: + return 0; + } + + return 1; +} + +static void +final_check(unsigned int flags) +{ + if (!(flags & IPT_ADDR_USED)) + exit_error(PARAMETER_PROBLEM, + "IPMARK target: Parameter --addr is required"); + if (!(flags & (IPT_AND_MASK_USED | IPT_OR_MASK_USED))) + exit_error(PARAMETER_PROBLEM, + "IPMARK target: Parameter --and-mask or --or-mask is required"); +} + +/* Prints out the targinfo. */ +static void +print(const void *entry, const struct xt_entry_target *target, + int numeric) +{ + const struct ipt_ipmark_target_info *ipmarkinfo = + (const struct ipt_ipmark_target_info *)target->data; + + if(ipmarkinfo->addr == IPT_IPMARK_SRC) + printf("IPMARK src"); + else + printf("IPMARK dst"); + printf(" ip and 0x%lx or 0x%lx", ipmarkinfo->andmask, ipmarkinfo->ormask); +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const void *entry, const struct xt_entry_target *target) +{ + const struct ipt_ipmark_target_info *ipmarkinfo = + (const struct ipt_ipmark_target_info *)target->data; + + if(ipmarkinfo->addr == IPT_IPMARK_SRC) + printf("--addr=src "); + else + printf("--addr=dst "); + if(ipmarkinfo->andmask != 0xffffffff) + printf("--and-mask 0x%lx ", ipmarkinfo->andmask); + if(ipmarkinfo->ormask != 0) + printf("--or-mask 0x%lx ", ipmarkinfo->ormask); +} + +static struct xtables_target ipmark = { + .next = NULL, + .name = "IPMARK", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct ipt_ipmark_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct ipt_ipmark_target_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + xtables_register_target(&ipmark); +} diff --git a/extensions/libxt_IPMARK.man b/extensions/libxt_IPMARK.man new file mode 100644 index 0000000..e4659b0 --- /dev/null +++ b/extensions/libxt_IPMARK.man @@ -0,0 +1,45 @@ +Allows you to mark a received packet basing on its IP address. This +can replace many mangle/mark entries with only one, if you use +firewall based classifier. + +This target is to be used inside the mangle table, in the PREROUTING, +POSTROUTING or FORWARD hooks. +.TP +.BI "--addr " "src/dst" +Use source or destination IP address. +.TP +.BI "--and-mask " "mask" +Perform bitwise `and' on the IP address and this mask. +.TP +.BI "--or-mask " "mask" +Perform bitwise `or' on the IP address and this mask. +.P +The order of IP address bytes is reversed to meet "human order of bytes": +192.168.0.1 is 0xc0a80001. At first the `and' operation is performed, then +`or'. + +Examples: + +We create a queue for each user, the queue number is adequate +to the IP address of the user, e.g.: all packets going to/from 192.168.5.2 +are directed to 1:0502 queue, 192.168.5.12 -> 1:050c etc. + +We have one classifier rule: +.IP +tc filter add dev eth3 parent 1:0 protocol ip fw +.P +Earlier we had many rules just like below: +.IP +iptables -t mangle -A POSTROUTING -o eth3 -d 192.168.5.2 -j MARK +--set-mark 0x10502 +.IP +iptables -t mangle -A POSTROUTING -o eth3 -d 192.168.5.3 -j MARK +--set-mark 0x10503 +.P +Using IPMARK target we can replace all the mangle/mark rules with only one: +.IP +iptables -t mangle -A POSTROUTING -o eth3 -j IPMARK --addr=dst +--and-mask=0xffff --or-mask=0x10000 +.P +On the routers with hundreds of users there should be significant load +decrease (e.g. twice). diff --git a/extensions/xt_IPMARK.Kconfig b/extensions/xt_IPMARK.Kconfig new file mode 100644 index 0000000..021cde3 --- /dev/null +++ b/extensions/xt_IPMARK.Kconfig @@ -0,0 +1,12 @@ +config NETFILTER_XT_TARGET_IPMARK + tristate '"IPMARK" target support' + depends on NETFILTER_XTABLES && NETFILTER_ADVANCED + depends on IP_NF_MANGLE || IP6_NF_MANGLE + ---help--- + This option adds an "IPMARK" target, which allows you to create + rules in the "mangle" table which alter the netfilter mark field + basing on the source or destination ip address of the packet. + This is very useful for very fast massive shaping -- using only one + rule you can direct packets to houndreds different queues. You + will probably find it helpful only if your linux machine acts as a + shaper for many others computers. diff --git a/extensions/xt_IPMARK.c b/extensions/xt_IPMARK.c new file mode 100644 index 0000000..07973ef --- /dev/null +++ b/extensions/xt_IPMARK.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +#include +#include "xt_IPMARK.h" +#include "compat_xtables.h" + +MODULE_AUTHOR("Grzegorz Janoszka "); +MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address"); +MODULE_LICENSE("GPL"); + +static unsigned int +ipmark_tg(struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const struct xt_target *target, + const void *targinfo) +{ + const struct ipt_ipmark_target_info *ipmarkinfo = targinfo; + struct iphdr *iph = ip_hdr(skb); + unsigned long mark; + + if (ipmarkinfo->addr == IPT_IPMARK_SRC) + mark = (unsigned long) ntohl(iph->saddr); + else + mark = (unsigned long) ntohl(iph->daddr); + + mark &= ipmarkinfo->andmask; + mark |= ipmarkinfo->ormask; + + skb_nfmark(skb) = mark; + return XT_CONTINUE; +} + +static struct xt_target ipt_ipmark_reg = { + .name = "IPMARK", + .family = AF_INET, + .table = "mangle", + .target = ipmark_tg, + .targetsize = sizeof(struct ipt_ipmark_target_info), + .me = THIS_MODULE +}; + +static int __init ipmark_tg_init(void) +{ + return xt_register_target(&ipt_ipmark_reg); +} + +static void __exit ipmark_tg_exit(void) +{ + xt_unregister_target(&ipt_ipmark_reg); +} + +module_init(ipmark_tg_init); +module_exit(ipmark_tg_exit); diff --git a/extensions/xt_IPMARK.h b/extensions/xt_IPMARK.h new file mode 100644 index 0000000..906115a --- /dev/null +++ b/extensions/xt_IPMARK.h @@ -0,0 +1,13 @@ +#ifndef _IPT_IPMARK_H_target +#define _IPT_IPMARK_H_target + +struct ipt_ipmark_target_info { + unsigned long andmask; + unsigned long ormask; + unsigned char addr; +}; + +#define IPT_IPMARK_SRC 0 +#define IPT_IPMARK_DST 1 + +#endif /*_IPT_IPMARK_H_target*/ diff --git a/mconfig b/mconfig index 38eedba..7b50b1a 100644 --- a/mconfig +++ b/mconfig @@ -3,6 +3,7 @@ build_CHAOS=m build_DELUDE=m build_ECHO= +build_IPMARK=m build_LOGMARK=m build_TARPIT=m build_TEE=m From e037035bd4697978ed2f175b23e8a7a125d02595 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 8 Apr 2008 19:23:07 +0200 Subject: [PATCH 2/9] IPMARK: rebuild parameter structure (fixed-size types) Rebuild the parameter structure to have fixed-size members only. --- extensions/libxt_IPMARK.c | 43 +++++++++++++++++---------------------- extensions/xt_IPMARK.c | 12 +++++------ extensions/xt_IPMARK.h | 20 ++++++++++-------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 4503347..384657b 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -40,12 +40,9 @@ static struct option opts[] = { static void init(struct xt_entry_target *t) { - struct ipt_ipmark_target_info *ipmarkinfo = - (struct ipt_ipmark_target_info *)t->data; - - ipmarkinfo->andmask=0xffffffff; - ipmarkinfo->ormask=0; + struct xt_ipmark_tginfo *info = (void *)t->data; + info->andmask = ~0U; } /* Function which parses command options; returns true if it @@ -54,14 +51,13 @@ static int parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_target **target) { - struct ipt_ipmark_target_info *ipmarkinfo - = (struct ipt_ipmark_target_info *)(*target)->data; + struct xt_ipmark_tginfo *info = (void *)(*target)->data; switch (c) { char *end; case '1': - if(!strcmp(optarg, "src")) ipmarkinfo->addr=IPT_IPMARK_SRC; - else if(!strcmp(optarg, "dst")) ipmarkinfo->addr=IPT_IPMARK_DST; + if(!strcmp(optarg, "src")) info->selector=XT_IPMARK_SRC; + else if(!strcmp(optarg, "dst")) info->selector=XT_IPMARK_DST; else exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg); if (*flags & IPT_ADDR_USED) exit_error(PARAMETER_PROBLEM, @@ -70,7 +66,7 @@ parse(int c, char **argv, int invert, unsigned int *flags, break; case '2': - ipmarkinfo->andmask = strtoul(optarg, &end, 0); + info->andmask = strtoul(optarg, &end, 0); if (*end != '\0' || end == optarg) exit_error(PARAMETER_PROBLEM, "Bad and-mask value `%s'", optarg); if (*flags & IPT_AND_MASK_USED) @@ -79,7 +75,7 @@ parse(int c, char **argv, int invert, unsigned int *flags, *flags |= IPT_AND_MASK_USED; break; case '3': - ipmarkinfo->ormask = strtoul(optarg, &end, 0); + info->ormask = strtoul(optarg, &end, 0); if (*end != '\0' || end == optarg) exit_error(PARAMETER_PROBLEM, "Bad or-mask value `%s'", optarg); if (*flags & IPT_OR_MASK_USED) @@ -111,39 +107,38 @@ static void print(const void *entry, const struct xt_entry_target *target, int numeric) { - const struct ipt_ipmark_target_info *ipmarkinfo = - (const struct ipt_ipmark_target_info *)target->data; + const struct xt_ipmark_tginfo *info = (const void *)target->data; - if(ipmarkinfo->addr == IPT_IPMARK_SRC) + if (info->selector == XT_IPMARK_SRC) printf("IPMARK src"); else printf("IPMARK dst"); - printf(" ip and 0x%lx or 0x%lx", ipmarkinfo->andmask, ipmarkinfo->ormask); + printf(" ip and 0x%x or 0x%x", + (unsigned int)info->andmask, (unsigned int)info->ormask); } /* Saves the union ipt_targinfo in parsable form to stdout. */ static void save(const void *entry, const struct xt_entry_target *target) { - const struct ipt_ipmark_target_info *ipmarkinfo = - (const struct ipt_ipmark_target_info *)target->data; + const struct xt_ipmark_tginfo *info = (const void *)target->data; - if(ipmarkinfo->addr == IPT_IPMARK_SRC) + if (info->selector == XT_IPMARK_SRC) printf("--addr=src "); else printf("--addr=dst "); - if(ipmarkinfo->andmask != 0xffffffff) - printf("--and-mask 0x%lx ", ipmarkinfo->andmask); - if(ipmarkinfo->ormask != 0) - printf("--or-mask 0x%lx ", ipmarkinfo->ormask); + if (info->andmask != ~0U) + printf("--and-mask 0x%x ", (unsigned int)info->andmask); + if (info->ormask != 0) + printf("--or-mask 0x%x ", (unsigned int)info->ormask); } static struct xtables_target ipmark = { .next = NULL, .name = "IPMARK", .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct ipt_ipmark_target_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_ipmark_target_info)), + .size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), .help = &help, .init = &init, .parse = &parse, diff --git a/extensions/xt_IPMARK.c b/extensions/xt_IPMARK.c index 07973ef..4db5258 100644 --- a/extensions/xt_IPMARK.c +++ b/extensions/xt_IPMARK.c @@ -20,14 +20,14 @@ ipmark_tg(struct sk_buff *skb, const struct xt_target *target, const void *targinfo) { - const struct ipt_ipmark_target_info *ipmarkinfo = targinfo; + const struct xt_ipmark_tginfo *ipmarkinfo = targinfo; struct iphdr *iph = ip_hdr(skb); - unsigned long mark; + __u32 mark; - if (ipmarkinfo->addr == IPT_IPMARK_SRC) - mark = (unsigned long) ntohl(iph->saddr); + if (ipmarkinfo->selector == XT_IPMARK_SRC) + mark = ntohl(iph->saddr); else - mark = (unsigned long) ntohl(iph->daddr); + mark = ntohl(iph->daddr); mark &= ipmarkinfo->andmask; mark |= ipmarkinfo->ormask; @@ -41,7 +41,7 @@ static struct xt_target ipt_ipmark_reg = { .family = AF_INET, .table = "mangle", .target = ipmark_tg, - .targetsize = sizeof(struct ipt_ipmark_target_info), + .targetsize = sizeof(struct xt_ipmark_tginfo), .me = THIS_MODULE }; diff --git a/extensions/xt_IPMARK.h b/extensions/xt_IPMARK.h index 906115a..121e06a 100644 --- a/extensions/xt_IPMARK.h +++ b/extensions/xt_IPMARK.h @@ -1,13 +1,15 @@ -#ifndef _IPT_IPMARK_H_target -#define _IPT_IPMARK_H_target +#ifndef _LINUX_NETFILTER_XT_IPMARK_H +#define _LINUX_NETFILTER_XT_IPMARK_H 1 -struct ipt_ipmark_target_info { - unsigned long andmask; - unsigned long ormask; - unsigned char addr; +enum { + XT_IPMARK_SRC, + XT_IPMARK_DST, }; -#define IPT_IPMARK_SRC 0 -#define IPT_IPMARK_DST 1 +struct xt_ipmark_tginfo { + __u32 andmask; + __u32 ormask; + __u8 selector; +}; -#endif /*_IPT_IPMARK_H_target*/ +#endif /* _LINUX_NETFILTER_XT_IPMARK_H */ From 3bf45b60b202adde1ef85f1183cd7fba77cfd41e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 8 Apr 2008 19:52:31 +0200 Subject: [PATCH 3/9] IPMARK: misc cleanups - order #include lists - const annotations, removal of casts - add ipt_IPMARK alias - make symbol names distinct --- extensions/libxt_IPMARK.c | 60 +++++++++++++++++---------------------- extensions/xt_IPMARK.c | 8 +++--- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 384657b..25e9025 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -5,11 +5,10 @@ * * This program is distributed under the terms of GNU GPL */ -#include -#include -#include #include - +#include +#include +#include #include #include "xt_IPMARK.h" @@ -18,8 +17,7 @@ #define IPT_OR_MASK_USED 4 /* Function which prints out usage message. */ -static void -help(void) +static void ipmark_tg_help(void) { printf( "IPMARK target options:\n" @@ -29,27 +27,23 @@ help(void) "\n"); } -static struct option opts[] = { +static const struct option ipmark_tg_opts[] = { { "addr", 1, 0, '1' }, { "and-mask", 1, 0, '2' }, { "or-mask", 1, 0, '3' }, - { 0 } + {NULL}, }; /* Initialize the target. */ -static void -init(struct xt_entry_target *t) +static void ipmark_tg_init(struct xt_entry_target *t) { struct xt_ipmark_tginfo *info = (void *)t->data; info->andmask = ~0U; } -/* Function which parses command options; returns true if it - ate an option */ -static int -parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) { struct xt_ipmark_tginfo *info = (void *)(*target)->data; @@ -91,8 +85,7 @@ parse(int c, char **argv, int invert, unsigned int *flags, return 1; } -static void -final_check(unsigned int flags) +static void ipmark_tg_check(unsigned int flags) { if (!(flags & IPT_ADDR_USED)) exit_error(PARAMETER_PROBLEM, @@ -102,10 +95,9 @@ final_check(unsigned int flags) "IPMARK target: Parameter --and-mask or --or-mask is required"); } -/* Prints out the targinfo. */ static void -print(const void *entry, const struct xt_entry_target *target, - int numeric) +ipmark_tg_print(const void *entry, const struct xt_entry_target *target, + int numeric) { const struct xt_ipmark_tginfo *info = (const void *)target->data; @@ -117,9 +109,8 @@ print(const void *entry, const struct xt_entry_target *target, (unsigned int)info->andmask, (unsigned int)info->ormask); } -/* Saves the union ipt_targinfo in parsable form to stdout. */ static void -save(const void *entry, const struct xt_entry_target *target) +ipmark_tg_save(const void *entry, const struct xt_entry_target *target) { const struct xt_ipmark_tginfo *info = (const void *)target->data; @@ -133,22 +124,23 @@ save(const void *entry, const struct xt_entry_target *target) printf("--or-mask 0x%x ", (unsigned int)info->ormask); } -static struct xtables_target ipmark = { - .next = NULL, - .name = "IPMARK", +static struct xtables_target ipmark_tg4_reg = { .version = XTABLES_VERSION, + .name = "IPMARK", + .family = PF_INET, + .revision = 0, .size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), - .help = &help, - .init = &init, - .parse = &parse, - .final_check = &final_check, - .print = &print, - .save = &save, - .extra_opts = opts + .help = ipmark_tg_help, + .init = ipmark_tg_init, + .parse = ipmark_tg_parse, + .final_check = ipmark_tg_check, + .print = ipmark_tg_print, + .save = ipmark_tg_save, + .extra_opts = ipmark_tg_opts, }; -void _init(void) +static void _init(void) { - xtables_register_target(&ipmark); + xtables_register_target(&ipmark_tg4_reg); } diff --git a/extensions/xt_IPMARK.c b/extensions/xt_IPMARK.c index 4db5258..e25bfe6 100644 --- a/extensions/xt_IPMARK.c +++ b/extensions/xt_IPMARK.c @@ -1,16 +1,16 @@ +#include #include #include #include -#include -#include - #include +#include #include "xt_IPMARK.h" #include "compat_xtables.h" MODULE_AUTHOR("Grzegorz Janoszka "); MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_IPMARK"); static unsigned int ipmark_tg(struct sk_buff *skb, @@ -21,7 +21,7 @@ ipmark_tg(struct sk_buff *skb, const void *targinfo) { const struct xt_ipmark_tginfo *ipmarkinfo = targinfo; - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); __u32 mark; if (ipmarkinfo->selector == XT_IPMARK_SRC) From 59ef68feccd6070238bf07b8832f64768a9ed131 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 9 Apr 2008 19:21:20 +0200 Subject: [PATCH 4/9] IPMARK: remove incorrect --and/--or check It is perfectly valid for no --and-mask and also no --or-mask to appear, in which case the IP(v4) address is taken as mark without modification. --- extensions/libxt_IPMARK.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 25e9025..3f47c20 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -90,9 +90,6 @@ static void ipmark_tg_check(unsigned int flags) if (!(flags & IPT_ADDR_USED)) exit_error(PARAMETER_PROBLEM, "IPMARK target: Parameter --addr is required"); - if (!(flags & (IPT_AND_MASK_USED | IPT_OR_MASK_USED))) - exit_error(PARAMETER_PROBLEM, - "IPMARK target: Parameter --and-mask or --or-mask is required"); } static void From 4b8ec990b8d736c63af66464a6254d6c8c2fb11b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 9 Apr 2008 14:44:24 +0200 Subject: [PATCH 5/9] IPMARK: omit printing unset mask --- extensions/libxt_IPMARK.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 3f47c20..0009a18 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -99,11 +99,14 @@ ipmark_tg_print(const void *entry, const struct xt_entry_target *target, const struct xt_ipmark_tginfo *info = (const void *)target->data; if (info->selector == XT_IPMARK_SRC) - printf("IPMARK src"); + printf("IPMARK src ip"); else - printf("IPMARK dst"); - printf(" ip and 0x%x or 0x%x", - (unsigned int)info->andmask, (unsigned int)info->ormask); + printf("IPMARK dst ip"); + + if (info->andmask != ~0U) + printf(" and 0x%x ", (unsigned int)info->andmask); + if (info->ormask != 0) + printf(" or 0x%x ", (unsigned int)info->ormask); } static void From b63ac3be458675a812c8db6e20fc325311bd34c6 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 9 Apr 2008 14:44:53 +0200 Subject: [PATCH 6/9] IPMARK: print --addr flag the usual way --- extensions/libxt_IPMARK.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 0009a18..47e09d0 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -115,9 +115,10 @@ ipmark_tg_save(const void *entry, const struct xt_entry_target *target) const struct xt_ipmark_tginfo *info = (const void *)target->data; if (info->selector == XT_IPMARK_SRC) - printf("--addr=src "); + printf("--addr src "); else - printf("--addr=dst "); + printf("--addr dst "); + if (info->andmask != ~0U) printf("--and-mask 0x%x ", (unsigned int)info->andmask); if (info->ormask != 0) From 2c7b1d5330025c6443f436b362f1dcb33a39a594 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 8 Apr 2008 20:00:40 +0200 Subject: [PATCH 7/9] IPMARK: IPv6 support --- extensions/libxt_IPMARK.c | 36 +++++++++++++++++ extensions/libxt_IPMARK.man | 12 ++++++ extensions/xt_IPMARK.c | 77 +++++++++++++++++++++++++++++-------- extensions/xt_IPMARK.h | 1 + 4 files changed, 111 insertions(+), 15 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 47e09d0..91210dd 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -16,6 +16,10 @@ #define IPT_AND_MASK_USED 2 #define IPT_OR_MASK_USED 4 +enum { + FL_SHIFT = 1 << 3, +}; + /* Function which prints out usage message. */ static void ipmark_tg_help(void) { @@ -24,6 +28,7 @@ static void ipmark_tg_help(void) " --addr src/dst use source or destination ip address\n" " --and-mask value logical AND ip address with this value becomes MARK\n" " --or-mask value logical OR ip address with this value becomes MARK\n" +" --shift value shift address right by value before copying to mark\n" "\n"); } @@ -31,6 +36,7 @@ static const struct option ipmark_tg_opts[] = { { "addr", 1, 0, '1' }, { "and-mask", 1, 0, '2' }, { "or-mask", 1, 0, '3' }, + {.name = "shift", .has_arg = true, .val = '4'}, {NULL}, }; @@ -46,6 +52,7 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_target **target) { struct xt_ipmark_tginfo *info = (void *)(*target)->data; + unsigned int n; switch (c) { char *end; @@ -78,6 +85,18 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, *flags |= IPT_OR_MASK_USED; break; + case '4': + param_act(P_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT); + param_act(P_NO_INVERT, "IPMARK", "--shift", invert); + /* + * Anything >31 does not make sense for IPv4, but it still + * does the right thing. + */ + if (!strtonum(optarg, NULL, &n, 0, 128)) + param_act(P_BAD_VALUE, "IPMARK", "--shift", optarg); + info->shift = n; + return true; + default: return 0; } @@ -141,7 +160,24 @@ static struct xtables_target ipmark_tg4_reg = { .extra_opts = ipmark_tg_opts, }; +static struct xtables_target ipmark_tg6_reg = { + .version = XTABLES_VERSION, + .name = "IPMARK", + .family = PF_INET6, + .revision = 0, + .size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), + .help = ipmark_tg_help, + .init = ipmark_tg_init, + .parse = ipmark_tg_parse, + .final_check = ipmark_tg_check, + .print = ipmark_tg_print, + .save = ipmark_tg_save, + .extra_opts = ipmark_tg_opts, +}; + static void _init(void) { xtables_register_target(&ipmark_tg4_reg); + xtables_register_target(&ipmark_tg6_reg); } diff --git a/extensions/libxt_IPMARK.man b/extensions/libxt_IPMARK.man index e4659b0..8ab0334 100644 --- a/extensions/libxt_IPMARK.man +++ b/extensions/libxt_IPMARK.man @@ -13,6 +13,11 @@ Perform bitwise `and' on the IP address and this mask. .TP .BI "--or-mask " "mask" Perform bitwise `or' on the IP address and this mask. +.TP +\fB--shift\fP \fIvalue\fP +Shift addresses to the right by the given number of bits before taking it +as a mark. (This is done before ANDing or ORing it.) This option is needed +to select part of an IPv6 address, because marks are only 32 bits in size. .P The order of IP address bytes is reversed to meet "human order of bytes": 192.168.0.1 is 0xc0a80001. At first the `and' operation is performed, then @@ -43,3 +48,10 @@ iptables -t mangle -A POSTROUTING -o eth3 -j IPMARK --addr=dst .P On the routers with hundreds of users there should be significant load decrease (e.g. twice). +.PP +(IPv6 example) If the source address is of the form +2001:db8:45:1d:20d:93ff:fe9b:e443 and the resulting mark should be 0x93ff, +then a right-shift of 16 is needed first: +.IP +-t mangle -A PREROUTING -s 2001:db8::/32 -j IPMARK --addr src --shift 16 +--and-mask 0xFFFF diff --git a/extensions/xt_IPMARK.c b/extensions/xt_IPMARK.c index e25bfe6..b64131a 100644 --- a/extensions/xt_IPMARK.c +++ b/extensions/xt_IPMARK.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,14 +12,12 @@ MODULE_AUTHOR("Grzegorz Janoszka "); MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_IPMARK"); +MODULE_ALIAS("ip6t_IPMARK"); static unsigned int -ipmark_tg(struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const struct xt_target *target, - const void *targinfo) +ipmark_tg4(struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo) { const struct xt_ipmark_tginfo *ipmarkinfo = targinfo; const struct iphdr *iph = ip_hdr(skb); @@ -29,6 +28,7 @@ ipmark_tg(struct sk_buff *skb, else mark = ntohl(iph->daddr); + mark >>= ipmarkinfo->shift; mark &= ipmarkinfo->andmask; mark |= ipmarkinfo->ormask; @@ -36,23 +36,70 @@ ipmark_tg(struct sk_buff *skb, return XT_CONTINUE; } -static struct xt_target ipt_ipmark_reg = { - .name = "IPMARK", - .family = AF_INET, - .table = "mangle", - .target = ipmark_tg, - .targetsize = sizeof(struct xt_ipmark_tginfo), - .me = THIS_MODULE +/* Function is safe for any value of @s */ +static __u32 ipmark_from_ip6(const struct in6_addr *a, unsigned int s) +{ + unsigned int q = s % 32; + __u32 mask; + + if (s >= 128) + return 0; + + mask = ntohl(a->s6_addr32[3 - s/32]) >> q; + if (s > 0 && s < 96 && q != 0) + mask |= ntohl(a->s6_addr32[2 - s/32]) << (32 - q); + return mask; +} + +static unsigned int +ipmark_tg6(struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo) +{ + const struct xt_ipmark_tginfo *info = targinfo; + const struct ipv6hdr *iph = ipv6_hdr(skb); + __u32 mark; + + if (info->selector == XT_IPMARK_SRC) + mark = ipmark_from_ip6(&iph->saddr, info->shift); + else + mark = ipmark_from_ip6(&iph->daddr, info->shift); + + mark &= info->andmask; + mark |= info->ormask; + skb_nfmark(skb) = mark; + return XT_CONTINUE; +} + +static struct xt_target ipmark_tg_reg[] __read_mostly = { + { + .name = "IPMARK", + .revision = 0, + .family = PF_INET, + .table = "mangle", + .target = ipmark_tg4, + .targetsize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), + .me = THIS_MODULE, + }, + { + .name = "IPMARK", + .revision = 0, + .family = PF_INET6, + .table = "mangle", + .target = ipmark_tg6, + .targetsize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), + .me = THIS_MODULE, + }, }; static int __init ipmark_tg_init(void) { - return xt_register_target(&ipt_ipmark_reg); + return xt_register_targets(ipmark_tg_reg, ARRAY_SIZE(ipmark_tg_reg)); } static void __exit ipmark_tg_exit(void) { - xt_unregister_target(&ipt_ipmark_reg); + xt_unregister_targets(ipmark_tg_reg, ARRAY_SIZE(ipmark_tg_reg)); } module_init(ipmark_tg_init); diff --git a/extensions/xt_IPMARK.h b/extensions/xt_IPMARK.h index 121e06a..67da4e5 100644 --- a/extensions/xt_IPMARK.h +++ b/extensions/xt_IPMARK.h @@ -10,6 +10,7 @@ struct xt_ipmark_tginfo { __u32 andmask; __u32 ormask; __u8 selector; + __u8 shift; }; #endif /* _LINUX_NETFILTER_XT_IPMARK_H */ From 03eeabb4bd56c68d13a8e0c2e8a11974190c5da1 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 9 Apr 2008 14:04:23 +0200 Subject: [PATCH 8/9] IPMARK: style cleanup --- extensions/libxt_IPMARK.c | 48 ++++++++++++++++++++------------------- extensions/xt_IPMARK.c | 2 +- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 91210dd..5ce8930 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -12,12 +12,11 @@ #include #include "xt_IPMARK.h" -#define IPT_ADDR_USED 1 -#define IPT_AND_MASK_USED 2 -#define IPT_OR_MASK_USED 4 - enum { - FL_SHIFT = 1 << 3, + FL_ADDR_USED = 1 << 0, + FL_AND_MASK_USED = 1 << 1, + FL_OR_MASK_USED = 1 << 2, + FL_SHIFT = 1 << 3, }; /* Function which prints out usage message. */ @@ -25,17 +24,17 @@ static void ipmark_tg_help(void) { printf( "IPMARK target options:\n" -" --addr src/dst use source or destination ip address\n" -" --and-mask value logical AND ip address with this value becomes MARK\n" -" --or-mask value logical OR ip address with this value becomes MARK\n" -" --shift value shift address right by value before copying to mark\n" +" --addr {src|dst} use source or destination ip address\n" +" --and-mask value logical AND ip address with this value becomes MARK\n" +" --or-mask value logical OR ip address with this value becomes MARK\n" +" --shift value shift address right by value before copying to mark\n" "\n"); } static const struct option ipmark_tg_opts[] = { - { "addr", 1, 0, '1' }, - { "and-mask", 1, 0, '2' }, - { "or-mask", 1, 0, '3' }, + {.name = "addr", .has_arg = true, .val = '1'}, + {.name = "and-mask", .has_arg = true, .val = '2'}, + {.name = "or-mask", .has_arg = true, .val = '3'}, {.name = "shift", .has_arg = true, .val = '4'}, {NULL}, }; @@ -53,36 +52,39 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, { struct xt_ipmark_tginfo *info = (void *)(*target)->data; unsigned int n; + char *end; switch (c) { - char *end; case '1': - if(!strcmp(optarg, "src")) info->selector=XT_IPMARK_SRC; - else if(!strcmp(optarg, "dst")) info->selector=XT_IPMARK_DST; - else exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg); - if (*flags & IPT_ADDR_USED) + if (strcmp(optarg, "src") == 0) + info->selector = XT_IPMARK_SRC; + else if (strcmp(optarg, "dst") == 0) + info->selector = XT_IPMARK_DST; + else + exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg); + if (*flags & FL_ADDR_USED) exit_error(PARAMETER_PROBLEM, "IPMARK target: Can't specify --addr twice"); - *flags |= IPT_ADDR_USED; + *flags |= FL_ADDR_USED; break; case '2': info->andmask = strtoul(optarg, &end, 0); if (*end != '\0' || end == optarg) exit_error(PARAMETER_PROBLEM, "Bad and-mask value `%s'", optarg); - if (*flags & IPT_AND_MASK_USED) + if (*flags & FL_AND_MASK_USED) exit_error(PARAMETER_PROBLEM, "IPMARK target: Can't specify --and-mask twice"); - *flags |= IPT_AND_MASK_USED; + *flags |= FL_AND_MASK_USED; break; case '3': info->ormask = strtoul(optarg, &end, 0); if (*end != '\0' || end == optarg) exit_error(PARAMETER_PROBLEM, "Bad or-mask value `%s'", optarg); - if (*flags & IPT_OR_MASK_USED) + if (*flags & FL_OR_MASK_USED) exit_error(PARAMETER_PROBLEM, "IPMARK target: Can't specify --or-mask twice"); - *flags |= IPT_OR_MASK_USED; + *flags |= FL_OR_MASK_USED; break; case '4': @@ -106,7 +108,7 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, static void ipmark_tg_check(unsigned int flags) { - if (!(flags & IPT_ADDR_USED)) + if (!(flags & FL_ADDR_USED)) exit_error(PARAMETER_PROBLEM, "IPMARK target: Parameter --addr is required"); } diff --git a/extensions/xt_IPMARK.c b/extensions/xt_IPMARK.c index b64131a..264e4c1 100644 --- a/extensions/xt_IPMARK.c +++ b/extensions/xt_IPMARK.c @@ -9,7 +9,7 @@ #include "compat_xtables.h" MODULE_AUTHOR("Grzegorz Janoszka "); -MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address"); +MODULE_DESCRIPTION("Xtables: mark based on IP address"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_IPMARK"); MODULE_ALIAS("ip6t_IPMARK"); From 1060138f7787cd085d5ac1baefd65067f8e8d71a Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 9 Apr 2008 14:39:44 +0200 Subject: [PATCH 9/9] IPMARK: redo ipmark_tg_parse() - check for illegal inversion on flags - use param_act() and strtonum() instead of open-coded checks --- extensions/libxt_IPMARK.c | 40 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/extensions/libxt_IPMARK.c b/extensions/libxt_IPMARK.c index 5ce8930..d0e8d22 100644 --- a/extensions/libxt_IPMARK.c +++ b/extensions/libxt_IPMARK.c @@ -52,40 +52,37 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, { struct xt_ipmark_tginfo *info = (void *)(*target)->data; unsigned int n; - char *end; switch (c) { case '1': + param_act(P_ONLY_ONCE, "IPMARK", "addr", *flags & FL_ADDR_USED); + param_act(P_NO_INVERT, "IPMARK", "addr", invert); if (strcmp(optarg, "src") == 0) info->selector = XT_IPMARK_SRC; else if (strcmp(optarg, "dst") == 0) info->selector = XT_IPMARK_DST; else exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg); - if (*flags & FL_ADDR_USED) - exit_error(PARAMETER_PROBLEM, - "IPMARK target: Can't specify --addr twice"); *flags |= FL_ADDR_USED; - break; + return true; case '2': - info->andmask = strtoul(optarg, &end, 0); - if (*end != '\0' || end == optarg) - exit_error(PARAMETER_PROBLEM, "Bad and-mask value `%s'", optarg); - if (*flags & FL_AND_MASK_USED) - exit_error(PARAMETER_PROBLEM, - "IPMARK target: Can't specify --and-mask twice"); + param_act(P_ONLY_ONCE, "IPMARK", "and-mask", *flags & FL_AND_MASK_USED); + param_act(P_NO_INVERT, "IPMARK", "and-mask", invert); + if (!strtonum(optarg, NULL, &n, 0, ~0U)) + param_act(P_BAD_VALUE, "IPMARK", "and-mask", optarg); + info->andmask = n; *flags |= FL_AND_MASK_USED; - break; + return true; + case '3': - info->ormask = strtoul(optarg, &end, 0); - if (*end != '\0' || end == optarg) - exit_error(PARAMETER_PROBLEM, "Bad or-mask value `%s'", optarg); - if (*flags & FL_OR_MASK_USED) - exit_error(PARAMETER_PROBLEM, - "IPMARK target: Can't specify --or-mask twice"); + param_act(P_ONLY_ONCE, "IPMARK", "or-mask", *flags & FL_OR_MASK_USED); + param_act(P_NO_INVERT, "IPMARK", "or-mask", invert); + if (!strtonum(optarg, NULL, &n, 0, ~0U)) + param_act(P_BAD_VALUE, "IPMARK", "or-mask", optarg); + info->ormask = n; *flags |= FL_OR_MASK_USED; - break; + return true; case '4': param_act(P_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT); @@ -98,12 +95,9 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags, param_act(P_BAD_VALUE, "IPMARK", "--shift", optarg); info->shift = n; return true; - - default: - return 0; } - return 1; + return false; } static void ipmark_tg_check(unsigned int flags)