diff -u --new-file --recursive linux-2.4.18_vanilla/Documentation/Configure.help linux-2.4.18_iptables-1.2.6a-extensions/Documentation/Configure.help --- linux-2.4.18_vanilla/Documentation/Configure.help Mon Feb 25 21:37:51 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/Documentation/Configure.help Mon Apr 29 00:35:27 2002 @@ -2354,6 +2354,20 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Talk protocol support +CONFIG_IP_NF_TALK + The talk protocols (talk and ntalk, ntalk2) use an additional channel + to setup the talk session and a separated data channel for the actual + conversation (like in FTP). Both the initiating and the setup channels + are over UDP, while the data channel is over TCP, on a random port. + The conntrack part of this extension will enable you to let in/out talk + sessions easily by matching these connections as RELATED by the state + match, while the NAT part helps you to let talk sessions trough a NAT + machine. + + If you want to compile it as a module, say 'M' here and read + Documentation/modules.txt. If unsure, say 'N'. + IRC Send/Chat protocol support CONFIG_IP_NF_IRC There is a commonly-used extension to IRC called @@ -2368,6 +2382,47 @@ If you want to compile it as a module, say 'M' here and read Documentation/modules.txt. If unsure, say 'N'. +Per connection mark support +CONFIG_IP_NF_CONNTRACK_MARK + This option enables support for connection marks, used by the + `CONNMARK' target and `connmark' match. Similar to the mark value + of packets, but this mark value is kept in the conntrack session + instead of the individual packets. + +CONNMARK target support +CONFIG_IP_NF_TARGET_CONNMARK + This option adds a `CONNMARK' target, which allows one to manipulate + the connection mark value. Similar to the MARK target, but + affects the connection mark value rather than the packet mark value. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called + ipt_CONNMARK.o. If unsure, say `N'. + +connmark match support +CONFIP_IP_NF_MATCH_CONNMARK + This option adds a `connmark' match, which allows you to match the + connection mark value previously set for the session by `CONNMARK'. + +TFTP protocol support +CONFIG_IP_NF_TFTP + TFTP connection tracking helper, this is required depending + on how restrictive your ruleset is. + If you are using a tftp client behind -j SNAT or -j MASQUERADING + you will need this. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `Y'. + +Eggdrop bot support +CONFIG_IP_NF_EGG + If you are running an eggdrop hub bot on this machine, then you + may want to enable this feature. This enables eggdrop bots to share + their user file to other eggdrop bots. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + FTP protocol support CONFIG_IP_NF_FTP Tracking FTP connections is problematic: special helpers are @@ -2395,6 +2450,14 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +quota match support +CONFIG_IP_NF_MATCH_QUOTA + This match implements network quotas. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + limit match support CONFIG_IP_NF_MATCH_LIMIT limit matching allows you to control the rate at which a rule can be @@ -2404,6 +2467,17 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +skb->pkt_type packet match support (EXPERIMENTAL) +CONFIG_IP_NF_MATCH_PKTTYPE + This patch allows you to match packet in accrodance + to its "class", eg. BROADCAST, MULTICAST, ... + + Typical usage: + iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + MAC address match support CONFIG_IP_NF_MATCH_MAC MAC matching allows you to match packets based on the source @@ -2421,6 +2495,14 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Multiple port with ranges match support +CONFIG_IP_NF_MATCH_MPORT + This is an enhanced multiport match which supports port + ranges as well as single ports. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Multiple port match support CONFIG_IP_NF_MATCH_MULTIPORT Multiport matching allows you to match TCP or UDP packets based on @@ -2454,6 +2536,84 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +Nth match support +CONFIG_IP_NF_MATCH_RANDOM + This option adds a `random' match, + which allow you to match packets randomly + following a given probability. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +Nth match support +CONFIG_IP_NF_MATCH_NTH + This option adds a `Nth' match, which allow you to make + rules that match every Nth packet. By default there are + 16 different counters. + +[options] + --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. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +TIME patch support +CONFIG_IP_NF_MATCH_TIME + This option adds a `time' match, which allows you + to matchbased on the packet arrival time + (arrival time at the machine which the netfilter is running on) or + departure time (for locally generated packets). + + If you say Y here, try iptables -m time --help for more information. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +psd match support +CONFIG_IP_NF_MATCH_PSD + This option adds a `psd' match, which allows you to create rules in + any iptables table wich will detect TCP and UDP port scans. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +IPV4OPTIONS patch support +CONFIG_IP_NF_MATCH_IPV4OPTIONS + This option adds a IPV4OPTIONS match. + It allows you to filter options like source routing, + record route, timestamp and router-altert. + + If you say Y here, try iptables -m ipv4options --help for more information. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +recent match support +CONFIG_IP_NF_MATCH_RECENT + This option allows you to create lists of recently seen source + addresses and then match against that list based on number of + times seen and the time since last seen. An option is also + availible to require a match against TTL in addition to source + address. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + TOS match support CONFIG_IP_NF_MATCH_TOS TOS matching allows you to match packets based on the Type Of @@ -2462,6 +2622,26 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Connections/IP limit match support +CONFIG_IP_NF_MATCH_IPLIMIT + This match allows you to restrict the number of parallel TCP + connections to a server per client IP address (or address block). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +conntrack match support +CONFIG_IP_NF_MATCH_CONNTRACK + This is a general conntrack match module, a superset of the state match. + + It allows matching on additional conntrack information, which is + useful in complex configurations, such as NAT gateways with multiple + internet links or tunnels. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + Connection state match support CONFIG_IP_NF_MATCH_STATE Connection state matching allows you to match packets based on their @@ -2471,6 +2651,19 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Bytelimit match support (EXPERIMENTAL) +CONFIG_IP_NF_MATCH_BYTELIMIT + Bytelimit allows to shape network traffic easily, to control + bandwidth allocated to a specific service or a specific host, + for instance. In many situations, it can save you the hassle + of understanding "classic" traffic control (which uses qdisc, + and many other things you don't want to know about, when your + only goal is to prevent a specific host to exceed a given + bandwidth). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Unclean match support CONFIG_IP_NF_MATCH_UNCLEAN Unclean packet matching matches any strange or invalid packets, by @@ -2496,6 +2689,24 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +IPV4OPTSSTRIP target support +CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP + This option adds an IPV4OPTSSTRIP target. + This target allows you to strip all IP options in a packet. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + +NETLINK target support +CONFIG_IP_NF_TARGET_NETLINK + The NETLINK target allows you to recieve packets in userspace via + the kernel firewall netlink socket. Apps such as fwmon + (http://firestorm.geek-ware.co.uk) can then recieve and dislpay + these packets. This option is basically a re-implementation of the + ipchains -o option. + + REJECT target support CONFIG_IP_NF_TARGET_REJECT The REJECT target allows a filtering rule to specify that an ICMP @@ -2513,6 +2724,14 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Local NAT support +CONFIG_IP_NF_NAT_LOCAL + This option enables support for NAT of locally originated connections. + Enable this if you need to use destination NAT on connections + originating from local processes on the nat box itself. + If unsure, say 'N'. + + Full NAT (Network Address Translation) CONFIG_IP_NF_NAT The Full NAT option allows masquerading, port forwarding and other @@ -2547,6 +2766,27 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +NETMAP target support +CONFIG_IP_NF_TARGET_NETMAP + NETMAP is an implementation of static 1:1 NAT mapping of network + addresses. It maps the network address part, while keeping the + host address part intact. It is similar to Fast NAT, except that + Netfilter's connection tracking doesn't work well with Fast NAT. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called + ipt_NETMAP.o. If unsure, say `N'. + +SAME NAT target support +CONFIG_IP_NF_TARGET_SAME + This option adds a `SAME' target, which works like the standard + SNAT target, but attempts to give clients the same IP for all + connections. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called + ipt_SAME.o. If unsure, say `N'. + REDIRECT target support CONFIG_IP_NF_TARGET_REDIRECT REDIRECT is a special case of NAT: all incoming connections are @@ -2566,6 +2806,21 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +DSCP target support +CONFIG_IP_NF_TARGET_DSCP + This option adds a `DSCP' target, which allows you to create rules in + the iptables mangle table. The selected packet has the DSCP field set + to the hex value provided on the command line; unlike the TOS target + which will only set the legal values within ip.h. + + The DSCP field can be set to any value between 0x0 and 0x4f. It does + take into account that bits 6 and 7 are used by ECN. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + + TOS target support CONFIG_IP_NF_TARGET_TOS This option adds a `TOS' target, which allows you to create rules in @@ -2634,6 +2889,38 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +pool match and target support +CONFIG_IP_NF_MATCH_POOL + Pool matching lets you use bitmaps with one bit per address from some + range of IP addresses; the match depends on whether a checked source + or destination address has its bit set in the pool. + + There is also a POOL netfilter target, which can be used to set or remove + the addresses of a packet from a pool. + + To define and use pools, you need userlevel utilities: a patched iptables, + and the program ippool(8), which defines the pools and their bounds. + The current release of pool matching is ippool-0.0.2, and can be found + in the archives of the netfilter mailing list at + http://lists.samba.org/netfilter/. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +pool match and target statistics gathering +CONFIG_IP_POOL_STATISTICS + This option controls whether usage gathering code is compiled into the + ip_pool module. Disabling statistics may be substantially faster. + +TTL target support +CONFIG_IP_NF_TARGET_TTL + This option adds a `TTL' target, which enables the user to set + the TTL value or increment / decrement the TTL value by a given + amount. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + LOG target support CONFIG_IP_NF_TARGET_LOG This option adds a `LOG' target, which allows you to create rules in @@ -2664,6 +2951,15 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +Aggregated address check (EXPERIMENTAL) +CONFIG_IP6_NF_MATCH_AGR + This module is perform checking on the IPv6 IP address + Compares the last 64 bits with the aggregated (delivered + from the MAC address) + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + MAC address match support CONFIG_IP6_NF_MATCH_MAC mac matching allows you to match packets based on the source @@ -2715,6 +3011,15 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. +REJECT target support +CONFIG_IP6_NF_TARGET_REJECT + The REJECT target allows a filtering rule to specify that an ICMPv6 + error should be issued in response to an incoming packet, rather + than silently being dropped. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Packet filtering CONFIG_IP6_NF_FILTER Packet filtering defines a table `filter', which has a series of diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_arp.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_arp.h --- linux-2.4.18_vanilla/include/linux/netfilter_arp.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_arp.h Sun Apr 28 22:43:55 2002 @@ -0,0 +1,19 @@ +#ifndef __LINUX_ARP_NETFILTER_H +#define __LINUX_ARP_NETFILTER_H + +/* ARP-specific defines for netfilter. + * (C)2002 Rusty Russell IBM -- This code is GPL. + */ + +#include +#include + +/* There is no PF_ARP. */ +#define NF_ARP 0 + +/* ARP Hooks */ +/* Coming in. */ +#define NF_ARP_IN 0 +#define NF_ARP_OUT 1 + +#endif /* __LINUX_ARP_NETFILTER_H */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack.h Mon Feb 25 21:38:13 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack.h Sun Apr 28 22:40:28 2002 @@ -87,6 +87,10 @@ #include #endif +#if defined(CONFIG_IP_NF_TALK) || defined(CONFIG_IP_NF_TALK_MODULE) +#include +#endif + struct ip_conntrack { /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, @@ -128,6 +132,9 @@ #if defined(CONFIG_IP_NF_IRC) || defined(CONFIG_IP_NF_IRC_MODULE) struct ip_ct_irc ct_irc_info; #endif +#if defined(CONFIG_IP_NF_TALK) || defined(CONFIG_IP_NF_TALK_MODULE) + struct ip_ct_talk ct_talk_info; +#endif } help; #ifdef CONFIG_IP_NF_NAT_NEEDED @@ -143,6 +150,9 @@ } nat; #endif /* CONFIG_IP_NF_NAT_NEEDED */ +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + unsigned long mark; +#endif }; /* Alter reply tuple (maybe alter helper). If it's already taken, diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack_protocol.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Fri Apr 27 23:15:01 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Sun Apr 28 22:31:39 2002 @@ -42,6 +42,9 @@ int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len); + /* Called when a conntrack entry is destroyed */ + void (*destroy)(struct ip_conntrack *conntrack); + /* Module (if any) which this is connected to. */ struct module *me; }; diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack_talk.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack_talk.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack_talk.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack_talk.h Sun Apr 28 22:40:28 2002 @@ -0,0 +1,152 @@ +#ifndef _IP_CONNTRACK_TALK_H +#define _IP_CONNTRACK_TALK_H +/* TALK tracking. */ + +#ifndef __KERNEL__ +#error Only in kernel. +#endif + +#include +#include + +/* Protects talk part of conntracks */ +DECLARE_LOCK_EXTERN(ip_talk_lock); + +#define TALK_PORT 517 +#define NTALK_PORT 518 + +/* talk structures and constants from */ + +/* + * 4.3BSD struct sockaddr + */ +struct talk_addr { + u_int16_t ta_family; + u_int16_t ta_port; + u_int32_t ta_addr; + u_int32_t ta_junk1; + u_int32_t ta_junk2; +}; + +#define OLD_NAME_SIZE 9 +#define NAME_SIZE 12 +#define TTY_SIZE 16 + +/* + * Client->server request message formats. + */ +struct talk_msg { + u_char type; /* request type, see below */ + char l_name[OLD_NAME_SIZE];/* caller's name */ + char r_name[OLD_NAME_SIZE];/* callee's name */ + u_char pad; + u_int32_t id_num; /* message id */ + int32_t pid; /* caller's process id */ + char r_tty[TTY_SIZE];/* callee's tty name */ + struct talk_addr addr; /* old (4.3) style */ + struct talk_addr ctl_addr; /* old (4.3) style */ +}; + +struct ntalk_msg { + u_char vers; /* protocol version */ + u_char type; /* request type, see below */ + u_char answer; /* not used */ + u_char pad; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* old (4.3) style */ + struct talk_addr ctl_addr; /* old (4.3) style */ + int32_t pid; /* caller's process id */ + char l_name[NAME_SIZE];/* caller's name */ + char r_name[NAME_SIZE];/* callee's name */ + char r_tty[TTY_SIZE];/* callee's tty name */ +}; + +struct ntalk2_msg { + u_char vers; /* talk protocol version */ + u_char type; /* request type */ + u_char answer; /* */ + u_char extended; /* !0 if additional parts */ + u_int32_t id_num; /* message id number (dels) */ + struct talk_addr addr; /* target address */ + struct talk_addr ctl_addr; /* reply to address */ + int32_t pid; /* caller's process id */ + char l_name[NAME_SIZE]; /* caller's name */ + char r_name[NAME_SIZE]; /* callee's name */ + char r_tty[TTY_SIZE]; /* callee's tty */ +}; + +/* + * Server->client response message formats. + */ +struct talk_response { + u_char type; /* type of request message, see below */ + u_char answer; /* response to request message, see below */ + u_char pad[2]; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* address for establishing conversation */ +}; + +struct ntalk_response { + u_char vers; /* protocol version */ + u_char type; /* type of request message, see below */ + u_char answer; /* response to request message, see below */ + u_char pad; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* address for establishing conversation */ +}; + +struct ntalk2_response { + u_char vers; /* protocol version */ + u_char type; /* type of request message */ + u_char answer; /* response to request */ + u_char rvers; /* Version of answering vers*/ + u_int32_t id_num; /* message id number */ + struct talk_addr addr; /* address for connection */ + /* This is at the end to compatiblize this with NTALK version. */ + char r_name[NAME_SIZE]; /* callee's name */ +}; + +#define TALK_STR(data, talk_str, member) ((struct talk_str *)data)->member) +#define TALK_RESP(data, ver, member) (ver ? ((struct ntalk_response *)data)->member : ((struct talk_response *)data)->member) +#define TALK_MSG(data, ver, member) (ver ? ((struct ntalk_msg *)data)->member : ((struct talk_msg *)data)->member) + +#define TALK_VERSION 0 /* protocol versions */ +#define NTALK_VERSION 1 +#define NTALK2_VERSION 2 + +/* message type values */ +#define LEAVE_INVITE 0 /* leave invitation with server */ +#define LOOK_UP 1 /* check for invitation by callee */ +#define DELETE 2 /* delete invitation by caller */ +#define ANNOUNCE 3 /* announce invitation by caller */ +/* NTALK2 */ +#define REPLY_QUERY 4 /* request reply data from local daemon */ + +/* answer values */ +#define SUCCESS 0 /* operation completed properly */ +#define NOT_HERE 1 /* callee not logged in */ +#define FAILED 2 /* operation failed for unexplained reason */ +#define MACHINE_UNKNOWN 3 /* caller's machine name unknown */ +#define PERMISSION_DENIED 4 /* callee's tty doesn't permit announce */ +#define UNKNOWN_REQUEST 5 /* request has invalid type value */ +#define BADVERSION 6 /* request has invalid protocol version */ +#define BADADDR 7 /* request has invalid addr value */ +#define BADCTLADDR 8 /* request has invalid ctl_addr value */ +/* NTALK2 */ +#define NO_CALLER 9 /* no-one calling answer from REPLY */ +#define TRY_HERE 10 /* Not on this machine, try this */ +#define SELECTIVE_REFUSAL 11 /* User Filter refusal. */ +#define MAX_RESPONSE_TYPE 11 /* Make sure this is updated */ + +/* We don't really need much for talk */ +struct ip_ct_talk +{ + /* This tells NAT that this is a talk connection + talk version */ + int is_talk; + /* Port that was to be used */ + u_int16_t port; +}; + +extern int ip_conntrack_talk_forceload(void); + +#endif /* _IP_CONNTRACK_TALK_H */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack_tcp.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack_tcp.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_conntrack_tcp.h Fri Aug 4 22:07:24 2000 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_conntrack_tcp.h Sun Apr 28 14:55:57 2002 @@ -8,25 +8,35 @@ enum tcp_conntrack { TCP_CONNTRACK_NONE, - TCP_CONNTRACK_ESTABLISHED, TCP_CONNTRACK_SYN_SENT, TCP_CONNTRACK_SYN_RECV, + TCP_CONNTRACK_ESTABLISHED, TCP_CONNTRACK_FIN_WAIT, - TCP_CONNTRACK_TIME_WAIT, - TCP_CONNTRACK_CLOSE, TCP_CONNTRACK_CLOSE_WAIT, TCP_CONNTRACK_LAST_ACK, + TCP_CONNTRACK_TIME_WAIT, + TCP_CONNTRACK_CLOSE, TCP_CONNTRACK_LISTEN, TCP_CONNTRACK_MAX }; +struct ip_ct_tcp_state { + u_int32_t td_end; /* max of seq + len */ + u_int32_t td_maxend; /* max of ack + max(win, 1) */ + u_int32_t td_maxwin; /* max(win) */ + u_int8_t td_scale; /* window scale factor */ +}; + struct ip_ct_tcp { - enum tcp_conntrack state; - - /* Poor man's window tracking: sequence number of valid ACK - handshake completion packet */ - u_int32_t handshake_ack; + enum tcp_conntrack state; /* state of the connection */ + struct ip_ct_tcp_state seen[2]; /* connection parameters per direction */ }; +/* For NAT, when it mangles the packet */ +extern void ip_conntrack_tcp_update(struct ip_conntrack *conntrack, int dir, + struct iphdr *iph, size_t newlen, + struct tcphdr *tcph); + + #endif /* _IP_CONNTRACK_TCP_H */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_nat.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_nat.h Thu Apr 26 00:00:28 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_nat.h Sun Apr 28 21:55:46 2002 @@ -11,8 +11,13 @@ IP_NAT_MANIP_DST }; +#ifndef CONFIG_IP_NF_NAT_LOCAL /* SRC manip occurs only on POST_ROUTING */ #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING) +#else +/* SRC manip occurs POST_ROUTING or LOCAL_IN */ +#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN) +#endif /* 2.3.19 (I hope) will define this in linux/netfilter_ipv4.h. */ #ifndef SO_ORIGINAL_DST diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_pool.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_pool.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ip_pool.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ip_pool.h Sun Apr 28 22:24:38 2002 @@ -0,0 +1,64 @@ +#ifndef _IP_POOL_H +#define _IP_POOL_H + +/***************************************************************************/ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/***************************************************************************/ + +/* A sockopt of such quality has hardly ever been seen before on the open + * market! This little beauty, hardly ever used: above 64, so it's + * traditionally used for firewalling, not touched (even once!) by the + * 2.0, 2.2 and 2.4 kernels! + * + * Comes with its own certificate of authenticity, valid anywhere in the + * Free world! + * + * Rusty, 19.4.2000 + */ +#define SO_IP_POOL 81 + +typedef int ip_pool_t; /* pool index */ +#define IP_POOL_NONE ((ip_pool_t)-1) + +struct ip_pool_request { + int op; + ip_pool_t index; + u_int32_t addr; + u_int32_t addr2; +}; + +/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */ + +#define IP_POOL_BAD001 0x00000010 + +#define IP_POOL_FLUSH 0x00000011 /* req.index, no arguments */ +#define IP_POOL_INIT 0x00000012 /* from addr to addr2 incl. */ +#define IP_POOL_DESTROY 0x00000013 /* req.index, no arguments */ +#define IP_POOL_ADD_ADDR 0x00000014 /* add addr to pool */ +#define IP_POOL_DEL_ADDR 0x00000015 /* del addr from pool */ +#define IP_POOL_HIGH_NR 0x00000016 /* result in req.index */ +#define IP_POOL_LOOKUP 0x00000017 /* result in addr and addr2 */ +#define IP_POOL_USAGE 0x00000018 /* result in addr */ +#define IP_POOL_TEST_ADDR 0x00000019 /* result (0/1) returned */ + +#ifdef __KERNEL__ + +/* NOTE: ip_pool_match() and ip_pool_mod() expect ADDR to be host byte order */ +extern int ip_pool_match(ip_pool_t pool, u_int32_t addr); +extern int ip_pool_mod(ip_pool_t pool, u_int32_t addr, int isdel); + +#endif + +#endif /*_IP_POOL_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_CONNMARK.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_CONNMARK.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_CONNMARK.h Sun Apr 28 22:09:41 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_DSCP.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_DSCP.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_DSCP.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_DSCP.h Sun Apr 28 22:31:21 2002 @@ -0,0 +1,22 @@ +/* iptables module for setting the IPv4 DSCP field + * + * (C) 2002 Harald Welte + * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh + * This software is distributed under GNU GPL v2, 1991 + * + * See RFC2474 for a description of the DSCP field within the IP Header. + * + * ipt_DSCP.h,v 1.6 2002/02/25 09:41:23 laforge Exp +*/ +#ifndef _IPT_DSCP_H +#define _IPT_DSCP_H + +#define IPT_DSCP_MASK 0xfc /* 11111100 */ +#define IPT_DSCP_SHIFT 2 /* shift DSCP two bits for ECN */ +#define IPT_DSCP_MAX 0x3f /* 00111111 */ + +struct ipt_DSCP_info { + u_int8_t dscp; +}; + +#endif /* _IPT_DSCP_H */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_NETLINK.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_NETLINK.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_NETLINK.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_NETLINK.h Sun Apr 28 22:32:39 2002 @@ -0,0 +1,27 @@ +#ifndef _IPT_FWMON_H +#define _IPT_FWMON_H + +/* Bitmask macros */ +#define MASK(x,y) (x & y) +#define MASK_SET(x,y) x |= y +#define MASK_UNSET(x,y) x &= ~y + +#define USE_MARK 0x00000001 +#define USE_DROP 0x00000002 +#define USE_SIZE 0x00000004 + +struct ipt_nldata +{ + unsigned int flags; + unsigned int mark; + unsigned int size; +}; + +/* Old header */ +struct netlink_t { + unsigned int len; + unsigned int mark; + char iface[IFNAMSIZ]; +}; + +#endif /*_IPT_FWMON_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_SAME.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_SAME.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_SAME.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_SAME.h Sun Apr 28 22:34:01 2002 @@ -0,0 +1,22 @@ +#ifndef _IPT_SAME_H +#define _IPT_SAME_H + +#define IPT_SAME_MAX_RANGE 10 + +#define IPT_SAME_NODST 0x01 + +struct ipt_same_info +{ + unsigned char info; + + unsigned int rangesize; + + unsigned int ipnum; + + u_int32_t *iparray; + + /* hangs off end. */ + struct ip_nat_range range[IPT_SAME_MAX_RANGE]; +}; + +#endif /*_IPT_SAME_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_TTL.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_TTL.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_TTL.h Sun Apr 28 22:34:32 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_bytelimit.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_bytelimit.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_bytelimit.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_bytelimit.h Sun Apr 28 21:47:58 2002 @@ -0,0 +1,17 @@ +#ifndef _IPT_BYTELIMIT_H +#define _IPT_BYTELIMIT_H + +struct ipt_bytelimitinfo { + u_int32_t rate; /* rate, in bytes per second */ + u_int32_t offset; /* Added to each packet length. */ + u_int64_t quota; /* maximal credit */ + u_int64_t credit; /* current quota */ + + /* Used internally by the kernel */ + unsigned long prev; /* last jiffy when the match was tested */ + u_int32_t tickrate; /* rate, in bytes per jiffy */ + + /* Ugly, ugly fucker. */ + struct ipt_bytelimitinfo *master; +}; +#endif /*_IPT_BYTELIMIT_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_connmark.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_connmark.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_connmark.h Sun Apr 28 22:09:41 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_conntrack.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_conntrack.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_conntrack.h Sun Apr 28 22:12:24 2002 @@ -0,0 +1,38 @@ +/* Header file for kernel module to match connection tracking information. + * GPL (C) 2001 Marc Boucher (marc@mbsi.ca). + */ + +#ifndef _IPT_CONNTRACK_H +#define _IPT_CONNTRACK_H + +#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1)) +#define IPT_CONNTRACK_STATE_INVALID (1 << 0) + +#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1)) +#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2)) + +/* flags, invflags: */ +#define IPT_CONNTRACK_STATE 0x01 +#define IPT_CONNTRACK_PROTO 0x02 +#define IPT_CONNTRACK_ORIGSRC 0x04 +#define IPT_CONNTRACK_ORIGDST 0x08 +#define IPT_CONNTRACK_REPLSRC 0x10 +#define IPT_CONNTRACK_REPLDST 0x20 +#define IPT_CONNTRACK_STATUS 0x40 +#define IPT_CONNTRACK_EXPIRES 0x80 + +struct ipt_conntrack_info +{ + unsigned int statemask, statusmask; + + struct ip_conntrack_tuple tuple[IP_CT_DIR_MAX]; + struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX]; + + unsigned long expires_min, expires_max; + + /* Flags word */ + u_int8_t flags; + /* Inverse flags */ + u_int8_t invflags; +}; +#endif /*_IPT_CONNTRACK_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_iplimit.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_iplimit.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_iplimit.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_iplimit.h Sun Apr 28 21:46:51 2002 @@ -0,0 +1,12 @@ +#ifndef _IPT_IPLIMIT_H +#define _IPT_IPLIMIT_H + +struct ipt_iplimit_data; + +struct ipt_iplimit_info { + int limit; + int inverse; + u_int32_t mask; + struct ipt_iplimit_data *data; +}; +#endif /* _IPT_IPLIMIT_H */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_ipv4options.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_ipv4options.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_ipv4options.h Sun Apr 28 22:23:44 2002 @@ -0,0 +1,21 @@ +#ifndef __ipt_ipv4options_h_included__ +#define __ipt_ipv4options_h_included__ + +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */ +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */ +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */ +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */ +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */ +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */ +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100 +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */ +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */ + +struct ipt_ipv4options_info { + u_int16_t options; +}; + + +#endif /* __ipt_ipv4options_h_included__ */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_mport.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_mport.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_mport.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_mport.h Sun Apr 28 21:59:30 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_nth.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_nth.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_nth.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_nth.h Sun Apr 28 22:00:58 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_owner.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_owner.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_owner.h Fri Mar 17 20:56:20 2000 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_owner.h Sun Apr 28 22:13:13 2002 @@ -6,12 +6,14 @@ #define IPT_OWNER_GID 0x02 #define IPT_OWNER_PID 0x04 #define IPT_OWNER_SID 0x08 +#define IPT_OWNER_COMM 0x10 struct ipt_owner_info { uid_t uid; gid_t gid; pid_t pid; pid_t sid; + char comm[16]; u_int8_t match, invert; /* flags */ }; diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_pkttype.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_pkttype.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_pkttype.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_pkttype.h Sun Apr 28 22:24:11 2002 @@ -0,0 +1,8 @@ +#ifndef _IPT_PKTTYPE_H +#define _IPT_PKTTYPE_H + +struct ipt_pkttype_info { + int pkttype; + int invert; +}; +#endif /*_IPT_PKTTYPE_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_pool.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_pool.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_pool.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_pool.h Sun Apr 28 22:24:38 2002 @@ -0,0 +1,25 @@ +#ifndef _IPT_POOL_H +#define _IPT_POOL_H + +#include + +#define IPT_POOL_INV_SRC 0x00000001 +#define IPT_POOL_INV_DST 0x00000002 +#define IPT_POOL_DEL_SRC 0x00000004 +#define IPT_POOL_DEL_DST 0x00000008 +#define IPT_POOL_INV_MOD_SRC 0x00000010 +#define IPT_POOL_INV_MOD_DST 0x00000020 +#define IPT_POOL_MOD_SRC_ACCEPT 0x00000040 +#define IPT_POOL_MOD_DST_ACCEPT 0x00000080 +#define IPT_POOL_MOD_SRC_DROP 0x00000100 +#define IPT_POOL_MOD_DST_DROP 0x00000200 + +/* match info */ +struct ipt_pool_info +{ + ip_pool_t src; + ip_pool_t dst; + unsigned flags; +}; + +#endif /*_IPT_POOL_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_psd.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_psd.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_psd.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_psd.h Sun Apr 28 22:09:21 2002 @@ -0,0 +1,40 @@ +#ifndef _IPT_PSD_H +#define _IPT_PSD_H + +#include +#include + +/* + * High port numbers have a lower weight to reduce the frequency of false + * positives, such as from passive mode FTP transfers. + */ +#define PORT_WEIGHT_PRIV 3 +#define PORT_WEIGHT_HIGH 1 + +/* + * Port scan detection thresholds: at least COUNT ports need to be scanned + * from the same source, with no longer than DELAY ticks between ports. + */ +#define SCAN_MIN_COUNT 7 +#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV) +#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT +#define SCAN_DELAY_THRESHOLD (HZ * 3) + +/* + * Keep track of up to LIST_SIZE source addresses, using a hash table of + * HASH_SIZE entries for faster lookups, but limiting hash collisions to + * HASH_MAX source addresses per the same hash value. + */ +#define LIST_SIZE 0x100 +#define HASH_LOG 9 +#define HASH_SIZE (1 << HASH_LOG) +#define HASH_MAX 0x10 + +struct ipt_psd_info { + unsigned int weight_threshold; + unsigned int delay_threshold; + unsigned short lo_ports_weight; + unsigned short hi_ports_weight; +}; + +#endif /*_IPT_PSD_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_quota.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_quota.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_quota.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_quota.h Sun Apr 28 22:06:40 2002 @@ -0,0 +1,11 @@ +#ifndef _IPT_QUOTA_H +#define _IPT_QUOTA_H + +/* print debug info in both kernel/netfilter module & iptable library */ +//#define DEBUG_IPT_QUOTA + +struct ipt_quota_info { + u_int64_t quota; +}; + +#endif /*_IPT_QUOTA_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_random.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_random.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_random.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_random.h Sun Apr 28 21:47:27 2002 @@ -0,0 +1,11 @@ +#ifndef _IPT_RAND_H +#define _IPT_RAND_H + +#include +#include + +struct ipt_rand_info { + u_int8_t average; +}; + +#endif /*_IPT_RAND_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_recent.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_recent.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_recent.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_recent.h Sun Apr 28 22:40:09 2002 @@ -0,0 +1,18 @@ +#ifndef _IPT_RECENT_H +#define _IPT_RECENT_H + +const static int IPT_RECENT_CHECK = 1; +const static int IPT_RECENT_SET = 2; +const static int IPT_RECENT_UPDATE = 4; +const static int IPT_RECENT_REMOVE = 8; +const static int IPT_RECENT_TTL = 16; + +struct ipt_recent_info { + u_int32_t seconds; + u_int32_t hit_count; + u_int8_t check_set; + u_int8_t invert; + char name[200]; +}; + +#endif /*_IPT_RECENT_H*/ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_time.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_time.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv4/ipt_time.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv4/ipt_time.h Sun Apr 28 22:07:44 2002 @@ -0,0 +1,13 @@ +#ifndef __ipt_time_h_included__ +#define __ipt_time_h_included__ + + +struct ipt_time_info { + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ + u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */ +}; + + +#endif /* __ipt_time_h_included__ */ diff -u --new-file --recursive linux-2.4.18_vanilla/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv6/ip6t_REJECT.h --- linux-2.4.18_vanilla/include/linux/netfilter_ipv6/ip6t_REJECT.h Tue Jun 20 23:32:27 2000 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/netfilter_ipv6/ip6t_REJECT.h Sun Apr 28 22:44:41 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/include/linux/sysctl.h linux-2.4.18_iptables-1.2.6a-extensions/include/linux/sysctl.h --- linux-2.4.18_vanilla/include/linux/sysctl.h Mon Nov 26 15:29:17 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/include/linux/sysctl.h Sun Apr 28 14:55:57 2002 @@ -231,6 +231,7 @@ NET_IPV4_NEIGH=17, NET_IPV4_ROUTE=18, NET_IPV4_FIB_HASH=19, + NET_IPV4_NETFILTER=20, NET_IPV4_TCP_TIMESTAMPS=33, NET_IPV4_TCP_WINDOW_SCALING=34, @@ -337,6 +338,28 @@ NET_IPV4_CONF_ARPFILTER=13 }; +enum +{ + NET_IPV4_NF_CONNTRACK_MAX=1, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_NONE=2, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=3, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=4, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=5, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=6, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=7, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=8, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=9, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=10, + NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LISTEN=11, + NET_IPV4_NF_CONNTRACK_TCP_LOG_INVALID_SCALE=12, + NET_IPV4_NF_CONNTRACK_TCP_LOG_OUT_OF_WINDOW=13, + NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL=14, + NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=15, + NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=16, + NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=17, + NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=18 +}; + /* /proc/sys/net/ipv6 */ enum { NET_IPV6_CONF=16, diff -u --new-file --recursive linux-2.4.18_vanilla/net/core/netfilter.c linux-2.4.18_iptables-1.2.6a-extensions/net/core/netfilter.c --- linux-2.4.18_vanilla/net/core/netfilter.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/core/netfilter.c Sun Apr 28 22:30:59 2002 @@ -65,6 +65,15 @@ for (i = nf_hooks[reg->pf][reg->hooknum].next; i != &nf_hooks[reg->pf][reg->hooknum]; i = i->next) { + /* assumption: If exact same thing already on the list + * we dont want to add a new one + */ + if ((reg->priority == ((struct nf_hook_ops *)i)->priority) + && (reg->hook == (((struct nf_hook_ops *)i)->hook))) { + br_write_unlock_bh(BR_NETPROTO_LOCK); + return -1; + } + if (reg->priority < ((struct nf_hook_ops *)i)->priority) break; } diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/arp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/arp.c --- linux-2.4.18_vanilla/net/ipv4/arp.c Fri Sep 7 20:01:20 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/arp.c Sun Apr 28 22:43:55 2002 @@ -112,7 +112,7 @@ #include #include - +#include /* * Interface to generic neighbour cache. @@ -561,7 +561,8 @@ arp_ptr+=dev->addr_len; memcpy(arp_ptr, &dest_ip, 4); - dev_queue_xmit(skb); + /* Send it off, maybe filter it using firewalling first. */ + NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, dev, dev_queue_xmit); return; out: @@ -574,45 +575,31 @@ } /* - * Receive an arp request by the device layer. + * Process an arp request. */ -int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +int arp_process(struct sk_buff *skb) { - struct arphdr *arp = skb->nh.arph; - unsigned char *arp_ptr= (unsigned char *)(arp+1); + struct net_device *dev = skb->dev; + struct in_device *in_dev = in_dev_get(dev); + struct arphdr *arp; + unsigned char *arp_ptr; struct rtable *rt; unsigned char *sha, *tha; u32 sip, tip; u16 dev_type = dev->type; int addr_type; - struct in_device *in_dev = in_dev_get(dev); struct neighbour *n; -/* - * The hardware length of the packet should match the hardware length - * of the device. Similarly, the hardware types should match. The - * device should be ARP-able. Also, if pln is not 4, then the lookup - * is not from an IP number. We can't currently handle this, so toss - * it. - */ - if (in_dev == NULL || - arp->ar_hln != dev->addr_len || - dev->flags & IFF_NOARP || - skb->pkt_type == PACKET_OTHERHOST || - skb->pkt_type == PACKET_LOOPBACK || - arp->ar_pln != 4) + /* arp_rcv below verifies the ARP header, verifies the device + * is ARP'able, and linearizes the SKB (if needed). + */ + + if (in_dev == NULL) goto out; - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) - goto out_of_mem; - - if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_ATOMIC) != 0) - goto freeskb; - arp = skb->nh.arph; - arp_ptr= (unsigned char *)(arp+1); - } + arp = skb->nh.arph; + arp_ptr= (unsigned char *)(arp+1); switch (dev_type) { default: @@ -827,13 +814,41 @@ out: if (in_dev) in_dev_put(in_dev); -freeskb: kfree_skb(skb); -out_of_mem: return 0; } +/* + * Receive an arp request from the device layer. + */ + +int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +{ + struct arphdr *arp = skb->nh.arph; + + if (arp->ar_hln != dev->addr_len || + dev->flags & IFF_NOARP || + skb->pkt_type == PACKET_OTHERHOST || + skb->pkt_type == PACKET_LOOPBACK || + arp->ar_pln != 4) + goto freeskb; + + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + goto out_of_mem; + + if (skb_is_nonlinear(skb)) { + if (skb_linearize(skb, GFP_ATOMIC) != 0) + goto freeskb; + } + + return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); + +freeskb: + kfree_skb(skb); +out_of_mem: + return 0; +} /* * User level interface (ioctl, /proc) diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/Config.in linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/Config.in --- linux-2.4.18_vanilla/net/ipv4/netfilter/Config.in Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/Config.in Mon Apr 29 00:35:26 2002 @@ -7,7 +7,11 @@ tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK + dep_tristate ' Eggdrop bot support' CONFIG_IP_NF_EGG $CONFIG_IP_NF_CONNTRACK + dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK + bool ' Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK + dep_tristate ' talk protocol support' CONFIG_IP_NF_TALK $CONFIG_IP_NF_CONNTRACK fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -17,25 +21,48 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then # The simple matches. dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES + + dep_tristate ' IP address pool support' CONFIG_IP_NF_POOL $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_POOL" = "y" -o "$CONFIG_IP_NF_POOL" = "m" ]; then + bool ' enable statistics on pool usage' CONFIG_IP_POOL_STATISTICS n + fi + + dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $CONFIG_IP_NF_IPTABLES dep_tristate ' MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES + dep_tristate ' Packet type match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES + dep_tristate ' Multiple port with ranges match support' CONFIG_IP_NF_MATCH_MPORT $CONFIG_IP_NF_IPTABLES dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES + dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES + dep_tristate ' IPV4OPTIONS match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_IPV4OPTIONS $CONFIG_IP_NF_IPTABLES + dep_tristate ' psd match support' CONFIG_IP_NF_MATCH_PSD $CONFIG_IP_NF_IPTABLES + dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES + dep_tristate ' Nth match support' CONFIG_IP_NF_MATCH_NTH $CONFIG_IP_NF_IPTABLES + dep_tristate ' random match support' CONFIG_IP_NF_MATCH_RANDOM $CONFIG_IP_NF_IPTABLES dep_tristate ' AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES dep_tristate ' LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES dep_tristate ' TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES dep_tristate ' tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES + dep_tristate ' Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then + dep_tristate ' Connection mark match support' CONFIG_IP_NF_MATCH_CONNMARK $CONFIG_IP_NF_IPTABLES + fi + dep_tristate ' Connections/IP limit match support' CONFIG_IP_NF_MATCH_IPLIMIT $CONFIG_IP_NF_IPTABLES fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES + dep_tristate ' Bytelimit match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_BYTELIMIT $CONFIG_IP_NF_IPTABLES dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES fi # The targets dep_tristate ' Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_FILTER" != "n" ]; then dep_tristate ' REJECT target support' CONFIG_IP_NF_TARGET_REJECT $CONFIG_IP_NF_FILTER +dep_tristate ' NETLINK target support' CONFIG_IP_NF_TARGET_NETLINK $CONFIG_IP_NF_FILTER + dep_tristate ' IPV4OPTSSTRIP target support' CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP $CONFIG_IP_NF_FILTER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' MIRROR target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_MIRROR $CONFIG_IP_NF_FILTER fi @@ -47,6 +74,18 @@ define_bool CONFIG_IP_NF_NAT_NEEDED y dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT + # If they want talk, set to $CONFIG_IP_NF_NAT (m or y), + # or $CONFIG_IP_NF_TALK (m or y), whichever is weaker. Argh. + if [ "$CONFIG_IP_NF_TALK" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_TALK m + else + if [ "$CONFIG_IP_NF_TALK" = "y" ]; then + define_tristate CONFIG_IP_NF_NAT_TALK $CONFIG_IP_NF_NAT + fi + fi + dep_tristate ' SAME target support' CONFIG_IP_NF_TARGET_SAME $CONFIG_IP_NF_NAT + dep_tristate ' NETMAP target support' CONFIG_IP_NF_TARGET_NETMAP $CONFIG_IP_NF_NAT + bool ' NAT of local connections' CONFIG_IP_NF_NAT_LOCAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT fi @@ -66,15 +105,28 @@ define_tristate CONFIG_IP_NF_NAT_FTP $CONFIG_IP_NF_NAT fi fi + if [ "$CONFIG_IP_NF_TFTP" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_TFTP m + else + if [ "$CONFIG_IP_NF_TFTP" = "y" ]; then + define_tristate CONFIG_IP_NF_NAT_TFTP $CONFIG_IP_NF_NAT + fi + fi fi fi dep_tristate ' Packet mangling' CONFIG_IP_NF_MANGLE $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_MANGLE" != "n" ]; then dep_tristate ' TOS target support' CONFIG_IP_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE + dep_tristate ' DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE + dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE fi dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES + dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then + dep_tristate ' CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK $CONFIG_IP_NF_IPTABLES + fi if [ "$CONFIG_NETLINK" != "n" ]; then dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_NETLINK $CONFIG_IP_NF_IPTABLES fi diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/Makefile linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/Makefile --- linux-2.4.18_vanilla/net/ipv4/netfilter/Makefile Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/Makefile Mon Apr 29 00:35:27 2002 @@ -30,6 +30,18 @@ # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o + +# talk protocol support +obj-$(CONFIG_IP_NF_TALK) += ip_conntrack_talk.o +obj-$(CONFIG_IP_NF_NAT_TALK) += ip_nat_talk.o +ifdef CONFIG_IP_NF_NAT_TALK + export-objs += ip_conntrack_talk.o +endif + +ifdef CONFIG_IP_NF_NAT_NEEDED + export-objs += ip_conntrack_proto_tcp.o +endif + # IRC support obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o @@ -37,9 +49,13 @@ # connection tracking helpers obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o +obj-$(CONFIG_IP_NF_EGG) += ip_conntrack_egg.o + +obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o # NAT helpers obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o +obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o @@ -51,29 +67,64 @@ # matches obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o +obj-$(CONFIG_IP_NF_POOL) += ipt_pool.o ipt_POOL.o ip_pool.o obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o + +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_RECENT) += ipt_recent.o + + +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o + + +obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o + +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o + + +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o + +obj-$(CONFIG_IP_NF_MATCH_RANDOM) += ipt_random.o obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o +obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o +obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o +obj-$(CONFIG_IP_NF_MATCH_IPLIMIT) += ipt_iplimit.o obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o +obj-$(CONFIG_IP_NF_MATCH_BYTELIMIT) += ipt_bytelimit.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o # targets obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o +obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o +obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o +obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.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_TTL) += ipt_TTL.o + +obj-$(CONFIG_IP_NF_TARGET_NETLINK) += ipt_NETLINK.o + +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o +obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_core.c Tue Aug 7 17:30:50 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_core.c Sun Apr 28 22:31:39 2002 @@ -50,7 +50,7 @@ LIST_HEAD(protocol_list); static LIST_HEAD(helpers); unsigned int ip_conntrack_htable_size = 0; -static int ip_conntrack_max = 0; +int ip_conntrack_max = 0; static atomic_t ip_conntrack_count = ATOMIC_INIT(0); struct list_head *ip_conntrack_hash; static kmem_cache_t *ip_conntrack_cachep; @@ -175,6 +175,7 @@ destroy_conntrack(struct nf_conntrack *nfct) { struct ip_conntrack *ct = (struct ip_conntrack *)nfct; + struct ip_conntrack_protocol *proto; IP_NF_ASSERT(atomic_read(&nfct->use) == 0); IP_NF_ASSERT(!timer_pending(&ct->timeout)); @@ -182,6 +183,13 @@ if (ct->master.master) nf_conntrack_put(&ct->master); + /* Let's hope we don't get any weird locking issues here. + * destroy_conntrack MUST NOT be called with a write lock + * to ip_conntrack_lock!!! -HW */ + proto = find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); + if (proto && proto->destroy) + proto->destroy(ct); + if (ip_conntrack_destroyed) ip_conntrack_destroyed(ct); kmem_cache_free(ip_conntrack_cachep, ct); @@ -554,6 +562,9 @@ conntrack->status = IPS_EXPECTED; conntrack->master.master = &expected->expectant->ct_general; IP_NF_ASSERT(conntrack->master.master); +#if CONFIG_IP_NF_CONNTRACK_MARK + conntrack->mark = expected->expectant->mark; +#endif LIST_DELETE(&expect_list, expected); expected->expectant = NULL; nf_conntrack_get(&conntrack->master); @@ -1015,29 +1026,6 @@ SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst, 0, NULL }; -#define NET_IP_CONNTRACK_MAX 2089 -#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max" - -#ifdef CONFIG_SYSCTL -static struct ctl_table_header *ip_conntrack_sysctl_header; - -static ctl_table ip_conntrack_table[] = { - { NET_IP_CONNTRACK_MAX, NET_IP_CONNTRACK_MAX_NAME, &ip_conntrack_max, - sizeof(ip_conntrack_max), 0644, NULL, proc_dointvec }, - { 0 } -}; - -static ctl_table ip_conntrack_dir_table[] = { - {NET_IPV4, "ipv4", NULL, 0, 0555, ip_conntrack_table, 0, 0, 0, 0, 0}, - { 0 } -}; - -static ctl_table ip_conntrack_root_table[] = { - {CTL_NET, "net", NULL, 0, 0555, ip_conntrack_dir_table, 0, 0, 0, 0, 0}, - { 0 } -}; -#endif /*CONFIG_SYSCTL*/ - static int kill_all(const struct ip_conntrack *i, void *data) { return 1; @@ -1047,9 +1035,6 @@ supposed to kill the mall. */ void ip_conntrack_cleanup(void) { -#ifdef CONFIG_SYSCTL - unregister_sysctl_table(ip_conntrack_sysctl_header); -#endif ip_ct_attach = NULL; /* This makes sure all current packets have passed through netfilter framework. Roll on, two-stage module @@ -1127,20 +1112,6 @@ for (i = 0; i < ip_conntrack_htable_size; i++) INIT_LIST_HEAD(&ip_conntrack_hash[i]); -/* This is fucking braindead. There is NO WAY of doing this without - the CONFIG_SYSCTL unless you don't want to detect errors. - Grrr... --RR */ -#ifdef CONFIG_SYSCTL - ip_conntrack_sysctl_header - = register_sysctl_table(ip_conntrack_root_table, 0); - if (ip_conntrack_sysctl_header == NULL) { - kmem_cache_destroy(ip_conntrack_cachep); - vfree(ip_conntrack_hash); - nf_unregister_sockopt(&so_getorigdst); - return -ENOMEM; - } -#endif /*CONFIG_SYSCTL*/ - /* For use by ipt_REJECT */ ip_ct_attach = ip_conntrack_attach; return ret; diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_egg.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_egg.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_egg.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_egg.c Sun Apr 28 22:54:09 2002 @@ -0,0 +1,228 @@ +/* Eggdrop extension for IP connection tracking, Version 0.0.3 + * based on ip_conntrack_irc.c + * + * This module only supports the share userfile-send command, + * used by eggdrops to share it's userfile. + * + * There are no support for NAT at the moment. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * + * please give the ports of all Eggdrops You have running + * on your system, the default port is 3333. + * + * 2001-04-19: Security update. IP addresses are now compared + * to prevent unauthorized "related" access. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +MODULE_AUTHOR("Magnus Sandin "); +MODULE_DESCRIPTION("Eggdrop (userfile-sharing) connection tracking module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of eggdrop servers"); +#endif + +DECLARE_LOCK(ip_egg_lock); +struct module *ip_conntrack_egg = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +int parse_command(char *data, char *data_end, u_int32_t * ip, u_int16_t * port) +/* tries to get the ip_addr and port out of a eggdrop command + return value: -1 on failure, 0 on success + data pointer to first byte of DCC command data + data_end pointer to last byte of dcc command data + ip returns parsed ip of dcc command + port returns parsed port of dcc command */ +{ + if (data > data_end) + return -1; + + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ + while (*data == ' ' && data < data_end) + data++; + + *port = simple_strtoul(data, &data, 10); + return 0; +} + + +/* FIXME: This should be in userspace. Later. */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + char *data = (char *) tcph + tcph->doff * 4; + char *data_limit; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + int bytes_scanned = 0; + struct ip_conntrack_tuple t, mask; + + u_int32_t egg_ip; + u_int16_t egg_port; + + memset(&mask, 0, sizeof(struct ip_conntrack_tuple)); + mask.dst.u.tcp.port = 0xFFFF; + mask.dst.protonum = 0xFFFF; + + DEBUGP("ip_ct_egg: help entered\n"); + + /* If packet is coming from IRC server */ + if (dir != IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ip_ct_egg: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("ip_ct_egg: tcplen = %u\n", (unsigned) tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP ("ip_ct_egg: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + data_limit = (char *) data + datalen; + while (datalen > 5 && bytes_scanned < 128) { + if (memcmp(data, "s us ", 5)) { + data++; + datalen--; + bytes_scanned++; + continue; + } + + data += 5; + + DEBUGP ("ip_ct_egg: Userfile-share found in connection %u.%u.%u.%u %u.%u.%u.%u\n", + NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + + if (parse_command + ((char *) data, data_limit, &egg_ip, + &egg_port)) { + DEBUGP ("ip_ct_egg: Didn't find any data in the Userfile-share packet\n"); + return NF_ACCEPT; + } + + memset(&t, 0, sizeof(t)); + t.src.ip = iph->daddr; + t.src.u.tcp.port = 0; + t.dst.ip = htonl(egg_ip); + t.dst.u.tcp.port = htons(egg_port); + t.dst.protonum = IPPROTO_TCP; + + if (ct->tuplehash[dir].tuple.src.ip != htonl(egg_ip)) { + if (net_ratelimit()) + printk("Forged Eggdrop command from " + "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + HIPQUAD(egg_ip), egg_port); + return NF_ACCEPT; + } + + DEBUGP ("ip_ct_egg: expect_related %u.%u.%u.%u:%u - %u.%u.%u.%u:%u\n", + NIPQUAD(t.src.ip), + ntohs(t.src.u.tcp.port), + NIPQUAD(t.dst.ip), + ntohs(t.dst.u.tcp.port)); + + ip_conntrack_expect_related(ct, &t, + &mask, + NULL); + break; + } + return NF_ACCEPT; +} + +static struct ip_conntrack_helper egg_helpers[MAX_PORTS]; + +static void __exit fini(void); + +static int __init init(void) +{ + int i, ret; + + /* If no port given, default to standard eggdrop port */ + if (ports[0] == 0) + ports[0] = 3333; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + memset(&egg_helpers[i], 0, + sizeof(struct ip_conntrack_helper)); + egg_helpers[i].tuple.src.u.tcp.port = htons(ports[i]); + egg_helpers[i].tuple.dst.protonum = IPPROTO_TCP; + egg_helpers[i].mask.src.u.tcp.port = 0xFFFF; + egg_helpers[i].mask.dst.protonum = 0xFFFF; + egg_helpers[i].help = help; + + DEBUGP("ip_ct_egg: port #%d: %d\n", i, ports[i]); + + ret = ip_conntrack_helper_register(&egg_helpers[i]); + + if (ret) { + printk("ip_ct_egg: ERROR registering port %d\n", + ports[i]); + fini(); + return 1; + } + ports_n_c++; + } + return 0; +} + +static void __exit fini(void) +{ + int i; + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("ip_ct_egg: unregistering port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&egg_helpers[i]); + } +} + +module_init(init); +module_exit(fini); + + + + diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_ftp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_ftp.c Wed Oct 31 01:08:12 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_ftp.c Sun Apr 28 22:28:19 2002 @@ -15,7 +15,7 @@ #define MAX_PORTS 8 static int ports[MAX_PORTS]; -static int ports_c; +static int ports_c = 0; #ifdef MODULE_PARM MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); #endif @@ -380,7 +380,7 @@ static void fini(void) { int i; - for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + for (i = 0; i < ports_c; i++) { DEBUGP("ip_ct_ftp: unregistering helper for port %d\n", ports[i]); ip_conntrack_helper_unregister(&ftp[i]); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_irc.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_irc.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_irc.c Sun Apr 28 22:28:19 2002 @@ -29,7 +29,7 @@ #define MAX_PORTS 8 static int ports[MAX_PORTS]; -static int ports_n_c = 0; +static int ports_c = 0; MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("IRC (DCC) connection tracking module"); @@ -256,7 +256,7 @@ fini(); return -EBUSY; } - ports_n_c++; + ports_c++; } return 0; } @@ -266,7 +266,7 @@ static void fini(void) { int i; - for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + for (i = 0; i < ports_c; i++) { DEBUGP("unregistering port %d\n", ports[i]); ip_conntrack_helper_unregister(&irc_helpers[i]); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_generic.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_generic.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_generic.c Sun Apr 28 22:31:39 2002 @@ -4,7 +4,7 @@ #include #include -#define GENERIC_TIMEOUT (600*HZ) +unsigned long ip_ct_generic_timeout = 600*HZ; static int generic_pkt_to_tuple(const void *datah, size_t datalen, struct ip_conntrack_tuple *tuple) @@ -43,7 +43,7 @@ struct iphdr *iph, size_t len, enum ip_conntrack_info conntrackinfo) { - ip_ct_refresh(conntrack, GENERIC_TIMEOUT); + ip_ct_refresh(conntrack, ip_ct_generic_timeout); return NF_ACCEPT; } @@ -57,5 +57,5 @@ struct ip_conntrack_protocol ip_conntrack_generic_protocol = { { NULL, NULL }, 0, "unknown", generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple, - generic_print_conntrack, established, new, NULL }; + generic_print_conntrack, established, new, NULL, NULL }; diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_icmp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Sun Apr 28 22:31:39 2002 @@ -6,7 +6,7 @@ #include #include -#define ICMP_TIMEOUT (30*HZ) +unsigned long ip_ct_icmp_timeout = 30*HZ; #if 0 #define DEBUGP printk @@ -82,7 +82,7 @@ ct->timeout.function((unsigned long)ct); } else { atomic_inc(&ct->proto.icmp.count); - ip_ct_refresh(ct, ICMP_TIMEOUT); + ip_ct_refresh(ct, ip_ct_icmp_timeout); } return NF_ACCEPT; @@ -113,4 +113,4 @@ struct ip_conntrack_protocol ip_conntrack_protocol_icmp = { { NULL, NULL }, IPPROTO_ICMP, "icmp", icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple, - icmp_print_conntrack, icmp_packet, icmp_new, NULL }; + icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL }; diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_tcp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Sun Apr 28 22:31:39 2002 @@ -1,3 +1,14 @@ +/* + * TCP connection tracking + */ + +/* + * Changes: + * Jozsef Kadlecsik: Real stateful connection tracking + * Modified state transitions table + * Window scaling support + */ + #define __NO_VERSION__ #include #include @@ -7,12 +18,15 @@ #include #include #include +#include +#include #include #include #include #if 0 #define DEBUGP printk +#define DDEBUGP #else #define DEBUGP(format, args...) #endif @@ -20,6 +34,14 @@ /* Protects conntrack->proto.tcp */ static DECLARE_RWLOCK(tcp_lock); +/* Logging options */ +int ip_ct_tcp_log_invalid_scale = 1; +int ip_ct_tcp_log_out_of_window = 1; + +/* "Be conservative in what you do, + be liberal in what you accept from others." */ +int ip_ct_tcp_be_liberal = 0; + /* FIXME: Examine ipfilter's timeouts and conntrack transitions more closely. They're more complex. --RR */ @@ -30,66 +52,202 @@ static const char *tcp_conntrack_names[] = { "NONE", - "ESTABLISHED", "SYN_SENT", "SYN_RECV", + "ESTABLISHED", "FIN_WAIT", - "TIME_WAIT", - "CLOSE", "CLOSE_WAIT", "LAST_ACK", + "TIME_WAIT", + "CLOSE", "LISTEN" }; -#define SECS *HZ +#define SECS * HZ #define MINS * 60 SECS #define HOURS * 60 MINS #define DAYS * 24 HOURS - -static unsigned long tcp_timeouts[] -= { 30 MINS, /* TCP_CONNTRACK_NONE, */ - 5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */ - 2 MINS, /* TCP_CONNTRACK_SYN_SENT, */ - 60 SECS, /* TCP_CONNTRACK_SYN_RECV, */ - 2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */ - 2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */ - 10 SECS, /* TCP_CONNTRACK_CLOSE, */ - 60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */ - 30 SECS, /* TCP_CONNTRACK_LAST_ACK, */ - 2 MINS, /* TCP_CONNTRACK_LISTEN, */ +unsigned long ip_ct_tcp_timeout_none = 30 MINS; +unsigned long ip_ct_tcp_timeout_syn_sent = 2 MINS; +unsigned long ip_ct_tcp_timeout_syn_recv = 60 SECS; +unsigned long ip_ct_tcp_timeout_established = 5 DAYS; +unsigned long ip_ct_tcp_timeout_fin_wait = 2 MINS; +unsigned long ip_ct_tcp_timeout_close_wait = 12 HOURS; +unsigned long ip_ct_tcp_timeout_last_ack = 30 SECS; +unsigned long ip_ct_tcp_timeout_time_wait = 2 MINS; +unsigned long ip_ct_tcp_timeout_close = 10 SECS; +unsigned long ip_ct_tcp_timeout_listen = 2 MINS; + +static unsigned long * tcp_timeouts[] += { &ip_ct_tcp_timeout_none, /* TCP_CONNTRACK_NONE, */ + &ip_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ + &ip_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ + &ip_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */ + &ip_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */ + &ip_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */ + &ip_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */ + &ip_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */ + &ip_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */ + &ip_ct_tcp_timeout_listen, /* TCP_CONNTRACK_LISTEN, */ }; #define sNO TCP_CONNTRACK_NONE -#define sES TCP_CONNTRACK_ESTABLISHED #define sSS TCP_CONNTRACK_SYN_SENT #define sSR TCP_CONNTRACK_SYN_RECV +#define sES TCP_CONNTRACK_ESTABLISHED #define sFW TCP_CONNTRACK_FIN_WAIT -#define sTW TCP_CONNTRACK_TIME_WAIT -#define sCL TCP_CONNTRACK_CLOSE #define sCW TCP_CONNTRACK_CLOSE_WAIT #define sLA TCP_CONNTRACK_LAST_ACK +#define sTW TCP_CONNTRACK_TIME_WAIT +#define sCL TCP_CONNTRACK_CLOSE #define sLI TCP_CONNTRACK_LISTEN #define sIV TCP_CONNTRACK_MAX -static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] = { +/* + * The TCP state transition table needs a few words... + * + * We are the man in the middle. All the packets go through us + * but might get lost in transit to the destination. + * It is assumed that the destinations can't receive segments + * we haven't seen. + * + * The checked segment is in window. + * + * The meaning of the states are: + * + * NONE: initial state + * SYN_SENT: SYN-only packet seen + * SYN_RECV: SYN-ACK packet seen + * ESTABLISHED: ACK packet seen + * FIN_WAIT: FIN packet seen + * CLOSE_WAIT: ACK seen (after FIN) + * LAST_ACK: FIN seen (after FIN) + * TIME_WAIT: last ACK seen + * CLOSE: closed connection + * + * LISTEN state is not used. + * + */ +static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { { -/* ORIGINAL */ -/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */ -/*syn*/ {sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI }, -/*fin*/ {sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI }, -/*ack*/ {sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES }, -/*rst*/ {sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL }, -/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } +/* ORIGINAL */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*syn*/ { sSS, sSS, sCL, sCL, sCL, sCL, sCL, sSS, sSS, sIV }, +/* + * sNO -> sSS Initialize a new connection + * sSS -> sSS Retransmitted SYN + * sSR -> sCL Error: SYNs in window outside the SYN_SENT state + * are errors. Receiver will either go back to the + * LISTEN state or reply with RST. + * sES -> sCL + * sFW -> sCL + * sCW -> sCL + * sLA -> sCL + * sTW -> sSS Reopened connection (RFC 1122). + * sCL -> sSS + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*synack*/ { sSR, sSR, sES, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/* + * sNO -> sSR Assumed: hey, we've just started up! + * sSS -> sSR Simultaneous open. + * sSR -> sES Ditto. + * sES -> sCL Error. + * sFW -> sCL + * sCW -> sCL + * sLA -> sCL + * sTW -> sCL + * sCL -> sCL + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*fin*/ { sTW, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, +/* + * sNO -> sTW We assume TIME-WAIT state. + * sSS -> sIV Client migth not send FIN in this state. + * sSR -> sFW Close started. + * sES -> sFW + * sFW -> sLA FIN seen in both directions, waiting for + * the last ACK. + * Migth be a retransmitted FIN as well... + * sCW -> sLA + * sLA -> sLA Retransmitted FIN. Remain in the same state. + * sTW -> sTW + * sCL -> sCL + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, +/* + * sNO -> sES Assumed. + * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. + * sSR -> sES Established state is reached. + * sES -> sES :-) + * sFW -> sCW Normal close request answered by ACK. + * sCW -> sCW + * sLA -> sTW Last ACK detected. + * sTW -> sTW Retransmitted last ACK. Remain in the same state. + * sCL -> sCL + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*rst*/ { sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } }, { -/* REPLY */ -/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */ -/*syn*/ {sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }, -/*fin*/ {sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI }, -/*ack*/ {sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI }, -/*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI }, -/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } +/* REPLY */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*syn*/ { sIV, sSS, sSR, sCL, sCL, sCL, sCL, sSS, sSS, sIV }, +/* + * sNO -> sIV Never reached. + * sSS -> sSS Simultaneous open. + * sSR -> sSR Simultaneous open, retransmitted SYN. + * We have seen a SYN/ACK, but it seems + * it is delayed or got lost. + * sES -> sCL Error. + * sFW -> sCL + * sCW -> sCL + * sLA -> sCL + * sTW -> sSS Reopened connection. + * sCL -> sSS + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*synack*/ { sIV, sSR, sES, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/* + * sSS -> sSR Standard open. + * sSR -> sES Simultaneous open. + * sES -> sCL Error. + * sFW -> sCL + * sCW -> sCL + * sLA -> sCL + * sTW -> sCL + * sCL -> sCL + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, +/* + * sSS -> sIV Server might not send FIN in this state. + * sSR -> sFW Close started. + * sES -> sFW + * sFW -> sLA FIN seen in both directions. + * sCW -> sLA + * sLA -> sLA Retransmitted FIN. + * sTW -> sTW + * sCL -> sCL + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*ack*/ { sIV, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, +/* + * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. + * sSR -> sES Simultaneous open. + * sES -> sES :-) + * sFW -> sCW Normal close request answered by ACK. + * sCW -> sCW + * sLA -> sTW Last ACK detected. + * sTW -> sTW Retransmitted last ACK. + * sCL -> sCL + */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/*rst*/ { sIV, sCL, sCL, sCL, sCL, sIV, sCL, sCL, sCL, sIV }, +/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } } }; @@ -136,19 +294,337 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph) { - if (tcph->rst) return 3; - else if (tcph->syn) return 0; - else if (tcph->fin) return 1; - else if (tcph->ack) return 2; - else return 4; + if (tcph->rst) return 4; + else if (tcph->syn) return (tcph->ack ? 1 : 0); + else if (tcph->fin) return 2; + else if (tcph->ack) return 3; + else return 5; +} + +/* From ipt_LOG.c... */ +/* Use lock to serialize, so printks don't overlap */ +static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; + +static void log_packet(struct iphdr *iph, struct tcphdr *tcph) +{ + /* Important fields: + * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ + /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ + printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", + NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + + /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ + printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", + ntohs(iph->tot_len), iph->tos & IPTOS_TOS_MASK, + iph->tos & IPTOS_PREC_MASK, iph->ttl, ntohs(iph->id)); + + /* Max length: 6 "CE DF MF " */ + if (ntohs(iph->frag_off) & IP_CE) + printk("CE "); + if (ntohs(iph->frag_off) & IP_DF) + printk("DF "); + /* ... but conntrack don't see fragments */ + + if (iph->ihl * 4 != sizeof(struct iphdr)) { + unsigned int i; + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + printk("OPT ("); + for (i = sizeof(struct iphdr); i < iph->ihl * 4; i++) + printk("%02X", ((u_int8_t *)iph)[i]); + printk(") "); + } + + /* Max length: 10 "PROTO=TCP " */ + printk("PROTO=TCP "); + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + printk("SPT=%u DPT=%u ", + ntohs(tcph->source), ntohs(tcph->dest)); + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ + printk("SEQ=%u ACK=%u ", + ntohl(tcph->seq), ntohl(tcph->ack_seq)); + /* Max length: 13 "WINDOW=65535 " */ + printk("WINDOW=%u ", ntohs(tcph->window)); + /* Max length: 9 "RES=0x3F " */ + printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22)); + /* Max length: 36 "URG ACK PSH RST SYN FIN " */ + if (tcph->urg) + printk("URG "); + if (tcph->ack) + printk("ACK "); + if (tcph->psh) + printk("PSH "); + if (tcph->rst) + printk("RST "); + if (tcph->syn) + printk("SYN "); + if (tcph->fin) + printk("FIN "); + /* Max length: 11 "URGP=65535 " */ + printk("URGP=%u ", ntohs(tcph->urg_ptr)); + + if (tcph->doff * 4 != sizeof(struct tcphdr)) { + unsigned int i; + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + printk("OPT ("); + for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++) + printk("%02X", ((u_int8_t *)tcph)[i]); + printk(") "); + } + + /* Proto Max log string length */ + /* IP: 40+46+6+11+127 = 230 */ + /* TCP: 10+max(25,20+30+13+9+36+11+127) = 256 */ +} + +#define log_invalid_packet(iph, tcph, format, arg...) \ +do { \ + spin_lock_bh(&log_lock); \ + log_packet(iph, tcph); \ + printk(format, ## arg); \ + spin_unlock_bh(&log_lock); \ +} while (0); + +/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering + in IP Filter' by Guido van Rooij. + + http://www.nluug.nl/events/sane2000/papers.html + http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz + + The boundaries according to the article: + + td_maxend = max(ack + max(win,1)) seen in reply packets + td_maxwin = max(max(win, 1)) seen in sent packets + td_end = max(seq + len) seen in sent packets + + I. Upper bound for valid data: seq + len <= sender.td_maxend + II. Lower bound for valid data: seq >= sender.td_end - receiver.td_maxwin + III. Upper bound for valid ack: ack <= receiver.td_end + IV. Lower bound for valid ack: ack >= receiver.td_end - MAXACKWINDOW + + The upper bound limit for a valid ack is not ignored - + we doesn't have to deal with fragments. +*/ + +#define SEGMENT_SEQ_PLUS_LEN(seq, len, iph, tcph) (seq + len - (iph->ihl + tcph->doff)*4 \ + + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0)) + +/* Fixme: what about big packets? */ +#define MAXACKWINCONST 66000 +#define MAXACKWINDOW(receiver) ((receiver)->td_scale && (receiver)->td_maxwin < MAXACKWINCONST \ + ? (receiver)->td_maxwin : MAXACKWINCONST) + +/* + * Simplified tcp_parse_options routine from tcp_input.c + */ +static u_int8_t tcp_scale_option(struct iphdr *iph, struct tcphdr *tcph) +{ + unsigned char *ptr; + int length = (tcph->doff*4) - sizeof(struct tcphdr); + + ptr = (unsigned char *)(tcph + 1); + + while (length > 0) { + int opcode=*ptr++; + int opsize; + + switch (opcode) { + case TCPOPT_EOL: + return 0; + case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ + length--; + continue; + default: + opsize=*ptr++; + if (opsize < 2) /* "silly options" */ + return 0; + if (opsize > length) + break; /* don't parse partial options */ + + if (opcode == TCPOPT_WINDOW && opsize == TCPOLEN_WINDOW) { + u_int8_t scale = *(u_int8_t *)ptr; + + if (scale > 14) { + /* See RFC1323 for an explanation of the limit to 14 */ + if (ip_ct_tcp_log_invalid_scale && net_ratelimit()) + log_invalid_packet(iph, tcph, "Illegal window scaling value %u > 14 ignored\n", + scale); + scale = 14; + } + return scale; + } + ptr += opsize - 2; + length -= opsize; + } + } + return 0; +} + +static int tcp_in_window(struct ip_ct_tcp_state *sender, + struct ip_ct_tcp_state *receiver, + struct iphdr *iph, size_t len, + struct tcphdr *tcph) +{ + __u32 seq, ack, end, swin; + __u16 win; + int res; + + /* + * Get the required data from the packet. + */ + seq = ntohl(tcph->seq); + ack = ntohl(tcph->ack_seq); + win = ntohs(tcph->window); + end = SEGMENT_SEQ_PLUS_LEN(seq, len, iph, tcph); + + DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu seq=%u ack=%u win=%u end=%u\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest), + seq, ack, win, end); + DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i receiver end=%u maxend=%u maxwin=%u scale=%i\n", + sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, + receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); + + if (sender->td_end == 0) { + /* + * Initialize sender data. + */ + if (tcph->syn && tcph->ack) { + /* + * Outgoing SYN-ACK in reply to a SYN. + * + * Fixme: here we loose supporting simultaneous open... + */ + sender->td_end = + sender->td_maxend = end; + sender->td_maxwin = (win == 0 ? 1 : win); + sender->td_scale = tcp_scale_option(iph, tcph); + } else { + /* + * We are in the middle of a connection, + * its history is lost for us. + * Let's try to use the data from the packet. + */ + sender->td_end = end; + sender->td_maxwin = (win == 0 ? 1 : win); + sender->td_maxend = end + sender->td_maxwin; + sender->td_scale = 0; + } + } + + if (!(tcph->ack)) { + /* + * If there is no ACK, just pretend it was set and OK. + */ + ack = receiver->td_end; + } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == (TCP_FLAG_ACK|TCP_FLAG_RST)) + && (ack == 0)) { + /* + * Broken TCP stacks, that set ACK in RST packets as well + * with zero ack value. + */ + ack = receiver->td_end; + } + + if (seq == end) + /* + * Packets contains no data: we assume it is valid + * and check the ack value only. + */ + seq = end = sender->td_end; + + DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i receiver end=%u maxend=%u maxwin=%u scale=%i\n", + sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, + receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); + DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu seq=%u ack=%u win=%u end=%u\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest), + seq, ack, win, end); + DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n", + before(end, sender->td_maxend + 1), + after(seq, sender->td_end - receiver->td_maxwin - 1), + before(ack, receiver->td_end + 1), + after(ack, receiver->td_end - MAXACKWINDOW(receiver))); + + if (before(end, sender->td_maxend + 1) && + after(seq, sender->td_end - receiver->td_maxwin - 1) && + before(ack, receiver->td_end + 1) && + after(ack, receiver->td_end - MAXACKWINDOW(receiver))) { + /* + * Take into account window scaling (RFC 1323). + */ + + swin = win; + + if (tcph->ack && sender->td_scale && receiver->td_scale) + swin <<= sender->td_scale; + /* + * Update sender data. + */ + if (sender->td_maxwin < swin) + sender->td_maxwin = swin; + if (after(end, sender->td_end)) + sender->td_end = end; + if (after(ack + swin, receiver->td_maxend - 1)) { + receiver->td_maxend = ack + swin; + if (win == 0) + receiver->td_maxend++; + } + res = 1; + } else { + if (ip_ct_tcp_log_out_of_window && net_ratelimit()) + log_invalid_packet(iph, tcph, "Out of window data: %s\n", + before(end, sender->td_maxend + 1) ? + after(seq, sender->td_end - receiver->td_maxwin - 1) ? + before(ack, receiver->td_end + 1) ? + after(ack, receiver->td_end - MAXACKWINDOW(receiver)) ? "BUG" + : "ACK is under the lower bound (possibly overly delayed ACK)" + : "ACK is over the upper bound (ACKed data has never seen yet)" + : "SEQ is under the lower bound (retransmitted already ACKed data)" + : "SEQ is over the upper bound (over the window of the receiver)"); + res = ip_ct_tcp_be_liberal && !tcph->rst; + } + + DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u receiver end=%u maxend=%u maxwin=%u\n", + res, sender->td_end, sender->td_maxend, sender->td_maxwin, + receiver->td_end, receiver->td_maxend, receiver->td_maxwin); + + return res; +} + +/* Update sender->td_end after NAT successfully mangled the packet */ +void ip_conntrack_tcp_update(struct ip_conntrack *conntrack, int dir, + struct iphdr *iph, size_t newlen, + struct tcphdr *tcph) +{ + __u32 end; +#ifdef DDEBUGP + struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir]; + struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir]; +#endif + + end = SEGMENT_SEQ_PLUS_LEN(ntohl(tcph->seq), newlen, iph, tcph); + + WRITE_LOCK(&tcp_lock); + /* + * We have to worry for the ack in the reply packet only... + */ + if (after(end, conntrack->proto.tcp.seen[dir].td_end)) + conntrack->proto.tcp.seen[dir].td_end = end; + WRITE_UNLOCK(&tcp_lock); + DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i receiver end=%u maxend=%u maxwin=%u scale=%i\n", + sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, + receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); } + /* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len, enum ip_conntrack_info ctinfo) { - enum tcp_conntrack newconntrack, oldtcpstate; + enum tcp_conntrack new_state, old_state; + enum ip_conntrack_dir dir; struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); /* We're guaranteed to have the base header, but maybe not the @@ -159,48 +635,65 @@ } WRITE_LOCK(&tcp_lock); - oldtcpstate = conntrack->proto.tcp.state; - newconntrack + old_state = conntrack->proto.tcp.state; + dir = CTINFO2DIR(ctinfo); + + new_state = tcp_conntracks - [CTINFO2DIR(ctinfo)] - [get_conntrack_index(tcph)][oldtcpstate]; + [dir] + [get_conntrack_index(tcph)][old_state]; + + if (new_state == TCP_CONNTRACK_SYN_SENT + && old_state >= TCP_CONNTRACK_TIME_WAIT) { + /* Attempt to reopen a closed connection. + * Delete this connection and look up again. */ + WRITE_UNLOCK(&tcp_lock); + if (del_timer(&conntrack->timeout)) + conntrack->timeout.function((unsigned long)conntrack); + return NF_REPEAT; + } else if (!(new_state == TCP_CONNTRACK_MAX + || tcp_in_window(&conntrack->proto.tcp.seen[dir], + &conntrack->proto.tcp.seen[!dir], + iph, len, tcph))) + new_state = TCP_CONNTRACK_MAX; + + DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest), + (tcph->syn ? 1 : 0), (tcph->ack ? 1 : 0), (tcph->fin ? 1 : 0), (tcph->rst ? 1 : 0), + old_state, new_state); /* Invalid */ - if (newconntrack == TCP_CONNTRACK_MAX) { + if (new_state == TCP_CONNTRACK_MAX) { DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n", - CTINFO2DIR(ctinfo), get_conntrack_index(tcph), - conntrack->proto.tcp.state); + dir, get_conntrack_index(tcph), + old_state); WRITE_UNLOCK(&tcp_lock); return -1; } - conntrack->proto.tcp.state = newconntrack; - - /* Poor man's window tracking: record SYN/ACK for handshake check */ - if (oldtcpstate == TCP_CONNTRACK_SYN_SENT - && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY - && tcph->syn && tcph->ack) - conntrack->proto.tcp.handshake_ack - = htonl(ntohl(tcph->seq) + 1); + conntrack->proto.tcp.state = new_state; WRITE_UNLOCK(&tcp_lock); - /* If only reply is a RST, we can consider ourselves not to - have an established connection: this is a fairly common - problem case, so we can delete the conntrack - immediately. --RR */ - if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) { - if (del_timer(&conntrack->timeout)) - conntrack->timeout.function((unsigned long)conntrack); - } else { - /* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */ - if (oldtcpstate == TCP_CONNTRACK_SYN_RECV - && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL - && tcph->ack && !tcph->syn - && tcph->ack_seq == conntrack->proto.tcp.handshake_ack) - set_bit(IPS_ASSURED_BIT, &conntrack->status); - - ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]); + if (!(conntrack->status & IPS_SEEN_REPLY)) { + /* If only reply is a RST, we can consider ourselves not to + have an established connection: this is a fairly common + problem case, so we can delete the conntrack + immediately. --RR */ + if (tcph->rst) { + if (del_timer(&conntrack->timeout)) + conntrack->timeout.function((unsigned long)conntrack); + + return NF_ACCEPT; + } else { + /* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV + or a valid answer for an picked up connection */ + if ((old_state == TCP_CONNTRACK_SYN_RECV + || old_state == TCP_CONNTRACK_ESTABLISHED) + && new_state == TCP_CONNTRACK_ESTABLISHED) + set_bit(IPS_ASSURED_BIT, &conntrack->status); + } } + ip_ct_refresh(conntrack, *tcp_timeouts[new_state]); return NF_ACCEPT; } @@ -209,25 +702,59 @@ static int tcp_new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len) { - enum tcp_conntrack newconntrack; + enum tcp_conntrack new_state; struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); /* Don't need lock here: this conntrack not in circulation yet */ - newconntrack + new_state = tcp_conntracks[0][get_conntrack_index(tcph)] [TCP_CONNTRACK_NONE]; /* Invalid: delete conntrack */ - if (newconntrack == TCP_CONNTRACK_MAX) { + if (new_state == TCP_CONNTRACK_MAX) { DEBUGP("ip_conntrack_tcp: invalid new deleting.\n"); return 0; } - conntrack->proto.tcp.state = newconntrack; + if (new_state == TCP_CONNTRACK_SYN_SENT) { + conntrack->proto.tcp.seen[0].td_end = + SEGMENT_SEQ_PLUS_LEN(ntohl(tcph->seq), len, iph, tcph); + conntrack->proto.tcp.seen[0].td_maxwin = ntohs(tcph->window); + if (conntrack->proto.tcp.seen[0].td_maxwin == 0) + conntrack->proto.tcp.seen[0].td_maxwin = 1; + conntrack->proto.tcp.seen[0].td_maxend = + conntrack->proto.tcp.seen[0].td_end; + conntrack->proto.tcp.seen[0].td_scale = tcp_scale_option(iph, tcph); + } else { + /* + * We are in the middle of a connection, + * its history is lost for us. + * Let's try to use the data from the packet. + */ + conntrack->proto.tcp.seen[0].td_end = + SEGMENT_SEQ_PLUS_LEN(ntohl(tcph->seq), len, iph, tcph); + conntrack->proto.tcp.seen[0].td_maxwin = ntohs(tcph->window); + if (conntrack->proto.tcp.seen[0].td_maxwin == 0) + conntrack->proto.tcp.seen[0].td_maxwin = 1; + conntrack->proto.tcp.seen[0].td_maxend = + conntrack->proto.tcp.seen[0].td_end + + conntrack->proto.tcp.seen[0].td_maxwin; + conntrack->proto.tcp.seen[0].td_scale = 0; + } + + conntrack->proto.tcp.seen[1].td_end = 0; + conntrack->proto.tcp.seen[1].td_maxend = 0; + conntrack->proto.tcp.seen[1].td_maxwin = 1; + conntrack->proto.tcp.seen[1].td_scale = 0; + + conntrack->proto.tcp.state = new_state; + return 1; } +EXPORT_SYMBOL(ip_conntrack_tcp_update); + struct ip_conntrack_protocol ip_conntrack_protocol_tcp = { { NULL, NULL }, IPPROTO_TCP, "tcp", tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack, - tcp_packet, tcp_new, NULL }; + tcp_packet, tcp_new, NULL, NULL }; diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_udp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_proto_udp.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_proto_udp.c Sun Apr 28 22:31:39 2002 @@ -6,8 +6,8 @@ #include #include -#define UDP_TIMEOUT (30*HZ) -#define UDP_STREAM_TIMEOUT (180*HZ) +unsigned long ip_ct_udp_timeout = 30*HZ; +unsigned long ip_ct_udp_timeout_stream = 180*HZ; static int udp_pkt_to_tuple(const void *datah, size_t datalen, struct ip_conntrack_tuple *tuple) @@ -52,11 +52,11 @@ /* If we've seen traffic both ways, this is some kind of UDP stream. Extend timeout. */ if (conntrack->status & IPS_SEEN_REPLY) { - ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT); + ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream); /* Also, more likely to be important, and not a probe */ set_bit(IPS_ASSURED_BIT, &conntrack->status); } else - ip_ct_refresh(conntrack, UDP_TIMEOUT); + ip_ct_refresh(conntrack, ip_ct_udp_timeout); return NF_ACCEPT; } @@ -71,4 +71,4 @@ struct ip_conntrack_protocol ip_conntrack_protocol_udp = { { NULL, NULL }, IPPROTO_UDP, "udp", udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack, - udp_packet, udp_new, NULL }; + udp_packet, udp_new, NULL, NULL }; diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_standalone.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_standalone.c Sun Apr 28 22:09:41 2002 @@ -7,6 +7,7 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General Public Licence. */ +#include #include #include #include @@ -15,6 +16,9 @@ #include #include #include +#ifdef CONFIG_SYSCTL +#include +#endif #include #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) @@ -92,6 +96,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=%d ", conntrack->mark); +#endif len += sprintf(buffer + len, "\n"); return len; @@ -226,6 +233,114 @@ static struct nf_hook_ops ip_conntrack_local_in_ops = { { NULL, NULL }, ip_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST-1 }; +/* Sysctl support */ + +#ifdef CONFIG_SYSCTL + +/* From ip_conntrack_core.c */ +extern int ip_conntrack_max; + +/* From ip_conntrack_proto_tcp.c */ +extern unsigned long ip_ct_tcp_timeout_none; +extern unsigned long ip_ct_tcp_timeout_syn_sent; +extern unsigned long ip_ct_tcp_timeout_syn_recv; +extern unsigned long ip_ct_tcp_timeout_established; +extern unsigned long ip_ct_tcp_timeout_fin_wait; +extern unsigned long ip_ct_tcp_timeout_close_wait; +extern unsigned long ip_ct_tcp_timeout_last_ack; +extern unsigned long ip_ct_tcp_timeout_time_wait; +extern unsigned long ip_ct_tcp_timeout_close; +extern unsigned long ip_ct_tcp_timeout_listen; +extern int ip_ct_tcp_log_invalid_scale; +extern int ip_ct_tcp_log_out_of_window; +extern int ip_ct_tcp_be_liberal; + +/* From ip_conntrack_proto_udp.c */ +extern unsigned long ip_ct_udp_timeout; +extern unsigned long ip_ct_udp_timeout_stream; + +/* From ip_conntrack_proto_icmp.c */ +extern unsigned long ip_ct_icmp_timeout; + +/* From ip_conntrack_proto_icmp.c */ +extern unsigned long ip_ct_generic_timeout; + +static struct ctl_table_header *ip_ct_sysctl_header; + +static ctl_table ip_ct_sysctl_table[19] = { + {NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max", + &ip_conntrack_max, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_NONE, "ip_conntrack_tcp_timeout_none", + &ip_ct_tcp_timeout_none, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, "ip_conntrack_tcp_timeout_syn_sent", + &ip_ct_tcp_timeout_syn_sent, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, "ip_conntrack_tcp_timeout_syn_recv", + &ip_ct_tcp_timeout_syn_recv, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, "ip_conntrack_tcp_timeout_established", + &ip_ct_tcp_timeout_established, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, "ip_conntrack_tcp_timeout_fin_wait", + &ip_ct_tcp_timeout_fin_wait, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, "ip_conntrack_tcp_timeout_close_wait", + &ip_ct_tcp_timeout_close_wait, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, "ip_conntrack_tcp_timeout_last_ack", + &ip_ct_tcp_timeout_last_ack, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, "ip_conntrack_tcp_timeout_time_wait", + &ip_ct_tcp_timeout_time_wait, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, "ip_conntrack_tcp_timeout_close", + &ip_ct_tcp_timeout_close, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LISTEN, "ip_conntrack_tcp_timeout_listen", + &ip_ct_tcp_timeout_listen, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_LOG_INVALID_SCALE, "ip_conntrack_tcp_log_invalid_scale", + &ip_ct_tcp_log_invalid_scale, sizeof(unsigned int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_NF_CONNTRACK_TCP_LOG_OUT_OF_WINDOW, "ip_conntrack_tcp_log_out_of_window", + &ip_ct_tcp_log_out_of_window, sizeof(unsigned int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL, "ip_conntrack_tcp_be_liberal", + &ip_ct_tcp_be_liberal, sizeof(unsigned int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, "ip_conntrack_udp_timeout", + &ip_ct_udp_timeout, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, "ip_conntrack_udp_timeout_stream", + &ip_ct_udp_timeout_stream, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, "ip_conntrack_icmp_timeout", + &ip_ct_icmp_timeout, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, "ip_conntrack_generic_timeout", + &ip_ct_generic_timeout, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {0} +}; + +static ctl_table ip_ct_netfilter_table[] = { + {NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0}, + {0} +}; + +static ctl_table ip_ct_ipv4_table[] = { + {NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0}, + {0} +}; + +static ctl_table ip_ct_net_table[] = { + {CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0}, + {0} +}; +#endif + static int init_or_cleanup(int init) { struct proc_dir_entry *proc; @@ -261,10 +376,20 @@ printk("ip_conntrack: can't register local in hook.\n"); goto cleanup_inoutandlocalops; } +#ifdef CONFIG_SYSCTL + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); + if (ip_ct_sysctl_header == NULL) { + printk("ip_conntrack: can't register to sysctl.\n"); + goto cleanup; + } +#endif return ret; cleanup: +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(ip_ct_sysctl_header); +#endif nf_unregister_hook(&ip_conntrack_local_in_ops); cleanup_inoutandlocalops: nf_unregister_hook(&ip_conntrack_out_ops); @@ -335,6 +460,7 @@ EXPORT_SYMBOL(ip_ct_selective_cleanup); EXPORT_SYMBOL(ip_ct_refresh); EXPORT_SYMBOL(ip_conntrack_expect_related); +EXPORT_SYMBOL(ip_conntrack_find_get); EXPORT_SYMBOL(ip_conntrack_tuple_taken); EXPORT_SYMBOL(ip_ct_gather_frags); EXPORT_SYMBOL(ip_conntrack_htable_size); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_talk.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_talk.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_talk.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_talk.c Sun Apr 28 22:40:28 2002 @@ -0,0 +1,290 @@ +/* + * talk extension for IP connection tracking. + * Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[01] + * + * talk=[0|1] disable|enable old talk support + * ntalk=[0|1] disable|enable ntalk support + * ntalk2=[0|1] disable|enable ntalk2 support + * + * The default is talk=1 ntalk=1 ntalk2=1 + * + ** + * + * ASCII art on talk protocols + * + * + * caller server callee server + * | \ / + * | \ / + * | \ / + * | / + * | / \ + * 2 | 1 / \ 3 + * caller client ----------- callee client + * 4 + * + * 1. caller client <-> callee server: LOOK_UP, then ANNOUNCE invitation + * ( 2. caller client <-> caller server: LEAVE_INVITE to server ) + * 3. callee client <-> caller server: LOOK_UP invitation + * 4. callee client <-> caller client: talk data channel + * + * [1]: M. Hunter, talk: a historical protocol for interactive communication + * draft-hunter-talk-00.txt + * [2]: D.B. Chapman, E.D. Zwicky: Building Internet Firewalls (O'Reilly) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Default all talk protocols are supported */ +static int talk = 1; +static int ntalk = 1; +static int ntalk2 = 1; +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("talk connection tracking module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(talk, "i"); +MODULE_PARM_DESC(talk, "support (old) talk protocol"); +MODULE_PARM(ntalk, "i"); +MODULE_PARM_DESC(ntalk, "support ntalk protocol"); +MODULE_PARM(ntalk2, "i"); +MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol"); +#endif + +DECLARE_LOCK(ip_talk_lock); +struct module *ip_conntrack_talk = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static int talk_help_response(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + int talk_port, + u_char type, + u_char answer, + struct talk_addr *addr) +{ + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_tuple t, mask; + struct ip_ct_talk *info = &ct->help.ct_talk_info; + + DEBUGP("ip_ct_talk_help_response: %u.%u.%u.%u:%u, type %d answer %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + type, answer); + + if (answer != SUCCESS) + return NF_ACCEPT; + + if (type == ANNOUNCE) { + + DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n"); + + /* update the talk info */ + LOCK_BH(&ip_talk_lock); + info->is_talk = talk_port; + info->port = htons(talk_port); + + /* expect callee client -> caller server message */ + t = ((struct ip_conntrack_tuple) + { { ct->tuplehash[dir].tuple.src.ip, + { 0 } }, + { ct->tuplehash[dir].tuple.dst.ip, + { htons(talk_port) }, + IPPROTO_UDP }}); + mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + + DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller daemon %u.%u.%u.%u:%u!\n", + NIPQUAD(t.src.ip), ntohs(t.src.u.udp.port), + NIPQUAD(t.dst.ip), ntohs(t.dst.u.udp.port)); + + /* Ignore failure; should only happen with NAT */ + ip_conntrack_expect_related(ct, &t, &mask, NULL); + UNLOCK_BH(&ip_talk_lock); + } + if (type == LOOK_UP) { + + DEBUGP("ip_ct_talk_help_response: LOOK_UP\n"); + + /* update the talk info */ + LOCK_BH(&ip_talk_lock); + info->is_talk = talk_port; + info->port = addr->ta_port; + + /* expect callee client -> caller client connection */ + t = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, + { 0 } }, + { addr->ta_addr, + { addr->ta_port }, + IPPROTO_TCP }}); + mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + + DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller client %u.%u.%u.%u:%u!\n", + NIPQUAD(t.src.ip), ntohs(t.src.u.tcp.port), + NIPQUAD(t.dst.ip), ntohs(t.dst.u.tcp.port)); + + /* Ignore failure; should only happen with NAT */ + ip_conntrack_expect_related(ct, &t, &mask, NULL); + UNLOCK_BH(&ip_talk_lock); + } + + return NF_ACCEPT; +} + +/* FIXME: This should be in userspace. Later. */ +static int talk_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + int talk_port) +{ + struct udphdr *udph = (void *)iph + iph->ihl * 4; + const char *data = (const char *)udph + sizeof(struct udphdr); + int dir = CTINFO2DIR(ctinfo); + size_t udplen; + struct ip_ct_talk *info = &ct->help.ct_talk_info; + + DEBUGP("ip_ct_talk_help: help entered\n"); + /* Can't track connections formed before we registered */ + if (!info) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ip_ct_talk_help: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole UDP header? */ + udplen = len - iph->ihl * 4; + if (udplen < sizeof(struct udphdr)) { + DEBUGP("ip_ct_talk_help: too short for udph, udplen = %u\n", (unsigned)udplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, udplen, 0))) { + DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + udph, udplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + DEBUGP("ip_ct_talk_help: %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(udph->source), NIPQUAD(iph->daddr), ntohs(udph->dest)); + + if (dir == IP_CT_DIR_ORIGINAL) + return NF_ACCEPT; + + if (talk_port == TALK_PORT + && udplen == sizeof(struct udphdr) + sizeof(struct talk_response)) + return talk_help_response(iph, len, ct, ctinfo, talk_port, + ((struct talk_response *)data)->type, + ((struct talk_response *)data)->answer, + &(((struct talk_response *)data)->addr)); + else if (talk_port == NTALK_PORT + && ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response) + && ((struct ntalk_response *)data)->vers == NTALK_VERSION) + return talk_help_response(iph, len, ct, ctinfo, talk_port, + ((struct ntalk_response *)data)->type, + ((struct ntalk_response *)data)->answer, + &(((struct ntalk_response *)data)->addr)); + else if (talk_port == NTALK_PORT + && ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response) + && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION) + return talk_help_response(iph, len, ct, ctinfo, talk_port, + ((struct ntalk2_response *)data)->type, + ((struct ntalk2_response *)data)->answer, + &(((struct ntalk2_response *)data)->addr)); + else { + DEBUGP("ip_ct_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_response), sizeof(struct ntalk2_response)); + return NF_ACCEPT; + } +} + +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(iph, len, ct, ctinfo, TALK_PORT); +} + +static int nhelp(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(iph, len, ct, ctinfo, NTALK_PORT); +} + +static struct ip_conntrack_helper talk_helpers[2] = { { { NULL, NULL }, + { { 0, { __constant_htons(TALK_PORT) } }, + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, + { 0, { 0 }, 0xFFFF } }, + help }, + { { NULL, NULL }, + { { 0, { __constant_htons(NTALK_PORT) } }, + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, + { 0, { 0 }, 0xFFFF } }, + nhelp } + }; + +static int __init init(void) +{ + if (talk > 0) + ip_conntrack_helper_register(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_conntrack_helper_register(&talk_helpers[1]); + + return 0; +} + +static void __exit fini(void) +{ + if (talk > 0) + ip_conntrack_helper_unregister(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_conntrack_helper_unregister(&talk_helpers[1]); +} + +#ifdef CONFIG_IP_NF_NAT_NEEDED +int ip_conntrack_talk_forceload(void) +{ + return 0; +} + +EXPORT_SYMBOL(ip_talk_lock); +EXPORT_SYMBOL(ip_conntrack_talk_forceload); +#endif + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_tftp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_conntrack_tftp.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_conntrack_tftp.c Sun Apr 28 22:41:27 2002 @@ -0,0 +1,123 @@ +/* + * Licensed under GNU GPL version 2 Copyright Magnus Boden + * Version: 0.0.7 + * + */ + +#include +#include +#include + +#include +#include +#include + +#define TFTP_PORT 69 +#define OPCODE_READ 1 +#define OPCODE_WRITE 2 + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("Netfilter connection tracking module for tftp"); +MODULE_LICENSE("GPL"); + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of tftp servers"); +#endif + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct tftphdr { + u_int16_t opcode; +}; + +static int tftp_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct udphdr *udph = (void *)iph + iph->ihl * 4; + struct tftphdr *tftph = (void *)udph + 8; + struct ip_conntrack_tuple t, m; + + switch(ntohs(tftph->opcode)) { + /* RRQ and WRQ works the same way */ + case OPCODE_READ: + case OPCODE_WRITE: + DEBUGP("<1> ip_ct_tftp: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u - %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port)); + memset(&t, 0, sizeof(struct ip_conntrack_tuple)); + memset(&m, 0, sizeof(struct ip_conntrack_tuple)); + t.dst.protonum = IPPROTO_UDP; + m.dst.protonum = 0xFFFF; + t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + m.src.ip = 0xFFFF; + t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + m.dst.ip = 0xFFFF; + t.dst.u.udp.port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; + m.dst.u.udp.port = 0xFFFF; + ip_conntrack_expect_related(ct, &t, &m, NULL); + break; + default: + DEBUGP("<1> ip_ct_tftp: Unknown opcode\n"); + } + return(NF_ACCEPT); +} + +static struct ip_conntrack_helper tftp[MAX_PORTS]; + +static void fini(void) +{ + int i; + + for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { + DEBUGP("<1> Unregistering ip_conntrack_tftp.o for port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&tftp[i]); + } +} + +static int __init init(void) +{ + int i, ret; + + if(!ports[0]) + ports[0]=TFTP_PORT; + + for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { + /* Create helper structure */ + memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); + + tftp[i].tuple.dst.protonum = IPPROTO_UDP; + tftp[i].tuple.src.u.udp.port = htons(ports[i]); + tftp[i].mask.dst.protonum = 0xFFFF; + tftp[i].mask.src.u.udp.port = 0xFFFF; + tftp[i].help = tftp_help; + + DEBUGP("<1> Registering ip_conntrack_tftp.o for port %d\n", + ports[i]); + + ret=ip_conntrack_helper_register(&tftp[i]); + if(ret) { + fini(); + return(ret); + } + } + + return(0); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_fw_compat_redir.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_fw_compat_redir.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_fw_compat_redir.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_fw_compat_redir.c Sun Apr 28 22:29:47 2002 @@ -43,7 +43,7 @@ netplay... */ \ printk("ASSERT: %s:%i(%s)\n", \ __FILE__, __LINE__, __FUNCTION__); \ -} while(0); +} while(0) #else #define IP_NF_ASSERT(x) #endif diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_core.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_core.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_core.c Fri Dec 21 19:42:05 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_core.c Sun Apr 28 21:55:46 2002 @@ -314,6 +314,7 @@ * do_extra_mangle last time. */ *other_ipp = saved_ip; +#ifdef CONFIG_IP_NF_NAT_LOCAL if (hooknum == NF_IP_LOCAL_OUT && *var_ipp != orig_dstip && !do_extra_mangle(*var_ipp, other_ipp)) { @@ -324,6 +325,7 @@ * anyway. */ continue; } +#endif /* Count how many others map onto this. */ score = count_maps(tuple->src.ip, tuple->dst.ip, @@ -367,11 +369,13 @@ else { /* Only do extra mangle when required (breaks socket binding) */ +#ifdef CONFIG_IP_NF_NAT_LOCAL if (tuple->dst.ip != mr->range[0].min_ip && hooknum == NF_IP_LOCAL_OUT && !do_extra_mangle(mr->range[0].min_ip, &tuple->src.ip)) return NULL; +#endif tuple->dst.ip = mr->range[0].min_ip; } } @@ -494,7 +498,10 @@ static unsigned int opposite_hook[NF_IP_NUMHOOKS] = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING, [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING, - [NF_IP_LOCAL_OUT] = NF_IP_POST_ROUTING +#ifdef CONFIG_IP_NF_NAT_LOCAL + [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN, + [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT, +#endif }; unsigned int diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_ftp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_ftp.c Wed Oct 31 01:08:12 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_ftp.c Sun Apr 28 22:28:19 2002 @@ -317,7 +317,7 @@ { int i; - for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + for (i = 0; i < ports_c; i++) { DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]); ip_nat_helper_unregister(&ftp[i]); } diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_helper.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_helper.c Fri Dec 21 19:42:05 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_helper.c Sun Apr 28 14:55:57 2002 @@ -243,6 +243,8 @@ tcph->seq = newseq; tcph->ack_seq = newack; + ip_conntrack_tcp_update(ct, dir, iph, skb->len, tcph); + return 0; } diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_rule.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_rule.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_rule.c Sun Apr 28 21:55:46 2002 @@ -140,8 +140,12 @@ struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; +#ifdef CONFIG_IP_NF_NAT_LOCAL IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT); +#else + IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING); +#endif ct = ip_conntrack_get(*pskb, &ctinfo); @@ -210,7 +214,7 @@ /* Only allow these for NAT. */ if (strcmp(tablename, "nat") != 0) { - DEBUGP("SNAT: wrong table %s\n", tablename); + DEBUGP("DNAT: wrong table %s\n", tablename); return 0; } @@ -218,6 +222,14 @@ DEBUGP("DNAT: hook mask 0x%x bad\n", hook_mask); return 0; } + +#ifndef CONFIG_IP_NF_NAT_LOCAL + if (hook_mask & (1 << NF_IP_LOCAL_OUT)) { + DEBUGP("DNAT: CONFIG_IP_NF_NAT_LOCAL not enabled\n"); + return 0; + } +#endif + return 1; } diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_standalone.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_standalone.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_standalone.c Sun Apr 28 22:30:04 2002 @@ -41,7 +41,8 @@ #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ - : "*ERROR*"))) + : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ + : "*ERROR*"))) static unsigned int ip_nat_fn(unsigned int hooknum, @@ -94,6 +95,12 @@ } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: +#ifdef CONFIG_IP_NF_NAT_LOCAL + /* LOCAL_IN hook doesn't have a chain and thus doesn't care + * about new packets -HW */ + if (hooknum == NF_IP_LOCAL_IN) + return NF_ACCEPT; +#endif info = &ct->nat.info; WRITE_LOCK(&ip_nat_lock); @@ -204,6 +211,11 @@ static struct nf_hook_ops ip_nat_local_out_ops = { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST }; +#ifdef CONFIG_IP_NF_NAT_LOCAL +static struct nf_hook_ops ip_nat_local_in_ops += { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_NAT_SRC }; +#endif + /* Protocol registration. */ int ip_nat_protocol_register(struct ip_nat_protocol *proto) { @@ -272,6 +284,13 @@ printk("ip_nat_init: can't register local out hook.\n"); goto cleanup_outops; } +#ifdef CONFIG_IP_NF_NAT_LOCAL + ret = nf_register_hook(&ip_nat_local_in_ops); + if (ret < 0) { + printk("ip_nat_init: can't register local in hook.\n"); + goto cleanup_localoutops; + } +#endif if (ip_conntrack_module) __MOD_INC_USE_COUNT(ip_conntrack_module); return ret; @@ -279,6 +298,10 @@ cleanup: if (ip_conntrack_module) __MOD_DEC_USE_COUNT(ip_conntrack_module); +#ifdef CONFIG_IP_NF_NAT_LOCAL + nf_unregister_hook(&ip_nat_local_in_ops); + cleanup_localoutops: +#endif nf_unregister_hook(&ip_nat_local_out_ops); cleanup_outops: nf_unregister_hook(&ip_nat_out_ops); @@ -307,6 +330,8 @@ module_exit(fini); EXPORT_SYMBOL(ip_nat_setup_info); +EXPORT_SYMBOL(ip_nat_protocol_register); +EXPORT_SYMBOL(ip_nat_protocol_unregister); EXPORT_SYMBOL(ip_nat_helper_register); EXPORT_SYMBOL(ip_nat_helper_unregister); EXPORT_SYMBOL(ip_nat_expect_register); @@ -315,4 +340,5 @@ EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); EXPORT_SYMBOL(ip_nat_seq_adjust); EXPORT_SYMBOL(ip_nat_delete_sack); +EXPORT_SYMBOL(ip_nat_used_tuple); MODULE_LICENSE("GPL"); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_talk.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_talk.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_talk.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_talk.c Sun Apr 28 22:40:28 2002 @@ -0,0 +1,463 @@ +/* + * talk extension for UDP NAT alteration. + * Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[0|1] + * + * talk=[0|1] disable|enable old talk support + * ntalk=[0|1] disable|enable ntalk support + * ntalk2=[0|1] disable|enable ntalk2 support + * + * The default is talk=1 ntalk=1 ntalk2=1 + * + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Default all talk protocols are supported */ +static int talk = 1; +static int ntalk = 1; +static int ntalk2 = 1; +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("talk network address translation module"); +#ifdef MODULE_PARM +MODULE_PARM(talk, "i"); +MODULE_PARM_DESC(talk, "support (old) talk protocol"); +MODULE_PARM(ntalk, "i"); +MODULE_PARM_DESC(ntalk, "support ntalk protocol"); +MODULE_PARM(ntalk2, "i"); +MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol"); +#endif + +#if 0 +#define DEBUGP printk +#define IP_NAT_TALK_DEBUG +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: Time out? --RR */ + +static int +talk_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info, + struct ip_conntrack *master, + struct ip_nat_info *masterinfo, + unsigned int *verdict) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + struct ip_ct_talk *talkinfo; + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + IP_NF_ASSERT(masterinfo); + + IP_NF_ASSERT(!(info->initialized & (1<help.ct_talk_info; + + LOCK_BH(&ip_talk_lock); + if (!(talkinfo->is_talk == NTALK_PORT || talkinfo->is_talk == TALK_PORT)) { + UNLOCK_BH(&ip_talk_lock); + DEBUGP("ip_nat_talk_expected: master not talk\n"); + return 0; + } + UNLOCK_BH(&ip_talk_lock); + DEBUGP("ip_nat_talk_expected: dir %s at hook %s, ct %p, master %p\n", + CTINFO2DIR((*pskb)->nfct - ct->infos) == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", + ct, master); + + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + /* Callee client -> caller server */ +#ifdef IP_NAT_TALK_DEBUG + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + + DEBUGP("ip_nat_talk_expected: UDP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(udph->source), + NIPQUAD(iph->daddr), ntohs(udph->dest)); +#endif + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + DEBUGP("ip_nat_talk_expected: callee client -> caller server, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + } else { + /* Callee client -> caller client */ +#ifdef IP_NAT_TALK_DEBUG + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *)iph + iph->ihl * 4; + + DEBUGP("ip_nat_talk_expected: TCP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), + NIPQUAD(iph->daddr), ntohs(tcph->dest)); +#endif + newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + DEBUGP("ip_nat_talk_expected: callee client -> caller client, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + } + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + newip = newsrcip; + else + newip = newdstip; + + DEBUGP("ip_nat_talk_expected: IP to %u.%u.%u.%u, port %u\n", NIPQUAD(newip), ntohs(talkinfo->port)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs... */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + *verdict = ip_nat_setup_info(ct, &mr, hooknum); + + + return 1; +} + +static int +mangle_packet(struct sk_buff **pskb, + struct ip_conntrack *ct, + u_int32_t newip, + u_int16_t port, + struct talk_addr *addr, + struct talk_addr *ctl_addr) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + size_t udplen = (*pskb)->len - iph->ihl * 4; + + /* Fortunately talk sends a structure with the address and + port in it. The size of the packet won't change. */ + + if (ctl_addr == NULL) { + /* response */ + if (addr->ta_addr == INADDR_ANY) + return 1; + DEBUGP("ip_nat_talk_mangle_packet: response orig %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(newip), ntohs(port)); + addr->ta_addr = newip; + addr->ta_port = port; + } else { + /* message */ + if (addr->ta_addr != INADDR_ANY) { + /* Change address inside packet to match way we're mapping + this connection. */ + DEBUGP("ip_nat_talk_mangle_packet: message orig addr %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(addr->ta_port)); + addr->ta_addr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + } + DEBUGP("ip_nat_talk_mangle_packet: message orig ctl_addr %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port), + NIPQUAD(newip), ntohs(port)); + ctl_addr->ta_addr = newip; + ctl_addr->ta_port = port; + } + + /* Fix checksums */ + (*pskb)->csum = csum_partial((char *)udph + sizeof(struct udphdr), udplen - sizeof(struct udphdr), 0); + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, sizeof(struct udphdr), (*pskb)->csum)); + + ip_send_check(iph); + return 1; +} + +static int talk_help_msg(struct ip_conntrack *ct, + struct sk_buff **pskb, + u_char type, + struct talk_addr *addr, + struct talk_addr *ctl_addr) +{ + u_int32_t newip; + u_int16_t port; + + unsigned int verdict = NF_ACCEPT; + + DEBUGP("ip_nat_talk_help_msg: addr: %u.%u.%u.%u:%u, ctl_addr: %u.%u.%u.%u:%u, type %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port), + type); + + /* Change address inside packet to match way we're mapping + this connection. */ + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; + DEBUGP("ip_nat_talk_help_msg: inserting: %u.%u.%u.%u:%u\n", + NIPQUAD(newip), ntohs(port)); + + if (!mangle_packet(pskb, ct, newip, port, addr, ctl_addr)) + verdict = NF_DROP; + + return verdict; +} + +static int talk_help_response(struct ip_conntrack *ct, + struct sk_buff **pskb, + u_char type, + u_char answer, + struct talk_addr *addr) +{ + u_int32_t newip; + u_int16_t port; + struct ip_conntrack_tuple t; + struct ip_ct_talk *talkinfo; + + DEBUGP("ip_nat_talk_help_response: addr: %u.%u.%u.%u:%u, type %d answer %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + type, answer); + + LOCK_BH(&ip_talk_lock); + talkinfo = &ct->help.ct_talk_info; + + if (!(answer == SUCCESS && (type == LOOK_UP || type == ANNOUNCE))) { + UNLOCK_BH(&ip_talk_lock); + return NF_ACCEPT; + } + + DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n", + ntohs(talkinfo->port), + type == LOOK_UP ? "LOOK_UP" : "ANNOUNCE"); + + /* Change address inside packet to match way we're mapping + this connection. */ + newip = ct->tuplehash[type == LOOK_UP ? IP_CT_DIR_ORIGINAL : + IP_CT_DIR_REPLY].tuple.dst.ip; + /* We can read expect here without conntrack lock, since it's + only set in ip_conntrack_talk , with ip_talk_lock held + writable */ + t = ct->expected.tuple; + t.dst.ip = newip; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(talkinfo->port); port != 0; port++) { + if (type == LOOK_UP) + t.dst.u.tcp.port = htons(port); + else + t.dst.u.udp.port = htons(port); + + if (ip_conntrack_expect_related(ct, &t, + &ct->expected.mask, + NULL) == 0) { + DEBUGP("ip_nat_talk_help_response: using %u.%u.%u.%u:%u\n", NIPQUAD(newip), port); + break; + } + } + UNLOCK_BH(&ip_talk_lock); + + if (port == 0 || !mangle_packet(pskb, ct, newip, htons(port), addr, NULL)) + return NF_DROP; + + return NF_ACCEPT; +} + +static unsigned int talk_help(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb, + int talk_port) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + unsigned int udplen = (*pskb)->len - iph->ihl * 4; + char *data = (char *)udph + sizeof(struct udphdr); + int dir; + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + dir = CTINFO2DIR(ctinfo); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("ip_nat_talk_help: Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + DEBUGP("ip_nat_talk_help: dir %s at hook %s, %u.%u.%u.%u:%u->%u.%u.%u.%u:%u, talk port %d\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", + NIPQUAD(iph->saddr), ntohs(udph->source), + NIPQUAD(iph->daddr), ntohs(udph->dest), + talk_port); + + /* Because conntrack does not drop packets, checking must be repeated here... */ + if (talk_port == TALK_PORT) { + if (dir == IP_CT_DIR_ORIGINAL + && udplen == sizeof(struct udphdr) + sizeof(struct talk_msg)) + return talk_help_msg(ct, pskb, + ((struct talk_msg *)data)->type, + &(((struct talk_msg *)data)->addr), + &(((struct talk_msg *)data)->ctl_addr)); + else if (dir == IP_CT_DIR_REPLY + && udplen == sizeof(struct udphdr) + sizeof(struct talk_response)) + return talk_help_response(ct, pskb, + ((struct talk_response *)data)->type, + ((struct talk_response *)data)->answer, + &(((struct talk_response *)data)->addr)); + else { + DEBUGP("ip_nat_talk_help: not talk %s, datalen %u != %u\n", + dir == IP_CT_DIR_ORIGINAL ? "message" : "response", + (unsigned)udplen - sizeof(struct udphdr), + dir == IP_CT_DIR_ORIGINAL ? sizeof(struct talk_msg) : sizeof(struct talk_response)); + return NF_DROP; + } + } else { + if (dir == IP_CT_DIR_ORIGINAL) { + if (ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_msg) + && ((struct ntalk_msg *)data)->vers == NTALK_VERSION) + return talk_help_msg(ct, pskb, + ((struct ntalk_msg *)data)->type, + &(((struct ntalk_msg *)data)->addr), + &(((struct ntalk_msg *)data)->ctl_addr)); + else if (ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_msg) + && ((struct ntalk2_msg *)data)->vers == NTALK2_VERSION + && udplen == sizeof(struct udphdr) + + sizeof(struct ntalk2_msg) + + ((struct ntalk2_msg *)data)->extended) + return talk_help_msg(ct, pskb, + ((struct ntalk2_msg *)data)->type, + &(((struct ntalk2_msg *)data)->addr), + &(((struct ntalk2_msg *)data)->ctl_addr)); + else { + DEBUGP("ip_nat_talk_help: not ntalk/ntalk2 message, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_msg), sizeof(struct ntalk2_msg)); + return NF_DROP; + } + } else { + if (ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response) + && ((struct ntalk_response *)data)->vers == NTALK_VERSION) + return talk_help_response(ct, pskb, + ((struct ntalk_response *)data)->type, + ((struct ntalk_response *)data)->answer, + &(((struct ntalk_response *)data)->addr)); + else if (ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response) + && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION) + return talk_help_response(ct, pskb, + ((struct ntalk2_response *)data)->type, + ((struct ntalk2_response *)data)->answer, + &(((struct ntalk2_response *)data)->addr)); + else { + DEBUGP("ip_nat_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_response), sizeof(struct ntalk2_response)); + return NF_DROP; + } + } + } +} + +static unsigned int help(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + return talk_help(ct, info, ctinfo, hooknum, pskb, TALK_PORT); +} + +static unsigned int nhelp(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + return talk_help(ct, info, ctinfo, hooknum, pskb, NTALK_PORT); +} + +static struct ip_nat_helper talk_helpers[2] = { { { NULL, NULL }, + { { 0, { __constant_htons(TALK_PORT) } }, + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, + { 0, { 0 }, 0xFFFF } }, + help, "talk" }, + { { NULL, NULL }, + { { 0, { __constant_htons(NTALK_PORT) } }, + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, + { 0, { 0 }, 0xFFFF } }, + nhelp, "ntalk" } }; +static struct ip_nat_expect talk_expect += { { NULL, NULL }, talk_nat_expected }; + +static int __init init(void) +{ + int ret = 0; + + ret = ip_conntrack_talk_forceload(); + + if (talk > 0 || ntalk > 0 || ntalk2 > 0) + ret = ip_nat_expect_register(&talk_expect); + if (ret != 0) + return ret; + + if (talk > 0) { + ret = ip_nat_helper_register(&talk_helpers[0]); + + if (ret != 0) { + ip_nat_expect_unregister(&talk_expect); + return ret; + } + } + if (ntalk > 0 || ntalk2 > 0) { + ret = ip_nat_helper_register(&talk_helpers[1]); + + if (ret != 0) { + if (talk > 0) + ip_nat_helper_unregister(&talk_helpers[0]); + ip_nat_expect_unregister(&talk_expect); + } + } + return ret; +} + +static void __exit fini(void) +{ + if (talk > 0) + ip_nat_helper_unregister(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_nat_helper_unregister(&talk_helpers[1]); + if (talk > 0 || ntalk > 0 || ntalk2 > 0) + ip_nat_expect_unregister(&talk_expect); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_tftp.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_tftp.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_nat_tftp.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_nat_tftp.c Sun Apr 28 22:41:27 2002 @@ -0,0 +1,212 @@ +/* + * Licensed under GNU GPL version 2 Copyright Magnus Boden + * Version: 0.0.7 + * This module currently supports DNAT: + * iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y + * + * and SNAT: + * iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x } + * + * It has not been tested with + * -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip + * If you do test this please let me know if it works or not. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Magnus Boden "); +MODULE_DESCRIPTION("Netfilter NAT helper for tftp"); +MODULE_LICENSE("GPL"); + +#define MAX_PORTS 8 +#define OPCODE_READ 1 +#define OPCODE_WRITE 2 +#define TFTP_PORT 69 + +static int ports[MAX_PORTS]; +#ifdef MODULE_PARM +MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of tftp servers"); +#endif + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct tftphdr { + u_int16_t opcode; +}; + +static unsigned int tftp_nat_help(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + struct tftphdr *tftph = (void *)udph + 8; + struct ip_conntrack_tuple t, m; + + switch(ntohs(tftph->opcode)) { + /* RRQ and WRQ works the same way */ + case OPCODE_READ: + case OPCODE_WRITE: + DEBUGP("<1> ip_nat_tftp: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u - %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port)); + memset(&t, 0, sizeof(struct ip_conntrack_tuple)); + memset(&m, 0, sizeof(struct ip_conntrack_tuple)); + t.dst.protonum = IPPROTO_UDP; + t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + t.dst.u.udp.port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; + m.dst.protonum = 0xFFFF; + m.src.ip = 0xFFFF; + m.dst.ip = 0xFFFF; + m.dst.u.udp.port = 0xFFFF; + ip_conntrack_expect_related(ct, &t, &m, NULL); + break; + default: + DEBUGP("<1> ip_nat_tftp: Unknown opcode\n"); + } + + return(NF_ACCEPT); +} + +static int tftp_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info, + struct ip_conntrack *master, + struct ip_nat_info *masterinfo, + unsigned int *verdict) +{ + struct ip_nat_multi_range mr; + int i; + u_int8_t is_tftp=0; + struct iphdr *iph = (*pskb)->nh.iph; +#if 0 + struct udphdr *udph = (void *)iph + iph->ihl*4; +#endif + + /* Remove this when netfilter stops giving me + tcp packets */ + if(iph->protocol != IPPROTO_UDP) + return(0); + + /* Check if master is tftp, The check is only + if the helper is registered for that port */ + for(i = 0; ituplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port == htons(ports[i])) + is_tftp=1; + } + if(!is_tftp) + return(0); + + mr.rangesize = 1; + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + + if(HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC){ + mr.range[0].min_ip = mr.range[0].max_ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + + DEBUGP("<1> ip_nat_tftp: orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u newsrc: %u.%u.%u.%u\n", + NIPQUAD((*pskb)->nh.iph->saddr), + ntohs(udph->source), + NIPQUAD((*pskb)->nh.iph->daddr), + ntohs(udph->dest), + NIPQUAD(master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); + }else{ + mr.range[0].min_ip = mr.range[0].max_ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + mr.range[0].min.udp.port = mr.range[0].max.udp.port = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + + DEBUGP("<1> ip_nat_tftp: orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u newdst: %u.%u.%u.%u:%u\n", + NIPQUAD((*pskb)->nh.iph->saddr), + ntohs(udph->source), + NIPQUAD((*pskb)->nh.iph->daddr), + ntohs(udph->dest), + NIPQUAD(master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), + ntohs(master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port)); + } + + *verdict = ip_nat_setup_info(ct,&mr,hooknum); + + return(NF_ACCEPT); +} + +static struct ip_nat_expect tftp_expect = { + { NULL, NULL }, + tftp_nat_expected +}; +static struct ip_nat_helper tftp[MAX_PORTS]; + +static void fini(void) +{ + int i; + + for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++){ + DEBUGP("<1> Unregistering ip_nat_tftp.o for port %d\n", + ports[i]); + ip_nat_helper_unregister(&tftp[i]); + } + + ip_nat_expect_unregister(&tftp_expect); +} + +static int __init init(void) +{ + int i, ret; + + ret = ip_nat_expect_register(&tftp_expect); + if(!ret) { + if(!ports[0]) + ports[0] = TFTP_PORT; + + for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { + memset(&tftp[i], 0, sizeof(struct ip_nat_helper)); + tftp[i].tuple.dst.protonum = IPPROTO_UDP; + tftp[i].tuple.src.u.udp.port = htons(ports[i]); + tftp[i].mask.dst.protonum = 0xFFFF; + tftp[i].mask.src.u.udp.port = 0xFFFF; + tftp[i].help = tftp_nat_help; + DEBUGP("<1> Registering ip_nat_tftp.o for port %d\n", + ports[i]); + + /* tmpname thingy */ + + ret = ip_nat_helper_register(&tftp[i]); + if(ret) { + DEBUGP("ip_nat_tftp.o: Unable to register for port %d\n", + ports[i]); + fini(); + return(ret); + } + } + } else { + ip_nat_expect_unregister(&tftp_expect); + } + + return(ret); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ip_pool.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_pool.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ip_pool.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ip_pool.c Sun Apr 28 22:24:38 2002 @@ -0,0 +1,332 @@ +/* Kernel module for IP pool management */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DP printk +#else +#define DP(format, args...) +#endif + +MODULE_LICENSE("GPL"); + +#define NR_POOL 16 +static int nr_pool = NR_POOL;/* overwrite this when loading module */ + +struct ip_pool { + u_int32_t first_ip; /* host byte order, included in range */ + u_int32_t last_ip; /* host byte order, included in range */ + void *members; /* the bitmap proper */ + int nr_use; /* total nr. of tests through this */ + int nr_match; /* total nr. of matches through this */ + rwlock_t lock; +}; + +static struct ip_pool *POOL; + +static inline struct ip_pool *lookup(ip_pool_t index) +{ + if (index < 0 || index >= nr_pool) { + DP("ip_pool:lookup: bad index %d\n", index); + return 0; + } + return POOL+index; +} + +int ip_pool_match(ip_pool_t index, u_int32_t addr) +{ + struct ip_pool *pool = lookup(index); + int res = 0; + + if (!pool || !pool->members) + return 0; + read_lock_bh(&pool->lock); + if (pool->members) { + if (addr >= pool->first_ip && addr <= pool->last_ip) { + addr -= pool->first_ip; + if (test_bit(addr, pool->members)) { + res = 1; +#ifdef CONFIG_IP_POOL_STATISTICS + pool->nr_match++; +#endif + } + } +#ifdef CONFIG_IP_POOL_STATISTICS + pool->nr_use++; +#endif + } + read_unlock_bh(&pool->lock); + return res; +} + +static int pool_change(ip_pool_t index, u_int32_t addr, int isdel) +{ + struct ip_pool *pool; + int res = -1; + + pool = lookup(index); + if ( !pool || !pool->members + || addr < pool->first_ip || addr > pool->last_ip) + return -1; + read_lock_bh(&pool->lock); + if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) { + addr -= pool->first_ip; + res = isdel + ? (0 != test_and_clear_bit(addr, pool->members)) + : (0 != test_and_set_bit(addr, pool->members)); + } + read_unlock_bh(&pool->lock); + return res; +} + +int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel) +{ + int res = pool_change(index,addr,isdel); + + if (!isdel) res = !res; + return res; +} + +static inline int bitmap_bytes(u_int32_t a, u_int32_t b) +{ + return 4*((((b-a+8)/8)+3)/4); +} + +static inline int poolbytes(ip_pool_t index) +{ + struct ip_pool *pool = lookup(index); + + return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0; +} + +static int setpool( + struct sock *sk, + int optval, + void *user, + unsigned int len +) { + struct ip_pool_request req; + + DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (optval != SO_IP_POOL) + return -EBADF; + if (len != sizeof(req)) + return -EINVAL; + if (copy_from_user(&req, user, sizeof(req)) != 0) + return -EFAULT; + printk("obsolete op - upgrade your ippool(8) utility.\n"); + return -EINVAL; +} + +static int getpool( + struct sock *sk, + int optval, + void *user, + int *len +) { + struct ip_pool_request req; + struct ip_pool *pool; + ip_pool_t i; + int newbytes; + void *newmembers; + int res; + + DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user); + if (!capable(CAP_NET_ADMIN)) + return -EINVAL; + if (optval != SO_IP_POOL) + return -EINVAL; + if (*len != sizeof(req)) { + return -EFAULT; + } + if (copy_from_user(&req, user, sizeof(req)) != 0) + return -EFAULT; + DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index); + if (req.op < IP_POOL_BAD001) { + printk("obsolete op - upgrade your ippool(8) utility.\n"); + return -EFAULT; + } + switch(req.op) { + case IP_POOL_HIGH_NR: + DP("ip_pool HIGH_NR\n"); + req.index = IP_POOL_NONE; + for (i=0; imembers) + return -EBADF; + req.addr = htonl(pool->first_ip); + req.addr2 = htonl(pool->last_ip); + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_USAGE: + DP("ip_pool USE\n"); + pool = lookup(req.index); + if (!pool) + return -EINVAL; + if (!pool->members) + return -EBADF; + req.addr = pool->nr_use; + req.addr2 = pool->nr_match; + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_TEST_ADDR: + DP("ip_pool TEST 0x%08x\n", req.addr); + pool = lookup(req.index); + if (!pool) + return -EINVAL; + res = 0; + read_lock_bh(&pool->lock); + if (!pool->members) { + DP("ip_pool TEST_ADDR no members in pool\n"); + res = -EBADF; + goto unlock_and_return_res; + } + req.addr = ntohl(req.addr); + if (req.addr < pool->first_ip) { + DP("ip_pool TEST_ADDR address < pool bounds\n"); + res = -ERANGE; + goto unlock_and_return_res; + } + if (req.addr > pool->last_ip) { + DP("ip_pool TEST_ADDR address > pool bounds\n"); + res = -ERANGE; + goto unlock_and_return_res; + } + req.addr = (0 != test_bit((req.addr - pool->first_ip), + pool->members)); + read_unlock_bh(&pool->lock); + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_FLUSH: + DP("ip_pool FLUSH not yet implemented.\n"); + return -EBUSY; + case IP_POOL_DESTROY: + DP("ip_pool DESTROY not yet implemented.\n"); + return -EBUSY; + case IP_POOL_INIT: + DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2); + pool = lookup(req.index); + if (!pool) + return -EINVAL; + req.addr = ntohl(req.addr); + req.addr2 = ntohl(req.addr2); + if (req.addr > req.addr2) { + DP("ip_pool INIT bad ip range\n"); + return -EINVAL; + } + newbytes = bitmap_bytes(req.addr, req.addr2); + newmembers = kmalloc(newbytes, GFP_KERNEL); + if (!newmembers) { + DP("ip_pool INIT out of mem for %d bytes\n", newbytes); + return -ENOMEM; + } + memset(newmembers, 0, newbytes); + write_lock_bh(&pool->lock); + if (pool->members) { + DP("ip_pool INIT pool %d exists\n", req.index); + kfree(newmembers); + res = -EBUSY; + goto unlock_and_return_res; + } + pool->first_ip = req.addr; + pool->last_ip = req.addr2; + pool->nr_use = 0; + pool->nr_match = 0; + pool->members = newmembers; + write_unlock_bh(&pool->lock); + return 0; + case IP_POOL_ADD_ADDR: + DP("ip_pool ADD_ADDR 0x%08x\n", req.addr); + req.addr = pool_change(req.index, ntohl(req.addr), 0); + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_DEL_ADDR: + DP("ip_pool DEL_ADDR 0x%08x\n", req.addr); + req.addr = pool_change(req.index, ntohl(req.addr), 1); + return copy_to_user(user, &req, sizeof(req)); + default: + DP("ip_pool:getpool bad op %d\n", req.op); + return -EINVAL; + } + return -EINVAL; + +unlock_and_return_res: + if (pool) + read_unlock_bh(&pool->lock); + return res; +} + +static struct nf_sockopt_ops so_pool += { { NULL, NULL }, PF_INET, + SO_IP_POOL, SO_IP_POOL+1, &setpool, + SO_IP_POOL, SO_IP_POOL+1, &getpool, + 0, NULL }; + +MODULE_PARM(nr_pool, "i"); + +static int __init init(void) +{ + ip_pool_t i; + int res; + + if (nr_pool < 1) { + printk("ip_pool module init: bad nr_pool %d\n", nr_pool); + return -EINVAL; + } + POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL); + if (!POOL) { + printk("ip_pool module init: out of memory for nr_pool %d\n", + nr_pool); + return -ENOMEM; + } + for (i=0; ipeer.pid, MSG_DONTWAIT); } -#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0); +#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static __inline__ void netlink_receive_user_skb(struct sk_buff *skb) { diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_CONNMARK.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_CONNMARK.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_CONNMARK.c Sun Apr 28 22:09:41 2002 @@ -0,0 +1,87 @@ +/* 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 += { { NULL, NULL }, "CONNMARK", target, checkentry, NULL, 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 -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_DSCP.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_DSCP.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_DSCP.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_DSCP.c Sun Apr 28 22:31:21 2002 @@ -0,0 +1,108 @@ +/* iptables module for setting the IPv4 DSCP field, Version 1.5 + * + * (C) 2002 by Harald Welte + * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh + * This software is distributed under GNU GPL v2, 1991 + * + * See RFC2474 for a description of the DSCP field within the IP Header. + * + * ipt_DSCP.c,v 1.5 2002/02/17 21:11:08 laforge Exp +*/ + +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IP tables DSCP modification module"); +MODULE_LICENSE("GPL"); + +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) +{ + struct iphdr *iph = (*pskb)->nh.iph; + const struct ipt_DSCP_info *dinfo = targinfo; + u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK); + + + if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) { + u_int16_t diffs[2]; + + /* raw socket (tcpdump) may have clone of incoming + * skb: don't disturb it --RR */ + if (skb_cloned(*pskb) && !(*pskb)->sk) { + struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + kfree_skb(*pskb); + *pskb = nskb; + iph = (*pskb)->nh.iph; + } + + diffs[0] = htons(iph->tos) ^ 0xFFFF; + iph->tos = iph->tos | sh_dscp; + diffs[1] = htons(iph->tos); + iph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + 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 dscp = ((struct ipt_DSCP_info *)targinfo)->dscp; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) { + printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_DSCP_info))); + return 0; + } + + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if ((dscp > IPT_DSCP_MAX)) { + printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_dscp_reg += { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_dscp_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_dscp_reg); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c Sun Apr 28 22:31:55 2002 @@ -0,0 +1,84 @@ +/** + * Strip all IP options in the IP packet header. + * + * (C) 2001 by Fabrice MARIE + * This software is distributed under GNU GPL v2, 1991 + */ + +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Fabrice MARIE "); +MODULE_DESCRIPTION("Stip all options in IPv4 packets"); +MODULE_LICENSE("GPL"); + +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) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct sk_buff *skb = (*pskb); + struct ip_options * opt; + unsigned char * optiph = skb->nh.raw; + int l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen; + + + /* if no options in packet then nothing to clear. */ + if (iph->ihl * 4 == sizeof(struct iphdr)) + return IPT_CONTINUE; + + /* else clear all options */ + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l); + opt = &(IPCB(skb)->opt); + opt->is_data = 0; + opt->optlen = l; + + skb->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) +{ + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + /* nothing else to check because no parameters */ + return 1; +} + +static struct ipt_target ipt_ipv4optsstrip_reg += { { NULL, NULL }, "IPV4OPTSSTRIP", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_ipv4optsstrip_reg)) + return -EINVAL; + printk("ipt_IPV4OPTSSTRIP loaded\n"); + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_ipv4optsstrip_reg); + printk("ipt_IPV4OPTSSTRIP unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_NETLINK.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_NETLINK.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_NETLINK.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_NETLINK.c Sun Apr 28 22:32:39 2002 @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Gianni Tedesco "); +MODULE_DESCRIPTION("Provides iptables NETLINK target similar to ipchains -o"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static struct sock *ipfwsk; + +static unsigned int ipt_netlink_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct ipt_nldata *nld = (struct ipt_nldata *)targinfo; + struct iphdr *ip = (*pskb)->nh.iph; + struct sk_buff *outskb; + struct netlink_t nlhdr; + size_t len=0; + + /* Allocate a socket buffer */ + if ( MASK(nld->flags, USE_SIZE) ) + len = nld->size+sizeof(nlhdr); + else + len = ntohs(ip->tot_len)+sizeof(nlhdr); + + outskb=alloc_skb(len, GFP_ATOMIC); + + if (outskb) { + nlhdr.len=len; + + if ( MASK(nld->flags, USE_MARK) ) + nlhdr.mark=(*pskb)->nfmark=nld->mark; + else + nlhdr.mark=(*pskb)->nfmark; + + if ( in && in->name ) { + strncpy((char *)&nlhdr.iface, in->name, IFNAMSIZ); + }else if ( out && out->name ){ + strncpy((char *)&nlhdr.iface, out->name, IFNAMSIZ); + } + + skb_put(outskb, len); + memcpy(outskb->data, &nlhdr, sizeof(nlhdr)); + memcpy((outskb->data)+sizeof(nlhdr), ip, len-sizeof(nlhdr)); + netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL); + }else{ + if (net_ratelimit()) + printk(KERN_WARNING "ipt_NETLINK: packet drop due to netlink failure\n"); + } + + if ( MASK(nld->flags, USE_DROP) ) + return NF_DROP; + + return IPT_CONTINUE; +} + +static int ipt_netlink_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hookmask) +{ + //struct ipt_nldata *nld = (struct ipt_nldata *)targinfo; + + return 1; +} + +static struct ipt_target ipt_netlink_reg = { + {NULL, NULL}, + "NETLINK", + ipt_netlink_target, + ipt_netlink_checkentry, + NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + DEBUGP("ipt_NETLINK: init module\n"); + + if (ipt_register_target(&ipt_netlink_reg) != 0) { + return -EINVAL; + } + + if ( !(ipfwsk=netlink_kernel_create(NETLINK_FIREWALL, NULL)) ){ + return -EINVAL; + } + + return 0; +} + +static void __exit fini(void) +{ + DEBUGP("ipt_NETLINK: cleanup_module\n"); + ipt_unregister_target(&ipt_netlink_reg); + if(ipfwsk->socket) sock_release(ipfwsk->socket); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_NETMAP.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_NETMAP.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_NETMAP.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_NETMAP.c Sun Apr 28 22:33:41 2002 @@ -0,0 +1,107 @@ +/* NETMAP - static NAT mapping of IP network addresses (1:1). + The mapping can be applied to source (POSTROUTING), + destination (PREROUTING), or both (with separate rules). + + Author: Svenning Soerensen +*/ + +#include +#include +#include +#include +#include +#include +#include + +#define MODULENAME "NETMAP" +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static int +check(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ip_nat_multi_range *mr = targinfo; + + if (strcmp(tablename, "nat") != 0) { + DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename); + return 0; + } + if (targinfosize != IPT_ALIGN(sizeof(*mr))) { + DEBUGP(MODULENAME":check: size %u.\n", targinfosize); + return 0; + } + if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING))) { + DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask); + return 0; + } + if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { + DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); + return 0; + } + if (mr->rangesize != 1) { + DEBUGP(MODULENAME":check: bad rangesize %u.\n", mr->rangesize); + return 0; + } + return 1; +} + +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) +{ + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + u_int32_t new_ip, netmask; + const struct ip_nat_multi_range *mr = targinfo; + struct ip_nat_multi_range newrange; + + IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING + || hooknum == NF_IP_POST_ROUTING); + ct = ip_conntrack_get(*pskb, &ctinfo); + + netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); + + if (hooknum == NF_IP_PRE_ROUTING) + new_ip = (*pskb)->nh.iph->daddr & ~netmask; + else + new_ip = (*pskb)->nh.iph->saddr & ~netmask; + new_ip |= mr->range[0].min_ip & netmask; + + newrange = ((struct ip_nat_multi_range) + { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, + new_ip, new_ip, + mr->range[0].min, mr->range[0].max } } }); + + /* Hand modified range to generic setup. */ + return ip_nat_setup_info(ct, &newrange, hooknum); +} + +static struct ipt_target target_module += { { NULL, NULL }, MODULENAME, target, check, NULL, + THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&target_module); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&target_module); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_POOL.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_POOL.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_POOL.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_POOL.c Sun Apr 28 22:24:38 2002 @@ -0,0 +1,116 @@ +/* ipt_POOL.c - netfilter target to manipulate IP pools + * + * This target can be used almost everywhere. It acts on some specified + * IP pool, adding or deleting some IP address in the pool. The address + * can be either the source (--addsrc, --delsrc), or destination (--add/deldst) + * of the packet under inspection. + * + * The target normally returns IPT_CONTINUE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/*** NOTE NOTE NOTE NOTE *** +** +** By sheer luck, I get away with using the "struct ipt_pool_info", as defined +** in , both as the match and target info. +** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE, +** is modified for the source IP address of the packet under inspection. +** The same way, the ipt_pool_info.dst pool is modified for the destination. +** +** The address is added to the pool normally. However, if IPT_POOL_DEL_dir +** flag is set in ipt_pool_info.flags, the address is deleted from the pool. +** +** If a modification was done to the pool, we possibly return ACCEPT or DROP, +** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set. +** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the +** ACCEPT and DROP flags are evaluated when the pool was not modified.) +*/ + +static int +do_check(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ipt_pool_info *ipi = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(*ipi))) { + DEBUGP("POOL_check: size %u.\n", targinfosize); + return 0; + } + DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags); + return 1; +} + +static unsigned int +do_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_pool_info *ipi = targinfo; + int modified; + unsigned int verdict = IPT_CONTINUE; + + if (ipi->src != IP_POOL_NONE) { + modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr), + ipi->flags & IPT_POOL_DEL_SRC); + if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) { + if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT) + verdict = NF_ACCEPT; + else if (ipi->flags & IPT_POOL_MOD_SRC_DROP) + verdict = NF_DROP; + } + } + if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) { + modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr), + ipi->flags & IPT_POOL_DEL_DST); + if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) { + if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT) + verdict = NF_ACCEPT; + else if (ipi->flags & IPT_POOL_MOD_DST_DROP) + verdict = NF_DROP; + } + } + return verdict; +} + +static struct ipt_target pool_reg += { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + DEBUGP("init ipt_POOL\n"); + return ipt_register_target(&pool_reg); +} + +static void __exit fini(void) +{ + DEBUGP("fini ipt_POOL\n"); + ipt_unregister_target(&pool_reg); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_REJECT.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_REJECT.c Sat Oct 6 17:50:28 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_REJECT.c Sun Apr 28 22:26:29 2002 @@ -234,11 +234,8 @@ iph->tos=tos; iph->tot_len = htons(length); - /* This abbreviates icmp->send->ip_build_xmit->ip_dont_fragment */ - if (!ipv4_config.no_pmtu_disc - && !(rt->u.dst.mxlock&(1<frag_off = htons(IP_DF); - else iph->frag_off = 0; + /* PMTU discovery never applies to ICMP packets. */ + iph->frag_off = 0; iph->ttl = MAXTTL; ip_select_ident(iph, &rt->u.dst, NULL); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_SAME.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_SAME.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_SAME.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_SAME.c Sun Apr 28 22:34:01 2002 @@ -0,0 +1,199 @@ +/* Same. Just like SNAT, only try to make the connections + * between client A and server B always have the same source ip. + * + * (C) 2000 Rusty Russell. GPL. + * + * 010320 Martin Josefsson + * * copied ipt_BALANCE.c to ipt_SAME.c and changed a few things. + * 010728 Martin Josefsson + * * added --nodst to not include destination-ip in new source + * calculations. + * * added some more sanity-checks. + * 010729 Martin Josefsson + * * fixed a buggy if-statement in same_check(), should have + * used ntohl() but didn't. + * * added support for multiple ranges. IPT_SAME_MAX_RANGE is + * defined in linux/include/linux/netfilter_ipv4/ipt_SAME.h + * and is currently set to 10. + * * added support for 1-address range, nice to have now that + * we have multiple ranges. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static int +same_check(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + unsigned int count, countess, rangeip, index = 0; + struct ipt_same_info *mr = targinfo; + + mr->ipnum = 0; + + if (strcmp(tablename, "nat") != 0) { + DEBUGP("same_check: bad table `%s'.\n", tablename); + return 0; + } + if (targinfosize != IPT_ALIGN(sizeof(*mr))) { + DEBUGP("same_check: size %u.\n", targinfosize); + return 0; + } + if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { + DEBUGP("same_check: bad hooks %x.\n", hook_mask); + return 0; + } + if (mr->rangesize < 1) { + DEBUGP("same_check: need at least one dest range.\n"); + return 0; + } + if (mr->rangesize > IPT_SAME_MAX_RANGE) { + DEBUGP("same_check: too many ranges specified, maximum " + "is %u ranges\n", + IPT_SAME_MAX_RANGE); + return 0; + } + for (count = 0; count < mr->rangesize; count++) { + if (ntohl(mr->range[count].min_ip) > + ntohl(mr->range[count].max_ip)) { + DEBUGP("same_check: min_ip is larger than max_ip in " + "range `%u.%u.%u.%u-%u.%u.%u.%u'.\n", + NIPQUAD(mr->range[count].min_ip), + NIPQUAD(mr->range[count].max_ip)); + return 0; + } + if (!(mr->range[count].flags & IP_NAT_RANGE_MAP_IPS)) { + DEBUGP("same_check: bad MAP_IPS.\n"); + return 0; + } + rangeip = (ntohl(mr->range[count].max_ip) - + ntohl(mr->range[count].min_ip) + 1); + mr->ipnum += rangeip; + + DEBUGP("same_check: range %u, ipnum = %u\n", count, rangeip); + } + DEBUGP("same_check: total ipaddresses = %u\n", mr->ipnum); + + mr->iparray = kmalloc((sizeof(u_int32_t) * mr->ipnum), GFP_KERNEL); + if (!mr->iparray) { + DEBUGP("same_check: Couldn't allocate %u bytes " + "for %u ipaddresses!\n", + (sizeof(u_int32_t) * mr->ipnum), mr->ipnum); + return 0; + } + DEBUGP("same_check: Allocated %u bytes for %u ipaddresses.\n", + (sizeof(u_int32_t) * mr->ipnum), mr->ipnum); + + for (count = 0; count < mr->rangesize; count++) { + for (countess = ntohl(mr->range[count].min_ip); + countess <= ntohl(mr->range[count].max_ip); + countess++) { + mr->iparray[index] = countess; + DEBUGP("same_check: Added ipaddress `%u.%u.%u.%u' " + "in index %u.\n", + HIPQUAD(countess), index); + index++; + } + } + return 1; +} + +static void +same_destroy(void *targinfo, + unsigned int targinfosize) +{ + struct ipt_same_info *mr = targinfo; + + kfree(mr->iparray); + + DEBUGP("same_destroy: Deallocated %u bytes for %u ipaddresses.\n", + (sizeof(u_int32_t) * mr->ipnum), mr->ipnum); +} + +static unsigned int +same_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + u_int32_t tmpip, aindex, new_ip; + const struct ipt_same_info *mr = targinfo; + struct ip_nat_multi_range newrange; + const struct ip_conntrack_tuple *t; + + IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); + ct = ip_conntrack_get(*pskb, &ctinfo); + + t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + + /* Base new source on real src ip and optionally dst ip, + giving some hope for consistency across reboots. + Here we calculate the index in mr->iparray which + holds the ipaddress we should use */ + + tmpip = ntohl(t->src.ip); + + if (!(mr->info & IPT_SAME_NODST)) + tmpip += ntohl(t->dst.ip); + + aindex = tmpip % mr->ipnum; + + new_ip = htonl(mr->iparray[aindex]); + + DEBUGP("ipt_SAME: src=%u.%u.%u.%u dst=%u.%u.%u.%u, " + "new src=%u.%u.%u.%u\n", + NIPQUAD(t->src.ip), NIPQUAD(t->dst.ip), + NIPQUAD(new_ip)); + + /* Transfer from original range. */ + newrange = ((struct ip_nat_multi_range) + { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, + new_ip, new_ip, + mr->range[0].min, mr->range[0].max } } }); + + /* Hand modified range to generic setup. */ + return ip_nat_setup_info(ct, &newrange, hooknum); +} + +static struct ipt_target same_reg += { { NULL, NULL }, "SAME", same_target, same_check, same_destroy, + THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&same_reg); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&same_reg); +} + +module_init(init); +module_exit(fini); + diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_TTL.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_TTL.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_TTL.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_TTL.c Sun Apr 28 22:34:32 2002 @@ -0,0 +1,110 @@ +/* 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 = { { NULL, NULL }, "TTL", + ipt_ttl_target, ipt_ttl_checkentry, NULL, 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 -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_ULOG.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_ULOG.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_ULOG.c Sun Apr 28 22:29:47 2002 @@ -61,7 +61,7 @@ #define DEBUGP(format, args...) #endif -#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0); +#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0) MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("IP tables userspace logging module"); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_bytelimit.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_bytelimit.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_bytelimit.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_bytelimit.c Sun Apr 28 21:47:58 2002 @@ -0,0 +1,106 @@ +/* Kernel module to control the rate + * + * Jérôme de Vivie + * Hervé Eychenne + * + * 2 September 1999: Changed from the target RATE to the match + * `limit', removed logging. Did I mention that + * Alexey is a fucking genius? + * Rusty Russell (rusty@rustcorp.com.au). + * 19 November 2001: shamelessly cloned from ipt_limit.c + * Jerome Petazzoni + */ + +#include +#include +#include +#include + +#include +#include + +static spinlock_t limit_lock = SPIN_LOCK_UNLOCKED; + +/* + Skaya: I modified all the limit stuff. Now, you get "tickrate" credits per + jiffy, and passing X bytes costs you X credits. "credit_cap" is + now "burst", which is the maximal credit you can ever have. + + "prev" tracks the last packet hit: you gain "rate" credits per jiffy. + If you get credit balance more than this, the extra credit is + discarded. +*/ + +static int +ipt_bytelimit_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) +{ + struct ipt_bytelimitinfo *r = + ((struct ipt_bytelimitinfo *)matchinfo)->master; + unsigned long now = jiffies; + + spin_lock_bh(&limit_lock); + r->credit += (now - xchg(&r->prev, now)) * r->tickrate ; + if (r->credit > r->quota) + r->credit = r->quota ; + + if (r->credit >= datalen) { + /* We're not limited. */ + r->credit -= datalen; + spin_unlock_bh(&limit_lock); + return 0; + } + + spin_unlock_bh(&limit_lock); + return 1; +} + +static int +ipt_bytelimit_checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_bytelimitinfo *r = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_bytelimitinfo))) + return 0; + + if (r->credit==-1) r->credit = r->quota ; + r->prev = jiffies; + r->tickrate = r->rate/HZ ; + r->rate = r->tickrate*HZ ; /* so we display the "real", rounded, rate */ + + /* For SMP, we only want to use one set of counters. */ + r->master = r; + + return 1; +} + +static struct ipt_match ipt_bytelimit_reg += { { NULL, NULL }, "bytelimit", + ipt_bytelimit_match, ipt_bytelimit_checkentry, NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_bytelimit_reg)) + return -EINVAL; + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_bytelimit_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_connmark.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_connmark.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_connmark.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_connmark.c Sun Apr 28 22:09:41 2002 @@ -0,0 +1,55 @@ +/* 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 += { { NULL, NULL }, "connmark", &match, &checkentry, NULL, 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 -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_conntrack.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_conntrack.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_conntrack.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_conntrack.c Sun Apr 28 22:12:24 2002 @@ -0,0 +1,123 @@ +/* Kernel module to match connection tracking information. + * Superset of Rusty's minimalistic state match. + * GPL (C) 2001 Marc Boucher (marc@mbsi.ca). + */ +#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_conntrack_info *sinfo = matchinfo; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + unsigned int statebit; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + +#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) + + statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo); + if(sinfo->flags & IPT_CONNTRACK_STATE) { + if (ct) { + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) + statebit |= IPT_CONNTRACK_STATE_SNAT; + + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) + statebit |= IPT_CONNTRACK_STATE_DNAT; + } + + if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_PROTO) { + if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) { + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_ORIGDST) { + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_REPLSRC) { + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_REPLDST) { + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_STATUS) { + if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS)) + return 0; + } + + if(sinfo->flags & IPT_CONNTRACK_EXPIRES) { + unsigned long expires; + + if(!ct) + return 0; + + expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; + + if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES)) + return 0; + } + + return 1; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info))) + return 0; + + return 1; +} + +static struct ipt_match conntrack_match += { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + /* NULL if ip_conntrack not a module */ + if (ip_conntrack_module) + __MOD_INC_USE_COUNT(ip_conntrack_module); + return ipt_register_match(&conntrack_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&conntrack_match); + if (ip_conntrack_module) + __MOD_DEC_USE_COUNT(ip_conntrack_module); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_iplimit.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_iplimit.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_iplimit.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_iplimit.c Sun Apr 28 21:46:51 2002 @@ -0,0 +1,228 @@ +/* + * netfilter module to limit the number of parallel tcp + * connections per IP address. + * (c) 2000 Gerd Knorr + * + * 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_iplimit_conn +{ + struct list_head list; + struct ip_conntrack_tuple tuple; +}; + +struct ipt_iplimit_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_iplimit_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_iplimit_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_iplimit_conn,list); + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple))) { + /* 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; + } + found = ip_conntrack_find_get(&conn->tuple,ct); +#if DEBUG + printk("ipt_iplimit [%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_iplimit [%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_iplimit_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_iplimit: 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_iplimit: 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_iplimit: 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_iplimit_info *info = matchinfo; + int i; + + /* verify size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_iplimit_info))) + return 0; + + /* refuse anything but tcp */ + if (ip->proto != IPPROTO_TCP) + return 0; + + /* init private data */ + info->data = kmalloc(sizeof(struct ipt_iplimit_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_iplimit_info *info = matchinfo; + struct ipt_iplimit_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_iplimit_conn,list); + list_del(hash->next); + kfree(conn); + } + } + kfree(info->data); +} + +static struct ipt_match iplimit_match += { { NULL, NULL }, "iplimit", &match, &check, &destroy, THIS_MODULE }; + +static int __init init(void) +{ + /* NULL if ip_conntrack not a module */ + if (ip_conntrack_module) + __MOD_INC_USE_COUNT(ip_conntrack_module); + return ipt_register_match(&iplimit_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&iplimit_match); + if (ip_conntrack_module) + __MOD_DEC_USE_COUNT(ip_conntrack_module); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_ipv4options.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_ipv4options.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_ipv4options.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_ipv4options.c Sun Apr 28 22:23:44 2002 @@ -0,0 +1,170 @@ +/* + This is a module which is used to match ipv4 options. + 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 + + 11-mars-2001 Fabrice MARIE : initial development. + 12-july-2001 Fabrice MARIE : added router-alert otions matching. Fixed a bug with no-srr + 12-august-2001 Imran Patel : optimization of the match. + 18-november-2001 Fabrice MARIE : added [!] 'any' option match. +*/ + +#include +#include +#include + +#include +#include + +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_ipv4options_info *info = matchinfo; /* match info for rule */ + const struct iphdr *iph = skb->nh.iph; + const struct ip_options *opt; + + if (iph->ihl * 4 == sizeof(struct iphdr)) { + /* No options, so we match only the "DONTs" and the "IGNOREs" */ + + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) || + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) || + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT)) + return 0; + return 1; + } + else { + if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) + /* there are options, and we don't need to care which one */ + return 1; + else { + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) + /* there are options but we don't want any ! */ + return 0; + } + } + + opt = &(IPCB(skb)->opt); + + /* source routing */ + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) { + if (!((opt->srr) & (opt->is_strictroute))) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) { + if (!((opt->srr) & (!opt->is_strictroute))) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) { + if (opt->srr) + return 0; + } + /* record route */ + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) { + if (!opt->rr) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) { + if (opt->rr) + return 0; + } + /* timestamp */ + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) { + if (!opt->ts) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) { + if (opt->ts) + return 0; + } + /* router-alert option */ + if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) { + if (!opt->router_alert) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) { + if (opt->router_alert) + return 0; + } + + /* we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ + /* Check the size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info))) + return 0; + /* Now check the coherence of the data ... */ + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) && + (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT))) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) && + (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) || + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) || + ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT))) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) && + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) + return 0; /* cannot match in the same time loose and strict source routing */ + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)) + return 0; /* opposites */ + + /* everything looks ok. */ + return 1; +} + +static struct ipt_match ipv4options_match += { { NULL, NULL }, "ipv4options", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk("ipt_ipv4options loading\n"); + return ipt_register_match(&ipv4options_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipv4options_match); + printk("ipt_ipv4options unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_mport.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_mport.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_mport.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_mport.c Sun Apr 28 21:59:30 2002 @@ -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->flags & 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 -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_nth.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_nth.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_nth.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_nth.c Sun Apr 28 22:00:58 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_owner.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_owner.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_owner.c Sun Sep 30 21:26:08 2001 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_owner.c Sun Apr 28 22:13:13 2002 @@ -12,6 +12,38 @@ #include static int +match_comm(const struct sk_buff *skb, const char *comm) +{ + struct task_struct *p; + struct files_struct *files; + int i; + + read_lock(&tasklist_lock); + for_each_task(p) { + if(strncmp(p->comm, comm, sizeof(p->comm))) + continue; + + task_lock(p); + files = p->files; + if(files) { + read_lock(&files->file_lock); + for (i=0; i < files->max_fds; i++) { + if (fcheck_files(files, i) == skb->sk->socket->file) { + read_unlock(&files->file_lock); + task_unlock(p); + read_unlock(&tasklist_lock); + return 1; + } + } + read_unlock(&files->file_lock); + } + task_unlock(p); + } + read_unlock(&tasklist_lock); + return 0; +} + +static int match_pid(const struct sk_buff *skb, pid_t pid) { struct task_struct *p; @@ -115,6 +147,12 @@ return 0; } + if(info->match & IPT_OWNER_COMM) { + if (!match_comm(skb, info->comm) ^ + !!(info->invert & IPT_OWNER_COMM)) + return 0; + } + return 1; } diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_pkttype.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_pkttype.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_pkttype.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_pkttype.c Sun Apr 28 22:24:11 2002 @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include +#include + +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_pkttype_info *info = matchinfo; + + return (skb->pkt_type == info->pkttype) ^ info->invert; +} + +static int checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ +/* + if (hook_mask + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) + | (1 << NF_IP_FORWARD))) { + printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n"); + return 0; + } +*/ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info))) + return 0; + + return 1; +} + +static struct ipt_match pkttype_match += { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&pkttype_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&pkttype_match); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_pool.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_pool.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_pool.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_pool.c Sun Apr 28 22:24:38 2002 @@ -0,0 +1,71 @@ +/* Kernel module to match an IP address pool. */ + +#include +#include +#include + +#include +#include +#include + +static inline int match_pool( + ip_pool_t index, + __u32 addr, + int inv +) { + if (ip_pool_match(index, ntohl(addr))) + inv = !inv; + return inv; +} + +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_pool_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + + if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr, + info->flags&IPT_POOL_INV_SRC)) + return 0; + + if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr, + info->flags&IPT_POOL_INV_DST)) + return 0; + + 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_pool_info))) + return 0; + return 1; +} + +static struct ipt_match pool_match += { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&pool_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&pool_match); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_psd.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_psd.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_psd.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_psd.c Sun Apr 28 22:09:21 2002 @@ -0,0 +1,360 @@ +/* + This is a module which is used for PSD (portscan detection) + Derived from scanlogd v2.1 written by Solar Designer + and LOG target module. + + Copyright (C) 2000,2001 astaro AG + + 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 + + 2000-05-04 Markus Hennig : initial + 2000-08-18 Dennis Koslowski : first release + 2000-12-01 Dennis Koslowski : UDP scans detection added + 2001-01-02 Dennis Koslowski : output modified + 2001-02-04 Jan Rekorajski : converted from target to match +*/ + +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_LICENSE("GPL"); + +#define HF_DADDR_CHANGING 0x01 +#define HF_SPORT_CHANGING 0x02 +#define HF_TOS_CHANGING 0x04 +#define HF_TTL_CHANGING 0x08 + +/* + * Information we keep per each target port + */ +struct port { + u_int16_t number; /* port number */ + u_int8_t proto; /* protocol number */ + u_int8_t and_flags; /* tcp ANDed flags */ + u_int8_t or_flags; /* tcp ORed flags */ +}; + +/* + * Information we keep per each source address. + */ +struct host { + struct host *next; /* Next entry with the same hash */ + clock_t timestamp; /* Last update time */ + struct in_addr src_addr; /* Source address */ + struct in_addr dest_addr; /* Destination address */ + unsigned short src_port; /* Source port */ + int count; /* Number of ports in the list */ + int weight; /* Total weight of ports in the list */ + struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */ + unsigned char tos; /* TOS */ + unsigned char ttl; /* TTL */ + unsigned char flags; /* HF_ flags bitmask */ +}; + +/* + * State information. + */ +static struct { + spinlock_t lock; + struct host list[LIST_SIZE]; /* List of source addresses */ + struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */ + int index; /* Oldest entry to be replaced */ +} state; + +/* + * Convert an IP address into a hash table index. + */ +static inline int hashfunc(struct in_addr addr) +{ + unsigned int value; + int hash; + + value = addr.s_addr; + hash = 0; + do { + hash ^= value; + } while ((value >>= HASH_LOG)); + + return hash & (HASH_SIZE - 1); +} + +static int +ipt_psd_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) +{ + struct iphdr *ip_hdr; + struct tcphdr *tcp_hdr; + struct in_addr addr; + u_int16_t src_port,dest_port; + u_int8_t tcp_flags, proto; + clock_t now; + struct host *curr, *last, **head; + int hash, index, count; + + /* Parameters from userspace */ + const struct ipt_psd_info *psdinfo = matchinfo; + + /* IP header */ + ip_hdr = pskb->nh.iph; + + /* Sanity check */ + if (ntohs(ip_hdr->frag_off) & IP_OFFSET) { + DEBUGP("PSD: sanity check failed\n"); + return 0; + } + + /* TCP or UDP ? */ + proto = ip_hdr->protocol; + + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { + DEBUGP("PSD: protocol not supported\n"); + return 0; + } + + /* Get the source address, source & destination ports, and TCP flags */ + + addr.s_addr = ip_hdr->saddr; + + tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl); + + /* Yep, itīs dirty */ + src_port = tcp_hdr->source; + dest_port = tcp_hdr->dest; + + if (proto == IPPROTO_TCP) { + tcp_flags = *((u_int8_t*)tcp_hdr + 13); + } + else { + tcp_flags = 0x00; + } + + /* We're using IP address 0.0.0.0 for a special purpose here, so don't let + * them spoof us. [DHCP needs this feature - HW] */ + if (!addr.s_addr) { + DEBUGP("PSD: spoofed source address (0.0.0.0)\n"); + return 0; + } + + /* Use jiffies here not to depend on someone setting the time while we're + * running; we need to be careful with possible return value overflows. */ + now = jiffies; + + spin_lock(&state.lock); + + /* Do we know this source address already? */ + count = 0; + last = NULL; + if ((curr = *(head = &state.hash[hash = hashfunc(addr)]))) + do { + if (curr->src_addr.s_addr == addr.s_addr) break; + count++; + if (curr->next) last = curr; + } while ((curr = curr->next)); + + if (curr) { + + /* We know this address, and the entry isn't too old. Update it. */ + if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 && + time_after_eq(now, curr->timestamp)) { + + /* Just update the appropriate list entry if we've seen this port already */ + for (index = 0; index < curr->count; index++) { + if (curr->ports[index].number == dest_port) { + curr->ports[index].proto = proto; + curr->ports[index].and_flags &= tcp_flags; + curr->ports[index].or_flags |= tcp_flags; + goto out_no_match; + } + } + + /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */ + if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst)) + goto out_no_match; + + /* Packet to a new port, and not TCP/ACK: update the timestamp */ + curr->timestamp = now; + + /* Logged this scan already? Then drop the packet. */ + if (curr->weight >= psdinfo->weight_threshold) + goto out_match; + + /* Specify if destination address, source port, TOS or TTL are not fixed */ + if (curr->dest_addr.s_addr != ip_hdr->daddr) + curr->flags |= HF_DADDR_CHANGING; + if (curr->src_port != src_port) + curr->flags |= HF_SPORT_CHANGING; + if (curr->tos != ip_hdr->tos) + curr->flags |= HF_TOS_CHANGING; + if (curr->ttl != ip_hdr->ttl) + curr->flags |= HF_TTL_CHANGING; + + /* Update the total weight */ + curr->weight += (ntohs(dest_port) < 1024) ? + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; + + /* Got enough destination ports to decide that this is a scan? */ + /* Then log it and drop the packet. */ + if (curr->weight >= psdinfo->weight_threshold) + goto out_match; + + /* Remember the new port */ + if (curr->count < SCAN_MAX_COUNT) { + curr->ports[curr->count].number = dest_port; + curr->ports[curr->count].proto = proto; + curr->ports[curr->count].and_flags = tcp_flags; + curr->ports[curr->count].or_flags = tcp_flags; + curr->count++; + } + + goto out_no_match; + } + + /* We know this address, but the entry is outdated. Mark it unused, and + * remove from the hash table. We'll allocate a new entry instead since + * this one might get re-used too soon. */ + curr->src_addr.s_addr = 0; + if (last) + last->next = last->next->next; + else if (*head) + *head = (*head)->next; + last = NULL; + } + + /* We don't need an ACK from a new source address */ + if (proto == IPPROTO_TCP && tcp_hdr->ack) + goto out_no_match; + + /* Got too many source addresses with the same hash value? Then remove the + * oldest one from the hash table, so that they can't take too much of our + * CPU time even with carefully chosen spoofed IP addresses. */ + if (count >= HASH_MAX && last) last->next = NULL; + + /* We're going to re-use the oldest list entry, so remove it from the hash + * table first (if it is really already in use, and isn't removed from the + * hash table already because of the HASH_MAX check above). */ + + /* First, find it */ + if (state.list[state.index].src_addr.s_addr) + head = &state.hash[hashfunc(state.list[state.index].src_addr)]; + else + head = &last; + last = NULL; + if ((curr = *head)) + do { + if (curr == &state.list[state.index]) break; + last = curr; + } while ((curr = curr->next)); + + /* Then, remove it */ + if (curr) { + if (last) + last->next = last->next->next; + else if (*head) + *head = (*head)->next; + } + + /* Get our list entry */ + curr = &state.list[state.index++]; + if (state.index >= LIST_SIZE) state.index = 0; + + /* Link it into the hash table */ + head = &state.hash[hash]; + curr->next = *head; + *head = curr; + + /* And fill in the fields */ + curr->timestamp = now; + curr->src_addr = addr; + curr->dest_addr.s_addr = ip_hdr->daddr; + curr->src_port = src_port; + curr->count = 1; + curr->weight = (ntohs(dest_port) < 1024) ? + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; + curr->ports[0].number = dest_port; + curr->ports[0].proto = proto; + curr->ports[0].and_flags = tcp_flags; + curr->ports[0].or_flags = tcp_flags; + curr->tos = ip_hdr->tos; + curr->ttl = ip_hdr->ttl; + +out_no_match: + spin_unlock(&state.lock); + return 0; + +out_match: + spin_unlock(&state.lock); + return 1; +} + +static int ipt_psd_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ +/* const struct ipt_psd_info *psdinfo = targinfo;*/ + + /* we accept TCP only */ +/* if (e->ip.proto != IPPROTO_TCP) { */ +/* DEBUGP("PSD: specified protocol may be TCP only\n"); */ +/* return 0; */ +/* } */ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) { + DEBUGP("PSD: matchsize %u != %u\n", + matchsize, + IPT_ALIGN(sizeof(struct ipt_psd_info))); + return 0; + } + + return 1; +} + +static struct ipt_match ipt_psd_reg = { + {NULL, NULL}, + "psd", + ipt_psd_match, + ipt_psd_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_psd_reg)) + return -EINVAL; + + memset(&state, 0, sizeof(state)); + + spin_lock_init(&(state.lock)); + + printk("netfilter PSD loaded - (c) astaro AG\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_psd_reg); + printk("netfilter PSD unloaded - (c) astaro AG\n"); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_quota.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_quota.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_quota.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_quota.c Sun Apr 28 22:06:40 2002 @@ -0,0 +1,81 @@ +/* + * netfilter module to enforce network quotas + * + * Sam Johnston + */ +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED; + +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) +{ + + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + + spin_lock_bh("a_lock); + + if (q->quota >= datalen) { + /* we can afford this one */ + q->quota -= datalen; + spin_unlock_bh("a_lock); + +#ifdef DEBUG_IPT_QUOTA + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen); +#endif + return 1; + } + + /* so we do not allow even small packets from now on */ + q->quota = 0; + +#ifdef DEBUG_IPT_QUOTA + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen); +#endif + + spin_unlock_bh("a_lock); + return 0; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + /* TODO: spinlocks? sanity checks? */ + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info))) + return 0; + + return 1; +} + +static struct ipt_match quota_match + = { {NULL, NULL}, "quota", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init +init(void) +{ + return ipt_register_match("a_match); +} + +static void __exit +fini(void) +{ + ipt_unregister_match("a_match); +} + +module_init(init); +module_exit(fini); + diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_random.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_random.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_random.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_random.c Sun Apr 28 21:47:27 2002 @@ -0,0 +1,96 @@ +/* + This is a module which is used for a "random" match support. + 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-10-14 Fabrice MARIE : initial implementation. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static int +ipt_rand_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_rand_info *info = matchinfo; + u_int8_t random_number; + + /* get 1 random number from the kernel random number generation routine */ + get_random_bytes((void *)(&random_number), 1); + + /* Do we match ? */ + if (random_number <= info->average) + return 1; + else + return 0; +} + +static int +ipt_rand_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ipt_rand_info *info = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_rand_info))) { + printk("ipt_random: matchsize %u != %u\n", matchsize, + IPT_ALIGN(sizeof(struct ipt_rand_info))); + return 0; + } + + /* must be 1 <= average % <= 99 */ + /* 1 x 2.55 = 2 */ + /* 99 x 2.55 = 252 */ + if ((info->average < 2) || (info->average > 252)) { + printk("ipt_random: invalid average %u\n", info->average); + return 0; + } + + return 1; +} + +static struct ipt_match ipt_rand_reg = { + {NULL, NULL}, + "random", + ipt_rand_match, + ipt_rand_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_rand_reg)) + return -EINVAL; + + printk("ipt_random match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_rand_reg); + printk("ipt_random match unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_recent.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_recent.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_recent.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_recent.c Sun Apr 28 22:40:09 2002 @@ -0,0 +1,518 @@ +/* Kernel module to check if the source address has been seen recently. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Defaults, these can be overridden on the module command-line. */ +static int ip_list_tot = 40; +static int ip_pkt_list_tot = 10; + +MODULE_AUTHOR("Stephen Frost "); +MODULE_DESCRIPTION("IP tables recently seen matching module"); +MODULE_LICENSE("GPL"); +MODULE_PARM(ip_list_tot,"i"); +MODULE_PARM(ip_pkt_list_tot,"i"); +MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list"); +MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember"); + +/* Structure of our list of recently seen addresses. */ +struct recent_ip_list { + u_int32_t saddr; + u_int8_t ttl; + u_int32_t last_seen; + u_int32_t *last_pkts; + u_int32_t oldest_pkt; +}; + +/* Structure of our linked list of tables of recent lists. */ +struct recent_ip_tables { + char name[200]; + int count; + struct recent_ip_list *table; + struct recent_ip_tables *next; + spinlock_t list_lock; + struct proc_dir_entry *status_proc; +}; + +/* Our current list of addresses we have recently seen. + * Only added to on a --set, and only updated on --set || --update + */ +static struct recent_ip_tables *r_tables; + +/* We protect r_list with this spinlock so two processors are not modifying + * the list at the same time. + */ +static spinlock_t recent_lock = SPIN_LOCK_UNLOCKED; + +/* Our /proc/net/ipt_recent entry */ +static struct proc_dir_entry *proc_net_ipt_recent; + +/* Function declaration for later. */ +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); + +/* This is the function which produces the output for our /proc output + * interface which lists each IP address, the last seen time and the + * other recent times the address was seen. + */ + +static int ip_recent_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + int len = 0, count, last_len = 0, pkt_count; + off_t pos = 0; + off_t begin = 0; + struct recent_ip_tables *curr_table; + + curr_table = (struct recent_ip_tables*) data; + + spin_lock_bh(&curr_table->list_lock); + for(count = 0; count < ip_list_tot; count++) { + if(!curr_table->table[count].saddr) continue; + last_len = len; + len += sprintf(buffer+len,"src=%u.%u.%u.%u ",NIPQUAD(curr_table->table[count].saddr)); + len += sprintf(buffer+len,"ttl: %d ",curr_table->table[count].ttl); + len += sprintf(buffer+len,"last_seen: %d ",curr_table->table[count].last_seen); + len += sprintf(buffer+len,"oldest_pkt: %d ",curr_table->table[count].oldest_pkt); + len += sprintf(buffer+len,"last_pkts: %d",curr_table->table[count].last_pkts[0]); + for(pkt_count = 1; pkt_count < ip_pkt_list_tot; pkt_count++) { + if(!curr_table->table[count].last_pkts[pkt_count]) break; + len += sprintf(buffer+len,", %d",curr_table->table[count].last_pkts[pkt_count]); + } + len += sprintf(buffer+len,"\n"); + pos = begin + len; + if(pos < offset) { len = 0; begin = pos; } + if(pos > offset + length) { len = last_len; break; } + } + + *start = buffer + (offset - begin); + len -= (offset - begin); + if(len > length) len = length; + + spin_unlock_bh(&curr_table->list_lock); + return len; +} + +/* ip_recent_ctrl provides an interface for users to modify the table + * directly. This allows adding entries, removing entries, and + * flushing the entire table. + * This is done by opening up the appropriate table for writing and + * sending one of: + * xx.xx.xx.xx -- Add entry to table with current time + * +xx.xx.xx.xx -- Add entry to table with current time + * -xx.xx.xx.xx -- Remove entry from table + * -0.0.0.0 -- Flush table, remove all entries + */ + +static int ip_recent_ctrl(struct file *file, const char *input, unsigned long size, void *data) +{ + static const u_int32_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + u_int32_t val; + int base; + char c, *cp; + union iaddr { + uint8_t bytes[4]; + uint32_t word; + } res; + uint8_t *pp = res.bytes; + int digit; + + char buffer[1024]; + int len, check_set = 0, count; + u_int32_t saddr = 0; + struct sk_buff skb; + struct ipt_recent_info info; + struct recent_ip_tables *curr_table; + + curr_table = (struct recent_ip_tables*) data; + + if(size > 1024) len = 1024; else len = size; + + if(copy_from_user(buffer,input,len)) return -EFAULT; + + buffer[len-1] = '\0'; + + cp = buffer; + if(buffer[0] == '+') { check_set = IPT_RECENT_SET; cp++; } + if(buffer[0] == '-') { check_set = IPT_RECENT_REMOVE; cp++; } + if(buffer[0] >= '0' && buffer[0] <= '9') check_set = IPT_RECENT_SET; + if(!check_set) return len; + + /* Get saddr (effectively inet_aton()) */ + /* Shamelessly stolen from libc, a function in the kernel for doing + * this would, of course, be greatly preferred, but our options appear + * to be rather limited, so we will just do it ourselves here. + */ + res.word = 0; + + c = *cp; + for(;;) { + if(!isdigit(c)) return len; + val = 0; base = 10; digit = 0; + if(c == '0') { + c = *++cp; + if(c == 'x' || c == 'X') base = 16, c = *++cp; + else { base = 8; digit = 1; } + } + for(;;) { + if(isascii(c) && isdigit(c)) { + if(base == 8 && (c == '8' || c == '0')) return len; + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if(base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } else break; + } + if(c == '.') { + if(pp > res.bytes + 2 || val > 0xff) return len; + *pp++ = val; + c = *++cp; + } else break; + } + if(c != '\0' && (!isascii(c) || !isspace(c))) return len; + if(!digit) return len; + + if(val > max[pp - res.bytes]) return len; + saddr = res.word | htonl(val); + + if(!saddr && check_set == IPT_RECENT_SET) return len; + + /* Check if we are asked to flush the entire table */ + if(!saddr && check_set == IPT_RECENT_REMOVE) { + spin_lock_bh(&curr_table->list_lock); + for(count = 0; count < ip_list_tot; count++) { + curr_table->table[count].last_seen = 0; + curr_table->table[count].saddr = 0; + curr_table->table[count].ttl = 0; + memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); + curr_table->table[count].oldest_pkt = 0; + } + spin_unlock_bh(&curr_table->list_lock); + return len; + } + + /* Set up and just call match */ + info.seconds = 0; + info.hit_count = 0; + info.check_set = check_set; + info.invert = 0; + strncpy(info.name,curr_table->name,200); + + skb.nh.iph = kmalloc(sizeof(struct iphdr),GFP_KERNEL); + if(!skb.nh.iph) { return -ENOMEM; } + + skb.nh.iph->saddr = saddr; + match(&skb,NULL,NULL,&info,0,NULL,sizeof(info),NULL); + kfree(skb.nh.iph); + + return len; +} + +/* 'match' is our primary function, called by the kernel whenever a rule is + * hit with our module as an option to it. + * What this function does depends on what was specifically asked of it by + * the user: + * --set -- Add or update last seen time of the source address of the packet + * -- matchinfo->check_set == IPT_RECENT_SET + * --rcheck -- Just check if the source address is in the list + * -- matchinfo->check_set == IPT_RECENT_CHECK + * --update -- If the source address is in the list, update last_seen + * -- matchinfo->check_set == IPT_RECENT_UPDATE + * --remove -- If the source address is in the list, remove it + * -- matchinfo->check_set == IPT_RECENT_REMOVE + * --seconds -- Option to --rcheck/--update, only match if last_seen within seconds + * -- matchinfo->seconds + * --hitcount -- Option to --rcheck/--update, only match if seen hitcount times + * -- matchinfo->hit_count + * --seconds and --hitcount can be combined + */ +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) +{ + int count, pkt_count, oldest = 0, hits_found, ans; + unsigned long now = jiffies; + unsigned long oldest_time; + const struct ipt_recent_info *info = matchinfo; + u_int32_t saddr = skb->nh.iph->saddr; + u_int8_t ttl = skb->nh.iph->ttl; + struct recent_ip_tables *curr_table; + struct recent_ip_tables *last_table; + struct recent_ip_list *r_list; + + /* Default is false ^ info->invert */ + ans = info->invert; + + /* Find the right table */ + spin_lock_bh(&recent_lock); + curr_table = r_tables; + while( (last_table = curr_table) && strncmp(info->name,curr_table->name,200) && (curr_table = curr_table->next) ); + spin_unlock_bh(&recent_lock); + + /* Table with this name not found, match impossible */ + if(!curr_table) { return ans; } + + /* Make sure no one is changing the list while we work with it */ + spin_lock_bh(&curr_table->list_lock); + + r_list = curr_table->table; + + for(count = 0, oldest_time = r_list[0].last_seen; count < ip_list_tot; count++) { + /* Keep track of empty spaces which can be filled up later */ + if(!r_list[count].saddr) { oldest = count; continue; } + /* Keep track of the oldest entry if we have been asked to add this entry + * to the table if it does not exist. */ + if(info->check_set & IPT_RECENT_SET && r_list[count].last_seen < oldest_time) { + oldest_time = r_list[count].last_seen; + oldest = count; + } + if(r_list[count].saddr == saddr) { + /* We have a match on address, now to make sure it meets all requirements for a + * full match. */ + /* Check for TTL match if requested. If TTL is zero then a match would never + * happen, so match regardless of existing TTL in that case. Zero means the + * entry was added via the /proc interface anyway, so we will just use the + * first TTL we get for that IP address. */ + if(info->check_set & IPT_RECENT_TTL && r_list[count].ttl && r_list[count].ttl != ttl) continue; + if(info->check_set & IPT_RECENT_CHECK || info->check_set & IPT_RECENT_UPDATE) { + if(!info->seconds && !info->hit_count) ans = !info->invert; else ans = info->invert; + if(info->seconds && !info->hit_count) { + if(time_before(now,r_list[count].last_seen+info->seconds*HZ)) ans = !info->invert; else ans = info->invert; + } + if(info->seconds && info->hit_count) { + for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) { + if(time_before(now,r_list[count].last_pkts[pkt_count]+info->seconds*HZ)) hits_found++; + } + if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert; + } + if(info->hit_count && !info->seconds) { + for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) { + if(r_list[count].last_pkts[pkt_count] == 0) break; + hits_found++; + } + if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert; + } + } + /* If and only if we have been asked to SET, or to UPDATE (on match) do we add the + * current timestamp to the last_seen. */ + if((info->check_set & IPT_RECENT_SET && (ans = !info->invert)) || (info->check_set & IPT_RECENT_UPDATE && ans)) { + r_list[count].last_seen = now; + /* If asked to match on TTL we will not hit here unless the TTL already matches, + * or is zero. If zero then the IP address was added via /proc, so we need to + * add the TTL here for the IP address. If non-zero, then we are not matching + * on TTL, or the TTL already matches, so it does not hurt to set it here. */ + r_list[count].ttl = ttl; + r_list[count].last_pkts[r_list[count].oldest_pkt] = now; + r_list[count].oldest_pkt = ++r_list[count].oldest_pkt % ip_pkt_list_tot; + } + /* If we have been asked to remove the entry from the list, just set it to 0 */ + if(info->check_set & IPT_RECENT_REMOVE) { + r_list[count].last_seen = 0; + r_list[count].saddr = 0; + r_list[count].ttl = 0; + memset(r_list[count].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); + r_list[count].oldest_pkt = 0; + ans = !info->invert; + } + spin_unlock_bh(&curr_table->list_lock); + return ans; + } + } + + /* If the address is not currently in the list and we have been asked to SET + * then we need to add it to the list. We do this by replacing the oldest + * entry in the list which is determined when we step through the list. */ + if(info->check_set & IPT_RECENT_SET) { + memset(r_list[oldest].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); + r_list[oldest].saddr = saddr; + r_list[oldest].ttl = ttl; + r_list[oldest].last_seen = now; + r_list[oldest].last_pkts[0] = now; + r_list[oldest].oldest_pkt = 1; + + ans = !info->invert; + } + + spin_unlock_bh(&curr_table->list_lock); + return ans; +} + +/* This function is to verify that the rule given during the userspace iptables + * command is correct. + * If the command is valid then we check if the table name referred to by the + * rule exists, if not it is created. + */ +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + int flag = 0, c; + u_int32_t *hold; + const struct ipt_recent_info *info = matchinfo; + struct recent_ip_tables *curr_table, *last_table; + if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0; + + /* seconds and hit_count only valid for CHECK/UPDATE */ + if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; } + if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; } + if(info->check_set & IPT_RECENT_CHECK) flag++; + if(info->check_set & IPT_RECENT_UPDATE) flag++; + + /* One and only one of these should ever be set */ + if(flag != 1) return 0; + + /* Name must be set to something */ + if(!info->name || !info->name[0]) return 0; + + /* Things look good, create a list for this if it does not exist */ + /* Lock the linked list while we play with it */ + spin_lock_bh(&recent_lock); + + /* Look for an entry with this name already created */ + /* Finds the end of the list and the entry before the end if current name does not exist */ + curr_table = r_tables; + while( (last_table = curr_table) && strncmp(info->name,curr_table->name,200) && (curr_table = curr_table->next) ); + + /* If a table already exists just increment the count on that table and return */ + if(curr_table) { curr_table->count++; spin_unlock_bh(&recent_lock); return 1; } + + /* Table with this name not found */ + /* Allocate memory for new linked list item */ + curr_table = kmalloc(sizeof(struct recent_ip_tables),GFP_KERNEL); + if(curr_table == NULL) { spin_unlock_bh(&recent_lock); return -ENOMEM; } + + curr_table->list_lock = SPIN_LOCK_UNLOCKED; + curr_table->next = NULL; + curr_table->count = 1; + strncpy(curr_table->name,info->name,200); + + /* Allocate memory for this table and the list of packets in each entry. */ + curr_table->table = kmalloc(sizeof(struct recent_ip_list)*ip_list_tot,GFP_KERNEL); + if(curr_table->table == NULL) { spin_unlock_bh(&recent_lock); return -ENOMEM; } + memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot); + hold = kmalloc(sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot,GFP_KERNEL); + if(hold == NULL) { kfree(curr_table->table); spin_unlock_bh(&recent_lock); return -ENOMEM; } + for(c = 0; c < ip_list_tot; c++) { + curr_table->table[c].last_pkts = hold + c*ip_pkt_list_tot; + } + + /* Create our proc 'status' entry. */ + curr_table->status_proc = create_proc_entry(curr_table->name, 0644, proc_net_ipt_recent); + if (curr_table->status_proc) curr_table->status_proc->owner = THIS_MODULE; + else { + kfree(curr_table->table); + kfree(curr_table); + kfree(hold); + return -ENOMEM; + } + curr_table->status_proc->read_proc = ip_recent_get_info; + curr_table->status_proc->write_proc = ip_recent_ctrl; + curr_table->status_proc->data = curr_table; + + /* Put the new table in place */ + if(!last_table) r_tables = curr_table; else last_table->next = curr_table; + + spin_unlock_bh(&recent_lock); + + return 1; +} + +/* This function is called in the event that a rule matching this module is + * removed. + * When this happens we need to check if there are no other rules matching + * the table given. If that is the case then we remove the table and clean + * up its memory. + */ +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + const struct ipt_recent_info *info = matchinfo; + struct recent_ip_tables *curr_table, *last_table; + if(matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return; + + /* Lock the linked list while we play with it */ + spin_lock_bh(&recent_lock); + + /* Look for an entry with this name already created */ + /* Finds the end of the list and the entry before the end if current name does not exist */ + last_table = NULL; + curr_table = r_tables; + if(!curr_table) { spin_unlock_bh(&recent_lock); return; } + while( strncmp(info->name,curr_table->name,200) && (last_table = curr_table) && (curr_table = curr_table->next) ); + + /* If a table does not exist then do nothing and return */ + if(!curr_table) { spin_unlock_bh(&recent_lock); return; } + + curr_table->count--; + /* If count is still non-zero then there are still rules referenceing it so we do nothing */ + if(curr_table->count) { spin_unlock_bh(&recent_lock); return; } + + /* Count must be zero so we remove this table from the list */ + if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next; + + /* lock to make sure any late-runners still using this after we removed it from + * the list finish up then remove everything */ + spin_lock_bh(&curr_table->list_lock); + remove_proc_entry(curr_table->name,proc_net_ipt_recent); + kfree(curr_table->table[0].last_pkts); + kfree(curr_table->table); + spin_unlock_bh(&curr_table->list_lock); + kfree(curr_table); + + spin_unlock_bh(&recent_lock); + + return; +} + +/* This is the structure we pass to ipt_register to register our + * module with iptables. + */ +static struct ipt_match recent_match += { { NULL, NULL }, "recent", &match, &checkentry, &destroy, THIS_MODULE }; + +/* Kernel module initialization. */ +static int __init init(void) +{ + proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net); + if(!proc_net_ipt_recent) return -ENOMEM; + + return ipt_register_match(&recent_match); +} + +/* Kernel module destruction. */ +static void __exit fini(void) +{ + ipt_unregister_match(&recent_match); + + remove_proc_entry("ipt_recent",proc_net); +} + +/* Register our module with the kernel. */ +module_init(init); +module_exit(fini); diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_time.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_time.c --- linux-2.4.18_vanilla/net/ipv4/netfilter/ipt_time.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv4/netfilter/ipt_time.c Sun Apr 28 22:07:44 2002 @@ -0,0 +1,185 @@ +/* + This is a module which is used for time matching + It is using some modified code from dietlibc (localtime() function) + that you can find at http://www.fefe.de/dietlibc/ + 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-05-04 Fabrice MARIE : initial development. + 2001-21-05 Fabrice MARIE : bug fix in the match code, + thanks to "Zeng Yu" for bug report. + 2001-26-09 Fabrice MARIE : force the match to be in LOCAL_IN or PRE_ROUTING only. + 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, + added Nguyen Dang Phuoc Dong patch to support timezones. +*/ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Fabrice MARIE "); +MODULE_DESCRIPTION("Match arrival timestamp"); +MODULE_LICENSE("GPL"); + +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + + long int tm_gmtoff; /* we don't care, we count from GMT */ + const char *tm_zone; /* we don't care, we count from GMT */ +}; + +void +localtime(const time_t *timepr, struct tm *r); + +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_time_info *info = matchinfo; /* match info for rule */ + struct tm currenttime; /* time human readable */ + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; + u_int16_t packet_time; + struct timeval kerneltimeval; + time_t packet_local_time; + + /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */ + if (info->kerneltime) + { + do_gettimeofday(&kerneltimeval); + packet_local_time = kerneltimeval.tv_sec; + } + else + packet_local_time = skb->stamp.tv_sec; + + /* Transform the timestamp of the packet, in a human readable form */ + localtime(&packet_local_time, ¤ttime); + + /* check if we match this timestamp, we start by the days... */ + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) + return 0; /* the day doesn't match */ + + /* ... check the time now */ + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; + if ((packet_time < info->time_start) || (packet_time > info->time_stop)) + return 0; + + /* here we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_time_info *info = matchinfo; /* match info for rule */ + + /* First, check that we are in the correct hook */ + /* PRE_ROUTING, LOCAL_IN or FROWARD */ + if (hook_mask + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) + { + printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); + return 0; + } + /* we use the kerneltime if we are in forward or output */ + info->kerneltime = 1; + if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) + /* if not, we use the skb time */ + info->kerneltime = 0; + + /* Check the size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info))) + return 0; + /* Now check the coherence of the data ... */ + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ + (info->time_stop > 1439)) + { + printk(KERN_WARNING "ipt_time: invalid argument\n"); + return 0; + } + + return 1; +} + +static struct ipt_match time_match += { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk("ipt_time loading\n"); + return ipt_register_match(&time_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&time_match); + printk("ipt_time unloaded\n"); +} + +module_init(init); +module_exit(fini); + + +/* The part below is borowed and modified from dietlibc */ + +/* seconds per day */ +#define SPD 24*60*60 + +void +localtime(const time_t *timepr, struct tm *r) { + time_t i; + time_t timep; + extern struct timezone sys_tz; + const unsigned int __spm[12] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + }; + register time_t work; + + timep = (*timepr) - (sys_tz.tz_minuteswest * 60); + work=timep%(SPD); + r->tm_sec=work%60; work/=60; + r->tm_min=work%60; r->tm_hour=work/60; + work=timep/(SPD); + r->tm_wday=(4+work)%7; + for (i=1970; ; ++i) { + register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; + if (work>k) + work-=k; + else + break; + } + r->tm_year=i-1900; + for (i=11; i && __spm[i]>work; --i) ; + r->tm_mon=i; + r->tm_mday=work-__spm[i]+1; +} diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv6/netfilter/Config.in linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/Config.in --- linux-2.4.18_vanilla/net/ipv6/netfilter/Config.in Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/Config.in Sun Apr 28 22:45:44 2002 @@ -24,6 +24,9 @@ fi # dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES dep_tristate ' netfilter MARK match support' CONFIG_IP6_NF_MATCH_MARK $CONFIG_IP6_NF_IPTABLES + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Aggregated address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_AGR $CONFIG_IP6_NF_IPTABLES + fi # dep_tristate ' Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES # dep_tristate ' TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES # if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then @@ -37,6 +40,9 @@ # The targets dep_tristate ' Packet filtering' CONFIG_IP6_NF_FILTER $CONFIG_IP6_NF_IPTABLES if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then + dep_tristate ' REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER + fi + if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_FILTER fi diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv6/netfilter/Makefile linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/Makefile --- linux-2.4.18_vanilla/net/ipv6/netfilter/Makefile Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/Makefile Sun Apr 28 22:45:44 2002 @@ -16,11 +16,13 @@ obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o +obj-$(CONFIG_IP6_NF_MATCH_AGR) += ip6t_agr.o obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o 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 diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv6/netfilter/ip6_queue.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/ip6_queue.c --- linux-2.4.18_vanilla/net/ipv6/netfilter/ip6_queue.c Mon Feb 25 21:38:14 2002 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/ip6_queue.c Sun Apr 28 22:29:47 2002 @@ -518,7 +518,7 @@ return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT); } -#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0); +#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static __inline__ void netlink_receive_user_skb(struct sk_buff *skb) { diff -u --new-file --recursive linux-2.4.18_vanilla/net/ipv6/netfilter/ip6t_REJECT.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/ip6t_REJECT.c --- linux-2.4.18_vanilla/net/ipv6/netfilter/ip6t_REJECT.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/ip6t_REJECT.c Sun Apr 28 22:44:41 2002 @@ -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 -u --new-file --recursive linux-2.4.18_vanilla/net/ipv6/netfilter/ip6t_agr.c linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/ip6t_agr.c --- linux-2.4.18_vanilla/net/ipv6/netfilter/ip6t_agr.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.18_iptables-1.2.6a-extensions/net/ipv6/netfilter/ip6t_agr.c Sun Apr 28 22:45:44 2002 @@ -0,0 +1,91 @@ +/* Kernel module to match AGR address parameters. */ +#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) +{ + + unsigned char aggregated[8]; + int i=0; + + /*TODO size and pointer checking */ + if ( !(skb->mac.raw >= skb->head + && (skb->mac.raw + ETH_HLEN) <= skb->data) + && offset != 0) { + *hotdrop = 1; + return 0; + } + + memset(aggregated, 0, sizeof(aggregated)); + + if (skb->mac.ethernet->h_proto == ntohs(ETH_P_IPV6)) { + if (skb->nh.ipv6h->version == 0x6) { + memcpy(aggregated, skb->mac.ethernet->h_source, 3); + memcpy(aggregated + 5, skb->mac.ethernet->h_source + 3, 3); + aggregated[3]=0xff; + aggregated[4]=0xfe; + aggregated[0] |= 0x02; + + i=0; + while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] == + aggregated[i]) && (i<8)) i++; + + if ( i == 8 ) + return 1; + } + } + + return 0; + +/* return (skb->mac.raw >= skb->head + && skb->mac.raw < skb->head + skb->len - ETH_HLEN */ + + +} + +static int +ipt_agr_checkentry(const char *tablename, + const struct ip6t_ip6 *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (hook_mask + & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN))) { + printk("ipt_agr: only valid for PRE_ROUTING or LOCAL_IN.\n"); + return 0; + } + + if (matchsize != IP6T_ALIGN(sizeof(int))) + return 0; + + return 1; +} + +static struct ip6t_match agr_match += { { NULL, NULL }, "agr", &match, &ipt_agr_checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ip6t_register_match(&agr_match); +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&agr_match); +} + +module_init(init); +module_exit(fini);