diff options
Diffstat (limited to 'net/ipv4/netfilter/ipt_TOS.c')
-rw-r--r-- | net/ipv4/netfilter/ipt_TOS.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c new file mode 100644 index 000000000000..85c70d240f8b --- /dev/null +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -0,0 +1,105 @@ +/* This is a module which is used for setting the TOS field of a packet. */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <net/checksum.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_TOS.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); +MODULE_DESCRIPTION("iptables TOS mangling module"); + +static unsigned int +target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) +{ + const struct ipt_tos_target_info *tosinfo = targinfo; + + if (((*pskb)->nh.iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { + u_int16_t diffs[2]; + + if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) + return NF_DROP; + + diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF; + (*pskb)->nh.iph->tos + = ((*pskb)->nh.iph->tos & IPTOS_PREC_MASK) + | tosinfo->tos; + diffs[1] = htons((*pskb)->nh.iph->tos); + (*pskb)->nh.iph->check + = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + (*pskb)->nh.iph->check + ^0xFFFF)); + (*pskb)->nfcache |= NFC_ALTERED; + } + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tos_target_info))) { + printk(KERN_WARNING "TOS: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_tos_target_info))); + return 0; + } + + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "TOS: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (tos != IPTOS_LOWDELAY + && tos != IPTOS_THROUGHPUT + && tos != IPTOS_RELIABILITY + && tos != IPTOS_MINCOST + && tos != IPTOS_NORMALSVC) { + printk(KERN_WARNING "TOS: bad tos value %#x\n", tos); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_tos_reg = { + .name = "TOS", + .target = target, + .checkentry = checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ipt_register_target(&ipt_tos_reg); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_tos_reg); +} + +module_init(init); +module_exit(fini); |