diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-01-26 03:31:19.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ip_conntrack.h 2004-01-30 12:25:22.000000000 +0100 @@ -206,6 +206,9 @@ } nat; #endif /* CONFIG_IP_NF_NAT_NEEDED */ +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + unsigned long mark; +#endif }; /* get master conntrack via master expectation */ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_CONNMARK.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_CONNMARK.h 2004-01-30 12:25:22.000000000 +0100 @@ -0,0 +1,15 @@ +#ifndef _IPT_CONNMARK_H_target +#define _IPT_CONNMARK_H_target + +enum { + IPT_CONNMARK_SET = 0, + IPT_CONNMARK_SAVE, + IPT_CONNMARK_RESTORE +}; + +struct ipt_connmark_target_info { + unsigned long mark; + u_int8_t mode; +}; + +#endif /*_IPT_CONNMARK_H_target*/ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_TTL.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_TTL.h 2004-01-30 12:25:07.000000000 +0100 @@ -0,0 +1,21 @@ +/* TTL modification module for IP tables + * (C) 2000 by Harald Welte */ + +#ifndef _IPT_TTL_H +#define _IPT_TTL_H + +enum { + IPT_TTL_SET = 0, + IPT_TTL_INC, + IPT_TTL_DEC +}; + +#define IPT_TTL_MAXMODE IPT_TTL_DEC + +struct ipt_TTL_info { + u_int8_t mode; + u_int8_t ttl; +}; + + +#endif diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-01-30 12:25:34.000000000 +0100 @@ -0,0 +1,12 @@ +#ifndef _IPT_CONNLIMIT_H +#define _IPT_CONNLIMIT_H + +struct ipt_connlimit_data; + +struct ipt_connlimit_info { + int limit; + int inverse; + u_int32_t mask; + struct ipt_connlimit_data *data; +}; +#endif /* _IPT_CONNLIMIT_H */ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_connmark.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_connmark.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_connmark.h 2004-01-30 12:25:22.000000000 +0100 @@ -0,0 +1,9 @@ +#ifndef _IPT_CONNMARK_H +#define _IPT_CONNMARK_H + +struct ipt_connmark_info { + unsigned long mark, mask; + u_int8_t invert; +}; + +#endif /*_IPT_CONNMARK_H*/ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_mport.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_mport.h 2004-01-30 12:25:56.000000000 +0100 @@ -0,0 +1,24 @@ +#ifndef _IPT_MPORT_H +#define _IPT_MPORT_H +#include + +#define IPT_MPORT_SOURCE (1<<0) +#define IPT_MPORT_DESTINATION (1<<1) +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION) + +#define IPT_MULTI_PORTS 15 + +/* Must fit inside union ipt_matchinfo: 32 bytes */ +/* every entry in ports[] except for the last one has one bit in pflags + * associated with it. If this bit is set, the port is the first port of + * a portrange, with the next entry being the last. + * End of list is marked with pflags bit set and port=65535. + * If 14 ports are used (last one does not have a pflag), the last port + * is repeated to fill the last entry in ports[] */ +struct ipt_mport +{ + u_int8_t flags:2; /* Type of comparison */ + u_int16_t pflags:14; /* Port flags */ + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ +}; +#endif /*_IPT_MPORT_H*/ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_nth.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_nth.h 2004-01-30 12:26:19.000000000 +0100 @@ -0,0 +1,19 @@ +#ifndef _IPT_NTH_H +#define _IPT_NTH_H + +#include +#include + +#ifndef IPT_NTH_NUM_COUNTERS +#define IPT_NTH_NUM_COUNTERS 16 +#endif + +struct ipt_nth_info { + u_int8_t every; + u_int8_t not; + u_int8_t startat; + u_int8_t counter; + u_int8_t packet; +}; + +#endif /*_IPT_NTH_H*/ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_u32.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv4/ipt_u32.h 2004-01-30 12:25:44.000000000 +0100 @@ -0,0 +1,40 @@ +#ifndef _IPT_U32_H +#define _IPT_U32_H +#include + +enum ipt_u32_ops +{ + IPT_U32_AND, + IPT_U32_LEFTSH, + IPT_U32_RIGHTSH, + IPT_U32_AT +}; + +struct ipt_u32_location_element +{ + u_int32_t number; + u_int8_t nextop; +}; +struct ipt_u32_value_element +{ + u_int32_t min; + u_int32_t max; +}; +/* *** any way to allow for an arbitrary number of elements? + for now I settle for a limit of 10 of each */ +#define U32MAXSIZE 10 +struct ipt_u32_test +{ + u_int8_t nnums; + struct ipt_u32_location_element location[U32MAXSIZE+1]; + u_int8_t nvalues; + struct ipt_u32_value_element value[U32MAXSIZE+1]; +}; + +struct ipt_u32 +{ + u_int8_t ntests; + struct ipt_u32_test tests[U32MAXSIZE+1]; +}; + +#endif /*_IPT_U32_H*/ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.2-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-01-26 03:29:50.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-01-30 12:26:08.000000000 +0100 @@ -2,15 +2,17 @@ #define _IP6T_REJECT_H enum ip6t_reject_with { - IP6T_ICMP_NET_UNREACHABLE, - IP6T_ICMP_HOST_UNREACHABLE, - IP6T_ICMP_PROT_UNREACHABLE, - IP6T_ICMP_PORT_UNREACHABLE, - IP6T_ICMP_ECHOREPLY + IP6T_ICMP6_NO_ROUTE, + IP6T_ICMP6_ADM_PROHIBITED, + IP6T_ICMP6_NOT_NEIGHBOUR, + IP6T_ICMP6_ADDR_UNREACH, + IP6T_ICMP6_PORT_UNREACH, + IP6T_ICMP6_ECHOREPLY, + IP6T_TCP_RESET }; struct ip6t_reject_info { enum ip6t_reject_with with; /* reject type */ }; -#endif /*_IPT_REJECT_H*/ +#endif /*_IP6T_REJECT_H*/ diff -Nur linux-2.6.2-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.2-rc2/include/linux/netfilter_ipv6/ip6t_nth.h --- linux-2.6.2-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/include/linux/netfilter_ipv6/ip6t_nth.h 2004-01-30 12:26:19.000000000 +0100 @@ -0,0 +1,19 @@ +#ifndef _IP6T_NTH_H +#define _IP6T_NTH_H + +#include +#include + +#ifndef IP6T_NTH_NUM_COUNTERS +#define IP6T_NTH_NUM_COUNTERS 16 +#endif + +struct ip6t_nth_info { + u_int8_t every; + u_int8_t not; + u_int8_t startat; + u_int8_t counter; + u_int8_t packet; +}; + +#endif /*_IP6T_NTH_H*/ diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.2-rc2/net/ipv4/netfilter/Kconfig --- linux-2.6.2-rc2.org/net/ipv4/netfilter/Kconfig 2004-01-26 03:31:15.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/Kconfig 2004-01-30 12:26:19.000000000 +0100 @@ -579,5 +579,140 @@ To compile it as a module, choose M here. If unsure, say N. +config IP_NF_TARGET_TTL + tristate 'TTL target support' + depends on IP_NF_MANGLE + help + This adds an iptables TTL manipulation target, which enables the user + to set the TTL value of an IP packet or to increment / decrement it + by a given value. + +config IP_NF_CONNTRACK_MARK + bool 'Connection mark tracking support' +config IP_NF_TARGET_CONNMARK + tristate 'CONNMARK target support' + depends on IP_NF_MANGLE +config IP_NF_MATCH_CONNMARK + tristate ' Connection mark match support' + depends on IP_NF_IPTABLES + help + + This patch adds per connection marks, and a target (CONNMARK) + respective a match (connmark) for using these. + + Usage: + + connmark + This module matches the netfilter mark field associated + with a connection (which can be set using the CONNMARK + target below). + + --mark value[/mask] + Matches packets in connections with the given + unsigned mark value (if a mask is specified, this + is logically ANDed with the mark before the comparison). + + + CONNMARK + This is used to set the netfilter mark value associated + with the connection + + --set-mark mark + Set connection mark + + --save-mark + Set connection mark to the same as the one on the + packet + + --restore-mark + Set the netfilter packet mark value to the one + associated with the connection. This is only valid + in the mangle table. + +config IP_NF_MATCH_CONNLIMIT + tristate 'Connections/IP limit match support' + depends on IP_NF_IPTABLES + help + This adds an iptables match which allows you to restrict the + number of parallel TCP connections to a server per client IP address + (or address block). + + Examples: + + # allow 2 telnet connections per client host + iptables -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT + + # you can also match the other way around: + iptables -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT + + # limit the nr of parallel http requests to 16 per class C sized + # network (24 bit netmask) + iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16 \ + --connlimit-mask 24 -j REJECT + +config IP_NF_MATCH_U32 + tristate 'U32 match support' + depends on IP_NF_IPTABLES + help + + U32 allows you to extract quantities of up to 4 bytes from a packet, + AND them with specified masks, shift them by specified amounts and + test whether the results are in any of a set of specified ranges. + The specification of what to extract is general enough to skip over + headers with lengths stored in the packet, as in IP or TCP header + lengths. + Details and examples are in the kernel module source. + +config IP_NF_MATCH_MPORT + tristate 'Multiple port with ranges match support' + depends on IP_NF_IPTABLES + help + This module is an enhanced multiport match. It has support for byte + ranges as well as for single ports. + Up to 15 ports are allowed. Note that a portrange uses up 2 port values. + + Examples: + # iptables -A FORWARD -p tcp -m mport --ports 23:42,65 + +config IP_NF_MATCH_NTH + tristate 'Nth match support' + depends on IP_NF_IPTABLES + help + This option adds an iptables `Nth' match, which allows you to match every Nth + packet encountered. By default there are 16 different counters that can be + used. + + This match functions in one of two ways + 1) Match ever Nth packet, and only the Nth packet. + example: + iptables -t mangle -A PREROUTING -m nth --every 10 -j DROP + This rule will drop every 10th packet. + 2) Unique rule for every packet. This is an easy and quick + method to produce load-balancing for both inbound and outbound. + example: + iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 \ + --every 3 --packet 0 -j SNAT --to-source 10.0.0.5 + iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 \ + --every 3 --packet 1 -j SNAT --to-source 10.0.0.6 + iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 \ + --every 3 --packet 2 -j SNAT --to-source 10.0.0.7 + This example evenly splits connections between the three SNAT + addresses. + + By using the mangle table and iproute2, you can setup complex + load-balanced routing. There's lot of other uses. Be creative! + + Suppported options are: + --every Nth Match every Nth packet + [--counter] num Use counter 0-15 (default:0) + [--start] num Initialize the counter at the number 'num' + instead of 0. Must be between 0 and Nth-1 + [--packet] num Match on 'num' packet. Must be between 0 + and Nth-1. + If --packet is used for a counter than + there must be Nth number of --packet + rules, covering all values between 0 and + Nth-1 inclusively. + endmenu diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.2-rc2/net/ipv4/netfilter/Makefile --- linux-2.6.2-rc2.org/net/ipv4/netfilter/Makefile 2004-01-26 03:30:09.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/Makefile 2004-01-30 12:26:19.000000000 +0100 @@ -48,9 +48,14 @@ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o + +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o + obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o + obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o @@ -59,8 +64,12 @@ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o + + obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o @@ -79,6 +88,8 @@ obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o +obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.2-rc2/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-01-26 03:29:48.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ip_conntrack_core.c 2004-01-30 12:25:22.000000000 +0100 @@ -713,6 +713,9 @@ __set_bit(IPS_EXPECTED_BIT, &conntrack->status); conntrack->master = expected; expected->sibling = conntrack; +#if CONFIG_IP_NF_CONNTRACK_MARK + conntrack->mark = expected->expectant->mark; +#endif LIST_DELETE(&ip_conntrack_expect_list, expected); expected->expectant->expecting--; nf_conntrack_get(&master_ct(conntrack)->infos[0]); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.2-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-01-26 03:30:37.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-01-30 12:25:22.000000000 +0100 @@ -105,6 +105,9 @@ len += sprintf(buffer + len, "[ASSURED] "); len += sprintf(buffer + len, "use=%u ", atomic_read(&conntrack->ct_general.use)); +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + len += sprintf(buffer + len, "mark=%ld ", conntrack->mark); +#endif len += sprintf(buffer + len, "\n"); return len; diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_CONNMARK.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_CONNMARK.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_CONNMARK.c 2004-01-30 12:25:22.000000000 +0100 @@ -0,0 +1,91 @@ +/* This is a module which is used for setting/remembering the mark field of + * an connection, or optionally restore it to the skb + */ +#include +#include +#include +#include + +#include +#include +#include + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_connmark_target_info *markinfo = targinfo; + + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); + if (ct) { + switch(markinfo->mode) { + case IPT_CONNMARK_SET: + ct->mark = markinfo->mark; + break; + case IPT_CONNMARK_SAVE: + ct->mark = (*pskb)->nfmark; + break; + case IPT_CONNMARK_RESTORE: + if (ct->mark != (*pskb)->nfmark) { + (*pskb)->nfmark = ct->mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + break; + } + } + + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_connmark_target_info *matchinfo = targinfo; + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) { + printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_connmark_target_info))); + return 0; + } + + if (matchinfo->mode == IPT_CONNMARK_RESTORE) { + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + } + + return 1; +} + +static struct ipt_target ipt_connmark_reg = { + .name = "CONNMARK", + .target = target, + .checkentry = checkentry, + .me = THIS_MODULE + }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_connmark_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_connmark_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_TTL.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_TTL.c 2004-01-30 12:25:07.000000000 +0100 @@ -0,0 +1,114 @@ +/* TTL modification target for IP tables + * (C) 2000 by Harald Welte + * + * Version: 1.8 + * + * This software is distributed under the terms of GNU GPL + */ + +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IP tables TTL modification module"); +MODULE_LICENSE("GPL"); + +static unsigned int ipt_ttl_target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct iphdr *iph = (*pskb)->nh.iph; + const struct ipt_TTL_info *info = targinfo; + u_int16_t diffs[2]; + int new_ttl; + + switch (info->mode) { + case IPT_TTL_SET: + new_ttl = info->ttl; + break; + case IPT_TTL_INC: + new_ttl = iph->ttl + info->ttl; + if (new_ttl > 255) + new_ttl = 255; + break; + case IPT_TTL_DEC: + new_ttl = iph->ttl + info->ttl; + if (new_ttl < 0) + new_ttl = 0; + break; + default: + new_ttl = iph->ttl; + break; + } + + if (new_ttl != iph->ttl) { + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF; + iph->ttl = new_ttl; + diffs[1] = htons(((unsigned)iph->ttl) << 8); + iph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + iph->check^0xFFFF)); + (*pskb)->nfcache |= NFC_ALTERED; + } + + return IPT_CONTINUE; +} + +static int ipt_ttl_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_TTL_info *info = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) { + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_TTL_info))); + return 0; + } + + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (info->mode > IPT_TTL_MAXMODE) { + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", + info->mode); + return 0; + } + + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) { + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n"); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_TTL = { + .name = "TTL", + .target = ipt_ttl_target, + .checkentry = ipt_ttl_checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ipt_register_target(&ipt_TTL); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_TTL); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_connlimit.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_connlimit.c 2004-01-30 12:25:34.000000000 +0100 @@ -0,0 +1,227 @@ +/* + * netfilter module to limit the number of parallel tcp + * connections per IP address. + * (c) 2000 Gerd Knorr + * Nov 2002: Martin Bene : + * only ignore TIME_WAIT or gone connections + * + * based on ... + * + * Kernel module to match connection tracking information. + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 0 + +MODULE_LICENSE("GPL"); + +/* we'll save the tuples of all connections we care about */ +struct ipt_connlimit_conn +{ + struct list_head list; + struct ip_conntrack_tuple tuple; +}; + +struct ipt_connlimit_data { + spinlock_t lock; + struct list_head iphash[256]; +}; + +static int ipt_iphash(u_int32_t addr) +{ + int hash; + + hash = addr & 0xff; + hash ^= (addr >> 8) & 0xff; + hash ^= (addr >> 16) & 0xff; + hash ^= (addr >> 24) & 0xff; + return hash; +} + +static int count_them(struct ipt_connlimit_data *data, + u_int32_t addr, u_int32_t mask, + struct ip_conntrack *ct) +{ +#if DEBUG + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", + "fin_wait", "time_wait", "close", "close_wait", + "last_ack", "listen" }; +#endif + int addit = 1, matches = 0; + struct ip_conntrack_tuple tuple; + struct ip_conntrack_tuple_hash *found; + struct ipt_connlimit_conn *conn; + struct list_head *hash,*lh; + + spin_lock(&data->lock); + tuple = ct->tuplehash[0].tuple; + hash = &data->iphash[ipt_iphash(addr & mask)]; + + /* check the saved connections */ + for (lh = hash->next; lh != hash; lh = lh->next) { + conn = list_entry(lh,struct ipt_connlimit_conn,list); + found = ip_conntrack_find_get(&conn->tuple,ct); + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) && + found != NULL && + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) { + /* Just to be sure we have it only once in the list. + We should'nt see tuples twice unless someone hooks this + into a table without "-p tcp --syn" */ + addit = 0; + } +#if DEBUG + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", + ipt_iphash(addr & mask), + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone"); +#endif + if (NULL == found) { + /* this one is gone */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + continue; + } + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { + /* we don't care about connections which are + closed already -> ditch it */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + nf_conntrack_put(&found->ctrack->infos[0]); + continue; + } + if ((addr & mask) == (conn->tuple.src.ip & mask)) { + /* same source IP address -> be counted! */ + matches++; + } + nf_conntrack_put(&found->ctrack->infos[0]); + } + if (addit) { + /* save the new connection in our list */ +#if DEBUG + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", + ipt_iphash(addr & mask), + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); +#endif + conn = kmalloc(sizeof(*conn),GFP_ATOMIC); + if (NULL == conn) + return -1; + memset(conn,0,sizeof(*conn)); + INIT_LIST_HEAD(&conn->list); + conn->tuple = tuple; + list_add(&conn->list,hash); + matches++; + } + spin_unlock(&data->lock); + return matches; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_connlimit_info *info = matchinfo; + int connections, match; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (NULL == ct) { + printk("ipt_connlimit: Oops: invalid ct state ?\n"); + *hotdrop = 1; + return 0; + } + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct); + if (-1 == connections) { + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n"); + *hotdrop = 1; /* let's free some memory :-) */ + return 0; + } + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); +#if DEBUG + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " + "connections=%d limit=%d match=%s\n", + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), + connections, info->limit, match ? "yes" : "no"); +#endif + + return match; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_connlimit_info *info = matchinfo; + int i; + + /* verify size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info))) + return 0; + + /* refuse anything but tcp */ + if (ip->proto != IPPROTO_TCP) + return 0; + + /* init private data */ + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL); + spin_lock_init(&(info->data->lock)); + for (i = 0; i < 256; i++) + INIT_LIST_HEAD(&(info->data->iphash[i])); + + return 1; +} + +static void destroy(void *matchinfo, unsigned int matchinfosize) +{ + struct ipt_connlimit_info *info = matchinfo; + struct ipt_connlimit_conn *conn; + struct list_head *hash; + int i; + + /* cleanup */ + for (i = 0; i < 256; i++) { + hash = &(info->data->iphash[i]); + while (hash != hash->next) { + conn = list_entry(hash->next,struct ipt_connlimit_conn,list); + list_del(hash->next); + kfree(conn); + } + } + kfree(info->data); +} + +static struct ipt_match connlimit_match += { { NULL, NULL }, "connlimit", &match, &check, &destroy, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&connlimit_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&connlimit_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_connmark.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_connmark.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_connmark.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_connmark.c 2004-01-30 12:25:22.000000000 +0100 @@ -0,0 +1,59 @@ +/* Kernel module to match connection mark values. */ +#include +#include + +#include +#include +#include + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_connmark_info *info = matchinfo; + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (!ct) + return 0; + + return ((ct->mark & info->mask) == info->mark) ^ info->invert; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info))) + return 0; + + return 1; +} + +static struct ipt_match connmark_match = { + .name = "connmark", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&connmark_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&connmark_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_mport.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_mport.c 2004-01-30 12:25:56.000000000 +0100 @@ -0,0 +1,112 @@ +/* Kernel module to match one of a list of TCP/UDP ports: ports are in + the same place so we can treat them as equal. */ +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +#if 0 +#define duprintf(format, args...) printk(format , ## args) +#else +#define duprintf(format, args...) +#endif + +/* Returns 1 if the port is matched by the test, 0 otherwise. */ +static inline int +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst) +{ + unsigned int i; + unsigned int m; + u_int16_t pflags = minfo->pflags; + for (i=0, m=1; iports[i] == 65535) + return 0; + + s = minfo->ports[i]; + + if (pflags & m) { + e = minfo->ports[++i]; + m <<= 1; + } else + e = s; + + if (minfo->flags & IPT_MPORT_SOURCE + && src >= s && src <= e) + return 1; + + if (minfo->flags & IPT_MPORT_DESTINATION + && dst >= s && dst <= e) + return 1; + } + + return 0; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct udphdr *udp = hdr; + const struct ipt_mport *minfo = matchinfo; + + /* Must be big enough to read ports. */ + if (offset == 0 && datalen < sizeof(struct udphdr)) { + /* We've been asked to examine this packet, and we + can't. Hence, no choice but to drop. */ + duprintf("ipt_mport:" + " Dropping evil offset=0 tinygram.\n"); + *hotdrop = 1; + return 0; + } + + /* Must not be a fragment. */ + return !offset + && ports_match(minfo, ntohs(udp->source), ntohs(udp->dest)); +} + +/* Called when user tries to insert an entry of this type. */ +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport))) + return 0; + + /* Must specify proto == TCP/UDP, no unknown flags or bad count */ + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) + && !(ip->invflags & IPT_INV_PROTO) + && matchsize == IPT_ALIGN(sizeof(struct ipt_mport)); +} + +static struct ipt_match mport_match += { { NULL, NULL }, "mport", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&mport_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&mport_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_nth.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_nth.c 2004-01-30 12:26:19.000000000 +0100 @@ -0,0 +1,172 @@ +/* + This is a module which is used for match support for every Nth packet + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2001-07-18 Fabrice MARIE : initial implementation. + 2001-09-20 Richard Wagner (rwagner@cloudnet.com) + * added support for multiple counters + * added support for matching on individual packets + in the counter cycle + +*/ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* + * State information. + */ +struct state { + spinlock_t lock; + u_int16_t number; +}; + +static struct state states[IPT_NTH_NUM_COUNTERS]; + +static int +ipt_nth_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* Parameters from userspace */ + const struct ipt_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1); + return 0; + }; + + spin_lock(&states[counter].lock); + + /* Are we matching every nth packet?*/ + if (info->packet == 0xFF) + { + /* We're matching every nth packet and only every nth packet*/ + /* Do we match or invert match? */ + if (info->not == 0) + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto match; + } + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto dontmatch; + } + else + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto dontmatch; + } + if (states[counter].number >= info->every) + states[counter].number = 0; + else + ++states[counter].number; + goto match; + } + } + else + { + /* We're using the --packet, so there must be a rule for every value */ + if (states[counter].number == info->packet) + { + /* only increment the counter when a match happens */ + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto match; + } + else + goto dontmatch; + } + + dontmatch: + /* don't match */ + spin_unlock(&states[counter].lock); + return 0; + + match: + spin_unlock(&states[counter].lock); + return 1; +} + +static int +ipt_nth_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ipt_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1); + return 0; + }; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) { + printk("nth: matchsize %u != %u\n", matchsize, + IPT_ALIGN(sizeof(struct ipt_nth_info))); + return 0; + } + + states[counter].number = info->startat; + + return 1; +} + +static struct ipt_match ipt_nth_reg = { + {NULL, NULL}, + "nth", + ipt_nth_match, + ipt_nth_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + unsigned counter; + memset(&states, 0, sizeof(states)); + if (ipt_register_match(&ipt_nth_reg)) + return -EINVAL; + + for(counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) + { + spin_lock_init(&(states[counter].lock)); + }; + + printk("ipt_nth match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_nth_reg); + printk("ipt_nth match unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.2-rc2/net/ipv4/netfilter/ipt_u32.c --- linux-2.6.2-rc2.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv4/netfilter/ipt_u32.c 2004-01-30 12:25:44.000000000 +0100 @@ -0,0 +1,211 @@ +/* Kernel module to match u32 packet content. */ + +/* +U32 tests whether quantities of up to 4 bytes extracted from a packet +have specified values. The specification of what to extract is general +enough to find data at given offsets from tcp headers or payloads. + + --u32 tests + The argument amounts to a program in a small language described below. + tests := location = value | tests && location = value + value := range | value , range + range := number | number : number + a single number, n, is interpreted the same as n:n + n:m is interpreted as the range of numbers >=n and <=m + location := number | location operator number + operator := & | << | >> | @ + + The operators &, <<, >>, && mean the same as in c. The = is really a set + membership operator and the value syntax describes a set. The @ operator + is what allows moving to the next header and is described further below. + + *** Until I can find out how to avoid it, there are some artificial limits + on the size of the tests: + - no more than 10 ='s (and 9 &&'s) in the u32 argument + - no more than 10 ranges (and 9 commas) per value + - no more than 10 numbers (and 9 operators) per location + + To describe the meaning of location, imagine the following machine that + interprets it. There are three registers: + A is of type char*, initially the address of the IP header + B and C are unsigned 32 bit integers, initially zero + + The instructions are: + number B = number; + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3) + &number C = C&number + <>number C = C>>number + @number A = A+C; then do the instruction number + Any access of memory outside [skb->head,skb->end] causes the match to fail. + Otherwise the result of the computation is the final value of C. + + Whitespace is allowed but not required in the tests. + However the characters that do occur there are likely to require + shell quoting, so it's a good idea to enclose the arguments in quotes. + +Example: + match IP packets with total length >= 256 + The IP header contains a total length field in bytes 2-3. + --u32 "0&0xFFFF=0x100:0xFFFF" + read bytes 0-3 + AND that with FFFF (giving bytes 2-3), + and test whether that's in the range [0x100:0xFFFF] + +Example: (more realistic, hence more complicated) + match icmp packets with icmp type 0 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1 + --u32 "6&0xFF=1 && ... + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1 + Next test that it's not a fragment. + (If so it might be part of such a packet but we can't always tell.) + n.b. This test is generally needed if you want to match anything + beyond the IP header. + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete + packet (not a fragment). Alternatively, you can allow first fragments + by only testing the last 5 bits of byte 6. + ... 4&0x3FFF=0 && ... + Last test: the first byte past the IP header (the type) is 0 + This is where we have to use the @syntax. The length of the IP header + (IHL) in 32 bit words is stored in the right half of byte 0 of the + IP header itself. + ... 0>>22&0x3C@0>>24=0" + The first 0 means read bytes 0-3, + >>22 means shift that 22 bits to the right. Shifting 24 bits would give + the first byte, so only 22 bits is four times that plus a few more bits. + &3C then eliminates the two extra bits on the right and the first four + bits of the first byte. + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long. + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100. + @ means to use this number as a new offset into the packet, and read + four bytes starting from there. This is the first 4 bytes of the icmp + payload, of which byte 0 is the icmp type. Therefore we simply shift + the value 24 to the right to throw out all but the first byte and compare + the result with 0. + +Example: + tcp payload bytes 8-12 is any of 1, 2, 5 or 8 + First we test that the packet is a tcp packet (similar to icmp). + --u32 "6&0xFF=6 && ... + Next, test that it's not a fragment (same as above). + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8" + 0>>22&3C as above computes the number of bytes in the IP header. + @ makes this the new offset into the packet, which is the start of the + tcp header. The length of the tcp header (again in 32 bit words) is + the left half of byte 12 of the tcp header. The 12>>26&3C + computes this length in bytes (similar to the IP header before). + @ makes this the new offset, which is the start of the tcp payload. + Finally 8 reads bytes 8-12 of the payload and = checks whether the + result is any of 1, 2, 5 or 8 +*/ + +#include +#include + +#include +#include + +/* #include for timing */ + +MODULE_AUTHOR("Don Cohen "); +MODULE_DESCRIPTION("IP tables u32 matching module"); +MODULE_LICENSE("GPL"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_u32 *data = matchinfo; + int testind, i; + unsigned char* origbase = (char*)skb->nh.iph; + unsigned char* base = origbase; + unsigned char* head = skb->head; + unsigned char* end = skb->end; + int nnums, nvals; + u_int32_t pos, val; + /* unsigned long long cycles1, cycles2, cycles3, cycles4; + cycles1 = get_cycles(); */ + + for (testind=0; testind < data->ntests; testind++) { + base = origbase; /* reset for each test */ + pos = data->tests[testind].location[0].number; + if (base+pos+3 > end || base+pos < head) + return 0; + val = (base[pos]<<24) + (base[pos+1]<<16) + + (base[pos+2]<<8) + base[pos+3]; + nnums = data->tests[testind].nnums; + for (i=1; i < nnums; i++) { + u_int32_t number = data->tests[testind].location[i].number; + switch (data->tests[testind].location[i].nextop) { + case IPT_U32_AND: + val = val & number; + break; + case IPT_U32_LEFTSH: + val = val << number; + break; + case IPT_U32_RIGHTSH: + val = val >> number; + break; + case IPT_U32_AT: + base = base + val; + pos = number; + if (base+pos+3 > end || base+pos < head) + return 0; + val = (base[pos]<<24) + (base[pos+1]<<16) + + (base[pos+2]<<8) + base[pos+3]; + break; + } + } + nvals = data->tests[testind].nvalues; + for (i=0; i < nvals; i++) { + if ((data->tests[testind].value[i].min <= val) && + (val <= data->tests[testind].value[i].max)) { + break; + } + } + if (i >= data->tests[testind].nvalues) { + /* cycles2 = get_cycles(); + printk("failed %d in %d cycles\n", testind, + cycles2-cycles1); */ + return 0; + } + } + /* cycles2 = get_cycles(); + printk("succeeded in %d cycles\n", cycles2-cycles1); */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32))) + return 0; + return 1; +} + +static struct ipt_match u32_match += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&u32_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&u32_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv6/netfilter/Kconfig linux-2.6.2-rc2/net/ipv6/netfilter/Kconfig --- linux-2.6.2-rc2.org/net/ipv6/netfilter/Kconfig 2004-01-26 03:31:18.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv6/netfilter/Kconfig 2004-01-30 12:26:19.000000000 +0100 @@ -218,5 +218,53 @@ To compile it as a module, choose M here. If unsure, say N. #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES +config IP6_NF_TARGET_REJECT + tristate 'REJECT target support' + depends on IP6_NF_FILTER + help + This CONFIG_IP6_NF_TARGET_REJECT option adds a REJECT target to ip6tables. + Please keep in mind that the icmp-types are different from the icmpv6 types + (see ip6tables -j REJECT -h for more info) + +config IP6_NF_MATCH_NTH + tristate 'Nth match support' + depends on IP6_NF_IPTABLES + help + This option adds an iptables `Nth' match, which allows you to match every Nth + packet encountered. By default there are 16 different counters that can be + used. + + This match functions in one of two ways + 1) Match ever Nth packet, and only the Nth packet. + example: + iptables -t mangle -A PREROUTING -m nth --every 10 -j DROP + This rule will drop every 10th packet. + 2) Unique rule for every packet. This is an easy and quick + method to produce load-balancing for both inbound and outbound. + example: + iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 \ + --every 3 --packet 0 -j SNAT --to-source 10.0.0.5 + iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 \ + --every 3 --packet 1 -j SNAT --to-source 10.0.0.6 + iptables -t nat -A POSTROUTING -o eth0 -m nth --counter 7 \ + --every 3 --packet 2 -j SNAT --to-source 10.0.0.7 + This example evenly splits connections between the three SNAT + addresses. + + By using the mangle table and iproute2, you can setup complex + load-balanced routing. There's lot of other uses. Be creative! + + Suppported options are: + --every Nth Match every Nth packet + [--counter] num Use counter 0-15 (default:0) + [--start] num Initialize the counter at the number 'num' + instead of 0. Must be between 0 and Nth-1 + [--packet] num Match on 'num' packet. Must be between 0 + and Nth-1. + If --packet is used for a counter than + there must be Nth number of --packet + rules, covering all values between 0 and + Nth-1 inclusively. + endmenu diff -Nur linux-2.6.2-rc2.org/net/ipv6/netfilter/Makefile linux-2.6.2-rc2/net/ipv6/netfilter/Makefile --- linux-2.6.2-rc2.org/net/ipv6/netfilter/Makefile 2004-01-26 03:30:53.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv6/netfilter/Makefile 2004-01-30 12:26:19.000000000 +0100 @@ -19,6 +19,9 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o + +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o diff -Nur linux-2.6.2-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.2-rc2/net/ipv6/netfilter/ip6t_REJECT.c --- linux-2.6.2-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv6/netfilter/ip6t_REJECT.c 2004-01-30 12:26:08.000000000 +0100 @@ -0,0 +1,274 @@ +/* + * This is a module which is used for rejecting packets. + * Added support for customized reject packets (Jozsef Kadlecsik). + * Sun 12 Nov 2000 + * Port to IPv6 / ip6tables (Harald Welte ) + */ +#include +#include +#include +#include +#include +#include +#include + +#if 1 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#if 0 +/* Send RST reply */ +static void send_reset(struct sk_buff *oldskb) +{ + struct sk_buff *nskb; + struct tcphdr *otcph, *tcph; + struct rtable *rt; + unsigned int otcplen; + int needs_ack; + + /* IP header checks: fragment, too short. */ + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) + return; + + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl); + otcplen = oldskb->len - oldskb->nh.iph->ihl*4; + + /* No RST for RST. */ + if (otcph->rst) + return; + + /* Check checksum. */ + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr, + oldskb->nh.iph->daddr, + csum_partial((char *)otcph, otcplen, 0)) != 0) + return; + + /* Copy skb (even if skb is about to be dropped, we can't just + clone it because there may be other things, such as tcpdump, + interested in it) */ + nskb = skb_copy(oldskb, GFP_ATOMIC); + if (!nskb) + return; + + /* This packet will not be the same as the other: clear nf fields */ + nf_conntrack_put(nskb->nfct); + nskb->nfct = NULL; + nskb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + nskb->nf_debug = 0; +#endif + + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); + + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); + tcph->source = xchg(&tcph->dest, tcph->source); + + /* Truncate to length (no data) */ + tcph->doff = sizeof(struct tcphdr)/4; + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); + nskb->nh.iph->tot_len = htons(nskb->len); + + if (tcph->ack) { + needs_ack = 0; + tcph->seq = otcph->ack_seq; + tcph->ack_seq = 0; + } else { + needs_ack = 1; + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin + + otcplen - (otcph->doff<<2)); + tcph->seq = 0; + } + + /* Reset flags */ + ((u_int8_t *)tcph)[13] = 0; + tcph->rst = 1; + tcph->ack = needs_ack; + + tcph->window = 0; + tcph->urg_ptr = 0; + + /* Adjust TCP checksum */ + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), + nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + csum_partial((char *)tcph, + sizeof(struct tcphdr), 0)); + + /* Adjust IP TTL, DF */ + nskb->nh.iph->ttl = MAXTTL; + /* Set DF, id = 0 */ + nskb->nh.iph->frag_off = htons(IP_DF); + nskb->nh.iph->id = 0; + + /* Adjust IP checksum */ + nskb->nh.iph->check = 0; + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, + nskb->nh.iph->ihl); + + /* Routing */ + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr, + RT_TOS(nskb->nh.iph->tos) | RTO_CONN, + 0) != 0) + goto free_nskb; + + dst_release(nskb->dst); + nskb->dst = &rt->u.dst; + + /* "Never happens" */ + if (nskb->len > nskb->dst->pmtu) + goto free_nskb; + + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, + ip_finish_output); + return; + + free_nskb: + kfree_skb(nskb); +} +#endif + +static unsigned int reject6_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ip6t_reject_info *reject = targinfo; + + /* WARNING: This code causes reentry within ip6tables. + This means that the ip6tables jump stack is now crap. We + must return an absolute verdict. --RR */ + DEBUGP("REJECTv6: calling icmpv6_send\n"); + switch (reject->with) { + case IP6T_ICMP6_NO_ROUTE: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out); + break; + case IP6T_ICMP6_ADM_PROHIBITED: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out); + break; + case IP6T_ICMP6_NOT_NEIGHBOUR: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out); + break; + case IP6T_ICMP6_ADDR_UNREACH: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out); + break; + case IP6T_ICMP6_PORT_UNREACH: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out); + break; +#if 0 + case IPT_ICMP_ECHOREPLY: { + struct icmp6hdr *icmph = (struct icmphdr *) + ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl); + unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; + + /* Not non-head frags, or truncated */ + if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0) + && datalen >= 4) { + /* Usually I don't like cut & pasting code, + but dammit, my party is starting in 45 + mins! --RR */ + struct icmp_bxm icmp_param; + + icmp_param.icmph=*icmph; + icmp_param.icmph.type=ICMP_ECHOREPLY; + icmp_param.data_ptr=(icmph+1); + icmp_param.data_len=datalen; + icmp_reply(&icmp_param, *pskb); + } + } + break; + case IPT_TCP_RESET: + send_reset(*pskb); + break; +#endif + default: + printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with); + break; + } + + return NF_DROP; +} + +static inline int find_ping_match(const struct ip6t_entry_match *m) +{ + const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data; + + if (strcmp(m->u.kernel.match->name, "icmp6") == 0 + && icmpinfo->type == ICMPV6_ECHO_REQUEST + && !(icmpinfo->invflags & IP6T_ICMP_INV)) + return 1; + + return 0; +} + +static int check(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ip6t_reject_info *rejinfo = targinfo; + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) { + DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize); + return 0; + } + + /* Only allow these for packet filtering. */ + if (strcmp(tablename, "filter") != 0) { + DEBUGP("REJECTv6: bad table `%s'.\n", tablename); + return 0; + } + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN) + | (1 << NF_IP6_FORWARD) + | (1 << NF_IP6_LOCAL_OUT))) != 0) { + DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask); + return 0; + } + + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { + /* Must specify that it's an ICMP ping packet. */ + if (e->ipv6.proto != IPPROTO_ICMPV6 + || (e->ipv6.invflags & IP6T_INV_PROTO)) { + DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n"); + return 0; + } + /* Must contain ICMP match. */ + if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) { + DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n"); + return 0; + } + } else if (rejinfo->with == IP6T_TCP_RESET) { + /* Must specify that it's a TCP packet */ + if (e->ipv6.proto != IPPROTO_TCP + || (e->ipv6.invflags & IP6T_INV_PROTO)) { + DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n"); + return 0; + } + } + + return 1; +} + +static struct ip6t_target ip6t_reject_reg += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ip6t_register_target(&ip6t_reject_reg)) + return -EINVAL; + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_reject_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.2-rc2.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.2-rc2/net/ipv6/netfilter/ip6t_nth.c --- linux-2.6.2-rc2.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.2-rc2/net/ipv6/netfilter/ip6t_nth.c 2004-01-30 12:26:19.000000000 +0100 @@ -0,0 +1,173 @@ +/* + This is a module which is used for match support for every Nth packet + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2001-07-18 Fabrice MARIE : initial implementation. + 2001-09-20 Richard Wagner (rwagner@cloudnet.com) + * added support for multiple counters + * added support for matching on individual packets + in the counter cycle + 2003-04-30 Maciej Soltysiak : IPv6 Port + +*/ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* + * State information. + */ +struct state { + spinlock_t lock; + u_int16_t number; +}; + +static struct state states[IP6T_NTH_NUM_COUNTERS]; + +static int +ip6t_nth_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* Parameters from userspace */ + const struct ip6t_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1); + return 0; + }; + + spin_lock(&states[counter].lock); + + /* Are we matching every nth packet?*/ + if (info->packet == 0xFF) + { + /* We're matching every nth packet and only every nth packet*/ + /* Do we match or invert match? */ + if (info->not == 0) + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto match; + } + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto dontmatch; + } + else + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto dontmatch; + } + if (states[counter].number >= info->every) + states[counter].number = 0; + else + ++states[counter].number; + goto match; + } + } + else + { + /* We're using the --packet, so there must be a rule for every value */ + if (states[counter].number == info->packet) + { + /* only increment the counter when a match happens */ + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto match; + } + else + goto dontmatch; + } + + dontmatch: + /* don't match */ + spin_unlock(&states[counter].lock); + return 0; + + match: + spin_unlock(&states[counter].lock); + return 1; +} + +static int +ip6t_nth_checkentry(const char *tablename, + const struct ip6t_ip6 *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ip6t_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1); + return 0; + }; + + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) { + printk("nth: matchsize %u != %u\n", matchsize, + IP6T_ALIGN(sizeof(struct ip6t_nth_info))); + return 0; + } + + states[counter].number = info->startat; + + return 1; +} + +static struct ip6t_match ip6t_nth_reg = { + {NULL, NULL}, + "nth", + ip6t_nth_match, + ip6t_nth_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + unsigned counter; + memset(&states, 0, sizeof(states)); + if (ip6t_register_match(&ip6t_nth_reg)) + return -EINVAL; + + for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) + { + spin_lock_init(&(states[counter].lock)); + }; + + printk("ip6t_nth match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&ip6t_nth_reg); + printk("ip6t_nth match unloaded\n"); +} + +module_init(init); +module_exit(fini);