Merge reworked "IPMARK" target

This commit is contained in:
Jan Engelhardt
2008-04-09 19:44:54 +02:00
8 changed files with 373 additions and 0 deletions

View File

@@ -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

View File

@@ -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

179
extensions/libxt_IPMARK.c Normal file
View File

@@ -0,0 +1,179 @@
/* Shared library add-on to iptables to add IPMARK target support.
* (C) 2003 by Grzegorz Janoszka <Grzegorz.Janoszka@pro.onet.pl>
*
* based on original MARK target
*
* This program is distributed under the terms of GNU GPL
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xtables.h>
#include "xt_IPMARK.h"
enum {
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. */
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"
"\n");
}
static const struct option ipmark_tg_opts[] = {
{.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},
};
/* Initialize the target. */
static void ipmark_tg_init(struct xt_entry_target *t)
{
struct xt_ipmark_tginfo *info = (void *)t->data;
info->andmask = ~0U;
}
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) {
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);
*flags |= FL_ADDR_USED;
return true;
case '2':
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;
return true;
case '3':
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;
return true;
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;
}
return false;
}
static void ipmark_tg_check(unsigned int flags)
{
if (!(flags & FL_ADDR_USED))
exit_error(PARAMETER_PROBLEM,
"IPMARK target: Parameter --addr is required");
}
static void
ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
const struct xt_ipmark_tginfo *info = (const void *)target->data;
if (info->selector == XT_IPMARK_SRC)
printf("IPMARK src ip");
else
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
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 ");
else
printf("--addr dst ");
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_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 = 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 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);
}

View File

@@ -0,0 +1,57 @@
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.
.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
`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).
.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

View File

@@ -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.

106
extensions/xt_IPMARK.c Normal file
View File

@@ -0,0 +1,106 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <linux/netfilter/x_tables.h>
#include <net/checksum.h>
#include "xt_IPMARK.h"
#include "compat_xtables.h"
MODULE_AUTHOR("Grzegorz Janoszka <Grzegorz@Janoszka.pl>");
MODULE_DESCRIPTION("Xtables: mark based on IP address");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_IPMARK");
MODULE_ALIAS("ip6t_IPMARK");
static unsigned int
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);
__u32 mark;
if (ipmarkinfo->selector == XT_IPMARK_SRC)
mark = ntohl(iph->saddr);
else
mark = ntohl(iph->daddr);
mark >>= ipmarkinfo->shift;
mark &= ipmarkinfo->andmask;
mark |= ipmarkinfo->ormask;
skb_nfmark(skb) = mark;
return XT_CONTINUE;
}
/* 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_targets(ipmark_tg_reg, ARRAY_SIZE(ipmark_tg_reg));
}
static void __exit ipmark_tg_exit(void)
{
xt_unregister_targets(ipmark_tg_reg, ARRAY_SIZE(ipmark_tg_reg));
}
module_init(ipmark_tg_init);
module_exit(ipmark_tg_exit);

16
extensions/xt_IPMARK.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _LINUX_NETFILTER_XT_IPMARK_H
#define _LINUX_NETFILTER_XT_IPMARK_H 1
enum {
XT_IPMARK_SRC,
XT_IPMARK_DST,
};
struct xt_ipmark_tginfo {
__u32 andmask;
__u32 ormask;
__u8 selector;
__u8 shift;
};
#endif /* _LINUX_NETFILTER_XT_IPMARK_H */

View File

@@ -3,6 +3,7 @@
build_CHAOS=m
build_DELUDE=m
build_ECHO=
build_IPMARK=m
build_LOGMARK=m
build_TARPIT=m
build_TEE=m