From 4356d229585594a5dfee866ef197a9a900f38a2e Mon Sep 17 00:00:00 2001 From: cieciwa Date: Wed, 24 Sep 2003 11:43:50 +0000 Subject: [PATCH] - netfilter snapshot 20030924 Changed files: linux-2.4.20-netfilter-1.2.8_20030924.patch -> 1.1 --- linux-2.4.20-netfilter-1.2.8_20030924.patch | 29498 ++++++++++++++++++ 1 file changed, 29498 insertions(+) create mode 100644 linux-2.4.20-netfilter-1.2.8_20030924.patch diff --git a/linux-2.4.20-netfilter-1.2.8_20030924.patch b/linux-2.4.20-netfilter-1.2.8_20030924.patch new file mode 100644 index 00000000..f50f9c72 --- /dev/null +++ b/linux-2.4.20-netfilter-1.2.8_20030924.patch @@ -0,0 +1,29498 @@ +diff -Nur --exclude '*.orig' linux-2.4.20.org/Documentation/Configure.help linux-2.4.20/Documentation/Configure.help +--- linux-2.4.20.org/Documentation/Configure.help Wed Sep 24 08:52:58 2003 ++++ linux-2.4.20/Documentation/Configure.help Wed Sep 24 09:18:15 2003 +@@ -2543,6 +2543,50 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++Amanda protocol support ++CONFIG_IP_NF_AMANDA ++ If you are running the Amanda backup package (http://www.amanda.org/) ++ on this machine or machines that will be MASQUERADED through this ++ machine, then you may want to enable this feature. This allows the ++ connection tracking and natting code to allow the sub-channels that ++ Amanda requires for communication of the backup data, messages and ++ index. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++CuSeeMe protocol support ++CONFIG_IP_NF_CUSEEME ++ The CuSeeMe conferencing protocol is problematic when used in ++ conjunction with NAT; even though there are no random ports used for ++ extra connections, the messages contain IP addresses inside them. ++ This NAT helper mangles the IP address inside packets so both ++ parties don't get confused. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `Y'. ++ ++MMS protocol support ++CONFIG_IP_NF_MMS ++ Tracking MMS (Microsoft Windows Media Services) connections ++ could be problematic if random ports are used to send the ++ streaming content. This option allows users to track streaming ++ connections over random UDP or TCP ports. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `Y'. ++ ++Quake III Arena protocol support ++CONFIG_IP_NF_QUAKE3 ++ Quake III Arena connection tracking helper. This module allows for a ++ stricter firewall rulebase if one only allows traffic to a master ++ server. Connections to Quake III server IP addresses and ports returned ++ by the master server will be tracked automatically. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `Y'. ++ + IRC Send/Chat protocol support + CONFIG_IP_NF_IRC + There is a commonly-used extension to IRC called +@@ -2557,6 +2601,118 @@ + If you want to compile it as a module, say 'M' here and read + Documentation/modules.txt. If unsure, say 'N'. + ++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'. ++ ++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'. ++ ++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'. ++ ++H.323 (netmeeting) support ++CONFIG_IP_NF_H323 ++ H.323 is a standard signalling protocol used by teleconferencing ++ softwares like netmeeting. With the ip_conntrack_h323 and ++ the ip_nat_h323 modules you can support the protocol on a connection ++ tracking/NATing firewall. ++ ++ If you want to compile it as a module, say 'M' here and read ++ Documentation/modules.txt. If unsure, say 'N'. ++ ++PPTP conntrack and NAT support ++CONFIG_IP_NF_PPTP ++ This module adds support for PPTP (Point to Point Tunnelling Protocol, ++ RFC2637) conncection tracking and NAT. ++ ++ If you are running PPTP sessions over a stateful firewall or NAT box, ++ you may want to enable this feature. ++ ++ Please note that not all PPTP modes of operation are supported yet. ++ For more info, read top of the file net/ipv4/netfilter/ip_conntrack_pptp.c ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++GRE protocol conntrack and NAT support ++CONFIG_IP_NF_CT_PROTO_GRE ++ This module adds generic support for connection tracking and NAT of the ++ GRE protocol (RFC1701, RFC2784). Please note that this will only work ++ with GRE connections using the key field of the GRE header. ++ ++ You will need GRE support to enable PPTP support. ++ ++ If you want to compile it as a module, say `M' here and read ++ Documentation/modules.txt. If unsire, say `N'. ++ ++RSH protocol support ++CONFIG_IP_NF_RSH ++ The RSH connection tracker is required if the dynamic ++ stderr "Server to Client" connection is to occur during a ++ normal RSH session. This typically operates as follows; ++ ++ Client 0:1023 --> Server 514 (stream 1 - stdin/stdout) ++ Client 0:1023 <-- Server 0:1023 (stream 2 - stderr) ++ ++ This connection tracker will identify new RSH sessions, ++ extract the outbound session details, and notify netfilter ++ of pending "related" sessions. ++ ++ Warning: This module could be dangerous. It is not "best ++ practice" to use RSH, use SSH in all instances. ++ (see rfc1244, rfc1948, rfc2179, etc ad-nauseum) ++ ++ ++ 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 (both otalk/talk - or talk/ntalk, to confuse ++ you by the different namings about which is old or which is new :-) ++ 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'. ++ + FTP protocol support + CONFIG_IP_NF_FTP + Tracking FTP connections is problematic: special helpers are +@@ -2584,6 +2740,33 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++recent match support ++CONFIG_IP_NF_MATCH_RECENT ++ This match is used for creating one or many lists of recently ++ used addresses and then matching against that/those list(s). ++ ++ Short options are available by using 'iptables -m recent -h' ++ Official Website: ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. 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'. ++ ++ ++addrtype match support ++CONFIG_IP_NF_MATCH_ADDRTYPE ++ This option allows you to match what routing thinks of an address, ++ eg. UNICAST, LOCAL, BROADCAST, ... ++ ++ 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 +@@ -2635,6 +2818,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 +@@ -2652,6 +2843,18 @@ + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + ++U32 patch support ++CONFIG_IP_NF_MATCH_U32 ++ U32 allows you to extract quantities of up to 4 bytes from a packet, ++ AND them with specified masks, shift them by specified amounts and ++ test whether the results are in any of a set of specified ranges. ++ The specification of what to extract is general enough to skip over ++ headers with lengths stored in the packet, as in IP or TCP header ++ lengths. ++ ++ Details and examples are in the kernel module source. ++ ++ + LENGTH match support + CONFIG_IP_NF_MATCH_LENGTH + This option allows you to match the length of a packet against a +@@ -2690,6 +2893,132 @@ + + + ++Fuzzy Logic Controller match support ++CONFIG_IP_NF_MATCH_FUZZY ++ This option adds a `fuzzy' match, ++ which allows you to match packets according to a fuzzy logic ++ based law . ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++iprange match support ++CONFIG_IP_NF_MATCH_IPRANGE ++ This option makes possible to match IP addresses against ++ IP address ranges. ++ ++ If you want to compile it as a module, say M here and read ++ . 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'. ++ ++ ++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'. ++ ++ ++OSF match support ++CONFIG_IP_NF_MATCH_OSF ++ ++ The idea of passive OS fingerprint matching exists for quite a long time, ++ but was created as extension fo OpenBSD pf only some weeks ago. ++ Original idea was lurked in some OpenBSD mailing list (thanks ++ grange@open...) and than adopted for Linux netfilter in form of this code. ++ ++ Original table was created by Michal Zalewski for ++ his excellent p0f and than changed a bit for more convenience. ++ ++ This module compares some data(WS, MSS, options and it's order, ttl, ++ df and others) from first SYN packet (actually from packets with SYN ++ bit set) with hardcoded in fingers[] table ones. ++ ++ If you say Y here, try iptables -m osf --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'. ++ ++ ++Random 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'. ++ ++ ++REALM match support ++CONFIG_IP_NF_MATCH_REALM ++ This option adds a `realm' match, which allows you to use the realm ++ key from the routing subsytem inside iptables. ++ ++ This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option ++ in tc world. ++ ++ 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'. ++ ++ ++Condition variable match support ++CONFIG_IP_NF_MATCH_CONDITION ++ This option allows you to match firewall rules against condition ++ variables stored in the /proc/net/ipt_condition directory. ++ ++ 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 +@@ -2710,6 +3039,44 @@ + Documentation/modules.txt. If unsure, say `N'. + + ++Connections/IP limit match support ++CONFIG_IP_NF_MATCH_CONNLIMIT ++ 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'. ++ ++RPC match support ++CONFIG_IP_NF_MATCH_RPC ++ This adds CONFIG_IP_NF_MATCH_RPC, which is the RPC connection ++ matcher and tracker. ++ ++ This option supplies two connection tracking modules; ++ ip_conntrack_rpc_udp and ip_conntrack_rpc_tcp, which track ++ portmapper requests using UDP and TCP respectively. ++ ++ This option also adds an RPC match module for iptables, which ++ matches both via the old "record match" method and a new ++ "procedure match" method. The older method matches all RPC ++ procedure packets that relate to previously recorded packets ++ seen querying a portmapper. The newer method matches only ++ those RPC procedure packets explicitly specified by the user, ++ and that can then be related to previously recorded packets ++ seen querying a portmapper. ++ ++ These three modules are required if RPCs are to be filtered ++ accurately; as RPCs are allocated pseudo-randomly to UDP and ++ TCP ports as they register with the portmapper. ++ ++ Up to 8 portmapper ports per module, and up to 128 RPC ++ procedures per iptables rule, may be specified by the user, ++ to enable effective RPC management. ++ ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ + Connection state match support + CONFIG_IP_NF_MATCH_STATE + Connection state matching allows you to match packets based on their +@@ -2719,6 +3086,14 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++String match support (EXPERIMENTAL) ++CONFIG_IP_NF_MATCH_STRING ++ String matching alows you to match packets which contain a ++ specified string of characters. ++ ++ 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 +@@ -2735,6 +3110,52 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++TARPIT target support ++CONFIG_IP_NF_TARGET_TARPIT ++ Adds a TARPIT target to iptables, which captures and holds ++ incoming TCP connections using no local per-connection resources. ++ Connections are accepted, but immediately switched to the persist ++ state (0 byte window), in which the remote side stops sending data ++ and asks to continue every 60-240 seconds. Attempts to close the ++ connection are ignored, forcing the remote side to time out the ++ connection in 12-24 minutes. ++ ++ This offers similar functionality to LaBrea ++ but doesn't require dedicated ++ hardware or IPs. Any TCP port that you would normally DROP or REJECT ++ can instead become a tarpit. ++ ++raw table support (required for NOTRACK/TRACE) ++CONFIG_IP_NF_RAW ++ This option adds a `raw' table to iptables. This table is the very ++ first in the netfilter framework and hooks in at the PREROUTING ++ and OUTPUT chains. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++TRACE target support ++CONFIG_IP_NF_TARGET_TRACE ++ The TRACE target allows packets to be traced as those ++ matches any subsequent rule in any table/rule. The matched ++ rule and the packet is logged with the prefix ++ ++ TRACE: tablename/chainname/rulenum ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++NOTRACK target support ++CONFIG_IP_NF_TARGET_NOTRACK ++ The NOTRACK target allows a select rule to specify ++ which packets *not* to enter the conntrack/NAT ++ subsystem with all the consequences (no ICMP error tracking, ++ no protocol helpers for the selected packets). ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++ + Packet filtering + CONFIG_IP_NF_FILTER + Packet filtering defines a table `filter', which has a series of +@@ -2744,6 +3165,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 +@@ -2808,6 +3247,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 +@@ -2866,6 +3326,42 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++IMQ target support ++CONFIG_IP_NF_TARGET_IMQ ++ This option adds a `IMQ' target which is used to specify if and ++ to which imq device packets should get enqueued/dequeued. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++IPMARK target support ++CONFIG_IP_NF_TARGET_IPMARK ++ This option adds a `IPMARK' target, which allows you to create rules ++ in the `mangle' table which alter the netfilter mark (nfmark) field ++ basing on the source or destination ip address of the packet. ++ This is very useful for very fast massive mangling and marking. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++ ++ ++ROUTE target support ++CONFIG_IP_NF_TARGET_ROUTE ++ This option adds a `ROUTE' target, which enables you to setup unusual ++ routes. For example, the ROUTE lets you route a received packet through ++ an interface or towards a host, even if the regular destination of the ++ packet is the router itself. The ROUTE target is also able to change the ++ incoming interface of a packet. ++ ++ The target can be or not a final target. It has to be used inside the ++ mangle table. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. The module will be called ipt_ROUTE.o. ++ If unsure, say `N'. ++ ++ + MARK target support + CONFIG_IP_NF_TARGET_MARK + This option adds a `MARK' target, which allows you to create rules +@@ -2933,6 +3429,73 @@ + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + ++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'. ++ ++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. ++ ++CLASSIFY target support ++CONFIG_IP_NF_TARGET_CLASSIFY ++ This option adds a `CLASSIFY' target, which enables the user to set ++ the priority of a packet. Some qdiscs can use this value for classification, ++ among these are: ++ ++ atm, cbq, dsmark, pfifo_fast, htb, prio ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++TCPLAG target support ++CONFIG_IP_NF_TARGET_TCPLAG ++ This option adds a `TCPLAG' target, intended for INPUT, OUTPUT and ++ FORWARD chains. ++ ++ This target has no effect on packets but will passively monitor TCP/IP ++ connections and send lag estimates to syslog. Lag estimates are ++ generated by considering the time delay between SEQ and matching ACK, ++ which does not map precisely to any particular network property. ++ We can say that a fast network will typically give smaller lag values ++ than a slow network. ++ ++ Safest option is to choose `M' here and compile as a module, ++ the module will do nothing until activated using the `iptables' utility. ++ ++ ++XOR target support ++CONFIG_IP_NF_TARGET_XOR ++ This option adds a `XOR' target, which can encrypt TCP and ++ UDP traffic using a simple XOR encryption. ++ ++ 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 +@@ -2972,6 +3535,93 @@ + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + ++AH/ESP match support (EXPERIMENTAL) ++CONFIG_IP6_NF_MATCH_AHESP ++ These two match extensions (`ah' and `esp') allow you to match a ++ range of SPIs inside AH or ESP headers of IPv6 packets. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++Fragmentation header match support (EXPERIMENTAL) ++CONFIG_IP6_NF_MATCH_FRAG ++ This match extension (`frag') allow you to select the packet based on the ++ fileds of the fragmentation header of the IPv6 packets. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++IPv6 Extension Headers Match (EXPERIMENTAL) ++CONFIG_IP6_NF_MATCH_IPV6HEADER ++ extension header matching allows you to controll the packets based ++ on their extension headers. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++Fragmentation header match support (EXPERIMENTAL) ++CONFIG_IP6_NF_MATCH_OPTS ++ These match extensions (`hbh' and `dst') allow you to select the packet ++ based on the fileds of the option header of the IPv6 packets. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++Fragmentation header match support (EXPERIMENTAL) ++CONFIG_IP6_NF_MATCH_RT ++ This match extension (`rt') allow you to select the packet based on the ++ fileds of the routing header of the IPv6 packets. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ ++ ++Fuzzy Logic Controller match support ++CONFIG_IP6_NF_MATCH_FUZZY ++ This option adds a `fuzzy' match, which allows you to match ++ packets according to a fuzzy logic based law. ++ ++ 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_IP6_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'. ++ ++ ++Random match support ++CONFIG_IP6_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'. ++ ++ + MAC address match support + CONFIG_IP6_NF_MATCH_MAC + mac matching allows you to match packets based on the source +@@ -2988,6 +3638,14 @@ + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + ++Condition variable match support ++CONFIG_IP6_NF_MATCH_CONDITION ++ This option allows you to match firewall rules against condition ++ variables stored in the /proc/net/ipt_condition directory. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ + Netfilter MARK match support + CONFIG_IP6_NF_MATCH_MARK + Netfilter mark matching allows you to match packets based on the +@@ -3031,6 +3689,35 @@ + 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'. ++ ++raw table support (required for TRACE) ++CONFIG_IP6_NF_RAW ++ This option adds a `raw' table to ip6tables. This table is the very ++ first in the netfilter framework and hooks in at the PREROUTING ++ and OUTPUT chains. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++TRACE target support ++CONFIG_IP6_NF_TARGET_TRACE ++ The TRACE target allows packets to be traced as those ++ matches any subsequent rule in any table/rule. The matched ++ rule and the packet is logged with the prefix ++ ++ TRACE: tablename/chainname/rulenum ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ + Packet filtering + CONFIG_IP6_NF_FILTER + Packet filtering defines a table `filter', which has a series of +@@ -3049,6 +3736,26 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++IMQ target support ++CONFIG_IP6_NF_TARGET_IMQ ++ This option adds a `IMQ' target which is used to specify if and ++ to which imq device packets should get enqueued/dequeued. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++ROUTE target support ++CONFIG_IP6_NF_TARGET_ROUTE ++ This option adds a `ROUTE' target, which enables you to setup unusual ++ routes. The ROUTE target is also able to change the incoming interface ++ of a packet. ++ ++ The target can be or not a final target. It has to be used inside the ++ mangle table. ++ ++ Not working as a module. ++ ++ + MARK target support + CONFIG_IP6_NF_TARGET_MARK + This option adds a `MARK' target, which allows you to create rules +@@ -3061,6 +3768,11 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++ARP payload mangling ++CONFIG_IP_NF_ARP_MANGLE ++ Allows altering the ARP packet payload: source and destination ++ hardware and network addresses. ++ + TCP Explicit Congestion Notification support + CONFIG_INET_ECN + Explicit Congestion Notification (ECN) allows routers to notify +@@ -3096,6 +3808,22 @@ + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. ++ ++HL match support ++CONFIG_IP6_NF_MATCH_HL ++ This option adds a `hl' match, which allows you match the value of ++ the IPv6 Hop Limit field. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. ++ ++HL target support ++CONFIG_IP6_NF_TARGET_HL ++ This option adds a `HL' target, which allows you to modify the value of ++ IPv6 Hop Limit field. ++ ++ If you want to compile it as a module, say M here and read ++ . If unsure, say `N'. + + LOG target support + CONFIG_IP6_NF_TARGET_LOG +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/jhash.h linux-2.4.20/include/linux/jhash.h +--- linux-2.4.20.org/include/linux/jhash.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/jhash.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,143 @@ ++#ifndef _LINUX_JHASH_H ++#define _LINUX_JHASH_H ++ ++/* jhash.h: Jenkins hash support. ++ * ++ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) ++ * ++ * http://burtleburtle.net/bob/hash/ ++ * ++ * These are the credits from Bob's sources: ++ * ++ * lookup2.c, by Bob Jenkins, December 1996, Public Domain. ++ * hash(), hash2(), hash3, and mix() are externally useful functions. ++ * Routines to test the hash are included if SELF_TEST is defined. ++ * You can use this free for any purpose. It has no warranty. ++ * ++ * Copyright (C) 2003 David S. Miller (davem@redhat.com) ++ * ++ * I've modified Bob's hash to be useful in the Linux kernel, and ++ * any bugs present are surely my fault. -DaveM ++ */ ++ ++/* NOTE: Arguments are modified. */ ++#define __jhash_mix(a, b, c) \ ++{ \ ++ a -= b; a -= c; a ^= (c>>13); \ ++ b -= c; b -= a; b ^= (a<<8); \ ++ c -= a; c -= b; c ^= (b>>13); \ ++ a -= b; a -= c; a ^= (c>>12); \ ++ b -= c; b -= a; b ^= (a<<16); \ ++ c -= a; c -= b; c ^= (b>>5); \ ++ a -= b; a -= c; a ^= (c>>3); \ ++ b -= c; b -= a; b ^= (a<<10); \ ++ c -= a; c -= b; c ^= (b>>15); \ ++} ++ ++/* The golden ration: an arbitrary value */ ++#define JHASH_GOLDEN_RATIO 0x9e3779b9 ++ ++/* The most generic version, hashes an arbitrary sequence ++ * of bytes. No alignment or length assumptions are made about ++ * the input key. ++ */ ++static inline u32 jhash(void *key, u32 length, u32 initval) ++{ ++ u32 a, b, c, len; ++ u8 *k = key; ++ ++ len = length; ++ a = b = JHASH_GOLDEN_RATIO; ++ c = initval; ++ ++ while (len >= 12) { ++ a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); ++ b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); ++ c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); ++ ++ __jhash_mix(a,b,c); ++ ++ k += 12; ++ len -= 12; ++ } ++ ++ c += length; ++ switch (len) { ++ case 11: c += ((u32)k[10]<<24); ++ case 10: c += ((u32)k[9]<<16); ++ case 9 : c += ((u32)k[8]<<8); ++ case 8 : b += ((u32)k[7]<<24); ++ case 7 : b += ((u32)k[6]<<16); ++ case 6 : b += ((u32)k[5]<<8); ++ case 5 : b += k[4]; ++ case 4 : a += ((u32)k[3]<<24); ++ case 3 : a += ((u32)k[2]<<16); ++ case 2 : a += ((u32)k[1]<<8); ++ case 1 : a += k[0]; ++ }; ++ ++ __jhash_mix(a,b,c); ++ ++ return c; ++} ++ ++/* A special optimized version that handles 1 or more of u32s. ++ * The length parameter here is the number of u32s in the key. ++ */ ++static inline u32 jhash2(u32 *k, u32 length, u32 initval) ++{ ++ u32 a, b, c, len; ++ ++ a = b = JHASH_GOLDEN_RATIO; ++ c = initval; ++ len = length; ++ ++ while (len >= 3) { ++ a += k[0]; ++ b += k[1]; ++ c += k[2]; ++ __jhash_mix(a, b, c); ++ k += 3; len -= 3; ++ } ++ ++ c += length * 4; ++ ++ switch (len) { ++ case 2 : b += k[1]; ++ case 1 : a += k[0]; ++ }; ++ ++ __jhash_mix(a,b,c); ++ ++ return c; ++} ++ ++ ++/* A special ultra-optimized versions that knows they are hashing exactly ++ * 3, 2 or 1 word(s). ++ * ++ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally ++ * done at the end is not done here. ++ */ ++static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) ++{ ++ a += JHASH_GOLDEN_RATIO; ++ b += JHASH_GOLDEN_RATIO; ++ c += initval; ++ ++ __jhash_mix(a, b, c); ++ ++ return c; ++} ++ ++static inline u32 jhash_2words(u32 a, u32 b, u32 initval) ++{ ++ return jhash_3words(a, b, 0, initval); ++} ++ ++static inline u32 jhash_1word(u32 a, u32 initval) ++{ ++ return jhash_3words(a, 0, 0, initval); ++} ++ ++#endif /* _LINUX_JHASH_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter.h linux-2.4.20/include/linux/netfilter.h +--- linux-2.4.20.org/include/linux/netfilter.h Thu Nov 22 19:47:48 2001 ++++ linux-2.4.20/include/linux/netfilter.h Wed Sep 24 09:18:12 2003 +@@ -19,9 +19,11 @@ + #define NF_REPEAT 4 + #define NF_MAX_VERDICT NF_REPEAT + +-/* Generic cache responses from hook functions. */ +-#define NFC_ALTERED 0x8000 ++/* Generic cache responses from hook functions. ++ <= 0x2000 is used for protocol-flags. */ + #define NFC_UNKNOWN 0x4000 ++#define NFC_ALTERED 0x8000 ++#define NFC_TRACE 0x10000 + + #ifdef __KERNEL__ + #include +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_arp/arpt_mangle.h linux-2.4.20/include/linux/netfilter_arp/arpt_mangle.h +--- linux-2.4.20.org/include/linux/netfilter_arp/arpt_mangle.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_arp/arpt_mangle.h Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,26 @@ ++#ifndef _ARPT_MANGLE_H ++#define _ARPT_MANGLE_H ++#include ++ ++#define ARPT_MANGLE_ADDR_LEN_MAX sizeof(struct in_addr) ++struct arpt_mangle ++{ ++ char src_devaddr[ARPT_DEV_ADDR_LEN_MAX]; ++ char tgt_devaddr[ARPT_DEV_ADDR_LEN_MAX]; ++ union { ++ struct in_addr src_ip; ++ } u_s; ++ union { ++ struct in_addr tgt_ip; ++ } u_t; ++ u_int8_t flags; ++ int target; ++}; ++ ++#define ARPT_MANGLE_SDEV 0x01 ++#define ARPT_MANGLE_TDEV 0x02 ++#define ARPT_MANGLE_SIP 0x04 ++#define ARPT_MANGLE_TIP 0x08 ++#define ARPT_MANGLE_MASK 0x0f ++ ++#endif /* _ARPT_MANGLE_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h Wed Sep 24 09:18:16 2003 +@@ -6,6 +6,7 @@ + + #include + #include ++#include + #include + + enum ip_conntrack_info +@@ -41,29 +42,50 @@ + /* Conntrack should never be early-expired. */ + IPS_ASSURED_BIT = 2, + IPS_ASSURED = (1 << IPS_ASSURED_BIT), ++ ++ /* Connection is confirmed: originating packet has left box */ ++ IPS_CONFIRMED_BIT = 3, ++ IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT), + }; + + #include + #include ++#include + + /* per conntrack: protocol private data */ + union ip_conntrack_proto { + /* insert conntrack proto private data here */ ++ struct ip_ct_gre gre; + struct ip_ct_tcp tcp; + struct ip_ct_icmp icmp; + }; + + union ip_conntrack_expect_proto { + /* insert expect proto private data here */ ++ struct ip_ct_gre_expect gre; + }; + + /* Add protocol helper include file here */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ + #include + #include + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { + /* insert conntrack helper private data (expect) here */ ++ struct ip_ct_talk_expect exp_talk_info; ++ struct ip_ct_rsh_expect exp_rsh_info; ++ struct ip_ct_pptp_expect exp_pptp_info; ++ struct ip_ct_mms_expect exp_mms_info; ++ struct ip_ct_h225_expect exp_h225_info; ++ struct ip_ct_amanda_expect exp_amanda_info; + struct ip_ct_ftp_expect exp_ftp_info; + struct ip_ct_irc_expect exp_irc_info; + +@@ -77,16 +99,23 @@ + /* per conntrack: application helper private data */ + union ip_conntrack_help { + /* insert conntrack helper private data (master) here */ ++ struct ip_ct_talk_master ct_talk_info; ++ struct ip_ct_rsh_master ct_rsh_info; ++ struct ip_ct_pptp_master ct_pptp_info; ++ struct ip_ct_mms_master ct_mms_info; ++ struct ip_ct_h225_master ct_h225_info; + struct ip_ct_ftp_master ct_ftp_info; + struct ip_ct_irc_master ct_irc_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + #include ++#include + + /* per conntrack: nat application helper private data */ + union ip_conntrack_nat_help { + /* insert nat helper private data here */ ++ struct ip_nat_pptp nat_pptp_info; + }; + #endif + +@@ -159,7 +188,7 @@ + struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; + + /* Have we seen traffic both ways yet? (bitset) */ +- volatile unsigned long status; ++ unsigned long status; + + /* Timer function; drops refcnt when it goes off. */ + struct timer_list timeout; +@@ -198,6 +227,9 @@ + } nat; + #endif /* CONFIG_IP_NF_NAT_NEEDED */ + ++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) ++ unsigned long mark; ++#endif + }; + + /* get master conntrack via master expectation */ +@@ -238,6 +270,9 @@ + extern void ip_ct_refresh(struct ip_conntrack *ct, + unsigned long extra_jiffies); + ++/* Kill conntrack */ ++extern void ip_ct_death_by_timeout(unsigned long ul_conntrack); ++ + /* These are for NAT. Icky. */ + /* Call me when a conntrack is destroyed. */ + extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); +@@ -254,9 +289,12 @@ + /* It's confirmed if it is, or has been in the hash table. */ + static inline int is_confirmed(struct ip_conntrack *ct) + { +- return ct->tuplehash[IP_CT_DIR_ORIGINAL].list.next != NULL; ++ return test_bit(IPS_CONFIRMED_BIT, &ct->status); + } + + extern unsigned int ip_conntrack_htable_size; ++ ++/* A fake conntrack entry which never vanishes. */ ++extern struct ip_conntrack ip_conntrack_untracked; + #endif /* __KERNEL__ */ + #endif /* _IP_CONNTRACK_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_amanda.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_amanda.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_amanda.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_amanda.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,29 @@ ++#ifndef _IP_CONNTRACK_AMANDA_H ++#define _IP_CONNTRACK_AMANDA_H ++/* AMANDA tracking. */ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* Protects amanda part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_amanda_lock); ++ ++#endif ++ ++struct conn { ++ char* match; ++ int matchlen; ++}; ++ ++#define NUM_MSGS 3 ++ ++ ++struct ip_ct_amanda_expect ++{ ++ u_int16_t port; /* port number of this expectation */ ++ u_int16_t offset; /* offset of the port specification in ctrl packet */ ++ u_int16_t len; /* the length of the port number specification */ ++}; ++ ++#endif /* _IP_CONNTRACK_AMANDA_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_core.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_core.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_core.h Wed Sep 24 09:16:17 2003 +@@ -1,5 +1,6 @@ + #ifndef _IP_CONNTRACK_CORE_H + #define _IP_CONNTRACK_CORE_H ++#include + #include + + /* This header is used to share core functionality between the +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h Wed Sep 24 09:17:38 2003 +@@ -0,0 +1,70 @@ ++#ifndef _IP_CT_CUSEEME ++#define _IP_CT_CUSEEME ++ ++#define CUSEEME_PORT 7648 ++ ++/* These structs come from the 2.2 ip_masq_cuseeme code... */ ++ ++#pragma pack(1) ++/* CuSeeMe data header */ ++struct cu_header { ++ u_int16_t dest_family; ++ u_int16_t dest_port; ++ u_int32_t dest_addr; ++ int16_t family; ++ u_int16_t port; ++ u_int32_t addr; ++ u_int32_t seq; ++ u_int16_t msg; ++ u_int16_t data_type; ++ /* possible values: ++ * 1 small video ++ * 2 big video ++ * 3 audio ++ * 100 acknowledge connectivity when there ++ * is nothing else to send ++ * 101 OpenContinue packet ++ * 104 display a text message and ++ * disconnect (used by reflector to ++ * kick clients off) ++ * 105 display a text message (welcome ++ * message from reflector) ++ * 106 exchanged among reflectors for ++ * reflector interoperation ++ * 107 carry aux stream data when there is ++ * no video to piggy-back on ++ * 108 obsolete (used in Mac alpha version) ++ * 109 obsolete (used in Mac alpha version) ++ * 110 used for data rate control ++ * 111 used for data rate control ++ * 256 aux data control messages ++ * 257 aux data packets ++ * */ ++ u_int16_t packet_len; ++}; ++ ++/* Open Continue Header */ ++struct oc_header { ++ struct cu_header cu_head; ++ u_int16_t client_count; /* Number of client info structs */ ++ u_int32_t seq_no; ++ char user_name[20]; ++ char stuff[4]; /* Flags, version stuff, etc */ ++}; ++ ++/* Client info structures */ ++struct client_info { ++ u_int32_t address; /* Client address */ ++ char stuff[8]; /* Flags, pruning bitfield, packet counts, etc */ ++}; ++#pragma pack() ++ ++/* This structure is per expected connection */ ++struct ip_ct_cuseeme_expect { ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_cuseeme_master { ++}; ++ ++#endif /* _IP_CT_CUSEEME */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_h323.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_h323.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_h323.h Wed Sep 24 09:17:43 2003 +@@ -0,0 +1,30 @@ ++#ifndef _IP_CONNTRACK_H323_H ++#define _IP_CONNTRACK_H323_H ++/* H.323 connection tracking. */ ++ ++#ifdef __KERNEL__ ++/* Protects H.323 related data */ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++#endif ++ ++/* Default H.225 port */ ++#define H225_PORT 1720 ++ ++/* This structure is per expected connection */ ++struct ip_ct_h225_expect { ++ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ unsigned int offset; /* offset of the address in the payload */ ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_h225_master { ++ int is_h225; /* H.225 or H.245 connection */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ ++ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ ++#endif ++}; ++ ++#endif /* _IP_CONNTRACK_H323_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_mms.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_mms.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_mms.h Wed Sep 24 09:17:48 2003 +@@ -0,0 +1,31 @@ ++#ifndef _IP_CONNTRACK_MMS_H ++#define _IP_CONNTRACK_MMS_H ++/* MMS tracking. */ ++ ++#ifdef __KERNEL__ ++#include ++ ++DECLARE_LOCK_EXTERN(ip_mms_lock); ++ ++#define MMS_PORT 1755 ++#define MMS_SRV_MSG_ID 196610 ++ ++#define MMS_SRV_MSG_OFFSET 36 ++#define MMS_SRV_UNICODE_STRING_OFFSET 60 ++#define MMS_SRV_CHUNKLENLV_OFFSET 16 ++#define MMS_SRV_CHUNKLENLM_OFFSET 32 ++#define MMS_SRV_MESSAGELENGTH_OFFSET 8 ++#endif ++ ++/* This structure is per expected connection */ ++struct ip_ct_mms_expect { ++ u_int32_t len; ++ u_int32_t padding; ++ u_int16_t port; ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_mms_master { ++}; ++ ++#endif /* _IP_CONNTRACK_MMS_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_pptp.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_pptp.h Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,313 @@ ++/* PPTP constants and structs */ ++#ifndef _CONNTRACK_PPTP_H ++#define _CONNTRACK_PPTP_H ++ ++/* state of the control session */ ++enum pptp_ctrlsess_state { ++ PPTP_SESSION_NONE, /* no session present */ ++ PPTP_SESSION_ERROR, /* some session error */ ++ PPTP_SESSION_STOPREQ, /* stop_sess request seen */ ++ PPTP_SESSION_REQUESTED, /* start_sess request seen */ ++ PPTP_SESSION_CONFIRMED, /* session established */ ++}; ++ ++/* state of the call inside the control session */ ++enum pptp_ctrlcall_state { ++ PPTP_CALL_NONE, ++ PPTP_CALL_ERROR, ++ PPTP_CALL_OUT_REQ, ++ PPTP_CALL_OUT_CONF, ++ PPTP_CALL_IN_REQ, ++ PPTP_CALL_IN_REP, ++ PPTP_CALL_IN_CONF, ++ PPTP_CALL_CLEAR_REQ, ++}; ++ ++ ++/* conntrack private data */ ++struct ip_ct_pptp_master { ++ enum pptp_ctrlsess_state sstate; /* session state */ ++ ++ /* everything below is going to be per-expectation in newnat, ++ * since there could be more than one call within one session */ ++ enum pptp_ctrlcall_state cstate; /* call state */ ++ u_int16_t pac_call_id; /* call id of PAC, host byte order */ ++ u_int16_t pns_call_id; /* call id of PNS, host byte order */ ++}; ++ ++/* conntrack_expect private member */ ++struct ip_ct_pptp_expect { ++ enum pptp_ctrlcall_state cstate; /* call state */ ++ u_int16_t pac_call_id; /* call id of PAC */ ++ u_int16_t pns_call_id; /* call id of PNS */ ++}; ++ ++ ++#ifdef __KERNEL__ ++ ++#include ++DECLARE_LOCK_EXTERN(ip_pptp_lock); ++ ++#define IP_CONNTR_PPTP PPTP_CONTROL_PORT ++ ++union pptp_ctrl_union { ++ void *rawreq; ++ struct PptpStartSessionRequest *sreq; ++ struct PptpStartSessionReply *srep; ++ struct PptpStopSessionReqest *streq; ++ struct PptpStopSessionReply *strep; ++ struct PptpOutCallRequest *ocreq; ++ struct PptpOutCallReply *ocack; ++ struct PptpInCallRequest *icreq; ++ struct PptpInCallReply *icack; ++ struct PptpInCallConnected *iccon; ++ struct PptpClearCallRequest *clrreq; ++ struct PptpCallDisconnectNotify *disc; ++ struct PptpWanErrorNotify *wanerr; ++ struct PptpSetLinkInfo *setlink; ++}; ++ ++ ++ ++#define PPTP_CONTROL_PORT 1723 ++ ++#define PPTP_PACKET_CONTROL 1 ++#define PPTP_PACKET_MGMT 2 ++ ++#define PPTP_MAGIC_COOKIE 0x1a2b3c4d ++ ++struct pptp_pkt_hdr { ++ __u16 packetLength; ++ __u16 packetType; ++ __u32 magicCookie; ++}; ++ ++/* PptpControlMessageType values */ ++#define PPTP_START_SESSION_REQUEST 1 ++#define PPTP_START_SESSION_REPLY 2 ++#define PPTP_STOP_SESSION_REQUEST 3 ++#define PPTP_STOP_SESSION_REPLY 4 ++#define PPTP_ECHO_REQUEST 5 ++#define PPTP_ECHO_REPLY 6 ++#define PPTP_OUT_CALL_REQUEST 7 ++#define PPTP_OUT_CALL_REPLY 8 ++#define PPTP_IN_CALL_REQUEST 9 ++#define PPTP_IN_CALL_REPLY 10 ++#define PPTP_IN_CALL_CONNECT 11 ++#define PPTP_CALL_CLEAR_REQUEST 12 ++#define PPTP_CALL_DISCONNECT_NOTIFY 13 ++#define PPTP_WAN_ERROR_NOTIFY 14 ++#define PPTP_SET_LINK_INFO 15 ++ ++#define PPTP_MSG_MAX 15 ++ ++/* PptpGeneralError values */ ++#define PPTP_ERROR_CODE_NONE 0 ++#define PPTP_NOT_CONNECTED 1 ++#define PPTP_BAD_FORMAT 2 ++#define PPTP_BAD_VALUE 3 ++#define PPTP_NO_RESOURCE 4 ++#define PPTP_BAD_CALLID 5 ++#define PPTP_REMOVE_DEVICE_ERROR 6 ++ ++struct PptpControlHeader { ++ __u16 messageType; ++ __u16 reserved; ++}; ++ ++/* FramingCapability Bitmap Values */ ++#define PPTP_FRAME_CAP_ASYNC 0x1 ++#define PPTP_FRAME_CAP_SYNC 0x2 ++ ++/* BearerCapability Bitmap Values */ ++#define PPTP_BEARER_CAP_ANALOG 0x1 ++#define PPTP_BEARER_CAP_DIGITAL 0x2 ++ ++struct PptpStartSessionRequest { ++ __u16 protocolVersion; ++ __u8 reserved1; ++ __u8 reserved2; ++ __u32 framingCapability; ++ __u32 bearerCapability; ++ __u16 maxChannels; ++ __u16 firmwareRevision; ++ __u8 hostName[64]; ++ __u8 vendorString[64]; ++}; ++ ++/* PptpStartSessionResultCode Values */ ++#define PPTP_START_OK 1 ++#define PPTP_START_GENERAL_ERROR 2 ++#define PPTP_START_ALREADY_CONNECTED 3 ++#define PPTP_START_NOT_AUTHORIZED 4 ++#define PPTP_START_UNKNOWN_PROTOCOL 5 ++ ++struct PptpStartSessionReply { ++ __u16 protocolVersion; ++ __u8 resultCode; ++ __u8 generalErrorCode; ++ __u32 framingCapability; ++ __u32 bearerCapability; ++ __u16 maxChannels; ++ __u16 firmwareRevision; ++ __u8 hostName[64]; ++ __u8 vendorString[64]; ++}; ++ ++/* PptpStopReasons */ ++#define PPTP_STOP_NONE 1 ++#define PPTP_STOP_PROTOCOL 2 ++#define PPTP_STOP_LOCAL_SHUTDOWN 3 ++ ++struct PptpStopSessionRequest { ++ __u8 reason; ++}; ++ ++/* PptpStopSessionResultCode */ ++#define PPTP_STOP_OK 1 ++#define PPTP_STOP_GENERAL_ERROR 2 ++ ++struct PptpStopSessionReply { ++ __u8 resultCode; ++ __u8 generalErrorCode; ++}; ++ ++struct PptpEchoRequest { ++ __u32 identNumber; ++}; ++ ++/* PptpEchoReplyResultCode */ ++#define PPTP_ECHO_OK 1 ++#define PPTP_ECHO_GENERAL_ERROR 2 ++ ++struct PptpEchoReply { ++ __u32 identNumber; ++ __u8 resultCode; ++ __u8 generalErrorCode; ++ __u16 reserved; ++}; ++ ++/* PptpFramingType */ ++#define PPTP_ASYNC_FRAMING 1 ++#define PPTP_SYNC_FRAMING 2 ++#define PPTP_DONT_CARE_FRAMING 3 ++ ++/* PptpCallBearerType */ ++#define PPTP_ANALOG_TYPE 1 ++#define PPTP_DIGITAL_TYPE 2 ++#define PPTP_DONT_CARE_BEARER_TYPE 3 ++ ++struct PptpOutCallRequest { ++ __u16 callID; ++ __u16 callSerialNumber; ++ __u32 minBPS; ++ __u32 maxBPS; ++ __u32 bearerType; ++ __u32 framingType; ++ __u16 packetWindow; ++ __u16 packetProcDelay; ++ __u16 reserved1; ++ __u16 phoneNumberLength; ++ __u16 reserved2; ++ __u8 phoneNumber[64]; ++ __u8 subAddress[64]; ++}; ++ ++/* PptpCallResultCode */ ++#define PPTP_OUTCALL_CONNECT 1 ++#define PPTP_OUTCALL_GENERAL_ERROR 2 ++#define PPTP_OUTCALL_NO_CARRIER 3 ++#define PPTP_OUTCALL_BUSY 4 ++#define PPTP_OUTCALL_NO_DIAL_TONE 5 ++#define PPTP_OUTCALL_TIMEOUT 6 ++#define PPTP_OUTCALL_DONT_ACCEPT 7 ++ ++struct PptpOutCallReply { ++ __u16 callID; ++ __u16 peersCallID; ++ __u8 resultCode; ++ __u8 generalErrorCode; ++ __u16 causeCode; ++ __u32 connectSpeed; ++ __u16 packetWindow; ++ __u16 packetProcDelay; ++ __u32 physChannelID; ++}; ++ ++struct PptpInCallRequest { ++ __u16 callID; ++ __u16 callSerialNumber; ++ __u32 callBearerType; ++ __u32 physChannelID; ++ __u16 dialedNumberLength; ++ __u16 dialingNumberLength; ++ __u8 dialedNumber[64]; ++ __u8 dialingNumber[64]; ++ __u8 subAddress[64]; ++}; ++ ++/* PptpInCallResultCode */ ++#define PPTP_INCALL_ACCEPT 1 ++#define PPTP_INCALL_GENERAL_ERROR 2 ++#define PPTP_INCALL_DONT_ACCEPT 3 ++ ++struct PptpInCallReply { ++ __u16 callID; ++ __u16 peersCallID; ++ __u8 resultCode; ++ __u8 generalErrorCode; ++ __u16 packetWindow; ++ __u16 packetProcDelay; ++ __u16 reserved; ++}; ++ ++struct PptpInCallConnected { ++ __u16 peersCallID; ++ __u16 reserved; ++ __u32 connectSpeed; ++ __u16 packetWindow; ++ __u16 packetProcDelay; ++ __u32 callFramingType; ++}; ++ ++struct PptpClearCallRequest { ++ __u16 callID; ++ __u16 reserved; ++}; ++ ++struct PptpCallDisconnectNotify { ++ __u16 callID; ++ __u8 resultCode; ++ __u8 generalErrorCode; ++ __u16 causeCode; ++ __u16 reserved; ++ __u8 callStatistics[128]; ++}; ++ ++struct PptpWanErrorNotify { ++ __u16 peersCallID; ++ __u16 reserved; ++ __u32 crcErrors; ++ __u32 framingErrors; ++ __u32 hardwareOverRuns; ++ __u32 bufferOverRuns; ++ __u32 timeoutErrors; ++ __u32 alignmentErrors; ++}; ++ ++struct PptpSetLinkInfo { ++ __u16 peersCallID; ++ __u16 reserved; ++ __u32 sendAccm; ++ __u32 recvAccm; ++}; ++ ++ ++struct pptp_priv_data { ++ __u16 call_id; ++ __u16 mcall_id; ++ __u16 pcall_id; ++}; ++ ++#endif /* __KERNEL__ */ ++#endif /* _CONNTRACK_PPTP_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,123 @@ ++#ifndef _CONNTRACK_PROTO_GRE_H ++#define _CONNTRACK_PROTO_GRE_H ++#include ++ ++/* GRE PROTOCOL HEADER */ ++ ++/* GRE Version field */ ++#define GRE_VERSION_1701 0x0 ++#define GRE_VERSION_PPTP 0x1 ++ ++/* GRE Protocol field */ ++#define GRE_PROTOCOL_PPTP 0x880B ++ ++/* GRE Flags */ ++#define GRE_FLAG_C 0x80 ++#define GRE_FLAG_R 0x40 ++#define GRE_FLAG_K 0x20 ++#define GRE_FLAG_S 0x10 ++#define GRE_FLAG_A 0x80 ++ ++#define GRE_IS_C(f) ((f)&GRE_FLAG_C) ++#define GRE_IS_R(f) ((f)&GRE_FLAG_R) ++#define GRE_IS_K(f) ((f)&GRE_FLAG_K) ++#define GRE_IS_S(f) ((f)&GRE_FLAG_S) ++#define GRE_IS_A(f) ((f)&GRE_FLAG_A) ++ ++/* GRE is a mess: Four different standards */ ++struct gre_hdr { ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++ __u16 rec:3, ++ srr:1, ++ seq:1, ++ key:1, ++ routing:1, ++ csum:1, ++ version:3, ++ reserved:4, ++ ack:1; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++ __u16 csum:1, ++ routing:1, ++ key:1, ++ seq:1, ++ srr:1, ++ rec:3, ++ ack:1, ++ reserved:4, ++ version:3; ++#else ++#error "Adjust your defines" ++#endif ++ __u16 protocol; ++}; ++ ++/* modified GRE header for PPTP */ ++struct gre_hdr_pptp { ++ __u8 flags; /* bitfield */ ++ __u8 version; /* should be GRE_VERSION_PPTP */ ++ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ ++ __u16 payload_len; /* size of ppp payload, not inc. gre header */ ++ __u16 call_id; /* peer's call_id for this session */ ++ __u32 seq; /* sequence number. Present if S==1 */ ++ __u32 ack; /* seq number of highest packet recieved by */ ++ /* sender in this session */ ++}; ++ ++ ++/* this is part of ip_conntrack */ ++struct ip_ct_gre { ++ unsigned int stream_timeout; ++ unsigned int timeout; ++}; ++ ++/* this is part of ip_conntrack_expect */ ++struct ip_ct_gre_expect { ++ struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; ++}; ++ ++#ifdef __KERNEL__ ++struct ip_conntrack_expect; ++ ++/* structure for original <-> reply keymap */ ++struct ip_ct_gre_keymap { ++ struct list_head list; ++ ++ struct ip_conntrack_tuple tuple; ++}; ++ ++ ++/* add new tuple->key_reply pair to keymap */ ++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, ++ struct ip_conntrack_tuple *t, ++ int reply); ++ ++/* change an existing keymap entry */ ++void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, ++ struct ip_conntrack_tuple *t); ++ ++/* delete keymap entries */ ++void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp); ++ ++ ++/* get pointer to gre key, if present */ ++static inline u_int32_t *gre_key(struct gre_hdr *greh) ++{ ++ if (!greh->key) ++ return NULL; ++ if (greh->csum || greh->routing) ++ return (u_int32_t *) (greh+sizeof(*greh)+4); ++ return (u_int32_t *) (greh+sizeof(*greh)); ++} ++ ++/* get pointer ot gre csum, if present */ ++static inline u_int16_t *gre_csum(struct gre_hdr *greh) ++{ ++ if (!greh->csum) ++ return NULL; ++ return (u_int16_t *) (greh+sizeof(*greh)); ++} ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _CONNTRACK_PROTO_GRE_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_protocol.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Wed Sep 24 09:18:12 2003 +@@ -57,6 +57,12 @@ + extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto); + extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto); + ++/* Get the tuple from the packet and return 1 if it's succeeded. */ ++extern int ++ip_conntrack_get_tuple(const struct iphdr *iph, size_t len, ++ struct ip_conntrack_tuple *tuple, ++ struct ip_conntrack_protocol *protocol); ++ + /* Existing built-in protocols */ + extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp; + extern struct ip_conntrack_protocol ip_conntrack_protocol_udp; +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_quake3.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_quake3.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_quake3.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_quake3.h Wed Sep 24 09:17:58 2003 +@@ -0,0 +1,21 @@ ++#ifndef _IP_CT_QUAKE3 ++#define _IP_CT_QUAKE3 ++ ++/* Don't confuse with 27960, often used as the Server Port */ ++#define QUAKE3_MASTER_PORT 27950 ++ ++struct quake3_search { ++ const char marker[4]; /* always 0xff 0xff 0xff 0xff ? */ ++ const char *pattern; ++ size_t plen; ++}; ++ ++/* This structure is per expected connection */ ++struct ip_ct_quake3_expect { ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_quake3_master { ++}; ++ ++#endif /* _IP_CT_QUAKE3 */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_rpc.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_rpc.h Wed Sep 24 09:18:01 2003 +@@ -0,0 +1,68 @@ ++/* RPC extension for IP connection tracking, Version 2.2 ++ * (C) 2000 by Marcelo Barbosa Lima ++ * - original rpc tracking module ++ * - "recent" connection handling for kernel 2.3+ netfilter ++ * ++ * (C) 2001 by Rusty Russell ++ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ ++ * ++ * (C) 2002 by Ian (Larry) Latter ++ * - upgraded conntrack modules to newnat api - kernel 2.4.20+ ++ * - extended matching to support filtering on procedures ++ * ++ * ip_conntrack_rpc.h,v 2.2 2003/01/12 18:30:00 ++ * ++ * 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. ++ ** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef _IP_CONNTRACK_RPC_H ++#define _IP_CONNTRACK_RPC_H ++ ++#define RPC_PORT 111 ++ ++ ++/* Datum in RPC packets are encoded in XDR */ ++#define IXDR_GET_INT32(buf) ((u_int32_t) ntohl((uint32_t)*buf)) ++ ++/* Fast timeout, to deny DoS atacks */ ++#define EXP (60 * HZ) ++ ++/* Normal timeouts */ ++#define EXPIRES (180 * HZ) ++ ++/* For future conections RPC, using client's cache bindings ++ * I'll use ip_conntrack_lock to lock these lists */ ++ ++/* This identifies each request and stores protocol */ ++struct request_p { ++ struct list_head list; ++ ++ u_int32_t xid; ++ u_int32_t ip; ++ u_int16_t port; ++ ++ /* Protocol */ ++ u_int16_t proto; ++ ++ struct timer_list timeout; ++}; ++ ++static inline int request_p_cmp(const struct request_p *p, u_int32_t xid, ++ u_int32_t ip, u_int32_t port) { ++ return (p->xid == xid && p->ip == ip && p->port); ++ ++} ++ ++#endif /* _IP_CONNTRACK_RPC_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_rsh.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_rsh.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_rsh.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_rsh.h Wed Sep 24 09:18:03 2003 +@@ -0,0 +1,35 @@ ++/* RSH extension for IP connection tracking, Version 1.0 ++ * (C) 2002 by Ian (Larry) Latter ++ * based on HW's ip_conntrack_irc.c ++ * ++ * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26 ++ * ++ * 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. ++ */ ++#ifndef _IP_CONNTRACK_RSH_H ++#define _IP_CONNTRACK_RSH_H ++ ++#ifdef __KERNEL__ ++#include ++ ++DECLARE_LOCK_EXTERN(ip_rsh_lock); ++#endif ++ ++ ++#define RSH_PORT 514 ++ ++/* This structure is per expected connection */ ++struct ip_ct_rsh_expect ++{ ++ u_int16_t port; ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_rsh_master { ++}; ++ ++#endif /* _IP_CONNTRACK_RSH_H */ ++ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_talk.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_talk.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_talk.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_talk.h Wed Sep 24 09:18:08 2003 +@@ -0,0 +1,152 @@ ++#ifndef _IP_CONNTRACK_TALK_H ++#define _IP_CONNTRACK_TALK_H ++/* TALK tracking. */ ++ ++#ifdef __KERNEL__ ++#include ++#include ++ ++/* Protects talk part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_talk_lock); ++#endif ++ ++ ++#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 TALK_OLD_NSIZE 9 ++#define TALK_NSIZE 12 ++#define TALK_TTY_NSIZE 16 ++ ++/* ++ * Client->server request message formats. ++ */ ++struct talk_msg { ++ u_char type; /* request type, see below */ ++ char l_name[TALK_OLD_NSIZE];/* caller's name */ ++ char r_name[TALK_OLD_NSIZE];/* callee's name */ ++ u_char pad; ++ u_int32_t id_num; /* message id */ ++ int32_t pid; /* caller's process id */ ++ char r_tty[TALK_TTY_NSIZE];/* 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[TALK_NSIZE];/* caller's name */ ++ char r_name[TALK_NSIZE];/* callee's name */ ++ char r_tty[TALK_TTY_NSIZE];/* 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[TALK_NSIZE]; /* caller's name */ ++ char r_name[TALK_NSIZE]; /* callee's name */ ++ char r_tty[TALK_TTY_NSIZE]; /* 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[TALK_NSIZE]; /* 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_expect ++{ ++ /* Port that was to be used */ ++ u_int16_t port; ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_talk_master ++{ ++}; ++ ++#endif /* _IP_CONNTRACK_TALK_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_tftp.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_tftp.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_tftp.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_tftp.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,13 @@ ++#ifndef _IP_CT_TFTP ++#define _IP_CT_TFTP ++ ++#define TFTP_PORT 69 ++ ++struct tftphdr { ++ u_int16_t opcode; ++}; ++ ++#define TFTP_OPCODE_READ 1 ++#define TFTP_OPCODE_WRITE 2 ++ ++#endif /* _IP_CT_TFTP */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h Mon Feb 25 19:38:13 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_tuple.h Wed Sep 24 09:17:55 2003 +@@ -14,7 +14,7 @@ + union ip_conntrack_manip_proto + { + /* Add other protocols here. */ +- u_int16_t all; ++ u_int32_t all; + + struct { + u_int16_t port; +@@ -25,6 +25,9 @@ + struct { + u_int16_t id; + } icmp; ++ struct { ++ u_int32_t key; ++ } gre; + }; + + /* The manipulable part of the tuple. */ +@@ -44,7 +47,7 @@ + u_int32_t ip; + union { + /* Add other protocols here. */ +- u_int16_t all; ++ u_int64_t all; + + struct { + u_int16_t port; +@@ -55,6 +58,11 @@ + struct { + u_int8_t type, code; + } icmp; ++ struct { ++ u_int16_t protocol; ++ u_int8_t version; ++ u_int32_t key; ++ } gre; + } u; + + /* The protocol. */ +@@ -62,6 +70,14 @@ + } dst; + }; + ++/* This is optimized opposed to a memset of the whole structure. Everything we ++ * really care about is the source/destination unions */ ++#define IP_CT_TUPLE_BLANK(tuple) \ ++ do { \ ++ (tuple)->src.u.all = 0; \ ++ (tuple)->dst.u.all = 0; \ ++ } while (0) ++ + enum ip_conntrack_dir + { + IP_CT_DIR_ORIGINAL, +@@ -72,10 +88,16 @@ + #ifdef __KERNEL__ + + #define DUMP_TUPLE(tp) \ +-DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ ++DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \ + (tp), (tp)->dst.protonum, \ +- NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ +- NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) ++ NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \ ++ NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all)) ++ ++#define DUMP_TUPLE_RAW(x) \ ++ DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\ ++ (x), (x)->dst.protonum, \ ++ NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \ ++ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all)) + + #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) + +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_logging.h linux-2.4.20/include/linux/netfilter_ipv4/ip_logging.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_logging.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_logging.h Wed Sep 24 09:16:23 2003 +@@ -0,0 +1,20 @@ ++/* IPv4 macros for the internal logging interface. */ ++#ifndef __IP_LOGGING_H ++#define __IP_LOGGING_H ++ ++#ifdef __KERNEL__ ++#include ++#include ++ ++#define nf_log_ip_packet(pskb,hooknum,in,out,fmt,args...) \ ++ nf_log_packet(AF_INET,pskb,hooknum,in,out,fmt,##args) ++ ++#define nf_log_ip(pfh,len,fmt,args...) \ ++ nf_log(AF_INET,pfh,len,fmt,##args) ++ ++#define nf_ip_log_register(logging) nf_log_register(AF_INET,logging) ++#define nf_ip_log_unregister(logging) nf_log_unregister(AF_INET,logging) ++ ++#endif /*__KERNEL__*/ ++ ++#endif /*__IP_LOGGING_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_helper.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_nat_helper.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_helper.h Wed Sep 24 09:16:14 2003 +@@ -50,6 +50,13 @@ + unsigned int match_len, + char *rep_buffer, + unsigned int rep_len); ++extern int ip_nat_mangle_udp_packet(struct sk_buff **skb, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ unsigned int match_offset, ++ unsigned int match_len, ++ char *rep_buffer, ++ unsigned int rep_len); + extern int ip_nat_seq_adjust(struct sk_buff *skb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo); +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_pptp.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_nat_pptp.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_pptp.h Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,11 @@ ++/* PPTP constants and structs */ ++#ifndef _NAT_PPTP_H ++#define _NAT_PPTP_H ++ ++/* conntrack private data */ ++struct ip_nat_pptp { ++ u_int16_t pns_call_id; /* NAT'ed PNS call id */ ++ u_int16_t pac_call_id; /* NAT'ed PAC call id */ ++}; ++ ++#endif /* _NAT_PPTP_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_nat_rule.h linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_rule.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_nat_rule.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_rule.h Wed Sep 24 09:16:27 2003 +@@ -14,5 +14,10 @@ + const struct net_device *out, + struct ip_conntrack *ct, + struct ip_nat_info *info); ++ ++extern unsigned int ++alloc_null_binding(struct ip_conntrack *conntrack, ++ struct ip_nat_info *info, ++ unsigned int hooknum); + #endif + #endif /* _IP_NAT_RULE_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ip_pool.h linux-2.4.20/include/linux/netfilter_ipv4/ip_pool.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ip_pool.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ip_pool.h Wed Sep 24 09:16:59 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_CLASSIFY.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_CLASSIFY.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_CLASSIFY.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_CLASSIFY.h Wed Sep 24 09:17:14 2003 +@@ -0,0 +1,8 @@ ++#ifndef _IPT_CLASSIFY_H ++#define _IPT_CLASSIFY_H ++ ++struct ipt_classify_target_info { ++ u_int32_t priority; ++}; ++ ++#endif /*_IPT_CLASSIFY_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_CONNMARK.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_CONNMARK.h Wed Sep 24 09:17:17 2003 +@@ -0,0 +1,15 @@ ++#ifndef _IPT_CONNMARK_H_target ++#define _IPT_CONNMARK_H_target ++ ++enum { ++ IPT_CONNMARK_SET = 0, ++ IPT_CONNMARK_SAVE, ++ IPT_CONNMARK_RESTORE ++}; ++ ++struct ipt_connmark_target_info { ++ unsigned long mark; ++ u_int8_t mode; ++}; ++ ++#endif /*_IPT_CONNMARK_H_target*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_IMQ.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_IMQ.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_IMQ.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_IMQ.h Wed Sep 24 09:17:19 2003 +@@ -0,0 +1,8 @@ ++#ifndef _IPT_IMQ_H ++#define _IPT_IMQ_H ++ ++struct ipt_imq_info { ++ unsigned int todev; /* target imq device */ ++}; ++ ++#endif /* _IPT_IMQ_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_IPMARK.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_IPMARK.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_IPMARK.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_IPMARK.h Wed Sep 24 09:17:23 2003 +@@ -0,0 +1,13 @@ ++#ifndef _IPT_IPMARK_H_target ++#define _IPT_IPMARK_H_target ++ ++struct ipt_ipmark_target_info { ++ unsigned long andmask; ++ unsigned long ormask; ++ unsigned int addr; ++}; ++ ++#define IPT_IPMARK_SRC 0 ++#define IPT_IPMARK_DST 1 ++ ++#endif /*_IPT_IPMARK_H_target*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_NETLINK.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_NETLINK.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_NETLINK.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_NETLINK.h Wed Sep 24 09:16:32 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_REJECT.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_REJECT.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_REJECT.h Fri Jul 14 19:20:23 2000 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_REJECT.h Wed Sep 24 09:18:09 2003 +@@ -9,11 +9,13 @@ + IPT_ICMP_ECHOREPLY, + IPT_ICMP_NET_PROHIBITED, + IPT_ICMP_HOST_PROHIBITED, +- IPT_TCP_RESET ++ IPT_TCP_RESET, ++ IPT_ICMP_ADMIN_PROHIBITED + }; + + struct ipt_reject_info { + enum ipt_reject_with with; /* reject type */ ++ u_int8_t fake_source_address; /* 1: fake src addr with original packet dest, 0: no fake */ + }; + +-#endif /*_IPT_REJECT_H*/ ++#endif /* _IPT_REJECT_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_ROUTE.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_ROUTE.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_ROUTE.h Wed Sep 24 09:17:25 2003 +@@ -0,0 +1,22 @@ ++/* Header file for iptables ipt_ROUTE target ++ * ++ * (C) 2002 by Cédric de Launois ++ * ++ * This software is distributed under GNU GPL v2, 1991 ++ */ ++#ifndef _IPT_ROUTE_H_target ++#define _IPT_ROUTE_H_target ++ ++#define IPT_ROUTE_IFNAMSIZ 16 ++ ++struct ipt_route_target_info { ++ char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */ ++ char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */ ++ u_int32_t gw; /* IP address of gateway */ ++ u_int8_t flags; ++}; ++ ++/* Values for "flags" field */ ++#define IPT_ROUTE_CONTINUE 0x01 ++ ++#endif /*_IPT_ROUTE_H_target*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_SAME.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_SAME.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_SAME.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_SAME.h Wed Sep 24 09:16:38 2003 +@@ -0,0 +1,19 @@ ++#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; ++ u_int32_t rangesize; ++ u_int32_t ipnum; ++ u_int32_t *iparray; ++ ++ /* hangs off end. */ ++ struct ip_nat_range range[IPT_SAME_MAX_RANGE]; ++}; ++ ++#endif /*_IPT_SAME_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_TCPLAG.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_TCPLAG.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_TCPLAG.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_TCPLAG.h Wed Sep 24 09:17:29 2003 +@@ -0,0 +1,10 @@ ++#ifndef _IPT_TCPLAG_H ++#define _IPT_TCPLAG_H ++ ++struct ipt_tcplag ++{ ++ unsigned char level; ++ unsigned char prefix[ 15 ]; ++}; ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_TTL.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_TTL.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_TTL.h Wed Sep 24 09:16:40 2003 +@@ -0,0 +1,21 @@ ++/* TTL modification module for IP tables ++ * (C) 2000 by Harald Welte */ ++ ++#ifndef _IPT_TTL_H ++#define _IPT_TTL_H ++ ++enum { ++ IPT_TTL_SET = 0, ++ IPT_TTL_INC, ++ IPT_TTL_DEC ++}; ++ ++#define IPT_TTL_MAXMODE IPT_TTL_DEC ++ ++struct ipt_TTL_info { ++ u_int8_t mode; ++ u_int8_t ttl; ++}; ++ ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_ULOG.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_ULOG.h Mon Feb 25 19:38:13 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_ULOG.h Wed Sep 24 09:16:23 2003 +@@ -11,6 +11,9 @@ + #define NETLINK_NFLOG 5 + #endif + ++#define ULOG_DEFAULT_NLGROUP 1 ++#define ULOG_DEFAULT_QTHRESHOLD 1 ++ + #define ULOG_MAC_LEN 80 + #define ULOG_PREFIX_LEN 32 + +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_XOR.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_XOR.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_XOR.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_XOR.h Wed Sep 24 09:17:31 2003 +@@ -0,0 +1,9 @@ ++#ifndef _IPT_XOR_H ++#define _IPT_XOR_H ++ ++struct ipt_XOR_info { ++ char key[30]; ++ u_int8_t block_size; ++}; ++ ++#endif /* _IPT_XOR_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_addrtype.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_addrtype.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_addrtype.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_addrtype.h Wed Sep 24 09:17:32 2003 +@@ -0,0 +1,11 @@ ++#ifndef _IPT_ADDRTYPE_H ++#define _IPT_ADDRTYPE_H ++ ++struct ipt_addrtype_info { ++ u_int16_t source; /* source-type mask */ ++ u_int16_t dest; /* dest-type mask */ ++ int invert_source; ++ int invert_dest; ++}; ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_condition.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_condition.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_condition.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_condition.h Wed Sep 24 09:17:34 2003 +@@ -0,0 +1,11 @@ ++#ifndef __IPT_CONDITION_MATCH__ ++#define __IPT_CONDITION_MATCH__ ++ ++#define CONDITION_NAME_LEN 32 ++ ++struct condition_info { ++ char name[CONDITION_NAME_LEN]; ++ int invert; ++}; ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_connlimit.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_connlimit.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_connlimit.h Wed Sep 24 09:16:42 2003 +@@ -0,0 +1,12 @@ ++#ifndef _IPT_CONNLIMIT_H ++#define _IPT_CONNLIMIT_H ++ ++struct ipt_connlimit_data; ++ ++struct ipt_connlimit_info { ++ int limit; ++ int inverse; ++ u_int32_t mask; ++ struct ipt_connlimit_data *data; ++}; ++#endif /* _IPT_CONNLIMIT_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_connmark.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_connmark.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_connmark.h Wed Sep 24 09:17:17 2003 +@@ -0,0 +1,9 @@ ++#ifndef _IPT_CONNMARK_H ++#define _IPT_CONNMARK_H ++ ++struct ipt_connmark_info { ++ unsigned long mark, mask; ++ u_int8_t invert; ++}; ++ ++#endif /*_IPT_CONNMARK_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_conntrack.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_conntrack.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_conntrack.h Wed Sep 24 09:18:12 2003 +@@ -11,6 +11,8 @@ + #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1)) + #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2)) + ++#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_IS_REPLY+3)) ++ + /* flags, invflags: */ + #define IPT_CONNTRACK_STATE 0x01 + #define IPT_CONNTRACK_PROTO 0x02 +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_fuzzy.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_fuzzy.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_fuzzy.h Wed Sep 24 09:16:44 2003 +@@ -0,0 +1,21 @@ ++#ifndef _IPT_FUZZY_H ++#define _IPT_FUZZY_H ++ ++#include ++#include ++ ++#define MAXFUZZYRATE 10000000 ++#define MINFUZZYRATE 3 ++ ++struct ipt_fuzzy_info { ++ u_int32_t minimum_rate; ++ u_int32_t maximum_rate; ++ u_int32_t packets_total; ++ u_int32_t bytes_total; ++ u_int32_t previous_time; ++ u_int32_t present_time; ++ u_int32_t mean_rate; ++ u_int8_t acceptance_rate; ++}; ++ ++#endif /*_IPT_FUZZY_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_iprange.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_iprange.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_iprange.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_iprange.h Wed Sep 24 09:16:47 2003 +@@ -0,0 +1,23 @@ ++#ifndef _IPT_IPRANGE_H ++#define _IPT_IPRANGE_H ++ ++#define IPRANGE_SRC 0x01 /* Match source IP address */ ++#define IPRANGE_DST 0x02 /* Match destination IP address */ ++#define IPRANGE_SRC_INV 0x10 /* Negate the condition */ ++#define IPRANGE_DST_INV 0x20 /* Negate the condition */ ++ ++struct ipt_iprange { ++ /* Inclusive: network order. */ ++ u_int32_t min_ip, max_ip; ++}; ++ ++struct ipt_iprange_info ++{ ++ struct ipt_iprange src; ++ struct ipt_iprange dst; ++ ++ /* Flags from above */ ++ u_int8_t flags; ++}; ++ ++#endif /* _IPT_IPRANGE_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_ipv4options.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_ipv4options.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_ipv4options.h Wed Sep 24 09:16:49 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_mark.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_mark.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_mark.h Fri Mar 17 18:56:20 2000 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_mark.h Wed Sep 24 09:18:10 2003 +@@ -1,9 +1,16 @@ + #ifndef _IPT_MARK_H + #define _IPT_MARK_H + ++enum { ++ IPT_MARK_BIT_OP_NONE, ++ IPT_MARK_BIT_OP_AND, ++ IPT_MARK_BIT_OP_OR ++}; ++ + struct ipt_mark_info { + unsigned long mark, mask; + u_int8_t invert; ++ u_int8_t bit_op; + }; + + #endif /*_IPT_MARK_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_mport.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_mport.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_mport.h Wed Sep 24 09:16:51 2003 +@@ -0,0 +1,24 @@ ++#ifndef _IPT_MPORT_H ++#define _IPT_MPORT_H ++#include ++ ++#define IPT_MPORT_SOURCE (1<<0) ++#define IPT_MPORT_DESTINATION (1<<1) ++#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION) ++ ++#define IPT_MULTI_PORTS 15 ++ ++/* Must fit inside union ipt_matchinfo: 32 bytes */ ++/* every entry in ports[] except for the last one has one bit in pflags ++ * associated with it. If this bit is set, the port is the first port of ++ * a portrange, with the next entry being the last. ++ * End of list is marked with pflags bit set and port=65535. ++ * If 14 ports are used (last one does not have a pflag), the last port ++ * is repeated to fill the last entry in ports[] */ ++struct ipt_mport ++{ ++ u_int8_t flags:2; /* Type of comparison */ ++ u_int16_t pflags:14; /* Port flags */ ++ u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ ++}; ++#endif /*_IPT_MPORT_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_nth.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_nth.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_nth.h Wed Sep 24 09:16:53 2003 +@@ -0,0 +1,19 @@ ++#ifndef _IPT_NTH_H ++#define _IPT_NTH_H ++ ++#include ++#include ++ ++#ifndef IPT_NTH_NUM_COUNTERS ++#define IPT_NTH_NUM_COUNTERS 16 ++#endif ++ ++struct ipt_nth_info { ++ u_int8_t every; ++ u_int8_t not; ++ u_int8_t startat; ++ u_int8_t counter; ++ u_int8_t packet; ++}; ++ ++#endif /*_IPT_NTH_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_osf.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_osf.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_osf.h Wed Sep 24 09:16:57 2003 +@@ -0,0 +1,120 @@ ++/* ++ * ipt_osf.h ++ * ++ * Copyright (c) 2003 Evgeniy Polyakov ++ * ++ * ++ * 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 ++ */ ++ ++#ifndef _IPT_OSF_H ++#define _IPT_OSF_H ++ ++#define MAXGENRELEN 32 ++#define MAXDETLEN 64 ++ ++#include ++ ++struct ipt_osf_info ++{ ++ char genre[MAXGENRELEN]; ++ int len; ++ int invert; /* UNSUPPORTED */ ++}; ++ ++struct osf_wc ++{ ++ char wc; ++ unsigned long val; ++}; ++ ++/* This struct represents IANA options ++ * http://www.iana.org/assignments/tcp-parameters ++ */ ++struct osf_opt ++{ ++ unsigned char kind; ++ unsigned char length; ++ struct osf_wc wc; ++}; ++ ++#ifdef __KERNEL__ ++ ++struct osf_finger ++{ ++ struct list_head flist; ++ struct osf_wc wss; ++ unsigned char ttl; ++ unsigned char df; ++ unsigned long ss; ++ char genre[MAXGENRELEN]; ++ ++ /* Not needed, but for consistency with original table from Michal Zalewski */ ++ char details[MAXDETLEN]; ++ ++ int opt_num; ++ struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */ ++ ++}; ++ ++/* Defines for IANA option kinds */ ++ ++#define OSFOPT_EOL 0 /* End of options */ ++#define OSFOPT_NOP 1 /* NOP */ ++#define OSFOPT_MSS 2 /* Maximum segment size */ ++#define OSFOPT_WSO 3 /* Window scale option */ ++#define OSFOPT_SACKP 4 /* SACK permitted */ ++#define OSFOPT_SACK 5 /* SACK */ ++#define OSFOPT_ECHO 6 ++#define OSFOPT_ECHOREPLY 7 ++#define OSFOPT_TS 8 /* Timestamp option */ ++#define OSFOPT_POCP 9 /* Partial Order Connection Permitted */ ++#define OSFOPT_POSP 10 /* Partial Order Service Profile */ ++/* Others are not used in current OSF */ ++ ++static struct osf_opt IANA_opts[] = ++{ ++ {0, 1,}, ++ {1, 1,}, ++ {2, 4,}, ++ {3, 3,}, ++ {4, 2,}, ++ {5, 1 ,}, /* SACK length is not defined */ ++ {6, 6,}, ++ {7, 6,}, ++ {8, 10,}, ++ {9, 2,}, ++ {10, 3,}, ++ {11, 1,}, /* CC: Suppose 1 */ ++ {12, 1,}, /* the same */ ++ {13, 1,}, /* and here too */ ++ {14, 3,}, ++ {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */ ++ {16, 1,}, ++ {17, 1,}, ++ {18, 3,}, ++ {19, 18,}, ++ {20, 1,}, ++ {21, 1,}, ++ {22, 1,}, ++ {23, 1,}, ++ {24, 1,}, ++ {25, 1,}, ++ {26, 1,}, ++}; ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _IPT_OSF_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_pool.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_pool.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_pool.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_pool.h Wed Sep 24 09:16:59 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_psd.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_psd.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_psd.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_psd.h Wed Sep 24 09:17:01 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_quota.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_quota.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_quota.h Wed Sep 24 09:17:03 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_random.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_random.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_random.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_random.h Wed Sep 24 09:17:05 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_realm.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_realm.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_realm.h Wed Sep 24 09:17:09 2003 +@@ -0,0 +1,9 @@ ++#ifndef _IPT_REALM_H ++#define _IPT_REALM_H ++ ++struct ipt_realm_info { ++ u_int32_t id; ++ u_int32_t mask; ++ u_int8_t invert; ++}; ++#endif /*_IPT_REALM_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_recent.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_recent.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_recent.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_recent.h Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,27 @@ ++#ifndef _IPT_RECENT_H ++#define _IPT_RECENT_H ++ ++#define RECENT_NAME "ipt_recent" ++#define RECENT_VER "v0.3.1" ++ ++#define IPT_RECENT_CHECK 1 ++#define IPT_RECENT_SET 2 ++#define IPT_RECENT_UPDATE 4 ++#define IPT_RECENT_REMOVE 8 ++#define IPT_RECENT_TTL 16 ++ ++#define IPT_RECENT_SOURCE 0 ++#define IPT_RECENT_DEST 1 ++ ++#define IPT_RECENT_NAME_LEN 200 ++ ++struct ipt_recent_info { ++ u_int32_t seconds; ++ u_int32_t hit_count; ++ u_int8_t check_set; ++ u_int8_t invert; ++ char name[IPT_RECENT_NAME_LEN]; ++ u_int8_t side; ++}; ++ ++#endif /*_IPT_RECENT_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_rpc.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_rpc.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_rpc.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_rpc.h Wed Sep 24 09:18:01 2003 +@@ -0,0 +1,35 @@ ++/* RPC extension for IP netfilter matching, Version 2.2 ++ * (C) 2000 by Marcelo Barbosa Lima ++ * - original rpc tracking module ++ * - "recent" connection handling for kernel 2.3+ netfilter ++ * ++ * (C) 2001 by Rusty Russell ++ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ ++ * ++ * (C) 2002 by Ian (Larry) Latter ++ * - upgraded conntrack modules to newnat api - kernel 2.4.20+ ++ * - extended matching to support filtering on procedures ++ * ++ * ipt_rpc.h.c,v 2.2 2003/01/12 18:30:00 ++ * ++ * 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. ++ ** ++ */ ++ ++#ifndef _IPT_RPC_H ++#define _IPT_RPC_H ++ ++struct ipt_rpc_data; ++ ++struct ipt_rpc_info { ++ int inverse; ++ int strict; ++ const char c_procs[1408]; ++ int i_procs; ++ struct ipt_rpc_data *data; ++}; ++ ++#endif /* _IPT_RPC_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_state.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_state.h Fri Apr 14 16:37:20 2000 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_state.h Wed Sep 24 09:18:12 2003 +@@ -3,6 +3,7 @@ + + #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1)) + #define IPT_STATE_INVALID (1 << 0) ++#define IPT_STATE_UNTRACKED (1 << (IP_CT_IS_REPLY+1)) + + struct ipt_state_info + { +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_string.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_string.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_string.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_string.h Wed Sep 24 09:18:05 2003 +@@ -0,0 +1,21 @@ ++#ifndef _IPT_STRING_H ++#define _IPT_STRING_H ++ ++/* *** PERFORMANCE TWEAK *** ++ * Packet size and search string threshold, ++ * above which sublinear searches is used. */ ++#define IPT_STRING_HAYSTACK_THRESH 100 ++#define IPT_STRING_NEEDLE_THRESH 20 ++ ++#define BM_MAX_NLEN 256 ++#define BM_MAX_HLEN 1024 ++ ++typedef char *(*proc_ipt_search) (char *, char *, int, int); ++ ++struct ipt_string_info { ++ char string[BM_MAX_NLEN]; ++ u_int16_t invert; ++ u_int16_t len; ++}; ++ ++#endif /* _IPT_STRING_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_time.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_time.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_time.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_time.h Wed Sep 24 09:17:10 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.4.20/include/linux/netfilter_ipv4/ipt_u32.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/ipt_u32.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv4/ipt_u32.h Wed Sep 24 09:17:12 2003 +@@ -0,0 +1,40 @@ ++#ifndef _IPT_U32_H ++#define _IPT_U32_H ++#include ++ ++enum ipt_u32_ops ++{ ++ IPT_U32_AND, ++ IPT_U32_LEFTSH, ++ IPT_U32_RIGHTSH, ++ IPT_U32_AT ++}; ++ ++struct ipt_u32_location_element ++{ ++ u_int32_t number; ++ u_int8_t nextop; ++}; ++struct ipt_u32_value_element ++{ ++ u_int32_t min; ++ u_int32_t max; ++}; ++/* *** any way to allow for an arbitrary number of elements? ++ for now I settle for a limit of 10 of each */ ++#define U32MAXSIZE 10 ++struct ipt_u32_test ++{ ++ u_int8_t nnums; ++ struct ipt_u32_location_element location[U32MAXSIZE+1]; ++ u_int8_t nvalues; ++ struct ipt_u32_value_element value[U32MAXSIZE+1]; ++}; ++ ++struct ipt_u32 ++{ ++ u_int8_t ntests; ++ struct ipt_u32_test tests[U32MAXSIZE+1]; ++}; ++ ++#endif /*_IPT_U32_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/listhelp.h linux-2.4.20/include/linux/netfilter_ipv4/listhelp.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/listhelp.h Thu Jul 26 20:52:12 2001 ++++ linux-2.4.20/include/linux/netfilter_ipv4/listhelp.h Wed Sep 24 09:16:17 2003 +@@ -39,6 +39,22 @@ + (type)__i; \ + }) + ++/* Just like LIST_FIND but we search backwards */ ++#define LIST_FIND_B(head, cmpfn, type, args...) \ ++({ \ ++ const struct list_head *__i = (head); \ ++ \ ++ ASSERT_READ_LOCK(head); \ ++ do { \ ++ __i = __i->prev; \ ++ if (__i == (head)) { \ ++ __i = NULL; \ ++ break; \ ++ } \ ++ } while (!cmpfn((const type)__i , ## args)); \ ++ (type)__i; \ ++}) ++ + static inline int + __list_cmp_same(const void *p1, const void *p2) { return p1 == p2; } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv4/lockhelp.h linux-2.4.20/include/linux/netfilter_ipv4/lockhelp.h +--- linux-2.4.20.org/include/linux/netfilter_ipv4/lockhelp.h Mon Jan 1 18:37:41 2001 ++++ linux-2.4.20/include/linux/netfilter_ipv4/lockhelp.h Wed Sep 24 09:16:17 2003 +@@ -42,22 +42,22 @@ + printk("ASSERT %s:%u %s locked\n", __FILE__, __LINE__, #l); \ + } while(0) + +-/* Write locked OK as well. */ \ ++/* Write locked OK as well. */ + #define MUST_BE_READ_LOCKED(l) \ +-do { if (!((l)->read_locked_map & (1 << smp_processor_id())) \ +- && !((l)->write_locked_map & (1 << smp_processor_id()))) \ ++do { if (!((l)->read_locked_map & (1UL << smp_processor_id())) \ ++ && !((l)->write_locked_map & (1UL << smp_processor_id()))) \ + printk("ASSERT %s:%u %s not readlocked\n", __FILE__, __LINE__, #l); \ + } while(0) + + #define MUST_BE_WRITE_LOCKED(l) \ +-do { if (!((l)->write_locked_map & (1 << smp_processor_id()))) \ ++do { if (!((l)->write_locked_map & (1UL << smp_processor_id()))) \ + printk("ASSERT %s:%u %s not writelocked\n", __FILE__, __LINE__, #l); \ + } while(0) + + #define MUST_BE_READ_WRITE_UNLOCKED(l) \ +-do { if ((l)->read_locked_map & (1 << smp_processor_id())) \ ++do { if ((l)->read_locked_map & (1UL << smp_processor_id())) \ + printk("ASSERT %s:%u %s readlocked\n", __FILE__, __LINE__, #l); \ +- else if ((l)->write_locked_map & (1 << smp_processor_id())) \ ++ else if ((l)->write_locked_map & (1UL << smp_processor_id())) \ + printk("ASSERT %s:%u %s writelocked\n", __FILE__, __LINE__, #l); \ + } while(0) + +@@ -91,7 +91,7 @@ + + #define READ_UNLOCK(lk) \ + do { \ +- if (!((lk)->read_locked_map & (1 << smp_processor_id()))) \ ++ if (!((lk)->read_locked_map & (1UL << smp_processor_id()))) \ + printk("ASSERT: %s:%u %s not readlocked\n", \ + __FILE__, __LINE__, #lk); \ + clear_bit(smp_processor_id(), &(lk)->read_locked_map); \ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6_logging.h linux-2.4.20/include/linux/netfilter_ipv6/ip6_logging.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6_logging.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6_logging.h Wed Sep 24 09:16:23 2003 +@@ -0,0 +1,20 @@ ++/* IPv6 macros for the nternal logging interface. */ ++#ifndef __IP6_LOGGING_H ++#define __IP6_LOGGING_H ++ ++#ifdef __KERNEL__ ++#include ++#include ++ ++#define nf_log_ip6_packet(pskb,hooknum,in,out,fmt,args...) \ ++ nf_log_packet(AF_INET6,pskb,hooknum,in,out,fmt,##args) ++ ++#define nf_log_ip6(pfh,len,fmt,args...) \ ++ nf_log(AF_INET6,pfh,len,fmt,##args) ++ ++#define nf_ip6_log_register(logging) nf_log_register(AF_INET6,logging) ++#define nf_ip6_log_unregister(logging) nf_log_unregister(AF_INET6,logging) ++ ++#endif /*__KERNEL__*/ ++ ++#endif /*__IP6_LOGGING_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6_tables.h linux-2.4.20/include/linux/netfilter_ipv6/ip6_tables.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6_tables.h Mon Feb 25 19:38:13 2002 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6_tables.h Wed Sep 24 09:16:14 2003 +@@ -449,6 +449,9 @@ + struct ip6t_table *table, + void *userdata); + ++/* Check for an extension */ ++extern int ip6t_ext_hdr(u8 nexthdr); ++ + #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) + + #endif /*__KERNEL__*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_HL.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_HL.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_HL.h Wed Sep 24 09:16:28 2003 +@@ -0,0 +1,22 @@ ++/* Hop Limit modification module for ip6tables ++ * Maciej Soltysiak ++ * Based on HW's TTL module */ ++ ++#ifndef _IP6T_HL_H ++#define _IP6T_HL_H ++ ++enum { ++ IP6T_HL_SET = 0, ++ IP6T_HL_INC, ++ IP6T_HL_DEC ++}; ++ ++#define IP6T_HL_MAXMODE IP6T_HL_DEC ++ ++struct ip6t_HL_info { ++ u_int8_t mode; ++ u_int8_t hop_limit; ++}; ++ ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_IMQ.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_IMQ.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_IMQ.h Wed Sep 24 09:17:21 2003 +@@ -0,0 +1,8 @@ ++#ifndef _IP6T_IMQ_H ++#define _IP6T_IMQ_H ++ ++struct ip6t_imq_info { ++ unsigned int todev; /* target imq device */ ++}; ++ ++#endif /* _IP6T_IMQ_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_REJECT.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_REJECT.h Tue Jun 20 21:32:27 2000 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_REJECT.h Wed Sep 24 09:16:36 2003 +@@ -2,15 +2,17 @@ + #define _IP6T_REJECT_H + + enum ip6t_reject_with { +- IP6T_ICMP_NET_UNREACHABLE, +- IP6T_ICMP_HOST_UNREACHABLE, +- IP6T_ICMP_PROT_UNREACHABLE, +- IP6T_ICMP_PORT_UNREACHABLE, +- IP6T_ICMP_ECHOREPLY ++ IP6T_ICMP6_NO_ROUTE, ++ IP6T_ICMP6_ADM_PROHIBITED, ++ IP6T_ICMP6_NOT_NEIGHBOUR, ++ IP6T_ICMP6_ADDR_UNREACH, ++ IP6T_ICMP6_PORT_UNREACH, ++ IP6T_ICMP6_ECHOREPLY, ++ IP6T_TCP_RESET + }; + + struct ip6t_reject_info { + enum ip6t_reject_with with; /* reject type */ + }; + +-#endif /*_IPT_REJECT_H*/ ++#endif /*_IP6T_REJECT_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ROUTE.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ROUTE.h Wed Sep 24 09:17:27 2003 +@@ -0,0 +1,22 @@ ++/* Header file for iptables ip6t_ROUTE target ++ * ++ * (C) 2003 by Cédric de Launois ++ * ++ * This software is distributed under GNU GPL v2, 1991 ++ */ ++#ifndef _IPT_ROUTE_H_target ++#define _IPT_ROUTE_H_target ++ ++#define IP6T_ROUTE_IFNAMSIZ 16 ++ ++struct ip6t_route_target_info { ++ char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */ ++ char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */ ++ u_int32_t gw[4]; /* IPv6 address of gateway */ ++ u_int8_t flags; ++}; ++ ++/* Values for "flags" field */ ++#define IP6T_ROUTE_CONTINUE 0x01 ++ ++#endif /*_IP6T_ROUTE_H_target*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_ah.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ah.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_ah.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ah.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,30 @@ ++#ifndef _IP6T_AH_H ++#define _IP6T_AH_H ++ ++struct ip6t_ah ++{ ++ u_int32_t spis[2]; /* Security Parameter Index */ ++ u_int32_t hdrlen; /* Header Length */ ++ u_int8_t hdrres; /* Test of the Reserved Filed */ ++ u_int8_t invflags; /* Inverse flags */ ++}; ++ ++#define IP6T_AH_SPI 0x01 ++#define IP6T_AH_LEN 0x02 ++#define IP6T_AH_RES 0x04 ++ ++/* Values for "invflags" field in struct ip6t_ah. */ ++#define IP6T_AH_INV_SPI 0x01 /* Invert the sense of spi. */ ++#define IP6T_AH_INV_LEN 0x02 /* Invert the sense of length. */ ++#define IP6T_AH_INV_MASK 0x03 /* All possible flags. */ ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++#endif /*_IP6T_AH_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_condition.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_condition.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_condition.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_condition.h Wed Sep 24 09:17:36 2003 +@@ -0,0 +1,11 @@ ++#ifndef __IP6T_CONDITION_MATCH__ ++#define __IP6T_CONDITION_MATCH__ ++ ++#define CONDITION6_NAME_LEN 32 ++ ++struct condition6_info { ++ char name[CONDITION6_NAME_LEN]; ++ int invert; ++}; ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_esp.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_esp.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_esp.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_esp.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,23 @@ ++#ifndef _IP6T_ESP_H ++#define _IP6T_ESP_H ++ ++struct ip6t_esp ++{ ++ u_int32_t spis[2]; /* Security Parameter Index */ ++ u_int8_t invflags; /* Inverse flags */ ++}; ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++/* Values for "invflags" field in struct ip6t_esp. */ ++#define IP6T_ESP_INV_SPI 0x01 /* Invert the sense of spi. */ ++#define IP6T_ESP_INV_MASK 0x01 /* All possible flags. */ ++ ++#endif /*_IP6T_ESP_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_frag.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_frag.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_frag.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_frag.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,33 @@ ++#ifndef _IP6T_FRAG_H ++#define _IP6T_FRAG_H ++ ++struct ip6t_frag ++{ ++ u_int32_t ids[2]; /* Security Parameter Index */ ++ u_int32_t hdrlen; /* Header Length */ ++ u_int8_t flags; /* */ ++ u_int8_t invflags; /* Inverse flags */ ++}; ++ ++#define IP6T_FRAG_IDS 0x01 ++#define IP6T_FRAG_LEN 0x02 ++#define IP6T_FRAG_RES 0x04 ++#define IP6T_FRAG_FST 0x08 ++#define IP6T_FRAG_MF 0x10 ++#define IP6T_FRAG_NMF 0x20 ++ ++/* Values for "invflags" field in struct ip6t_frag. */ ++#define IP6T_FRAG_INV_IDS 0x01 /* Invert the sense of ids. */ ++#define IP6T_FRAG_INV_LEN 0x02 /* Invert the sense of length. */ ++#define IP6T_FRAG_INV_MASK 0x03 /* All possible flags. */ ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++#endif /*_IP6T_FRAG_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_fuzzy.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_fuzzy.h Wed Sep 24 09:16:45 2003 +@@ -0,0 +1,21 @@ ++#ifndef _IP6T_FUZZY_H ++#define _IP6T_FUZZY_H ++ ++#include ++#include ++ ++#define MAXFUZZYRATE 10000000 ++#define MINFUZZYRATE 3 ++ ++struct ip6t_fuzzy_info { ++ u_int32_t minimum_rate; ++ u_int32_t maximum_rate; ++ u_int32_t packets_total; ++ u_int32_t bytes_total; ++ u_int32_t previous_time; ++ u_int32_t present_time; ++ u_int32_t mean_rate; ++ u_int8_t acceptance_rate; ++}; ++ ++#endif /*_IP6T_FUZZY_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_hl.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_hl.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_hl.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_hl.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,22 @@ ++/* ip6tables module for matching the Hop Limit value ++ * Maciej Soltysiak ++ * Based on HW's ttl module */ ++ ++#ifndef _IP6T_HL_H ++#define _IP6T_HL_H ++ ++enum { ++ IP6T_HL_EQ = 0, /* equals */ ++ IP6T_HL_NE, /* not equals */ ++ IP6T_HL_LT, /* less than */ ++ IP6T_HL_GT, /* greater than */ ++}; ++ ++ ++struct ip6t_hl_info { ++ u_int8_t mode; ++ u_int8_t hop_limit; ++}; ++ ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_ipv6header.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ipv6header.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_ipv6header.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ipv6header.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,27 @@ ++/* ipv6header match - matches IPv6 packets based ++on whether they contain certain headers */ ++ ++/* Original idea: Brad Chapman ++ * Rewritten by: Andras Kis-Szabo */ ++ ++ ++#ifndef __IPV6HEADER_H ++#define __IPV6HEADER_H ++ ++struct ip6t_ipv6header_info ++{ ++ u_int8_t matchflags; ++ u_int8_t invflags; ++ u_int8_t modeflag; ++}; ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++#endif /* __IPV6HEADER_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_nth.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_nth.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_nth.h Wed Sep 24 09:16:55 2003 +@@ -0,0 +1,19 @@ ++#ifndef _IP6T_NTH_H ++#define _IP6T_NTH_H ++ ++#include ++#include ++ ++#ifndef IP6T_NTH_NUM_COUNTERS ++#define IP6T_NTH_NUM_COUNTERS 16 ++#endif ++ ++struct ip6t_nth_info { ++ u_int8_t every; ++ u_int8_t not; ++ u_int8_t startat; ++ u_int8_t counter; ++ u_int8_t packet; ++}; ++ ++#endif /*_IP6T_NTH_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_opts.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_opts.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_opts.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_opts.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,32 @@ ++#ifndef _IP6T_OPTS_H ++#define _IP6T_OPTS_H ++ ++#define IP6T_OPTS_OPTSNR 16 ++ ++struct ip6t_opts ++{ ++ u_int32_t hdrlen; /* Header Length */ ++ u_int8_t flags; /* */ ++ u_int8_t invflags; /* Inverse flags */ ++ u_int16_t opts[IP6T_OPTS_OPTSNR]; /* opts */ ++ u_int8_t optsnr; /* Nr of OPts */ ++}; ++ ++#define IP6T_OPTS_LEN 0x01 ++#define IP6T_OPTS_OPTS 0x02 ++#define IP6T_OPTS_NSTRICT 0x04 ++ ++/* Values for "invflags" field in struct ip6t_rt. */ ++#define IP6T_OPTS_INV_LEN 0x01 /* Invert the sense of length. */ ++#define IP6T_OPTS_INV_MASK 0x01 /* All possible flags. */ ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++#endif /*_IP6T_OPTS_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_owner.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_owner.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_owner.h Tue Jun 20 21:32:27 2000 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_owner.h Wed Sep 24 09:17:52 2003 +@@ -6,12 +6,14 @@ + #define IP6T_OWNER_GID 0x02 + #define IP6T_OWNER_PID 0x04 + #define IP6T_OWNER_SID 0x08 ++#define IP6T_OWNER_COMM 0x10 + + struct ip6t_owner_info { + uid_t uid; + gid_t gid; + pid_t pid; + pid_t sid; ++ char comm[16]; + u_int8_t match, invert; /* flags */ + }; + +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_random.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_random.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_random.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_random.h Wed Sep 24 09:17:07 2003 +@@ -0,0 +1,11 @@ ++#ifndef _IP6T_RAND_H ++#define _IP6T_RAND_H ++ ++#include ++#include ++ ++struct ip6t_rand_info { ++ u_int8_t average; ++}; ++ ++#endif /*_IP6T_RAND_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_rt.h linux-2.4.20/include/linux/netfilter_ipv6/ip6t_rt.h +--- linux-2.4.20.org/include/linux/netfilter_ipv6/ip6t_rt.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_ipv6/ip6t_rt.h Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,42 @@ ++#ifndef _IP6T_RT_H ++#define _IP6T_RT_H ++ ++/*#include */ ++ ++#define IP6T_RT_HOPS 16 ++ ++struct ip6t_rt ++{ ++ u_int32_t rt_type; /* Routing Type */ ++ u_int32_t segsleft[2]; /* Segments Left */ ++ u_int32_t hdrlen; /* Header Length */ ++ u_int8_t flags; /* */ ++ u_int8_t invflags; /* Inverse flags */ ++ struct in6_addr addrs[IP6T_RT_HOPS]; /* Hops */ ++ u_int8_t addrnr; /* Nr of Addresses */ ++}; ++ ++#define IP6T_RT_TYP 0x01 ++#define IP6T_RT_SGS 0x02 ++#define IP6T_RT_LEN 0x04 ++#define IP6T_RT_RES 0x08 ++#define IP6T_RT_FST_MASK 0x30 ++#define IP6T_RT_FST 0x10 ++#define IP6T_RT_FST_NSTRICT 0x20 ++ ++/* Values for "invflags" field in struct ip6t_rt. */ ++#define IP6T_RT_INV_TYP 0x01 /* Invert the sense of type. */ ++#define IP6T_RT_INV_SGS 0x02 /* Invert the sense of Segments. */ ++#define IP6T_RT_INV_LEN 0x04 /* Invert the sense of length. */ ++#define IP6T_RT_INV_MASK 0x07 /* All possible flags. */ ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++#endif /*_IP6T_RT_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/netfilter_logging.h linux-2.4.20/include/linux/netfilter_logging.h +--- linux-2.4.20.org/include/linux/netfilter_logging.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/netfilter_logging.h Wed Sep 24 09:16:23 2003 +@@ -0,0 +1,33 @@ ++/* Internal logging interface, which relies on the real ++ LOG target modules */ ++#ifndef __LINUX_NETFILTER_LOGGING_H ++#define __LINUX_NETFILTER_LOGGING_H ++ ++#ifdef __KERNEL__ ++#include ++ ++struct nf_logging_t { ++ void (*nf_log_packet)(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const char *prefix); ++ void (*nf_log)(char *pfh, size_t len, ++ const char *prefix); ++}; ++ ++extern void nf_log_register(int pf, const struct nf_logging_t *logging); ++extern void nf_log_unregister(int pf, const struct nf_logging_t *logging); ++ ++extern void nf_log_packet(int pf, ++ struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const char *fmt, ...); ++extern void nf_log(int pf, ++ char *pfh, size_t len, ++ const char *fmt, ...); ++#endif /*__KERNEL__*/ ++ ++#endif /*__LINUX_NETFILTER_LOGGING_H*/ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/nfnetlink.h linux-2.4.20/include/linux/nfnetlink.h +--- linux-2.4.20.org/include/linux/nfnetlink.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/nfnetlink.h Wed Sep 24 09:17:51 2003 +@@ -0,0 +1,158 @@ ++#ifndef _NFNETLINK_H ++#define _NFNETLINK_H ++#include ++ ++/* Generic structure for encapsulation optional netfilter information. ++ * It is reminiscent of sockaddr, but with sa_family replaced ++ * with attribute type. ++ * ! This should someday be put somewhere generic as now rtnetlink and ++ * ! nfnetlink use the same attributes methods. - J. Schulist. ++ */ ++ ++struct nfattr ++{ ++ unsigned short nfa_len; ++ unsigned short nfa_type; ++}; ++ ++#define NFA_ALIGNTO 4 ++#define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1)) ++#define NFA_OK(nfa,len) ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \ ++ && (nfa)->nfa_len <= (len)) ++#define NFA_NEXT(nfa,attrlen) ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \ ++ (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len))) ++#define NFA_LENGTH(len) (NFA_ALIGN(sizeof(struct nfattr)) + (len)) ++#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len)) ++#define NFA_DATA(nfa) ((void *)(((char *)(nfa)) + NFA_LENGTH(0))) ++#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0)) ++ ++/* General form of address family dependent message. ++ */ ++struct nfgenmsg { ++ unsigned char nfgen_family; ++}; ++ ++#if 0 ++struct iptgenmsg { ++ unsigned char iptgen_family; ++ char iptgen_table[IPT_TABLE_MAXNAMELEN]; ++}; ++ ++struct iptmsg { ++ unsigned char iptm_family; ++ char iptm_table[IPT_TABLE_MAXNAMELEN]; ++ char iptm_chain[IPT_FUNCTION_MAXNAMELEN]; ++ unsigned int iptm_entry_num; ++}; ++ ++enum iptattr_type_t ++{ ++ IPTA_UNSPEC, /* [none] I don't know (unspecified). */ ++ IPTA_IP, /* [ipt_ip] */ ++ IPTA_NFCACHE, /* [u_int] */ ++ IPTA_COUNTERS, /* [ipt_counters] */ ++ IPTA_MATCH, /* [ipt_info] */ ++ IPTA_TARGET, /* [ipt_info] */ ++ IPTA_MAX = IPTA_TARGET ++}; ++ ++struct ipta_info { ++ u_int16_t size; ++ char name[IPT_FUNCTION_MAXNAMELEN]; ++ unsigned char data[0]; ++}; ++ ++#define NFM_IPTA(n) ((struct nfattr *)(((char *)(n)) \ ++ + NLMSG_ALIGN(sizeof(struct iptmsg)))) ++ ++#endif ++ ++#define NFM_NFA(n) ((struct nfattr *)(((char *)(n)) \ ++ + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) ++#define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg)) ++ ++ ++#ifndef NETLINK_NETFILTER ++#define NETLINK_NETFILTER 6 ++#endif ++ ++/* netfilter netlink message types are split in two pieces: ++ * 8 bit subsystem, 8bit operation. ++ */ ++ ++#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) ++#define NFNL_MSG_TYPE(x) (x & 0x00ff) ++ ++enum nfnl_subsys_id { ++ NFNL_SUBSYS_NONE = 0, ++ NFNL_SUBSYS_CTNETLINK, ++ NFNL_SUBSYS_CTNETLINK_EXP, ++ NFNL_SUBSYS_IPTNETLINK, ++ NFNL_SUBSYS_QUEUE, ++ NFNL_SUBSYS_ULOG, ++ NFNL_SUBSYS_COUNT, ++}; ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct nfnl_callback ++{ ++ kernel_cap_t cap_required; /* capabilities required for this msg */ ++ int (*call)(struct sock *nl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp); ++}; ++ ++struct nfnetlink_subsystem ++{ ++ /* Internal use. */ ++ struct list_head list; ++ ++ const char *name; ++ __u8 subsys_id; /* nfnetlink subsystem ID */ ++ __u8 cb_count; /* number of callbacks */ ++ u_int32_t attr_count; /* number of nfattr's */ ++ struct nfnl_callback cb[0]; /* callback for individual types */ ++}; ++ ++extern void __nfa_fill(struct sk_buff *skb, int attrtype, ++ int attrlen, const void *data); ++#define NFA_PUT(skb, attrtype, attrlen, data) \ ++({ if (skb_tailroom(skb) < (int)NFA_SPACE(attrlen)) goto nfattr_failure; \ ++ __nfa_fill(skb, attrtype, attrlen, data); }) ++ ++extern struct semaphore nfnl_sem; ++#define nfnl_exlock() do { } while(0) ++#define nfnl_exunlock() do { } while(0) ++#define nfnl_exlock_nowait() (0) ++ ++#define nfnl_shlock() down(&nfnl_sem) ++#define nfnl_shlock_nowait() down_trylock(&nfnl_sem) ++ ++#ifndef CONFIG_NF_NETLINK ++#define nfnl_shunlock() up(&nfnl_sem) ++#else ++#define nfnl_shunlock() do { up(&nfnl_sem); \ ++ if(nfnl && nfnl->receive_queue.qlen) \ ++ nfnl->data_ready(nfnl, 0); \ ++ } while(0) ++#endif ++ ++extern void nfnl_lock(void); ++extern void nfnl_unlock(void); ++ ++extern struct nfnetlink_subsystem *nfnetlink_subsys_alloc(int cb_count); ++extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n); ++extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n); ++ ++extern int nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys, ++ struct nlmsghdr *nlh, ++ struct nfattr *cda[]); ++extern int nfattr_parse(struct nfattr *tb[], int maxattr, ++ struct nfattr *nfa, int len); ++extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, ++ int echo); ++ ++#endif /* __KERNEL__ */ ++#endif /* _NFNETLINK_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/nfnetlink_conntrack.h linux-2.4.20/include/linux/nfnetlink_conntrack.h +--- linux-2.4.20.org/include/linux/nfnetlink_conntrack.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/include/linux/nfnetlink_conntrack.h Wed Sep 24 09:17:51 2003 +@@ -0,0 +1,84 @@ ++#ifndef _NFNETLINK_CONNTRACK_H ++#define _NFNETLINK_CONNTRACK_H ++#include ++#include ++//#include ++ ++/* CTNETLINK for ip_conntrack */ ++ ++enum cntl_msg_types { ++ CTNL_MSG_NEWCONNTRACK, ++ CTNL_MSG_GETCONNTRACK, ++ CTNL_MSG_DELCONNTRACK, ++ ++ CTNL_MSG_NEWEXPECT, ++ CTNL_MSG_GETEXPECT, ++ CTNL_MSG_DELEXPECT, ++ CTNL_MSG_CONFIRMEXPECT, ++ ++ CTNL_MSG_COUNT, ++}; ++ ++/* ctnetlink attribute types. ++ */ ++enum ctattr_type_t ++{ ++ CTA_UNSPEC, /* [none] I don't know (unspecified). */ ++ CTA_ORIG, /* [ip_conntrack_tuple] Original tuple. */ ++ CTA_RPLY, /* [ip_conntrack_tuple] Reply tuple. */ ++ CTA_IIF, /* [char] Input interface name (ie eth0). */ ++ CTA_OIF, /* [char] Output interface name (ie eth1). */ ++ CTA_STATUS, /* [unsigned long] Status of connection. */ ++ CTA_INFO, /* [unsigned long] Information (ctinfo). */ ++ CTA_PROTOINFO, /* [cta_proto] Protocol specific ct information. */ ++ CTA_HELPINFO, /* [cta_help] Helper specific information. */ ++ CTA_NATINFO, /* [cta_nat] Any NAT transformations. */ ++ CTA_TIMEOUT, /* [unsigne long] timer */ ++ ++ CTA_EXP_TIMEOUT,/* [fixme] timer */ ++ CTA_EXP_TUPLE, /* [ip_conntrack_tuple] Expected tuple */ ++ CTA_EXP_MASK, /* [ip_conntrack_tuple] Mask for EXP_TUPLE */ ++ CTA_EXP_SEQNO, /* [u_int32_t] sequence number */ ++ CTA_EXP_PROTO, /* [cta_exp_proto] */ ++ CTA_EXP_HELP, /* [cta_exp_help] */ ++ ++ CTA_MAX = CTA_EXP_HELP ++}; ++ ++/* Attribute specific data structures. ++ */ ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++#include ++struct cta_nat { ++ unsigned int num_manips; ++ struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS]; ++}; ++#endif /* CONFIG_IP_NF_NAT_NEEDED */ ++ ++struct cta_proto { ++ unsigned char num_proto; /* Protocol number IPPROTO_X */ ++ union ip_conntrack_proto proto; ++}; ++ ++struct cta_help { ++ struct ip_conntrack_tuple tuple; ++ struct ip_conntrack_tuple mask; ++ char name[31]; /* name of conntrack helper */ ++ union ip_conntrack_help help; ++}; ++ ++/* ctnetlink multicast groups: reports any change of ctinfo, ++ * ctstatus, or protocol state change. ++ */ ++#define NFGRP_IPV4_CT_TCP 0x01 ++#define NFGRP_IPV4_CT_UDP 0x02 ++#define NFGRP_IPV4_CT_ICMP 0x04 ++#define NFGRP_IPV4_CT_OTHER 0x08 ++ ++#define NFGRP_IPV6_CT_TCP 0x10 ++#define NFGRP_IPV6_CT_UDP 0x20 ++#define NFGRP_IPV6_CT_ICMP 0x40 ++#define NFGRP_IPV6_CT_OTHER 0x80 ++ ++#endif /* _NFNETLINK_CONNTRACK_H */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/linux/sysctl.h linux-2.4.20/include/linux/sysctl.h +--- linux-2.4.20.org/include/linux/sysctl.h Wed Sep 24 08:52:38 2003 ++++ linux-2.4.20/include/linux/sysctl.h Wed Sep 24 09:16:22 2003 +@@ -235,6 +235,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, +@@ -343,6 +344,24 @@ + NET_IPV4_CONF_MEDIUM_ID=14, + }; + ++/* /proc/sys/net/ipv4/netfilter */ ++enum ++{ ++ NET_IPV4_NF_CONNTRACK_MAX=1, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8, ++ NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9, ++ NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10, ++ NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11, ++ NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12, ++ NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13, ++}; ++ + /* /proc/sys/net/ipv6 */ + enum { + NET_IPV6_CONF=16, +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/net/ip6_route.h linux-2.4.20/include/net/ip6_route.h +--- linux-2.4.20.org/include/net/ip6_route.h Mon Dec 11 21:30:48 2000 ++++ linux-2.4.20/include/net/ip6_route.h Wed Sep 24 09:16:14 2003 +@@ -31,6 +31,8 @@ + extern struct dst_entry * ip6_route_output(struct sock *sk, + struct flowi *fl); + ++extern int ip6_route_me_harder(struct sk_buff *skb); ++ + extern void ip6_route_init(void); + extern void ip6_route_cleanup(void); + +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/net/tcp.h linux-2.4.20/include/net/tcp.h +--- linux-2.4.20.org/include/net/tcp.h Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/include/net/tcp.h Wed Sep 24 09:17:52 2003 +@@ -140,6 +140,7 @@ + extern void tcp_bucket_unlock(struct sock *sk); + extern int tcp_port_rover; + extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif); ++extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 hnum, int dif); + + /* These are AF independent. */ + static __inline__ int tcp_bhashfn(__u16 lport) +diff -Nur --exclude '*.orig' linux-2.4.20.org/include/net/udp.h linux-2.4.20/include/net/udp.h +--- linux-2.4.20.org/include/net/udp.h Thu Nov 22 19:47:15 2001 ++++ linux-2.4.20/include/net/udp.h Wed Sep 24 09:17:52 2003 +@@ -69,6 +69,8 @@ + extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); + extern int udp_disconnect(struct sock *sk, int flags); + ++extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); ++ + extern struct udp_mib udp_statistics[NR_CPUS*2]; + #define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field) + #define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field) +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/core/netfilter.c linux-2.4.20/net/core/netfilter.c +--- linux-2.4.20.org/net/core/netfilter.c Sat Aug 3 00:39:46 2002 ++++ linux-2.4.20/net/core/netfilter.c Wed Sep 24 09:17:50 2003 +@@ -8,9 +8,12 @@ + * + * February 2000: Modified by James Morris to have 1 queue per protocol. + * 15-Mar-2000: Added NF_REPEAT --RR. ++ * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik. + */ + #include ++#include + #include ++#include + #include + #include + #include +@@ -57,6 +60,10 @@ + void *data; + } queue_handler[NPROTO]; + ++/** ++ * nf_register_hook - Register with a netfilter hook ++ * @reg: Hook operations to be registered ++ */ + int nf_register_hook(struct nf_hook_ops *reg) + { + struct list_head *i; +@@ -73,6 +80,10 @@ + return 0; + } + ++/** ++ * nf_unregister_hook - Unregister from a netfilter hook ++ * @reg: hook operations to be unregistered ++ */ + void nf_unregister_hook(struct nf_hook_ops *reg) + { + br_write_lock_bh(BR_NETPROTO_LOCK); +@@ -373,6 +384,18 @@ + return NF_ACCEPT; + } + ++/** ++ * nf_register_queue_handler - Registere a queue handler with netfilter ++ * @pf: protocol family ++ * @outfn: function called by core to enqueue a packet ++ * @data: opaque parameter, passed through ++ * ++ * This function registers a queue handler with netfilter. There can only ++ * be one queue handler for every protocol family. ++ * ++ * A queue handler _must_ reinject every packet via nf_reinject, no ++ * matter what. ++ */ + int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) + { + int ret; +@@ -390,7 +413,12 @@ + return ret; + } + +-/* The caller must flush their queue before this */ ++/** ++ * nf_unregister_queue_handler - Unregister queue handler from netfilter ++ * @pf: protocol family ++ * ++ * The caller must flush their queue before unregistering ++ */ + int nf_unregister_queue_handler(int pf) + { + br_write_lock_bh(BR_NETPROTO_LOCK); +@@ -502,6 +530,15 @@ + return ret; + } + ++/** ++ * nf_reinject - Reinject a packet from a queue handler ++ * @skb: the packet to be reinjected ++ * @info: info which was passed to the outfn() of the queue handler ++ * @verdict: verdict (NF_ACCEPT, ...) for this packet ++ * ++ * This is the function called by a queue handler to reinject a ++ * packet. ++ */ + void nf_reinject(struct sk_buff *skb, struct nf_info *info, + unsigned int verdict) + { +@@ -563,67 +600,134 @@ + { + struct iphdr *iph = (*pskb)->nh.iph; + struct rtable *rt; +- struct rt_key key = { dst:iph->daddr, +- src:iph->saddr, +- oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, +- tos:RT_TOS(iph->tos)|RTO_CONN, +-#ifdef CONFIG_IP_ROUTE_FWMARK +- fwmark:(*pskb)->nfmark +-#endif +- }; +- struct net_device *dev_src = NULL; +- int err; +- +- /* accomodate ip_route_output_slow(), which expects the key src to be +- 0 or a local address; however some non-standard hacks like +- ipt_REJECT.c:send_reset() can cause packets with foreign +- saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */ +- if(key.src && !(dev_src = ip_dev_find(key.src))) +- key.src = 0; +- +- if ((err=ip_route_output_key(&rt, &key)) != 0) { +- printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n", +- NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), +- (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, +- RT_TOS(iph->tos)|RTO_CONN, ++ struct rt_key key = {}; ++ struct dst_entry *odst; ++ unsigned int hh_len; ++ ++ /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause ++ * packets with foreign saddr to be appear on the NF_IP_LOCAL_OUT hook. ++ */ ++ if (inet_addr_type(iph->saddr) == RTN_LOCAL) { ++ key.dst = iph->daddr; ++ key.src = iph->saddr; ++ key.oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0; ++ key.tos = RT_TOS(iph->tos); + #ifdef CONFIG_IP_ROUTE_FWMARK +- (*pskb)->nfmark, +-#else +- 0UL, ++ key.fwmark = (*pskb)->nfmark; + #endif +- err); +- goto out; +- } ++ if (ip_route_output_key(&rt, &key) != 0) ++ return -1; + +- /* Drop old route. */ +- dst_release((*pskb)->dst); +- +- (*pskb)->dst = &rt->u.dst; ++ /* Drop old route. */ ++ dst_release((*pskb)->dst); ++ (*pskb)->dst = &rt->u.dst; ++ } else { ++ /* non-local src, find valid iif to satisfy ++ * rp-filter when calling ip_route_input. */ ++ key.dst = iph->saddr; ++ if (ip_route_output_key(&rt, &key) != 0) ++ return -1; ++ ++ odst = (*pskb)->dst; ++ if (ip_route_input(*pskb, iph->daddr, iph->saddr, ++ RT_TOS(iph->tos), rt->u.dst.dev) != 0) { ++ dst_release(&rt->u.dst); ++ return -1; ++ } ++ dst_release(&rt->u.dst); ++ dst_release(odst); ++ } ++ ++ if ((*pskb)->dst->error) ++ return -1; + + /* Change in oif may mean change in hh_len. */ +- if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) { ++ hh_len = (*pskb)->dst->dev->hard_header_len; ++ if (skb_headroom(*pskb) < hh_len) { + struct sk_buff *nskb; + +- nskb = skb_realloc_headroom(*pskb, +- (*pskb)->dst->dev->hard_header_len); +- if (!nskb) { +- err = -ENOMEM; +- goto out; +- } ++ nskb = skb_realloc_headroom(*pskb, hh_len); ++ if (!nskb) ++ return -1; + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + } + +-out: +- if (dev_src) +- dev_put(dev_src); +- +- return err; ++ return 0; + } + #endif /*CONFIG_INET*/ + ++/* Internal logging interface, which relies on the real ++ LOG target modules */ ++ ++#define NF_LOG_PREFIXLEN 128 ++ ++static struct nf_logging_t nf_logging[NPROTO] = {}; ++static int reported = 0; ++ ++void nf_log_register(int pf, const struct nf_logging_t *logging) ++{ ++ br_write_lock_bh(BR_NETPROTO_LOCK); ++ if (!nf_logging[pf].nf_log_packet) { ++ nf_logging[pf].nf_log_packet = logging->nf_log_packet; ++ nf_logging[pf].nf_log = logging->nf_log; ++ } ++ br_write_unlock_bh(BR_NETPROTO_LOCK); ++} ++ ++void nf_log_unregister(int pf, const struct nf_logging_t *logging) ++{ ++ br_write_lock_bh(BR_NETPROTO_LOCK); ++ if (nf_logging[pf].nf_log_packet == logging->nf_log_packet) { ++ nf_logging[pf].nf_log_packet = NULL; ++ nf_logging[pf].nf_log = NULL; ++ } ++ br_write_unlock_bh(BR_NETPROTO_LOCK); ++} ++ ++void nf_log_packet(int pf, ++ struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const char *fmt, ...) ++{ ++ va_list args; ++ char prefix[NF_LOG_PREFIXLEN]; ++ ++ if (nf_logging[pf].nf_log_packet) { ++ va_start(args, fmt); ++ vsnprintf(prefix, sizeof(prefix), fmt, args); ++ va_end(args); ++ nf_logging[pf].nf_log_packet(pskb, hooknum, in, out, prefix); ++ } else if (!reported) { ++ printk(KERN_WARNING "nf_log_packet: can\'t log yet, " ++ "no backend logging module loaded in!\n"); ++ reported++; ++ } ++} ++ ++void nf_log(int pf, ++ char *pfh, size_t len, ++ const char *fmt, ...) ++{ ++ va_list args; ++ char prefix[NF_LOG_PREFIXLEN]; ++ ++ if (nf_logging[pf].nf_log) { ++ va_start(args, fmt); ++ vsnprintf(prefix, sizeof(prefix), fmt, args); ++ va_end(args); ++ nf_logging[pf].nf_log(pfh, len, prefix); ++ } else if (!reported) { ++ printk(KERN_WARNING "nf_log: can\'t log yet, " ++ "no backend logging module loaded in!\n"); ++ reported++; ++ } ++} ++ + /* This does not belong here, but ipt_REJECT needs it if connection + tracking in use: without this, connection may not be in hash table, + and hence manufactured ICMP or RST packets will not be associated +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/Config.in linux-2.4.20/net/ipv4/netfilter/Config.in +--- linux-2.4.20.org/net/ipv4/netfilter/Config.in Wed Sep 24 08:52:39 2003 ++++ linux-2.4.20/net/ipv4/netfilter/Config.in Wed Sep 24 09:18:12 2003 +@@ -4,10 +4,29 @@ + mainmenu_option next_comment + comment ' IP: Netfilter Configuration' + ++tristate 'Netfilter netlink interface' CONFIG_IP_NF_NETLINK ++ + tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK + if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then ++ if [ "$CONFIG_IP_NF_CONNTRACK" = "y" ]; then ++ dep_tristate ' Connection tracking netlink interface' CONFIG_IP_NF_NETLINK_CONNTRACK $CONFIG_IP_NF_NETLINK ++ else ++ dep_tristate ' Connection tracking netlink interface' CONFIG_IP_NF_NETLINK_CONNTRACK $CONFIG_IP_NF_CONNTRACK ++ fi + dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' talk protocol support' CONFIG_IP_NF_TALK $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' RSH protocol support' CONFIG_IP_NF_RSH $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' Eggdrop bot support' CONFIG_IP_NF_EGG $CONFIG_IP_NF_CONNTRACK ++ bool ' Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK ++ dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK + dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' Quake III protocol support' CONFIG_IP_NF_QUAKE3 $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE ++ dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' CuSeeMe protocol support' CONFIG_IP_NF_CUSEEME $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -15,39 +34,85 @@ + fi + tristate 'IP tables support (required for filtering/masq/NAT)' CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ tristate 'raw table support (required for NOTRACK/TRACE)' CONFIG_IP_NF_RAW $CONFIG_IP_NF_IPTABLES ++ fi + # The simple matches. ++ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then ++ dep_tristate ' RPC match support' CONFIG_IP_NF_MATCH_RPC $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES ++ fi + dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $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 ' IP range match support' CONFIG_IP_NF_MATCH_IPRANGE $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' 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 ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' random match support' CONFIG_IP_NF_MATCH_RANDOM $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' psd match support' CONFIG_IP_NF_MATCH_PSD $CONFIG_IP_NF_IPTABLES ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' OSF match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OSF $CONFIG_IP_NF_IPTABLES ++ fi ++ dep_tristate ' Nth match support' CONFIG_IP_NF_MATCH_NTH $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' IPV4OPTIONS match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_IPV4OPTIONS $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' fuzzy match support' CONFIG_IP_NF_MATCH_FUZZY $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES + dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES + + dep_tristate ' DSCP match support' CONFIG_IP_NF_MATCH_DSCP $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 ' U32 match support' CONFIG_IP_NF_MATCH_U32 $CONFIG_IP_NF_U32 + dep_tristate ' TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' address type match support' CONFIG_IP_NF_MATCH_ADDRTYPE $CONFIG_IP_NF_IPTABLES + dep_tristate ' tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' realm match support' CONFIG_IP_NF_MATCH_REALM $CONFIG_IP_NF_IPTABLES + dep_tristate ' stealth match support' CONFIG_IP_NF_MATCH_STEALTH $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then + dep_tristate ' Helper match support' CONFIG_IP_NF_MATCH_HELPER $CONFIG_IP_NF_IPTABLES + fi + 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 ++ 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_CONNLIMIT $CONFIG_IP_NF_IPTABLES + dep_tristate ' Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $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 ' String match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_STRING $CONFIG_IP_NF_IPTABLES + dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES + fi + # The targets ++ if [ "$CONFIG_IP_NF_RAW" != "n" ]; then ++ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then ++ dep_tristate ' NOTRACK target support' CONFIG_IP_NF_TARGET_NOTRACK $CONFIG_IP_NF_RAW ++ fi ++ dep_tristate ' TRACE target support' CONFIG_IP_NF_TARGET_TRACE $CONFIG_IP_NF_RAW ++ if [ "$CONFIG_IP_NF_TARGET_TRACE" != "n" ]; then ++ define_bool CONFIG_IP_NF_TARGET_TRACE_NEEDED y ++ fi ++ fi + 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 ++ dep_tristate ' TARPIT target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_TARPIT $CONFIG_IP_NF_FILTER + fi + fi + +@@ -57,6 +122,45 @@ + 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 ++ if [ "$CONFIG_IP_NF_H323" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 m ++ else ++ if [ "$CONFIG_IP_NF_H323" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 $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 ++ if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_AMANDA m ++ else ++ if [ "$CONFIG_IP_NF_AMANDA" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT ++ fi ++ fi ++ if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_PPTP m ++ else ++ if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT ++ fi ++ fi ++ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m ++ else ++ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT ++ fi ++ fi + bool ' NAT of local connections (READ HELP)' 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 +@@ -68,6 +172,27 @@ + define_tristate CONFIG_IP_NF_NAT_IRC $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_QUAKE3" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_QUAKE3 m ++ else ++ if [ "$CONFIG_IP_NF_QUAKE3" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_QUAKE3 $CONFIG_IP_NF_NAT ++ fi ++ fi ++ if [ "$CONFIG_IP_NF_MMS" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_MMS m ++ else ++ if [ "$CONFIG_IP_NF_MMS" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT ++ fi ++ fi ++ if [ "$CONFIG_IP_NF_CUSEEME" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_CUSEEME m ++ else ++ if [ "$CONFIG_IP_NF_CUSEEME" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_CUSEEME $CONFIG_IP_NF_NAT ++ fi ++ fi + # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), + # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. + if [ "$CONFIG_IP_NF_FTP" = "m" ]; then +@@ -77,6 +202,13 @@ + 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 + +@@ -88,8 +220,19 @@ + 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 ++ dep_tristate ' ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_MANGLE ++ ++ dep_tristate ' IPMARK target support' CONFIG_IP_NF_TARGET_IPMARK $CONFIG_IP_NF_MANGLE ++ dep_tristate ' IMQ target support' CONFIG_IP_NF_TARGET_IMQ $CONFIG_IP_NF_MANGLE ++ dep_tristate ' CLASSIFY target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_CLASSIFY $CONFIG_IP_NF_FILTER + fi + dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' XOR target support' CONFIG_IP_NF_TARGET_XOR $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' TCPLAG target support' CONFIG_IP_NF_TARGET_TCPLAG $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 ++ dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES + dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES + dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES + fi +@@ -98,6 +241,9 @@ + if [ "$CONFIG_IP_NF_ARPTABLES" != "n" ]; then + dep_tristate ' ARP packet filtering' CONFIG_IP_NF_ARPFILTER $CONFIG_IP_NF_ARPTABLES + fi ++if [ "$CONFIG_IP_NF_ARPTABLES" != "n" ]; then ++ dep_tristate ' ARP payload mangling' CONFIG_IP_NF_ARP_MANGLE $CONFIG_IP_NF_ARPTABLES ++fi + + # Backwards compatibility modules: only if you don't build in the others. + if [ "$CONFIG_IP_NF_CONNTRACK" != "y" ]; then +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/Makefile linux-2.4.20/net/ipv4/netfilter/Makefile +--- linux-2.4.20.org/net/ipv4/netfilter/Makefile Wed Sep 24 08:52:39 2003 ++++ linux-2.4.20/net/ipv4/netfilter/Makefile Wed Sep 24 09:18:13 2003 +@@ -28,23 +28,85 @@ + ipfwadm-objs := $(ip_nf_compat-objs) ipfwadm_core.o + ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o + ++# netfilter netlink interface ++obj-$(CONFIG_IP_NF_NETLINK) += nfnetlink.o ++ifdef CONFIG_IP_NF_NETLINK ++ export-objs += nfnetlink.o ++endif ++ ++# nfnetlink modules ++obj-$(CONFIG_IP_NF_NETLINK_CONNTRACK) += nfnetlink_conntrack.o ++ + # connection tracking + obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o + ++# talk protocol support ++obj-$(CONFIG_IP_NF_TALK) += ip_conntrack_talk.o ++ifdef CONFIG_IP_NF_TALK ++ export-objs += ip_conntrack_talk.o ++endif ++obj-$(CONFIG_IP_NF_NAT_TALK) += ip_nat_talk.o ++ ++ ++# H.323 support ++obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o ++ifdef CONFIG_IP_NF_H323 ++ export-objs += ip_conntrack_h323.o ++endif ++obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o ++ ++ ++# connection tracking protocol helpers ++obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o ++ifdef CONFIG_IP_NF_CT_PROTO_GRE ++ export-objs += ip_conntrack_proto_gre.o ++endif ++ ++# NAT protocol helpers ++obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o ++ + # connection tracking helpers ++obj-$(CONFIG_IP_NF_QUAKE3) += ip_conntrack_quake3.o ++ifdef CONFIG_IP_NF_NAT_QUAKE3 ++ export-objs += ip_conntrack_quake3.o ++endif ++obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o ++ifdef CONFIG_IP_NF_NAT_PPTP ++ export-objs += ip_conntrack_pptp.o ++endif ++obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o ++ifdef CONFIG_IP_NF_MMS ++ export-objs += ip_conntrack_mms.o ++endif ++obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o ++ifdef CONFIG_IP_NF_AMANDA ++ export-objs += ip_conntrack_amanda.o ++endif ++ ++obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o + obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o +-ifdef CONFIG_IP_NF_NAT_FTP ++obj-$(CONFIG_IP_NF_RSH) += ip_conntrack_rsh.o ++ ++obj-$(CONFIG_IP_NF_EGG) += ip_conntrack_egg.o ++ ++ifdef CONFIG_IP_NF_FTP + export-objs += ip_conntrack_ftp.o + endif + + obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o +-ifdef CONFIG_IP_NF_NAT_IRC ++ifdef CONFIG_IP_NF_IRC + export-objs += ip_conntrack_irc.o + endif + + # NAT helpers ++obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o ++obj-$(CONFIG_IP_NF_NAT_CUSEEME) += ip_nat_cuseeme.o ++obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o ++obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o + obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o + obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o ++obj-$(CONFIG_IP_NF_NAT_QUAKE3) += ip_nat_quake3.o ++obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +@@ -53,46 +115,103 @@ + obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o + obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o + obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o ++obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o + + # matches ++obj-$(CONFIG_IP_NF_MATCH_RPC) += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o ipt_rpc.o ++export-objs += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o ++ + obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o + obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o ++obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o ++obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.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_CONDITION) += ipt_condition.o ++ ++obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o ++ ++ ++obj-$(CONFIG_IP_NF_MATCH_RANDOM) += ipt_random.o ++ ++obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o ++ ++obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o ++ ++ ++obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o ++ ++obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o ++ ++ ++obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o ++ ++obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o ++ + obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o + obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.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_U32) += ipt_u32.o ++ ++ + obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o + obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o ++obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o ++obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o + obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o + obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o ++obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o + obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o ++obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o ++obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o + obj-$(CONFIG_IP_NF_MATCH_STEALTH) += ipt_stealth.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_TARPIT) += ipt_TARPIT.o ++obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o + obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o + obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o + obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o + obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o ++obj-$(CONFIG_IP_NF_TARGET_IPMARK) += ipt_IPMARK.o ++obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o + obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o + obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o ++obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.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_XOR) += ipt_XOR.o ++obj-$(CONFIG_IP_NF_TARGET_TCPLAG) += ipt_TCPLAG.o ++obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.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_ULOG) += ipt_ULOG.o + obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o ++obj-$(CONFIG_IP_NF_TARGET_TRACE) += ipt_TRACE.o ++obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o + + # generic ARP tables + obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o ++obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o + + # just filtering instance of ARP tables for now + obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/arp_tables.c linux-2.4.20/net/ipv4/netfilter/arp_tables.c +--- linux-2.4.20.org/net/ipv4/netfilter/arp_tables.c Sat Aug 3 00:39:46 2002 ++++ linux-2.4.20/net/ipv4/netfilter/arp_tables.c Wed Sep 24 09:16:17 2003 +@@ -136,6 +136,7 @@ + dprintf("ARP hardware address length mismatch.\n"); + dprintf("ar_hln: %02x info->arhln: %02x info->arhln_mask: %02x\n", + arphdr->ar_hln, arpinfo->arhln, arpinfo->arhln_mask); ++ return 0; + } + + src_devaddr = arpptr; +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/arpt_mangle.c linux-2.4.20/net/ipv4/netfilter/arpt_mangle.c +--- linux-2.4.20.org/net/ipv4/netfilter/arpt_mangle.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/arpt_mangle.c Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,101 @@ ++/* module that allows mangling of the arp payload */ ++#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 arpt_mangle *mangle = targinfo; ++ struct arphdr *arp; ++ unsigned char *arpptr; ++ int pln, hln; ++ ++ if (skb_shared(*pskb) || skb_cloned(*pskb)) { ++ struct sk_buff *nskb; ++ ++ nskb = skb_copy(*pskb, GFP_ATOMIC); ++ if (!nskb) ++ return NF_DROP; ++ if ((*pskb)->sk) ++ skb_set_owner_w(nskb, (*pskb)->sk); ++ kfree_skb(*pskb); ++ *pskb = nskb; ++ } ++ ++ arp = (*pskb)->nh.arph; ++ arpptr = (*pskb)->nh.raw + sizeof(*arp); ++ pln = arp->ar_pln; ++ hln = arp->ar_hln; ++ /* We assume that hln was checked in the match */ ++ if (mangle->flags & ARPT_MANGLE_SDEV) { ++ if (ARPT_DEV_ADDR_LEN_MAX < hln || ++ (arpptr + hln > (**pskb).tail)) ++ return NF_DROP; ++ memcpy(arpptr, mangle->src_devaddr, hln); ++ } ++ arpptr += hln; ++ if (mangle->flags & ARPT_MANGLE_SIP) { ++ if (ARPT_MANGLE_ADDR_LEN_MAX < pln || ++ (arpptr + pln > (**pskb).tail)) ++ return NF_DROP; ++ memcpy(arpptr, &mangle->u_s.src_ip, pln); ++ } ++ arpptr += pln; ++ if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (ARPT_DEV_ADDR_LEN_MAX < hln || ++ (arpptr + hln > (**pskb).tail)) ++ return NF_DROP; ++ memcpy(arpptr, mangle->tgt_devaddr, hln); ++ } ++ arpptr += hln; ++ if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (ARPT_MANGLE_ADDR_LEN_MAX < pln || ++ (arpptr + pln > (**pskb).tail)) ++ return NF_DROP; ++ memcpy(arpptr, &mangle->u_t.tgt_ip, pln); ++ } ++ return mangle->target; ++} ++ ++static int ++checkentry(const char *tablename, const struct arpt_entry *e, void *targinfo, ++ unsigned int targinfosize, unsigned int hook_mask) ++{ ++ const struct arpt_mangle *mangle = targinfo; ++ ++ if (mangle->flags & ~ARPT_MANGLE_MASK || ++ !(mangle->flags & ARPT_MANGLE_MASK)) ++ return 0; ++ ++ if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT && ++ mangle->target != ARPT_CONTINUE) ++ return 0; ++ return 1; ++} ++ ++static struct arpt_target arpt_mangle_reg ++= { ++ .name = "mangle", ++ .target = target, ++ .checkentry = checkentry, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ if (arpt_register_target(&arpt_mangle_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ arpt_unregister_target(&arpt_mangle_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_amanda.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_amanda.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_amanda.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_amanda.c Wed Sep 24 09:16:24 2003 +@@ -0,0 +1,234 @@ ++/* Amanda extension for IP connection tracking, Version 0.2 ++ * (C) 2002 by Brian J. Murrell ++ * based on HW's ip_conntrack_irc.c as well as other modules ++ * ++ * 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_conntrack_amanda.o [master_timeout=n] ++ * ++ * Where master_timeout is the timeout (in seconds) of the master ++ * connection (port 10080). This defaults to 5 minutes but if ++ * your clients take longer than 5 minutes to do their work ++ * before getting back to the Amanda server, you can increase ++ * this value. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++static unsigned int master_timeout = 300; ++ ++MODULE_AUTHOR("Brian J. Murrell "); ++MODULE_DESCRIPTION("Amanda connection tracking module"); ++MODULE_LICENSE("GPL"); ++MODULE_PARM(master_timeout, "i"); ++MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); ++ ++DECLARE_LOCK(ip_amanda_lock); ++struct module *ip_conntrack_amanda = THIS_MODULE; ++ ++#define MAXMATCHLEN 6 ++struct conn conns[NUM_MSGS] = { ++ {"DATA ", 5}, ++ {"MESG ", 5}, ++ {"INDEX ", 6}, ++}; ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++ ++/* 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) ++{ ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ u_int32_t udplen = len - iph->ihl * 4; ++ u_int32_t datalen = udplen - sizeof(struct udphdr); ++ char *data = (char *)udph + sizeof(struct udphdr); ++ char *datap = data; ++ char *data_limit = (char *) data + datalen; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_amanda *info = ++ (struct ip_ct_amanda *)&ct->help.ct_ftp_info; ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* increase the UDP timeout of the master connection as replies from ++ * Amanda clients to the server can be quite delayed */ ++ ip_ct_refresh(ct, master_timeout * HZ); ++ ++ /* If packet is coming from Amanda server */ ++ if (dir == IP_CT_DIR_ORIGINAL) ++ return NF_ACCEPT; ++ ++ /* Not whole UDP header? */ ++ if (udplen < sizeof(struct udphdr)) { ++ printk("ip_conntrack_amanda_help: udplen = %u\n", ++ (unsigned)udplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ 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; ++ } ++ ++ /* Search for the CONNECT string */ ++ while (data < data_limit) { ++ if (!memcmp(data, "CONNECT ", 8)) { ++ break; ++ } ++ data++; ++ } ++ if (memcmp(data, "CONNECT ", 8)) ++ return NF_ACCEPT; ++ ++ DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection " ++ "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), htons(udph->source), ++ NIPQUAD(iph->daddr), htons(udph->dest)); ++ data += 8; ++ while (*data != 0x0a && data < data_limit) { ++ ++ int i; ++ ++ for (i = 0; i < NUM_MSGS; i++) { ++ if (!memcmp(data, conns[i].match, ++ conns[i].matchlen)) { ++ ++ char *portchr; ++ struct ip_conntrack_expect expect; ++ struct ip_ct_amanda_expect ++ *exp_amanda_info = ++ &expect.help.exp_amanda_info; ++ ++ memset(&expect, 0, sizeof(expect)); ++ ++ data += conns[i].matchlen; ++ /* this is not really tcp, but let's steal an ++ * idea from a tcp stream helper :-) ++ */ ++ // XXX expect.seq = data - datap; ++ exp_amanda_info->offset = data - datap; ++// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, datap, expect.seq); ++DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, datap, exp_amanda_info->offset); ++ portchr = data; ++ exp_amanda_info->port = ++ simple_strtoul(data, &data, 10); ++ exp_amanda_info->len = data - portchr; ++ ++ /* eat whitespace */ ++ while (*data == ' ') ++ data++; ++ DEBUGP ("ip_conntrack_amanda_help: " ++ "CONNECT %s request with port " ++ "%u found\n", conns[i].match, ++ exp_amanda_info->port); ++ ++ LOCK_BH(&ip_amanda_lock); ++ ++ expect.tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, ++ { 0 } }, ++ { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, ++ { htons(exp_amanda_info->port) }, ++ IPPROTO_TCP }}); ++ expect.mask = ((struct ip_conntrack_tuple) ++ { { 0, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ expect.expectfn = NULL; ++ ++ DEBUGP ("ip_conntrack_amanda_help: " ++ "expect_related: %u.%u.%u.%u:%u - " ++ "%u.%u.%u.%u:%u\n", ++ NIPQUAD(expect.tuple.src.ip), ++ ntohs(expect.tuple.src.u.tcp.port), ++ NIPQUAD(expect.tuple.dst.ip), ++ ntohs(expect.tuple.dst.u.tcp.port)); ++ if (ip_conntrack_expect_related(ct, &expect) == ++ -EEXIST) { ++ ; ++ /* this must be a packet being resent */ ++ /* XXX - how do I get the ++ * ip_conntrack_expect that ++ * already exists so that I can ++ * update the .seq so that the ++ * nat module rewrites the port ++ * numbers? ++ * Perhaps I should use the ++ * exp_amanda_info instead of ++ * .seq. ++ */ ++ } ++ UNLOCK_BH(&ip_amanda_lock); ++ } /* if memcmp(conns) */ ++ } /* for .. NUM_MSGS */ ++ data++; ++ } /* while (*data != 0x0a && data < data_limit) */ ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper amanda_helper; ++ ++static void fini(void) ++{ ++ DEBUGP("ip_ct_amanda: unregistering helper for port 10080\n"); ++ ip_conntrack_helper_unregister(&amanda_helper); ++} ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ amanda_helper.tuple.src.u.udp.port = htons(10080); ++ amanda_helper.tuple.dst.protonum = IPPROTO_UDP; ++ amanda_helper.mask.src.u.udp.port = 0xFFFF; ++ amanda_helper.mask.dst.protonum = 0xFFFF; ++ amanda_helper.max_expected = NUM_MSGS; ++ amanda_helper.timeout = 180; ++ amanda_helper.flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ amanda_helper.me = ip_conntrack_amanda; ++ amanda_helper.help = help; ++ amanda_helper.name = "amanda"; ++ ++ DEBUGP("ip_ct_amanda: registering helper for port 10080\n"); ++ ++ ret = ip_conntrack_helper_register(&amanda_helper); ++ ++ if (ret) { ++ printk("ip_ct_amanda: ERROR registering helper\n"); ++ fini(); ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(ip_amanda_lock); ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_core.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_core.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_core.c Wed Sep 24 09:18:16 2003 +@@ -4,6 +4,7 @@ + + /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General + * Public Licence. ++ * (C) 2000-2003 by the netfilter core team + * + * 23 Apr 2001: Harald Welte + * - new API and handling of conntrack/nat helpers +@@ -11,11 +12,10 @@ + * 16 Jul 2002: Harald Welte + * - add usage/reference counts to ip_conntrack_expect + * - export ip_conntrack[_expect]_{find_get,put} functions ++ * 05 Aug 2002: Harald Welte ++ * - added DocBook-style comments for public API + * */ + +-#ifdef MODULE +-#define __NO_VERSION__ +-#endif + #include + #include + #include +@@ -31,6 +31,8 @@ + #include + #include + #include ++#include ++#include + /* For ERR_PTR(). Yeah, I know... --RR */ + #include + +@@ -61,10 +63,11 @@ + 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; ++struct ip_conntrack ip_conntrack_untracked; + + extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; + +@@ -87,6 +90,10 @@ + return p; + } + ++/** ++ * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number ++ * @protocol: protocol number ++ */ + struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol) + { + struct ip_conntrack_protocol *p; +@@ -107,20 +114,19 @@ + nf_conntrack_put(&ct->infos[0]); + } + +-static inline u_int32_t ++static int ip_conntrack_hash_rnd_initted; ++static unsigned int ip_conntrack_hash_rnd; ++ ++static u_int32_t + hash_conntrack(const struct ip_conntrack_tuple *tuple) + { + #if 0 + dump_tuple(tuple); + #endif +- /* ntohl because more differences in low bits. */ +- /* To ensure that halves of the same connection don't hash +- clash, we add the source per-proto again. */ +- return (ntohl(tuple->src.ip + tuple->dst.ip +- + tuple->src.u.all + tuple->dst.u.all +- + tuple->dst.protonum) +- + ntohs(tuple->src.u.all)) +- % ip_conntrack_htable_size; ++ return (jhash_3words(tuple->src.ip, ++ (tuple->dst.ip ^ tuple->dst.protonum), ++ (tuple->src.u.all | (tuple->dst.u.all << 16)), ++ ip_conntrack_hash_rnd) % ip_conntrack_htable_size); + } + + inline int +@@ -144,12 +150,22 @@ + tuple->dst.ip = iph->daddr; + tuple->dst.protonum = iph->protocol; + ++ tuple->src.u.all = tuple->dst.u.all = 0; ++ + ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl, + len - 4*iph->ihl, + tuple); + return ret; + } + ++int ++ip_conntrack_get_tuple(const struct iphdr *iph, size_t len, ++ struct ip_conntrack_tuple *tuple, ++ struct ip_conntrack_protocol *protocol) ++{ ++ return get_tuple(iph, len, tuple, protocol); ++} ++ + static int + invert_tuple(struct ip_conntrack_tuple *inverse, + const struct ip_conntrack_tuple *orig, +@@ -159,6 +175,8 @@ + inverse->dst.ip = orig->src.ip; + inverse->dst.protonum = orig->dst.protonum; + ++ inverse->src.u.all = inverse->dst.u.all = 0; ++ + return protocol->invert_tuple(inverse, orig); + } + +@@ -176,8 +194,8 @@ + static void + destroy_expect(struct ip_conntrack_expect *exp) + { +- DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(exp->use)); +- IP_NF_ASSERT(atomic_read(exp->use)); ++ DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use)); ++ IP_NF_ASSERT(atomic_read(&exp->use)); + IP_NF_ASSERT(!timer_pending(&exp->timeout)); + + kfree(exp); +@@ -259,16 +277,14 @@ + } + + /* delete all unconfirmed expectations for this conntrack */ +-static void remove_expectations(struct ip_conntrack *ct) ++static void remove_expectations(struct ip_conntrack *ct, int drop_refcount) + { + struct list_head *exp_entry, *next; + struct ip_conntrack_expect *exp; + + DEBUGP("remove_expectations(%p)\n", ct); + +- for (exp_entry = ct->sibling_list.next; +- exp_entry != &ct->sibling_list; exp_entry = next) { +- next = exp_entry->next; ++ list_for_each_safe(exp_entry, next, &ct->sibling_list) { + exp = list_entry(exp_entry, struct ip_conntrack_expect, + expected_list); + +@@ -276,6 +292,11 @@ + * the un-established ones only */ + if (exp->sibling) { + DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct); ++ if (drop_refcount) { ++ /* Indicate that this expectations parent is dead */ ++ ip_conntrack_put(exp->expectant); ++ exp->expectant = NULL; ++ } + continue; + } + +@@ -290,20 +311,18 @@ + static void + clean_from_lists(struct ip_conntrack *ct) + { ++ unsigned int ho, hr; ++ + DEBUGP("clean_from_lists(%p)\n", ct); + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); +- /* Remove from both hash lists: must not NULL out next ptrs, +- otherwise we'll look unconfirmed. Fortunately, LIST_DELETE +- doesn't do this. --RR */ +- LIST_DELETE(&ip_conntrack_hash +- [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)], +- &ct->tuplehash[IP_CT_DIR_ORIGINAL]); +- LIST_DELETE(&ip_conntrack_hash +- [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)], +- &ct->tuplehash[IP_CT_DIR_REPLY]); ++ ++ ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]); ++ LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); + + /* Destroy all un-established, pending expectations */ +- remove_expectations(ct); ++ remove_expectations(ct, 1); + } + + static void +@@ -316,9 +335,6 @@ + IP_NF_ASSERT(atomic_read(&nfct->use) == 0); + IP_NF_ASSERT(!timer_pending(&ct->timeout)); + +- if (ct->master && master_ct(ct)) +- ip_conntrack_put(master_ct(ct)); +- + /* To make sure we don't get any weird locking issues here: + * destroy_conntrack() MUST NOT be called with a write lock + * to ip_conntrack_lock!!! -HW */ +@@ -330,11 +346,17 @@ + ip_conntrack_destroyed(ct); + + WRITE_LOCK(&ip_conntrack_lock); ++ /* Delete us from our own list to prevent corruption later */ ++ list_del(&ct->sibling_list); ++ + /* Delete our master expectation */ + if (ct->master) { +- /* can't call __unexpect_related here, +- * since it would screw up expect_list */ +- list_del(&ct->master->expected_list); ++ if (ct->master->expectant) { ++ /* can't call __unexpect_related here, ++ * since it would screw up expect_list */ ++ list_del(&ct->master->expected_list); ++ ip_conntrack_put(ct->master->expectant); ++ } + kfree(ct->master); + } + WRITE_UNLOCK(&ip_conntrack_lock); +@@ -344,7 +366,7 @@ + atomic_dec(&ip_conntrack_count); + } + +-static void death_by_timeout(unsigned long ul_conntrack) ++void ip_ct_death_by_timeout(unsigned long ul_conntrack) + { + struct ip_conntrack *ct = (void *)ul_conntrack; + +@@ -369,16 +391,24 @@ + const struct ip_conntrack *ignored_conntrack) + { + struct ip_conntrack_tuple_hash *h; ++ unsigned int hash = hash_conntrack(tuple); + + MUST_BE_READ_LOCKED(&ip_conntrack_lock); +- h = LIST_FIND(&ip_conntrack_hash[hash_conntrack(tuple)], ++ h = LIST_FIND(&ip_conntrack_hash[hash], + conntrack_tuple_cmp, + struct ip_conntrack_tuple_hash *, + tuple, ignored_conntrack); + return h; + } + +-/* Find a connection corresponding to a tuple. */ ++/** ++ * ip_conntrack_find_get - find conntrack according to tuple ++ * @tuple: conntrack tuple for which we search conntrack ++ * @ignored_conntrack: ignore this conntrack during search ++ * ++ * This function increments the reference count of the found ++ * conntrack (if any). ++ */ + struct ip_conntrack_tuple_hash * + ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, + const struct ip_conntrack *ignored_conntrack) +@@ -406,7 +436,14 @@ + return ct; + } + +-/* Return conntrack and conntrack_info given skb->nfct->master */ ++/** ++ * ip_conntrack_get - Return conntrack and conntrack_info for given skb ++ * @skb: skb for which we want to find conntrack and conntrack_info ++ * @ctinfo: pointer to ctinfo, used as return value ++ * ++ * This function resolves the respective conntrack and conntrack_info ++ * structures for the connection this packet (skb) is part of. ++ */ + struct ip_conntrack * + ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) + { +@@ -467,6 +504,7 @@ + ct->timeout.expires += jiffies; + add_timer(&ct->timeout); + atomic_inc(&ct->ct_general.use); ++ set_bit(IPS_CONFIRMED_BIT, &ct->status); + WRITE_UNLOCK(&ip_conntrack_lock); + return NF_ACCEPT; + } +@@ -475,8 +513,14 @@ + return NF_DROP; + } + +-/* Returns true if a connection correspondings to the tuple (required +- for NAT). */ ++/** ++ * ip_conntrack_tuple_taken - Find out if tuple is already in use ++ * @tuple: tuple to be used for this test ++ * @ignored_conntrack: conntrack which is excluded from result ++ * ++ * This function is called by the NAT code in order to find out if ++ * a particular tuple is already in use by some connection. ++ */ + int + ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, + const struct ip_conntrack *ignored_conntrack) +@@ -585,7 +629,7 @@ + connection. Too bad: we're in trouble anyway. */ + static inline int unreplied(const struct ip_conntrack_tuple_hash *i) + { +- return !(i->ctrack->status & IPS_ASSURED); ++ return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status)); + } + + static int early_drop(struct list_head *chain) +@@ -595,7 +639,7 @@ + int dropped = 0; + + READ_LOCK(&ip_conntrack_lock); +- h = LIST_FIND(chain, unreplied, struct ip_conntrack_tuple_hash *); ++ h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *); + if (h) + atomic_inc(&h->ctrack->ct_general.use); + READ_UNLOCK(&ip_conntrack_lock); +@@ -604,7 +648,7 @@ + return dropped; + + if (del_timer(&h->ctrack->timeout)) { +- death_by_timeout((unsigned long)h->ctrack); ++ ip_ct_death_by_timeout((unsigned long)h->ctrack); + dropped = 1; + } + ip_conntrack_put(h->ctrack); +@@ -616,7 +660,13 @@ + { + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); + } +- ++/** ++ * ip_ct_find_helper - Find application helper according to tuple ++ * @tuple: tuple for which helper needs to be found ++ * ++ * This function is used to determine if any registered conntrack helper ++ * is to be used for the given tuple. ++ */ + struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple) + { + return LIST_FIND(&helpers, helper_cmp, +@@ -633,11 +683,16 @@ + { + struct ip_conntrack *conntrack; + struct ip_conntrack_tuple repl_tuple; +- size_t hash, repl_hash; ++ size_t hash; + struct ip_conntrack_expect *expected; + int i; + static unsigned int drop_next = 0; + ++ if (!ip_conntrack_hash_rnd_initted) { ++ get_random_bytes(&ip_conntrack_hash_rnd, 4); ++ ip_conntrack_hash_rnd_initted = 1; ++ } ++ + hash = hash_conntrack(tuple); + + if (ip_conntrack_max && +@@ -661,7 +716,6 @@ + DEBUGP("Can't invert tuple.\n"); + return NULL; + } +- repl_hash = hash_conntrack(&repl_tuple); + + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC); + if (!conntrack) { +@@ -686,13 +740,10 @@ + /* Don't set timer yet: wait for confirmation */ + init_timer(&conntrack->timeout); + conntrack->timeout.data = (unsigned long)conntrack; +- conntrack->timeout.function = death_by_timeout; ++ conntrack->timeout.function = ip_ct_death_by_timeout; + + INIT_LIST_HEAD(&conntrack->sibling_list); + +- /* Mark clearly that it's not in the hash table. */ +- conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL; +- + WRITE_LOCK(&ip_conntrack_lock); + /* Need finding and deleting of expected ONLY if we win race */ + READ_LOCK(&ip_conntrack_expect_tuple_lock); +@@ -700,6 +751,14 @@ + struct ip_conntrack_expect *, tuple); + READ_UNLOCK(&ip_conntrack_expect_tuple_lock); + ++ /* If master is not in hash table yet (ie. packet hasn't left ++ this machine yet), how can other end know about expected? ++ Hence these are not the droids you are looking for (if ++ master ct never got confirmed, we'd hold a reference to it ++ and weird things would happen to future packets). */ ++ if (expected && !is_confirmed(expected->expectant)) ++ expected = NULL; ++ + /* Look up the conntrack helper for master connections only */ + if (!expected) + conntrack->helper = ip_ct_find_helper(&repl_tuple); +@@ -710,19 +769,17 @@ + && ! del_timer(&expected->timeout)) + expected = NULL; + +- /* If master is not in hash table yet (ie. packet hasn't left +- this machine yet), how can other end know about expected? +- Hence these are not the droids you are looking for (if +- master ct never got confirmed, we'd hold a reference to it +- and weird things would happen to future packets). */ +- if (expected && is_confirmed(expected->expectant)) { ++ if (expected) { + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", + conntrack, expected); + /* Welcome, Mr. Bond. We've been expecting you... */ + IP_NF_ASSERT(master_ct(conntrack)); +- conntrack->status = IPS_EXPECTED; ++ __set_bit(IPS_EXPECTED_BIT, &conntrack->status); + conntrack->master = expected; + expected->sibling = conntrack; ++#if CONFIG_IP_NF_CONNTRACK_MARK ++ conntrack->mark = expected->expectant->mark; ++#endif + LIST_DELETE(&ip_conntrack_expect_list, expected); + expected->expectant->expecting--; + nf_conntrack_get(&master_ct(conntrack)->infos[0]); +@@ -768,11 +825,11 @@ + *set_reply = 1; + } else { + /* Once we've had two way comms, always ESTABLISHED. */ +- if (h->ctrack->status & IPS_SEEN_REPLY) { ++ if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) { + DEBUGP("ip_conntrack_in: normal packet for %p\n", + h->ctrack); + *ctinfo = IP_CT_ESTABLISHED; +- } else if (h->ctrack->status & IPS_EXPECTED) { ++ } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) { + DEBUGP("ip_conntrack_in: related packet for %p\n", + h->ctrack); + *ctinfo = IP_CT_RELATED; +@@ -907,6 +964,14 @@ + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask); + } + ++/** ++ * ip_conntrack_unexpect_related - Unexpect a related connection ++ * @expect: expecattin to be removed ++ * ++ * This function removes an existing expectation, that has not yet been ++ * confirmed (i.e. expectation was issued, but expected connection didn't ++ * arrive yet) ++ */ + inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect) + { + WRITE_LOCK(&ip_conntrack_lock); +@@ -924,7 +989,20 @@ + WRITE_UNLOCK(&ip_conntrack_lock); + } + +-/* Add a related connection. */ ++/** ++ * ip_conntrack_expect_related - Expect a related connection ++ * @related_to: master conntrack ++ * @expect: expectation with all values filled in ++ * ++ * This function is called by conntrack application helpers who ++ * have detected that the control (master) connection is just about ++ * to negotiate a related slave connection. ++ * ++ * Note: This function allocates it's own struct ip_conntrack_expect, ++ * copying the values from the 'expect' parameter. Thus, 'expect' can ++ * be allocated on the stack and does not need to be valid after this ++ * function returns. ++ */ + int ip_conntrack_expect_related(struct ip_conntrack *related_to, + struct ip_conntrack_expect *expect) + { +@@ -936,8 +1014,8 @@ + * so there is no need to use the tuple lock too */ + + DEBUGP("ip_conntrack_expect_related %p\n", related_to); +- DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); +- DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); ++ DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple); ++ DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask); + + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect, + struct ip_conntrack_expect *, &expect->tuple, +@@ -966,23 +1044,28 @@ + related_to->expecting >= related_to->helper->max_expected) { + struct list_head *cur_item; + /* old == NULL */ +- if (net_ratelimit()) +- printk(KERN_WARNING +- "ip_conntrack: max number of expected " +- "connections %i of %s reached for " +- "%u.%u.%u.%u->%u.%u.%u.%u%s\n", +- related_to->helper->max_expected, +- related_to->helper->name, +- NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), +- NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), +- related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ? +- ", reusing" : ""); + if (!(related_to->helper->flags & + IP_CT_HELPER_F_REUSE_EXPECT)) { + WRITE_UNLOCK(&ip_conntrack_lock); ++ if (net_ratelimit()) ++ printk(KERN_WARNING ++ "ip_conntrack: max number of expected " ++ "connections %i of %s reached for " ++ "%u.%u.%u.%u->%u.%u.%u.%u\n", ++ related_to->helper->max_expected, ++ related_to->helper->name, ++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); + return -EPERM; + } +- ++ DEBUGP("ip_conntrack: max number of expected " ++ "connections %i of %s reached for " ++ "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n", ++ related_to->helper->max_expected, ++ related_to->helper->name, ++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); ++ + /* choose the the oldest expectation to evict */ + list_for_each(cur_item, &related_to->sibling_list) { + struct ip_conntrack_expect *cur; +@@ -1023,18 +1106,11 @@ + return -ENOMEM; + } + +- /* Zero out the new structure, then fill out it with the data */ + DEBUGP("new expectation %p of conntrack %p\n", new, related_to); +- memset(new, 0, sizeof(*expect)); +- INIT_LIST_HEAD(&new->list); +- INIT_LIST_HEAD(&new->expected_list); + memcpy(new, expect, sizeof(*expect)); + new->expectant = related_to; + new->sibling = NULL; +- /* increase usage count. This sucks. The memset above overwrites +- * old usage count [if still present] and we increase to one. Only +- * works because everything is done under ip_conntrack_lock() */ +- atomic_inc(&new->use); ++ atomic_set(&new->use, 1); + + /* add to expected list for this connection */ + list_add(&new->expected_list, &related_to->sibling_list); +@@ -1056,7 +1132,15 @@ + return ret; + } + +-/* Change tuple in an existing expectation */ ++/** ++ * ip_conntrack_change_expect - Change tuple in existing expectation ++ * @expect: expectation which is to be changed ++ * @newtuple: new tuple for expect ++ * ++ * This function is mostly called by NAT application helpers, who want to ++ * change an expectation issued by their respective conntrack application ++ * helper counterpart. ++ */ + int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, + struct ip_conntrack_tuple *newtuple) + { +@@ -1064,15 +1148,14 @@ + + MUST_BE_READ_LOCKED(&ip_conntrack_lock); + WRITE_LOCK(&ip_conntrack_expect_tuple_lock); +- + DEBUGP("change_expect:\n"); +- DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple); +- DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask); +- DEBUGP("newtuple: "); DUMP_TUPLE(newtuple); ++ DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple); ++ DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask); ++ DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple); + if (expect->ct_tuple.dst.protonum == 0) { + /* Never seen before */ + DEBUGP("change expect: never seen before\n"); +- if (!ip_ct_tuple_equal(&expect->tuple, newtuple) ++ if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask) + && LIST_FIND(&ip_conntrack_expect_list, expect_clash, + struct ip_conntrack_expect *, newtuple, &expect->mask)) { + /* Force NAT to find an unused tuple */ +@@ -1097,8 +1180,15 @@ + return ret; + } + +-/* Alter reply tuple (maybe alter helper). If it's already taken, +- return 0 and don't do alteration. */ ++/** ++ * ip_conntrack_alter_reply - Alter reply tuple of conntrack ++ * @conntrack: conntrack whose reply tuple we want to alter ++ * @newreply: designated reply tuple for this conntrack ++ * ++ * This function alters the reply tuple of a conntrack to the given ++ * newreply tuple. If this newreply tuple is already taken, return 0 ++ * and don't do alteration ++ */ + int ip_conntrack_alter_reply(struct ip_conntrack *conntrack, + const struct ip_conntrack_tuple *newreply) + { +@@ -1123,6 +1213,13 @@ + return 1; + } + ++/** ++ * ip_conntrack_helper_register - Register a conntrack application helper ++ * @me: structure describing the helper ++ * ++ * This function is called by conntrack application helpers to register ++ * themselves with the conntrack core. ++ */ + int ip_conntrack_helper_register(struct ip_conntrack_helper *me) + { + MOD_INC_USE_COUNT; +@@ -1139,13 +1236,20 @@ + { + if (i->ctrack->helper == me) { + /* Get rid of any expected. */ +- remove_expectations(i->ctrack); ++ remove_expectations(i->ctrack, 0); + /* And *then* set helper to NULL */ + i->ctrack->helper = NULL; + } + return 0; + } + ++/** ++ * ip_conntrack_helper_unregister - Unregister a conntrack application helper ++ * @me: structure describing the helper ++ * ++ * This function is called by conntrack application helpers to unregister ++ * themselvers from the conntrack core. ++ */ + void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) + { + unsigned int i; +@@ -1167,7 +1271,14 @@ + MOD_DEC_USE_COUNT; + } + +-/* Refresh conntrack for this many jiffies. */ ++/** ++ * ip_ct_refresh - Refresh conntrack timer for given conntrack ++ * @ct: conntrack which we want to refresh ++ * @extra_jiffies: number of jiffies to add ++ * ++ * This function is called by protocol helpers and application helpers in ++ * order to change the expiration timer of a conntrack entry. ++ */ + void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) + { + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); +@@ -1177,8 +1288,10 @@ + if (!is_confirmed(ct)) + ct->timeout.expires = extra_jiffies; + else { +- /* Need del_timer for race avoidance (may already be dying). */ +- if (del_timer(&ct->timeout)) { ++ /* Don't update timer for each packet, only if it's been >HZ ++ * ticks since last update. ++ * Need del_timer for race avoidance (may already be dying). */ ++ if (abs(jiffies + extra_jiffies - ct->timeout.expires) >= HZ && del_timer(&ct->timeout)) { + ct->timeout.expires = jiffies + extra_jiffies; + add_timer(&ct->timeout); + } +@@ -1186,7 +1299,16 @@ + WRITE_UNLOCK(&ip_conntrack_lock); + } + +-/* Returns new sk_buff, or NULL */ ++ ++/** ++ * ip_ct_gather_frags - Gather fragments of a particular skb ++ * @skb: pointer to sk_buff of fragmented IP packet ++ * ++ * This code is just a wrapper around the defragmentation code in the core IPv4 ++ * stack. It also takes care of nonlinear skb's. ++ * ++ * Returns new sk_buff, or NULL ++ */ + struct sk_buff * + ip_ct_gather_frags(struct sk_buff *skb) + { +@@ -1274,6 +1396,16 @@ + return h; + } + ++/** ++ * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries ++ * @kill: callback function selecting which entries to delete ++ * @data: opaque data pointer, becomes 2nd argument for kill function ++ * ++ * This function can be used to selectively delete elements of the conntrack ++ * hashtable. The function iterates over the list of conntrack entries and ++ * calls the 'kill' function for every entry. If the return value is true, ++ * the connection is deleted (death_by_timeout). ++ */ + void + ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data), + void *data) +@@ -1284,7 +1416,7 @@ + while ((h = get_next_corpse(kill, data)) != NULL) { + /* Time to push up daises... */ + if (del_timer(&h->ctrack->timeout)) +- death_by_timeout((unsigned long)h->ctrack); ++ ip_ct_death_by_timeout((unsigned long)h->ctrack); + /* ... else the timer will get him soon. */ + + ip_conntrack_put(h->ctrack); +@@ -1299,9 +1431,14 @@ + getorigdst(struct sock *sk, int optval, void *user, int *len) + { + struct ip_conntrack_tuple_hash *h; +- struct ip_conntrack_tuple tuple = { { sk->rcv_saddr, { sk->sport } }, +- { sk->daddr, { sk->dport }, +- IPPROTO_TCP } }; ++ struct ip_conntrack_tuple tuple; ++ ++ IP_CT_TUPLE_BLANK(&tuple); ++ tuple.src.ip = sk->rcv_saddr; ++ tuple.src.u.tcp.port = sk->sport; ++ tuple.dst.ip = sk->daddr; ++ tuple.dst.u.tcp.port = sk->dport; ++ tuple.dst.protonum = IPPROTO_TCP; + + /* We only do TCP at the moment: is there a better way? */ + if (strcmp(sk->prot->name, "TCP") != 0) { +@@ -1345,29 +1482,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; +@@ -1377,9 +1491,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 +@@ -1423,7 +1534,7 @@ + ip_conntrack_max = 8 * ip_conntrack_htable_size; + + printk("ip_conntrack version %s (%u buckets, %d max)" +- " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION, ++ " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION, + ip_conntrack_htable_size, ip_conntrack_max, + sizeof(struct ip_conntrack)); + +@@ -1458,23 +1569,19 @@ + 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) { +- goto err_free_ct_cachep; +- } +-#endif /*CONFIG_SYSCTL*/ +- + /* For use by ipt_REJECT */ + ip_ct_attach = ip_conntrack_attach; ++ ++ /* Set up fake conntrack: ++ - to never be deleted, not in any hashes */ ++ atomic_set(&ip_conntrack_untracked.ct_general.use, 1); ++ /* - and look it like as a confirmed connection */ ++ set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status); ++ /* - and prepare the ctinfo field for NAT. */ ++ ip_conntrack_untracked.infos[IP_CT_NEW].master = &ip_conntrack_untracked.ct_general; ++ + return ret; + +-err_free_ct_cachep: +- kmem_cache_destroy(ip_conntrack_cachep); + err_free_hash: + vfree(ip_conntrack_hash); + err_unreg_sockopt: +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_egg.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_egg.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_egg.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_egg.c Wed Sep 24 09:17:40 2003 +@@ -0,0 +1,237 @@ ++/* Eggdrop extension for IP connection tracking, Version 0.0.5 ++ * 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. ++ * ++ * 2002-03-25: Harald Welte : ++ * Port to netfilter 'newnat' API. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++static unsigned int egg_timeout = 300; ++ ++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; ++} ++ ++ ++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_expect exp; ++ ++ u_int32_t egg_ip; ++ u_int16_t egg_port; ++ ++ DEBUGP("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("Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { ++ DEBUGP("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("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("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("no data in userfile-share pkt\n"); ++ return NF_ACCEPT; ++ } ++ ++ memset(&exp, 0, sizeof(exp)); ++ ++ 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; ++ } ++ ++ exp.tuple.src.ip = iph->daddr; ++ exp.tuple.src.u.tcp.port = 0; ++ exp.tuple.dst.ip = htonl(egg_ip); ++ exp.tuple.dst.u.tcp.port = htons(egg_port); ++ exp.tuple.dst.protonum = IPPROTO_TCP; ++ ++ exp.mask.dst.u.tcp.port = 0xffff; ++ exp.mask.dst.protonum = 0xffff; ++ ++ DEBUGP("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, &exp); ++ break; ++ } ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper egg_helpers[MAX_PORTS]; ++static char egg_names[MAX_PORTS][14]; /* eggdrop-65535 */ ++ ++static void deregister_helpers(void) { ++ int i; ++ ++ for (i = 0; i < ports_c; i++) { ++ DEBUGP("unregistering helper for port %d\n", ports[i]); ++ ip_conntrack_helper_unregister(&egg_helpers[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret; ++ char *tmpname; ++ ++ /* 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].max_expected = 1; ++ egg_helpers[i].timeout = egg_timeout; ++ egg_helpers[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ egg_helpers[i].me = THIS_MODULE; ++ egg_helpers[i].help = help; ++ ++ tmpname = &egg_names[i][0]; ++ if (ports[i] == 3333) ++ sprintf(tmpname, "eggdrop"); ++ else ++ sprintf(tmpname, "eggdrop-%d", ports[i]); ++ egg_helpers[i].name = tmpname; ++ ++ DEBUGP("port #%d: %d\n", i, ports[i]); ++ ++ ret = ip_conntrack_helper_register(&egg_helpers[i]); ++ ++ if (ret) { ++ printk("ip_conntrack_egg: ERROR registering helper " ++ "for port %d\n", ports[i]); ++ deregister_helpers(); ++ return 1; ++ } ++ ports_c++; ++ } ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ deregister_helpers(); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_ftp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_ftp.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_ftp.c Wed Sep 24 09:16:17 2003 +@@ -32,7 +32,7 @@ + + static int try_rfc959(const char *, size_t, u_int32_t [], char); + static int try_eprt(const char *, size_t, u_int32_t [], char); +-static int try_espv_response(const char *, size_t, u_int32_t [], char); ++static int try_epsv_response(const char *, size_t, u_int32_t [], char); + + static struct ftp_search { + enum ip_conntrack_dir dir; +@@ -65,7 +65,7 @@ + IP_CT_DIR_REPLY, + "229 ", sizeof("229 ") - 1, '(', ')', + IP_CT_FTP_EPSV, +- try_espv_response, ++ try_epsv_response, + }, + }; + +@@ -157,7 +157,7 @@ + } + + /* Returns 0, or length of numbers: |||6446| */ +-static int try_espv_response(const char *data, size_t dlen, u_int32_t array[6], ++static int try_epsv_response(const char *data, size_t dlen, u_int32_t array[6], + char term) + { + char delim; +@@ -200,9 +200,9 @@ + + DEBUGP("ftp: string mismatch\n"); + for (i = 0; i < plen; i++) { +- DEBUGFTP("ftp:char %u `%c'(%u) vs `%c'(%u)\n", +- i, data[i], data[i], +- pattern[i], pattern[i]); ++ DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n", ++ i, data[i], data[i], ++ pattern[i], pattern[i]); + } + #endif + return 0; +@@ -366,11 +366,11 @@ + { 0 } }, + { htonl((array[0] << 24) | (array[1] << 16) + | (array[2] << 8) | array[3]), +- { htons(array[4] << 8 | array[5]) }, ++ { .tcp = { htons(array[4] << 8 | array[5]) } }, + IPPROTO_TCP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, +- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); + + exp->expectfn = NULL; + +@@ -405,7 +405,6 @@ + ports[0] = FTP_PORT; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { +- memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper)); + ftp[i].tuple.src.u.tcp.port = htons(ports[i]); + ftp[i].tuple.dst.protonum = IPPROTO_TCP; + ftp[i].mask.src.u.tcp.port = 0xFFFF; +@@ -436,9 +435,7 @@ + return 0; + } + +-#ifdef CONFIG_IP_NF_NAT_NEEDED + EXPORT_SYMBOL(ip_ftp_lock); +-#endif + + MODULE_LICENSE("GPL"); + module_init(init); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_h323.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_h323.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_h323.c Wed Sep 24 09:17:43 2003 +@@ -0,0 +1,308 @@ ++/* ++ * H.323 'brute force' extension for H.323 connection tracking. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat/) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK(ip_h323_lock); ++struct module *ip_conntrack_h323 = THIS_MODULE; ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* FIXME: This should be in userspace. Later. */ ++static int h245_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* 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("ct_h245_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h245_help: 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("ct_h245_help: 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 = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ data_ip = *((u_int32_t *)data); ++ if (data_ip == iph->saddr) { ++ data_port = *((u_int16_t *)(data + 4)); ++ memset(&expect, 0, sizeof(expect)); ++ /* update the H.225 info */ ++ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT + 1; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { .tcp = { data_port } }, ++ IPPROTO_UDP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); ++ ++ exp->expectfn = NULL; ++ ++ /* Ignore failure; should only happen with NAT */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++/* H.245 helper is not registered! */ ++static struct ip_conntrack_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ NULL, /* module */ ++ 8, /* max_ expected */ ++ 240, /* timeout */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h245_help /* helper */ ++ }; ++ ++static int h225_expect(struct ip_conntrack *ct) ++{ ++ WRITE_LOCK(&ip_conntrack_lock); ++ ct->helper = &h245; ++ DEBUGP("h225_expect: helper for %p added\n", ct); ++ WRITE_UNLOCK(&ip_conntrack_lock); ++ ++ return NF_ACCEPT; /* unused */ ++} ++ ++/* FIXME: This should be in userspace. Later. */ ++static int h225_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* 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("ct_h225_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h225_help: 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("ct_h225_help: 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 = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ data_ip = *((u_int32_t *)data); ++ if (data_ip == iph->saddr) { ++ data_port = *((u_int16_t *)(data + 4)); ++ if (data_port == tcph->source) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", ++ NIPQUAD(iph->saddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_ORIGINAL] = i; ++ UNLOCK_BH(&ip_h323_lock); ++#endif ++ } else { ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* update the H.225 info */ ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { .tcp = { data_port } }, ++ IPPROTO_TCP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); ++ ++ exp->expectfn = h225_expect; ++ ++ /* Ignore failure */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ } else if (data_ip == iph->daddr) { ++ data_port = *((u_int16_t *)(data + 4)); ++ if (data_port == tcph->dest) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", ++ NIPQUAD(iph->daddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_REPLY] = i; ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#endif ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++static struct ip_conntrack_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ THIS_MODULE, /* module */ ++ 2, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_help /* helper */ ++ }; ++ ++static int __init init(void) ++{ ++ return ip_conntrack_helper_register(&h225); ++} ++ ++static void __exit fini(void) ++{ ++ /* Unregister H.225 helper */ ++ ip_conntrack_helper_unregister(&h225); ++} ++ ++EXPORT_SYMBOL(ip_h323_lock); ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_irc.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_irc.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_irc.c Wed Sep 24 09:16:26 2003 +@@ -59,7 +59,7 @@ + {"TSEND ", 6}, + {"SCHAT ", 6} + }; +-#define MAXMATCHLEN 6 ++#define MINMATCHLEN 5 + + DECLARE_LOCK(ip_irc_lock); + struct module *ip_conntrack_irc = THIS_MODULE; +@@ -92,9 +92,11 @@ + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ +- while (*data == ' ') ++ while (*data == ' ') { ++ if (data >= data_end) ++ return -1; + data++; +- ++ } + + *port = simple_strtoul(data, &data, 10); + *ad_end_p = data; +@@ -153,13 +155,17 @@ + } + + data_limit = (char *) data + datalen; +- while (data < (data_limit - (22 + MAXMATCHLEN))) { ++ ++ /* strlen("\1DCC SEND t AAAAAAAA P\1\n")=24 ++ * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ ++ while (data < (data_limit - (19 + MINMATCHLEN))) { + if (memcmp(data, "\1DCC ", 5)) { + data++; + continue; + } + + data += 5; ++ /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ + + DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), +@@ -174,6 +180,9 @@ + + DEBUGP("DCC %s detected\n", dccprotos[i].match); + data += dccprotos[i].matchlen; ++ /* we have at least ++ * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid ++ * data left (== 14/13 bytes) */ + if (parse_dcc((char *) data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { + /* unable to parse */ +@@ -183,7 +192,10 @@ + DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", + HIPQUAD(dcc_ip), dcc_port); + +- if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) { ++ /* dcc_ip can be the internal OR external (NAT'ed) IP ++ * Tiago Sousa */ ++ if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip) ++ && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) { + if (net_ratelimit()) + printk(KERN_WARNING + "Forged DCC command from " +@@ -209,11 +221,11 @@ + + exp->tuple = ((struct ip_conntrack_tuple) + { { 0, { 0 } }, +- { htonl(dcc_ip), { htons(dcc_port) }, ++ { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } }, + IPPROTO_TCP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0, { 0 } }, +- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); + + exp->expectfn = NULL; + +@@ -259,8 +271,6 @@ + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + hlpr = &irc_helpers[i]; +- memset(hlpr, 0, +- sizeof(struct ip_conntrack_helper)); + hlpr->tuple.src.u.tcp.port = htons(ports[i]); + hlpr->tuple.dst.protonum = IPPROTO_TCP; + hlpr->mask.src.u.tcp.port = 0xFFFF; +@@ -305,9 +315,7 @@ + } + } + +-#ifdef CONFIG_IP_NF_NAT_NEEDED + EXPORT_SYMBOL(ip_irc_lock); +-#endif + + module_init(init); + module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_mms.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_mms.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_mms.c Wed Sep 24 09:17:48 2003 +@@ -0,0 +1,308 @@ ++/* MMS extension for IP connection tracking ++ * (C) 2002 by Filip Sneppe ++ * based on ip_conntrack_ftp.c and ip_conntrack_irc.c ++ * ++ * ip_conntrack_mms.c v0.3 2002-09-22 ++ * ++ * 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_conntrack_mms.o ports=port1,port2,...port ++ * ++ * Please give the ports of all MMS servers You wish to connect to. ++ * If you don't specify ports, the default will be TCP port 1755. ++ * ++ * More info on MMS protocol, firewalls and NAT: ++ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp ++ * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp ++ * ++ * The SDP project people are reverse-engineering MMS: ++ * http://get.to/sdp ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++DECLARE_LOCK(ip_mms_lock); ++struct module *ip_conntrack_mms = THIS_MODULE; ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c; ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++#endif ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++EXPORT_SYMBOL(ip_mms_lock); ++ ++MODULE_AUTHOR("Filip Sneppe "); ++MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++/* #define isdigit(c) (c >= '0' && c <= '9') */ ++ ++/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */ ++static void unicode_to_ascii (char *string, short *unicode, int unicode_size) ++{ ++ int i; ++ for (i = 0; i < unicode_size; ++i) { ++ string[i] = (char)(unicode[i]); ++ } ++ string[unicode_size] = 0x00; ++} ++ ++__inline static int atoi(char *s) ++{ ++ int i=0; ++ while (isdigit(*s)) { ++ i = i*10 + *(s++) - '0'; ++ } ++ return i; ++} ++ ++/* convert ip address string like "192.168.0.10" to unsigned int */ ++__inline static u_int32_t asciiiptoi(char *s) ++{ ++ unsigned int i, j, k; ++ ++ for(i=k=0; k<3; ++k, ++s, i<<=8) { ++ i+=atoi(s); ++ for(j=0; (*(++s) != '.') && (j<3); ++j) ++ ; ++ } ++ i+=atoi(s); ++ return ntohl(i); ++} ++ ++int parse_mms(const char *data, ++ const unsigned int datalen, ++ u_int32_t *mms_ip, ++ u_int16_t *mms_proto, ++ u_int16_t *mms_port, ++ char **mms_string_b, ++ char **mms_string_e, ++ char **mms_padding_e) ++{ ++ int unicode_size, i; ++ char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */ ++ char getlengthstring[28]; ++ ++ for(unicode_size=0; ++ (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0; ++ unicode_size++) ++ if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) ++ return -1; /* out of bounds - incomplete packet */ ++ ++ unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size); ++ DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring)); ++ ++ /* IP address ? */ ++ *mms_ip = asciiiptoi(tempstring+2); ++ ++ i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip)); ++ ++ /* protocol ? */ ++ if(strncmp(tempstring+3+i, "TCP", 3)==0) ++ *mms_proto = IPPROTO_TCP; ++ else if(strncmp(tempstring+3+i, "UDP", 3)==0) ++ *mms_proto = IPPROTO_UDP; ++ ++ /* port ? */ ++ *mms_port = atoi(tempstring+7+i); ++ ++ /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" ++ unicode string, one to the end of the string, and one to the end ++ of the packet, since we must keep track of the number of bytes ++ between end of the unicode string and the end of packet (padding) */ ++ *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET); ++ *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2); ++ *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */ ++ 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 guaranteed by ip_conntrack_tcp.c */ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)tcph + tcph->doff * 4; ++ unsigned int tcplen = len - iph->ihl * 4; ++ unsigned int datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info; ++ ++ u_int32_t mms_ip; ++ u_int16_t mms_proto; ++ char mms_proto_string[8]; ++ u_int16_t mms_port; ++ char *mms_string_b, *mms_string_e, *mms_padding_e; ++ ++ /* 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_conntrack_mms: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) { ++ DEBUGP("ip_conntrack_mms: 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("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */ ++ /* FIXME: There is an issue with only looking at this packet: before this packet, ++ the client has already sent a packet to the server with the server's hostname ++ according to the client (think of it as the "Host: " header in HTTP/1.1). The ++ server will break the connection if this doesn't correspond to its own host ++ header. The client can also connect to an IP address; if it's the server's IP ++ address, it will not break the connection. When doing DNAT on a connection ++ where the client uses a server's IP address, the nat module should detect ++ this and change this string accordingly to the DNATed address. This should ++ probably be done by checking for an IP address, then storing it as a member ++ of struct ip_ct_mms_expect and checking for it in ip_nat_mms... ++ */ ++ if( (MMS_SRV_MSG_OFFSET < datalen) && ++ ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) { ++ DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", ++ (u8)*(data+36), (u8)*(data+37), ++ (u8)*(data+38), (u8)*(data+39), ++ datalen); ++ if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, ++ &mms_string_b, &mms_string_e, &mms_padding_e)) ++ if(net_ratelimit()) ++ /* FIXME: more verbose debugging ? */ ++ printk(KERN_WARNING ++ "ip_conntrack_mms: Unable to parse data payload\n"); ++ ++ memset(&expect, 0, sizeof(expect)); ++ ++ sprintf(mms_proto_string, "(%u)", mms_proto); ++ DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n", ++ mms_proto == IPPROTO_TCP ? "TCP" ++ : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(mms_ip), ++ mms_port); ++ ++ /* it's possible that the client will just ask the server to tunnel ++ the stream over the same TCP session (from port 1755): there's ++ shouldn't be a need to add an expectation in that case, but it ++ makes NAT packet mangling so much easier */ ++ LOCK_BH(&ip_mms_lock); ++ ++ DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq); ++ ++ exp->seq = ntohl(tcph->seq) + (mms_string_b - data); ++ exp_mms_info->len = (mms_string_e - mms_string_b); ++ exp_mms_info->padding = (mms_padding_e - mms_string_e); ++ exp_mms_info->port = mms_port; ++ ++ DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n", ++ exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding); ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, ++ { mms_ip, ++ { .tcp = { (__u16) ntohs(mms_port) } }, ++ mms_proto } } ++ ); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); ++ exp->expectfn = NULL; ++ ip_conntrack_expect_related(ct, &expect); ++ UNLOCK_BH(&ip_mms_lock); ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper mms[MAX_PORTS]; ++static char mms_names[MAX_PORTS][10]; ++ ++/* Not __exit: called from init() */ ++static void fini(void) ++{ ++ int i; ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n", ++ ports[i]); ++ ip_conntrack_helper_unregister(&mms[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret; ++ char *tmpname; ++ ++ if (ports[0] == 0) ++ ports[0] = MMS_PORT; ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ memset(&mms[i], 0, sizeof(struct ip_conntrack_helper)); ++ mms[i].tuple.src.u.tcp.port = htons(ports[i]); ++ mms[i].tuple.dst.protonum = IPPROTO_TCP; ++ mms[i].mask.src.u.tcp.port = 0xFFFF; ++ mms[i].mask.dst.protonum = 0xFFFF; ++ mms[i].max_expected = 1; ++ mms[i].timeout = 0; ++ mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ mms[i].me = THIS_MODULE; ++ mms[i].help = help; ++ ++ tmpname = &mms_names[i][0]; ++ if (ports[i] == MMS_PORT) ++ sprintf(tmpname, "mms"); ++ else ++ sprintf(tmpname, "mms-%d", ports[i]); ++ mms[i].name = tmpname; ++ ++ DEBUGP("ip_conntrack_mms: registering helper for port %d\n", ++ ports[i]); ++ ret = ip_conntrack_helper_register(&mms[i]); ++ ++ if (ret) { ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ return 0; ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_pptp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_pptp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_pptp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_pptp.c Wed Sep 24 09:18:16 2003 +@@ -0,0 +1,639 @@ ++/* ++ * ip_conntrack_pptp.c - Version 1.9 ++ * ++ * Connection tracking support for PPTP (Point to Point Tunneling Protocol). ++ * PPTP is a a protocol for creating virtual private networks. ++ * It is a specification defined by Microsoft and some vendors ++ * working with Microsoft. PPTP is built on top of a modified ++ * version of the Internet Generic Routing Encapsulation Protocol. ++ * GRE is defined in RFC 1701 and RFC 1702. Documentation of ++ * PPTP can be found in RFC 2637 ++ * ++ * (C) 2000-2003 by Harald Welte ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ * Limitations: ++ * - We blindly assume that control connections are always ++ * established in PNS->PAC direction. This is a violation ++ * of RFFC2673 ++ * ++ * TODO: - finish support for multiple calls within one session ++ * (needs expect reservations in newnat) ++ * - testing of incoming PPTP calls ++ * ++ * Changes: ++ * 2002-02-05 - Version 1.3 ++ * - Call ip_conntrack_unexpect_related() from ++ * pptp_timeout_related() to destroy expectations in case ++ * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen ++ * (Philip Craig ) ++ * - Add Version information at module loadtime ++ * 2002-02-10 - Version 1.6 ++ * - move to C99 style initializers ++ * - remove second expectation if first arrives ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define IP_CT_PPTP_VERSION "1.9" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte "); ++MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); ++ ++DECLARE_LOCK(ip_pptp_lock); ++ ++#if 0 ++#include "ip_conntrack_pptp_priv.h" ++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++ ": " format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#define SECS *HZ ++#define MINS * 60 SECS ++#define HOURS * 60 MINS ++#define DAYS * 24 HOURS ++ ++#define PPTP_GRE_TIMEOUT (10 MINS) ++#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS) ++ ++static int pptp_expectfn(struct ip_conntrack *ct) ++{ ++ struct ip_conntrack *master; ++ struct ip_conntrack_expect *exp; ++ ++ DEBUGP("increasing timeouts\n"); ++ /* increase timeout of GRE data channel conntrack entry */ ++ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; ++ ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; ++ ++ master = master_ct(ct); ++ if (!master) { ++ DEBUGP(" no master!!!\n"); ++ return 0; ++ } ++ ++ exp = ct->master; ++ if (!exp) { ++ DEBUGP("no expectation!!\n"); ++ return 0; ++ } ++ ++ DEBUGP("completing tuples with ct info\n"); ++ /* we can do this, since we're unconfirmed */ ++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == ++ htonl(master->help.ct_pptp_info.pac_call_id)) { ++ /* assume PNS->PAC */ ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = ++ htonl(master->help.ct_pptp_info.pns_call_id); ++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = ++ htonl(master->help.ct_pptp_info.pns_call_id); ++ } else { ++ /* assume PAC->PNS */ ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = ++ htonl(master->help.ct_pptp_info.pac_call_id); ++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = ++ htonl(master->help.ct_pptp_info.pac_call_id); ++ } ++ ++ /* delete other expectation */ ++ if (exp->expected_list.next != &exp->expected_list) { ++ struct ip_conntrack_expect *other_exp; ++ struct list_head *cur_item, *next; ++ ++ for (cur_item = master->sibling_list.next; ++ cur_item != &master->sibling_list; cur_item = next) { ++ next = cur_item->next; ++ other_exp = list_entry(cur_item, ++ struct ip_conntrack_expect, ++ expected_list); ++ /* remove only if occurred at same sequence number */ ++ if (other_exp != exp && other_exp->seq == exp->seq) { ++ DEBUGP("unexpecting other direction\n"); ++ ip_ct_gre_keymap_destroy(other_exp); ++ ip_conntrack_unexpect_related(other_exp); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* timeout GRE data connections */ ++static int pptp_timeout_related(struct ip_conntrack *ct) ++{ ++ struct list_head *cur_item, *next; ++ struct ip_conntrack_expect *exp; ++ ++ /* FIXME: do we have to lock something ? */ ++ for (cur_item = ct->sibling_list.next; ++ cur_item != &ct->sibling_list; cur_item = next) { ++ next = cur_item->next; ++ exp = list_entry(cur_item, struct ip_conntrack_expect, ++ expected_list); ++ ++ ip_ct_gre_keymap_destroy(exp); ++ if (!exp->sibling) { ++ ip_conntrack_unexpect_related(exp); ++ continue; ++ } ++ ++ DEBUGP("killing conntrack %p\n", ++ exp->sibling); ++ exp->sibling->proto.gre.timeout = 0; ++ exp->sibling->proto.gre.stream_timeout = 0; ++ ++ if (del_timer(&exp->sibling->timeout)) ++ ip_ct_death_by_timeout((unsigned long)exp->sibling); ++ } ++ ++ return 0; ++} ++ ++/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ ++static inline int ++exp_gre(struct ip_conntrack *master, ++ u_int32_t seq, ++ u_int16_t callid, ++ u_int16_t peer_callid) ++{ ++ struct ip_conntrack_expect exp; ++ struct ip_conntrack_tuple inv_tuple; ++ ++ memset(&exp, 0, sizeof(exp)); ++ /* tuple in original direction, PNS->PAC */ ++ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid)); ++ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ exp.tuple.dst.u.gre.key = htonl(ntohs(callid)); ++ exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP); ++ exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP; ++ exp.tuple.dst.protonum = IPPROTO_GRE; ++ ++ exp.mask.src.ip = 0xffffffff; ++ exp.mask.src.u.all = 0; ++ exp.mask.dst.u.all = 0; ++ exp.mask.dst.u.gre.key = 0xffffffff; ++ exp.mask.dst.u.gre.version = 0xff; ++ exp.mask.dst.u.gre.protocol = 0xffff; ++ exp.mask.dst.ip = 0xffffffff; ++ exp.mask.dst.protonum = 0xffff; ++ ++ exp.seq = seq; ++ exp.expectfn = pptp_expectfn; ++ ++ exp.help.exp_pptp_info.pac_call_id = ntohs(callid); ++ exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid); ++ ++ DEBUGP("calling expect_related "); ++ DUMP_TUPLE_RAW(&exp.tuple); ++ ++ /* Add GRE keymap entries */ ++ if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0) ++ return 1; ++ ++ invert_tuplepr(&inv_tuple, &exp.tuple); ++ if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) { ++ ip_ct_gre_keymap_destroy(&exp); ++ return 1; ++ } ++ ++ if (ip_conntrack_expect_related(master, &exp) != 0) { ++ ip_ct_gre_keymap_destroy(&exp); ++ DEBUGP("cannot expect_related()\n"); ++ return 1; ++ } ++ ++ /* tuple in reply direction, PAC->PNS */ ++ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ exp.tuple.src.u.gre.key = htonl(ntohs(callid)); ++ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid)); ++ ++ DEBUGP("calling expect_related "); ++ DUMP_TUPLE_RAW(&exp.tuple); ++ ++ /* Add GRE keymap entries */ ++ ip_ct_gre_keymap_add(&exp, &exp.tuple, 0); ++ invert_tuplepr(&inv_tuple, &exp.tuple); ++ ip_ct_gre_keymap_add(&exp, &inv_tuple, 1); ++ /* FIXME: cannot handle error correctly, since we need to free ++ * the above keymap :( */ ++ ++ if (ip_conntrack_expect_related(master, &exp) != 0) { ++ /* free the second pair of keypmaps */ ++ ip_ct_gre_keymap_destroy(&exp); ++ DEBUGP("cannot expect_related():\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static inline int ++pptp_inbound_pkt(struct tcphdr *tcph, ++ struct pptp_pkt_hdr *pptph, ++ size_t datalen, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct PptpControlHeader *ctlh; ++ union pptp_ctrl_union pptpReq; ++ ++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; ++ u_int16_t msg, *cid, *pcid; ++ u_int32_t seq; ++ ++ ctlh = (struct PptpControlHeader *) ++ ((char *) pptph + sizeof(struct pptp_pkt_hdr)); ++ pptpReq.rawreq = (void *) ++ ((char *) ctlh + sizeof(struct PptpControlHeader)); ++ ++ msg = ntohs(ctlh->messageType); ++ DEBUGP("inbound control message %s\n", strMName[msg]); ++ ++ switch (msg) { ++ case PPTP_START_SESSION_REPLY: ++ /* server confirms new control session */ ++ if (info->sstate < PPTP_SESSION_REQUESTED) { ++ DEBUGP("%s without START_SESS_REQUEST\n", ++ strMName[msg]); ++ break; ++ } ++ if (pptpReq.srep->resultCode == PPTP_START_OK) ++ info->sstate = PPTP_SESSION_CONFIRMED; ++ else ++ info->sstate = PPTP_SESSION_ERROR; ++ break; ++ ++ case PPTP_STOP_SESSION_REPLY: ++ /* server confirms end of control session */ ++ if (info->sstate > PPTP_SESSION_STOPREQ) { ++ DEBUGP("%s without STOP_SESS_REQUEST\n", ++ strMName[msg]); ++ break; ++ } ++ if (pptpReq.strep->resultCode == PPTP_STOP_OK) ++ info->sstate = PPTP_SESSION_NONE; ++ else ++ info->sstate = PPTP_SESSION_ERROR; ++ break; ++ ++ case PPTP_OUT_CALL_REPLY: ++ /* server accepted call, we now expect GRE frames */ ++ if (info->sstate != PPTP_SESSION_CONFIRMED) { ++ DEBUGP("%s but no session\n", strMName[msg]); ++ break; ++ } ++ if (info->cstate != PPTP_CALL_OUT_REQ && ++ info->cstate != PPTP_CALL_OUT_CONF) { ++ DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]); ++ break; ++ } ++ if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) { ++ info->cstate = PPTP_CALL_NONE; ++ break; ++ } ++ ++ cid = &pptpReq.ocack->callID; ++ pcid = &pptpReq.ocack->peersCallID; ++ ++ info->pac_call_id = ntohs(*cid); ++ ++ if (htons(info->pns_call_id) != *pcid) { ++ DEBUGP("%s for unknown callid %u\n", ++ strMName[msg], ntohs(*pcid)); ++ break; ++ } ++ ++ DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], ++ ntohs(*cid), ntohs(*pcid)); ++ ++ info->cstate = PPTP_CALL_OUT_CONF; ++ ++ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); ++ if (exp_gre(ct, seq, *cid, *pcid) != 0) ++ printk("ip_conntrack_pptp: error during exp_gre\n"); ++ break; ++ ++ case PPTP_IN_CALL_REQUEST: ++ /* server tells us about incoming call request */ ++ if (info->sstate != PPTP_SESSION_CONFIRMED) { ++ DEBUGP("%s but no session\n", strMName[msg]); ++ break; ++ } ++ pcid = &pptpReq.icack->peersCallID; ++ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); ++ info->cstate = PPTP_CALL_IN_REQ; ++ info->pac_call_id= ntohs(*pcid); ++ break; ++ ++ case PPTP_IN_CALL_CONNECT: ++ /* server tells us about incoming call established */ ++ if (info->sstate != PPTP_SESSION_CONFIRMED) { ++ DEBUGP("%s but no session\n", strMName[msg]); ++ break; ++ } ++ if (info->sstate != PPTP_CALL_IN_REP ++ && info->sstate != PPTP_CALL_IN_CONF) { ++ DEBUGP("%s but never sent IN_CALL_REPLY\n", ++ strMName[msg]); ++ break; ++ } ++ ++ pcid = &pptpReq.iccon->peersCallID; ++ cid = &info->pac_call_id; ++ ++ if (info->pns_call_id != ntohs(*pcid)) { ++ DEBUGP("%s for unknown CallID %u\n", ++ strMName[msg], ntohs(*cid)); ++ break; ++ } ++ ++ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); ++ info->cstate = PPTP_CALL_IN_CONF; ++ ++ /* we expect a GRE connection from PAC to PNS */ ++ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); ++ if (exp_gre(ct, seq, *cid, *pcid) != 0) ++ printk("ip_conntrack_pptp: error during exp_gre\n"); ++ ++ break; ++ ++ case PPTP_CALL_DISCONNECT_NOTIFY: ++ /* server confirms disconnect */ ++ cid = &pptpReq.disc->callID; ++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); ++ info->cstate = PPTP_CALL_NONE; ++ ++ /* untrack this call id, unexpect GRE packets */ ++ pptp_timeout_related(ct); ++ break; ++ ++ case PPTP_WAN_ERROR_NOTIFY: ++ break; ++ ++ case PPTP_ECHO_REQUEST: ++ case PPTP_ECHO_REPLY: ++ /* I don't have to explain these ;) */ ++ break; ++ default: ++ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) ++ ? strMName[msg]:strMName[0], msg); ++ break; ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++static inline int ++pptp_outbound_pkt(struct tcphdr *tcph, ++ struct pptp_pkt_hdr *pptph, ++ size_t datalen, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct PptpControlHeader *ctlh; ++ union pptp_ctrl_union pptpReq; ++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; ++ u_int16_t msg, *cid, *pcid; ++ ++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); ++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); ++ ++ msg = ntohs(ctlh->messageType); ++ DEBUGP("outbound control message %s\n", strMName[msg]); ++ ++ switch (msg) { ++ case PPTP_START_SESSION_REQUEST: ++ /* client requests for new control session */ ++ if (info->sstate != PPTP_SESSION_NONE) { ++ DEBUGP("%s but we already have one", ++ strMName[msg]); ++ } ++ info->sstate = PPTP_SESSION_REQUESTED; ++ break; ++ case PPTP_STOP_SESSION_REQUEST: ++ /* client requests end of control session */ ++ info->sstate = PPTP_SESSION_STOPREQ; ++ break; ++ ++ case PPTP_OUT_CALL_REQUEST: ++ /* client initiating connection to server */ ++ if (info->sstate != PPTP_SESSION_CONFIRMED) { ++ DEBUGP("%s but no session\n", ++ strMName[msg]); ++ break; ++ } ++ info->cstate = PPTP_CALL_OUT_REQ; ++ /* track PNS call id */ ++ cid = &pptpReq.ocreq->callID; ++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); ++ info->pns_call_id = ntohs(*cid); ++ break; ++ case PPTP_IN_CALL_REPLY: ++ /* client answers incoming call */ ++ if (info->cstate != PPTP_CALL_IN_REQ ++ && info->cstate != PPTP_CALL_IN_REP) { ++ DEBUGP("%s without incall_req\n", ++ strMName[msg]); ++ break; ++ } ++ if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) { ++ info->cstate = PPTP_CALL_NONE; ++ break; ++ } ++ pcid = &pptpReq.icack->peersCallID; ++ if (info->pac_call_id != ntohs(*pcid)) { ++ DEBUGP("%s for unknown call %u\n", ++ strMName[msg], ntohs(*pcid)); ++ break; ++ } ++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid)); ++ /* part two of the three-way handshake */ ++ info->cstate = PPTP_CALL_IN_REP; ++ info->pns_call_id = ntohs(pptpReq.icack->callID); ++ break; ++ ++ case PPTP_CALL_CLEAR_REQUEST: ++ /* client requests hangup of call */ ++ if (info->sstate != PPTP_SESSION_CONFIRMED) { ++ DEBUGP("CLEAR_CALL but no session\n"); ++ break; ++ } ++ /* FUTURE: iterate over all calls and check if ++ * call ID is valid. We don't do this without newnat, ++ * because we only know about last call */ ++ info->cstate = PPTP_CALL_CLEAR_REQ; ++ break; ++ case PPTP_SET_LINK_INFO: ++ break; ++ case PPTP_ECHO_REQUEST: ++ case PPTP_ECHO_REPLY: ++ /* I don't have to explain these ;) */ ++ break; ++ default: ++ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? ++ strMName[msg]:strMName[0], msg); ++ /* unknown: no need to create GRE masq table entry */ ++ break; ++ } ++ ++ return NF_ACCEPT; ++} ++ ++ ++/* track caller id inside control connection, call expect_related */ ++static int ++conntrack_pptp_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) ++ ++{ ++ struct pptp_pkt_hdr *pptph; ++ ++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ void *datalimit; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; ++ ++ int oldsstate, oldcstate; ++ int ret; ++ ++ /* don't do any tracking before tcp handshake complete */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { ++ DEBUGP("ctinfo = %u, skipping\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* not a complete TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { ++ DEBUGP("tcplen = %u\n", tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* checksum invalid? */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *) tcph, tcplen, 0))) { ++ printk(KERN_NOTICE __FILE__ ": bad csum\n"); ++ /* W2K PPTP server sends TCP packets with wrong checksum :(( */ ++ //return NF_ACCEPT; ++ } ++ ++ if (tcph->fin || tcph->rst) { ++ DEBUGP("RST/FIN received, timeouting GRE\n"); ++ /* can't do this after real newnat */ ++ info->cstate = PPTP_CALL_NONE; ++ ++ /* untrack this call id, unexpect GRE packets */ ++ pptp_timeout_related(ct); ++ } ++ ++ ++ pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); ++ datalimit = (void *) pptph + datalen; ++ ++ /* not a full pptp packet header? */ ++ if ((void *) pptph+sizeof(*pptph) >= datalimit) { ++ DEBUGP("no full PPTP header, can't track\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* if it's not a control message we can't do anything with it */ ++ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || ++ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { ++ DEBUGP("not a control packet\n"); ++ return NF_ACCEPT; ++ } ++ ++ oldsstate = info->sstate; ++ oldcstate = info->cstate; ++ ++ LOCK_BH(&ip_pptp_lock); ++ ++ /* FIXME: We just blindly assume that the control connection is always ++ * established from PNS->PAC. However, RFC makes no guarantee */ ++ if (dir == IP_CT_DIR_ORIGINAL) ++ /* client -> server (PNS -> PAC) */ ++ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); ++ else ++ /* server -> client (PAC -> PNS) */ ++ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); ++ DEBUGP("sstate: %d->%d, cstate: %d->%d\n", ++ oldsstate, info->sstate, oldcstate, info->cstate); ++ UNLOCK_BH(&ip_pptp_lock); ++ ++ return ret; ++} ++ ++/* control protocol helper */ ++static struct ip_conntrack_helper pptp = { ++ .list = { NULL, NULL }, ++ .name = "pptp", ++ .flags = IP_CT_HELPER_F_REUSE_EXPECT, ++ .me = THIS_MODULE, ++ .max_expected = 2, ++ .timeout = 0, ++ .tuple = { .src = { .ip = 0, ++ .u = { .tcp = { .port = ++ __constant_htons(PPTP_CONTROL_PORT) } } ++ }, ++ .dst = { .ip = 0, ++ .u = { .all = 0 }, ++ .protonum = IPPROTO_TCP ++ } ++ }, ++ .mask = { .src = { .ip = 0, ++ .u = { .tcp = { .port = 0xffff } } ++ }, ++ .dst = { .ip = 0, ++ .u = { .all = 0 }, ++ .protonum = 0xffff ++ } ++ }, ++ .help = conntrack_pptp_help ++}; ++ ++/* ip_conntrack_pptp initialization */ ++static int __init init(void) ++{ ++ int retcode; ++ ++ DEBUGP(__FILE__ ": registering helper\n"); ++ if ((retcode = ip_conntrack_helper_register(&pptp))) { ++ printk(KERN_ERR "Unable to register conntrack application " ++ "helper for pptp: %d\n", retcode); ++ return -EIO; ++ } ++ ++ printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip_conntrack_helper_unregister(&pptp); ++ printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++EXPORT_SYMBOL(ip_pptp_lock); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.4.20/net/ipv4/netfilter/ip_conntrack_pptp_priv.h +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_pptp_priv.h Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,24 @@ ++#ifndef _IP_CT_PPTP_PRIV_H ++#define _IP_CT_PPTP_PRIV_H ++ ++/* PptpControlMessageType names */ ++static const char *strMName[] = { ++ "UNKNOWN_MESSAGE", ++ "START_SESSION_REQUEST", ++ "START_SESSION_REPLY", ++ "STOP_SESSION_REQUEST", ++ "STOP_SESSION_REPLY", ++ "ECHO_REQUEST", ++ "ECHO_REPLY", ++ "OUT_CALL_REQUEST", ++ "OUT_CALL_REPLY", ++ "IN_CALL_REQUEST", ++ "IN_CALL_REPLY", ++ "IN_CALL_CONNECT", ++ "CALL_CLEAR_REQUEST", ++ "CALL_DISCONNECT_NOTIFY", ++ "WAN_ERROR_NOTIFY", ++ "SET_LINK_INFO" ++}; ++ ++#endif +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_generic.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_generic.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_generic.c Wed Sep 24 09:16:22 2003 +@@ -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; + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_gre.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_gre.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_gre.c Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,343 @@ ++/* ++ * ip_conntrack_proto_gre.c - Version 1.2 ++ * ++ * Connection tracking protocol helper module for GRE. ++ * ++ * GRE is a generic encapsulation protocol, which is generally not very ++ * suited for NAT, as it has no protocol-specific part as port numbers. ++ * ++ * It has an optional key field, which may help us distinguishing two ++ * connections between the same two hosts. ++ * ++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 ++ * ++ * PPTP is built on top of a modified version of GRE, and has a mandatory ++ * field called "CallID", which serves us for the same purpose as the key ++ * field in plain GRE. ++ * ++ * Documentation about PPTP can be found in RFC 2637 ++ * ++ * (C) 2000-2003 by Harald Welte ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++DECLARE_RWLOCK(ip_ct_gre_lock); ++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock) ++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock) ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte "); ++MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); ++ ++/* shamelessly stolen from ip_conntrack_proto_udp.c */ ++#define GRE_TIMEOUT (30*HZ) ++#define GRE_STREAM_TIMEOUT (180*HZ) ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++ ": " format, ## args) ++#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \ ++ NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \ ++ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \ ++ (x)->dst.u.gre.version, \ ++ ntohs((x)->dst.u.gre.protocol)) ++#else ++#define DEBUGP(x, args...) ++#define DUMP_TUPLE_GRE(x) ++#endif ++ ++/* GRE KEYMAP HANDLING FUNCTIONS */ ++static LIST_HEAD(gre_keymap_list); ++ ++static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, ++ const struct ip_conntrack_tuple *t) ++{ ++ return ((km->tuple.src.ip == t->src.ip) && ++ (km->tuple.dst.ip == t->dst.ip) && ++ (km->tuple.dst.protonum == t->dst.protonum) && ++ (km->tuple.dst.u.all == t->dst.u.all)); ++} ++ ++/* look up the source key for a given tuple */ ++static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) ++{ ++ struct ip_ct_gre_keymap *km; ++ u_int32_t key; ++ ++ READ_LOCK(&ip_ct_gre_lock); ++ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, ++ struct ip_ct_gre_keymap *, t); ++ if (!km) { ++ READ_UNLOCK(&ip_ct_gre_lock); ++ return 0; ++ } ++ ++ key = km->tuple.src.u.gre.key; ++ READ_UNLOCK(&ip_ct_gre_lock); ++ ++ return key; ++} ++ ++/* add a single keymap entry, associate with specified expect */ ++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, ++ struct ip_conntrack_tuple *t, int reply) ++{ ++ struct ip_ct_gre_keymap *km; ++ ++ km = kmalloc(sizeof(*km), GFP_ATOMIC); ++ if (!km) ++ return -1; ++ ++ /* initializing list head should be sufficient */ ++ memset(km, 0, sizeof(*km)); ++ ++ memcpy(&km->tuple, t, sizeof(*t)); ++ ++ if (!reply) ++ exp->proto.gre.keymap_orig = km; ++ else ++ exp->proto.gre.keymap_reply = km; ++ ++ DEBUGP("adding new entry %p: ", km); ++ DUMP_TUPLE_GRE(&km->tuple); ++ ++ WRITE_LOCK(&ip_ct_gre_lock); ++ list_append(&gre_keymap_list, km); ++ WRITE_UNLOCK(&ip_ct_gre_lock); ++ ++ return 0; ++} ++ ++/* change the tuple of a keymap entry (used by nat helper) */ ++void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, ++ struct ip_conntrack_tuple *t) ++{ ++ DEBUGP("changing entry %p to: ", km); ++ DUMP_TUPLE_GRE(t); ++ ++ WRITE_LOCK(&ip_ct_gre_lock); ++ memcpy(&km->tuple, t, sizeof(km->tuple)); ++ WRITE_UNLOCK(&ip_ct_gre_lock); ++} ++ ++/* destroy the keymap entries associated with specified expect */ ++void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp) ++{ ++ DEBUGP("entering for exp %p\n", exp); ++ WRITE_LOCK(&ip_ct_gre_lock); ++ if (exp->proto.gre.keymap_orig) { ++ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig); ++ list_del(&exp->proto.gre.keymap_orig->list); ++ kfree(exp->proto.gre.keymap_orig); ++ exp->proto.gre.keymap_orig = NULL; ++ } ++ if (exp->proto.gre.keymap_reply) { ++ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply); ++ list_del(&exp->proto.gre.keymap_reply->list); ++ kfree(exp->proto.gre.keymap_reply); ++ exp->proto.gre.keymap_reply = NULL; ++ } ++ WRITE_UNLOCK(&ip_ct_gre_lock); ++} ++ ++ ++/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ ++ ++/* invert gre part of tuple */ ++static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, ++ const struct ip_conntrack_tuple *orig) ++{ ++ tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol; ++ tuple->dst.u.gre.version = orig->dst.u.gre.version; ++ ++ tuple->dst.u.gre.key = orig->src.u.gre.key; ++ tuple->src.u.gre.key = orig->dst.u.gre.key; ++ ++ return 1; ++} ++ ++/* gre hdr info to tuple */ ++static int gre_pkt_to_tuple(const void *datah, size_t datalen, ++ struct ip_conntrack_tuple *tuple) ++{ ++ struct gre_hdr *grehdr = (struct gre_hdr *) datah; ++ struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah; ++ u_int32_t srckey; ++ ++ /* core guarantees 8 protocol bytes, no need for size check */ ++ ++ tuple->dst.u.gre.version = grehdr->version; ++ tuple->dst.u.gre.protocol = grehdr->protocol; ++ ++ switch (grehdr->version) { ++ case GRE_VERSION_1701: ++ if (!grehdr->key) { ++ DEBUGP("Can't track GRE without key\n"); ++ return 0; ++ } ++ tuple->dst.u.gre.key = *(gre_key(grehdr)); ++ break; ++ ++ case GRE_VERSION_PPTP: ++ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { ++ DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); ++ return 0; ++ } ++ tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id)); ++ break; ++ ++ default: ++ printk(KERN_WARNING "unknown GRE version %hu\n", ++ tuple->dst.u.gre.version); ++ return 0; ++ } ++ ++ srckey = gre_keymap_lookup(tuple); ++ ++#if 0 ++ DEBUGP("found src key %x for tuple ", ntohl(srckey)); ++ DUMP_TUPLE_GRE(tuple); ++#endif ++ tuple->src.u.gre.key = srckey; ++ ++ return 1; ++} ++ ++/* print gre part of tuple */ ++static unsigned int gre_print_tuple(char *buffer, ++ const struct ip_conntrack_tuple *tuple) ++{ ++ return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ", ++ tuple->dst.u.gre.version, ++ ntohs(tuple->dst.u.gre.protocol), ++ ntohl(tuple->src.u.gre.key), ++ ntohl(tuple->dst.u.gre.key)); ++} ++ ++/* print private data for conntrack */ ++static unsigned int gre_print_conntrack(char *buffer, ++ const struct ip_conntrack *ct) ++{ ++ return sprintf(buffer, "timeout=%u, stream_timeout=%u ", ++ (ct->proto.gre.timeout / HZ), ++ (ct->proto.gre.stream_timeout / HZ)); ++} ++ ++/* Returns verdict for packet, and may modify conntrack */ ++static int gre_packet(struct ip_conntrack *ct, ++ struct iphdr *iph, size_t len, ++ enum ip_conntrack_info conntrackinfo) ++{ ++ /* If we've seen traffic both ways, this is a GRE connection. ++ * Extend timeout. */ ++ if (ct->status & IPS_SEEN_REPLY) { ++ ip_ct_refresh(ct, ct->proto.gre.stream_timeout); ++ /* Also, more likely to be important, and not a probe. */ ++ set_bit(IPS_ASSURED_BIT, &ct->status); ++ } else ++ ip_ct_refresh(ct, ct->proto.gre.timeout); ++ ++ return NF_ACCEPT; ++} ++ ++/* Called when a new connection for this protocol found. */ ++static int gre_new(struct ip_conntrack *ct, ++ struct iphdr *iph, size_t len) ++{ ++ DEBUGP(": "); ++ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ ++ /* initialize to sane value. Ideally a conntrack helper ++ * (e.g. in case of pptp) is increasing them */ ++ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; ++ ct->proto.gre.timeout = GRE_TIMEOUT; ++ ++ return 1; ++} ++ ++/* Called when a conntrack entry has already been removed from the hashes ++ * and is about to be deleted from memory */ ++static void gre_destroy(struct ip_conntrack *ct) ++{ ++ struct ip_conntrack_expect *master = ct->master; ++ ++ DEBUGP(" entering\n"); ++ ++ if (!master) { ++ DEBUGP("no master exp for ct %p\n", ct); ++ return; ++ } ++ ++ ip_ct_gre_keymap_destroy(master); ++} ++ ++/* protocol helper struct */ ++static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE, ++ "gre", ++ gre_pkt_to_tuple, ++ gre_invert_tuple, ++ gre_print_tuple, ++ gre_print_conntrack, ++ gre_packet, ++ gre_new, ++ gre_destroy, ++ NULL, ++ THIS_MODULE }; ++ ++/* ip_conntrack_proto_gre initialization */ ++static int __init init(void) ++{ ++ int retcode; ++ ++ if ((retcode = ip_conntrack_protocol_register(&gre))) { ++ printk(KERN_ERR "Unable to register conntrack protocol " ++ "helper for gre: %d\n", retcode); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ struct list_head *pos, *n; ++ ++ /* delete all keymap entries */ ++ WRITE_LOCK(&ip_ct_gre_lock); ++ list_for_each_safe(pos, n, &gre_keymap_list) { ++ DEBUGP("deleting keymap %p at module unload time\n", pos); ++ list_del(pos); ++ kfree(pos); ++ } ++ WRITE_UNLOCK(&ip_ct_gre_lock); ++ ++ ip_conntrack_protocol_unregister(&gre); ++} ++ ++EXPORT_SYMBOL(ip_ct_gre_keymap_add); ++EXPORT_SYMBOL(ip_ct_gre_keymap_change); ++EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Wed Sep 24 09:16:22 2003 +@@ -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; +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Wed Sep 24 09:16:22 2003 +@@ -1,4 +1,3 @@ +-#define __NO_VERSION__ + #include + #include + #include +@@ -50,20 +49,28 @@ + #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_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 = 3 DAYS; ++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; ++ ++static unsigned long * tcp_timeouts[] ++= { 0, /* TCP_CONNTRACK_NONE */ ++ &ip_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */ ++ &ip_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ ++ &ip_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ ++ &ip_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */ ++ &ip_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */ ++ &ip_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */ ++ &ip_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */ ++ &ip_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */ ++ 0, /* TCP_CONNTRACK_LISTEN */ ++ }; ++ + #define sNO TCP_CONNTRACK_NONE + #define sES TCP_CONNTRACK_ESTABLISHED + #define sSS TCP_CONNTRACK_SYN_SENT +@@ -186,13 +193,13 @@ + && tcph->syn && tcph->ack) + conntrack->proto.tcp.handshake_ack + = htonl(ntohl(tcph->seq) + 1); +- 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 (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) { ++ WRITE_UNLOCK(&tcp_lock); + if (del_timer(&conntrack->timeout)) + conntrack->timeout.function((unsigned long)conntrack); + } else { +@@ -203,7 +210,8 @@ + && tcph->ack_seq == conntrack->proto.tcp.handshake_ack) + set_bit(IPS_ASSURED_BIT, &conntrack->status); + +- ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]); ++ WRITE_UNLOCK(&tcp_lock); ++ ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]); + } + + return NF_ACCEPT; +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_udp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_proto_udp.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_udp.c Wed Sep 24 09:16:22 2003 +@@ -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) +@@ -51,12 +51,12 @@ + { + /* 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); ++ if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { ++ 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; + } +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_quake3.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_quake3.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_quake3.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_quake3.c Wed Sep 24 09:17:58 2003 +@@ -0,0 +1,156 @@ ++/* Quake3 extension for IP connection tracking ++ * (C) 2002 by Filip Sneppe ++ * based on ip_conntrack_ftp.c and ip_conntrack_tftp.c ++ * ++ * ip_conntrack_quake3.c v0.04 2002-08-31 ++ * ++ * 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_conntrack_quake3.o ports=port1,port2,...port ++ * ++ * please give the ports of all Quake3 master servers You wish to ++ * connect to. If you don't specify ports, the default will be UDP ++ * port 27950. ++ * ++ * Thanks to the Ethereal folks for their analysis of the Quake3 protocol. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++struct module *ip_conntrack_quake3 = THIS_MODULE; ++ ++MODULE_AUTHOR("Filip Sneppe "); ++MODULE_DESCRIPTION("Netfilter connection tracking module for Quake III Arena"); ++MODULE_LICENSE("GPL"); ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of Quake III master servers"); ++#endif ++ ++/* Quake3 master server reply will add > 100 expectations per reply packet; when ++ doing lots of printk's, klogd may not be able to read /proc/kmsg fast enough */ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++struct quake3_search quake3s_conntrack = { "****", "getserversResponse", sizeof("getserversResponse") - 1 }; ++ ++static int quake3_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; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_conntrack_expect exp; ++ int i; ++ ++ /* Until there's been traffic both ways, don't look in packets. note: it's UDP ! */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_IS_REPLY) { ++ DEBUGP("ip_conntrack_quake3: not ok ! Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } else { DEBUGP("ip_conntrack_quake3: it's ok ! Conntrackinfo = %u\n", ctinfo); } ++ ++ if (strnicmp((const char *)udph + 12, quake3s_conntrack.pattern, quake3s_conntrack.plen) == 0) { ++ for(i=31; /* 8 bytes UDP hdr, 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */ ++ i+6 < ntohs(udph->len); ++ i+=7) { ++ DEBUGP("ip_conntrack_quake3: adding server at offset %u/%u %u.%u.%u.%u:%u\n", ++ i, ntohs(udph->len), ++ NIPQUAD( (u_int32_t) *( (u_int32_t *)( (int)udph + i ) ) ), ++ ntohs((__u16) *( (__u16 *)( (int)udph + i + 4 ) ) ) ); ++ ++ memset(&exp, 0, sizeof(exp)); ++ ++ exp.tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, ++ { (u_int32_t) *((u_int32_t *)((int)udph + i)), ++ { .udp = { (__u16) *((__u16 *)((int)udph+i+4)) } }, ++ IPPROTO_UDP } } ++ ); ++ exp.mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 0xFFFF }}); ++ exp.expectfn = NULL; ++ ++ ip_conntrack_expect_related(ct, &exp); ++ } ++ ++ } ++ ++ return(NF_ACCEPT); ++} ++ ++static struct ip_conntrack_helper quake3[MAX_PORTS]; ++static char quake3_names[MAX_PORTS][13]; /* quake3-65535 */ ++ ++static void fini(void) ++{ ++ int i; ++ ++ for(i = 0 ; (i < ports_c); i++) { ++ DEBUGP("ip_conntrack_quake3: unregistering helper for port %d\n", ++ ports[i]); ++ ip_conntrack_helper_unregister(&quake3[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret; ++ char *tmpname; ++ ++ if(!ports[0]) ++ ports[0]=QUAKE3_MASTER_PORT; ++ ++ for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { ++ /* Create helper structure */ ++ memset(&quake3[i], 0, sizeof(struct ip_conntrack_helper)); ++ ++ quake3[i].tuple.dst.protonum = IPPROTO_UDP; ++ quake3[i].tuple.src.u.udp.port = htons(ports[i]); ++ quake3[i].mask.dst.protonum = 0xFFFF; ++ quake3[i].mask.src.u.udp.port = 0xFFFF; ++ quake3[i].help = quake3_help; ++ quake3[i].me = THIS_MODULE; ++ ++ tmpname = &quake3_names[i][0]; ++ if (ports[i] == QUAKE3_MASTER_PORT) ++ sprintf(tmpname, "quake3"); ++ else ++ sprintf(tmpname, "quake3-%d", i); ++ quake3[i].name = tmpname; ++ ++ DEBUGP("ip_conntrack_quake3: registering helper for port %d\n", ++ ports[i]); ++ ++ ret=ip_conntrack_helper_register(&quake3[i]); ++ if(ret) { ++ fini(); ++ return(ret); ++ } ++ ports_c++; ++ } ++ ++ return(0); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c Wed Sep 24 09:18:01 2003 +@@ -0,0 +1,508 @@ ++/* RPC extension for IP (TCP) connection tracking, Version 2.2 ++ * (C) 2000 by Marcelo Barbosa Lima ++ * - original rpc tracking module ++ * - "recent" connection handling for kernel 2.3+ netfilter ++ * ++ * (C) 2001 by Rusty Russell ++ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ ++ * ++ * (C) 2002,2003 by Ian (Larry) Latter ++ * - upgraded conntrack modules to newnat api - kernel 2.4.20+ ++ * - extended matching to support filtering on procedures ++ * ++ * ip_conntrack_rpc_tpc.c,v 2.2 2003/01/12 18:30:00 ++ * ++ * 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_conntrack_rpc_tcp.o ports=port1,port2,...port ++ * ++ * Please give the ports of all RPC servers you wish to connect to. ++ * If you don't specify ports, the default will be port 111. ++ ** ++ * Note to all: ++ * ++ * RPCs should not be exposed to the internet - ask the Pentagon; ++ * ++ * "The unidentified crackers pleaded guilty in July to charges ++ * of juvenile delinquency stemming from a string of Pentagon ++ * network intrusions in February. ++ * ++ * The youths, going by the names TooShort and Makaveli, used ++ * a common server security hole to break in, according to ++ * Dane Jasper, owner of the California Internet service ++ * provider, Sonic. They used the hole, known as the 'statd' ++ * exploit, to attempt more than 800 break-ins, Jasper said." ++ * ++ * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 ++ * URL: http://www.wired.com/news/politics/0,1283,16098,00.html ++ ** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_n_c = 0; ++ ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers"); ++#endif ++ ++MODULE_AUTHOR("Marcelo Barbosa Lima "); ++MODULE_DESCRIPTION("RPC TCP connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \ ++ format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++DECLARE_RWLOCK(ipct_rpc_tcp_lock); ++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock) ++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock) ++#include ++ ++/* For future conections RPC, using client's cache bindings ++ * I'll use ip_conntrack_lock to lock these lists */ ++ ++LIST_HEAD(request_p_list_tcp); ++ ++ ++static void delete_request_p(unsigned long request_p_ul) ++{ ++ struct request_p *p = (void *)request_p_ul; ++ ++ WRITE_LOCK(&ipct_rpc_tcp_lock); ++ LIST_DELETE(&request_p_list_tcp, p); ++ WRITE_UNLOCK(&ipct_rpc_tcp_lock); ++ kfree(p); ++ return; ++} ++ ++ ++static void req_cl(struct request_p * r) ++{ ++ WRITE_LOCK(&ipct_rpc_tcp_lock); ++ del_timer(&r->timeout); ++ LIST_DELETE(&request_p_list_tcp, r); ++ WRITE_UNLOCK(&ipct_rpc_tcp_lock); ++ kfree(r); ++ return; ++} ++ ++ ++static void clean_request(struct list_head *list) ++{ ++ struct list_head *first = list->prev; ++ struct list_head *temp = list->next; ++ struct list_head *aux; ++ ++ if (list_empty(list)) ++ return; ++ ++ while (first != temp) { ++ aux = temp->next; ++ req_cl((struct request_p *)temp); ++ temp = aux; ++ } ++ req_cl((struct request_p *)temp); ++ return; ++} ++ ++ ++static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip, ++ u_int16_t port) ++{ ++ struct request_p *req_p; ++ ++ /* Verifies if entry already exists */ ++ WRITE_LOCK(&ipct_rpc_tcp_lock); ++ req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp, ++ struct request_p *, xid, ip, port); ++ ++ if (req_p) { ++ /* Refresh timeout */ ++ if (del_timer(&req_p->timeout)) { ++ req_p->timeout.expires = jiffies + EXP; ++ add_timer(&req_p->timeout); ++ } ++ WRITE_UNLOCK(&ipct_rpc_tcp_lock); ++ return; ++ ++ } ++ WRITE_UNLOCK(&ipct_rpc_tcp_lock); ++ ++ /* Allocate new request_p */ ++ req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC); ++ if (!req_p) { ++ DEBUGP("can't allocate request_p\n"); ++ return; ++ } ++ *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, ++ { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p, ++ NULL }}); ++ ++ /* Initialize timer */ ++ init_timer(&req_p->timeout); ++ req_p->timeout.function = delete_request_p; ++ add_timer(&req_p->timeout); ++ ++ /* Put in list */ ++ WRITE_LOCK(&ipct_rpc_tcp_lock); ++ list_prepend(&request_p_list_tcp, req_p); ++ WRITE_UNLOCK(&ipct_rpc_tcp_lock); ++ return; ++ ++} ++ ++ ++static int check_rpc_packet(const u_int32_t *data, ++ int dir, struct ip_conntrack *ct, ++ struct list_head request_p_list) ++{ ++ struct request_p *req_p; ++ u_int32_t xid; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ ++ /* Translstion's buffer for XDR */ ++ u_int16_t port_buf; ++ ++ ++ /* Get XID */ ++ xid = *data; ++ ++ /* This does sanity checking on RPC payloads, ++ * and permits only the RPC "get port" (3) ++ * in authorised procedures in client ++ * communications with the portmapper. ++ */ ++ ++ /* perform direction dependant RPC work */ ++ if (dir == IP_CT_DIR_ORIGINAL) { ++ ++ data += 5; ++ ++ /* Get RPC requestor */ ++ if (IXDR_GET_INT32(data) != 3) { ++ DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n"); ++ ++ data++; ++ ++ /* Jump Credentials and Verfifier */ ++ data += IXDR_GET_INT32(data) + 2; ++ data += IXDR_GET_INT32(data) + 2; ++ ++ /* Get RPC procedure */ ++ DEBUGP("RPC packet contains procedure request [%u]. [cont]\n", ++ (unsigned int)IXDR_GET_INT32(data)); ++ ++ /* Get RPC protocol and store against client parameters */ ++ data = data + 2; ++ alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip, ++ ct->tuplehash[dir].tuple.src.u.all); ++ ++ DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n", ++ xid, IXDR_GET_INT32(data), ++ NIPQUAD(ct->tuplehash[dir].tuple.src.ip), ++ ntohs(ct->tuplehash[dir].tuple.src.u.all)); ++ ++ DEBUGP("allocated RPC request for protocol %u. [done]\n", ++ (unsigned int)IXDR_GET_INT32(data)); ++ ++ } else { ++ ++ /* Check for returning packet's stored counterpart */ ++ req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp, ++ struct request_p *, xid, ++ ct->tuplehash[!dir].tuple.src.ip, ++ ct->tuplehash[!dir].tuple.src.u.all); ++ ++ /* Drop unexpected packets */ ++ if (!req_p) { ++ DEBUGP("packet is not expected. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Verifies if packet is really an RPC reply packet */ ++ data = data++; ++ if (IXDR_GET_INT32(data) != 1) { ++ DEBUGP("packet is not a valid RPC reply. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Is status accept? */ ++ data++; ++ if (IXDR_GET_INT32(data)) { ++ DEBUGP("packet is not an RPC accept. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Get Verifier length. Jump verifier */ ++ data++; ++ data = data + IXDR_GET_INT32(data) + 2; ++ ++ /* Is accpet status "success"? */ ++ if (IXDR_GET_INT32(data)) { ++ DEBUGP("packet is not an RPC accept status of success. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Get server port number */ ++ data++; ++ port_buf = (u_int16_t) IXDR_GET_INT32(data); ++ ++ /* If a packet has made it this far then it deserves an ++ * expectation ... if port == 0, then this service is ++ * not going to be registered. ++ */ ++ if (port_buf) { ++ DEBUGP("port found: %u\n", port_buf); ++ ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* Watch out, Radioactive-Man! */ ++ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; ++ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; ++ exp->mask.src.ip = 0xffffffff; ++ exp->mask.dst.ip = 0xffffffff; ++ ++ switch (req_p->proto) { ++ case IPPROTO_UDP: ++ exp->tuple.src.u.udp.port = 0; ++ exp->tuple.dst.u.udp.port = htons(port_buf); ++ exp->tuple.dst.protonum = IPPROTO_UDP; ++ exp->mask.src.u.udp.port = 0; ++ exp->mask.dst.u.udp.port = htons(0xffff); ++ exp->mask.dst.protonum = 0xffff; ++ break; ++ ++ case IPPROTO_TCP: ++ exp->tuple.src.u.tcp.port = 0; ++ exp->tuple.dst.u.tcp.port = htons(port_buf); ++ exp->tuple.dst.protonum = IPPROTO_TCP; ++ exp->mask.src.u.tcp.port = 0; ++ exp->mask.dst.u.tcp.port = htons(0xffff); ++ exp->mask.dst.protonum = 0xffff; ++ break; ++ } ++ exp->expectfn = NULL; ++ ++ ip_conntrack_expect_related(ct, &expect); ++ ++ DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n", ++ NIPQUAD(exp->tuple.src.ip), ++ NIPQUAD(exp->tuple.dst.ip), ++ port_buf, req_p->proto); ++ ++ DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n", ++ NIPQUAD(exp->mask.src.ip), ++ NIPQUAD(exp->mask.dst.ip), ++ exp->mask.dst.protonum); ++ ++ } ++ ++ req_cl(req_p); ++ ++ DEBUGP("packet evaluated. [expect]\n"); ++ return NF_ACCEPT; ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++ ++/* RPC TCP helper */ ++static int help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; ++ const u_int32_t *data = (const u_int32_t *)tcph + tcph->doff; ++ size_t tcplen = len - iph->ihl * 4; ++ ++ int dir = CTINFO2DIR(ctinfo); ++ int crp_ret; ++ ++ ++ DEBUGP("new packet to evaluate ..\n"); ++ ++ /* This works for packets like handshake packets, ignore */ ++ if (len == ((tcph->doff + iph->ihl) * 4)) { ++ DEBUGP("packet has no data (may still be handshaking). [skip]\n"); ++ 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("connection tracking state is; ctinfo=%u ..\n", ctinfo); ++ DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n"); ++ DEBUGP("packet is not yet part of a two way stream. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { ++ DEBUGP("TCP header length is; tcplen=%u ..\n", (unsigned) tcplen); ++ DEBUGP("packet does not contain a complete TCP header. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* FIXME: Source route IP option packets --RR */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *) tcph, tcplen, 0))) { ++ DEBUGP("csum; %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ DEBUGP("[note: failure to get past this error may indicate source routing]\n"); ++ DEBUGP("packet contains a bad checksum. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* perform direction dependant protocol work */ ++ if (dir == IP_CT_DIR_ORIGINAL) { ++ ++ DEBUGP("packet is from the initiator. [cont]\n"); ++ ++ /* Tests if packet len is ok */ ++ if ((tcplen - (tcph->doff * 4)) != 60) { ++ DEBUGP("packet length is not correct. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ } else { ++ ++ DEBUGP("packet is from the receiver. [cont]\n"); ++ ++ /* Tests if packet len is ok */ ++ if ((tcplen - (tcph->doff * 4)) != 32) { ++ DEBUGP("packet length is not correct. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ } ++ ++ /* Get to the data */ ++ data++; ++ ++ /* Check the RPC data */ ++ crp_ret = check_rpc_packet(data, dir, ct, request_p_list_tcp); ++ ++ return crp_ret; ++ ++} ++ ++ ++static struct ip_conntrack_helper rpc_helpers[MAX_PORTS]; ++ ++static void fini(void); ++ ++ ++static int __init init(void) ++{ ++ int port, ret; ++ static char name[10]; ++ ++ ++ /* If no port given, default to standard RPC port */ ++ if (ports[0] == 0) ++ ports[0] = RPC_PORT; ++ ++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { ++ memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper)); ++ ++ if (ports[port] == RPC_PORT) ++ sprintf(name, "rpc"); ++ else ++ sprintf(name, "rpc-%d", port); ++ ++ rpc_helpers[port].name = name; ++ rpc_helpers[port].me = THIS_MODULE; ++ rpc_helpers[port].max_expected = 1; ++ rpc_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ rpc_helpers[port].timeout = 0; ++ ++ rpc_helpers[port].tuple.dst.protonum = IPPROTO_TCP; ++ rpc_helpers[port].mask.dst.protonum = 0xffff; ++ ++ /* RPC can come from ports 0:65535 to ports[port] (111) */ ++ rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]); ++ rpc_helpers[port].mask.src.u.udp.port = htons(0xffff); ++ rpc_helpers[port].mask.dst.u.udp.port = htons(0x0); ++ ++ rpc_helpers[port].help = help; ++ ++ DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]); ++ DEBUGP("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(rpc_helpers[port].tuple.dst.ip), ++ ntohs(rpc_helpers[port].tuple.dst.u.tcp.port), ++ NIPQUAD(rpc_helpers[port].tuple.src.ip), ++ ntohs(rpc_helpers[port].tuple.src.u.tcp.port)); ++ DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(rpc_helpers[port].mask.dst.ip), ++ ntohs(rpc_helpers[port].mask.dst.u.tcp.port), ++ NIPQUAD(rpc_helpers[port].mask.src.ip), ++ ntohs(rpc_helpers[port].mask.src.u.tcp.port)); ++ ++ ret = ip_conntrack_helper_register(&rpc_helpers[port]); ++ ++ if (ret) { ++ printk("ERROR registering port %d\n", ++ ports[port]); ++ fini(); ++ return -EBUSY; ++ } ++ ports_n_c++; ++ } ++ return 0; ++} ++ ++ ++/* This function is intentionally _NOT_ defined as __exit, because ++ * it is needed by the init function */ ++static void fini(void) ++{ ++ int port; ++ ++ DEBUGP("cleaning request list\n"); ++ clean_request(&request_p_list_tcp); ++ ++ for (port = 0; (port < ports_n_c) && ports[port]; port++) { ++ DEBUGP("unregistering port %d\n", ports[port]); ++ ip_conntrack_helper_unregister(&rpc_helpers[port]); ++ } ++} ++ ++ ++module_init(init); ++module_exit(fini); ++ ++struct module *ip_conntrack_rpc_tcp = THIS_MODULE; ++EXPORT_SYMBOL(request_p_list_tcp); ++EXPORT_SYMBOL(ip_conntrack_rpc_tcp); ++EXPORT_SYMBOL(ipct_rpc_tcp_lock); ++ +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_rpc_udp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_rpc_udp.c Wed Sep 24 09:18:01 2003 +@@ -0,0 +1,503 @@ ++/* RPC extension for IP (UDP) connection tracking, Version 2.2 ++ * (C) 2000 by Marcelo Barbosa Lima ++ * - original rpc tracking module ++ * - "recent" connection handling for kernel 2.3+ netfilter ++ * ++ * (C) 2001 by Rusty Russell ++ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ ++ * ++ * (C) 2002,2003 by Ian (Larry) Latter ++ * - upgraded conntrack modules to newnat api - kernel 2.4.20+ ++ * - extended matching to support filtering on procedures ++ * ++ * ip_conntrack_rpc_udp.c,v 2.2 2003/01/12 18:30:00 ++ * ++ * 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_conntrack_rpc_udp.o ports=port1,port2,...port ++ * ++ * Please give the ports of all RPC servers you wish to connect to. ++ * If you don't specify ports, the default will be port 111. ++ ** ++ * Note to all: ++ * ++ * RPCs should not be exposed to the internet - ask the Pentagon; ++ * ++ * "The unidentified crackers pleaded guilty in July to charges ++ * of juvenile delinquency stemming from a string of Pentagon ++ * network intrusions in February. ++ * ++ * The youths, going by the names TooShort and Makaveli, used ++ * a common server security hole to break in, according to ++ * Dane Jasper, owner of the California Internet service ++ * provider, Sonic. They used the hole, known as the 'statd' ++ * exploit, to attempt more than 800 break-ins, Jasper said." ++ * ++ * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 ++ * URL: http://www.wired.com/news/politics/0,1283,16098,00.html ++ ** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_n_c = 0; ++ ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers"); ++#endif ++ ++MODULE_AUTHOR("Marcelo Barbosa Lima "); ++MODULE_DESCRIPTION("RPC UDP connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \ ++ format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++DECLARE_RWLOCK(ipct_rpc_udp_lock); ++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock) ++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock) ++#include ++ ++/* For future conections RPC, using client's cache bindings ++ * I'll use ip_conntrack_lock to lock these lists */ ++ ++LIST_HEAD(request_p_list_udp); ++ ++ ++static void delete_request_p(unsigned long request_p_ul) ++{ ++ struct request_p *p = (void *)request_p_ul; ++ ++ WRITE_LOCK(&ipct_rpc_udp_lock); ++ LIST_DELETE(&request_p_list_udp, p); ++ WRITE_UNLOCK(&ipct_rpc_udp_lock); ++ kfree(p); ++ return; ++} ++ ++ ++static void req_cl(struct request_p * r) ++{ ++ WRITE_LOCK(&ipct_rpc_udp_lock); ++ del_timer(&r->timeout); ++ LIST_DELETE(&request_p_list_udp, r); ++ WRITE_UNLOCK(&ipct_rpc_udp_lock); ++ kfree(r); ++ return; ++} ++ ++ ++static void clean_request(struct list_head *list) ++{ ++ struct list_head *first = list->prev; ++ struct list_head *temp = list->next; ++ struct list_head *aux; ++ ++ if (list_empty(list)) ++ return; ++ ++ while (first != temp) { ++ aux = temp->next; ++ req_cl((struct request_p *)temp); ++ temp = aux; ++ } ++ req_cl((struct request_p *)temp); ++ return; ++} ++ ++ ++static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip, ++ u_int16_t port) ++{ ++ struct request_p *req_p; ++ ++ /* Verifies if entry already exists */ ++ WRITE_LOCK(&ipct_rpc_udp_lock); ++ req_p = LIST_FIND(&request_p_list_udp, request_p_cmp, ++ struct request_p *, xid, ip, port); ++ ++ if (req_p) { ++ /* Refresh timeout */ ++ if (del_timer(&req_p->timeout)) { ++ req_p->timeout.expires = jiffies + EXP; ++ add_timer(&req_p->timeout); ++ } ++ WRITE_UNLOCK(&ipct_rpc_udp_lock); ++ return; ++ ++ } ++ WRITE_UNLOCK(&ipct_rpc_udp_lock); ++ ++ /* Allocate new request_p */ ++ req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC); ++ if (!req_p) { ++ DEBUGP("can't allocate request_p\n"); ++ return; ++ } ++ *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, ++ { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p, ++ NULL }}); ++ ++ /* Initialize timer */ ++ init_timer(&req_p->timeout); ++ req_p->timeout.function = delete_request_p; ++ add_timer(&req_p->timeout); ++ ++ /* Put in list */ ++ WRITE_LOCK(&ipct_rpc_udp_lock); ++ list_prepend(&request_p_list_udp, req_p); ++ WRITE_UNLOCK(&ipct_rpc_udp_lock); ++ return; ++ ++} ++ ++ ++static int check_rpc_packet(const u_int32_t *data, ++ int dir, struct ip_conntrack *ct, ++ struct list_head request_p_list) ++{ ++ struct request_p *req_p; ++ u_int32_t xid; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ ++ /* Translstion's buffer for XDR */ ++ u_int16_t port_buf; ++ ++ ++ /* Get XID */ ++ xid = *data; ++ ++ /* This does sanity checking on RPC payloads, ++ * and permits only the RPC "get port" (3) ++ * in authorised procedures in client ++ * communications with the portmapper. ++ */ ++ ++ /* perform direction dependant RPC work */ ++ if (dir == IP_CT_DIR_ORIGINAL) { ++ ++ data += 5; ++ ++ /* Get RPC requestor */ ++ if (IXDR_GET_INT32(data) != 3) { ++ DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n"); ++ ++ data++; ++ ++ /* Jump Credentials and Verfifier */ ++ data = data + IXDR_GET_INT32(data) + 2; ++ data = data + IXDR_GET_INT32(data) + 2; ++ ++ /* Get RPC procedure */ ++ DEBUGP("RPC packet contains procedure request [%u]. [cont]\n", ++ (unsigned int)IXDR_GET_INT32(data)); ++ ++ /* Get RPC protocol and store against client parameters */ ++ data = data + 2; ++ alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip, ++ ct->tuplehash[dir].tuple.src.u.all); ++ ++ DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n", ++ xid, IXDR_GET_INT32(data), ++ NIPQUAD(ct->tuplehash[dir].tuple.src.ip), ++ ntohs(ct->tuplehash[dir].tuple.src.u.all)); ++ ++ DEBUGP("allocated RPC request for protocol %u. [done]\n", ++ (unsigned int)IXDR_GET_INT32(data)); ++ ++ } else { ++ ++ /* Check for returning packet's stored counterpart */ ++ req_p = LIST_FIND(&request_p_list_udp, request_p_cmp, ++ struct request_p *, xid, ++ ct->tuplehash[!dir].tuple.src.ip, ++ ct->tuplehash[!dir].tuple.src.u.all); ++ ++ /* Drop unexpected packets */ ++ if (!req_p) { ++ DEBUGP("packet is not expected. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Verifies if packet is really an RPC reply packet */ ++ data = data++; ++ if (IXDR_GET_INT32(data) != 1) { ++ DEBUGP("packet is not a valid RPC reply. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Is status accept? */ ++ data++; ++ if (IXDR_GET_INT32(data)) { ++ DEBUGP("packet is not an RPC accept. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Get Verifier length. Jump verifier */ ++ data++; ++ data = data + IXDR_GET_INT32(data) + 2; ++ ++ /* Is accpet status "success"? */ ++ if (IXDR_GET_INT32(data)) { ++ DEBUGP("packet is not an RPC accept status of success. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Get server port number */ ++ data++; ++ port_buf = (u_int16_t) IXDR_GET_INT32(data); ++ ++ /* If a packet has made it this far then it deserves an ++ * expectation ... if port == 0, then this service is ++ * not going to be registered. ++ */ ++ if (port_buf) { ++ DEBUGP("port found: %u\n", port_buf); ++ ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* Watch out, Radioactive-Man! */ ++ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; ++ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; ++ exp->mask.src.ip = 0xffffffff; ++ exp->mask.dst.ip = 0xffffffff; ++ ++ switch (req_p->proto) { ++ case IPPROTO_UDP: ++ exp->tuple.src.u.udp.port = 0; ++ exp->tuple.dst.u.udp.port = htons(port_buf); ++ exp->tuple.dst.protonum = IPPROTO_UDP; ++ exp->mask.src.u.udp.port = 0; ++ exp->mask.dst.u.udp.port = htons(0xffff); ++ exp->mask.dst.protonum = 0xffff; ++ break; ++ ++ case IPPROTO_TCP: ++ exp->tuple.src.u.tcp.port = 0; ++ exp->tuple.dst.u.tcp.port = htons(port_buf); ++ exp->tuple.dst.protonum = IPPROTO_TCP; ++ exp->mask.src.u.tcp.port = 0; ++ exp->mask.dst.u.tcp.port = htons(0xffff); ++ exp->mask.dst.protonum = 0xffff; ++ break; ++ } ++ exp->expectfn = NULL; ++ ++ ip_conntrack_expect_related(ct, &expect); ++ ++ DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n", ++ NIPQUAD(exp->tuple.src.ip), ++ NIPQUAD(exp->tuple.dst.ip), ++ port_buf, req_p->proto); ++ ++ DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n", ++ NIPQUAD(exp->mask.src.ip), ++ NIPQUAD(exp->mask.dst.ip), ++ exp->mask.dst.protonum); ++ ++ } ++ ++ req_cl(req_p); ++ ++ DEBUGP("packet evaluated. [expect]\n"); ++ return NF_ACCEPT; ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++ ++/* RPC UDP helper */ ++static int 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; ++ const u_int32_t *data = (const u_int32_t *)udph + 2; ++ size_t udplen = len - iph->ihl * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ int crp_ret; ++ ++ /* Checksum */ ++ const u_int16_t *chsm = (const u_int16_t *)udph + 3; ++ ++ ++ DEBUGP("new packet to evaluate ..\n"); ++ ++ /* Not whole UDP header? */ ++ if (udplen < sizeof(struct udphdr)) { ++ DEBUGP("UDP header length is; udplen=%u ..\n", (unsigned) udplen); ++ DEBUGP("packet does not contain a complete UDP header. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* FIXME: Source route IP option packets --RR */ ++ if (*chsm) { ++ if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, ++ csum_partial((char *)udph, udplen, 0))) { ++ DEBUGP("[note: failure to get past this error may indicate source routing]\n"); ++ DEBUGP("packet contains a bad checksum. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ } ++ ++ /* perform direction dependant protocol work */ ++ if (dir == IP_CT_DIR_ORIGINAL) { ++ ++ DEBUGP("packet is from the initiator. [cont]\n"); ++ ++ /* Tests if packet len is ok */ ++ if ((udplen - sizeof(struct udphdr)) != 56) { ++ DEBUGP("packet length is not correct. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ } else { ++ ++ DEBUGP("packet is from the receiver. [cont]\n"); ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo); ++ DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n"); ++ DEBUGP("packet is not yet part of a two way stream. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Tests if packet len is ok */ ++ if ((udplen - sizeof(struct udphdr)) != 28) { ++ DEBUGP("packet length is not correct. [skip]\n"); ++ return NF_ACCEPT; ++ } ++ ++ } ++ ++ /* Get to the data */ ++ /* udp *data == *correct */ ++ ++ /* Check the RPC data */ ++ crp_ret = check_rpc_packet(data, dir, ct, request_p_list_udp); ++ ++ return crp_ret; ++ ++} ++ ++ ++static struct ip_conntrack_helper rpc_helpers[MAX_PORTS]; ++ ++static void fini(void); ++ ++ ++static int __init init(void) ++{ ++ int port, ret; ++ static char name[10]; ++ ++ ++ /* If no port given, default to standard RPC port */ ++ if (ports[0] == 0) ++ ports[0] = RPC_PORT; ++ ++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { ++ memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper)); ++ ++ if (ports[port] == RPC_PORT) ++ sprintf(name, "rpc"); ++ else ++ sprintf(name, "rpc-%d", port); ++ ++ rpc_helpers[port].name = name; ++ rpc_helpers[port].me = THIS_MODULE; ++ rpc_helpers[port].max_expected = 1; ++ rpc_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ rpc_helpers[port].timeout = 0; ++ ++ rpc_helpers[port].tuple.dst.protonum = IPPROTO_UDP; ++ rpc_helpers[port].mask.dst.protonum = 0xffff; ++ ++ /* RPC can come from ports 0:65535 to ports[port] (111) */ ++ rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]); ++ rpc_helpers[port].mask.src.u.udp.port = htons(0xffff); ++ rpc_helpers[port].mask.dst.u.udp.port = htons(0x0); ++ ++ rpc_helpers[port].help = help; ++ ++ DEBUGP("registering helper for port #%d: %d/UDP\n", port, ports[port]); ++ DEBUGP("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(rpc_helpers[port].tuple.dst.ip), ++ ntohs(rpc_helpers[port].tuple.dst.u.udp.port), ++ NIPQUAD(rpc_helpers[port].tuple.src.ip), ++ ntohs(rpc_helpers[port].tuple.src.u.udp.port)); ++ DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(rpc_helpers[port].mask.dst.ip), ++ ntohs(rpc_helpers[port].mask.dst.u.udp.port), ++ NIPQUAD(rpc_helpers[port].mask.src.ip), ++ ntohs(rpc_helpers[port].mask.src.u.udp.port)); ++ ++ ret = ip_conntrack_helper_register(&rpc_helpers[port]); ++ ++ if (ret) { ++ printk("ERROR registering port %d\n", ++ ports[port]); ++ fini(); ++ return -EBUSY; ++ } ++ ports_n_c++; ++ } ++ return 0; ++} ++ ++ ++/* This function is intentionally _NOT_ defined as __exit, because ++ * it is needed by the init function */ ++static void fini(void) ++{ ++ int port; ++ ++ DEBUGP("cleaning request list\n"); ++ clean_request(&request_p_list_udp); ++ ++ for (port = 0; (port < ports_n_c) && ports[port]; port++) { ++ DEBUGP("unregistering port %d\n", ports[port]); ++ ip_conntrack_helper_unregister(&rpc_helpers[port]); ++ } ++} ++ ++ ++module_init(init); ++module_exit(fini); ++ ++struct module *ip_conntrack_rpc_udp = THIS_MODULE; ++EXPORT_SYMBOL(request_p_list_udp); ++EXPORT_SYMBOL(ip_conntrack_rpc_udp); ++EXPORT_SYMBOL(ipct_rpc_udp_lock); ++ +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_rsh.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_rsh.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_rsh.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_rsh.c Wed Sep 24 09:18:03 2003 +@@ -0,0 +1,331 @@ ++/* RSH extension for IP connection tracking, Version 1.0 ++ * (C) 2002 by Ian (Larry) Latter ++ * based on HW's ip_conntrack_irc.c ++ * ++ * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26 ++ * ++ * 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_conntrack_rsh.o ports=port1,port2,...port ++ * ++ * please give the ports of all RSH servers You wish to connect to. ++ * If You don't specify ports, the default will be port 514 ++ ** ++ * Note to all: ++ * RSH blows ... you should use SSH (openssh.org) to replace it, ++ * unfortunately I babysit some sysadmins that won't migrate ++ * their legacy crap, in our second tier. ++ */ ++ ++ ++/* ++ * Some docco ripped from the net to teach me all there is to know about ++ * RSH, in 16.5 seconds (ie, all of the non-netfilter docco used to write ++ * this module). ++ * ++ * I have no idea what "unix rshd man pages" these guys have .. but that ++ * is some pretty detailed docco! ++ ** ++ * ++ * 4. Of the rsh protocol. ++ * ----------------------- ++ * ++ * The rshd listens on TCP port #514. The following info is from the unix ++ * rshd man pages : ++ * ++ * "Service Request Protocol ++ * ++ * When the rshd daemon receives a service request, it initiates the ++ * following protocol: ++ * ++ * 1. The rshd daemon checks the source port number for the request. ++ * If the port number is not in the range 0 through 1023, the rshd daemon ++ * terminates the connection. ++ * ++ * 2. The rshd daemon reads characters from the socket up to a null byte. ++ * The string read is interpreted as an ASCII number (base 10). If this ++ * number is nonzero, the rshd daemon interprets it as the port number ++ * of a secondary stream to be used as standard error. A second connection ++ * is created to the specified port on the client host. The source port ++ * on the local host is in the range 0 through 1023. ++ * ++ * 3. The rshd daemon uses the source address of the initial connection ++ * request to determine the name of the client host. If the name cannot ++ * be determined, the rshd daemon uses the dotted decimal representation ++ * of the client host's address. ++ * ++ * 4. The rshd daemon retrieves the following information from the initial ++ * socket: ++ * ++ * * A null-terminated string of at most 16 bytes interpreted as ++ * the user name of the user on the client host. ++ * ++ * * A null-terminated string of at most 16 bytes interpreted as ++ * the user name to be used on the local server host. ++ * ++ * * Another null-terminated string interpreted as a command line ++ * to be passed to a shell on the local server host. ++ * ++ * 5. The rshd daemon attempts to validate the user using the following steps: ++ * ++ * a. The rshd daemon looks up the local user name in the /etc/passwd ++ * file and tries to switch to the home directory (using the chdir ++ * subroutine). If either the lookup or the directory change fails, ++ * the rshd daemon terminates the connection. ++ * ++ * b. If the local user ID is a nonzero value, the rshd daemon searches ++ * the /etc/hosts.equiv file to see if the name of the client ++ * workstation is listed. If the client workstation is listed as an ++ * equivalent host, the rshd daemon validates the user. ++ * ++ * c. If the $HOME/.rhosts file exists, the rshd daemon tries to ++ * authenticate the user by checking the .rhosts file. ++ * ++ * d. If either the $HOME/.rhosts authentication fails or the ++ * client host is not an equivalent host, the rshd daemon ++ * terminates the connection. ++ * ++ * 6. Once rshd validates the user, the rshd daemon returns a null byte ++ * on the initial connection and passes the command line to the user's ++ * local login shell. The shell then inherits the network connections ++ * established by the rshd daemon." ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_n_c = 0; ++ ++MODULE_AUTHOR("Ian (Larry) Latter "); ++MODULE_DESCRIPTION("RSH 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 RSH servers"); ++#endif ++ ++DECLARE_LOCK(ip_rsh_lock); ++struct module *ip_conntrack_rsh = THIS_MODULE; ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rsh: " \ ++ format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++ ++ ++/* 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; ++ const char *data = (const char *) tcph + tcph->doff * 4; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_rsh_expect *exp_rsh_info = &exp->help.exp_rsh_info; ++ u_int16_t port; ++ int maxoctet; ++ ++ /* note that "maxoctet" is used to maintain sanity (8 was the ++ * original array size used in rshd/glibc) -- is there a ++ * vulnerability in rshd.c in the looped port *= 10? ++ */ ++ ++ ++ DEBUGP("entered\n"); ++ ++ /* bail if packet is not from RSH client */ ++ 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("Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { ++ DEBUGP("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("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ /* find the rsh stderr port */ ++ maxoctet = 4; ++ port = 0; ++ for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) { ++ if (*data < 0) ++ return(1); ++ if (*data == 0) ++ break; ++ if (*data < 48 || *data > 57) { ++ DEBUGP("these aren't the packets you're looking for ..\n"); ++ return NF_ACCEPT; ++ } ++ port = port * 10 + ( *data - 48 ); ++ } ++ ++ /* dont relate sessions that try to expose the client */ ++ DEBUGP("found port %u\n", port); ++ if (port > 1023) { ++ DEBUGP("skipping, expected port size is greater than 1023!\n"); ++ return NF_ACCEPT; ++ } ++ ++ ++ LOCK_BH(&ip_rsh_lock); ++ ++ /* new(,related) connection is; ++ * reply + dst (uint)port + src port (0:1023) ++ */ ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* save some discovered data, in case someone ever wants to write ++ * a NAT module for this bastard .. ++ */ ++ exp_rsh_info->port = port; ++ ++ DEBUGP("wrote info port=%u\n", exp_rsh_info->port); ++ ++ ++ /* Watch out, Radioactive-Man! */ ++ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; ++ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; ++ exp->tuple.src.u.tcp.port = 0; ++ exp->tuple.dst.u.tcp.port = htons(exp_rsh_info->port); ++ exp->tuple.dst.protonum = IPPROTO_TCP; ++ ++ exp->mask.src.ip = 0xffffffff; ++ exp->mask.dst.ip = 0xffffffff; ++ ++ exp->mask.src.u.tcp.port = htons(0xfc00); ++ exp->mask.dst.u.tcp.port = htons(0xfc00); ++ exp->mask.dst.protonum = 0xffff; ++ ++ exp->expectfn = NULL; ++ ++ ip_conntrack_expect_related(ct, &expect); ++ ++ DEBUGP("expect related ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++ NIPQUAD(exp->tuple.src.ip), ++ ntohs(exp->tuple.src.u.tcp.port), ++ NIPQUAD(exp->tuple.dst.ip), ++ ntohs(exp->tuple.dst.u.tcp.port)); ++ ++ DEBUGP("expect related mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++ NIPQUAD(exp->mask.src.ip), ++ ntohs(exp->mask.src.u.tcp.port), ++ NIPQUAD(exp->mask.dst.ip), ++ ntohs(exp->mask.dst.u.tcp.port)); ++ UNLOCK_BH(&ip_rsh_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper rsh_helpers[MAX_PORTS]; ++ ++static void fini(void); ++ ++static int __init init(void) ++{ ++ int port, ret; ++ static char name[10]; ++ ++ ++ /* If no port given, default to standard RSH port */ ++ if (ports[0] == 0) ++ ports[0] = RSH_PORT; ++ ++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { ++ memset(&rsh_helpers[port], 0, sizeof(struct ip_conntrack_helper)); ++ ++ if (ports[port] == RSH_PORT) ++ sprintf(name, "rsh"); ++ else ++ sprintf(name, "rsh-%d", port); ++ ++ rsh_helpers[port].name = name; ++ rsh_helpers[port].me = THIS_MODULE; ++ rsh_helpers[port].max_expected = 1; ++ rsh_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ rsh_helpers[port].timeout = 0; ++ ++ rsh_helpers[port].tuple.dst.protonum = IPPROTO_TCP; ++ rsh_helpers[port].mask.dst.protonum = 0xffff; ++ ++ /* RSH must come from ports 0:1023 to ports[port] (514) */ ++ rsh_helpers[port].tuple.src.u.tcp.port = htons(ports[port]); ++ rsh_helpers[port].mask.src.u.tcp.port = htons(0xfc00); ++ rsh_helpers[port].mask.dst.u.tcp.port = htons(0xfc00); ++ ++ rsh_helpers[port].help = help; ++ ++ DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]); ++ DEBUGP("helper match ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++ NIPQUAD(rsh_helpers[port].tuple.src.ip), ++ ntohs(rsh_helpers[port].tuple.src.u.tcp.port), ++ NIPQUAD(rsh_helpers[port].tuple.dst.ip), ++ ntohs(rsh_helpers[port].tuple.dst.u.tcp.port)); ++ DEBUGP("helper match mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++ NIPQUAD(rsh_helpers[port].mask.src.ip), ++ ntohs(rsh_helpers[port].mask.src.u.tcp.port), ++ NIPQUAD(rsh_helpers[port].mask.dst.ip), ++ ntohs(rsh_helpers[port].mask.dst.u.tcp.port)); ++ ++ ret = ip_conntrack_helper_register(&rsh_helpers[port]); ++ ++ if (ret) { ++ printk("ERROR registering port %d\n", ++ ports[port]); ++ fini(); ++ return -EBUSY; ++ } ++ ports_n_c++; ++ } ++ return 0; ++} ++ ++/* This function is intentionally _NOT_ defined as __exit, because ++ * it is needed by the init function */ ++static void fini(void) ++{ ++ int port; ++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { ++ DEBUGP("unregistering port %d\n", ports[port]); ++ ip_conntrack_helper_unregister(&rsh_helpers[port]); ++ } ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_standalone.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_standalone.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_standalone.c Wed Sep 24 09:18:16 2003 +@@ -7,6 +7,7 @@ + /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General + Public Licence. */ + ++#include + #include + #include + #include +@@ -16,6 +17,9 @@ + #include + #include + #include ++#ifdef CONFIG_SYSCTL ++#include ++#endif + #include + + #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) +@@ -77,7 +81,7 @@ + } + + static unsigned int +-print_conntrack(char *buffer, const struct ip_conntrack *conntrack) ++print_conntrack(char *buffer, struct ip_conntrack *conntrack) + { + unsigned int len; + struct ip_conntrack_protocol *proto +@@ -95,15 +99,18 @@ + len += print_tuple(buffer + len, + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, + proto); +- if (!(conntrack->status & IPS_SEEN_REPLY)) ++ if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) + len += sprintf(buffer + len, "[UNREPLIED] "); + len += print_tuple(buffer + len, + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, + proto); +- if (conntrack->status & IPS_ASSURED) ++ if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) + len += sprintf(buffer + len, "[ASSURED] "); + len += sprintf(buffer + len, "use=%u ", + atomic_read(&conntrack->ct_general.use)); ++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) ++ len += sprintf(buffer + len, "mark=%ld ", conntrack->mark); ++#endif + len += sprintf(buffer + len, "\n"); + + return len; +@@ -239,6 +246,98 @@ + 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_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; ++ ++/* 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[] = { ++ {NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max", ++ &ip_conntrack_max, sizeof(int), 0644, NULL, ++ &proc_dointvec}, ++ {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_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} ++}; ++ ++#define NET_IP_CONNTRACK_MAX 2089 ++ ++static ctl_table ip_ct_netfilter_table[] = { ++ {NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0}, ++ {NET_IP_CONNTRACK_MAX, "ip_conntrack_max", ++ &ip_conntrack_max, sizeof(int), 0644, NULL, ++ &proc_dointvec}, ++ {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; +@@ -274,10 +373,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); +@@ -293,13 +402,20 @@ + return ret; + } + +-/* FIXME: Allow NULL functions and sub in pointers to generic for +- them. --RR */ ++/** ++ * ip_conntrack_protocol_register - Register layer 4 protocol helper ++ * @proto: structure describing this layer 4 protocol helper ++ * ++ * This function is called by layer 4 protocol helpers to register ++ * themselves with the conntrack core. ++ */ + int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) + { + int ret = 0; + struct list_head *i; + ++ /* FIXME: Allow NULL functions and sub in pointers to generic for ++ them. --RR */ + WRITE_LOCK(&ip_conntrack_lock); + for (i = protocol_list.next; i != &protocol_list; i = i->next) { + if (((struct ip_conntrack_protocol *)i)->proto +@@ -317,12 +433,20 @@ + return ret; + } + ++/** ++ * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper ++ * @proto: structure describing this layer 4 protocol helper ++ * ++ * This function is called byh layer 4 protocol helpers to unregister ++ * themselvers from the conntrack core. Please note that all conntrack ++ * entries for this protocol are deleted from the conntrack hash table. ++ */ + void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) + { + WRITE_LOCK(&ip_conntrack_lock); + +- /* ip_ct_find_proto() returns proto_generic in case there is no protocol +- * helper. So this should be enough - HW */ ++ /* ip_ct_find_proto() returns proto_generic in case there is no ++ * protocol helper. So this should be enough - HW */ + LIST_DELETE(&protocol_list, proto); + WRITE_UNLOCK(&ip_conntrack_lock); + +@@ -355,11 +479,13 @@ + EXPORT_SYMBOL(ip_conntrack_alter_reply); + EXPORT_SYMBOL(ip_conntrack_destroyed); + EXPORT_SYMBOL(ip_conntrack_get); ++EXPORT_SYMBOL(ip_conntrack_get_tuple); + EXPORT_SYMBOL(ip_conntrack_module); + EXPORT_SYMBOL(ip_conntrack_helper_register); + EXPORT_SYMBOL(ip_conntrack_helper_unregister); + EXPORT_SYMBOL(ip_ct_selective_cleanup); + EXPORT_SYMBOL(ip_ct_refresh); ++EXPORT_SYMBOL(ip_ct_death_by_timeout); + EXPORT_SYMBOL(ip_ct_find_proto); + EXPORT_SYMBOL(__ip_ct_find_proto); + EXPORT_SYMBOL(ip_ct_find_helper); +@@ -374,5 +500,6 @@ + EXPORT_SYMBOL(ip_conntrack_expect_list); + EXPORT_SYMBOL(ip_conntrack_lock); + EXPORT_SYMBOL(ip_conntrack_hash); ++EXPORT_SYMBOL(ip_conntrack_untracked); + EXPORT_SYMBOL_GPL(ip_conntrack_find_get); + EXPORT_SYMBOL_GPL(ip_conntrack_put); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_talk.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_talk.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_talk.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_talk.c Wed Sep 24 09:18:08 2003 +@@ -0,0 +1,360 @@ ++/* ++ * 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 ++ * ++ * The helper does not support simultaneous talk requests. ++ ** ++ * ++ * 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 ++#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_expect(struct ip_conntrack *ct); ++static int ntalk_expect(struct ip_conntrack *ct); ++ ++static int (*talk_expectfn[2])(struct ip_conntrack *ct) = {talk_expect, ntalk_expect}; ++ ++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 mode, ++ u_char type, ++ u_char answer, ++ struct talk_addr *addr) ++{ ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_talk_expect *exp_talk_info = &exp->help.exp_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 && type == mode)) ++ return NF_ACCEPT; ++ ++ memset(&expect, 0, sizeof(expect)); ++ ++ if (type == ANNOUNCE) { ++ ++ DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n"); ++ ++ /* update the talk info */ ++ LOCK_BH(&ip_talk_lock); ++ exp_talk_info->port = htons(talk_port); ++ ++ /* expect callee client -> caller server message */ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[dir].tuple.src.ip, ++ { 0 } }, ++ { ct->tuplehash[dir].tuple.dst.ip, ++ { .tcp = { htons(talk_port) } }, ++ IPPROTO_UDP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); ++ ++ exp->expectfn = talk_expectfn[talk_port - TALK_PORT]; ++ ++ DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller daemon %u.%u.%u.%u:%u!\n", ++ NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.udp.port), ++ NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.udp.port)); ++ ++ /* Ignore failure; should only happen with NAT */ ++ ip_conntrack_expect_related(ct, &expect); ++ 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); ++ exp_talk_info->port = addr->ta_port; ++ ++ /* expect callee client -> caller client connection */ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { addr->ta_addr, ++ { addr->ta_port }, ++ IPPROTO_TCP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = NULL; ++ ++ DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller client %u.%u.%u.%u:%u!\n", ++ NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), ++ NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); ++ ++ /* Ignore failure; should only happen with NAT */ ++ ip_conntrack_expect_related(ct, &expect); ++ 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, ++ u_char mode) ++{ ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + sizeof(struct udphdr); ++ int dir = CTINFO2DIR(ctinfo); ++ size_t udplen; ++ ++ DEBUGP("ip_ct_talk_help: help entered\n"); ++ ++ /* 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, mode, ++ ((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, mode, ++ ((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, mode, ++ ((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 lookup_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, LOOK_UP); ++} ++ ++static int lookup_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, LOOK_UP); ++} ++ ++static struct ip_conntrack_helper lookup_helpers[2] = ++ { { { NULL, NULL }, ++ "talk", /* name */ ++ 0, /* flags */ ++ NULL, /* module */ ++ 1, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(TALK_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_UDP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ lookup_help }, /* helper */ ++ { { NULL, NULL }, ++ "ntalk", /* name */ ++ 0, /* flags */ ++ NULL, /* module */ ++ 1, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(NTALK_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_UDP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ lookup_nhelp } /* helper */ ++ }; ++ ++static int talk_expect(struct ip_conntrack *ct) ++{ ++ DEBUGP("ip_conntrack_talk: calling talk_expectfn for ct %p\n", ct); ++ WRITE_LOCK(&ip_conntrack_lock); ++ ct->helper = &lookup_helpers[0]; ++ WRITE_UNLOCK(&ip_conntrack_lock); ++ ++ return NF_ACCEPT; /* unused */ ++} ++ ++static int ntalk_expect(struct ip_conntrack *ct) ++{ ++ DEBUGP("ip_conntrack_talk: calling ntalk_expectfn for ct %p\n", ct); ++ WRITE_LOCK(&ip_conntrack_lock); ++ ct->helper = &lookup_helpers[1]; ++ WRITE_UNLOCK(&ip_conntrack_lock); ++ ++ return NF_ACCEPT; /* unused */ ++} ++ ++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, ANNOUNCE); ++} ++ ++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, ANNOUNCE); ++} ++ ++static struct ip_conntrack_helper talk_helpers[2] = ++ { { { NULL, NULL }, ++ "talk", /* name */ ++ 0, /* flags */ ++ THIS_MODULE, /* module */ ++ 1, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(TALK_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_UDP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ help }, /* helper */ ++ { { NULL, NULL }, ++ "ntalk", /* name */ ++ 0, /* flags */ ++ THIS_MODULE, /* module */ ++ 1, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(NTALK_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_UDP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ nhelp } /* helper */ ++ }; ++ ++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]); ++} ++ ++EXPORT_SYMBOL(ip_talk_lock); ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.4.20/net/ipv4/netfilter/ip_conntrack_tftp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_conntrack_tftp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_conntrack_tftp.c Wed Sep 24 09:16:24 2003 +@@ -0,0 +1,129 @@ ++/* ++ * Licensed under GNU GPL version 2 Copyright Magnus Boden ++ * Version: 0.0.7 ++ * ++ * Thu 21 Mar 2002 Harald Welte ++ * - port to newnat API ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Magnus Boden "); ++MODULE_DESCRIPTION("Netfilter connection tracking module for tftp"); ++MODULE_LICENSE("GPL"); ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++#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(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \ ++ format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++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_expect exp; ++ ++ switch (ntohs(tftph->opcode)) { ++ /* RRQ and WRQ works the same way */ ++ case TFTP_OPCODE_READ: ++ case TFTP_OPCODE_WRITE: ++ DEBUGP(""); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ memset(&exp, 0, sizeof(exp)); ++ ++ exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ exp.mask.src.ip = 0xffffffff; ++ exp.mask.dst.ip = 0xffffffff; ++ exp.mask.dst.u.udp.port = 0xffff; ++ exp.mask.dst.protonum = 0xffff; ++ exp.expectfn = NULL; ++ ++ DEBUGP("expect: "); ++ DUMP_TUPLE(&exp.tuple); ++ DUMP_TUPLE(&exp.mask); ++ ip_conntrack_expect_related(ct, &exp); ++ break; ++ default: ++ DEBUGP("Unknown opcode\n"); ++ } ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper tftp[MAX_PORTS]; ++static char tftp_names[MAX_PORTS][10]; ++ ++static void fini(void) ++{ ++ int i; ++ ++ for (i = 0 ; i < ports_c; i++) { ++ DEBUGP("unregistering helper for port %d\n", ++ ports[i]); ++ ip_conntrack_helper_unregister(&tftp[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret; ++ char *tmpname; ++ ++ if (!ports[0]) ++ ports[0]=TFTP_PORT; ++ ++ for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { ++ /* Create helper structure */ ++ 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].max_expected = 1; ++ tftp[i].timeout = 0; ++ tftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ tftp[i].me = THIS_MODULE; ++ tftp[i].help = tftp_help; ++ ++ tmpname = &tftp_names[i][0]; ++ if (ports[i] == TFTP_PORT) ++ sprintf(tmpname, "tftp"); ++ else ++ sprintf(tmpname, "tftp-%d", i); ++ tftp[i].name = tmpname; ++ ++ DEBUGP("port #%d: %d\n", i, ports[i]); ++ ++ ret=ip_conntrack_helper_register(&tftp[i]); ++ if (ret) { ++ printk("ERROR registering helper for port %d\n", ++ ports[i]); ++ fini(); ++ return(ret); ++ } ++ ports_c++; ++ } ++ return(0); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_amanda.c linux-2.4.20/net/ipv4/netfilter/ip_nat_amanda.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_amanda.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_amanda.c Wed Sep 24 09:16:24 2003 +@@ -0,0 +1,224 @@ ++/* Amanda extension for TCP NAT alteration. ++ * (C) 2002 by Brian J. Murrell ++ * based on a copy of HW's ip_nat_irc.c as well as other modules ++ * ++ * 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_amanda.o ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#if 0 ++#define DEBUGP printk ++#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); ++#else ++#define DEBUGP(format, args...) ++#define DUMP_OFFSET(x) ++#endif ++ ++MODULE_AUTHOR("Brian J. Murrell "); ++MODULE_DESCRIPTION("Amanda network address translation module"); ++MODULE_LICENSE("GPL"); ++ ++/* protects amanda part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_amanda_lock); ++ ++static unsigned int ++amanda_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ u_int16_t port; ++ struct ip_ct_amanda_expect *exp_info; ++ struct ip_conntrack *master = master_ct(ct); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ DEBUGP("nat_expected: We have a connection!\n"); ++ exp_info = &ct->master->help.exp_amanda_info; ++ ++ newdstip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ DEBUGP("nat_expected: %u.%u.%u.%u->%u.%u.%u.%u\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ ++ port = exp_info->port; ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ 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; ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { .udp = { htons(port) } }); ++ } ++ ++ return ip_nat_setup_info(ct, &mr, hooknum); ++} ++ ++static int amanda_data_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ u_int32_t newip; ++ /* DATA 99999 MESG 99999 INDEX 99999 */ ++ char buffer[6]; ++ struct ip_conntrack_expect *exp = expect; ++ struct ip_ct_amanda_expect *ct_amanda_info = &exp->help.exp_amanda_info; ++ struct ip_conntrack_tuple t = exp->tuple; ++ int port; ++ ++ MUST_BE_LOCKED(&ip_amanda_lock); ++ ++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ DEBUGP ("ip_nat_amanda_help: newip = %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ /* Alter conntrack's expectations. */ ++ ++ /* We can read expect here without conntrack lock, since it's ++ only set in ip_conntrack_amanda, with ip_amanda_lock held ++ writable */ ++ ++ t.dst.ip = newip; ++ for (port = ct_amanda_info->port + 10; port != 0; port++) { ++ t.dst.u.tcp.port = htons(port); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ break; ++ } ++ ++ if (port == 0) ++ return 0; ++ ++ sprintf(buffer, "%u", port); ++ ++ return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, /* XXX exp->seq */ ct_amanda_info->offset, ++ ct_amanda_info->len, buffer, strlen(buffer)); ++} ++ ++static unsigned int help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir; ++ ++ if (!exp) ++ DEBUGP("ip_nat_amanda: no exp!!"); ++ ++ /* 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_amanda_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" ++ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ DEBUGP("ip_nat_amanda_help: got beyond not touching: dir %s at hook %s for expect: ", ++ 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" ++ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???"); ++ DUMP_TUPLE(&exp->tuple); ++ ++ LOCK_BH(&ip_amanda_lock); ++// XXX if (exp->seq != 0) ++ if (exp->help.exp_amanda_info.offset != 0) ++ /* if this packet has a "seq" it needs to have it's content mangled */ ++ if (!amanda_data_fixup(ct, pskb, ctinfo, exp)) { ++ UNLOCK_BH(&ip_amanda_lock); ++ DEBUGP("ip_nat_amanda: NF_DROP\n"); ++ return NF_DROP; ++ } ++ exp->help.exp_amanda_info.offset = 0; ++ UNLOCK_BH(&ip_amanda_lock); ++ ++ DEBUGP("ip_nat_amanda: NF_ACCEPT\n"); ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper ip_nat_amanda_helper; ++ ++/* This function is intentionally _NOT_ defined as __exit, because ++ * it is needed by init() */ ++static void fini(void) ++{ ++ DEBUGP("ip_nat_amanda: unregistering nat helper\n"); ++ ip_nat_helper_unregister(&ip_nat_amanda_helper); ++} ++ ++static int __init init(void) ++{ ++ int ret = 0; ++ struct ip_nat_helper *hlpr; ++ ++ hlpr = &ip_nat_amanda_helper; ++ hlpr->tuple.dst.protonum = IPPROTO_UDP; ++ hlpr->tuple.src.u.udp.port = htons(10080); ++ hlpr->mask.src.u.udp.port = 0xFFFF; ++ hlpr->mask.dst.protonum = 0xFFFF; ++ hlpr->help = help; ++ hlpr->flags = 0; ++ hlpr->me = THIS_MODULE; ++ hlpr->expect = amanda_nat_expected; ++ ++ hlpr->name = "amanda"; ++ ++ DEBUGP ++ ("ip_nat_amanda: Trying to register nat helper\n"); ++ ret = ip_nat_helper_register(hlpr); ++ ++ if (ret) { ++ printk ++ ("ip_nat_amanda: error registering nat helper\n"); ++ fini(); ++ return 1; ++ } ++ return ret; ++} ++ ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_core.c linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_core.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c Wed Sep 24 09:18:12 2003 +@@ -1,10 +1,9 @@ + /* NAT for netfilter; shared with compatibility layer. */ + + /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General +- Public Licence. */ +-#ifdef MODULE +-#define __NO_VERSION__ +-#endif ++ * Public Licence. ++ * (c) 2000-2002 by the netfilter core team ++ */ + #include + #include + #include +@@ -70,6 +69,7 @@ + static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn) + { + struct ip_nat_info *info = &conn->nat.info; ++ unsigned int hs, hp; + + if (!info->initialized) + return; +@@ -77,27 +77,31 @@ + IP_NF_ASSERT(info->bysource.conntrack); + IP_NF_ASSERT(info->byipsproto.conntrack); + ++ hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src, ++ conn->tuplehash[IP_CT_DIR_ORIGINAL] ++ .tuple.dst.protonum); ++ ++ hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, ++ conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip, ++ conn->tuplehash[IP_CT_DIR_REPLY] ++ .tuple.dst.protonum); ++ + WRITE_LOCK(&ip_nat_lock); +- LIST_DELETE(&bysource[hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL] +- .tuple.src, +- conn->tuplehash[IP_CT_DIR_ORIGINAL] +- .tuple.dst.protonum)], +- &info->bysource); +- +- LIST_DELETE(&byipsproto +- [hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY] +- .tuple.src.ip, +- conn->tuplehash[IP_CT_DIR_REPLY] +- .tuple.dst.ip, +- conn->tuplehash[IP_CT_DIR_REPLY] +- .tuple.dst.protonum)], +- &info->byipsproto); ++ LIST_DELETE(&bysource[hs], &info->bysource); ++ LIST_DELETE(&byipsproto[hp], &info->byipsproto); + WRITE_UNLOCK(&ip_nat_lock); + } + +-/* We do checksum mangling, so if they were wrong before they're still +- * wrong. Also works for incomplete packets (eg. ICMP dest +- * unreachables.) */ ++/** ++ * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum ++ * @oldvalinv: bit-inverted old value of 32bit word ++ * @newval: new value of 32bit word ++ * @oldcheck: old checksum value ++ * ++ * This function implements incremental checksum mangling, so if a checksum ++ * was wrong it will still be wrong after mangling. Also works for incomplete ++ * packets (eg. ICMP dest unreachables). Return value is the new checksum. ++ */ + u_int16_t + ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) + { +@@ -123,7 +127,14 @@ + return i; + } + +-/* Is this tuple already taken? (not by us) */ ++/** ++ * ip_nat_used_tuple - Is this tuple already in use? ++ * @tuple: tuple to be used for this check ++ * @ignored_conntrack: conntrack excluded from this check ++ * ++ * This function checks for the reply (inverted) tuple in the conntrack ++ * hash. This is necessarry with NAT, since there is no fixed mapping. ++ */ + int + ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, + const struct ip_conntrack *ignored_conntrack) +@@ -162,8 +173,8 @@ + continue; + } + +- if ((mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED) +- && proto->in_range(&newtuple, IP_NAT_MANIP_SRC, ++ if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED) ++ || proto->in_range(&newtuple, IP_NAT_MANIP_SRC, + &mr->range[i].min, &mr->range[i].max)) + return 1; + } +@@ -247,11 +258,12 @@ + const struct ip_conntrack *conntrack) + { + unsigned int score = 0; ++ unsigned int h; + + MUST_BE_READ_LOCKED(&ip_nat_lock); +- LIST_FIND(&byipsproto[hash_by_ipsproto(src, dst, protonum)], +- fake_cmp, struct ip_nat_hash *, src, dst, protonum, &score, +- conntrack); ++ h = hash_by_ipsproto(src, dst, protonum); ++ LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *, ++ src, dst, protonum, &score, conntrack); + + return score; + } +@@ -434,7 +446,7 @@ + *tuple = *orig_tuple; + while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) + != NULL) { +- DEBUGP("Found best for "); DUMP_TUPLE(tuple); ++ DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple); + /* 3) The per-protocol part of the manip is made to + map into the range to make a unique tuple. */ + +@@ -511,6 +523,19 @@ + #endif + }; + ++/** ++ * ip_nat_setup_info - Set up NAT mappings for NEW packet ++ * @conntrack: conntrack on which we operate ++ * @mr: address/port range which is valid for this NAT mapping ++ * @hooknum: hook at which this NAT mapping applies ++ * ++ * This function is called by NAT targets (SNAT,DNAT,...) and by ++ * the NAT application helper modules. It is called for the NEW packet ++ * of a connection in order to specify which NAT mappings shall apply to ++ * this connection at a given hook. ++ * ++ * Note: The reply mappings are created automagically by this function. ++ */ + unsigned int + ip_nat_setup_info(struct ip_conntrack *conntrack, + const struct ip_nat_multi_range *mr, +@@ -519,12 +544,14 @@ + struct ip_conntrack_tuple new_tuple, inv_tuple, reply; + struct ip_conntrack_tuple orig_tp; + struct ip_nat_info *info = &conntrack->nat.info; ++ int in_hashes = info->initialized; + + MUST_BE_WRITE_LOCKED(&ip_nat_lock); + IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING + || hooknum == NF_IP_POST_ROUTING + || hooknum == NF_IP_LOCAL_OUT); + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + /* What we've got will look like inverse of reply. Normally + this is what is in the conntrack, except for prior +@@ -573,9 +600,9 @@ + HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", + conntrack); + DEBUGP("Original: "); +- DUMP_TUPLE(&orig_tp); ++ DUMP_TUPLE_RAW(&orig_tp); + DEBUGP("New: "); +- DUMP_TUPLE(&new_tuple); ++ DUMP_TUPLE_RAW(&new_tuple); + #endif + + /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): +@@ -641,6 +668,14 @@ + + /* It's done. */ + info->initialized |= (1 << HOOK2MANIP(hooknum)); ++ ++ if (in_hashes) { ++ IP_NF_ASSERT(info->bysource.conntrack); ++ replace_in_hashes(conntrack, info); ++ } else { ++ place_in_hashes(conntrack, info); ++ } ++ + return NF_ACCEPT; + } + +@@ -799,6 +834,7 @@ + struct ip_conntrack_expect *exp = NULL; + struct list_head *cur_item; + int ret = NF_ACCEPT; ++ int helper_called = 0; + + DEBUGP("do_bindings: helper existing for (%p)\n", ct); + +@@ -817,19 +853,21 @@ + continue; + + if (exp_for_packet(exp, pskb)) { +- /* FIXME: May be true multiple times in the case of UDP!! */ +- DEBUGP("calling nat helper (exp=%p) for packet\n", +- exp); ++ /* FIXME: May be true multiple times in the ++ * case of UDP!! */ ++ DEBUGP("calling nat helper (exp=%p) for packet\n", exp); + ret = helper->help(ct, exp, info, ctinfo, + hooknum, pskb); + if (ret != NF_ACCEPT) { + READ_UNLOCK(&ip_conntrack_lock); + return ret; + } ++ helper_called = 1; + } + } +- /* Helper might want to manip the packet even when there is no expectation */ +- if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) { ++ /* Helper might want to manip the packet even when there is no ++ * matching expectation for this packet */ ++ if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) { + DEBUGP("calling nat helper for packet without expectation\n"); + ret = helper->help(ct, NULL, info, ctinfo, + hooknum, pskb); +@@ -915,7 +953,7 @@ + packet, except it was never src/dst reversed, so + where we would normally apply a dst manip, we apply + a src, and vice versa. */ +- if (info->manips[i].hooknum == opposite_hook[hooknum]) { ++ if (info->manips[i].hooknum == hooknum) { + DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n", + info->manips[i].maniptype == IP_NAT_MANIP_SRC + ? "DST" : "SRC", +@@ -926,9 +964,9 @@ + &info->manips[i].manip, + !info->manips[i].maniptype, + &skb->nfcache); +- /* Outer packet needs to have IP header NATed like +- it's a reply. */ +- } else if (info->manips[i].hooknum == hooknum) { ++ /* Outer packet needs to have IP header NATed like ++ it's a reply. */ ++ + /* Use mapping to map outer packet: 0 give no + per-proto mapping */ + DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n", +@@ -982,6 +1020,10 @@ + /* FIXME: Man, this is a hack. */ + IP_NF_ASSERT(ip_conntrack_destroyed == NULL); + ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; ++ ++ /* Initialize fake conntrack so that NAT will skip it */ ++ ip_conntrack_untracked.nat.info.initialized |= ++ (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST); + + return 0; + } +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_cuseeme.c linux-2.4.20/net/ipv4/netfilter/ip_nat_cuseeme.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_cuseeme.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_cuseeme.c Wed Sep 24 09:17:38 2003 +@@ -0,0 +1,289 @@ ++/* CuSeeMe extension for UDP NAT alteration. ++ * (C) 2002 by Filip Sneppe ++ * based on ip_masq_cuseeme.c in 2.2 kernels ++ * ++ * ip_nat_cuseeme.c v0.0.7 2003-02-18 ++ * ++ * 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_cuseeme.o ports=port1,port2,...port ++ * ++ * Please give the ports of the CuSeeMe traffic you want to track. ++ * If you don't specify ports, the default will be UDP port 7648. ++ * ++ * CuSeeMe Protocol Documentation: ++ * http://cu-seeme.net/squeek/tech/contents.html ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Filip Sneppe "); ++MODULE_DESCRIPTION("Netfilter NAT helper for CuSeeMe"); ++MODULE_LICENSE("GPL"); ++ ++#define MAX_PORTS 8 ++ ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++#ifdef MODULE_PARM ++MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of CuSeeMe reflectors"); ++#endif ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* process packet from client->reflector, possibly manipulate client IP in payload */ ++void cuseeme_mangle_outgoing(struct ip_conntrack *ct, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, ++ char *data, ++ unsigned int datalen) ++{ ++ char new_port_ip[6]; ++ struct cu_header *cu_head=(struct cu_header *)data; ++ ++ DEBUGP("ip_nat_cuseeme: outgoing packet, ID %u, dest_family %u\n", ++ ntohs(cu_head->data_type), ntohs(cu_head->dest_family)); ++ ++ /* At least check that the data at offset 10 is the client's port and IP address */ ++ if ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == cu_head->addr) && ++ (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port == cu_head->port)) { ++ DEBUGP("ip_nat_cuseeme: rewrite outgoing client %u.%u.%u.%u:%u->%u.%u.%u.%u:%u at offset 10\n", ++ NIPQUAD(cu_head->addr), ++ ntohs(cu_head->port), ++ NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ++ ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port)); ++ *((u_int16_t *)new_port_ip) = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; ++ *((u_int32_t *)(new_port_ip+2)) = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ /* at offset 10, replace 6 bytes containing port + IP address */ ++ ip_nat_mangle_udp_packet(pskb, ct, ctinfo, ++ 10, 6, (char *)(new_port_ip), 6); ++ } else ++ DEBUGP("ip_nat_cuseeme: expected outgoing client %u.%u.%u.%u:%u, but got %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(cu_head->addr), ++ ntohs(cu_head->port)); ++} ++ ++/* process packet from reflector->client, possibly manipulate client IP & reflector IP in payload */ ++void cuseeme_mangle_incoming(struct ip_conntrack *ct, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, ++ char *data, ++ unsigned int datalen) ++{ ++ char new_port_ip[6]; ++ struct cu_header *cu_head = (struct cu_header *)data; ++ struct oc_header *oc_head = (struct oc_header *)data; ++ struct client_info *ci; ++ int i, off; ++ ++ ++ DEBUGP("ip_nat_cuseeme: incoming packet, ID %u, dest_family %u\n", ++ ntohs(cu_head->data_type), ntohs(cu_head->dest_family)); ++ ++ /* Check if we're really dealing with the client's port + IP address before rewriting */ ++ if((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == cu_head->dest_addr) && ++ (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port == cu_head->dest_port)) { ++ DEBUGP("ip_nat_cuseeme: rewrite incoming client %u.%u.%u.%u:%u->%u.%u.%u.%u:%u at offset 2\n", ++ NIPQUAD(cu_head->dest_addr), ++ ntohs(cu_head->dest_port), ++ NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ++ ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port)); ++ *((u_int16_t *)new_port_ip) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; ++ *((u_int32_t *)(new_port_ip+2)) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ /* at offset 2, replace 6 bytes containing port + IP address */ ++ ip_nat_mangle_udp_packet(pskb, ct, ctinfo, ++ 2, 6, (char *)(new_port_ip), 6); ++ } else ++ DEBUGP("ip_nat_cuseeme: expected incoming client %u.%u.%u.%u:%u, but got %u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ++ ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port), ++ NIPQUAD(cu_head->dest_addr), ++ ntohs(cu_head->dest_port)); ++ ++ /* Check if we're really dealing with the server's port + IP address before rewriting. ++ In some cases, the IP address == 0.0.0.0 so we don't rewrite anything */ ++ if((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == cu_head->addr) && ++ (ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port == cu_head->port)) { ++ DEBUGP("in_nat_cuseeme: rewrite incoming server %u.%u.%u.%u:%u->%u.%u.%u.%u:%u at offset 10\n", ++ NIPQUAD(cu_head->addr), ++ ntohs(cu_head->port), ++ NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), ++ ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port)); ++ *((u_int16_t *)new_port_ip) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port; ++ *((u_int32_t *)(new_port_ip+2)) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ /* at offset 10, replace 6 bytes containing port + IP address */ ++ ip_nat_mangle_udp_packet(pskb, ct, ctinfo, ++ 10, 6, (char *)(new_port_ip), 6); ++ } else ++ /* Sometimes we find 0.0.0.0, sometimes an IP address - the docs say this field ++ is not that important so we're not logging this unless we're debugging */ ++ DEBUGP("ip_nat_cuseeme: no biggie, expected incoming server %u.%u.%u.%u:%u, but got %u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), ++ ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port), ++ NIPQUAD(cu_head->addr), ++ ntohs(cu_head->port)); ++ ++ /* Spin through client_info structs until we find our own */ ++ if((ntohs(cu_head->data_type) == 101) && (datalen >= sizeof(struct oc_header))) { ++ DEBUGP("ip_nat_cuseeme: looping through %u client_info structs\n", oc_head->client_count); ++ for(i=0, off=sizeof(struct oc_header); ++ (i < oc_head->client_count && ++ off+sizeof(struct client_info) <= datalen); ++ i++) { ++ ci=(struct client_info *)(data+off); ++ DEBUGP("ip_nat_cuseeme: comparing %u.%u.%u.%u with %u.%u.%u.%u at offset %u\n", ++ NIPQUAD(ci->address), NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ++ (unsigned int)((void *)&(ci->address) - (void *)cu_head)); ++ if(ci->address == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) { ++ /* mangle this IP address */ ++ DEBUGP("ip_nat_cuseeme: changing %u.%u.%u.%u->%u.%u.%u.%u at offset %u\n", ++ NIPQUAD(ci->address), ++ NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ++ (unsigned int)((void *)&(ci->address) - (void *)cu_head)); ++ ip_nat_mangle_udp_packet(pskb, ct, ctinfo, ++ (unsigned int)((void *)&(ci->address) - (void *)cu_head), 4, ++ (char *)(&(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip)), 4); ++ break; ++ } else ++ off+=sizeof(struct client_info); ++ } ++ } else ++ DEBUGP("ip_nat_cuseeme: data_type %u, datalen %u < sizeof(struct oc_header) %u\n", ++ ntohs(cu_head->data_type), datalen, sizeof(struct oc_header)); ++} ++ ++static unsigned int ++cuseeme_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ 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; ++ int dir = CTINFO2DIR(ctinfo); ++ unsigned int datalen = (*pskb)->len - iph->ihl * 4 - sizeof(struct udphdr); ++ char *data = (char *) &udph[1]; ++ ++ DEBUGP("ip_nat_cuseeme: cuseeme_nat_help, direction: %s 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" : "???" ++ ); ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("ip_nat_cuseeme: 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; ++ } ++ ++ if(datalen < sizeof(struct cu_header)) { ++ /* packet too small */ ++ if (net_ratelimit()) ++ printk("ip_nat_cuseeme: payload too small (%u, should be >= %u)\n", ++ datalen, sizeof(struct cu_header)); ++ return NF_ACCEPT; ++ } ++ ++ ++ /* In the debugging output, "outgoing" is from client to server, and ++ "incoming" is from server to client */ ++ if(HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ cuseeme_mangle_outgoing(ct, info, ctinfo, pskb, data, datalen); ++ else ++ cuseeme_mangle_incoming(ct, info, ctinfo, pskb, data, datalen); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper cuseeme[MAX_PORTS]; ++static char cuseeme_names[MAX_PORTS][14]; /* cuseeme-65535 */ ++ ++static void fini(void) ++{ ++ int i; ++ ++ for (i = 0 ; i < ports_c; i++) { ++ DEBUGP("ip_nat_cuseeme: unregistering helper for port %d\n", ports[i]); ++ ip_nat_helper_unregister(&cuseeme[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret = 0; ++ char *tmpname; ++ ++ if (!ports[0]) ++ ports[0] = CUSEEME_PORT; ++ ++ for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { ++ memset(&cuseeme[i], 0, sizeof(struct ip_nat_helper)); ++ ++ cuseeme[i].tuple.dst.protonum = IPPROTO_UDP; ++ cuseeme[i].tuple.dst.u.udp.port = htons(ports[i]); ++ cuseeme[i].mask.dst.protonum = 0xFFFF; ++ cuseeme[i].mask.dst.u.udp.port = 0xFFFF; ++ cuseeme[i].help = cuseeme_nat_help; ++ cuseeme[i].flags = IP_NAT_HELPER_F_STANDALONE + ++ IP_NAT_HELPER_F_ALWAYS; /* dunno if IP_NAT_HELPER_F_ALWAYS ++ is stricly needed... */ ++ cuseeme[i].me = THIS_MODULE; ++ cuseeme[i].expect = NULL; /* cuseeme_nat_expected; */ ++ ++ tmpname = &cuseeme_names[i][0]; ++ if (ports[i] == CUSEEME_PORT) ++ sprintf(tmpname, "cuseeme"); ++ else ++ sprintf(tmpname, "cuseeme-%d", ports[i]); ++ cuseeme[i].name = tmpname; ++ ++ DEBUGP("ip_nat_cuseeme: registering helper for port %d: name %s\n", ++ ports[i], cuseeme[i].name); ++ ret = ip_nat_helper_register(&cuseeme[i]); ++ ++ if (ret) { ++ printk("ip_nat_cuseeme: unable to register helper for port %d\n", ++ ports[i]); ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ return ret; ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.20/net/ipv4/netfilter/ip_nat_ftp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_ftp.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_ftp.c Wed Sep 24 09:16:17 2003 +@@ -84,7 +84,7 @@ + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + mr.range[0].min = mr.range[0].max + = ((union ip_conntrack_manip_proto) +- { htons(exp_ftp_info->port) }); ++ { .tcp = { htons(exp_ftp_info->port) } }); + } + return ip_nat_setup_info(ct, &mr, hooknum); + } +@@ -306,9 +306,6 @@ + ports[0] = FTP_PORT; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { +- +- memset(&ftp[i], 0, sizeof(struct ip_nat_helper)); +- + ftp[i].tuple.dst.protonum = IPPROTO_TCP; + ftp[i].tuple.src.u.tcp.port = htons(ports[i]); + ftp[i].mask.dst.protonum = 0xFFFF; +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.20/net/ipv4/netfilter/ip_nat_h323.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_h323.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_h323.c Wed Sep 24 09:17:43 2003 +@@ -0,0 +1,419 @@ ++/* ++ * H.323 'brute force' extension for NAT alteration. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat.html) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++struct module *ip_nat_h323 = THIS_MODULE; ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* FIXME: Time out? --RR */ ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info); ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb); ++ ++static struct ip_nat_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ 0, /* flags */ ++ NULL, /* module */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ u_int16_t port; ++ struct ip_ct_h225_expect *exp_info; ++ struct ip_ct_h225_master *master_info; ++ struct ip_conntrack *master = master_ct(ct); ++ unsigned int is_h225, ret; ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1<master->expectant->help.ct_h225_info; ++ exp_info = &ct->master->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ ++ DEBUGP("master: "); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); ++ DEBUGP("conntrack: "); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ if (exp_info->dir == IP_CT_DIR_ORIGINAL) { ++ /* Make connection go to the client. */ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } else { ++ /* Make the connection go to the server */ ++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } ++ port = exp_info->port; ++ is_h225 = master_info->is_h225 == H225_PORT; ++ UNLOCK_BH(&ip_h323_lock); ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ 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; ++ ++ /* ... unless we're doing a MANIP_DST, in which case, make ++ sure we map to the correct port */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { .tcp = { port } }); ++ } ++ ++ ret = ip_nat_setup_info(ct, &mr, hooknum); ++ ++ if (is_h225) { ++ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); ++ /* NAT expectfn called with ip_nat_lock write-locked */ ++ info->helper = &h245; ++ } ++ return ret; ++} ++ ++static int h323_signal_address_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ char *data = (char *) tcph + tcph->doff * 4; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ u_int32_t datalen = tcplen - tcph->doff*4; ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ u_int32_t newip; ++ u_int16_t port; ++ int i; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no", ++ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no"); ++ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) ++ return 1; ++ ++ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", ++ info->offset[IP_CT_DIR_ORIGINAL], ++ info->offset[IP_CT_DIR_REPLY], ++ tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ for (i = 0; i < IP_CT_DIR_MAX; i++) { ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", ++ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); ++ if (!between(info->seq[i], ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) ++ continue; ++ if (!between(info->seq[i] + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ info->seq[i], ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (i == IP_CT_DIR_ORIGINAL) { ++ newip = ct->tuplehash[!info->dir].tuple.dst.ip; ++ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; ++ } else { ++ newip = ct->tuplehash[!info->dir].tuple.src.ip; ++ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; ++ } ++ ++ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), ++ ntohs(*((u_int16_t *)(data + info->offset[i] + 4)))); ++ ++ /* Modify the packet */ ++ *(u_int32_t *)(data + info->offset[i]) = newip; ++ *(u_int16_t *)(data + info->offset[i] + 4) = port; ++ ++ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), ++ ntohs(*((u_int16_t *)(data + info->offset[i] + 4)))); ++ } ++ ++ /* fix checksum information */ ++ ++ (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4, ++ datalen, 0); ++ ++ tcph->check = 0; ++ tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcph->doff*4, ++ (*pskb)->csum)); ++ ip_send_check(iph); ++ ++ return 1; ++} ++ ++static int h323_data_fixup(struct ip_ct_h225_expect *info, ++ struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ u_int32_t newip; ++ u_int16_t port; ++ struct ip_conntrack_tuple newtuple; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ char *data = (char *) tcph + tcph->doff * 4; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; ++ int is_h225; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ if (!between(expect->seq + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ expect->seq, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (info->dir == IP_CT_DIR_REPLY) { ++ /* Must be where client thinks server is */ ++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ /* Expect something from client->server */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ } else { ++ /* Must be where server thinks client is */ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ /* Expect something from server->client */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ } ++ ++ is_h225 = (master_info->is_h225 == H225_PORT); ++ ++ if (is_h225) { ++ newtuple.dst.protonum = IPPROTO_TCP; ++ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; ++ } else { ++ newtuple.dst.protonum = IPPROTO_UDP; ++ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; ++ } ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (port = ntohs(info->port); port != 0; port++) { ++ if (is_h225) ++ newtuple.dst.u.tcp.port = htons(port); ++ else ++ newtuple.dst.u.udp.port = htons(port); ++ ++ if (ip_conntrack_change_expect(expect, &newtuple) == 0) ++ break; ++ } ++ if (port == 0) { ++ DEBUGP("h323_data_fixup: no free port found!\n"); ++ return 0; ++ } ++ ++ port = htons(port); ++ ++ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", ++ NIPQUAD(*((u_int32_t *)(data + info->offset))), ++ ntohs(*((u_int16_t *)(data + info->offset + 4)))); ++ ++ /* Modify the packet */ ++ *(u_int32_t *)(data + info->offset) = newip; ++ *(u_int16_t *)(data + info->offset + 4) = port; ++ ++ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", ++ NIPQUAD(*((u_int32_t *)(data + info->offset))), ++ ntohs(*((u_int16_t *)(data + info->offset + 4)))); ++ ++ /* fix checksum information */ ++ /* FIXME: usually repeated multiple times in the case of H.245! */ ++ ++ (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4, ++ tcplen - tcph->doff*4, 0); ++ ++ tcph->check = 0; ++ tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcph->doff*4, ++ (*pskb)->csum)); ++ ip_send_check(iph); ++ ++ return 1; ++} ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir; ++ struct ip_ct_h225_expect *exp_info; ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ dir = CTINFO2DIR(ctinfo); ++ DEBUGP("nat_h323: 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" : "???"); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("nat_h323: 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; ++ } ++ ++ if (!exp) { ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_ACCEPT; ++ } ++ ++ exp_info = &exp->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_NAT_HELPER_F_ALWAYS, /* flags */ ++ THIS_MODULE, /* module */ ++ { { 0, { .tcp = { __constant_htons(H225_PORT) } } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { .tcp = { 0xFFFF } } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ ret = ip_nat_helper_register(&h225); ++ ++ if (ret != 0) ++ printk("ip_nat_h323: cannot initialize the module!\n"); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ ip_nat_helper_unregister(&h225); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_helper.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c Wed Sep 24 09:17:50 2003 +@@ -8,6 +8,9 @@ + * - add support for SACK adjustment + * 14 Mar 2002 Harald Welte : + * - merge SACK support into newnat API ++ * 16 Aug 2002 Brian J. Murrell : ++ * - make ip_nat_resize_packet more generic (TCP and UDP) ++ * - add ip_nat_mangle_udp_packet + */ + #include + #include +@@ -22,6 +25,7 @@ + #include + #include + #include ++#include + + #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) + #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +@@ -51,18 +55,12 @@ + int new_size) + { + struct iphdr *iph; +- struct tcphdr *tcph; +- void *data; + int dir; + struct ip_nat_seq *this_way, *other_way; + + DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n", + (*skb)->len, new_size); + +- iph = (*skb)->nh.iph; +- tcph = (void *)iph + iph->ihl*4; +- data = (void *)tcph + tcph->doff*4; +- + dir = CTINFO2DIR(ctinfo); + + this_way = &ct->nat.info.seq[dir]; +@@ -84,37 +82,50 @@ + } + + iph = (*skb)->nh.iph; +- tcph = (void *)iph + iph->ihl*4; +- data = (void *)tcph + tcph->doff*4; ++ if (iph->protocol == IPPROTO_TCP) { ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; + +- DEBUGP("ip_nat_resize_packet: Seq_offset before: "); +- DUMP_OFFSET(this_way); ++ DEBUGP("ip_nat_resize_packet: Seq_offset before: "); ++ DUMP_OFFSET(this_way); + +- LOCK_BH(&ip_nat_seqofs_lock); ++ LOCK_BH(&ip_nat_seqofs_lock); + +- /* SYN adjust. If it's uninitialized, of this is after last +- * correction, record it: we don't handle more than one +- * adjustment in the window, but do deal with common case of a +- * retransmit */ +- if (this_way->offset_before == this_way->offset_after +- || before(this_way->correction_pos, ntohl(tcph->seq))) { +- this_way->correction_pos = ntohl(tcph->seq); +- this_way->offset_before = this_way->offset_after; +- this_way->offset_after = (int32_t) +- this_way->offset_before + new_size - (*skb)->len; +- } ++ /* SYN adjust. If it's uninitialized, of this is after last ++ * correction, record it: we don't handle more than one ++ * adjustment in the window, but do deal with common case of a ++ * retransmit */ ++ if (this_way->offset_before == this_way->offset_after ++ || before(this_way->correction_pos, ntohl(tcph->seq))) { ++ this_way->correction_pos = ntohl(tcph->seq); ++ this_way->offset_before = this_way->offset_after; ++ this_way->offset_after = (int32_t) ++ this_way->offset_before + new_size - ++ (*skb)->len; ++ } + +- UNLOCK_BH(&ip_nat_seqofs_lock); ++ UNLOCK_BH(&ip_nat_seqofs_lock); + +- DEBUGP("ip_nat_resize_packet: Seq_offset after: "); +- DUMP_OFFSET(this_way); ++ DEBUGP("ip_nat_resize_packet: Seq_offset after: "); ++ DUMP_OFFSET(this_way); ++ } + + return 1; + } + + +-/* Generic function for mangling variable-length address changes inside +- * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP). ++/** ++ * ip_nat_mangle_tcp_packet - Mangle and potentially resize payload packet ++ * @skb: pointer to skb of packet on which we operate ++ * @ct: conntrack of the connection to which this packet belongs ++ * @ctinfo: conntrack_info of the connection to which this packet belongs ++ * @match_offset: offset in bytes where to-be-manipulated part starts ++ * @match_len: lenght of the to-be-manipulated part ++ * @rep_buffer: pointer to buffer containing replacement ++ * @rep_len: length of replacement ++ * ++ * Generic function for mangling fixed and variable-length changes inside ++ * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command ++ * in FTP). + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... +@@ -174,10 +185,11 @@ + tcph = (void *)iph + iph->ihl*4; + data = (void *)tcph + tcph->doff*4; + +- /* move post-replacement */ +- memmove(data + match_offset + rep_len, +- data + match_offset + match_len, +- (*skb)->tail - (data + match_offset + match_len)); ++ if (rep_len != match_len) ++ /* move post-replacement */ ++ memmove(data + match_offset + rep_len, ++ data + match_offset + match_len, ++ (*skb)->tail - (data + match_offset + match_len)); + + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); +@@ -207,6 +219,125 @@ + + return 1; + } ++ ++/** ++ * ip_nat_mangle_udp_packet - Mangle and potentially resize payload packet ++ * @skb: pointer to skb of packet on which we operate ++ * @ct: conntrack of the connection to which this packet belongs ++ * @ctinfo: conntrack_info of the connection to which this packet belongs ++ * @match_offset: offset in bytes where to-be-manipulated part starts ++ * @match_len: lenght of the to-be-manipulated part ++ * @rep_buffer: pointer to buffer containing replacement ++ * @rep_len: length of replacement ++ * ++ * Generic function for mangling fixed and variable-length changes inside ++ * NATed TCP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX ++ * commad in the Amanda protocol) ++ * ++ * Takes care about all the nasty sequence number changes, checksumming, ++ * skb enlargement, ... ++ * ++ * FIXME: should be unified with ip_nat_mangle_tcp_packet!! ++ * ++ * */ ++ ++int ++ip_nat_mangle_udp_packet(struct sk_buff **skb, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ unsigned int match_offset, ++ unsigned int match_len, ++ char *rep_buffer, ++ unsigned int rep_len) ++{ ++ struct iphdr *iph = (*skb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ unsigned char *data; ++ u_int32_t udplen, newlen, newudplen; ++ ++ udplen = (*skb)->len - iph->ihl*4; ++ newudplen = udplen - match_len + rep_len; ++ newlen = iph->ihl*4 + newudplen; ++ ++ if (newlen > 65535) { ++ if (net_ratelimit()) ++ printk("ip_nat_mangle_udp_packet: nat'ed packet " ++ "exceeds maximum packet size\n"); ++ return 0; ++ } ++ ++ if ((*skb)->len != newlen) { ++ if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) { ++ printk("resize_packet failed!!\n"); ++ return 0; ++ } ++ } ++ ++ /* Alexey says: if a hook changes _data_ ... it can break ++ original packet sitting in tcp queue and this is fatal */ ++ if (skb_cloned(*skb)) { ++ struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC); ++ if (!nskb) { ++ if (net_ratelimit()) ++ printk("Out of memory cloning TCP packet\n"); ++ return 0; ++ } ++ /* Rest of kernel will get very unhappy if we pass it ++ a suddenly-orphaned skbuff */ ++ if ((*skb)->sk) ++ skb_set_owner_w(nskb, (*skb)->sk); ++ kfree_skb(*skb); ++ *skb = nskb; ++ } ++ ++ /* skb may be copied !! */ ++ iph = (*skb)->nh.iph; ++ udph = (void *)iph + iph->ihl*4; ++ data = (void *)udph + sizeof(struct udphdr); ++ ++ if (rep_len != match_len) ++ /* move post-replacement */ ++ memmove(data + match_offset + rep_len, ++ data + match_offset + match_len, ++ (*skb)->tail - (data + match_offset + match_len)); ++ ++ /* insert data from buffer */ ++ memcpy(data + match_offset, rep_buffer, rep_len); ++ ++ /* update skb info */ ++ if (newlen > (*skb)->len) { ++ DEBUGP("ip_nat_mangle_udp_packet: Extending packet by " ++ "%u to %u bytes\n", newlen - (*skb)->len, newlen); ++ skb_put(*skb, newlen - (*skb)->len); ++ } else { ++ DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from " ++ "%u to %u bytes\n", (*skb)->len, newlen); ++ skb_trim(*skb, newlen); ++ } ++ ++ /* update the length of the UDP and IP packets to the new values*/ ++ udph->len = htons((*skb)->len - iph->ihl*4); ++ iph->tot_len = htons(newlen); ++ ++ /* fix udp checksum if udp checksum was previously calculated */ ++ if ((*skb)->csum != 0) { ++ (*skb)->csum = csum_partial((char *)udph + ++ sizeof(struct udphdr), ++ newudplen - sizeof(struct udphdr), ++ 0); ++ ++ udph->check = 0; ++ udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ++ newudplen, IPPROTO_UDP, ++ csum_partial((char *)udph, ++ sizeof(struct udphdr), ++ (*skb)->csum)); ++ } ++ ++ ip_send_check(iph); ++ ++ return 1; ++} + + /* Adjust one found SACK option including checksum correction */ + static void +@@ -255,54 +386,49 @@ + } + + +-/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */ +-static inline int ++/* TCP SACK sequence number adjustment. */ ++static inline void + ip_nat_sack_adjust(struct sk_buff *skb, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) + { +- struct iphdr *iph; + struct tcphdr *tcph; +- unsigned char *ptr; +- int length, dir, sack_adjusted = 0; ++ unsigned char *ptr, *optend; ++ unsigned int dir; + +- iph = skb->nh.iph; +- tcph = (void *)iph + iph->ihl*4; +- length = (tcph->doff*4)-sizeof(struct tcphdr); ++ tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4; ++ optend = (unsigned char *)tcph + tcph->doff*4; + ptr = (unsigned char *)(tcph+1); + + dir = CTINFO2DIR(ctinfo); + +- while (length > 0) { +- int opcode = *ptr++; ++ while (ptr < optend) { ++ int opcode = ptr[0]; + int opsize; + + switch (opcode) { + case TCPOPT_EOL: +- return !sack_adjusted; ++ return; + case TCPOPT_NOP: +- length--; ++ ptr++; + continue; + default: +- opsize = *ptr++; +- if (opsize > length) /* no partial opts */ +- return !sack_adjusted; ++ opsize = ptr[1]; ++ /* no partial opts */ ++ if (ptr + opsize > optend || opsize < 2) ++ return; + if (opcode == TCPOPT_SACK) { + /* found SACK */ + if((opsize >= (TCPOLEN_SACK_BASE + +TCPOLEN_SACK_PERBLOCK)) && + !((opsize - TCPOLEN_SACK_BASE) + % TCPOLEN_SACK_PERBLOCK)) +- sack_adjust(tcph, ptr-2, ++ sack_adjust(tcph, ptr, + &ct->nat.info.seq[!dir]); +- +- sack_adjusted = 1; + } +- ptr += opsize-2; +- length -= opsize; ++ ptr += opsize; + } + } +- return !sack_adjusted; + } + + /* TCP sequence number adjustment */ +@@ -363,6 +489,13 @@ + + #define MODULE_MAX_NAMELEN 32 + ++/** ++ * ip_nat_helper_register - Register NAT application helper ++ * @me: structure describing the helper ++ * ++ * This function is called by NAT application helpers to register ++ * themselves with the NAT core. ++ */ + int ip_nat_helper_register(struct ip_nat_helper *me) + { + int ret = 0; +@@ -382,9 +515,9 @@ + const char *tmp = me->me->name; + + if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) { +- printk(__FUNCTION__ ": unable to " ++ printk("%s: unable to " + "compute conntrack helper name " +- "from %s\n", tmp); ++ "from %s\n", __FUNCTION__, tmp); + return -EBUSY; + } + tmp += 6; +@@ -430,6 +563,13 @@ + return ret; + } + ++/** ++ * ip_nat_helper_unregister - Unregister NAT application helper ++ * @me: structure describing the helper ++ * ++ * This function is called by NAT application helpers to unregister ++ * themselves from the NAT core. ++ */ + void ip_nat_helper_unregister(struct ip_nat_helper *me) + { + int found = 0; +@@ -467,7 +607,8 @@ + && ct_helper->me) { + __MOD_DEC_USE_COUNT(ct_helper->me); + } else +- printk(__FUNCTION__ ": unable to decrement usage count" +- " of conntrack helper %s\n", me->me->name); ++ printk("%s: unable to decrement usage count" ++ " of conntrack helper %s\n", ++ __FUNCTION__, me->me->name); + } + } +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_irc.c linux-2.4.20/net/ipv4/netfilter/ip_nat_irc.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_irc.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_irc.c Wed Sep 24 09:16:17 2003 +@@ -243,9 +243,6 @@ + + for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) { + hlpr = &ip_nat_irc_helpers[i]; +- memset(hlpr, 0, +- sizeof(struct ip_nat_helper)); +- + hlpr->tuple.dst.protonum = IPPROTO_TCP; + hlpr->tuple.src.u.tcp.port = htons(ports[i]); + hlpr->mask.src.u.tcp.port = 0xFFFF; +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.20/net/ipv4/netfilter/ip_nat_mms.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_mms.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_mms.c Wed Sep 24 09:17:48 2003 +@@ -0,0 +1,350 @@ ++/* MMS extension for TCP NAT alteration. ++ * (C) 2002 by Filip Sneppe ++ * based on ip_nat_ftp.c and ip_nat_irc.c ++ * ++ * ip_nat_mms.c v0.3 2002-09-22 ++ * ++ * 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_mms.o ports=port1,port2,...port ++ * ++ * Please give the ports of all MMS servers You wish to connect to. ++ * If you don't specify ports, the default will be TCP port 1755. ++ * ++ * More info on MMS protocol, firewalls and NAT: ++ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp ++ * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp ++ * ++ * The SDP project people are reverse-engineering MMS: ++ * http://get.to/sdp ++ */ ++ ++/* FIXME: issue with UDP & fragmentation with this URL: ++ http://www.cnn.com/video/world/2002/01/21/jb.shoe.bomb.cafe.cnn.low.asx ++ may be related to out-of-order first packets: ++ basically the expectation is set up correctly, then the server sends ++ a first UDP packet which is fragmented plus arrives out-of-order. ++ the MASQUERADING firewall with ip_nat_mms loaded responds with ++ an ICMP unreachable back to the server */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#define DUMP_BYTES(address, counter) \ ++({ \ ++ int temp_counter; \ ++ for(temp_counter=0; temp_counter"); ++MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK_EXTERN(ip_mms_lock); ++ ++/* FIXME: Time out? --RR */ ++ ++static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info, ++ struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ u_int32_t newip; ++ struct ip_conntrack_tuple t; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; ++ char *data = (char *)tcph + tcph->doff * 4; ++ int i, j, k, port; ++ u_int16_t mms_proto; ++ ++ u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET); ++ u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET); ++ u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET); ++ ++ int zero_padding; ++ ++ char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */ ++ char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */ ++ char proto_string[6]; ++ ++ MUST_BE_LOCKED(&ip_mms_lock); ++ ++ /* what was the protocol again ? */ ++ mms_proto = expect->tuple.dst.protonum; ++ sprintf(proto_string, "%u", mms_proto); ++ ++ DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n", ++ expect->seq, ct_mms_info->len, ntohl(tcph->seq), ++ mms_proto == IPPROTO_UDP ? "UDP" ++ : mms_proto == IPPROTO_TCP ? "TCP":proto_string); ++ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ ++ /* Alter conntrack's expectations. */ ++ t = expect->tuple; ++ t.dst.ip = newip; ++ for (port = ct_mms_info->port; port != 0; port++) { ++ t.dst.u.tcp.port = htons(port); ++ if (ip_conntrack_change_expect(expect, &t) == 0) { ++ DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port); ++ break; ++ } ++ } ++ ++ if(port == 0) ++ return 0; ++ ++ sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u", ++ NIPQUAD(newip), ++ expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP" ++ : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string, ++ port); ++ DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer); ++ ++ memset(unicode_buffer, 0, sizeof(char)*75); ++ ++ for (i=0; ipadding, ct_mms_info->len); ++ DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len); ++ DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60); ++ ++ /* add end of packet to it */ ++ for (j=0; jpadding; ++j) { ++ DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", ++ i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j)); ++ *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j); ++ } ++ ++ /* pad with zeroes at the end ? see explanation of weird math below */ ++ zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8; ++ for (k=0; k chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", ++ *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); ++ ++ /* explanation, before I forget what I did: ++ strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8; ++ divide by 8 and add 3 to compute the mms_chunkLenLM field, ++ but note that things may have to be padded with zeroes to align by 8 ++ bytes, hence we add 7 and divide by 8 to get the correct length */ ++ *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8); ++ *mms_chunkLenLV = *mms_chunkLenLM+2; ++ *mms_messageLength = *mms_chunkLenLV*8; ++ ++ DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", ++ *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); ++ ++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++ expect->seq - ntohl(tcph->seq), ++ ct_mms_info->len + ct_mms_info->padding, unicode_buffer, ++ strlen(buffer)*2 + ct_mms_info->padding + zero_padding); ++ DUMP_BYTES(unicode_buffer, 60); ++ ++ return 1; ++} ++ ++static unsigned int ++mms_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ ++ struct ip_conntrack *master = master_ct(ct); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n"); ++ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ 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; ++ ++ return ip_nat_setup_info(ct, &mr, hooknum); ++} ++ ++ ++static unsigned int mms_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; ++ unsigned int datalen; ++ int dir; ++ struct ip_ct_mms_expect *ct_mms_info; ++ ++ if (!exp) ++ DEBUGP("ip_nat_mms: no exp!!"); ++ ++ ct_mms_info = &exp->help.exp_mms_info; ++ ++ /* 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_mms: mms_nat_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_mms: mms_nat_help: beyond 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" : "???"); ++ ++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; ++ ++ DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len, ++ exp->seq + ct_mms_info->len, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen); ++ ++ LOCK_BH(&ip_mms_lock); ++ /* Check wether the whole IP/proto/port pattern is carried in the payload */ ++ if (between(exp->seq + ct_mms_info->len, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) { ++ if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) { ++ UNLOCK_BH(&ip_mms_lock); ++ return NF_DROP; ++ } ++ } else { ++ /* Half a match? This means a partial retransmisison. ++ It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("ip_nat_mms: partial packet %u/%u in %u/%u\n", ++ exp->seq, ct_mms_info->len, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen); ++ } ++ UNLOCK_BH(&ip_mms_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_mms_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper mms[MAX_PORTS]; ++static char mms_names[MAX_PORTS][10]; ++ ++/* Not __exit: called from init() */ ++static void fini(void) ++{ ++ int i; ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]); ++ ip_nat_helper_unregister(&mms[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret = 0; ++ char *tmpname; ++ ++ if (ports[0] == 0) ++ ports[0] = MMS_PORT; ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ ++ memset(&mms[i], 0, sizeof(struct ip_nat_helper)); ++ ++ mms[i].tuple.dst.protonum = IPPROTO_TCP; ++ mms[i].tuple.src.u.tcp.port = htons(ports[i]); ++ mms[i].mask.dst.protonum = 0xFFFF; ++ mms[i].mask.src.u.tcp.port = 0xFFFF; ++ mms[i].help = mms_nat_help; ++ mms[i].me = THIS_MODULE; ++ mms[i].flags = 0; ++ mms[i].expect = mms_nat_expected; ++ ++ tmpname = &mms_names[i][0]; ++ if (ports[i] == MMS_PORT) ++ sprintf(tmpname, "mms"); ++ else ++ sprintf(tmpname, "mms-%d", i); ++ mms[i].name = tmpname; ++ ++ DEBUGP("ip_nat_mms: register helper for port %d\n", ++ ports[i]); ++ ret = ip_nat_helper_register(&mms[i]); ++ ++ if (ret) { ++ printk("ip_nat_mms: error registering " ++ "helper for port %d\n", ports[i]); ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ ++ return ret; ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_pptp.c linux-2.4.20/net/ipv4/netfilter/ip_nat_pptp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_pptp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_pptp.c Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,475 @@ ++/* ++ * ip_nat_pptp.c - Version 1.5 ++ * ++ * NAT support for PPTP (Point to Point Tunneling Protocol). ++ * PPTP is a a protocol for creating virtual private networks. ++ * It is a specification defined by Microsoft and some vendors ++ * working with Microsoft. PPTP is built on top of a modified ++ * version of the Internet Generic Routing Encapsulation Protocol. ++ * GRE is defined in RFC 1701 and RFC 1702. Documentation of ++ * PPTP can be found in RFC 2637 ++ * ++ * (C) 2000-2003 by Harald Welte ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ * TODO: - Support for multiple calls within one session ++ * (needs netfilter newnat code) ++ * - NAT to a unique tuple, not to TCP source port ++ * (needs netfilter tuple reservation) ++ * ++ * Changes: ++ * 2002-02-10 - Version 1.3 ++ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's ++ * in local connections (Philip Craig ) ++ * - add checks for magicCookie and pptp version ++ * - make argument list of pptp_{out,in}bound_packet() shorter ++ * - move to C99 style initializers ++ * - print version number at module loadtime ++ * 2003-09-22 - Version 1.5 ++ * - use SNATed tcp sourceport as callid, since we get called before ++ * TCP header is mangled (Philip Craig ) ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define IP_NAT_PPTP_VERSION "1.5" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte "); ++MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); ++ ++ ++#if 0 ++#include "ip_conntrack_pptp_priv.h" ++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++ ": " format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++static unsigned int ++pptp_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_conntrack *master = master_ct(ct); ++ struct ip_nat_multi_range mr; ++ struct ip_ct_pptp_master *ct_pptp_info; ++ struct ip_nat_pptp *nat_pptp_info; ++ u_int32_t newip, newcid; ++ int ret; ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ DEBUGP("we have a connection!\n"); ++ ++ LOCK_BH(&ip_pptp_lock); ++ ct_pptp_info = &master->help.ct_pptp_info; ++ nat_pptp_info = &master->nat.help.nat_pptp_info; ++ ++ /* need to alter GRE tuple because conntrack expectfn() used 'wrong' ++ * (unmanipulated) values */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ DEBUGP("completing tuples with NAT info \n"); ++ /* we can do this, since we're unconfirmed */ ++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == ++ htonl(ct_pptp_info->pac_call_id)) { ++ /* assume PNS->PAC */ ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = ++ htonl(nat_pptp_info->pns_call_id); ++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = ++ htonl(nat_pptp_info->pns_call_id); ++ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newcid = htonl(nat_pptp_info->pac_call_id); ++ } else { ++ /* assume PAC->PNS */ ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = ++ htonl(nat_pptp_info->pac_call_id); ++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = ++ htonl(nat_pptp_info->pac_call_id); ++ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newcid = htonl(nat_pptp_info->pns_call_id); ++ } ++ } else { ++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == ++ htonl(ct_pptp_info->pac_call_id)) { ++ /* assume PNS->PAC */ ++ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ newcid = htonl(ct_pptp_info->pns_call_id); ++ } ++ else { ++ /* assume PAC->PNS */ ++ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ newcid = htonl(ct_pptp_info->pac_call_id); ++ } ++ } ++ ++ mr.rangesize = 1; ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ mr.range[0].min = mr.range[0].max = ++ ((union ip_conntrack_manip_proto ) { newcid }); ++ DEBUGP("change ip to %u.%u.%u.%u\n", ++ NIPQUAD(newip)); ++ DEBUGP("change key to 0x%x\n", ntohl(newcid)); ++ ret = ip_nat_setup_info(ct, &mr, hooknum); ++ ++ UNLOCK_BH(&ip_pptp_lock); ++ ++ return ret; ++ ++} ++ ++/* outbound packets == from PNS to PAC */ ++static inline unsigned int ++pptp_outbound_pkt(struct sk_buff **pskb, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *exp) ++ ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *) iph + iph->ihl*4; ++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) ++ ((void *)tcph + tcph->doff*4); ++ ++ struct PptpControlHeader *ctlh; ++ union pptp_ctrl_union pptpReq; ++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; ++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; ++ ++ u_int16_t msg, *cid = NULL, new_callid; ++ ++ /* FIXME: size checks !!! */ ++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); ++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); ++ ++ new_callid = htons(ct_pptp_info->pns_call_id); ++ ++ switch (msg = ntohs(ctlh->messageType)) { ++ case PPTP_OUT_CALL_REQUEST: ++ cid = &pptpReq.ocreq->callID; ++ /* FIXME: ideally we would want to reserve a call ID ++ * here. current netfilter NAT core is not able to do ++ * this :( For now we use TCP source port. This breaks ++ * multiple calls within one control session */ ++ ++ /* save original call ID in nat_info */ ++ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; ++ ++ /* don't use tcph->source since we are at a DSTmanip ++ * hook (e.g. PREROUTING) and pkt is not mangled yet */ ++ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; ++ ++ /* save new call ID in ct info */ ++ ct_pptp_info->pns_call_id = ntohs(new_callid); ++ break; ++ case PPTP_IN_CALL_REPLY: ++ cid = &pptpReq.icreq->callID; ++ break; ++ case PPTP_CALL_CLEAR_REQUEST: ++ cid = &pptpReq.clrreq->callID; ++ break; ++ default: ++ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, ++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); ++ /* fall through */ ++ ++ case PPTP_SET_LINK_INFO: ++ /* only need to NAT in case PAC is behind NAT box */ ++ case PPTP_START_SESSION_REQUEST: ++ case PPTP_START_SESSION_REPLY: ++ case PPTP_STOP_SESSION_REQUEST: ++ case PPTP_STOP_SESSION_REPLY: ++ case PPTP_ECHO_REQUEST: ++ case PPTP_ECHO_REPLY: ++ /* no need to alter packet */ ++ return NF_ACCEPT; ++ } ++ ++ IP_NF_ASSERT(cid); ++ ++ DEBUGP("altering call id from 0x%04x to 0x%04x\n", ++ ntohs(*cid), ntohs(new_callid)); ++ ++ /* mangle packet */ ++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph, ++ sizeof(new_callid), (char *)&new_callid, ++ sizeof(new_callid)); ++ ++ return NF_ACCEPT; ++} ++ ++/* inbound packets == from PAC to PNS */ ++static inline unsigned int ++pptp_inbound_pkt(struct sk_buff **pskb, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *oldexp) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *) iph + iph->ihl*4; ++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) ++ ((void *)tcph + tcph->doff*4); ++ ++ struct PptpControlHeader *ctlh; ++ union pptp_ctrl_union pptpReq; ++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; ++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; ++ ++ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; ++ u_int32_t old_dst_ip; ++ ++ struct ip_conntrack_tuple t, inv_t; ++ struct ip_conntrack_tuple *orig_t, *reply_t; ++ ++ /* FIXME: size checks !!! */ ++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); ++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); ++ ++ new_pcid = htons(nat_pptp_info->pns_call_id); ++ ++ switch (msg = ntohs(ctlh->messageType)) { ++ case PPTP_OUT_CALL_REPLY: ++ pcid = &pptpReq.ocack->peersCallID; ++ cid = &pptpReq.ocack->callID; ++ if (!oldexp) { ++ DEBUGP("outcall but no expectation\n"); ++ break; ++ } ++ old_dst_ip = oldexp->tuple.dst.ip; ++ t = oldexp->tuple; ++ invert_tuplepr(&inv_t, &t); ++ ++ /* save original PAC call ID in nat_info */ ++ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; ++ ++ /* alter expectation */ ++ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) { ++ /* expectation for PNS->PAC direction */ ++ t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); ++ t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); ++ inv_t.src.ip = reply_t->src.ip; ++ inv_t.dst.ip = reply_t->dst.ip; ++ inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); ++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); ++ } else { ++ /* expectation for PAC->PNS direction */ ++ t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); ++ t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); ++ inv_t.src.ip = orig_t->src.ip; ++ inv_t.dst.ip = orig_t->dst.ip; ++ inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); ++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); ++ } ++ ++ if (!ip_conntrack_change_expect(oldexp, &t)) { ++ DEBUGP("successfully changed expect\n"); ++ } else { ++ DEBUGP("can't change expect\n"); ++ } ++ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t); ++ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t); ++ break; ++ case PPTP_IN_CALL_CONNECT: ++ pcid = &pptpReq.iccon->peersCallID; ++ if (!oldexp) ++ break; ++ old_dst_ip = oldexp->tuple.dst.ip; ++ t = oldexp->tuple; ++ ++ /* alter expectation, no need for callID */ ++ if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { ++ /* expectation for PNS->PAC direction */ ++ t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ } else { ++ /* expectation for PAC->PNS direction */ ++ t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ } ++ ++ if (!ip_conntrack_change_expect(oldexp, &t)) { ++ DEBUGP("successfully changed expect\n"); ++ } else { ++ DEBUGP("can't change expect\n"); ++ } ++ break; ++ case PPTP_IN_CALL_REQUEST: ++ /* only need to nat in case PAC is behind NAT box */ ++ break; ++ case PPTP_WAN_ERROR_NOTIFY: ++ pcid = &pptpReq.wanerr->peersCallID; ++ break; ++ case PPTP_CALL_DISCONNECT_NOTIFY: ++ pcid = &pptpReq.disc->callID; ++ break; ++ ++ default: ++ DEBUGP("unknown inbound packet %s\n", ++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); ++ /* fall through */ ++ ++ case PPTP_START_SESSION_REQUEST: ++ case PPTP_START_SESSION_REPLY: ++ case PPTP_STOP_SESSION_REQUEST: ++ case PPTP_STOP_SESSION_REPLY: ++ case PPTP_ECHO_REQUEST: ++ case PPTP_ECHO_REPLY: ++ /* no need to alter packet */ ++ return NF_ACCEPT; ++ } ++ ++ /* mangle packet */ ++ IP_NF_ASSERT(pcid); ++ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", ++ ntohs(*pcid), ntohs(new_pcid)); ++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph, ++ sizeof(new_pcid), (char *)&new_pcid, ++ sizeof(new_pcid)); ++ ++ if (new_cid) { ++ IP_NF_ASSERT(cid); ++ DEBUGP("altering call id from 0x%04x to 0x%04x\n", ++ ntohs(*cid), ntohs(new_cid)); ++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++ (void *)cid - (void *)pptph, ++ sizeof(new_cid), (char *)&new_cid, ++ sizeof(new_cid)); ++ } ++ ++ /* great, at least we don't need to resize packets */ ++ return NF_ACCEPT; ++} ++ ++ ++static unsigned int tcp_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, struct sk_buff **pskb) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *) iph + iph->ihl*4; ++ unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; ++ struct pptp_pkt_hdr *pptph; ++ ++ int dir; ++ ++ DEBUGP("entering\n"); ++ ++ /* Only mangle things once: DST for original direction ++ and SRC for reply direction. */ ++ dir = CTINFO2DIR(ctinfo); ++ if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ++ && dir == IP_CT_DIR_ORIGINAL) ++ || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST ++ && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("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" ++ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ ++ /* if packet is too small, just skip it */ ++ if (datalen < sizeof(struct pptp_pkt_hdr)+ ++ sizeof(struct PptpControlHeader)) { ++ DEBUGP("pptp packet too short\n"); ++ return NF_ACCEPT; ++ } ++ ++ pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4); ++ ++ /* if it's not a control message, we can't handle it */ ++ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || ++ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { ++ DEBUGP("not a pptp control packet\n"); ++ return NF_ACCEPT; ++ } ++ ++ LOCK_BH(&ip_pptp_lock); ++ ++ if (dir == IP_CT_DIR_ORIGINAL) { ++ /* reuqests sent by client to server (PNS->PAC) */ ++ pptp_outbound_pkt(pskb, ct, ctinfo, exp); ++ } else { ++ /* response from the server to the client (PAC->PNS) */ ++ pptp_inbound_pkt(pskb, ct, ctinfo, exp); ++ } ++ ++ UNLOCK_BH(&ip_pptp_lock); ++ ++ return NF_ACCEPT; ++} ++ ++/* nat helper struct for control connection */ ++static struct ip_nat_helper pptp_tcp_helper = { ++ .list = { NULL, NULL }, ++ .name = "pptp", ++ .flags = IP_NAT_HELPER_F_ALWAYS, ++ .me = THIS_MODULE, ++ .tuple = { .src = { .ip = 0, ++ .u = { .tcp = { .port = ++ __constant_htons(PPTP_CONTROL_PORT) } ++ } ++ }, ++ .dst = { .ip = 0, ++ .u = { .all = 0 }, ++ .protonum = IPPROTO_TCP ++ } ++ }, ++ ++ .mask = { .src = { .ip = 0, ++ .u = { .tcp = { .port = 0xFFFF } } ++ }, ++ .dst = { .ip = 0, ++ .u = { .all = 0 }, ++ .protonum = 0xFFFF ++ } ++ }, ++ .help = tcp_help, ++ .expect = pptp_nat_expected ++}; ++ ++ ++static int __init init(void) ++{ ++ DEBUGP("%s: registering NAT helper\n", __FILE__); ++ if (ip_nat_helper_register(&pptp_tcp_helper)) { ++ printk(KERN_ERR "Unable to register NAT application helper " ++ "for pptp\n"); ++ return -EIO; ++ } ++ ++ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ DEBUGP("cleanup_module\n" ); ++ ip_nat_helper_unregister(&pptp_tcp_helper); ++ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.4.20/net/ipv4/netfilter/ip_nat_proto_gre.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_proto_gre.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_proto_gre.c Wed Sep 24 09:17:55 2003 +@@ -0,0 +1,225 @@ ++/* ++ * ip_nat_proto_gre.c - Version 1.2 ++ * ++ * NAT protocol helper module for GRE. ++ * ++ * GRE is a generic encapsulation protocol, which is generally not very ++ * suited for NAT, as it has no protocol-specific part as port numbers. ++ * ++ * It has an optional key field, which may help us distinguishing two ++ * connections between the same two hosts. ++ * ++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 ++ * ++ * PPTP is built on top of a modified version of GRE, and has a mandatory ++ * field called "CallID", which serves us for the same purpose as the key ++ * field in plain GRE. ++ * ++ * Documentation about PPTP can be found in RFC 2637 ++ * ++ * (C) 2000-2003 by Harald Welte ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte "); ++MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++ ": " format, ## args) ++#else ++#define DEBUGP(x, args...) ++#endif ++ ++/* is key in given range between min and max */ ++static int ++gre_in_range(const struct ip_conntrack_tuple *tuple, ++ enum ip_nat_manip_type maniptype, ++ const union ip_conntrack_manip_proto *min, ++ const union ip_conntrack_manip_proto *max) ++{ ++ u_int32_t key; ++ ++ if (maniptype == IP_NAT_MANIP_SRC) ++ key = tuple->src.u.gre.key; ++ else ++ key = tuple->dst.u.gre.key; ++ ++ return ntohl(key) >= ntohl(min->gre.key) ++ && ntohl(key) <= ntohl(max->gre.key); ++} ++ ++/* generate unique tuple ... */ ++static int ++gre_unique_tuple(struct ip_conntrack_tuple *tuple, ++ const struct ip_nat_range *range, ++ enum ip_nat_manip_type maniptype, ++ const struct ip_conntrack *conntrack) ++{ ++ u_int32_t min, i, range_size; ++ u_int32_t key = 0, *keyptr; ++ ++ if (maniptype == IP_NAT_MANIP_SRC) ++ keyptr = &tuple->src.u.gre.key; ++ else ++ keyptr = &tuple->dst.u.gre.key; ++ ++ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { ++ ++ switch (tuple->dst.u.gre.version) { ++ case 0: ++ DEBUGP("NATing GRE version 0 (ct=%p)\n", ++ conntrack); ++ min = 1; ++ range_size = 0xffffffff; ++ break; ++ case GRE_VERSION_PPTP: ++ DEBUGP("%p: NATing GRE PPTP\n", ++ conntrack); ++ min = 1; ++ range_size = 0xffff; ++ break; ++ default: ++ printk(KERN_WARNING "nat_gre: unknown GRE version\n"); ++ return 0; ++ break; ++ } ++ ++ } else { ++ min = ntohl(range->min.gre.key); ++ range_size = ntohl(range->max.gre.key) - min + 1; ++ } ++ ++ DEBUGP("min = %u, range_size = %u\n", min, range_size); ++ ++ for (i = 0; i < range_size; i++, key++) { ++ *keyptr = htonl(min + key % range_size); ++ if (!ip_nat_used_tuple(tuple, conntrack)) ++ return 1; ++ } ++ ++ DEBUGP("%p: no NAT mapping\n", conntrack); ++ ++ return 0; ++} ++ ++/* manipulate a GRE packet according to maniptype */ ++static void ++gre_manip_pkt(struct iphdr *iph, size_t len, ++ const struct ip_conntrack_manip *manip, ++ enum ip_nat_manip_type maniptype) ++{ ++ struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); ++ struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; ++ ++ /* we only have destination manip of a packet, since 'source key' ++ * is not present in the packet itself */ ++ if (maniptype == IP_NAT_MANIP_DST) { ++ /* key manipulation is always dest */ ++ switch (greh->version) { ++ case 0: ++ if (!greh->key) { ++ DEBUGP("can't nat GRE w/o key\n"); ++ break; ++ } ++ if (greh->csum) { ++ /* FIXME: Never tested this code... */ ++ *(gre_csum(greh)) = ++ ip_nat_cheat_check(~*(gre_key(greh)), ++ manip->u.gre.key, ++ *(gre_csum(greh))); ++ } ++ *(gre_key(greh)) = manip->u.gre.key; ++ break; ++ case GRE_VERSION_PPTP: ++ DEBUGP("call_id -> 0x%04x\n", ++ ntohl(manip->u.gre.key)); ++ pgreh->call_id = htons(ntohl(manip->u.gre.key)); ++ break; ++ default: ++ DEBUGP("can't nat unknown GRE version\n"); ++ break; ++ } ++ } ++} ++ ++/* print out a nat tuple */ ++static unsigned int ++gre_print(char *buffer, ++ const struct ip_conntrack_tuple *match, ++ const struct ip_conntrack_tuple *mask) ++{ ++ unsigned int len = 0; ++ ++ if (mask->dst.u.gre.version) ++ len += sprintf(buffer + len, "version=%d ", ++ ntohs(match->dst.u.gre.version)); ++ ++ if (mask->dst.u.gre.protocol) ++ len += sprintf(buffer + len, "protocol=0x%x ", ++ ntohs(match->dst.u.gre.protocol)); ++ ++ if (mask->src.u.gre.key) ++ len += sprintf(buffer + len, "srckey=0x%x ", ++ ntohl(match->src.u.gre.key)); ++ ++ if (mask->dst.u.gre.key) ++ len += sprintf(buffer + len, "dstkey=0x%x ", ++ ntohl(match->src.u.gre.key)); ++ ++ return len; ++} ++ ++/* print a range of keys */ ++static unsigned int ++gre_print_range(char *buffer, const struct ip_nat_range *range) ++{ ++ if (range->min.gre.key != 0 ++ || range->max.gre.key != 0xFFFF) { ++ if (range->min.gre.key == range->max.gre.key) ++ return sprintf(buffer, "key 0x%x ", ++ ntohl(range->min.gre.key)); ++ else ++ return sprintf(buffer, "keys 0x%u-0x%u ", ++ ntohl(range->min.gre.key), ++ ntohl(range->max.gre.key)); ++ } else ++ return 0; ++} ++ ++/* nat helper struct */ ++static struct ip_nat_protocol gre = ++ { { NULL, NULL }, "GRE", IPPROTO_GRE, ++ gre_manip_pkt, ++ gre_in_range, ++ gre_unique_tuple, ++ gre_print, ++ gre_print_range ++ }; ++ ++static int __init init(void) ++{ ++ if (ip_nat_protocol_register(&gre)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip_nat_protocol_unregister(&gre); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_quake3.c linux-2.4.20/net/ipv4/netfilter/ip_nat_quake3.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_quake3.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_quake3.c Wed Sep 24 09:17:58 2003 +@@ -0,0 +1,249 @@ ++/* Quake3 extension for UDP NAT alteration. ++ * (C) 2002 by Filip Sneppe ++ * based on ip_nat_ftp.c and ip_nat_tftp.c ++ * ++ * ip_nat_quake3.c v0.0.3 2002-08-31 ++ * ++ * 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_quake3.o ports=port1,port2,...port ++ * ++ * please give the ports of all Quake3 master servers You wish to ++ * connect to. If you don't specify ports, the default will be UDP ++ * port 27950. ++ * ++ * Thanks to the Ethereal folks for their analysis of the Quake3 protocol. ++ * ++ * Notes: ++ * - If you're one of those people who would try anything to lower ++ * latency while playing Quake (and who isn't :-) ), you may want to ++ * consider not loading ip_nat_quake3 at all and just MASQUERADE all ++ * outgoing UDP traffic. ++ * This will make ip_conntrack_quake3 add the necessary expectations, ++ * but there will be no overhead for client->server UDP streams. If ++ * ip_nat_quake3 is loaded, quake3_nat_expected will be called per NAT ++ * hook for every packet in the client->server UDP stream. ++ * - Only SNAT/MASQUEARDE targets are useful for ip_nat_quake3. ++ * The IP addresses in the master connection payload (=IP addresses ++ * of Quake servers) have no relation with the master server so ++ * DNAT'ing the master connection to a server should not change the ++ * expected connections. ++ * - Not tested due to lack of equipment: ++ * - multiple Quake3 clients behind one MASQUERADE gateway ++ * - what if Quake3 client is running on router too ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Filip Sneppe "); ++MODULE_DESCRIPTION("Netfilter NAT helper for Quake III Arena"); ++MODULE_LICENSE("GPL"); ++ ++#define MAX_PORTS 8 ++ ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++#ifdef MODULE_PARM ++MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of Quake III master servers"); ++#endif ++ ++/* Quake3 master server reply will add > 100 expectations per reply packet; when ++ doing lots of printk's, klogd may not be able to read /proc/kmsg fast enough */ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++static struct quake3_search quake3s_nat = { "****", "getserversResponse", sizeof("getserversResponse") - 1 }; ++ ++static unsigned int ++quake3_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ 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 ip_conntrack_tuple repl; ++ int dir = CTINFO2DIR(ctinfo); ++ int i; ++ ++ DEBUGP("ip_nat_quake3: quake3_nat_help, direction: %s 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" : "???" ++ ); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("ip_nat_quake3: 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; ++ } ++ ++ if (!exp) { ++ DEBUGP("no conntrack expectation to modify\n"); ++ return NF_ACCEPT; ++ } ++ ++ if (strnicmp((const char *)udph + 12, quake3s_nat.pattern, quake3s_nat.plen) == 0) { ++ for(i=31; /* 8 bytes UDP hdr, 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */ ++ i+6 < ntohs(udph->len); ++ i+=7) { ++ DEBUGP("ip_nat_quake3: adding server at offset %u/%u %u.%u.%u.%u:%u\n", ++ i, ntohs(udph->len), ++ NIPQUAD( (u_int32_t) *( (u_int32_t *)( (int)udph + i ) ) ), ++ ntohs((__u16) *( (__u16 *)( (int)udph + i + 4 ) ) ) ); ++ ++ memset(&repl, 0, sizeof(repl)); ++ ++ repl.dst.protonum = IPPROTO_UDP; ++ repl.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ repl.dst.ip = *( (u_int32_t *)( (int)udph + i ) ); ++ repl.dst.u.udp.port = (__u16) *( (__u16 *)( (int)udph + i + 4 ) ); ++ ++ ip_conntrack_change_expect(exp, &repl); ++ } ++ } ++ return NF_ACCEPT; ++} ++ ++static unsigned int ++quake3_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ const struct ip_conntrack *master = ct->master->expectant; ++ struct ip_nat_multi_range mr; ++ u_int32_t newsrcip, newdstip, newip; ++#if 0 ++ const struct ip_conntrack_tuple *repl = ++ &master->tuplehash[IP_CT_DIR_REPLY].tuple; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl*4; ++#endif ++ ++ DEBUGP("ip_nat_quake3: quake3_nat_expected: here we are\n"); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ newdstip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) { ++ newip = newsrcip; ++ DEBUGP("hook: %s orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " ++ "newsrc: %u.%u.%u.%u\n", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????", ++ NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), ++ NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), ++ NIPQUAD(newip)); ++ ++ } else { ++ newip = newdstip; ++ DEBUGP("hook: %s orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " ++ "newdst: %u.%u.%u.%u\n", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????", ++ NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), ++ NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), ++ NIPQUAD(newip)); ++ } ++ ++ mr.rangesize = 1; ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ return ip_nat_setup_info(ct,&mr,hooknum); ++} ++ ++static struct ip_nat_helper quake3[MAX_PORTS]; ++static char quake3_names[MAX_PORTS][13]; /* quake3-65535 */ ++ ++static void fini(void) ++{ ++ int i; ++ ++ for (i = 0 ; i < ports_c; i++) { ++ DEBUGP("ip_nat_quake3: unregistering helper for port %d\n", ports[i]); ++ ip_nat_helper_unregister(&quake3[i]); ++ } ++} ++ ++static int __init init(void) ++ { ++ int i, ret = 0; ++ char *tmpname; ++ ++ if (!ports[0]) ++ ports[0] = QUAKE3_MASTER_PORT; ++ ++ for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { ++ memset(&quake3[i], 0, sizeof(struct ip_nat_helper)); ++ ++ quake3[i].tuple.dst.protonum = IPPROTO_UDP; ++ quake3[i].tuple.src.u.udp.port = htons(ports[i]); ++ quake3[i].mask.dst.protonum = 0xFFFF; ++ quake3[i].mask.src.u.udp.port = 0xFFFF; ++ quake3[i].help = quake3_nat_help; ++ quake3[i].flags = 0; ++ quake3[i].me = THIS_MODULE; ++ quake3[i].expect = quake3_nat_expected; ++ ++ tmpname = &quake3_names[i][0]; ++ if (ports[i] == QUAKE3_MASTER_PORT) ++ sprintf(tmpname, "quake3"); ++ else ++ sprintf(tmpname, "quake3-%d", i); ++ quake3[i].name = tmpname; ++ ++ DEBUGP("ip_nat_quake3: registering helper for port %d: name %s\n", ++ ports[i], quake3[i].name); ++ ret = ip_nat_helper_register(&quake3[i]); ++ ++ if (ret) { ++ printk("ip_nat_quake3: unable to register helper for port %d\n", ++ ports[i]); ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ return ret; ++ } ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.20/net/ipv4/netfilter/ip_nat_rule.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_rule.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_rule.c Wed Sep 24 09:16:27 2003 +@@ -1,5 +1,4 @@ + /* Everything about the rules for NAT. */ +-#define __NO_VERSION__ + #include + #include + #include +@@ -231,7 +230,7 @@ + return 1; + } + +-static inline unsigned int ++inline unsigned int + alloc_null_binding(struct ip_conntrack *conntrack, + struct ip_nat_info *info, + unsigned int hooknum) +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_snmp_basic.c linux-2.4.20/net/ipv4/netfilter/ip_nat_snmp_basic.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_snmp_basic.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_snmp_basic.c Wed Sep 24 09:16:21 2003 +@@ -53,9 +53,9 @@ + #include + #include + #include ++#include + #include + #include +-#include + + + +@@ -1309,9 +1309,9 @@ + "snmp", + IP_NAT_HELPER_F_STANDALONE, + THIS_MODULE, +- { { 0, { __constant_htons(SNMP_PORT) } }, ++ { { 0, { .udp = { __constant_htons(SNMP_PORT) } } }, + { 0, { 0 }, IPPROTO_UDP } }, +- { { 0, { 0xFFFF } }, ++ { { 0, { .udp = { 0xFFFF } } }, + { 0, { 0 }, 0xFFFF } }, + nat_help, NULL }; + +@@ -1320,9 +1320,9 @@ + "snmp_trap", + IP_NAT_HELPER_F_STANDALONE, + THIS_MODULE, +- { { 0, { __constant_htons(SNMP_TRAP_PORT) } }, ++ { { 0, { .udp = { __constant_htons(SNMP_TRAP_PORT) } } }, + { 0, { 0 }, IPPROTO_UDP } }, +- { { 0, { 0xFFFF } }, ++ { { 0, { .udp = { 0xFFFF } } }, + { 0, { 0 }, 0xFFFF } }, + nat_help, NULL }; + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.20/net/ipv4/netfilter/ip_nat_standalone.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_standalone.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_standalone.c Wed Sep 24 09:17:50 2003 +@@ -109,19 +109,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); + /* Seen it before? This can happen for loopback, retrans, + or local packets.. */ + if (!(info->initialized & (1 << maniptype))) { +- int in_hashes = info->initialized; + unsigned int ret; + + if (ct->master +@@ -130,6 +123,13 @@ + ret = call_expect(master_ct(ct), pskb, + hooknum, ct, info); + } else { ++#ifdef CONFIG_IP_NF_NAT_LOCAL ++ /* LOCAL_IN hook doesn't have a chain! */ ++ if (hooknum == NF_IP_LOCAL_IN) ++ ret = alloc_null_binding(ct, info, ++ hooknum); ++ else ++#endif + ret = ip_nat_rule_find(pskb, hooknum, in, out, + ct, info); + } +@@ -138,13 +138,6 @@ + WRITE_UNLOCK(&ip_nat_lock); + return ret; + } +- +- if (in_hashes) { +- IP_NF_ASSERT(info->bysource.conntrack); +- replace_in_hashes(ct, info); +- } else { +- place_in_hashes(ct, info); +- } + } else + DEBUGP("Already setup manip %s for ct %p\n", + maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", +@@ -195,6 +188,7 @@ + return ip_nat_fn(hooknum, pskb, in, out, okfn); + } + ++#ifdef CONFIG_IP_NF_NAT_LOCAL + static unsigned int + ip_nat_local_fn(unsigned int hooknum, + struct sk_buff **pskb, +@@ -220,6 +214,7 @@ + return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + return ret; + } ++#endif + + /* We must be after connection tracking and before packet filtering. */ + +@@ -229,16 +224,23 @@ + /* After packet filtering, change source */ + static struct nf_hook_ops ip_nat_out_ops + = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC}; ++ ++#ifdef CONFIG_IP_NF_NAT_LOCAL + /* Before packet filtering, change destination */ + 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 ++/* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */ + 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. */ ++/** ++ * ip_nat_protocol_register - Register a layer 4 protocol helper ++ * @proto: structure describing this helper ++ * ++ * This function is called by NAT layer 4 protocol helpers to register ++ * themselvers with the NAT core. ++ */ + int ip_nat_protocol_register(struct ip_nat_protocol *proto) + { + int ret = 0; +@@ -261,9 +263,16 @@ + return ret; + } + +-/* Noone stores the protocol anywhere; simply delete it. */ ++/** ++ * ip_nat_protocol_unregister - Unregister a layer 4 protocol helper ++ * @proto: sturcture describing the helper ++ * ++ * This function is called by NAT layer 4 protocol helpers to ++ * unregister themselves from the NAT core. ++ */ + void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) + { ++ /* Noone stores the protocol anywhere; simply delete it. */ + WRITE_LOCK(&ip_nat_lock); + LIST_DELETE(&protos, proto); + WRITE_UNLOCK(&ip_nat_lock); +@@ -301,12 +310,12 @@ + printk("ip_nat_init: can't register out hook.\n"); + goto cleanup_inops; + } ++#ifdef CONFIG_IP_NF_NAT_LOCAL + ret = nf_register_hook(&ip_nat_local_out_ops); + if (ret < 0) { + 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"); +@@ -323,9 +332,9 @@ + #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: ++#endif + nf_unregister_hook(&ip_nat_out_ops); + cleanup_inops: + nf_unregister_hook(&ip_nat_in_ops); +@@ -358,5 +367,6 @@ + EXPORT_SYMBOL(ip_nat_helper_unregister); + EXPORT_SYMBOL(ip_nat_cheat_check); + EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); ++EXPORT_SYMBOL(ip_nat_mangle_udp_packet); + EXPORT_SYMBOL(ip_nat_used_tuple); + MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_talk.c linux-2.4.20/net/ipv4/netfilter/ip_nat_talk.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_talk.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_talk.c Wed Sep 24 09:18:08 2003 +@@ -0,0 +1,473 @@ ++/* ++ * 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 ++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 ip_conntrack_expect *exp, ++ 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_expect *ct_talk_info; ++ ++ 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); ++ ct_talk_info = &exp->help.exp_talk_info; ++ ++ if (!(answer == SUCCESS ++ && (type == LOOK_UP || type == ANNOUNCE) ++ && exp != NULL)) { ++ UNLOCK_BH(&ip_talk_lock); ++ return NF_ACCEPT; ++ } ++ ++ DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n", ++ ntohs(ct_talk_info->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 = exp->tuple; ++ t.dst.ip = newip; ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (port = ntohs(ct_talk_info->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_change_expect(exp, &t) == 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_conntrack_expect *exp, ++ 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, exp, 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, exp, 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, exp, 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_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ return talk_help(ct, exp, info, ctinfo, hooknum, pskb, TALK_PORT); ++} ++ ++static unsigned int nhelp(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ return talk_help(ct, exp, info, ctinfo, hooknum, pskb, NTALK_PORT); ++} ++ ++static unsigned int ++talk_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info); ++ ++static struct ip_nat_helper talk_helpers[2] = ++ { { { NULL, NULL }, ++ "talk", /* name */ ++ IP_NAT_HELPER_F_ALWAYS, /* flags */ ++ THIS_MODULE, /* module */ ++ { { 0, { .udp = { __constant_htons(TALK_PORT) } } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_UDP } }, ++ { { 0, { .udp = { 0xFFFF } } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ help, /* helper */ ++ talk_nat_expected }, /* expectfn */ ++ { { NULL, NULL }, ++ "ntalk", /* name */ ++ IP_NAT_HELPER_F_ALWAYS, /* flags */ ++ THIS_MODULE, /* module */ ++ { { 0, { .udp = { __constant_htons(NTALK_PORT) } } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_UDP } }, ++ { { 0, { .udp = { 0xFFFF } } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ nhelp, /* helper */ ++ talk_nat_expected } /* expectfn */ ++ }; ++ ++static unsigned int ++talk_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ u_int16_t port; ++ unsigned int ret; ++ ++ struct ip_conntrack *master = master_ct(ct); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1<master->help.exp_talk_info.port; ++ 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(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; ++ ++ /* ... unless we're doing a MANIP_DST, in which case, make ++ sure we map to the correct port */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { .udp = { port } }); ++ } ++ ret = ip_nat_setup_info(ct, &mr, hooknum); ++ ++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { ++ DEBUGP("talk_expected: setting NAT helper for %p\n", ct); ++ /* NAT expectfn called with ip_nat_lock write-locked */ ++ info->helper = &talk_helpers[htons(port) - TALK_PORT]; ++ } ++ return ret; ++} ++ ++static int __init init(void) ++{ ++ int ret = 0; ++ ++ if (talk > 0) { ++ ret = ip_nat_helper_register(&talk_helpers[0]); ++ ++ if (ret != 0) ++ return ret; ++ } ++ if (ntalk > 0 || ntalk2 > 0) { ++ ret = ip_nat_helper_register(&talk_helpers[1]); ++ ++ if (ret != 0 && talk > 0) ++ ip_nat_helper_unregister(&talk_helpers[0]); ++ } ++ 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]); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_nat_tftp.c linux-2.4.20/net/ipv4/netfilter/ip_nat_tftp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_nat_tftp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_nat_tftp.c Wed Sep 24 09:16:24 2003 +@@ -0,0 +1,195 @@ ++/* ++ * Licensed under GNU GPL version 2 Copyright Magnus Boden ++ * Version: 0.0.7 ++ * ++ * Thu 21 Mar 2002 Harald Welte ++ * - Port to newnat API ++ * ++ * 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 ++ ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++#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(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \ ++ format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++static unsigned int ++tftp_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir = CTINFO2DIR(ctinfo); ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ struct tftphdr *tftph = (void *)udph + 8; ++ struct ip_conntrack_tuple repl; ++ ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) ++ return NF_ACCEPT; ++ ++ if (!exp) { ++ DEBUGP("no conntrack expectation to modify\n"); ++ return NF_ACCEPT; ++ } ++ ++ switch (ntohs(tftph->opcode)) { ++ /* RRQ and WRQ works the same way */ ++ case TFTP_OPCODE_READ: ++ case TFTP_OPCODE_WRITE: ++ repl = ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ DEBUGP(""); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ DEBUGP("expecting: "); ++ DUMP_TUPLE(&repl); ++ DUMP_TUPLE(&exp->mask); ++ ip_conntrack_change_expect(exp, &repl); ++ break; ++ default: ++ DEBUGP("Unknown opcode\n"); ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static unsigned int ++tftp_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ const struct ip_conntrack *master = ct->master->expectant; ++ const struct ip_conntrack_tuple *orig = ++ &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct ip_nat_multi_range mr; ++#if 0 ++ const struct ip_conntrack_tuple *repl = ++ &master->tuplehash[IP_CT_DIR_REPLY].tuple; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl*4; ++#endif ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ 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 = orig->dst.ip; ++ DEBUGP("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(orig->dst.ip)); ++ } else { ++ mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip; ++ mr.range[0].min.udp.port = mr.range[0].max.udp.port = ++ orig->src.u.udp.port; ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ ++ DEBUGP("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(orig->src.ip), ntohs(orig->src.u.udp.port)); ++ } ++ ++ return ip_nat_setup_info(ct,&mr,hooknum); ++} ++ ++static struct ip_nat_helper tftp[MAX_PORTS]; ++static char tftp_names[MAX_PORTS][10]; ++ ++static void fini(void) ++{ ++ int i; ++ ++ for (i = 0 ; i < ports_c; i++) { ++ DEBUGP("unregistering helper for port %d\n", ports[i]); ++ ip_nat_helper_unregister(&tftp[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret = 0; ++ char *tmpname; ++ ++ if (!ports[0]) ++ ports[0] = TFTP_PORT; ++ ++ for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { ++ 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; ++ tftp[i].flags = 0; ++ tftp[i].me = THIS_MODULE; ++ tftp[i].expect = tftp_nat_expected; ++ ++ tmpname = &tftp_names[i][0]; ++ if (ports[i] == TFTP_PORT) ++ sprintf(tmpname, "tftp"); ++ else ++ sprintf(tmpname, "tftp-%d", i); ++ tftp[i].name = tmpname; ++ ++ DEBUGP("ip_nat_tftp: registering for port %d: name %s\n", ++ ports[i], tftp[i].name); ++ ret = ip_nat_helper_register(&tftp[i]); ++ ++ if (ret) { ++ printk("ip_nat_tftp: unable to register for port %d\n", ++ ports[i]); ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ return ret; ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ip_pool.c linux-2.4.20/net/ipv4/netfilter/ip_pool.c +--- linux-2.4.20.org/net/ipv4/netfilter/ip_pool.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ip_pool.c Wed Sep 24 09:16:59 2003 +@@ -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; i + * ++ * 6 Mar 2002 Robert Olsson ++ * 17 Apr 2003 Chris Wilson ++ * - mark_source_chains speedup for complex chains ++ * + * 19 Jan 2002 Harald Welte + * - increase module usage count as soon as we have rules inside + * a table +@@ -24,6 +28,17 @@ + #include + + #include ++#include ++ ++#ifdef CONFIG_IP_NF_TARGET_TRACE_NEEDED ++static const char *hooknames[] = { ++ [NF_IP_PRE_ROUTING] "PREROUTING", ++ [NF_IP_LOCAL_IN] "INPUT", ++ [NF_IP_FORWARD] "FORWARD", ++ [NF_IP_LOCAL_OUT] "OUTPUT", ++ [NF_IP_POST_ROUTING] "POSTROUTING", ++}; ++#endif + + /*#define DEBUG_IP_FIREWALL*/ + /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */ +@@ -68,13 +83,12 @@ + #define inline + #endif + +-/* Locking is simple: we assume at worst case there will be one packet +- in user context and one from bottom halves (or soft irq if Alexey's +- softnet patch was applied). +- ++/* + We keep a set of rules for each CPU, so we can avoid write-locking +- them; doing a readlock_bh() stops packets coming through if we're +- in user context. ++ them in the softirq when updating the counters and therefore ++ only need to read-lock in the softirq; doing a write_lock_bh() in user ++ context stops packets coming through and allows user context to read ++ the counters or update the rules. + + To be cache friendly on SMP, we arrange them like so: + [ n-entries ] +@@ -251,6 +265,39 @@ + return (struct ipt_entry *)(base + offset); + } + ++static inline int ++get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, ++ char **chainname, u_int16_t *rulenum) ++{ ++ struct ipt_entry_target *t; ++ ++ (*rulenum)++; ++ ++ if (s == e) ++ return 1; ++ ++ t = ipt_get_target(s); ++ if (strcmp(t->u.kernel.target->name, IPT_ERROR_TARGET) == 0) { ++ *chainname = t->data; ++ (*rulenum) = 0; ++ } ++ ++ return 0; ++} ++ ++/* All zeroes == unconditional rule. */ ++static inline int ++unconditional(const struct ipt_ip *ip) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++) ++ if (((__u32 *)ip)[i]) ++ return 0; ++ ++ return 1; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(struct sk_buff **pskb, +@@ -326,6 +373,27 @@ + + t = ipt_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); ++#ifdef CONFIG_IP_NF_TARGET_TRACE_NEEDED ++ /* The packet traced and the rule isn't an unconditional return/END. */ ++ if (((*pskb)->nfcache & NFC_TRACE) ++ && !(e->target_offset == sizeof(struct ipt_entry) ++ && (strcmp(t->u.kernel.target->name, ++ IPT_STANDARD_TARGET) == 0) ++ && !t->u.kernel.target->target ++ && ((struct ipt_standard_target *)t)->verdict < 0 ++ && unconditional(&e->ip))) { ++ char *chainname = (char *) hooknames[hook]; ++ u_int16_t rulenum = 0; ++ ++ IPT_ENTRY_ITERATE(get_entry(table_base, table->private->hook_entry[hook]), ++ table->private->size, ++ get_chainname_rulenum, ++ e, &chainname, &rulenum); ++ ++ nf_log_ip_packet(pskb, hook, in, out, "TRACE: %s/%s/%u ", ++ table->name, chainname, rulenum); ++ } ++#endif + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; +@@ -482,19 +550,6 @@ + return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex); + } + +-/* All zeroes == unconditional rule. */ +-static inline int +-unconditional(const struct ipt_ip *ip) +-{ +- unsigned int i; +- +- for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++) +- if (((__u32 *)ip)[i]) +- return 0; +- +- return 1; +-} +- + /* Figures out from what hook each rule can be called: returns 0 if + there are loops. Puts hook bitmask in comefrom. */ + static int +@@ -502,6 +557,9 @@ + { + unsigned int hook; + ++ /* keep track of where we have been: */ ++ unsigned char *been = vmalloc(newinfo->size); ++ + /* No recursion; use packet counter to save back ptrs (reset + to 0 as we leave), and comefrom to save source hook bitmask */ + for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) { +@@ -514,6 +572,7 @@ + + /* Set initial back pointer. */ + e->counters.pcnt = pos; ++ memset(been, 0, newinfo->size); + + for (;;) { + struct ipt_standard_target *t +@@ -522,6 +581,7 @@ + if (e->comefrom & (1 << NF_IP_NUMHOOKS)) { + printk("iptables: loop hook %u pos %u %08X.\n", + hook, pos, e->comefrom); ++ vfree(been); + return 0; + } + e->comefrom +@@ -569,10 +629,14 @@ + } else { + int newpos = t->verdict; + +- if (strcmp(t->target.u.user.name, ++ if ( (pos < 0 || pos >= newinfo->size ++ || !been[pos]) ++ && strcmp(t->target.u.user.name, + IPT_STANDARD_TARGET) == 0 + && newpos >= 0) { + /* This a jump; chase it. */ ++ if (pos >= 0 && pos < newinfo->size) ++ been[pos]++; + duprintf("Jump rule %u -> %u\n", + pos, newpos); + } else { +@@ -588,6 +652,7 @@ + next: + duprintf("Finished chain %u\n", hook); + } ++ vfree(been); + return 1; + } + +@@ -1630,7 +1695,7 @@ + u_int8_t type, u_int8_t code, + int invert) + { +- return (type == test_type && code >= min_code && code <= max_code) ++ return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code)) + ^ invert; + } + +@@ -1699,14 +1764,15 @@ + = { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL }; + + #ifdef CONFIG_PROC_FS +-static inline int print_name(const struct ipt_table *t, ++static inline int print_name(const char *i, + off_t start_offset, char *buffer, int length, + off_t *pos, unsigned int *count) + { + if ((*count)++ >= start_offset) { + unsigned int namelen; + +- namelen = sprintf(buffer + *pos, "%s\n", t->name); ++ namelen = sprintf(buffer + *pos, "%s\n", ++ i + sizeof(struct list_head)); + if (*pos + namelen > length) { + /* Stop iterating */ + return 1; +@@ -1724,7 +1790,7 @@ + if (down_interruptible(&ipt_mutex) != 0) + return 0; + +- LIST_FIND(&ipt_tables, print_name, struct ipt_table *, ++ LIST_FIND(&ipt_tables, print_name, void *, + offset, buffer, length, &pos, &count); + + up(&ipt_mutex); +@@ -1733,6 +1799,46 @@ + *start=(char *)((unsigned long)count-offset); + return pos; + } ++ ++static int ipt_get_targets(char *buffer, char **start, off_t offset, int length) ++{ ++ off_t pos = 0; ++ unsigned int count = 0; ++ ++ if (down_interruptible(&ipt_mutex) != 0) ++ return 0; ++ ++ LIST_FIND(&ipt_target, print_name, void *, ++ offset, buffer, length, &pos, &count); ++ ++ up(&ipt_mutex); ++ ++ *start = (char *)((unsigned long)count - offset); ++ return pos; ++} ++ ++static int ipt_get_matches(char *buffer, char **start, off_t offset, int length) ++{ ++ off_t pos = 0; ++ unsigned int count = 0; ++ ++ if (down_interruptible(&ipt_mutex) != 0) ++ return 0; ++ ++ LIST_FIND(&ipt_match, print_name, void *, ++ offset, buffer, length, &pos, &count); ++ ++ up(&ipt_mutex); ++ ++ *start = (char *)((unsigned long)count - offset); ++ return pos; ++} ++ ++static struct { char *name; get_info_t *get_info; } ipt_proc_entry[] = ++{ { "ip_tables_names", ipt_get_tables }, ++ { "ip_tables_targets", ipt_get_targets }, ++ { "ip_tables_matches", ipt_get_matches }, ++ { NULL, NULL} }; + #endif /*CONFIG_PROC_FS*/ + + static int __init init(void) +@@ -1758,13 +1864,19 @@ + #ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *proc; ++ int i; + +- proc = proc_net_create("ip_tables_names", 0, ipt_get_tables); +- if (!proc) { +- nf_unregister_sockopt(&ipt_sockopts); +- return -ENOMEM; ++ for (i = 0; ipt_proc_entry[i].name; i++) { ++ proc = proc_net_create(ipt_proc_entry[i].name, 0, ++ ipt_proc_entry[i].get_info); ++ if (!proc) { ++ while (--i >= 0) ++ proc_net_remove(ipt_proc_entry[i].name); ++ nf_unregister_sockopt(&ipt_sockopts); ++ return -ENOMEM; ++ } ++ proc->owner = THIS_MODULE; + } +- proc->owner = THIS_MODULE; + } + #endif + +@@ -1776,7 +1888,11 @@ + { + nf_unregister_sockopt(&ipt_sockopts); + #ifdef CONFIG_PROC_FS +- proc_net_remove("ip_tables_names"); ++ { ++ int i; ++ for (i = 0; ipt_proc_entry[i].name; i++) ++ proc_net_remove(ipt_proc_entry[i].name); ++ } + #endif + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipchains_core.c linux-2.4.20/net/ipv4/netfilter/ipchains_core.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipchains_core.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipchains_core.c Wed Sep 24 09:16:14 2003 +@@ -1566,16 +1566,8 @@ + + /* File offset is actually in records, not bytes. */ + static int ip_chain_procinfo(char *buffer, char **start, +- off_t offset, int length +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29) +- , int reset +-#endif +- ) ++ off_t offset, int length) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) +- /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ +- int reset = 0; +-#endif + struct ip_chain *i; + struct ip_fwkernel *j = ip_fw_chains->chain; + unsigned long flags; +@@ -1612,9 +1604,6 @@ + len = last_len; + goto outside; + } +- else if (reset) +- memset(j->counters, 0, +- sizeof(struct ip_counters)*NUM_SLOTS); + } + } + outside: +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipfwadm_core.c linux-2.4.20/net/ipv4/netfilter/ipfwadm_core.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipfwadm_core.c Wed Sep 24 08:52:55 2003 ++++ linux-2.4.20/net/ipv4/netfilter/ipfwadm_core.c Wed Sep 24 09:16:14 2003 +@@ -1108,9 +1108,8 @@ + #endif /* CONFIG_IP_FIREWALL */ + + #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) +- + static int ip_chain_procinfo(int stage, char *buffer, char **start, +- off_t offset, int length, int reset) ++ off_t offset, int length) + { + off_t pos=0, begin=0; + struct ip_fw *i; +@@ -1181,12 +1180,6 @@ + len = last_len; + break; + } +- else if(reset) +- { +- /* This needs to be done at this specific place! */ +- i->fw_pcnt=0L; +- i->fw_bcnt=0L; +- } + last_len = len; + i=i->fw_next; + } +@@ -1200,69 +1193,30 @@ + #endif + + #ifdef CONFIG_IP_ACCT +- + static int ip_acct_procinfo(char *buffer, char **start, off_t offset, +- int length +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29) +- , int reset +-#endif +- ) ++ int length) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) +- /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ +- int reset = 0; +-#endif +- return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length, +- reset); ++ return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length); + } +- + #endif + + #ifdef CONFIG_IP_FIREWALL +- + static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset, +- int length +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29) +- , int reset +-#endif +- ) ++ int length) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) +- /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ +- int reset = 0; +-#endif +- return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length, +- reset); ++ return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length); + } + + static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset, +- int length +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29) +- , int reset +-#endif +- ) ++ int length) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) +- /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ +- int reset = 0; +-#endif +- return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length, +- reset); ++ return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length); + } + + static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, +- int length +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29) +- , int reset +-#endif +- ) ++ int length) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) +- /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ +- int reset = 0; +-#endif +- return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length, +- reset); ++ return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length); + } + #endif + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_CLASSIFY.c linux-2.4.20/net/ipv4/netfilter/ipt_CLASSIFY.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_CLASSIFY.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_CLASSIFY.c Wed Sep 24 09:17:14 2003 +@@ -0,0 +1,82 @@ ++/* ++ * This is a module which is used for setting the skb->priority field ++ * of an skb for qdisc classification. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Patrick McHardy "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("iptables qdisc classification target module"); ++ ++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_classify_target_info *clinfo = targinfo; ++ ++ if((*pskb)->priority != clinfo->priority) { ++ (*pskb)->priority = clinfo->priority; ++ (*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) ++{ ++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_classify_target_info))){ ++ printk(KERN_ERR "CLASSIFY: invalid size (%u != %u).\n", ++ targinfosize, ++ IPT_ALIGN(sizeof(struct ipt_classify_target_info))); ++ return 0; ++ } ++ ++ if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { ++ printk(KERN_ERR "CLASSIFY: only valid in POST_ROUTING.\n"); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk(KERN_WARNING "CLASSIFY: can only be called from " ++ "\"mangle\" table, not \"%s\".\n", ++ tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_classify_reg ++= { { NULL, NULL }, "CLASSIFY", target, checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_classify_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_classify_reg); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.4.20/net/ipv4/netfilter/ipt_CONNMARK.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_CONNMARK.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_CONNMARK.c Wed Sep 24 09:17:17 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_ECN.c linux-2.4.20/net/ipv4/netfilter/ipt_ECN.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_ECN.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_ECN.c Wed Sep 24 09:16:14 2003 +@@ -87,8 +87,8 @@ + } + + if (diffs[0] != *tcpflags) { +- diffs[0] = htons(diffs[0]) ^ 0xFFFF; +- diffs[1] = htons(*tcpflags); ++ diffs[0] = diffs[0] ^ 0xFFFF; ++ diffs[1] = *tcpflags; + tcph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + tcph->check^0xFFFF)); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_IMQ.c linux-2.4.20/net/ipv4/netfilter/ipt_IMQ.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_IMQ.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_IMQ.c Wed Sep 24 09:17:19 2003 +@@ -0,0 +1,78 @@ ++/* This target marks packets to be enqueued to an imq device */ ++#include ++#include ++#include ++#include ++#include ++ ++static unsigned int imq_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_imq_info *mr = (struct ipt_imq_info*)targinfo; ++ ++ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE; ++ (*pskb)->nfcache |= NFC_ALTERED; ++ ++ return IPT_CONTINUE; ++} ++ ++static int imq_checkentry(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ struct ipt_imq_info *mr; ++ ++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_imq_info))) { ++ printk(KERN_WARNING "IMQ: invalid targinfosize\n"); ++ return 0; ++ } ++ mr = (struct ipt_imq_info*)targinfo; ++ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk(KERN_WARNING ++ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n", ++ tablename); ++ return 0; ++ } ++ ++ if (mr->todev > IMQ_MAX_DEVS) { ++ printk(KERN_WARNING ++ "IMQ: invalid device specified, highest is %u\n", ++ IMQ_MAX_DEVS); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_imq_reg = { ++ { NULL, NULL}, ++ "IMQ", ++ imq_target, ++ imq_checkentry, ++ NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_imq_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_imq_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_IPMARK.c linux-2.4.20/net/ipv4/netfilter/ipt_IPMARK.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_IPMARK.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_IPMARK.c Wed Sep 24 09:17:23 2003 +@@ -0,0 +1,88 @@ ++/* This is a module which is used for setting the NFMARK field of an skb. */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Grzegorz Janoszka "); ++MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address"); ++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) ++{ ++ const struct ipt_ipmark_target_info *ipmarkinfo = targinfo; ++ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ ++ unsigned long mark; ++ char *a, t; ++ ++ if(ipmarkinfo->addr == IPT_IPMARK_SRC) ++ mark = (unsigned long) iph->saddr; ++ else ++ mark = (unsigned long) iph->daddr; ++ ++// mark has ip address in little indian, we have to change the byte order: ++ a = (char *) &mark; ++ t = *a; *a=*(a+3); *(a+3)=t; ++ t=*(a+1); *(a+1)=*(a+2); *(a+2)=t; ++ ++ mark &= ipmarkinfo->andmask; ++ mark |= ipmarkinfo->ormask; ++ ++ if((*pskb)->nfmark != mark) { ++ (*pskb)->nfmark = mark; ++ (*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) ++{ ++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ipmark_target_info))) { ++ printk(KERN_WARNING "IPMARK: targinfosize %u != %Zu\n", ++ targinfosize, ++ IPT_ALIGN(sizeof(struct ipt_ipmark_target_info))); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk(KERN_WARNING "IPMARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_ipmark_reg ++= { { NULL, NULL }, "IPMARK", target, checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_ipmark_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_ipmark_reg); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.4.20/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c Wed Sep 24 09:16:30 2003 +@@ -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("Strip 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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_LOG.c linux-2.4.20/net/ipv4/netfilter/ipt_LOG.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_LOG.c Mon Feb 25 19:38:14 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_LOG.c Wed Sep 24 09:16:23 2003 +@@ -3,16 +3,20 @@ + */ + #include + #include +-#include + #include ++#include + #include + #include + #include +-#include +- +-struct in_device; + #include ++ ++#include + #include ++#include ++ ++static unsigned int nflog = 1; ++MODULE_PARM(nflog, "i"); ++MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); + + #if 0 + #define DEBUGP printk +@@ -20,10 +24,20 @@ + #define DEBUGP(format, args...) + #endif + ++/* FIXME: move to ip.h like in 2.5 */ ++struct ahhdr { ++ __u8 nexthdr; ++ __u8 hdrlen; ++ __u16 reserved; ++ __u32 spi; ++ __u32 seq_no; ++}; ++ + struct esphdr { + __u32 spi; +-}; /* FIXME evil kludge */ +- ++ __u32 seq_no; ++}; ++ + /* Use lock to serialize, so printks don't overlap */ + static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; + +@@ -58,7 +72,8 @@ + printk("FRAG:%u ", ntohs(iph->frag_off) & IP_OFFSET); + + if ((info->logflags & IPT_LOG_IPOPT) +- && iph->ihl * 4 != sizeof(struct iphdr)) { ++ && iph->ihl * 4 != sizeof(struct iphdr) ++ && iph->ihl * 4 >= datalen) { + unsigned int i; + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ +@@ -230,13 +245,30 @@ + break; + } + /* Max Length */ +- case IPPROTO_AH: ++ case IPPROTO_AH: { ++ struct ahhdr *ah = protoh; ++ ++ /* Max length: 9 "PROTO=AH " */ ++ printk("PROTO=AH "); ++ ++ if (ntohs(iph->frag_off) & IP_OFFSET) ++ break; ++ ++ /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ++ if (datalen < sizeof (*ah)) { ++ printk("INCOMPLETE [%u bytes] ", datalen); ++ break; ++ } ++ ++ /* Length: 15 "SPI=0xF1234567 " */ ++ printk("SPI=0x%x ", ntohl(ah->spi) ); ++ break; ++ } + case IPPROTO_ESP: { + struct esphdr *esph = protoh; +- int esp= (iph->protocol==IPPROTO_ESP); + + /* Max length: 10 "PROTO=ESP " */ +- printk("PROTO=%s ",esp? "ESP" : "AH"); ++ printk("PROTO=ESP "); + + if (ntohs(iph->frag_off) & IP_OFFSET) + break; +@@ -270,23 +302,21 @@ + /* maxlen = 230+ 91 + 230 + 252 = 803 */ + } + +-static unsigned int +-ipt_log_target(struct sk_buff **pskb, ++static void ++ipt_log_packet(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_log_info *loginfo, ++ const char *level_string, ++ const char *prefix) + { + struct iphdr *iph = (*pskb)->nh.iph; +- const struct ipt_log_info *loginfo = targinfo; +- char level_string[4] = "< >"; + +- level_string[1] = '0' + (loginfo->level % 8); + spin_lock_bh(&log_lock); + printk(level_string); + printk("%sIN=%s OUT=%s ", +- loginfo->prefix, ++ prefix == NULL ? loginfo->prefix : prefix, + in ? in->name : "", + out ? out->name : ""); + if (in && !out) { +@@ -306,10 +336,59 @@ + dump_packet(loginfo, iph, (*pskb)->len, 1); + printk("\n"); + spin_unlock_bh(&log_lock); ++} ++ ++static unsigned int ++ipt_log_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_log_info *loginfo = targinfo; ++ char level_string[4] = "< >"; ++ ++ level_string[1] = '0' + (loginfo->level % 8); ++ ipt_log_packet(pskb, hooknum, in, out, loginfo, level_string, NULL); + + return IPT_CONTINUE; + } + ++static void ++ip_log_packet_fn(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const char *prefix) ++{ ++ struct ipt_log_info loginfo = { ++ .level = 0, ++ .logflags = IPT_LOG_MASK, ++ .prefix = "" ++ }; ++ ++ ipt_log_packet(pskb, hooknum, in, out, &loginfo, KERN_WARNING, prefix); ++} ++ ++static void ++ip_log_fn(char *pfh, size_t len, ++ const char *prefix) ++{ ++ struct iphdr *iph = (struct iphdr *)pfh; ++ struct ipt_log_info loginfo = { ++ .level = 0, ++ .logflags = IPT_LOG_MASK, ++ .prefix = "", ++ }; ++ ++ spin_lock_bh(&log_lock); ++ printk(KERN_WARNING "%s", prefix); ++ dump_packet(&loginfo, iph, len, 1); ++ printk("\n"); ++ spin_unlock_bh(&log_lock); ++} ++ + static int ipt_log_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, +@@ -341,17 +420,23 @@ + static struct ipt_target ipt_log_reg + = { { NULL, NULL }, "LOG", ipt_log_target, ipt_log_checkentry, NULL, + THIS_MODULE }; ++static struct nf_logging_t ip_logging_fn ++= { ip_log_packet_fn, ip_log_fn }; + + static int __init init(void) + { + if (ipt_register_target(&ipt_log_reg)) + return -EINVAL; +- ++ if (nflog) ++ nf_ip_log_register(&ip_logging_fn); ++ + return 0; + } + + static void __exit fini(void) + { ++ if (nflog) ++ nf_ip_log_unregister(&ip_logging_fn); + ipt_unregister_target(&ipt_log_reg); + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.4.20/net/ipv4/netfilter/ipt_MASQUERADE.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_MASQUERADE.c Sun Sep 30 19:26:08 2001 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_MASQUERADE.c Wed Sep 24 09:16:25 2003 +@@ -87,13 +87,21 @@ + key.dst = (*pskb)->nh.iph->daddr; + key.src = 0; /* Unknown: that's what we're trying to establish */ + key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN; +- key.oif = out->ifindex; ++ key.oif = 0; + #ifdef CONFIG_IP_ROUTE_FWMARK + key.fwmark = (*pskb)->nfmark; + #endif + if (ip_route_output_key(&rt, &key) != 0) { +- /* Shouldn't happen */ +- printk("MASQUERADE: No route: Rusty's brain broke!\n"); ++ /* Funky routing can do this. */ ++ if (net_ratelimit()) ++ printk("MASQUERADE:" ++ " No route: Rusty's brain broke!\n"); ++ return NF_DROP; ++ } ++ if (rt->u.dst.dev != out) { ++ if (net_ratelimit()) ++ printk("MASQUERADE:" ++ " Route sent us somewhere else.\n"); + return NF_DROP; + } + +@@ -116,63 +124,37 @@ + } + + static inline int +-device_cmp(const struct ip_conntrack *i, void *ifindex) ++device_cmp(const struct ip_conntrack *i, void *_ina) + { +- int ret; ++ int ret = 0; ++ struct in_ifaddr *ina = _ina; + + READ_LOCK(&masq_lock); +- ret = (i->nat.masq_index == (int)(long)ifindex); ++ /* If it's masquerading out this interface with a different address, ++ * or we don't know the new address of this interface. */ ++ if (i->nat.masq_index == ina->ifa_dev->dev->ifindex ++ && i->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != ina->ifa_address) ++ ret = 1; + READ_UNLOCK(&masq_lock); + + return ret; + } + +-static int masq_device_event(struct notifier_block *this, +- unsigned long event, +- void *ptr) +-{ +- struct net_device *dev = ptr; +- +- if (event == NETDEV_DOWN) { +- /* Device was downed. Search entire table for +- conntracks which were associated with that device, +- and forget them. */ +- IP_NF_ASSERT(dev->ifindex != 0); +- +- ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex); +- } +- +- return NOTIFY_DONE; +-} +- + static int masq_inet_event(struct notifier_block *this, + unsigned long event, + void *ptr) + { +- struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; +- +- if (event == NETDEV_DOWN) { +- /* IP address was deleted. Search entire table for +- conntracks which were associated with that device, +- and forget them. */ +- IP_NF_ASSERT(dev->ifindex != 0); +- +- ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex); +- } ++ /* For some configurations, interfaces often come back with ++ * the same address. If not, clean up old conntrack ++ * entries. */ ++ if (event == NETDEV_UP) ++ ip_ct_selective_cleanup(device_cmp, ptr); + + return NOTIFY_DONE; + } + +-static struct notifier_block masq_dev_notifier = { +- masq_device_event, +- NULL, +- 0 +-}; +- + static struct notifier_block masq_inet_notifier = { +- masq_inet_event, +- NULL, +- 0 ++ .notifier_call = masq_inet_event + }; + + static struct ipt_target masquerade +@@ -185,12 +167,9 @@ + + ret = ipt_register_target(&masquerade); + +- if (ret == 0) { +- /* Register for device down reports */ +- register_netdevice_notifier(&masq_dev_notifier); ++ if (ret == 0) + /* Register IP address change reports */ + register_inetaddr_notifier(&masq_inet_notifier); +- } + + return ret; + } +@@ -198,7 +177,6 @@ + static void __exit fini(void) + { + ipt_unregister_target(&masquerade); +- unregister_netdevice_notifier(&masq_dev_notifier); + unregister_inetaddr_notifier(&masq_inet_notifier); + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_MIRROR.c linux-2.4.20/net/ipv4/netfilter/ipt_MIRROR.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_MIRROR.c Fri Dec 21 17:42:05 2001 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_MIRROR.c Wed Sep 24 09:16:17 2003 +@@ -32,7 +32,6 @@ + #include + #include + #include +-struct in_device; + #include + + #if 0 +@@ -41,31 +40,47 @@ + #define DEBUGP(format, args...) + #endif + +-static int route_mirror(struct sk_buff *skb) ++static inline struct rtable *route_mirror(struct sk_buff *skb, int local) + { + struct iphdr *iph = skb->nh.iph; ++ struct dst_entry *odst; ++ struct rt_key key = {}; + struct rtable *rt; + +- /* Backwards */ +- if (ip_route_output(&rt, iph->saddr, iph->daddr, +- RT_TOS(iph->tos) | RTO_CONN, +- 0)) { +- return 0; ++ if (local) { ++ key.dst = iph->saddr; ++ key.src = iph->daddr; ++ key.tos = RT_TOS(iph->tos); ++ ++ if (ip_route_output_key(&rt, &key) != 0) ++ return NULL; ++ } else { ++ /* non-local src, find valid iif to satisfy ++ * rp-filter when calling ip_route_input. */ ++ key.dst = iph->daddr; ++ if (ip_route_output_key(&rt, &key) != 0) ++ return NULL; ++ ++ odst = skb->dst; ++ if (ip_route_input(skb, iph->saddr, iph->daddr, ++ RT_TOS(iph->tos), rt->u.dst.dev) != 0) { ++ dst_release(&rt->u.dst); ++ return NULL; ++ } ++ dst_release(&rt->u.dst); ++ rt = (struct rtable *)skb->dst; ++ skb->dst = odst; + } + +- /* check if the interface we are leaving by is the same as the +- one we arrived on */ +- if (skb->dev == rt->u.dst.dev) { +- /* Drop old route. */ +- dst_release(skb->dst); +- skb->dst = &rt->u.dst; +- return 1; ++ if (rt->u.dst.error) { ++ dst_release(&rt->u.dst); ++ rt = NULL; + } +- return 0; ++ ++ return rt; + } + +-static void +-ip_rewrite(struct sk_buff *skb) ++static inline void ip_rewrite(struct sk_buff *skb) + { + struct iphdr *iph = skb->nh.iph; + u32 odaddr = iph->saddr; +@@ -105,32 +120,48 @@ + const void *targinfo, + void *userinfo) + { +- if (((*pskb)->dst != NULL) && +- route_mirror(*pskb)) { +- +- ip_rewrite(*pskb); ++ struct rtable *rt; ++ struct sk_buff *nskb; ++ unsigned int hh_len; + +- /* If we are not at FORWARD hook (INPUT/PREROUTING), +- * the TTL isn't decreased by the IP stack */ +- if (hooknum != NF_IP_FORWARD) { +- struct iphdr *iph = (*pskb)->nh.iph; +- if (iph->ttl <= 1) { +- /* this will traverse normal stack, and +- * thus call conntrack on the icmp packet */ +- icmp_send(*pskb, ICMP_TIME_EXCEEDED, +- ICMP_EXC_TTL, 0); +- return NF_DROP; +- } +- ip_decrease_ttl(iph); ++ /* If we are not at FORWARD hook (INPUT/PREROUTING), ++ * the TTL isn't decreased by the IP stack */ ++ if (hooknum != NF_IP_FORWARD) { ++ struct iphdr *iph = (*pskb)->nh.iph; ++ if (iph->ttl <= 1) { ++ /* this will traverse normal stack, and ++ * thus call conntrack on the icmp packet */ ++ icmp_send(*pskb, ICMP_TIME_EXCEEDED, ++ ICMP_EXC_TTL, 0); ++ return NF_DROP; + } ++ ip_decrease_ttl(iph); ++ } + +- /* Don't let conntrack code see this packet: +- it will think we are starting a new +- connection! --RR */ +- ip_direct_send(*pskb); ++ if ((rt = route_mirror(*pskb, hooknum == NF_IP_LOCAL_IN)) == NULL) ++ return NF_DROP; + +- return NF_STOLEN; ++ hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15; ++ ++ /* 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). We also need to expand headroom in case ++ * hh_len of incoming interface < hh_len of outgoing interface */ ++ nskb = skb_copy_expand(*pskb, hh_len, skb_tailroom(*pskb), GFP_ATOMIC); ++ if (nskb == NULL) { ++ dst_release(&rt->u.dst); ++ return NF_DROP; + } ++ ++ dst_release(nskb->dst); ++ nskb->dst = &rt->u.dst; ++ ++ ip_rewrite(nskb); ++ /* Don't let conntrack code see this packet: ++ it will think we are starting a new ++ connection! --RR */ ++ ip_direct_send(nskb); ++ + return NF_DROP; + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_NETLINK.c linux-2.4.20/net/ipv4/netfilter/ipt_NETLINK.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_NETLINK.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_NETLINK.c Wed Sep 24 09:16:32 2003 +@@ -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_ATOMIC); ++ }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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_NETMAP.c linux-2.4.20/net/ipv4/netfilter/ipt_NETMAP.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_NETMAP.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_NETMAP.c Wed Sep 24 09:16:34 2003 +@@ -0,0 +1,109 @@ ++/* 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"); ++MODULE_AUTHOR("Svenning Soerensen "); ++MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target"); ++ ++#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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.4.20/net/ipv4/netfilter/ipt_NOTRACK.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_NOTRACK.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_NOTRACK.c Wed Sep 24 09:18:12 2003 +@@ -0,0 +1,83 @@ ++/* This is a module which is used for setting up fake conntracks ++ * on packets so that they are not seen by the conntrack/NAT code. ++ */ ++#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) ++{ ++ struct ip_conntrack_protocol *proto; ++ struct ip_conntrack_tuple tuple; ++ ++ if ((*pskb)->nfct != NULL) ++ return IPT_CONTINUE; ++ ++ proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); ++ ++ if (ip_conntrack_get_tuple((*pskb)->nh.iph, (*pskb)->len, ++ &tuple, proto) ++ && !ip_conntrack_tuple_taken(&tuple, NULL)) { ++ (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW]; ++ nf_conntrack_get((*pskb)->nfct); ++ } ++ ++ return IPT_CONTINUE; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (targinfosize != 0) { ++ printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n", ++ targinfosize); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "raw") != 0) { ++ printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_notrack_reg = { ++ .list = { NULL, NULL }, ++ .name = "NOTRACK", ++ .target = target, ++ .checkentry = checkentry, ++ .destroy = NULL, ++ .me = THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_notrack_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_notrack_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_POOL.c linux-2.4.20/net/ipv4/netfilter/ipt_POOL.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_POOL.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_POOL.c Wed Sep 24 09:16:59 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.20/net/ipv4/netfilter/ipt_REJECT.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_REJECT.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_REJECT.c Wed Sep 24 09:18:09 2003 +@@ -1,15 +1,18 @@ + /* + * This is a module which is used for rejecting packets. + * Added support for customized reject packets (Jozsef Kadlecsik). ++ * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812] ++ * Added support for fake source IP in icmp-unreach (Fabrice MARIE & Guillaume MORIN). + */ + #include + #include + #include + #include ++#include ++#include + #include + #include + #include +-struct in_device; + #include + #include + #include +@@ -32,8 +35,49 @@ + attach(new_skb, nfct); + } + ++static inline struct rtable *route_reverse(struct sk_buff *skb, int hook) ++{ ++ struct iphdr *iph = skb->nh.iph; ++ struct dst_entry *odst; ++ struct rt_key key = {}; ++ struct rtable *rt; ++ ++ if (hook != NF_IP_FORWARD) { ++ key.dst = iph->saddr; ++ if (hook == NF_IP_LOCAL_IN) ++ key.src = iph->daddr; ++ key.tos = RT_TOS(iph->tos); ++ ++ if (ip_route_output_key(&rt, &key) != 0) ++ return NULL; ++ } else { ++ /* non-local src, find valid iif to satisfy ++ * rp-filter when calling ip_route_input. */ ++ key.dst = iph->daddr; ++ if (ip_route_output_key(&rt, &key) != 0) ++ return NULL; ++ ++ odst = skb->dst; ++ if (ip_route_input(skb, iph->saddr, iph->daddr, ++ RT_TOS(iph->tos), rt->u.dst.dev) != 0) { ++ dst_release(&rt->u.dst); ++ return NULL; ++ } ++ dst_release(&rt->u.dst); ++ rt = (struct rtable *)skb->dst; ++ skb->dst = odst; ++ } ++ ++ if (rt->u.dst.error) { ++ dst_release(&rt->u.dst); ++ rt = NULL; ++ } ++ ++ return rt; ++} ++ + /* Send RST reply */ +-static void send_reset(struct sk_buff *oldskb, int local) ++static void send_reset(struct sk_buff *oldskb, int hook) + { + struct sk_buff *nskb; + struct tcphdr *otcph, *tcph; +@@ -42,6 +86,7 @@ + u_int16_t tmp_port; + u_int32_t tmp_addr; + int needs_ack; ++ int hh_len; + + /* IP header checks: fragment, too short. */ + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) +@@ -61,12 +106,25 @@ + csum_partial((char *)otcph, otcplen, 0)) != 0) + return; + ++ if ((rt = route_reverse(oldskb, hook)) == NULL) ++ return; ++ ++ hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; ++ ++ + /* 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) ++ interested in it). We also need to expand headroom in case ++ hh_len of incoming interface < hh_len of outgoing interface */ ++ nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), ++ GFP_ATOMIC); ++ if (!nskb) { ++ dst_release(&rt->u.dst); + return; ++ } ++ ++ dst_release(nskb->dst); ++ nskb->dst = &rt->u.dst; + + /* This packet will not be the same as the other: clear nf fields */ + nf_conntrack_put(nskb->nfct); +@@ -130,16 +188,6 @@ + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, + nskb->nh.iph->ihl); + +- /* Routing: if not headed for us, route won't like source */ +- if (ip_route_output(&rt, nskb->nh.iph->daddr, +- local ? nskb->nh.iph->saddr : 0, +- 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; +@@ -154,12 +202,13 @@ + kfree_skb(nskb); + } + +-static void send_unreach(struct sk_buff *skb_in, int code) ++static void send_unreach(struct sk_buff *skb_in, int code, u_int8_t fake_source_address) + { + struct iphdr *iph; ++ struct udphdr *udph; + struct icmphdr *icmph; + struct sk_buff *nskb; +- u32 saddr; ++ u32 saddr,packet_daddr; + u8 tos; + int hh_len, length; + struct rtable *rt = (struct rtable*)skb_in->dst; +@@ -186,6 +235,19 @@ + if (iph->frag_off&htons(IP_OFFSET)) + return; + ++ /* if UDP checksum is set, verify it's correct */ ++ if (iph->protocol == IPPROTO_UDP ++ && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) { ++ int datalen = skb_in->len - (iph->ihl<<2); ++ udph = (struct udphdr *)((char *)iph + (iph->ihl<<2)); ++ if (udph->check ++ && csum_tcpudp_magic(iph->saddr, iph->daddr, ++ datalen, IPPROTO_UDP, ++ csum_partial((char *)udph, datalen, ++ 0)) != 0) ++ return; ++ } ++ + /* If we send an ICMP error to an ICMP error a mess would result.. */ + if (iph->protocol == IPPROTO_ICMP + && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { +@@ -201,7 +263,7 @@ + return; + } + +- saddr = iph->daddr; ++ packet_daddr = saddr = iph->daddr; + if (!(rt->rt_flags & RTCF_LOCAL)) + saddr = 0; + +@@ -244,7 +306,16 @@ + iph->ttl = MAXTTL; + ip_select_ident(iph, &rt->u.dst, NULL); + iph->protocol=IPPROTO_ICMP; +- iph->saddr=rt->rt_src; ++ ++ /* fake source IP if we have to ++ if fake_source_address == 1, we fake the source IP ++ from the packet destination address dynamically. ++ */ ++ if (fake_source_address == 1) ++ iph->saddr = packet_daddr; ++ else ++ iph->saddr=rt->rt_src; ++ + iph->daddr=rt->rt_dst; + iph->check=0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); +@@ -291,25 +362,28 @@ + must return an absolute verdict. --RR */ + switch (reject->with) { + case IPT_ICMP_NET_UNREACHABLE: +- send_unreach(*pskb, ICMP_NET_UNREACH); ++ send_unreach(*pskb, ICMP_NET_UNREACH, reject->fake_source_address); + break; + case IPT_ICMP_HOST_UNREACHABLE: +- send_unreach(*pskb, ICMP_HOST_UNREACH); ++ send_unreach(*pskb, ICMP_HOST_UNREACH, reject->fake_source_address); + break; + case IPT_ICMP_PROT_UNREACHABLE: +- send_unreach(*pskb, ICMP_PROT_UNREACH); ++ send_unreach(*pskb, ICMP_PROT_UNREACH, reject->fake_source_address); + break; + case IPT_ICMP_PORT_UNREACHABLE: +- send_unreach(*pskb, ICMP_PORT_UNREACH); ++ send_unreach(*pskb, ICMP_PORT_UNREACH, reject->fake_source_address); + break; + case IPT_ICMP_NET_PROHIBITED: +- send_unreach(*pskb, ICMP_NET_ANO); ++ send_unreach(*pskb, ICMP_NET_ANO, reject->fake_source_address); + break; + case IPT_ICMP_HOST_PROHIBITED: +- send_unreach(*pskb, ICMP_HOST_ANO); ++ send_unreach(*pskb, ICMP_HOST_ANO, reject->fake_source_address); + break; ++ case IPT_ICMP_ADMIN_PROHIBITED: ++ send_unreach(*pskb, ICMP_PKT_FILTERED, reject->fake_source_address); ++ break; + case IPT_TCP_RESET: +- send_reset(*pskb, hooknum == NF_IP_LOCAL_IN); ++ send_reset(*pskb, hooknum); + case IPT_ICMP_ECHOREPLY: + /* Doesn't happen. */ + break; +@@ -353,6 +427,11 @@ + DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n"); + return 0; + } ++ /* cannot fake source address */ ++ if (rejinfo->fake_source_address != 0) { ++ DEBUGP("REJECT: fake-source-address illegal for TCP-RESET\n"); ++ return 0; ++ } + } + + return 1; +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_ROUTE.c linux-2.4.20/net/ipv4/netfilter/ipt_ROUTE.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_ROUTE.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_ROUTE.c Wed Sep 24 09:17:25 2003 +@@ -0,0 +1,369 @@ ++/* ++ * This implements the ROUTE target, which enables you to setup unusual ++ * routes not supported by the standard kernel routing table. ++ * ++ * Copyright (C) 2002 Cedric de Launois ++ * ++ * v 1.8 2003/07/25 ++ * ++ * This software is distributed under GNU GPL v2, 1991 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++ ++/* Try to route the packet according to the routing keys specified in ++ * route_info. Keys are : ++ * - ifindex : ++ * 0 if no oif preferred, ++ * otherwise set to the index of the desired oif ++ * - route_info->gw : ++ * 0 if no gateway specified, ++ * otherwise set to the next host to which the pkt must be routed ++ * If success, skb->dev is the output device to which the packet must ++ * be sent and skb->dst is not NULL ++ * ++ * RETURN: -1 if an error occured ++ * 1 if the packet was succesfully routed to the ++ * destination desired ++ * 0 if the kernel routing table could not route the packet ++ * according to the keys specified ++ */ ++static int route(struct sk_buff *skb, ++ unsigned int ifindex, ++ const struct ipt_route_target_info *route_info) ++{ ++ int err; ++ struct rtable *rt; ++ struct iphdr *iph = skb->nh.iph; ++ struct rt_key key = { ++ dst:iph->daddr, ++ src:0, ++ oif:ifindex, ++ tos:RT_TOS(iph->tos) ++ }; ++ ++ /* The destination address may be overloaded by the target */ ++ if (route_info->gw) ++ key.dst = route_info->gw; ++ ++ /* Trying to route the packet using the standard routing table. */ ++ if ((err = ip_route_output_key(&rt, &key))) { ++ if (net_ratelimit()) ++ DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err); ++ return -1; ++ } ++ ++ /* Drop old route. */ ++ dst_release(skb->dst); ++ skb->dst = NULL; ++ ++ /* Success if no oif specified or if the oif correspond to the ++ * one desired */ ++ if (!ifindex || rt->u.dst.dev->ifindex == ifindex) { ++ skb->dst = &rt->u.dst; ++ skb->dev = skb->dst->dev; ++ return 1; ++ } ++ ++ /* The interface selected by the routing table is not the one ++ * specified by the user. This may happen because the dst address ++ * is one of our own addresses. ++ */ ++ if (net_ratelimit()) ++ DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", ++ NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex); ++ ++ return 0; ++} ++ ++ ++/* Stolen from ip_finish_output2 ++ * PRE : skb->dev is set to the device we are leaving by ++ * skb->dst is not NULL ++ * POST: the packet is sent with the link layer header pushed ++ * the packet is destroyed ++ */ ++static void ip_direct_send(struct sk_buff *skb) ++{ ++ struct dst_entry *dst = skb->dst; ++ struct hh_cache *hh = dst->hh; ++ ++ if (hh) { ++ read_lock_bh(&hh->hh_lock); ++ memcpy(skb->data - 16, hh->hh_data, 16); ++ read_unlock_bh(&hh->hh_lock); ++ skb_push(skb, hh->hh_len); ++ hh->hh_output(skb); ++ } else if (dst->neighbour) ++ dst->neighbour->output(skb); ++ else { ++ if (net_ratelimit()) ++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n"); ++ kfree_skb(skb); ++ } ++} ++ ++ ++/* PRE : skb->dev is set to the device we are leaving by ++ * POST: - the packet is directly sent to the skb->dev device, without ++ * pushing the link layer header. ++ * - the packet is destroyed ++ */ ++static inline int dev_direct_send(struct sk_buff *skb) ++{ ++ return dev_queue_xmit(skb); ++} ++ ++ ++static unsigned int route_oif(const struct ipt_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ unsigned int ifindex = 0; ++ struct net_device *dev_out = NULL; ++ ++ /* The user set the interface name to use. ++ * Getting the current interface index. ++ */ ++ if ((dev_out = dev_get_by_name(route_info->oif))) { ++ ifindex = dev_out->ifindex; ++ } else { ++ /* Unknown interface name : packet dropped */ ++ if (net_ratelimit()) ++ DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif); ++ return NF_DROP; ++ } ++ ++ /* Trying the standard way of routing packets */ ++ switch (route(skb, ifindex, route_info)) { ++ case 1: ++ dev_put(dev_out); ++ if (route_info->flags & IPT_ROUTE_CONTINUE) ++ return IPT_CONTINUE; ++ ++ ip_direct_send(skb); ++ return NF_STOLEN; ++ ++ case 0: ++ /* Failed to send to oif. Trying the hard way */ ++ if (route_info->flags & IPT_ROUTE_CONTINUE) ++ return NF_DROP; ++ ++ if (net_ratelimit()) ++ DEBUGP("ipt_ROUTE: forcing the use of %i\n", ++ ifindex); ++ ++ /* We have to force the use of an interface. ++ * This interface must be a tunnel interface since ++ * otherwise we can't guess the hw address for ++ * the packet. For a tunnel interface, no hw address ++ * is needed. ++ */ ++ if ((dev_out->type != ARPHRD_TUNNEL) ++ && (dev_out->type != ARPHRD_IPGRE)) { ++ if (net_ratelimit()) ++ DEBUGP("ipt_ROUTE: can't guess the hw addr !\n"); ++ dev_put(dev_out); ++ return NF_DROP; ++ } ++ ++ /* Send the packet. This will also free skb ++ * Do not go through the POST_ROUTING hook because ++ * skb->dst is not set and because it will probably ++ * get confused by the destination IP address. ++ */ ++ skb->dev = dev_out; ++ dev_direct_send(skb); ++ dev_put(dev_out); ++ return NF_STOLEN; ++ ++ default: ++ /* Unexpected error */ ++ dev_put(dev_out); ++ return NF_DROP; ++ } ++} ++ ++ ++static unsigned int route_iif(const struct ipt_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ struct net_device *dev_out = NULL; ++ unsigned int ifindex = 0; ++ ++ /* Getting the current interface index. */ ++ if ((dev_out = dev_get_by_name(route_info->iif))) ++ ifindex = dev_out->ifindex; ++ else { ++ /* Unknown interface name : packet dropped */ ++ if (net_ratelimit()) ++ DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->oif); ++ return NF_DROP; ++ } ++ ++ skb->dev = dev_out; ++ dst_release(skb->dst); ++ skb->dst = NULL; ++ ++ netif_rx(skb); ++ ++ return NF_STOLEN; ++} ++ ++ ++static unsigned int route_gw(const struct ipt_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ if (route(skb, 0, route_info)!=1) ++ return NF_DROP; ++ ++ if (route_info->flags & IPT_ROUTE_CONTINUE) ++ return IPT_CONTINUE; ++ ++ ip_direct_send(skb); ++ return NF_STOLEN; ++} ++ ++ ++static unsigned int ipt_route_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_route_target_info *route_info = targinfo; ++ struct sk_buff *skb = *pskb; ++ ++ /* If we are at PREROUTING or INPUT hook ++ * the TTL isn't decreased by the IP stack ++ */ ++ if (hooknum == NF_IP_PRE_ROUTING || ++ hooknum == NF_IP_LOCAL_IN) { ++ ++ struct iphdr *iph = skb->nh.iph; ++ ++ if (iph->ttl <= 1) { ++ struct rtable *rt; ++ ++ if (ip_route_output(&rt, iph->saddr, iph->daddr, ++ RT_TOS(iph->tos) | RTO_CONN, ++ 0)) { ++ return NF_DROP; ++ } ++ ++ if (skb->dev == rt->u.dst.dev) { ++ /* Drop old route. */ ++ dst_release(skb->dst); ++ skb->dst = &rt->u.dst; ++ ++ /* this will traverse normal stack, and ++ * thus call conntrack on the icmp packet */ ++ icmp_send(skb, ICMP_TIME_EXCEEDED, ++ ICMP_EXC_TTL, 0); ++ } ++ ++ return NF_DROP; ++ } ++ ++ ip_decrease_ttl(iph); ++ } ++ ++ /* Tell conntrack to forget this packet since it may get confused ++ * when a packet is leaving with dst address == our address. ++ * Good idea ? Dunno. Need advice. ++ */ ++ if (!(route_info->flags & IPT_ROUTE_CONTINUE)) { ++ nf_conntrack_put(skb->nfct); ++ skb->nfct = NULL; ++ skb->nfcache = 0; ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug = 0; ++#endif ++ } ++ ++ if (route_info->oif[0]) ++ return route_oif(route_info, *pskb); ++ ++ if (route_info->iif[0]) ++ return route_iif(route_info, *pskb); ++ ++ if (route_info->gw) ++ return route_gw(route_info, *pskb); ++ ++ if (net_ratelimit()) ++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n"); ++ ++ return IPT_CONTINUE; ++} ++ ++ ++static int ipt_route_checkentry(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n", ++ tablename); ++ return 0; ++ } ++ ++ if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING) ++ | (1 << NF_IP_LOCAL_IN) ++ | (1 << NF_IP_FORWARD) ++ | (1 << NF_IP_LOCAL_OUT) ++ | (1 << NF_IP_POST_ROUTING))) { ++ printk("ipt_ROUTE: bad hook\n"); ++ return 0; ++ } ++ ++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) { ++ printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n", ++ targinfosize, ++ IPT_ALIGN(sizeof(struct ipt_route_target_info))); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static struct ipt_target ipt_route_reg ++= { { NULL, NULL }, "ROUTE", ipt_route_target, ipt_route_checkentry, NULL, ++ THIS_MODULE }; ++ ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_route_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_route_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_SAME.c linux-2.4.20/net/ipv4/netfilter/ipt_SAME.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_SAME.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_SAME.c Wed Sep 24 09:16:38 2003 +@@ -0,0 +1,202 @@ ++/* 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"); ++MODULE_AUTHOR("Martin Josefsson "); ++MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip"); ++ ++#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_PRE_ROUTING | 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_PRE_ROUTING || ++ 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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_TARPIT.c linux-2.4.20/net/ipv4/netfilter/ipt_TARPIT.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_TARPIT.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_TARPIT.c Wed Sep 24 09:17:45 2003 +@@ -0,0 +1,284 @@ ++/* ++ * Kernel module to capture and hold incoming TCP connections using ++ * no local per-connection resources. ++ * ++ * Based on ipt_REJECT.c and offering functionality similar to ++ * LaBrea . ++ * ++ * Copyright (c) 2002 Aaron Hopkins ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Goal: ++ * - Allow incoming TCP connections to be established. ++ * - Passing data should result in the connection being switched to the ++ * persist state (0 byte window), in which the remote side stops sending ++ * data and asks to continue every 60 seconds. ++ * - Attempts to shut down the connection should be ignored completely, so ++ * the remote side ends up having to time it out. ++ * ++ * This means: ++ * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes ++ * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing ++ * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++struct in_device; ++#include ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++ ++/* Stolen from ip_finish_output2 */ ++static int ip_direct_send(struct sk_buff *skb) ++{ ++ struct dst_entry *dst = skb->dst; ++ struct hh_cache *hh = dst->hh; ++ ++ if (hh) { ++ read_lock_bh(&hh->hh_lock); ++ memcpy(skb->data - 16, hh->hh_data, 16); ++ read_unlock_bh(&hh->hh_lock); ++ skb_push(skb, hh->hh_len); ++ return hh->hh_output(skb); ++ } else if (dst->neighbour) ++ return dst->neighbour->output(skb); ++ ++ if (net_ratelimit()) ++ printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n"); ++ kfree_skb(skb); ++ return -EINVAL; ++} ++ ++ ++/* Send reply */ ++static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local) ++{ ++ struct sk_buff *nskb; ++ struct rtable *nrt; ++ struct tcphdr *otcph, *ntcph; ++ unsigned int otcplen; ++ u_int16_t tmp; ++ ++ /* A truncated TCP header isn't going to be useful */ ++ if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr)) ++ return; ++ ++ otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph ++ + oskb->nh.iph->ihl); ++ otcplen = oskb->len - oskb->nh.iph->ihl*4; ++ ++ /* No replies for RST or FIN */ ++ if (otcph->rst || otcph->fin) ++ return; ++ ++ /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */ ++ if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ))) ++ return; ++ ++ /* Check checksum. */ ++ if (tcp_v4_check(otcph, otcplen, oskb->nh.iph->saddr, ++ oskb->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(oskb, 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 ++ ++ ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); ++ ++ /* Truncate to length (no data) */ ++ ntcph->doff = sizeof(struct tcphdr)/4; ++ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); ++ nskb->nh.iph->tot_len = htons(nskb->len); ++ ++ /* Swap source and dest */ ++ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); ++ tmp = ntcph->source; ++ ntcph->source = ntcph->dest; ++ ntcph->dest = tmp; ++ ++ /* Use supplied sequence number or make a new one */ ++ ntcph->seq = otcph->ack ? otcph->ack_seq ++ : htonl(secure_tcp_sequence_number(nskb->nh.iph->saddr, ++ nskb->nh.iph->daddr, ++ ntcph->source, ++ ntcph->dest)); ++ ++ /* Our SYN-ACKs must have a >0 window */ ++ ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0; ++ ++ ntcph->urg_ptr = 0; ++ ++ /* Reset flags */ ++ ((u_int8_t *)ntcph)[13] = 0; ++ ++ if (otcph->syn && otcph->ack) { ++ ntcph->rst = 1; ++ ntcph->ack_seq = 0; ++ } else { ++ ntcph->syn = otcph->syn; ++ ntcph->ack = 1; ++ ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn); ++ } ++ ++ /* Adjust TCP checksum */ ++ ntcph->check = 0; ++ ntcph->check = tcp_v4_check(ntcph, sizeof(struct tcphdr), ++ nskb->nh.iph->saddr, ++ nskb->nh.iph->daddr, ++ csum_partial((char *)ntcph, ++ sizeof(struct tcphdr), 0)); ++ ++ /* Adjust IP TTL */ ++ nskb->nh.iph->ttl = sysctl_ip_default_ttl; ++ ++ /* 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); ++ ++ if (ip_route_output(&nrt, nskb->nh.iph->daddr, ++ local ? nskb->nh.iph->saddr : 0, ++ RT_TOS(nskb->nh.iph->tos) | RTO_CONN, ++ 0) != 0) ++ goto free_nskb; ++ ++ dst_release(nskb->dst); ++ nskb->dst = &nrt->u.dst; ++ ++ /* "Never happens" */ ++ if (nskb->len > nskb->dst->pmtu) ++ goto free_nskb; ++ ++ ip_direct_send (nskb); ++ ++ return; ++ ++ free_nskb: ++ kfree_skb(nskb); ++} ++ ++ ++static unsigned int tarpit(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *targinfo, ++ void *userinfo) ++{ ++ struct sk_buff *skb = *pskb; ++ struct rtable *rt = (struct rtable*)skb->dst; ++ ++ /* Do we have an input route cache entry? */ ++ if (!rt) ++ return NF_DROP; ++ ++ /* No replies to physical multicast/broadcast */ ++ if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST) ++ return NF_DROP; ++ ++ /* Now check at the protocol level */ ++ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) ++ return NF_DROP; ++ ++ /* Our naive response construction doesn't deal with IP ++ options, and probably shouldn't try. */ ++ if (skb->nh.iph->ihl*4 != sizeof(struct iphdr)) ++ return NF_DROP; ++ ++ /* We aren't interested in fragments */ ++ if (skb->nh.iph->frag_off & htons(IP_OFFSET)) ++ return NF_DROP; ++ ++ tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN); ++ ++ return NF_DROP; ++} ++ ++ ++static int check(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ /* Only allow these for input/forward packet filtering. */ ++ if (strcmp(tablename, "filter") != 0) { ++ DEBUGP("TARPIT: bad table %s'.\n", tablename); ++ return 0; ++ } ++ if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) ++ | (1 << NF_IP_FORWARD))) != 0) { ++ DEBUGP("TARPIT: bad hook mask %X\n", hook_mask); ++ return 0; ++ } ++ ++ /* Must specify that it's a TCP packet */ ++ if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) { ++ DEBUGP("TARPIT: not valid for non-tcp\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_tarpit_reg ++= { { NULL, NULL }, "TARPIT", tarpit, check, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_tarpit_reg)) ++ return -EINVAL; ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_tarpit_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_TCPLAG.c linux-2.4.20/net/ipv4/netfilter/ipt_TCPLAG.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_TCPLAG.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_TCPLAG.c Wed Sep 24 09:17:29 2003 +@@ -0,0 +1,697 @@ ++/* ipt_TCPLAG.c -- kernel module to implement TCPLAG target into netfilter ++ * Copyright (C) 2002 Telford Tendys ++ * ++ * 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 ++ */ ++ ++/* ++ * This collects packets and attempts to make them into pairs ++ * based on its own knowledge of how typical network conversations ++ * operate. Once it has a pair, it logs the time between them. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* ++ * We need one spinlock for the hash table. ++ */ ++static spinlock_t hash_lock = SPIN_LOCK_UNLOCKED; ++ ++typedef struct timeval timeval_T; ++ ++/* ++ * Linked lists of events in the connection, ++ * these store the SEQ numbers and the newest is always ++ * at the start of the linked list, then they get older ++ * down to the end of the linked list (this is not perfect ++ * if packets get out of order but we don't worry about fine ++ * details like that). ++ * ++ * Matching any event wipes out that event and also all other ++ * events down the chain (i.e. all older events). ++ * This keeps the linked list as short as possible. ++ */ ++typedef struct tcplag_event_S ++{ ++ struct tcplag_event_S *next; ++ u16 source_port; ++ u16 dest_port; ++ u32 expected_ACK; ++ struct timeval stamp; ++} tcplag_event_T; ++ ++/* ++ * This stores the connection statistics ++ * We define connections more loosely than TCP/IP does, ++ * because we only consider the two hosts, not the ports ++ * Also, we list the host-pairs in low,high order which ++ * means that we don't care who originated the connection. ++ */ ++typedef struct tcplag_hash_S ++{ ++ u32 low_ip; ++ u32 high_ip; ++ struct timeval lag_l_SEQ_h_ACK; /* l sends some data and h acknowledges that (sum of lag times) */ ++ struct timeval lag_h_SEQ_l_ACK; /* h sends some data and l acknowledges that (sum of lag times) */ ++ tcplag_event_T *h_ACK_list; /* Try to match ACK packets coming from h in this list */ ++ tcplag_event_T *l_ACK_list; /* Try to match ACK packets coming from l in this list */ ++ time_t stamp; /* When this bucket got added to the table */ ++ u16 count_l_SEQ_h_ACK; /* Increment for each event */ ++ u16 count_h_SEQ_l_ACK; /* Increment for each event */ ++} tcplag_hash_T; ++ ++static tcplag_hash_T **hashtab = 0; ++static u32 hashsize = 0; ++static u16 max_seconds = 30; /* Empty a hash bucket after this time */ ++static u32 reaper_ix = 0; ++ ++static void divide_down( timeval_T *T, int c ) ++{ ++ int remainder; ++ ++ T->tv_usec /= c; ++ remainder = T->tv_sec % c; /* Only works properly with positive numbers */ ++ remainder *= 1000000; ++ T->tv_usec == remainder; ++ T->tv_sec /= c; ++} ++ ++int diff_timeval( timeval_T *tv1, timeval_T *tv2 ) ++{ ++ register long x; ++ ++ x = tv1->tv_sec - tv2->tv_sec; ++ if( x ) return( x ); ++ x = tv1->tv_usec - tv2->tv_usec; ++ return( x ); ++} ++ ++void sprint_timeval( char *buf, timeval_T *tv ) ++{ ++ if( tv->tv_sec ) ++ sprintf( buf, "%lu%06lu", tv->tv_sec, tv->tv_usec ); ++ else ++ sprintf( buf, "%lu", tv->tv_usec ); ++} ++ ++/* ++ * This generates the log messages through printk() ++ * ++ * There is really no particular interest in the port numbers at this stage, ++ * they are only useful for matching up the request with the reply. ++ * The IP numbers are useful because some sites may be slower than others ++ * or may travel different routes, etc (OK, in theory changing the port number ++ * could also change the route but I don't like that sort of theory). ++ * ++ * The tags are: ++ * ++ * LIP= The IP number of the side with the lowest lag ++ * RIP= The IP number of the side with the highest lag ++ * LLAG= The average time (in us) between RIP->LIP SEQ and LIP->RIP ACK ++ * RLAG= The average time (in us) between LIP->RIP SEQ and RIP->LIP ACK ++ */ ++static void output( tcplag_hash_T *H, int level, const char *prefix ) ++{ ++ struct timeval ltm, rtm; ++ u32 local_ip, remote_ip; ++ char r_buf[ 20 ], l_buf[ 20 ]; ++/* ++ * We can't make sense of a connection that only passes data one way, ++ * In principle, at least the SYN and FIN should go both ways so we ++ * should get a few hits for every connection. ++ */ ++ if( 0 == H->count_l_SEQ_h_ACK || 0 == H->count_h_SEQ_l_ACK ) return; ++/* ++ * Calculate average times by dividing down ++ */ ++ divide_down( &H->lag_l_SEQ_h_ACK, H->count_l_SEQ_h_ACK ); ++ divide_down( &H->lag_h_SEQ_l_ACK, H->count_h_SEQ_l_ACK ); ++/* ++ * Sort these two by the lag so the the local is always the short lag ++ */ ++ if( diff_timeval( &H->lag_l_SEQ_h_ACK, &H->lag_h_SEQ_l_ACK ) > 0 ) ++ { ++ local_ip = H->low_ip; ++ remote_ip = H->high_ip; ++ rtm.tv_sec = H->lag_l_SEQ_h_ACK.tv_sec; ++ rtm.tv_usec = H->lag_l_SEQ_h_ACK.tv_usec; ++ ltm.tv_sec = H->lag_h_SEQ_l_ACK.tv_sec; ++ ltm.tv_usec = H->lag_h_SEQ_l_ACK.tv_usec; ++ } ++ else ++ { ++ local_ip = H->high_ip; ++ remote_ip = H->low_ip; ++ ltm.tv_sec = H->lag_l_SEQ_h_ACK.tv_sec; ++ ltm.tv_usec = H->lag_l_SEQ_h_ACK.tv_usec; ++ rtm.tv_sec = H->lag_h_SEQ_l_ACK.tv_sec; ++ rtm.tv_usec = H->lag_h_SEQ_l_ACK.tv_usec; ++ } ++/* ++ * Don't use a spinlock on the output, ++ * it is not guaranteed safe because some OTHER printk could ++ * split our log message so we want only one single printk. ++ * ++ * We use sprintf() to partially pre-digest the output ++ * ++ * Actually, neither this not the main netfilter LOG target is ++ * really safe from printk() overlap, basically syslog cannot ++ * be regarded as a guaranteed data output channel. It is good ++ * enough for most purposes. ++ */ ++ sprint_timeval( l_buf, <m ); ++ sprint_timeval( r_buf, &rtm ); ++ printk( "<%d>%sLIP=%u.%u.%u.%u RIP=%u.%u.%u.%u LLAG=%s RLAG=%s\n", ++ level & 7, prefix, ++ NIPQUAD( local_ip ), NIPQUAD( remote_ip ), ++ l_buf, r_buf ); ++} ++ ++/* ++ * The reaper rolls through the hash table looking for old. ++ * Log entries are only generated at the reaping time ++ * (which means all log entries are out-of-date) ++ */ ++static void reaper( time_t now, int level, const char *prefix ) ++{ ++ int i; ++ ++ now -= max_seconds; ++ if( !hashsize ) return; ++ if( !hashtab ) return; ++ for( i = 0; i < 10; i++ ) ++ { ++ if( ++reaper_ix >= hashsize ) reaper_ix = 0; ++ ++// DEBUGP( KERN_WARNING "reaper checking %u\n", reaper_ix ); ++ ++ if( hashtab[ reaper_ix ]) ++ { ++ tcplag_hash_T *found = 0; ++ ++ spin_lock_bh( &hash_lock ); ++ if( hashtab[ reaper_ix ]) ++ { ++ if( now > hashtab[ reaper_ix ]->stamp ) ++ { ++ DEBUGP( KERN_WARNING "reaper found expired entry\n" ); ++ found = hashtab[ reaper_ix ]; ++ hashtab[ reaper_ix ] = 0; ++ } ++ } ++ spin_unlock_bh( &hash_lock ); ++ ++ if( found ) ++ { ++ output( found, level, prefix ); ++ kfree( found ); ++ } ++ } ++ } ++} ++ ++/* ++ * Convert the connection characteristics into a number ++ * (not including the timestamp) FIXME: this is a sucky hash function ++ */ ++static u32 make_hash( tcplag_hash_T *connection ) ++{ ++ register u32 r; ++ ++ r = connection->low_ip; ++ r += connection->high_ip; ++ return( r ); ++} ++ ++static int compare_connections( tcplag_hash_T *con1, tcplag_hash_T *con2 ) ++{ ++ int x; ++ ++ x = con1->low_ip - con2->low_ip; if( x ) return( x ); ++ x = con1->high_ip - con2->high_ip; ++ return( x ); ++} ++ ++static int compare_events( tcplag_event_T *ev1, tcplag_event_T *ev2 ) ++{ ++ int x; ++ ++ DEBUGP( "Comparing sequence %u to %u\n", ev1->expected_ACK, ev2->expected_ACK ); ++ x = ev1->expected_ACK - ev2->expected_ACK; ++ if( x ) return( x ); ++ DEBUGP( "Comparing source port %u to %u\n", ev1->source_port, ev2->source_port ); ++ x = ev1->source_port - ev2->source_port; ++ if( x ) return( x ); ++ DEBUGP( "Comparing destination port %u to %u\n", ev1->dest_port, ev2->dest_port ); ++ x = ev1->dest_port - ev2->dest_port; ++ return( x ); ++} ++ ++/* ++ * Go to the hash table and either find an existing connection that ++ * matches correctly or inject a new connection into the table. ++ * Once the connection is OK, chain the event onto the linked list. ++ */ ++static void hash_insert( tcplag_hash_T *connection, tcplag_event_T *event, int direction ) ++{ ++ u32 h, i; ++ ++ if( !event ) return; /* Just to be safe */ ++ if( !hashsize ) return; ++ if( !hashtab ) return; ++ ++ h = make_hash( connection ); ++ h %= hashsize; ++ ++ DEBUGP( KERN_WARNING "hash_insert( %u )\n", h ); ++ ++ spin_lock_bh( &hash_lock ); ++ for( i = 0; i < hashsize; i++, ({ if( ++h >= hashsize ) { h = 0; }})) ++ { ++ tcplag_hash_T *co_new = 0; ++/* ++ * Consider existing entry ++ */ ++ if( hashtab[ h ]) ++ { ++ if( compare_connections( hashtab[ h ], connection )) continue; ++ co_new = hashtab[ h ]; ++ DEBUGP( KERN_WARNING "Existing connection at %u\n", h ); ++ goto add_link; ++ } ++/* ++ * Use empty slot for new entry ++ */ ++ if( !hashtab[ h ]) ++ { ++ co_new = kmalloc( sizeof( tcplag_hash_T ), GFP_ATOMIC ); ++ memset( co_new, 0, sizeof( tcplag_hash_T )); ++ co_new->low_ip = connection->low_ip; ++ co_new->high_ip = connection->high_ip; ++ co_new->stamp = event->stamp.tv_sec; ++ hashtab[ h ] = co_new; ++ DEBUGP( KERN_WARNING "Added connection to table at %u\n", h ); ++ add_link: ++ { ++ tcplag_event_T *ev_new; ++ ++ ev_new = kmalloc( sizeof( tcplag_event_T ), GFP_ATOMIC ); ++ memcpy( ev_new, event, sizeof( tcplag_event_T )); ++ if( direction ) ++ { ++ ev_new->next = co_new->h_ACK_list; ++ co_new->h_ACK_list = ev_new; ++ DEBUGP( KERN_WARNING "Connection at %u, direction is h_ACK_list\n", h ); ++ } ++ else ++ { ++ ev_new->next = co_new->l_ACK_list; ++ co_new->l_ACK_list = ev_new; ++ DEBUGP( KERN_WARNING "Connection at %u, direction is l_ACK_list\n", h ); ++ } ++ } ++ goto done; ++ } ++ } ++ done: ++ spin_unlock_bh( &hash_lock ); ++} ++ ++/* ++ * Search the hash table for a matching connection, ++ * if we can't find one of those then we are stuffed. ++ * ++ * Once a connection has been found, scan along the list for ++ * a matching SEQ number and if that is found then calculate ++ * the lag, update the counters and cut the chain at the ++ * point where the matching SEQ is found. ++ */ ++static int request_complete( tcplag_hash_T *connection, tcplag_event_T *event, int direction ) ++{ ++ u32 h, i; ++ ++ if( !event ) return( 0 ); ++ if( !hashsize ) return( 0 ); ++ if( !hashtab ) return( 0 ); ++ h = make_hash( connection ); ++ h %= hashsize; ++ ++ DEBUGP( KERN_WARNING "request_complete( %u )\n", h ); ++ ++ for( i = 0; i < hashsize; i++ ) ++ { ++ tcplag_hash_T *found = 0; ++ ++ if( !hashtab[ h ]) return( 0 ); ++ ++ spin_lock_bh( &hash_lock ); ++ if( hashtab[ h ]) ++ { ++ if( !compare_connections( hashtab[ h ], connection )) ++ { ++ tcplag_event_T *ev, **evroot; ++ timeval_T *tv; ++ u16 *cn; ++ ++ found = hashtab[ h ]; ++ if( direction ) ++ { ++ evroot = &found->h_ACK_list; ++ tv = &found->lag_l_SEQ_h_ACK; ++ cn = &found->count_l_SEQ_h_ACK; ++ DEBUGP( KERN_WARNING "Connection at %u, direction is h_ACK_list\n", h ); ++ } ++ else ++ { ++ evroot = &found->l_ACK_list; ++ tv = &found->lag_h_SEQ_l_ACK; ++ cn = &found->count_h_SEQ_l_ACK; ++ DEBUGP( KERN_WARNING "Connection at %u, direction is l_ACK_list\n", h ); ++ } ++ for( ev = *evroot; ev; ev = ev->next ) ++ { ++ if( !compare_events( ev, event )) ++ { ++/* ++ * Calculate the lag (in two parts) and add that to the collection ++ */ ++ event->stamp.tv_sec -= ev->stamp.tv_sec; ++ event->stamp.tv_usec -= ev->stamp.tv_usec; ++ if( event->stamp.tv_usec < 0 ) ++ { ++ event->stamp.tv_usec += 1000000; ++ event->stamp.tv_sec++; ++ } ++ if( event->stamp.tv_sec < 0 ) ++ { ++ DEBUGP( KERN_WARNING "Negative lag detected\n" ); ++ } ++ else ++ { ++ tv->tv_sec += event->stamp.tv_sec; ++ tv->tv_usec += event->stamp.tv_usec; ++ ++*cn; ++ DEBUGP( KERN_WARNING "Found a match, added %lu.%06lu" ++ " (accumulator is up to %lu.%06lu, %u events)\n", ++ event->stamp.tv_sec, ++ event->stamp.tv_usec, ++ tv->tv_sec, tv->tv_usec, *cn ); ++ } ++/* ++ * Truncate the linked list. ++ * ++ * Visit each event in the list and return the memory to the pool. ++ * ++ * If a host is making multiple connections to the same remote host ++ * then this truncation will result in some requests not being ++ * monitored. Statistically we will still get some reasonable number ++ * of measurements and multiple simultaneous connections between host ++ * pairs don't happen all that often. ++ */ ++ *evroot = 0; ++ while( ev ) ++ { ++ tcplag_event_T *ev_next = ev->next; ++ DEBUGP( KERN_WARNING "Shitcan %u\n", ev->expected_ACK ); ++ kfree( ev ); ++ ev = ev_next; ++ } ++/* ++ * TODO: overflow limit for *cn, force premature output() if necessary ++ * (and drop this connection from the hash table) ++ */ ++ break; ++ } ++ } ++ goto done; ++ } ++ } ++ done: ++ spin_unlock_bh( &hash_lock ); ++ ++ if( found ) return( 1 ); ++ if( ++h >= hashsize ) h = 0; ++ } ++ return( 0 ); ++} ++ ++/* ++ * Here is our target data: ++ * ++ * pskb -- The packet itself (see linux/skbuff.h for breakdown) ++ * ++ * hooknum -- ++ * ++ * in -- The device that this packet came in on ++ * (depending on the chain this may or may not exist) ++ * ++ * out -- The device that this packet is just about to go ++ * out onto (again existance depends on the chain) ++ * ++ * targinfo -- Our private data (handed through from iptables command util) ++ * ++ * userinfo -- Some more data ++ * ++ */ ++ ++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_tcplag *el = targinfo; ++ tcplag_hash_T connection; ++ tcplag_event_T event; ++ int direction; ++/* ++ * We know we are dealing with IP here ++ * Fill in all the obvious fields ++ */ ++ if( iph->saddr > iph->daddr ) ++ { ++ direction = 0; ++ connection.high_ip = iph->saddr; ++ connection.low_ip = iph->daddr; ++ } ++ else ++ { ++ direction = 1; ++ connection.low_ip = iph->saddr; ++ connection.high_ip = iph->daddr; ++ } ++ do_gettimeofday( &event.stamp ); ++/* ++ * Do a bit of cleaning ++ */ ++ reaper( event.stamp.tv_sec, el->level, el->prefix ); ++ ++ DEBUGP( KERN_WARNING "got packet %lu %lu %s %s\n", ++ event.stamp.tv_sec, ++ event.stamp.tv_usec, ++ in ? in->name : "none", out ? out->name : "none" ); ++/* ++ * Now start looking at the details ++ * ++ * First step is to identify this packet to see if it is ++ * the sort of packet that we are interested in. ++ * Don't hold any locks while we are doing this because often ++ * we will just let the packet go without any further consideration. ++ */ ++ switch( iph->protocol ) ++ { ++ case IPPROTO_TCP: ++ { ++ struct tcphdr *tcp; ++ ++ if( ntohs( iph->frag_off ) & IP_OFFSET ) ++ { ++ DEBUGP( KERN_WARNING "ignoring fragment\n" ); ++ break; ++ } ++ tcp = (struct tcphdr *)((u32 *)iph + iph->ihl ); ++ event.source_port = ntohs( tcp->source ); ++ event.dest_port = ntohs( tcp->dest ); ++/* ++ * Every packet should have a valid SEQ number so use this to ++ * generate an ACK number. This works along the formula: ++ * -- Start with the SEQ number ++ * -- For SYN or FIN add 1 to that number ++ * -- For data packet, add the data length to that number ++ */ ++ ++/* ++ * Data length requires a bit of fiddling around ++ */ ++ { ++ unsigned int data_len; ++ if( tcp->syn || tcp->fin ) ++ { ++ data_len = 1; /* Not real data, the SEQ clicks forward by 1 */ ++ } ++ else ++ { ++ data_len = ntohs( iph->tot_len ); ++ data_len -= 4 * iph->ihl; /* Subtract away IP header & options */ ++ data_len -= 4 * tcp->doff; /* Subtract away TCP header & options */ ++ } ++ ++ DEBUGP( KERN_WARNING "Data length calculated at %u\n", data_len ); ++ ++ if( data_len ) /* Only track events that demand an ACK */ ++ { ++ event.expected_ACK = ntohl( tcp->seq ) + data_len; ++ hash_insert( &connection, &event, direction ); ++ } ++ else ++ { ++ DEBUGP( "Don't bother to insert this, ACK not required\n" ); ++ } ++ } ++ ++ if( tcp->ack ) ++ { ++/* ++ * Now we consider the matching of an existing event. ++ * Reverse the port numbers and change the ACK number to the actual ACK number ++ * Note that the direction is reversed because the reply will be going ++ * the opposite way to the request. ++ */ ++ event.expected_ACK = ntohl( tcp->ack_seq ); ++ event.dest_port = ntohs( tcp->source ); ++ event.source_port = ntohs( tcp->dest ); ++ request_complete( &connection, &event, !direction ); ++ } ++ else ++ { ++ DEBUGP( "Don't bother to check this, ACK not valid\n" ); ++ } ++ } ++ } ++ return( IPT_CONTINUE ); ++} ++ ++/* ++ * return( 0 ) if there is a problem with this entry (i.e. kick it out of the kernel) ++ * return( 1 ) if the entry is suitable ++ * ++ * tablename -- ++ * ++ * e -- ++ * ++ * targinfo -- Our private data block (handed to us from iptables plug-in) ++ * ++ * targinfosize -- The size of our private data block ++ * ++ * hook_mask -- ++ * ++ * ++ * Not much can go wrong for us, any illegal flags are harmlessly ignored, ++ * all possible flag combos make sense. All we check for is correct data size. ++ */ ++static int checkentry( const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask ) ++{ ++ const struct ipt_tcplag *el = targinfo; ++ ++ if( targinfosize != IPT_ALIGN( sizeof( struct ipt_tcplag ))) ++ { ++ DEBUGP( "TCPLAG: targinfosize %u != %u\n", targinfosize, ++ IPT_ALIGN( sizeof( struct ipt_tcplag ))); ++ return( 0 ); ++ } ++ if( el->prefix[ 14 ]) return( 0 ); /* Be sure to have terminated string */ ++ return( 1 ); ++} ++ ++static struct ipt_target reg = ++{ ++ { 0, 0 }, ++ "TCPLAG", ++ &target, ++ &checkentry, ++ 0, ++ THIS_MODULE ++}; ++ ++static int __init init( void ) ++{ ++ if( ipt_register_target( ® )) return( -EINVAL ); ++ hashsize = 123; /* should be configurable */ ++ hashtab = kmalloc( sizeof( void * ) * hashsize, GFP_ATOMIC ); ++ memset( hashtab, 0, sizeof( void * ) * hashsize ); ++ return( 0 ); ++} ++ ++/* ++ * This should not need locks (in theory) ++ * because it can only get punted after it is no longer ++ * chained into any of the netfilter lists. ++ */ ++static void __exit fini( void ) ++{ ++ int i; ++ ++ ipt_unregister_target( ® ); ++/* ++ * Put back kernel memory ++ */ ++ for( i = 0; i < hashsize; i++ ) ++ { ++ tcplag_hash_T *p; ++ ++ if(( p = hashtab[ i ])) ++ { ++ tcplag_event_T *ev, *evn; ++ ++ hashtab[ i ] = 0; ++ for( ev = p->h_ACK_list; ev; ev = evn ) ++ { ++ evn = ev->next; ++ kfree( ev ); ++ } ++ for( ev = p->l_ACK_list; ev; ev = evn ) ++ { ++ evn = ev->next; ++ kfree( ev ); ++ } ++ kfree( p ); ++ } ++ } ++ kfree( hashtab ); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_TRACE.c linux-2.4.20/net/ipv4/netfilter/ipt_TRACE.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_TRACE.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_TRACE.c Wed Sep 24 09:18:12 2003 +@@ -0,0 +1,66 @@ ++/* This is a module which is used for setting ++ * the NFC_TRACE flag in the nfcache field of an skb. ++ */ ++#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) ++{ ++ (*pskb)->nfcache |= NFC_TRACE; ++ return IPT_CONTINUE; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (targinfosize != 0) { ++ printk(KERN_WARNING "TRACE: targinfosize %u != 0\n", ++ targinfosize); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "raw") != 0) { ++ printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_trace_reg = { ++ .list = { NULL, NULL }, ++ .name = "TRACE", ++ .target = target, ++ .checkentry = checkentry, ++ .destroy = NULL, ++ .me THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_trace_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_trace_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_TTL.c linux-2.4.20/net/ipv4/netfilter/ipt_TTL.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_TTL.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_TTL.c Wed Sep 24 09:16:40 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.20/net/ipv4/netfilter/ipt_ULOG.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_ULOG.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_ULOG.c Wed Sep 24 09:16:23 2003 +@@ -12,6 +12,7 @@ + * module loadtime -HW + * 2002/07/07 remove broken nflog_rcv() function -HW + * 2002/08/29 fix shifted/unshifted nlgroup bug -HW ++ * 2002/10/30 fix uninitialized mac_len field - + * + * Released under the terms of the GPL + * +@@ -31,7 +32,7 @@ + * Specify, after how many clock ticks (intel: 100 per second) the queue + * should be flushed even if it is not full yet. + * +- * ipt_ULOG.c,v 1.21 2002/08/29 10:54:34 laforge Exp ++ * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp + */ + + #include +@@ -47,6 +48,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -76,6 +78,10 @@ + MODULE_PARM(flushtimeout, "i"); + MODULE_PARM_DESC(flushtimeout, "buffer flush timeout"); + ++static unsigned int nflog = 1; ++MODULE_PARM(nflog, "i"); ++MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); ++ + /* global data structures */ + + typedef struct { +@@ -153,17 +159,17 @@ + return skb; + } + +-static unsigned int ipt_ulog_target(struct sk_buff **pskb, +- unsigned int hooknum, +- const struct net_device *in, +- const struct net_device *out, +- const void *targinfo, void *userinfo) ++static void ipt_ulog_packet(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const struct ipt_ulog_info *loginfo, ++ const char *prefix) + { + ulog_buff_t *ub; + ulog_packet_msg_t *pm; + size_t size, copy_len; + struct nlmsghdr *nlh; +- struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; + + /* ffs == find first bit set, necessary because userspace + * is already shifting groupnumber, but we need unshifted. +@@ -214,7 +220,9 @@ + pm->timestamp_usec = (*pskb)->stamp.tv_usec; + pm->mark = (*pskb)->nfmark; + pm->hook = hooknum; +- if (loginfo->prefix[0] != '\0') ++ if (prefix != NULL) ++ strncpy(pm->prefix, prefix, sizeof(pm->prefix)); ++ else if (loginfo->prefix[0] != '\0') + strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); + else + *(pm->prefix) = '\0'; +@@ -224,7 +232,8 @@ + && in->hard_header_len <= ULOG_MAC_LEN) { + memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len); + pm->mac_len = in->hard_header_len; +- } ++ } else ++ pm->mac_len = 0; + + if (in) + strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); +@@ -260,8 +269,7 @@ + + UNLOCK_BH(&ulog_lock); + +- return IPT_CONTINUE; +- ++ return; + + nlmsg_failure: + PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); +@@ -270,8 +278,128 @@ + PRINTR("ipt_ULOG: Error building netlink message\n"); + + UNLOCK_BH(&ulog_lock); ++} + +- return IPT_CONTINUE; ++static unsigned int ipt_ulog_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_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; ++ ++ ipt_ulog_packet(pskb, hooknum, in, out, loginfo, NULL); ++ ++ return IPT_CONTINUE; ++} ++ ++static void ip_ulog_packet_fn(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const char *prefix) ++{ ++ struct ipt_ulog_info loginfo = { ++ .nl_group = ULOG_DEFAULT_NLGROUP, ++ .copy_range = 0, ++ .qthreshold = ULOG_DEFAULT_QTHRESHOLD, ++ .prefix = "" ++ }; ++ ++ ipt_ulog_packet(pskb, hooknum, in, out, &loginfo, prefix); ++} ++ ++static void ip_ulog_fn(char *pfh, size_t len, ++ const char *prefix) ++{ ++ struct ipt_ulog_info loginfo = { ++ .nl_group = ULOG_DEFAULT_NLGROUP, ++ .copy_range = 0, ++ .qthreshold = ULOG_DEFAULT_QTHRESHOLD, ++ .prefix = "" ++ }; ++ ulog_buff_t *ub; ++ ulog_packet_msg_t *pm; ++ size_t size; ++ struct nlmsghdr *nlh; ++ ++ /* ffs == find first bit set, necessary because userspace ++ * is already shifting groupnumber, but we need unshifted. ++ * ffs() returns [1..32], we need [0..31] */ ++ unsigned int groupnum = ffs(loginfo.nl_group) - 1; ++ ++ size = NLMSG_SPACE(sizeof(*pm) + len); ++ ++ ub = &ulog_buffers[groupnum]; ++ ++ LOCK_BH(&ulog_lock); ++ ++ if (!ub->skb) { ++ if (!(ub->skb = ulog_alloc_skb(size))) ++ goto alloc_failure; ++ } else if (ub->qlen >= loginfo.qthreshold || ++ size > skb_tailroom(ub->skb)) { ++ /* either the queue len is too high or we don't have ++ * enough room in nlskb left. send it to userspace. */ ++ ++ ulog_send(groupnum); ++ ++ if (!(ub->skb = ulog_alloc_skb(size))) ++ goto alloc_failure; ++ } ++ ++ DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, ++ loginfo.qthreshold); ++ ++ /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ ++ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, ++ size - sizeof(*nlh)); ++ ub->qlen++; ++ ++ pm = NLMSG_DATA(nlh); ++ ++ /* Set fake hook, prefix, timestamp etc. */ ++ pm->data_len = len; ++ pm->timestamp_sec = 0; ++ pm->timestamp_usec = 0; ++ pm->mark = 0; ++ pm->hook = 0; ++ strncpy(pm->prefix, prefix, sizeof(pm->prefix)); ++ pm->mac_len = 0; ++ pm->indev_name[0] = '\0'; ++ pm->outdev_name[0] = '\0'; ++ memcpy(pm->payload, pfh, len); ++ ++ /* check if we are building multi-part messages */ ++ if (ub->qlen > 1) { ++ ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; ++ } ++ ++ /* if threshold is reached, send message to userspace */ ++ if (qlen >= loginfo.qthreshold) { ++ if (loginfo.qthreshold > 1) ++ nlh->nlmsg_type = NLMSG_DONE; ++ } ++ ++ ub->lastnlh = nlh; ++ ++ /* if timer isn't already running, start it */ ++ if (!timer_pending(&ub->timer)) { ++ ub->timer.expires = jiffies + flushtimeout; ++ add_timer(&ub->timer); ++ } ++ ++ UNLOCK_BH(&ulog_lock); ++ ++ return; ++ ++nlmsg_failure: ++ PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); ++ ++alloc_failure: ++ PRINTR("ipt_ULOG: Error building netlink message\n"); ++ ++ UNLOCK_BH(&ulog_lock); + } + + static int ipt_ulog_checkentry(const char *tablename, +@@ -306,6 +434,8 @@ + { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL, + THIS_MODULE + }; ++static struct nf_logging_t ip_logging_fn ++= { ip_ulog_packet_fn, ip_ulog_fn }; + + static int __init init(void) + { +@@ -320,7 +450,6 @@ + + /* initialize ulog_buffers */ + for (i = 0; i < ULOG_MAXNLGROUPS; i++) { +- memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t)); + init_timer(&ulog_buffers[i].timer); + ulog_buffers[i].timer.function = ulog_timer; + ulog_buffers[i].timer.data = i; +@@ -334,7 +463,9 @@ + sock_release(nflognl->socket); + return -EINVAL; + } +- ++ if (nflog) ++ nf_ip_log_register(&ip_logging_fn); ++ + return 0; + } + +@@ -345,6 +476,8 @@ + + DEBUGP("ipt_ULOG: cleanup_module\n"); + ++ if (nflog) ++ nf_ip_log_unregister(&ip_logging_fn); + ipt_unregister_target(&ipt_ulog_reg); + sock_release(nflognl->socket); + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_XOR.c linux-2.4.20/net/ipv4/netfilter/ipt_XOR.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_XOR.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_XOR.c Wed Sep 24 09:17:31 2003 +@@ -0,0 +1,107 @@ ++/* XOR target for IP tables ++ * (C) 2000 by Tim Vandermeersch ++ * Based on ipt_TTL.c ++ * ++ * Version 1.0 ++ * ++ * This software is distributed under the terms of GNU GPL ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Tim Vandermeersch "); ++MODULE_DESCRIPTION("IP tables XOR module"); ++MODULE_LICENSE("GPL"); ++ ++static unsigned int ipt_xor_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_XOR_info *info = (void *) targinfo; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph; ++ struct udphdr *udph; ++ int i, j, k; ++ ++ if (iph->protocol == IPPROTO_TCP) { ++ tcph = (struct tcphdr *) ((*pskb)->data + iph->ihl*4); ++ for (i=0, j=0; i<(ntohs(iph->tot_len) - iph->ihl*4 - tcph->doff*4); ) { ++ for (k=0; k<=info->block_size; k++) { ++ (char) (*pskb)->data[ iph->ihl*4 + tcph->doff*4 + i ] ^= ++ info->key[j]; ++ i++; ++ } ++ j++; ++ if (info->key[j] == 0x00) ++ j = 0; ++ } ++ } else if (iph->protocol == IPPROTO_UDP) { ++ udph = (struct udphdr *) ((*pskb)->data + iph->ihl*4); ++ for (i=0, j=0; i<(ntohs(udph->len)-8); ) { ++ for (k=0; k<=info->block_size; k++) { ++ (char) (*pskb)->data[ iph->ihl*4 + sizeof(struct udphdr) + i ] ^= ++ info->key[j]; ++ i++; ++ } ++ j++; ++ if (info->key[j] == 0x00) ++ j = 0; ++ } ++ } ++ ++ return IPT_CONTINUE; ++} ++ ++static int ipt_xor_checkentry(const char *tablename, const struct ipt_entry *e, ++ void *targinfo, unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ struct ipt_XOR_info *info = targinfo; ++ ++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_XOR_info))) { ++ printk(KERN_WARNING "XOR: targinfosize %u != %Zu\n", ++ targinfosize, IPT_ALIGN(sizeof(struct ipt_XOR_info))); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "mangle")) { ++ printk(KERN_WARNING "XOR: can only be called from" ++ "\"mangle\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ if (!strcmp(info->key, "")) { ++ printk(KERN_WARNING "XOR: You must specify a key"); ++ return 0; ++ } ++ ++ if (info->block_size == 0) { ++ printk(KERN_WARNING "XOR: You must specify a block-size"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_XOR = { { NULL, NULL }, "XOR", ++ ipt_xor_target, ipt_xor_checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ipt_register_target(&ipt_XOR); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_XOR); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_addrtype.c linux-2.4.20/net/ipv4/netfilter/ipt_addrtype.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_addrtype.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_addrtype.c Wed Sep 24 09:17:32 2003 +@@ -0,0 +1,65 @@ ++/* ++ * iptables module to match inet_addr_type() of an ip. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++static inline int match_type(u_int32_t addr, u_int16_t mask) ++{ ++ return !!(mask & (1 << inet_addr_type(addr))); ++} ++ ++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_addrtype_info *info = matchinfo; ++ const struct iphdr *iph = skb->nh.iph; ++ int ret = 1; ++ ++ if (info->source) ++ ret &= match_type(iph->saddr, info->source)^info->invert_source; ++ if (info->dest) ++ ret &= match_type(iph->daddr, info->dest)^info->invert_dest; ++ ++ return ret; ++} ++ ++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_addrtype_info))) { ++ printk(KERN_ERR "ipt_addrtype: invalid size (%u != %u)\n.", ++ matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info))); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_match addrtype_match = { { NULL, NULL }, "addrtype", &match, ++ &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&addrtype_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&addrtype_match); ++ ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_ah.c linux-2.4.20/net/ipv4/netfilter/ipt_ah.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_ah.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_ah.c Wed Sep 24 09:16:18 2003 +@@ -15,7 +15,11 @@ + #endif + + struct ahhdr { ++ __u8 nexthdr; ++ __u8 hdrlen; ++ __u16 reserved; + __u32 spi; ++ __u32 seq_no; + }; + + /* Returns 1 if the spi is matched by the range, 0 otherwise */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_condition.c linux-2.4.20/net/ipv4/netfilter/ipt_condition.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_condition.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_condition.c Wed Sep 24 09:17:34 2003 +@@ -0,0 +1,256 @@ ++/*-------------------------------------------*\ ++| Netfilter Condition Module | ++| | ++| Description: This module allows firewall | ++| rules to match using condition variables | ++| stored in /proc files. | ++| | ++| Author: Stephane Ouellette 2002-10-22 | ++| | ++| | ++| History: | ++| 2003-02-10 Second version with improved | ++| locking and simplified code. | ++| | ++| This software is distributed under the | ++| terms of the GNU GPL. | ++\*-------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifndef CONFIG_PROC_FS ++#error "Proc file system support is required for this module" ++#endif ++ ++ ++MODULE_AUTHOR("Stephane Ouellette "); ++MODULE_DESCRIPTION("Allows rules to match against condition variables"); ++MODULE_LICENSE("GPL"); ++ ++ ++struct condition_variable { ++ struct condition_variable *next; ++ struct proc_dir_entry *status_proc; ++ atomic_t refcount; ++ int enabled; /* TRUE == 1, FALSE == 0 */ ++}; ++ ++ ++static rwlock_t list_lock; ++static struct condition_variable *head = NULL; ++static struct proc_dir_entry *proc_net_condition = NULL; ++ ++ ++static int ++ipt_condition_read_info(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (offset == 0) { ++ *start = buffer; ++ buffer[0] = (var->enabled) ? '1' : '0'; ++ buffer[1] = '\n'; ++ return 2; ++ } ++ ++ *eof = 1; ++ return 0; ++} ++ ++ ++static int ++ipt_condition_write_info(struct file *file, const char *buffer, ++ unsigned long length, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (length) { ++ /* Match only on the first character */ ++ switch (buffer[0]) { ++ case '0': ++ var->enabled = 0; ++ break; ++ case '1': ++ var->enabled = 1; ++ } ++ } ++ ++ return (int) length; ++} ++ ++ ++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 condition_info *info = ++ (const struct condition_info *) matchinfo; ++ struct condition_variable *var; ++ int condition_status = 0; ++ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ condition_status = var->enabled; ++ break; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ return condition_status ^ info->invert; ++} ++ ++ ++ ++static int ++checkentry(const char *tablename, const struct ipt_ip *ip, ++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask) ++{ ++ struct condition_info *info = (struct condition_info *) matchinfo; ++ struct condition_variable *var, *newvar; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) ++ return 0; ++ ++ /* The first step is to check if the condition variable already exists. */ ++ /* Here, a read lock is sufficient because we won't change the list */ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ /* At this point, we need to allocate a new condition variable */ ++ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); ++ ++ if (!newvar) ++ return -ENOMEM; ++ ++ /* Create the condition variable's proc file entry */ ++ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); ++ ++ if (!newvar->status_proc) { ++ /* ++ * There are two possibilities: ++ * 1- Another condition variable with the same name has been created, which is valid. ++ * 2- There was a memory allocation error. ++ */ ++ kfree(newvar); ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ return -ENOMEM; ++ } ++ ++ atomic_set(&newvar->refcount, 1); ++ newvar->enabled = 0; ++ newvar->status_proc->owner = THIS_MODULE; ++ newvar->status_proc->data = newvar; ++ wmb(); ++ newvar->status_proc->read_proc = ipt_condition_read_info; ++ newvar->status_proc->write_proc = ipt_condition_write_info; ++ ++ write_lock(&list_lock); ++ ++ newvar->next = head; ++ head = newvar; ++ ++ write_unlock(&list_lock); ++ ++ return 1; ++} ++ ++ ++static void ++destroy(void *matchinfo, unsigned int matchsize) ++{ ++ struct condition_info *info = (struct condition_info *) matchinfo; ++ struct condition_variable *var, *prev = NULL; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) ++ return; ++ ++ write_lock(&list_lock); ++ ++ for (var = head; var && strcmp(info->name, var->status_proc->name); ++ prev = var, var = var->next); ++ ++ if (var && atomic_dec_and_test(&var->refcount)) { ++ if (prev) ++ prev->next = var->next; ++ else ++ head = var->next; ++ ++ write_unlock(&list_lock); ++ remove_proc_entry(var->status_proc->name, proc_net_condition); ++ kfree(var); ++ } else ++ write_unlock(&list_lock); ++} ++ ++ ++static struct ipt_match condition_match = { ++ .name = "condition", ++ .match = &match, ++ .checkentry = &checkentry, ++ .destroy = &destroy, ++ .me = THIS_MODULE ++}; ++ ++ ++static int __init ++init(void) ++{ ++ int errorcode; ++ ++ rwlock_init(&list_lock); ++ proc_net_condition = proc_mkdir("ipt_condition", proc_net); ++ ++ if (proc_net_condition) { ++ errorcode = ipt_register_match(&condition_match); ++ ++ if (errorcode) ++ remove_proc_entry("ipt_condition", proc_net); ++ } else ++ errorcode = -EACCES; ++ ++ return errorcode; ++} ++ ++ ++static void __exit ++fini(void) ++{ ++ ipt_unregister_match(&condition_match); ++ remove_proc_entry("ipt_condition", proc_net); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.4.20/net/ipv4/netfilter/ipt_connlimit.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_connlimit.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_connlimit.c Wed Sep 24 09:16:42 2003 +@@ -0,0 +1,232 @@ ++/* ++ * netfilter module to limit the number of parallel tcp ++ * connections per IP address. ++ * (c) 2000 Gerd Knorr ++ * Nov 2002: Martin Bene : ++ * only ignore TIME_WAIT or gone connections ++ * ++ * based on ... ++ * ++ * Kernel module to match connection tracking information. ++ * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEBUG 0 ++ ++MODULE_LICENSE("GPL"); ++ ++/* we'll save the tuples of all connections we care about */ ++struct ipt_connlimit_conn ++{ ++ struct list_head list; ++ struct ip_conntrack_tuple tuple; ++}; ++ ++struct ipt_connlimit_data { ++ spinlock_t lock; ++ struct list_head iphash[256]; ++}; ++ ++static int ipt_iphash(u_int32_t addr) ++{ ++ int hash; ++ ++ hash = addr & 0xff; ++ hash ^= (addr >> 8) & 0xff; ++ hash ^= (addr >> 16) & 0xff; ++ hash ^= (addr >> 24) & 0xff; ++ return hash; ++} ++ ++static int count_them(struct ipt_connlimit_data *data, ++ u_int32_t addr, u_int32_t mask, ++ struct ip_conntrack *ct) ++{ ++#if DEBUG ++ const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", ++ "fin_wait", "time_wait", "close", "close_wait", ++ "last_ack", "listen" }; ++#endif ++ int addit = 1, matches = 0; ++ struct ip_conntrack_tuple tuple; ++ struct ip_conntrack_tuple_hash *found; ++ struct ipt_connlimit_conn *conn; ++ struct list_head *hash,*lh; ++ ++ spin_lock(&data->lock); ++ tuple = ct->tuplehash[0].tuple; ++ hash = &data->iphash[ipt_iphash(addr & mask)]; ++ ++ /* check the saved connections */ ++ for (lh = hash->next; lh != hash; lh = lh->next) { ++ conn = list_entry(lh,struct ipt_connlimit_conn,list); ++ found = ip_conntrack_find_get(&conn->tuple,ct); ++ if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) && ++ found != NULL && ++ found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) { ++ /* Just to be sure we have it only once in the list. ++ We should'nt see tuples twice unless someone hooks this ++ into a table without "-p tcp --syn" */ ++ addit = 0; ++ } ++#if DEBUG ++ printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", ++ ipt_iphash(addr & mask), ++ NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), ++ NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), ++ (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone"); ++#endif ++ if (NULL == found) { ++ /* this one is gone */ ++ lh = lh->prev; ++ list_del(lh->next); ++ kfree(conn); ++ continue; ++ } ++ if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { ++ /* we don't care about connections which are ++ closed already -> ditch it */ ++ lh = lh->prev; ++ list_del(lh->next); ++ kfree(conn); ++ nf_conntrack_put(&found->ctrack->infos[0]); ++ continue; ++ } ++ if ((addr & mask) == (conn->tuple.src.ip & mask)) { ++ /* same source IP address -> be counted! */ ++ matches++; ++ } ++ nf_conntrack_put(&found->ctrack->infos[0]); ++ } ++ if (addit) { ++ /* save the new connection in our list */ ++#if DEBUG ++ printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", ++ ipt_iphash(addr & mask), ++ NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), ++ NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); ++#endif ++ conn = kmalloc(sizeof(*conn),GFP_ATOMIC); ++ if (NULL == conn) ++ return -1; ++ memset(conn,0,sizeof(*conn)); ++ INIT_LIST_HEAD(&conn->list); ++ conn->tuple = tuple; ++ list_add(&conn->list,hash); ++ matches++; ++ } ++ spin_unlock(&data->lock); ++ return matches; ++} ++ ++static int ++match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ const struct ipt_connlimit_info *info = matchinfo; ++ int connections, match; ++ struct ip_conntrack *ct; ++ enum ip_conntrack_info ctinfo; ++ ++ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); ++ if (NULL == ct) { ++ printk("ipt_connlimit: Oops: invalid ct state ?\n"); ++ *hotdrop = 1; ++ return 0; ++ } ++ connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct); ++ if (-1 == connections) { ++ printk("ipt_connlimit: Hmm, kmalloc failed :-(\n"); ++ *hotdrop = 1; /* let's free some memory :-) */ ++ return 0; ++ } ++ match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); ++#if DEBUG ++ printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " ++ "connections=%d limit=%d match=%s\n", ++ NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), ++ connections, info->limit, match ? "yes" : "no"); ++#endif ++ ++ return match; ++} ++ ++static int check(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ struct ipt_connlimit_info *info = matchinfo; ++ int i; ++ ++ /* verify size */ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info))) ++ return 0; ++ ++ /* refuse anything but tcp */ ++ if (ip->proto != IPPROTO_TCP) ++ return 0; ++ ++ /* init private data */ ++ info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL); ++ spin_lock_init(&(info->data->lock)); ++ for (i = 0; i < 256; i++) ++ INIT_LIST_HEAD(&(info->data->iphash[i])); ++ ++ return 1; ++} ++ ++static void destroy(void *matchinfo, unsigned int matchinfosize) ++{ ++ struct ipt_connlimit_info *info = matchinfo; ++ struct ipt_connlimit_conn *conn; ++ struct list_head *hash; ++ int i; ++ ++ /* cleanup */ ++ for (i = 0; i < 256; i++) { ++ hash = &(info->data->iphash[i]); ++ while (hash != hash->next) { ++ conn = list_entry(hash->next,struct ipt_connlimit_conn,list); ++ list_del(hash->next); ++ kfree(conn); ++ } ++ } ++ kfree(info->data); ++} ++ ++static struct ipt_match connlimit_match ++= { { NULL, NULL }, "connlimit", &match, &check, &destroy, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ /* NULL if ip_conntrack not a module */ ++ if (ip_conntrack_module) ++ __MOD_INC_USE_COUNT(ip_conntrack_module); ++ return ipt_register_match(&connlimit_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&connlimit_match); ++ if (ip_conntrack_module) ++ __MOD_DEC_USE_COUNT(ip_conntrack_module); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_connmark.c linux-2.4.20/net/ipv4/netfilter/ipt_connmark.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_connmark.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_connmark.c Wed Sep 24 09:17:17 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.4.20/net/ipv4/netfilter/ipt_conntrack.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_conntrack.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_conntrack.c Wed Sep 24 09:18:12 2003 +@@ -27,7 +27,13 @@ + + #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) + +- statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo); ++ if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW]) ++ statebit = IPT_CONNTRACK_STATE_UNTRACKED; ++ else if (ct) ++ statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); ++ else ++ statebit = IPT_CONNTRACK_STATE_INVALID; ++ + if(sinfo->flags & IPT_CONNTRACK_STATE) { + if (ct) { + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_esp.c linux-2.4.20/net/ipv4/netfilter/ipt_esp.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_esp.c Mon Feb 25 19:38:14 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_esp.c Wed Sep 24 09:16:18 2003 +@@ -16,6 +16,7 @@ + + struct esphdr { + __u32 spi; ++ __u32 seq_no; + }; + + /* Returns 1 if the spi is matched by the range, 0 otherwise */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.4.20/net/ipv4/netfilter/ipt_fuzzy.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_fuzzy.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_fuzzy.c Wed Sep 24 09:16:44 2003 +@@ -0,0 +1,190 @@ ++/* ++ * This module implements a simple TSK FLC ++ * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims ++ * to limit , in an adaptive and flexible way , the packet rate crossing ++ * a given stream . It serves as an initial and very simple (but effective) ++ * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks. ++ * As a matter of fact , Fuzzy Logic can help us to insert any "behavior" ++ * into our code in a precise , adaptive and efficient manner. ++ * The goal is very similar to that of "limit" match , but using techniques of ++ * Fuzzy Control , that allow us to shape the transfer functions precisely , ++ * avoiding over and undershoots - and stuff like that . ++ * ++ * ++ * 2002-08-10 Hime Aguiar e Oliveira Jr. : Initial version. ++ * 2002-08-17 : Changed to eliminate floating point operations . ++ * 2002-08-23 : Coding style changes . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH ++ Expressed in percentage ++*/ ++ ++#define PAR_LOW 1/100 ++#define PAR_HIGH 1 ++ ++static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ; ++ ++MODULE_AUTHOR("Hime Aguiar e Oliveira Junior "); ++MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); ++MODULE_LICENSE("GPL"); ++ ++static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi) ++{ ++ if (tx >= maxi) return 100; ++ ++ if (tx <= mini) return 0; ++ ++ return ( (100*(tx-mini)) / (maxi-mini) ) ; ++} ++ ++static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi) ++{ ++ if (tx <= mini) return 100; ++ ++ if (tx >= maxi) return 0; ++ ++ return ( (100*( maxi - tx )) / ( maxi - mini ) ) ; ++ ++} ++ ++static int ++ipt_fuzzy_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) ++{ ++ /* From userspace */ ++ ++ struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo; ++ ++ u_int8_t random_number; ++ unsigned long amount ; ++ u_int8_t howhigh , howlow ; ++ ++ ++ spin_lock_bh(&fuzzy_lock) ; /* Rise the lock */ ++ ++ info->bytes_total += pskb->len ; ++ info->packets_total++ ; ++ ++ info->present_time = jiffies ; ++ ++ if ( info->present_time >= info->previous_time ) ++ amount = info->present_time - info->previous_time ; ++ else { ++ /* There was a transition : I choose to re-sample ++ and keep the old acceptance rate... ++ */ ++ ++ amount = 0 ; ++ info->previous_time = info->present_time ; ++ info->bytes_total = info->packets_total = 0; ++ }; ++ ++ if ( amount > HZ/10 ) /* More than 100 ms elapsed ... */ ++ { ++ ++ info->mean_rate = (u_int32_t) ( ( HZ * info->packets_total ) \ ++ / amount ) ; ++ ++ info->previous_time = info->present_time ; ++ info->bytes_total = info->packets_total = 0 ; ++ ++ howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); ++ howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); ++ ++ info->acceptance_rate = (u_int8_t) \ ++ ( howhigh*PAR_LOW + PAR_HIGH*howlow ) ; ++ ++ /* In fact , the above defuzzification would require a denominator ++ proportional to (howhigh+howlow) but , in this particular case , ++ that expression is constant . ++ An imediate consequence is that it isn't necessary to call ++ both mf_high and mf_low - but to keep things understandable , ++ I did so . ++ */ ++ ++ } ++ ++ spin_unlock_bh(&fuzzy_lock) ; /* Release the lock */ ++ ++ ++ if ( info->acceptance_rate < 100 ) ++ { ++ get_random_bytes((void *)(&random_number), 1); ++ ++ /* If within the acceptance , it can pass => don't match */ ++ if ( random_number <= (255 * info->acceptance_rate) / 100 ) ++ return 0 ; ++ else ++ return 1; /* It can't pass ( It matches ) */ ++ } ; ++ ++ return 0; /* acceptance_rate == 100 % => Everything passes ... */ ++ ++} ++ ++static int ++ipt_fuzzy_checkentry(const char *tablename, ++ const struct ipt_ip *e, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ ++ const struct ipt_fuzzy_info *info = matchinfo; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) { ++ printk("ipt_fuzzy: matchsize %u != %u\n", matchsize, ++ IPT_ALIGN(sizeof(struct ipt_fuzzy_info))); ++ return 0; ++ } ++ ++if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE) ++ || (info->minimum_rate >= info->maximum_rate )) ++ { ++ printk("ipt_fuzzy: BAD limits , please verify !!!\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_match ipt_fuzzy_reg = { ++ {NULL, NULL}, ++ "fuzzy", ++ ipt_fuzzy_match, ++ ipt_fuzzy_checkentry, ++ NULL, ++ THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ipt_register_match(&ipt_fuzzy_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&ipt_fuzzy_reg); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_helper.c linux-2.4.20/net/ipv4/netfilter/ipt_helper.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_helper.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_helper.c Wed Sep 24 09:16:17 2003 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -36,6 +37,7 @@ + struct ip_conntrack_expect *exp; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; ++ int ret = 0; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (!ct) { +@@ -49,23 +51,27 @@ + } + + exp = ct->master; ++ READ_LOCK(&ip_conntrack_lock); + if (!exp->expectant) { + DEBUGP("ipt_helper: expectation %p without expectant !?!\n", + exp); +- return 0; ++ goto out_unlock; + } + + if (!exp->expectant->helper) { + DEBUGP("ipt_helper: master ct %p has no helper\n", + exp->expectant); +- return 0; ++ goto out_unlock; + } + + DEBUGP("master's name = %s , info->name = %s\n", + exp->expectant->helper->name, info->name); + +- return !strncmp(exp->expectant->helper->name, info->name, +- strlen(exp->expectant->helper->name)) ^ info->invert; ++ ret = !strncmp(exp->expectant->helper->name, info->name, ++ strlen(exp->expectant->helper->name)) ^ info->invert; ++out_unlock: ++ READ_UNLOCK(&ip_conntrack_lock); ++ return ret; + } + + static int check(const char *tablename, +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_iprange.c linux-2.4.20/net/ipv4/netfilter/ipt_iprange.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_iprange.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_iprange.c Wed Sep 24 09:16:47 2003 +@@ -0,0 +1,101 @@ ++/* ++ * iptables module to match IP address ranges ++ * (c) 2003 Jozsef Kadlecsik ++ * ++ * Released under the terms of GNU GPLv2. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("iptables arbitrary IP range match module"); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++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_iprange_info *info = matchinfo; ++ const struct iphdr *iph = skb->nh.iph; ++ ++ ++ if (info->flags & IPRANGE_SRC) { ++ if (((ntohl(iph->saddr) < ntohl(info->src.min_ip)) ++ || (ntohl(iph->saddr) > ntohl(info->src.max_ip))) ++ ^ !!(info->flags & IPRANGE_SRC_INV)) { ++ DEBUGP("src IP %u.%u.%u.%u NOT in range %s" ++ "%u.%u.%u.%u-%u.%u.%u.%u\n", ++ NIPQUAD(iph->saddr), ++ info->flags & IPRANGE_SRC_INV ? "(INV) " : "", ++ NIPQUAD(info->src.min_ip), ++ NIPQUAD(info->src.max_ip)); ++ return 0; ++ } ++ } ++ if (info->flags & IPRANGE_DST) { ++ if (((ntohl(iph->daddr) < ntohl(info->dst.min_ip)) ++ || (ntohl(iph->daddr) > ntohl(info->dst.max_ip))) ++ ^ !!(info->flags & IPRANGE_DST_INV)) { ++ DEBUGP("dst IP %u.%u.%u.%u NOT in range %s" ++ "%u.%u.%u.%u-%u.%u.%u.%u\n", ++ NIPQUAD(iph->daddr), ++ info->flags & IPRANGE_DST_INV ? "(INV) " : "", ++ NIPQUAD(info->dst.min_ip), ++ NIPQUAD(info->dst.max_ip)); ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static int check(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ /* verify size */ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_iprange_info))) ++ return 0; ++ ++ return 1; ++} ++ ++static struct ipt_match iprange_match = ++{ ++ .list = { NULL, NULL }, ++ .name = "iprange", ++ .match = &match, ++ .checkentry = &check, ++ .destroy = NULL, ++ .me = THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&iprange_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&iprange_match); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.4.20/net/ipv4/netfilter/ipt_ipv4options.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_ipv4options.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_ipv4options.c Wed Sep 24 09:16:49 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_mark.c linux-2.4.20/net/ipv4/netfilter/ipt_mark.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_mark.c Sun Sep 30 19:26:08 2001 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_mark.c Wed Sep 24 09:18:10 2003 +@@ -15,9 +15,15 @@ + u_int16_t datalen, + int *hotdrop) + { +- const struct ipt_mark_info *info = matchinfo; ++ const struct ipt_mark_info *info = (struct ipt_mark_info *)matchinfo; + +- return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; ++ if (info->bit_op == IPT_MARK_BIT_OP_NONE) ++ return (skb->nfmark == info->mark) ^ info->invert; ++ else ++ if (info->bit_op == IPT_MARK_BIT_OP_AND) ++ return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; ++ else ++ return ((skb->nfmark | info->mask) == info->mark) ^ info->invert; + } + + static int +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_mport.c linux-2.4.20/net/ipv4/netfilter/ipt_mport.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_mport.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_mport.c Wed Sep 24 09:16:51 2003 +@@ -0,0 +1,112 @@ ++/* Kernel module to match one of a list of TCP/UDP ports: ports are in ++ the same place so we can treat them as equal. */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++#if 0 ++#define duprintf(format, args...) printk(format , ## args) ++#else ++#define duprintf(format, args...) ++#endif ++ ++/* Returns 1 if the port is matched by the test, 0 otherwise. */ ++static inline int ++ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst) ++{ ++ unsigned int i; ++ unsigned int m; ++ u_int16_t pflags = minfo->pflags; ++ for (i=0, m=1; iports[i] == 65535) ++ return 0; ++ ++ s = minfo->ports[i]; ++ ++ if (pflags & m) { ++ e = minfo->ports[++i]; ++ m <<= 1; ++ } else ++ e = s; ++ ++ if (minfo->flags & IPT_MPORT_SOURCE ++ && src >= s && src <= e) ++ return 1; ++ ++ if (minfo->flags & IPT_MPORT_DESTINATION ++ && dst >= s && dst <= e) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int ++match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ const struct udphdr *udp = hdr; ++ const struct ipt_mport *minfo = matchinfo; ++ ++ /* Must be big enough to read ports. */ ++ if (offset == 0 && datalen < sizeof(struct udphdr)) { ++ /* We've been asked to examine this packet, and we ++ can't. Hence, no choice but to drop. */ ++ duprintf("ipt_mport:" ++ " Dropping evil offset=0 tinygram.\n"); ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ /* Must not be a fragment. */ ++ return !offset ++ && ports_match(minfo, ntohs(udp->source), ntohs(udp->dest)); ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport))) ++ return 0; ++ ++ /* Must specify proto == TCP/UDP, no unknown flags or bad count */ ++ return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) ++ && !(ip->invflags & IPT_INV_PROTO) ++ && matchsize == IPT_ALIGN(sizeof(struct ipt_mport)); ++} ++ ++static struct ipt_match mport_match ++= { { NULL, NULL }, "mport", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&mport_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&mport_match); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_multiport.c linux-2.4.20/net/ipv4/netfilter/ipt_multiport.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_multiport.c Sun Sep 30 19:26:08 2001 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_multiport.c Wed Sep 24 09:16:14 2003 +@@ -78,7 +78,7 @@ + + /* 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) ++ && !(ip->invflags & IPT_INV_PROTO) + && matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)) + && (multiinfo->flags == IPT_MULTIPORT_SOURCE + || multiinfo->flags == IPT_MULTIPORT_DESTINATION +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_nth.c linux-2.4.20/net/ipv4/netfilter/ipt_nth.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_nth.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_nth.c Wed Sep 24 09:16:53 2003 +@@ -0,0 +1,172 @@ ++/* ++ This is a module which is used for match support for every Nth packet ++ This file is distributed under the terms of the GNU General Public ++ License (GPL). Copies of the GPL can be obtained from: ++ ftp://prep.ai.mit.edu/pub/gnu/GPL ++ ++ 2001-07-18 Fabrice MARIE : initial implementation. ++ 2001-09-20 Richard Wagner (rwagner@cloudnet.com) ++ * added support for multiple counters ++ * added support for matching on individual packets ++ in the counter cycle ++ ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++/* ++ * State information. ++ */ ++struct state { ++ spinlock_t lock; ++ u_int16_t number; ++}; ++ ++static struct state states[IPT_NTH_NUM_COUNTERS]; ++ ++static int ++ipt_nth_match(const struct sk_buff *pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ /* Parameters from userspace */ ++ const struct ipt_nth_info *info = matchinfo; ++ unsigned counter = info->counter; ++ if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) ++ { ++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1); ++ return 0; ++ }; ++ ++ spin_lock(&states[counter].lock); ++ ++ /* Are we matching every nth packet?*/ ++ if (info->packet == 0xFF) ++ { ++ /* We're matching every nth packet and only every nth packet*/ ++ /* Do we match or invert match? */ ++ if (info->not == 0) ++ { ++ if (states[counter].number == 0) ++ { ++ ++states[counter].number; ++ goto match; ++ } ++ if (states[counter].number >= info->every) ++ states[counter].number = 0; /* reset the counter */ ++ else ++ ++states[counter].number; ++ goto dontmatch; ++ } ++ else ++ { ++ if (states[counter].number == 0) ++ { ++ ++states[counter].number; ++ goto dontmatch; ++ } ++ if (states[counter].number >= info->every) ++ states[counter].number = 0; ++ else ++ ++states[counter].number; ++ goto match; ++ } ++ } ++ else ++ { ++ /* We're using the --packet, so there must be a rule for every value */ ++ if (states[counter].number == info->packet) ++ { ++ /* only increment the counter when a match happens */ ++ if (states[counter].number >= info->every) ++ states[counter].number = 0; /* reset the counter */ ++ else ++ ++states[counter].number; ++ goto match; ++ } ++ else ++ goto dontmatch; ++ } ++ ++ dontmatch: ++ /* don't match */ ++ spin_unlock(&states[counter].lock); ++ return 0; ++ ++ match: ++ spin_unlock(&states[counter].lock); ++ return 1; ++} ++ ++static int ++ipt_nth_checkentry(const char *tablename, ++ const struct ipt_ip *e, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ /* Parameters from userspace */ ++ const struct ipt_nth_info *info = matchinfo; ++ unsigned counter = info->counter; ++ if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) ++ { ++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1); ++ return 0; ++ }; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) { ++ printk("nth: matchsize %u != %u\n", matchsize, ++ IPT_ALIGN(sizeof(struct ipt_nth_info))); ++ return 0; ++ } ++ ++ states[counter].number = info->startat; ++ ++ return 1; ++} ++ ++static struct ipt_match ipt_nth_reg = { ++ {NULL, NULL}, ++ "nth", ++ ipt_nth_match, ++ ipt_nth_checkentry, ++ NULL, ++ THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ unsigned counter; ++ memset(&states, 0, sizeof(states)); ++ if (ipt_register_match(&ipt_nth_reg)) ++ return -EINVAL; ++ ++ for(counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) ++ { ++ spin_lock_init(&(states[counter].lock)); ++ }; ++ ++ printk("ipt_nth match loaded\n"); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&ipt_nth_reg); ++ printk("ipt_nth match unloaded\n"); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_osf.c linux-2.4.20/net/ipv4/netfilter/ipt_osf.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_osf.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_osf.c Wed Sep 24 09:16:57 2003 +@@ -0,0 +1,685 @@ ++/* ++ * ipt_osf.c ++ * ++ * Copyright (c) 2003 Evgeniy Polyakov ++ * ++ * ++ * 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 ++ */ ++ ++/* ++ * OS fingerprint matching module. ++ * It simply compares various parameters from SYN packet with ++ * some hardcoded ones. ++ * ++ * Original table was created by Michal Zalewski ++ * for his p0f. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#include ++ ++//#define OSF_DEBUG ++ ++#ifdef OSF_DEBUG ++#define log(x...) printk(KERN_ERR "ipt_osf: " x) ++#define loga(x...) printk(x) ++#else ++#define log(x...) do {} while(0) ++#define loga(x...) do {} while(0) ++#endif ++ ++#define FMATCH_WRONG 0 ++#define FMATCH_OK 1 ++#define FMATCH_OPT_WRONG 2 ++ ++#define OPTDEL ',' ++#define OSFPDEL ':' ++#define MAXOPTSTRLEN 128 ++#define OSFFLUSH "FLUSH" ++ ++static rwlock_t osf_lock = RW_LOCK_UNLOCKED; ++static struct list_head finger_list; ++ ++static int match(const struct sk_buff *, const struct net_device *, const struct net_device *, ++ const void *, int, const void *, u_int16_t, int *); ++static int checkentry(const char *, const struct ipt_ip *, void *, ++ unsigned int, unsigned int); ++ ++static struct ipt_match osf_match = ++{ ++ { NULL, NULL }, ++ "osf", ++ &match, ++ &checkentry, ++ NULL, ++ THIS_MODULE ++}; ++ ++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_osf_info *info = (struct ipt_osf_info *)matchinfo; ++ struct iphdr *ip = skb->nh.iph; ++ struct tcphdr *tcp; ++ int fmatch = FMATCH_WRONG; ++ unsigned long totlen, optsize = 0, window; ++ unsigned char df, *optp = NULL, *_optp = NULL; ++ char check_WSS = 0; ++ struct list_head *ent; ++ struct osf_finger *f; ++ ++ if (!ip || !info) ++ return 0; ++ ++ tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl); ++ ++ if (!tcp->syn) ++ return 0; ++ ++ totlen = ntohs(ip->tot_len); ++ df = ((ntohs(ip->frag_off) & IP_DF)?1:0); ++ window = ntohs(tcp->window); ++ ++ if (tcp->doff*4 > sizeof(struct tcphdr)) ++ { ++ _optp = optp = (char *)(tcp+1); ++ optsize = tcp->doff*4 - sizeof(struct tcphdr); ++ } ++ ++ ++ /* Actually we can create hash/table of all genres and search ++ * only in appropriate part, but here is initial variant, ++ * so will use slow path. ++ */ ++ read_lock(&osf_lock); ++ list_for_each(ent, &finger_list) ++ { ++ f = list_entry(ent, struct osf_finger, flist); ++ ++ if (strcmp(info->genre, f->genre)) ++ continue; ++ ++ optp = _optp; ++ ++ if ( ip->ttl == f->ttl && ++ totlen == f->ss && ++ df == f->df) ++ { ++ unsigned long foptsize; ++ int optnum; ++ unsigned short mss = 0; ++ ++ check_WSS = 0; ++ ++ switch (f->wss.wc) ++ { ++ case 0: check_WSS = 0; break; ++ case 'S': check_WSS = 1; break; ++ case 'T': check_WSS = 2; break; ++ case '%': check_WSS = 3; break; ++ default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", ++ f->wss.wc, f->genre, f->details); ++ check_WSS = 4; ++ break; ++ } ++ if (check_WSS == 4) ++ continue; ++ ++ /* Check options */ ++ ++ foptsize = 0; ++ for (optnum=0; optnumopt_num; ++optnum) ++ foptsize += f->opt[optnum].length; ++ ++ ++ if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize) ++ continue; ++ ++ if (!optp) ++ { ++ fmatch = FMATCH_OK; ++ loga("\tYEP : matching without options.\n"); ++ break; ++ } ++ ++ ++ for (optnum=0; optnumopt_num; ++optnum) ++ { ++ if (f->opt[optnum].kind == (*optp)) ++ { ++ unsigned char len = f->opt[optnum].length; ++ unsigned char *optend = optp + len; ++ ++ fmatch = FMATCH_OK; ++ ++ if (*optp == OSFOPT_MSS) /* MSS */ ++ mss = ntohs(*(unsigned short *)(optp+2)); ++ ++ if (len != 1) ++ { ++ /* Skip kind and length fields*/ ++ optp += 2; ++ ++ if (f->opt[optnum].wc.wc != 0) ++ { ++ unsigned long tmp = 0; ++ ++ /* Hmmm... It looks a bit ugly. :) */ ++ memcpy(&tmp, &f->opt[optnum].wc.val, ++ (len > sizeof(unsigned long)? ++ sizeof(unsigned long):len)); ++ ++ tmp = ntohl(tmp); ++ if (tmp != f->opt[optnum].wc.val) ++ fmatch = FMATCH_OPT_WRONG; ++ } ++ } ++ ++ optp = optend; ++ } ++ else ++ fmatch = FMATCH_OPT_WRONG; ++ ++ if (fmatch != FMATCH_OK) ++ break; ++ } ++ ++ if (fmatch != FMATCH_OPT_WRONG) ++ { ++ fmatch = FMATCH_WRONG; ++ ++ switch (check_WSS) ++ { ++ case 0: ++ if (window == f->wss.val) ++ fmatch = FMATCH_OK; ++ break; ++ case 1: /* MSS */ ++ if (window == f->wss.val*mss) ++ fmatch = FMATCH_OK; ++ break; ++ case 2: /* MTU */ ++ if (window == f->wss.val*(mss+40)) ++ fmatch = FMATCH_OK; ++ break; ++ case 3: /* MOD */ ++ if (window % f->wss.val == 0) ++ fmatch = FMATCH_OK; ++ break; ++ } ++ } ++ ++ ++ if (fmatch == FMATCH_OK) ++ { ++ ++ log("genre %s[%25s]: ttl=%d, size=%lu, df=%d, " ++ "check_WSS=%d, win=%lu, optsize=%lu:\n", ++ f->genre, f->details, ++ ip->ttl, totlen, df, ++ check_WSS, window, optsize); ++ break; ++ } ++ } ++ } ++ read_unlock(&osf_lock); ++ ++ return (fmatch == FMATCH_OK)?1:0; ++} ++ ++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_osf_info))) ++ return 0; ++ if (ip->proto != IPPROTO_TCP) ++ return 0; ++ ++ return 1; ++} ++ ++static struct osf_finger * finger_alloc() ++{ ++ struct osf_finger *f; ++ ++ f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL); ++ if (f) ++ memset(f, 0, sizeof(struct osf_finger)); ++ ++ return f; ++} ++ ++static void finger_free(struct osf_finger *f) ++{ ++ memset(f, 0, sizeof(struct osf_finger)); ++ kfree(f); ++} ++ ++ ++static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen) ++{ ++ int i, op; ++ char *ptr, wc; ++ unsigned long val; ++ ++ ptr = &obuf[0]; ++ i = 0; ++ while (ptr != NULL && i < olen) ++ { ++ val = 0; ++ op = 0; ++ wc = 0; ++ switch (obuf[i]) ++ { ++ case 'N': ++ op = OSFOPT_NOP; ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ *ptr = '\0'; ++ ptr++; ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ case 'S': ++ op = OSFOPT_SACKP; ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ *ptr = '\0'; ++ ptr++; ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ case 'T': ++ op = OSFOPT_TS; ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ *ptr = '\0'; ++ ptr++; ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ case 'W': ++ op = OSFOPT_WSO; ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ switch (obuf[i+1]) ++ { ++ case '%': wc = '%'; break; ++ case 'S': wc = 'S'; break; ++ case 'T': wc = 'T'; break; ++ default: wc = 0; break; ++ } ++ ++ *ptr = '\0'; ++ ptr++; ++ if (wc) ++ val = simple_strtoul(&obuf[i+2], NULL, 10); ++ else ++ val = simple_strtoul(&obuf[i+1], NULL, 10); ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ case 'M': ++ op = OSFOPT_MSS; ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ if (obuf[i+1] == '%') ++ wc = '%'; ++ *ptr = '\0'; ++ ptr++; ++ if (wc) ++ val = simple_strtoul(&obuf[i+2], NULL, 10); ++ else ++ val = simple_strtoul(&obuf[i+1], NULL, 10); ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ case 'E': ++ op = OSFOPT_EOL; ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ *ptr = '\0'; ++ ptr++; ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ default: ++ ptr = strchr(&obuf[i], OPTDEL); ++ if (ptr) ++ { ++ ptr++; ++ i += (int)(ptr-&obuf[i]); ++ ++ } ++ else ++ i++; ++ break; ++ } ++ ++ opt[*optnum].kind = IANA_opts[op].kind; ++ opt[*optnum].length = IANA_opts[op].length; ++ opt[*optnum].wc.wc = wc; ++ opt[*optnum].wc.val = val; ++ ++ log("opt %2d: kind=%2d, length=%2d, wc.wc=%d, wc.val=%5lu\n", ++ *optnum, opt[*optnum].kind, opt[*optnum].length, ++ opt[*optnum].wc.wc, opt[*optnum].wc.val); ++ ++ (*optnum)++; ++ } ++} ++ ++static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data) ++{ ++ struct list_head *ent; ++ struct osf_finger *f = NULL; ++ int i; ++ ++ *eof = 1; ++ count = 0; ++ ++ read_lock_bh(&osf_lock); ++ list_for_each(ent, &finger_list) ++ { ++ f = list_entry(ent, struct osf_finger, flist); ++ ++ log("%s - %s: ttl=%d, wss=%c%lu, df=%d, size=%lu", ++ f->genre, f->details, f->ttl, (f->wss.wc)?f->wss.wc:' ', f->wss.val, f->df, f->ss); ++ ++ count += sprintf(buf+count, "%s - %s: ttl=%d, wss=%c%lu, df=%d, size=%lu", ++ f->genre, f->details, f->ttl, (f->wss.wc)?f->wss.wc:' ', f->wss.val, f->df, f->ss); ++ ++ if (f->opt_num) ++ { ++ loga(" OPT: "); ++ //count += sprintf(buf+count, " OPT: "); ++ for (i=0; iopt_num; ++i) ++ { ++ //count += sprintf(buf+count, "%d.%c%lu; ", ++ // f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val); ++ loga("%d.%c%lu; ", ++ f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val); ++ } ++ } ++ loga("\n"); ++ count += sprintf(buf+count, "\n"); ++ } ++ read_unlock_bh(&osf_lock); ++ ++ return count; ++} ++ ++static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ int cnt; ++ unsigned long i; ++ char quirks[MAXOPTSTRLEN], obuf[MAXOPTSTRLEN]; ++ struct osf_finger *finger; ++ struct list_head *ent, *n; ++ ++ char *pbeg, *pend; ++ ++ if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH))) ++ { ++ int i = 0; ++ write_lock_bh(&osf_lock); ++ list_for_each_safe(ent, n, &finger_list) ++ { ++ i++; ++ finger = list_entry(ent, struct osf_finger, flist); ++ list_del(&finger->flist); ++ finger_free(finger); ++ } ++ write_unlock_bh(&osf_lock); ++ ++ log("Flushed %d entries.\n", i); ++ ++ return count; ++ } ++ ++ ++ cnt = 0; ++ for (i=0; iwss.wc = 'S'; ++ if (pbeg[1] == '%') ++ finger->wss.val = simple_strtoul(pbeg+2, NULL, 10); ++ else if (pbeg[1] == '*') ++ finger->wss.val = 0; ++ else ++ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10); ++ } ++ else if (pbeg[0] == 'T') ++ { ++ finger->wss.wc = 'T'; ++ if (pbeg[1] == '%') ++ finger->wss.val = simple_strtoul(pbeg+2, NULL, 10); ++ else if (pbeg[1] == '*') ++ finger->wss.val = 0; ++ else ++ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10); ++ } ++ if (isdigit(pbeg[0])) ++ { ++ finger->wss.wc = 0; ++ finger->wss.val = simple_strtoul(pbeg, NULL, 10); ++ } ++ ++ pbeg = pend+1; ++ } ++ pend = strchr(pbeg, OSFPDEL); ++ if (pend) ++ { ++ *pend = '\0'; ++ finger->ttl = simple_strtoul(pbeg, NULL, 10); ++ pbeg = pend+1; ++ } ++ pend = strchr(pbeg, OSFPDEL); ++ if (pend) ++ { ++ *pend = '\0'; ++ finger->df = simple_strtoul(pbeg, NULL, 10); ++ pbeg = pend+1; ++ } ++ pend = strchr(pbeg, OSFPDEL); ++ if (pend) ++ { ++ *pend = '\0'; ++ finger->ss = simple_strtoul(pbeg, NULL, 10); ++ pbeg = pend+1; ++ } ++ ++ pend = strchr(pbeg, OSFPDEL); ++ if (pend) ++ { ++ *pend = '\0'; ++ cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg); ++ pbeg = pend+1; ++ } ++ ++ pend = strchr(pbeg, OSFPDEL); ++ if (pend) ++ { ++ *pend = '\0'; ++ cnt = snprintf(quirks, sizeof(quirks), "%s", pbeg); ++ pbeg = pend+1; ++ } ++ ++ pend = strchr(pbeg, OSFPDEL); ++ if (pend) ++ { ++ *pend = '\0'; ++ if (pbeg[0] == '@' || pbeg[0] == '*') ++ cnt = snprintf(finger->genre, ++ ((count-(pbeg+1-buffer)+1) > MAXGENRELEN)?MAXGENRELEN:(count-(pbeg+1-buffer)+1), ++ "%s", pbeg+1); ++ else ++ cnt = snprintf(finger->genre, ++ ((count-(pbeg-buffer)+1) > MAXGENRELEN)?MAXGENRELEN:(count-(pbeg-buffer)+1), ++ "%s", pbeg); ++ pbeg = pend+1; ++ } ++ ++ cnt = snprintf(finger->details, ++ ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), ++ "%s", pbeg); ++ ++ log("%s - %s. ttl=%d, df=%d, size=%lu, wss=[%d, %lu]\n", ++ finger->genre, finger->details, ++ finger->ttl, finger->df, finger->ss, ++ finger->wss.wc, finger->wss.val); ++ ++ osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf)); ++ ++ ++ write_lock_bh(&osf_lock); ++ list_add(&finger->flist, &finger_list); ++ write_unlock_bh(&osf_lock); ++ ++ return count; ++} ++ ++static int __init osf_init(void) ++{ ++ int err; ++ struct proc_dir_entry *p; ++ ++ log("Startng OS fingerprint matching module.\n"); ++ ++ INIT_LIST_HEAD(&finger_list); ++ ++ err = ipt_register_match(&osf_match); ++ if (err) ++ { ++ log("Failed to register OS fingerprint matching module.\n"); ++ return -ENXIO; ++ } ++ ++ p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL); ++ if (!p) ++ { ++ ipt_unregister_match(&osf_match); ++ return -ENXIO; ++ } ++ ++ p->write_proc = osf_proc_write; ++ p->read_proc = osf_proc_read; ++ ++ return 0; ++} ++ ++static void __exit osf_fini(void) ++{ ++ struct list_head *ent, *n; ++ struct osf_finger *f; ++ ++ remove_proc_entry("sys/net/ipv4/osf", NULL); ++ ipt_unregister_match(&osf_match); ++ ++ list_for_each_safe(ent, n, &finger_list) ++ { ++ f = list_entry(ent, struct osf_finger, flist); ++ list_del(&f->flist); ++ finger_free(f); ++ } ++ ++ log("OS fingerprint matching module finished.\n"); ++} ++ ++module_init(osf_init); ++module_exit(osf_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Evgeniy Polyakov "); ++MODULE_DESCRIPTION("Passive OS fingerprint matching."); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_owner.c linux-2.4.20/net/ipv4/netfilter/ipt_owner.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_owner.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_owner.c Wed Sep 24 09:17:52 2003 +@@ -2,17 +2,25 @@ + locally generated outgoing packets. + + Copyright (C) 2000 Marc Boucher ++ ++ 03/26/2003 Patrick McHardy : LOCAL_IN support + */ + #include + #include + #include ++#include ++#include ++#include + #include ++#include ++#include ++#include + + #include + #include + + static int +-match_comm(const struct sk_buff *skb, const char *comm) ++match_comm(const struct sock *sk, const char *comm) + { + struct task_struct *p; + struct files_struct *files; +@@ -28,7 +36,7 @@ + if(files) { + read_lock(&files->file_lock); + for (i=0; i < files->max_fds; i++) { +- if (fcheck_files(files, i) == skb->sk->socket->file) { ++ if (fcheck_files(files, i) == sk->socket->file) { + read_unlock(&files->file_lock); + task_unlock(p); + read_unlock(&tasklist_lock); +@@ -44,7 +52,7 @@ + } + + static int +-match_pid(const struct sk_buff *skb, pid_t pid) ++match_pid(const struct sock *sk, pid_t pid) + { + struct task_struct *p; + struct files_struct *files; +@@ -59,7 +67,7 @@ + if(files) { + read_lock(&files->file_lock); + for (i=0; i < files->max_fds; i++) { +- if (fcheck_files(files, i) == skb->sk->socket->file) { ++ if (fcheck_files(files, i) == sk->socket->file) { + read_unlock(&files->file_lock); + task_unlock(p); + read_unlock(&tasklist_lock); +@@ -75,10 +83,10 @@ + } + + static int +-match_sid(const struct sk_buff *skb, pid_t sid) ++match_sid(const struct sock *sk, pid_t sid) + { + struct task_struct *p; +- struct file *file = skb->sk->socket->file; ++ struct file *file = sk->socket->file; + int i, found=0; + + read_lock(&tasklist_lock); +@@ -119,41 +127,71 @@ + int *hotdrop) + { + const struct ipt_owner_info *info = matchinfo; +- +- if (!skb->sk || !skb->sk->socket || !skb->sk->socket->file) +- return 0; ++ struct iphdr *iph = skb->nh.iph; ++ struct sock *sk = NULL; ++ int ret = 0; ++ ++ if (out) { ++ sk = skb->sk; ++ } else { ++ if (iph->protocol == IPPROTO_TCP) { ++ struct tcphdr *tcph = ++ (struct tcphdr*)((u_int32_t*)iph + iph->ihl); ++ sk = tcp_v4_lookup(iph->saddr, tcph->source, ++ iph->daddr, tcph->dest, ++ ((struct rtable*)skb->dst)->rt_iif); ++ if (sk && sk->state == TCP_TIME_WAIT) { ++ tcp_tw_put((struct tcp_tw_bucket *)sk); ++ return ret; ++ } ++ } else if (iph->protocol == IPPROTO_UDP) { ++ struct udphdr *udph = ++ (struct udphdr*)((u_int32_t*)iph + iph->ihl); ++ sk = udp_v4_lookup(iph->saddr, udph->source, iph->daddr, ++ udph->dest, skb->dev->ifindex); ++ } ++ } ++ ++ if (!sk || !sk->socket || !sk->socket->file) ++ goto out; + + if(info->match & IPT_OWNER_UID) { +- if((skb->sk->socket->file->f_uid != info->uid) ^ ++ if((sk->socket->file->f_uid != info->uid) ^ + !!(info->invert & IPT_OWNER_UID)) +- return 0; ++ goto out; + } + + if(info->match & IPT_OWNER_GID) { +- if((skb->sk->socket->file->f_gid != info->gid) ^ ++ if((sk->socket->file->f_gid != info->gid) ^ + !!(info->invert & IPT_OWNER_GID)) +- return 0; ++ goto out; + } + + if(info->match & IPT_OWNER_PID) { +- if (!match_pid(skb, info->pid) ^ ++ if (!match_pid(sk, info->pid) ^ + !!(info->invert & IPT_OWNER_PID)) +- return 0; ++ goto out; + } + + if(info->match & IPT_OWNER_SID) { +- if (!match_sid(skb, info->sid) ^ ++ if (!match_sid(sk, info->sid) ^ + !!(info->invert & IPT_OWNER_SID)) +- return 0; ++ goto out; + } + + if(info->match & IPT_OWNER_COMM) { +- if (!match_comm(skb, info->comm) ^ ++ if (!match_comm(sk, info->comm) ^ + !!(info->invert & IPT_OWNER_COMM)) +- return 0; ++ goto out; + } + +- return 1; ++ ret = 1; ++ ++out: ++ if (in && sk) ++ sock_put(sk); ++ ++ return ret; + } + + static int +@@ -164,11 +202,19 @@ + unsigned int hook_mask) + { + if (hook_mask +- & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) { +- printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); ++ & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING) | ++ (1 << NF_IP_LOCAL_IN))) { ++ printk("ipt_owner: only valid for LOCAL_IN, LOCAL_OUT " ++ "or POST_ROUTING.\n"); + return 0; + } + ++ if ((hook_mask & (1 << NF_IP_LOCAL_IN)) ++ && ip->proto != IPPROTO_TCP && ip->proto != IPPROTO_UDP) { ++ printk("ipt_owner: only TCP or UDP can be used in LOCAL_IN\n"); ++ return 0; ++ } ++ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) + return 0; + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_pool.c linux-2.4.20/net/ipv4/netfilter/ipt_pool.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_pool.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_pool.c Wed Sep 24 09:16:59 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_psd.c linux-2.4.20/net/ipv4/netfilter/ipt_psd.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_psd.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_psd.c Wed Sep 24 09:17:01 2003 +@@ -0,0 +1,361 @@ ++/* ++ 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"); ++MODULE_AUTHOR("Dennis Koslowski "); ++ ++#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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_quota.c linux-2.4.20/net/ipv4/netfilter/ipt_quota.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_quota.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_quota.c Wed Sep 24 09:17:03 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_random.c linux-2.4.20/net/ipv4/netfilter/ipt_random.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_random.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_random.c Wed Sep 24 09:17:05 2003 +@@ -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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_realm.c linux-2.4.20/net/ipv4/netfilter/ipt_realm.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_realm.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_realm.c Wed Sep 24 09:17:09 2003 +@@ -0,0 +1,68 @@ ++/* Kernel module to match realm from routing. */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Sampsa Ranta "); ++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_realm_info *info = matchinfo; ++ struct dst_entry *dst = skb->dst; ++ u32 id; ++ ++ if(dst == NULL) ++ return 0; ++ id = dst->tclassid; ++ ++ return (info->id == (id & info->mask)) ^ info->invert; ++} ++ ++static int check(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ if (hook_mask ++ & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | ++ (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) { ++ printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, " ++ "LOCAL_IN or FORWARD.\n"); ++ return 0; ++ } ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info))) ++ return 0; ++ ++ return 1; ++} ++ ++static struct ipt_match realm_match ++= { { NULL, NULL }, "realm", &match, &check, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&realm_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&realm_match); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_recent.c linux-2.4.20/net/ipv4/netfilter/ipt_recent.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_recent.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_recent.c Wed Sep 24 09:16:20 2003 +@@ -0,0 +1,1002 @@ ++/* Kernel module to check if the source address has been seen recently. */ ++/* Copyright 2002-2003, Stephen Frost */ ++/* Author: Stephen Frost */ ++/* Project Page: http://snowman.net/projects/ipt_recent/ */ ++/* This software is distributed under the terms of the GPL, Version 2 */ ++/* This copyright does not cover user programs that use kernel services ++ * by normal system calls. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#undef DEBUG ++#define HASH_LOG 9 ++ ++/* Defaults, these can be overridden on the module command-line. */ ++static int ip_list_tot = 100; ++static int ip_pkt_list_tot = 20; ++static int ip_list_hash_size = 0; ++static int ip_list_perms = 0644; ++#ifdef DEBUG ++static int debug = 1; ++#endif ++ ++static char version[] = ++KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost . http://snowman.net/projects/ipt_recent/\n"; ++ ++MODULE_AUTHOR("Stephen Frost "); ++MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER); ++MODULE_LICENSE("GPL"); ++MODULE_PARM(ip_list_tot,"i"); ++MODULE_PARM(ip_pkt_list_tot,"i"); ++MODULE_PARM(ip_list_hash_size,"i"); ++MODULE_PARM(ip_list_perms,"i"); ++#ifdef DEBUG ++MODULE_PARM(debug,"i"); ++MODULE_PARM_DESC(debug,"debugging level, defaults to 1"); ++#endif ++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"); ++MODULE_PARM_DESC(ip_list_hash_size,"size of hash table used to look up IPs"); ++MODULE_PARM_DESC(ip_list_perms,"permissions on /proc/net/ipt_recent/* files"); ++ ++/* Structure of our list of recently seen addresses. */ ++struct recent_ip_list { ++ u_int32_t addr; ++ u_int8_t ttl; ++ u_int32_t last_seen; ++ u_int32_t *last_pkts; ++ u_int32_t oldest_pkt; ++ u_int32_t hash_entry; ++ u_int32_t time_pos; ++}; ++ ++struct time_info_list { ++ u_int32_t position; ++ u_int32_t time; ++}; ++ ++/* Structure of our linked list of tables of recent lists. */ ++struct recent_ip_tables { ++ char name[IPT_RECENT_NAME_LEN]; ++ int count; ++ int time_pos; ++ struct recent_ip_list *table; ++ struct recent_ip_tables *next; ++ spinlock_t list_lock; ++ int *hash_table; ++ struct time_info_list *time_info; ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *status_proc; ++#endif /* CONFIG_PROC_FS */ ++}; ++ ++/* 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 = NULL; ++ ++/* 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; ++ ++#ifdef CONFIG_PROC_FS ++/* Our /proc/net/ipt_recent entry */ ++static struct proc_dir_entry *proc_net_ipt_recent = NULL; ++#endif ++ ++/* 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); ++ ++/* Function to hash a given address into the hash table of table_size size */ ++int hash_func(unsigned int addr, int table_size) ++{ ++ int result = 0; ++ unsigned int value = addr; ++ do { result ^= value; } while((value >>= HASH_LOG)); ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": %d = hash_func(%u,%d)\n", ++ result & (table_size - 1), ++ addr, ++ table_size); ++#endif ++ ++ return(result & (table_size - 1)); ++} ++ ++#ifdef CONFIG_PROC_FS ++/* 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].addr) continue; ++ last_len = len; ++ len += sprintf(buffer+len,"src=%u.%u.%u.%u ",NIPQUAD(curr_table->table[count].addr)); ++ len += sprintf(buffer+len,"ttl: %u ",curr_table->table[count].ttl); ++ len += sprintf(buffer+len,"last_seen: %u ",curr_table->table[count].last_seen); ++ len += sprintf(buffer+len,"oldest_pkt: %u ",curr_table->table[count].oldest_pkt); ++ len += sprintf(buffer+len,"last_pkts: %u",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,", %u",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 ++ * clear -- 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, used = 0; ++ char c, *cp; ++ union iaddr { ++ uint8_t bytes[4]; ++ uint32_t word; ++ } res; ++ uint8_t *pp = res.bytes; ++ int digit; ++ ++ char buffer[20]; ++ int len, check_set = 0, count; ++ u_int32_t addr = 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 > 20) len = 20; else len = size; ++ ++ if(copy_from_user(buffer,input,len)) return -EFAULT; ++ ++ if(len < 20) buffer[len] = '\0'; ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl len: %d, input: `%.20s'\n",len,buffer); ++#endif ++ ++ cp = buffer; ++ while(isspace(*cp)) { cp++; used++; if(used >= len-5) return used; } ++ ++ /* Check if we are asked to flush the entire table */ ++ if(!memcmp(cp,"clear",5)) { ++ used += 5; ++ spin_lock_bh(&curr_table->list_lock); ++ curr_table->time_pos = 0; ++ for(count = 0; count < ip_list_hash_size; count++) { ++ curr_table->hash_table[count] = -1; ++ } ++ for(count = 0; count < ip_list_tot; count++) { ++ curr_table->table[count].last_seen = 0; ++ curr_table->table[count].addr = 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; ++ curr_table->table[count].time_pos = 0; ++ curr_table->time_info[count].position = count; ++ curr_table->time_info[count].time = 0; ++ } ++ spin_unlock_bh(&curr_table->list_lock); ++ return used; ++ } ++ ++ check_set = IPT_RECENT_SET; ++ switch(*cp) { ++ case '+': check_set = IPT_RECENT_SET; cp++; used++; break; ++ case '-': check_set = IPT_RECENT_REMOVE; cp++; used++; break; ++ default: if(!isdigit(*cp)) return (used+1); break; ++ } ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl cp: `%c', check_set: %d\n",*cp,check_set); ++#endif ++ /* Get addr (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 used; ++ 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 used; ++ 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 used; ++ *pp++ = val; ++ c = *++cp; ++ } else break; ++ } ++ used = cp - buffer; ++ if(c != '\0' && (!isascii(c) || !isspace(c))) return used; ++ if(c == '\n') used++; ++ if(!digit) return used; ++ ++ if(val > max[pp - res.bytes]) return used; ++ addr = res.word | htonl(val); ++ ++ if(!addr && check_set == IPT_RECENT_SET) return used; ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl c: %c, addr: %u used: %d\n",c,addr,used); ++#endif ++ ++ /* Set up and just call match */ ++ info = kmalloc(sizeof(struct ipt_recent_info),GFP_KERNEL); ++ if(!info) { return -ENOMEM; } ++ info->seconds = 0; ++ info->hit_count = 0; ++ info->check_set = check_set; ++ info->invert = 0; ++ info->side = IPT_RECENT_SOURCE; ++ strncpy(info->name,curr_table->name,IPT_RECENT_NAME_LEN); ++ info->name[IPT_RECENT_NAME_LEN-1] = '\0'; ++ ++ skb = kmalloc(sizeof(struct sk_buff),GFP_KERNEL); ++ if (!skb) { ++ used = -ENOMEM; ++ goto out_free_info; ++ } ++ skb->nh.iph = kmalloc(sizeof(struct iphdr),GFP_KERNEL); ++ if (!skb->nh.iph) { ++ used = -ENOMEM; ++ goto out_free_skb; ++ } ++ ++ skb->nh.iph->saddr = addr; ++ skb->nh.iph->daddr = 0; ++ /* Clear ttl since we have no way of knowing it */ ++ skb->nh.iph->ttl = 0; ++ match(skb,NULL,NULL,info,0,NULL,sizeof(struct ipt_recent_info),NULL); ++ ++ kfree(skb->nh.iph); ++out_free_skb: ++ kfree(skb); ++out_free_info: ++ kfree(info); ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": Leaving ip_recent_ctrl addr: %u used: %d\n",addr,used); ++#endif ++ return used; ++} ++ ++#endif /* CONFIG_PROC_FS */ ++ ++/* '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 pkt_count, hits_found, ans; ++ unsigned long now; ++ const struct ipt_recent_info *info = matchinfo; ++ u_int32_t addr = 0, time_temp; ++ u_int8_t ttl = skb->nh.iph->ttl; ++ int *hash_table; ++ int orig_hash_result, hash_result, temp, location = 0, time_loc, end_collision_chain = -1; ++ struct time_info_list *time_info; ++ struct recent_ip_tables *curr_table; ++ struct recent_ip_tables *last_table; ++ struct recent_ip_list *r_list; ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match() called\n"); ++#endif ++ ++ /* Default is false ^ info->invert */ ++ ans = info->invert; ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): name = '%s'\n",info->name); ++#endif ++ ++ /* if out != NULL then routing has been done and TTL changed. ++ * We change it back here internally for match what came in before routing. */ ++ if(out) ttl++; ++ ++ /* Find the right table */ ++ spin_lock_bh(&recent_lock); ++ curr_table = r_tables; ++ while( (last_table = curr_table) && strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (curr_table = curr_table->next) ); ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): table found('%s')\n",info->name); ++#endif ++ ++ 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; ++ if(info->side == IPT_RECENT_DEST) addr = skb->nh.iph->daddr; else addr = skb->nh.iph->saddr; ++ ++ if(!addr) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match() address (%u) invalid, leaving.\n",addr); ++#endif ++ spin_unlock_bh(&curr_table->list_lock); ++ return ans; ++ } ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): checking table, addr: %u, ttl: %u, orig_ttl: %u\n",addr,ttl,skb->nh.iph->ttl); ++#endif ++ ++ /* Get jiffies now in case they changed while we were waiting for a lock */ ++ now = jiffies; ++ hash_table = curr_table->hash_table; ++ time_info = curr_table->time_info; ++ ++ orig_hash_result = hash_result = hash_func(addr,ip_list_hash_size); ++ /* Hash entry at this result used */ ++ /* 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) { ++ while(hash_table[hash_result] != -1 && !(r_list[hash_table[hash_result]].addr == addr && ++ (!r_list[hash_table[hash_result]].ttl || r_list[hash_table[hash_result]].ttl == ttl))) { ++ /* Collision in hash table */ ++ hash_result = (hash_result + 1) % ip_list_hash_size; ++ } ++ } else { ++ while(hash_table[hash_result] != -1 && r_list[hash_table[hash_result]].addr != addr) { ++ /* Collision in hash table */ ++ hash_result = (hash_result + 1) % ip_list_hash_size; ++ } ++ } ++ ++ if(hash_table[hash_result] == -1 && !(info->check_set & IPT_RECENT_SET)) { ++ /* IP not in list and not asked to SET */ ++ spin_unlock_bh(&curr_table->list_lock); ++ return ans; ++ } ++ ++ /* Check if we need to handle the collision, do not need to on REMOVE */ ++ if(orig_hash_result != hash_result && !(info->check_set & IPT_RECENT_REMOVE)) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision in hash table. (or: %d,hr: %d,oa: %u,ha: %u)\n", ++ orig_hash_result, ++ hash_result, ++ r_list[hash_table[orig_hash_result]].addr, ++ addr); ++#endif ++ ++ /* We had a collision. ++ * orig_hash_result is where we started, hash_result is where we ended up. ++ * So, swap them because we are likely to see the same guy again sooner */ ++#ifdef DEBUG ++ if(debug) { ++ printk(KERN_INFO RECENT_NAME ": match(): Collision; hash_table[orig_hash_result] = %d\n",hash_table[orig_hash_result]); ++ printk(KERN_INFO RECENT_NAME ": match(): Collision; r_list[hash_table[orig_hash_result]].hash_entry = %d\n", ++ r_list[hash_table[orig_hash_result]].hash_entry); ++ } ++#endif ++ ++ r_list[hash_table[orig_hash_result]].hash_entry = hash_result; ++ ++ ++ temp = hash_table[orig_hash_result]; ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision; hash_table[hash_result] = %d\n",hash_table[hash_result]); ++#endif ++ hash_table[orig_hash_result] = hash_table[hash_result]; ++ hash_table[hash_result] = temp; ++ temp = hash_result; ++ hash_result = orig_hash_result; ++ orig_hash_result = temp; ++ time_info[r_list[hash_table[orig_hash_result]].time_pos].position = hash_table[orig_hash_result]; ++ if(hash_table[hash_result] != -1) { ++ r_list[hash_table[hash_result]].hash_entry = hash_result; ++ time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result]; ++ } ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision handled.\n"); ++#endif ++ } ++ ++ if(hash_table[hash_result] == -1) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): New table entry. (hr: %d,ha: %u)\n", ++ hash_result, addr); ++#endif ++ ++ /* New item found and IPT_RECENT_SET, so we need to add it */ ++ location = time_info[curr_table->time_pos].position; ++ hash_table[r_list[location].hash_entry] = -1; ++ hash_table[hash_result] = location; ++ memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); ++ r_list[location].time_pos = curr_table->time_pos; ++ r_list[location].addr = addr; ++ r_list[location].ttl = ttl; ++ r_list[location].last_seen = now; ++ r_list[location].oldest_pkt = 1; ++ r_list[location].last_pkts[0] = now; ++ r_list[location].hash_entry = hash_result; ++ time_info[curr_table->time_pos].time = r_list[location].last_seen; ++ curr_table->time_pos = (curr_table->time_pos + 1) % ip_list_tot; ++ ++ ans = !info->invert; ++ } else { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): Existing table entry. (hr: %d,ha: %u)\n", ++ hash_result, ++ addr); ++#endif ++ ++ /* Existing item found */ ++ location = hash_table[hash_result]; ++ /* We have a match on address, now to make sure it meets all requirements for a ++ * full match. */ ++ 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_eq(now,r_list[location].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_eq(now,r_list[location].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[location].last_pkts[pkt_count] == 0) break; ++ hits_found++; ++ } ++ if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert; ++ } ++ } ++#ifdef DEBUG ++ if(debug) { ++ if(ans) ++ printk(KERN_INFO RECENT_NAME ": match(): match addr: %u\n",addr); ++ else ++ printk(KERN_INFO RECENT_NAME ": match(): no match addr: %u\n",addr); ++ } ++#endif ++ ++ /* 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)) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): SET or UPDATE; updating time info.\n"); ++#endif ++ /* Have to update our time info */ ++ time_loc = r_list[location].time_pos; ++ time_info[time_loc].time = now; ++ time_info[time_loc].position = location; ++ while((time_info[(time_loc+1) % ip_list_tot].time < time_info[time_loc].time) && ((time_loc+1) % ip_list_tot) != curr_table->time_pos) { ++ time_temp = time_info[time_loc].time; ++ time_info[time_loc].time = time_info[(time_loc+1)%ip_list_tot].time; ++ time_info[(time_loc+1)%ip_list_tot].time = time_temp; ++ time_temp = time_info[time_loc].position; ++ time_info[time_loc].position = time_info[(time_loc+1)%ip_list_tot].position; ++ time_info[(time_loc+1)%ip_list_tot].position = time_temp; ++ r_list[time_info[time_loc].position].time_pos = time_loc; ++ r_list[time_info[(time_loc+1)%ip_list_tot].position].time_pos = (time_loc+1)%ip_list_tot; ++ time_loc = (time_loc+1) % ip_list_tot; ++ } ++ r_list[location].time_pos = time_loc; ++ r_list[location].ttl = ttl; ++ r_list[location].last_pkts[r_list[location].oldest_pkt] = now; ++ r_list[location].oldest_pkt = ++r_list[location].oldest_pkt % ip_pkt_list_tot; ++ r_list[location].last_seen = now; ++ } ++ /* If we have been asked to remove the entry from the list, just set it to 0 */ ++ if(info->check_set & IPT_RECENT_REMOVE) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; clearing entry (or: %d, hr: %d).\n",orig_hash_result,hash_result); ++#endif ++ /* Check if this is part of a collision chain */ ++ while(hash_table[(orig_hash_result+1) % ip_list_hash_size] != -1) { ++ orig_hash_result++; ++ if(hash_func(r_list[hash_table[orig_hash_result]].addr,ip_list_hash_size) == hash_result) { ++ /* Found collision chain, how deep does this rabbit hole go? */ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; found collision chain.\n"); ++#endif ++ end_collision_chain = orig_hash_result; ++ } ++ } ++ if(end_collision_chain != -1) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; part of collision chain, moving to end.\n"); ++#endif ++ /* Part of a collision chain, swap it with the end of the chain ++ * before removing. */ ++ r_list[hash_table[end_collision_chain]].hash_entry = hash_result; ++ temp = hash_table[end_collision_chain]; ++ hash_table[end_collision_chain] = hash_table[hash_result]; ++ hash_table[hash_result] = temp; ++ time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result]; ++ hash_result = end_collision_chain; ++ r_list[hash_table[hash_result]].hash_entry = hash_result; ++ time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result]; ++ } ++ location = hash_table[hash_result]; ++ hash_table[r_list[location].hash_entry] = -1; ++ time_loc = r_list[location].time_pos; ++ time_info[time_loc].time = 0; ++ time_info[time_loc].position = location; ++ while((time_info[(time_loc+1) % ip_list_tot].time < time_info[time_loc].time) && ((time_loc+1) % ip_list_tot) != curr_table->time_pos) { ++ time_temp = time_info[time_loc].time; ++ time_info[time_loc].time = time_info[(time_loc+1)%ip_list_tot].time; ++ time_info[(time_loc+1)%ip_list_tot].time = time_temp; ++ time_temp = time_info[time_loc].position; ++ time_info[time_loc].position = time_info[(time_loc+1)%ip_list_tot].position; ++ time_info[(time_loc+1)%ip_list_tot].position = time_temp; ++ r_list[time_info[time_loc].position].time_pos = time_loc; ++ r_list[time_info[(time_loc+1)%ip_list_tot].position].time_pos = (time_loc+1)%ip_list_tot; ++ time_loc = (time_loc+1) % ip_list_tot; ++ } ++ r_list[location].time_pos = time_loc; ++ r_list[location].last_seen = 0; ++ r_list[location].addr = 0; ++ r_list[location].ttl = 0; ++ memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); ++ r_list[location].oldest_pkt = 0; ++ ans = !info->invert; ++ } ++ spin_unlock_bh(&curr_table->list_lock); ++ return ans; ++ } ++ ++ spin_unlock_bh(&curr_table->list_lock); ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": match() left.\n"); ++#endif ++ 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, *find_table, *last_table; ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n"); ++#endif ++ ++ 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 */ ++ find_table = r_tables; ++ while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) ); ++ ++ /* If a table already exists just increment the count on that table and return */ ++ if(find_table) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), incrementing count.\n",info->name); ++#endif ++ find_table->count++; ++ spin_unlock_bh(&recent_lock); ++ return 1; ++ } ++ ++ spin_unlock_bh(&recent_lock); ++ ++ /* Table with this name not found */ ++ /* Allocate memory for new linked list item */ ++ ++#ifdef DEBUG ++ if(debug) { ++ printk(KERN_INFO RECENT_NAME ": checkentry: no table found (%s)\n",info->name); ++ printk(KERN_INFO RECENT_NAME ": checkentry: Allocationg %d for link-list entry.\n",sizeof(struct recent_ip_tables)); ++ } ++#endif ++ ++ curr_table = vmalloc(sizeof(struct recent_ip_tables)); ++ if(curr_table == NULL) return -ENOMEM; ++ ++ curr_table->list_lock = SPIN_LOCK_UNLOCKED; ++ curr_table->next = NULL; ++ curr_table->count = 1; ++ curr_table->time_pos = 0; ++ strncpy(curr_table->name,info->name,IPT_RECENT_NAME_LEN); ++ curr_table->name[IPT_RECENT_NAME_LEN-1] = '\0'; ++ ++ /* Allocate memory for this table and the list of packets in each entry. */ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for table (%s).\n", ++ sizeof(struct recent_ip_list)*ip_list_tot, ++ info->name); ++#endif ++ ++ curr_table->table = vmalloc(sizeof(struct recent_ip_list)*ip_list_tot); ++ if(curr_table->table == NULL) { vfree(curr_table); return -ENOMEM; } ++ memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot); ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n", ++ sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot); ++#endif ++ ++ hold = vmalloc(sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot); ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n"); ++#endif ++ if(hold == NULL) { ++ printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for pkt_list.\n"); ++ vfree(curr_table->table); ++ vfree(curr_table); ++ return -ENOMEM; ++ } ++ for(c = 0; c < ip_list_tot; c++) { ++ curr_table->table[c].last_pkts = hold + c*ip_pkt_list_tot; ++ } ++ ++ /* Allocate memory for the hash table */ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for hash_table.\n", ++ sizeof(int)*ip_list_hash_size); ++#endif ++ ++ curr_table->hash_table = vmalloc(sizeof(int)*ip_list_hash_size); ++ if(!curr_table->hash_table) { ++ printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for hash_table.\n"); ++ vfree(hold); ++ vfree(curr_table->table); ++ vfree(curr_table); ++ return -ENOMEM; ++ } ++ ++ for(c = 0; c < ip_list_hash_size; c++) { ++ curr_table->hash_table[c] = -1; ++ } ++ ++ /* Allocate memory for the time info */ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for time_info.\n", ++ sizeof(struct time_info_list)*ip_list_tot); ++#endif ++ ++ curr_table->time_info = vmalloc(sizeof(struct time_info_list)*ip_list_tot); ++ if(!curr_table->time_info) { ++ printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for time_info.\n"); ++ vfree(curr_table->hash_table); ++ vfree(hold); ++ vfree(curr_table->table); ++ vfree(curr_table); ++ return -ENOMEM; ++ } ++ for(c = 0; c < ip_list_tot; c++) { ++ curr_table->time_info[c].position = c; ++ curr_table->time_info[c].time = 0; ++ } ++ ++ /* Put the new table in place */ ++ spin_lock_bh(&recent_lock); ++ find_table = r_tables; ++ while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) ); ++ ++ /* If a table already exists just increment the count on that table and return */ ++ if(find_table) { ++ find_table->count++; ++ spin_unlock_bh(&recent_lock); ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), created by other process.\n",info->name); ++#endif ++ vfree(curr_table->time_info); ++ vfree(curr_table->hash_table); ++ vfree(hold); ++ vfree(curr_table->table); ++ vfree(curr_table); ++ return 1; ++ } ++ if(!last_table) r_tables = curr_table; else last_table->next = curr_table; ++ ++ spin_unlock_bh(&recent_lock); ++ ++#ifdef CONFIG_PROC_FS ++ /* Create our proc 'status' entry. */ ++ curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent); ++ if (!curr_table->status_proc) { ++ printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n"); ++ /* Destroy the created table */ ++ spin_lock_bh(&recent_lock); ++ last_table = NULL; ++ curr_table = r_tables; ++ if(!curr_table) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, no tables.\n"); ++#endif ++ spin_unlock_bh(&recent_lock); ++ return -ENOMEM; ++ } ++ while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) ); ++ if(!curr_table) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, table already destroyed.\n"); ++#endif ++ spin_unlock_bh(&recent_lock); ++ return -ENOMEM; ++ } ++ if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next; ++ spin_unlock_bh(&recent_lock); ++ vfree(curr_table->time_info); ++ vfree(curr_table->hash_table); ++ vfree(hold); ++ vfree(curr_table->table); ++ vfree(curr_table); ++ return -ENOMEM; ++ } ++ ++ curr_table->status_proc->owner = THIS_MODULE; ++ curr_table->status_proc->data = curr_table; ++ wmb(); ++ curr_table->status_proc->read_proc = ip_recent_get_info; ++ curr_table->status_proc->write_proc = ip_recent_ctrl; ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() left.\n"); ++#endif ++ ++ 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; ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": destroy() entered.\n"); ++#endif ++ ++ 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) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": destroy() No tables found, leaving.\n"); ++#endif ++ spin_unlock_bh(&recent_lock); ++ return; ++ } ++ while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) ); ++ ++ /* If a table does not exist then do nothing and return */ ++ if(!curr_table) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table not found, leaving.\n"); ++#endif ++ 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) { ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, non-zero count, leaving.\n"); ++#endif ++ spin_unlock_bh(&recent_lock); ++ return; ++ } ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, zero count, removing.\n"); ++#endif ++ ++ /* 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; ++ ++ spin_unlock_bh(&recent_lock); ++ ++ /* 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); ++ spin_unlock_bh(&curr_table->list_lock); ++ ++#ifdef CONFIG_PROC_FS ++ if(curr_table->status_proc) remove_proc_entry(curr_table->name,proc_net_ipt_recent); ++#endif /* CONFIG_PROC_FS */ ++ vfree(curr_table->table[0].last_pkts); ++ vfree(curr_table->table); ++ vfree(curr_table->hash_table); ++ vfree(curr_table->time_info); ++ vfree(curr_table); ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": destroy() left.\n"); ++#endif ++ ++ return; ++} ++ ++/* This is the structure we pass to ipt_register to register our ++ * module with iptables. ++ */ ++static struct ipt_match recent_match = { ++ .name = "recent", ++ .match = &match, ++ .checkentry = &checkentry, ++ .destroy = &destroy, ++ .me = THIS_MODULE ++}; ++ ++/* Kernel module initialization. */ ++static int __init init(void) ++{ ++ int count; ++ ++ printk(version); ++#ifdef CONFIG_PROC_FS ++ proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net); ++ if(!proc_net_ipt_recent) return -ENOMEM; ++#endif ++ ++ if(ip_list_hash_size && ip_list_hash_size <= ip_list_tot) { ++ printk(KERN_WARNING RECENT_NAME ": ip_list_hash_size too small, resetting to default.\n"); ++ ip_list_hash_size = 0; ++ } ++ ++ if(!ip_list_hash_size) { ++ ip_list_hash_size = ip_list_tot*3; ++ count = 2*2; ++ while(ip_list_hash_size > count) count = count*2; ++ ip_list_hash_size = count; ++ } ++ ++#ifdef DEBUG ++ if(debug) printk(KERN_INFO RECENT_NAME ": ip_list_hash_size: %d\n",ip_list_hash_size); ++#endif ++ ++ 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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_rpc.c linux-2.4.20/net/ipv4/netfilter/ipt_rpc.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_rpc.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_rpc.c Wed Sep 24 09:18:01 2003 +@@ -0,0 +1,428 @@ ++/* RPC extension for IP connection matching, Version 2.2 ++ * (C) 2000 by Marcelo Barbosa Lima ++ * - original rpc tracking module ++ * - "recent" connection handling for kernel 2.3+ netfilter ++ * ++ * (C) 2001 by Rusty Russell ++ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ ++ * ++ * (C) 2002,2003 by Ian (Larry) Latter ++ * - upgraded conntrack modules to newnat api - kernel 2.4.20+ ++ * - extended matching to support filtering on procedures ++ * ++ * ipt_rpc.c,v 2.2 2003/01/12 18:30:00 ++ * ++ * 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 ipt_rpc.o ports=port1,port2,...port ++ * ++ * Please give the ports of all RPC servers you wish to connect to. ++ * If you don't specify ports, the default will be port 111. ++ ** ++ * Note to all: ++ * ++ * RPCs should not be exposed to the internet - ask the Pentagon; ++ * ++ * "The unidentified crackers pleaded guilty in July to charges ++ * of juvenile delinquency stemming from a string of Pentagon ++ * network intrusions in February. ++ * ++ * The youths, going by the names TooShort and Makaveli, used ++ * a common server security hole to break in, according to ++ * Dane Jasper, owner of the California Internet service ++ * provider, Sonic. They used the hole, known as the 'statd' ++ * exploit, to attempt more than 800 break-ins, Jasper said." ++ * ++ * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 ++ * URL: http://www.wired.com/news/politics/0,1283,16098,00.html ++ ** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_n_c = 0; ++ ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers"); ++#endif ++ ++MODULE_AUTHOR("Marcelo Barbosa Lima "); ++MODULE_DESCRIPTION("RPC connection matching module"); ++MODULE_LICENSE("GPL"); ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG "ipt_rpc: " \ ++ format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++EXPORT_NO_SYMBOLS; ++ ++/* vars from ip_conntrack_rpc_tcp */ ++extern struct list_head request_p_list_tcp; ++extern struct module *ip_conntrack_rpc_tcp; ++ ++/* vars from ip_conntrack_rpc_udp */ ++extern struct list_head request_p_list_udp; ++extern struct module *ip_conntrack_rpc_udp; ++ ++DECLARE_RWLOCK_EXTERN(ipct_rpc_tcp_lock); ++DECLARE_RWLOCK_EXTERN(ipct_rpc_udp_lock); ++ ++#define ASSERT_READ_LOCK(x) \ ++do { \ ++ if (x == &request_p_list_udp) \ ++ MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock); \ ++ else if (x == &request_p_list_tcp) \ ++ MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock); \ ++} while (0) ++ ++#define ASSERT_WRITE_LOCK(x) \ ++do { \ ++ if (x == &request_p_list_udp) \ ++ MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock); \ ++ else if (x == &request_p_list_tcp) \ ++ MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock); \ ++} while (0) ++ ++#include ++ ++const int IPT_RPC_CHAR_LEN = 11; ++ ++ ++static int k_atoi(char *string) ++{ ++ unsigned int result = 0; ++ int maxoctet = IPT_RPC_CHAR_LEN; ++ ++ for ( ; *string != 0 && maxoctet != 0; maxoctet--, string++) { ++ if (*string < 0) ++ return(0); ++ if (*string == 0) ++ break; ++ if (*string < 48 || *string > 57) { ++ return(0); ++ } ++ result = result * 10 + ( *string - 48 ); ++ } ++ return(result); ++} ++ ++ ++static int match_rpcs(char *c_procs, int i_procs, int proc) ++{ ++ int proc_ctr; ++ char *proc_ptr; ++ unsigned int proc_num; ++ ++ DEBUGP("entered match_rpcs [%i] [%i] ..\n", i_procs, proc); ++ ++ if (i_procs == -1) ++ return 1; ++ ++ for (proc_ctr=0; proc_ctr <= i_procs; proc_ctr++) { ++ ++ proc_ptr = c_procs; ++ proc_ptr += proc_ctr * IPT_RPC_CHAR_LEN; ++ proc_num = k_atoi(proc_ptr); ++ ++ if (proc_num == proc) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++static int check_rpc_packet(const u_int32_t *data, const void *matchinfo, ++ int *hotdrop, int dir, struct ip_conntrack *ct, ++ int offset, struct list_head request_p_list) ++{ ++ const struct ipt_rpc_info *rpcinfo = matchinfo; ++ struct request_p *req_p; ++ u_int32_t xid; ++ ++ ++ /* Get XID */ ++ xid = *data; ++ ++ /* This does sanity checking on RPC payloads, ++ * and permits only the RPC "get port" (3) ++ * in authorised procedures in client ++ * communications with the portmapper. ++ */ ++ ++ data += 5; ++ ++ /* Get RPC requestor */ ++ if (IXDR_GET_INT32(data) != 3) { ++ DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n"); ++ if(rpcinfo->strict == 1) ++ *hotdrop = 1; ++ return 0; ++ } ++ DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n"); ++ ++ data++; ++ ++ /* Jump Credentials and Verfifier */ ++ data = data + IXDR_GET_INT32(data) + 2; ++ data = data + IXDR_GET_INT32(data) + 2; ++ ++ /* Get RPC procedure */ ++ if (match_rpcs((char *)&rpcinfo->c_procs, ++ rpcinfo->i_procs, IXDR_GET_INT32(data)) == 0) { ++ DEBUGP("RPC packet contains illegal procedure request [%u]. [drop]\n", ++ (unsigned int)IXDR_GET_INT32(data)); ++ ++ /* If the RPC conntrack half entry already exists .. */ ++ ++ switch (ct->tuplehash[0].tuple.dst.protonum) { ++ case IPPROTO_UDP: ++ WRITE_LOCK(&ipct_rpc_udp_lock); ++ case IPPROTO_TCP: ++ WRITE_LOCK(&ipct_rpc_tcp_lock); ++ } ++ req_p = LIST_FIND(&request_p_list, request_p_cmp, ++ struct request_p *, xid, ++ ct->tuplehash[dir].tuple.src.ip, ++ ct->tuplehash[dir].tuple.src.u.all); ++ ++ if (req_p) { ++ DEBUGP("found req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n", ++ xid, ct->tuplehash[dir].tuple.dst.protonum, ++ NIPQUAD(ct->tuplehash[dir].tuple.src.ip), ++ ntohs(ct->tuplehash[dir].tuple.src.u.all)); ++ ++ /* .. remove it */ ++ if (del_timer(&req_p->timeout)) ++ req_p->timeout.expires = 0; ++ ++ LIST_DELETE(&request_p_list, req_p); ++ DEBUGP("RPC req_p removed. [done]\n"); ++ ++ } else { ++ DEBUGP("no req_p found for xid=%u proto=%u %u.%u.%u.%u:%u\n", ++ xid, ct->tuplehash[dir].tuple.dst.protonum, ++ NIPQUAD(ct->tuplehash[dir].tuple.src.ip), ++ ntohs(ct->tuplehash[dir].tuple.src.u.all)); ++ ++ } ++ switch (ct->tuplehash[0].tuple.dst.protonum) { ++ case IPPROTO_UDP: ++ WRITE_UNLOCK(&ipct_rpc_udp_lock); ++ case IPPROTO_TCP: ++ WRITE_UNLOCK(&ipct_rpc_tcp_lock); ++ } ++ ++ if(rpcinfo->strict == 1) ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ DEBUGP("RPC packet contains authorised procedure request [%u]. [match]\n", ++ (unsigned int)IXDR_GET_INT32(data)); ++ return (1 && (!offset)); ++} ++ ++ ++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 ip_conntrack *ct; ++ enum ip_conntrack_info ctinfo; ++ const u_int32_t *data; ++ enum ip_conntrack_dir dir; ++ const struct tcphdr *tcp; ++ const struct ipt_rpc_info *rpcinfo = matchinfo; ++ int port, portsok; ++ int tval; ++ ++ ++ DEBUGP("new packet to evaluate ..\n"); ++ ++ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); ++ if (!ct) { ++ DEBUGP("no ct available [skip]\n"); ++ return 0; ++ } ++ ++ DEBUGP("ct detected. [cont]\n"); ++ dir = CTINFO2DIR(ctinfo); ++ ++ /* we only want the client to server packets for matching */ ++ if (dir != IP_CT_DIR_ORIGINAL) ++ return 0; ++ ++ /* This does sanity checking on UDP or TCP packets, ++ * like their respective modules. ++ */ ++ ++ switch (ct->tuplehash[0].tuple.dst.protonum) { ++ ++ case IPPROTO_UDP: ++ DEBUGP("PROTO_UDP [cont]\n"); ++ if (offset == 0 && datalen < sizeof(struct udphdr)) { ++ DEBUGP("packet does not contain a complete header. [drop]\n"); ++ return 0; ++ } ++ ++ for (port=0,portsok=0; port <= ports_n_c; port++) { ++ if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) { ++ portsok++; ++ break; ++ } ++ } ++ if (portsok == 0) { ++ DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n", ++ ntohs(ct->tuplehash[dir].tuple.dst.u.all)); ++ return 0; ++ } ++ ++ if ((datalen - sizeof(struct udphdr)) != 56) { ++ DEBUGP("packet length is not correct for RPC content. [skip]\n"); ++ if (rpcinfo->strict == 1) ++ *hotdrop = 1; ++ return 0; ++ } ++ DEBUGP("packet length is correct. [cont]\n"); ++ ++ /* Get to the data */ ++ data = (const u_int32_t *)hdr + 2; ++ ++ /* Check the RPC data */ ++ tval = check_rpc_packet(data, matchinfo, hotdrop, ++ dir, ct, offset, ++ request_p_list_udp); ++ ++ return tval; ++ ++ ++ case IPPROTO_TCP: ++ DEBUGP("PROTO_TCP [cont]\n"); ++ if (offset == 0 && datalen < sizeof(struct tcphdr)) { ++ DEBUGP("packet does not contain a complete header. [drop]\n"); ++ return 0; ++ } ++ ++ for (port=0,portsok=0; port <= ports_n_c; port++) { ++ if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) { ++ portsok++; ++ break; ++ } ++ } ++ if (portsok == 0) { ++ DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n", ++ ntohs(ct->tuplehash[dir].tuple.dst.u.all)); ++ return 0; ++ } ++ ++ tcp = hdr; ++ if (datalen == (tcp->doff * 4)) { ++ DEBUGP("packet does not contain any data. [match]\n"); ++ return (1 && (!offset)); ++ } ++ ++ /* Tests if packet len is ok */ ++ if ((datalen - (tcp->doff * 4)) != 60) { ++ DEBUGP("packet length is not correct for RPC content. [skip]\n"); ++ if(rpcinfo->strict == 1) ++ *hotdrop = 1; ++ return 0; ++ } ++ DEBUGP("packet length is correct. [cont]\n"); ++ ++ /* Get to the data */ ++ data = (const u_int32_t *)tcp + tcp->doff + 1; ++ ++ /* Check the RPC data */ ++ tval = check_rpc_packet(data, matchinfo, hotdrop, ++ dir, ct, offset, ++ request_p_list_tcp); ++ ++ return tval; ++ ++ } ++ ++ DEBUGP("transport protocol=%u, is not supported [skip]\n", ++ ct->tuplehash[0].tuple.dst.protonum); ++ return 0; ++} ++ ++ ++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_FORWARD) | (1 << NF_IP_POST_ROUTING) ++ | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) { ++ printk("ipt_rpc: only valid for PRE_ROUTING, FORWARD, POST_ROUTING, LOCAL_IN and/or LOCAL_OUT targets.\n"); ++ return 0; ++ } ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_rpc_info))) ++ return 0; ++ ++ return 1; ++} ++ ++ ++static struct ipt_match rpc_match = { { NULL, NULL }, "rpc", ++ &match, &checkentry, NULL, ++ THIS_MODULE }; ++ ++ ++static int __init init(void) ++{ ++ int port; ++ ++ DEBUGP("incrementing usage counts\n"); ++ __MOD_INC_USE_COUNT(ip_conntrack_rpc_udp); ++ __MOD_INC_USE_COUNT(ip_conntrack_rpc_tcp); ++ ++ /* If no port given, default to standard RPC port */ ++ if (ports[0] == 0) ++ ports[0] = RPC_PORT; ++ ++ DEBUGP("registering match [%s] for;\n", rpc_match.name); ++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { ++ DEBUGP(" port %i (UDP|TCP);\n", ports[port]); ++ ports_n_c++; ++ } ++ ++ return ipt_register_match(&rpc_match); ++} ++ ++ ++static void fini(void) ++{ ++ DEBUGP("unregistering match\n"); ++ ipt_unregister_match(&rpc_match); ++ ++ DEBUGP("decrementing usage counts\n"); ++ __MOD_DEC_USE_COUNT(ip_conntrack_rpc_tcp); ++ __MOD_DEC_USE_COUNT(ip_conntrack_rpc_udp); ++} ++ ++ ++module_init(init); ++module_exit(fini); ++ +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_state.c linux-2.4.20/net/ipv4/netfilter/ipt_state.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_state.c Sun Sep 30 19:26:08 2001 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_state.c Wed Sep 24 09:18:12 2003 +@@ -21,7 +21,9 @@ + enum ip_conntrack_info ctinfo; + unsigned int statebit; + +- if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) ++ if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW]) ++ statebit = IPT_STATE_UNTRACKED; ++ else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) + statebit = IPT_STATE_INVALID; + else + statebit = IPT_STATE_BIT(ctinfo); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_string.c linux-2.4.20/net/ipv4/netfilter/ipt_string.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_string.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_string.c Wed Sep 24 09:18:05 2003 +@@ -0,0 +1,218 @@ ++/* Kernel module to match a string into a packet. ++ * ++ * Copyright (C) 2000 Emmanuel Roger ++ * ++ * ChangeLog ++ * 19.02.2002: Gianni Tedesco ++ * Fixed SMP re-entrancy problem using per-cpu data areas ++ * for the skip/shift tables. ++ * 02.05.2001: Gianni Tedesco ++ * Fixed kernel panic, due to overrunning boyer moore string ++ * tables. Also slightly tweaked heuristic for deciding what ++ * search algo to use. ++ * 27.01.2001: Gianni Tedesco ++ * Implemented Boyer Moore Sublinear search algorithm ++ * alongside the existing linear search based on memcmp(). ++ * Also a quick check to decide which method to use on a per ++ * packet basis. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++struct string_per_cpu { ++ int *skip; ++ int *shift; ++ int *len; ++}; ++ ++struct string_per_cpu *bm_string_data=NULL; ++ ++/* Boyer Moore Sublinear string search - VERY FAST */ ++char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len) ++{ ++ int M1, right_end, sk, sh; ++ int ended, j, i; ++ ++ int *skip, *shift, *len; ++ ++ /* use data suitable for this CPU */ ++ shift=bm_string_data[smp_processor_id()].shift; ++ skip=bm_string_data[smp_processor_id()].skip; ++ len=bm_string_data[smp_processor_id()].len; ++ ++ /* Setup skip/shift tables */ ++ M1 = right_end = needle_len-1; ++ for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len; ++ for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i; ++ ++ for (i = 1; i < needle_len; i++) { ++ for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++); ++ len[i] = j; ++ } ++ ++ shift[0] = 1; ++ for (i = 1; i < needle_len; i++) shift[i] = needle_len; ++ for (i = M1; i > 0; i--) shift[len[i]] = i; ++ ended = 0; ++ ++ for (i = 0; i < needle_len; i++) { ++ if (len[i] == M1 - i) ended = i; ++ if (ended) shift[i] = ended; ++ } ++ ++ /* Do the search*/ ++ while (right_end < haystack_len) ++ { ++ for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++); ++ if (i == needle_len) { ++ return haystack+(right_end - M1); ++ } ++ ++ sk = skip[haystack[right_end - i]]; ++ sh = shift[i]; ++ right_end = max(right_end - i + sk, right_end + sh); ++ } ++ ++ return NULL; ++} ++ ++/* Linear string search based on memcmp() */ ++char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len) ++{ ++ char *k = haystack + (haystack_len-needle_len); ++ char *t = haystack; ++ ++ while ( t <= k ) { ++ if (memcmp(t, needle, needle_len) == 0) ++ return t; ++ t++; ++ } ++ ++ return NULL; ++} ++ ++ ++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_string_info *info = matchinfo; ++ struct iphdr *ip = skb->nh.iph; ++ int hlen, nlen; ++ char *needle, *haystack; ++ proc_ipt_search search=search_linear; ++ ++ if ( !ip ) return 0; ++ ++ /* get lenghts, and validate them */ ++ nlen=info->len; ++ hlen=ntohs(ip->tot_len)-(ip->ihl*4); ++ if ( nlen > hlen ) return 0; ++ ++ needle=(char *)&info->string; ++ haystack=(char *)ip+(ip->ihl*4); ++ ++ /* The sublinear search comes in to its own ++ * on the larger packets */ ++ if ( (hlen>IPT_STRING_HAYSTACK_THRESH) && ++ (nlen>IPT_STRING_NEEDLE_THRESH) ) { ++ if ( hlen < BM_MAX_HLEN ) { ++ search=search_sublinear; ++ }else{ ++ if (net_ratelimit()) ++ printk(KERN_INFO "ipt_string: Packet too big " ++ "to attempt sublinear string search " ++ "(%d bytes)\n", hlen ); ++ } ++ } ++ ++ return ((search(needle, haystack, nlen, hlen)!=NULL) ^ 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_string_info))) ++ return 0; ++ ++ return 1; ++} ++ ++void string_freeup_data(void) ++{ ++ int c; ++ ++ if ( bm_string_data ) { ++ for(c=0; c : 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 -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_u32.c linux-2.4.20/net/ipv4/netfilter/ipt_u32.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_u32.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_u32.c Wed Sep 24 09:17:12 2003 +@@ -0,0 +1,211 @@ ++/* Kernel module to match u32 packet content. */ ++ ++/* ++U32 tests whether quantities of up to 4 bytes extracted from a packet ++have specified values. The specification of what to extract is general ++enough to find data at given offsets from tcp headers or payloads. ++ ++ --u32 tests ++ The argument amounts to a program in a small language described below. ++ tests := location = value | tests && location = value ++ value := range | value , range ++ range := number | number : number ++ a single number, n, is interpreted the same as n:n ++ n:m is interpreted as the range of numbers >=n and <=m ++ location := number | location operator number ++ operator := & | << | >> | @ ++ ++ The operators &, <<, >>, && mean the same as in c. The = is really a set ++ membership operator and the value syntax describes a set. The @ operator ++ is what allows moving to the next header and is described further below. ++ ++ *** Until I can find out how to avoid it, there are some artificial limits ++ on the size of the tests: ++ - no more than 10 ='s (and 9 &&'s) in the u32 argument ++ - no more than 10 ranges (and 9 commas) per value ++ - no more than 10 numbers (and 9 operators) per location ++ ++ To describe the meaning of location, imagine the following machine that ++ interprets it. There are three registers: ++ A is of type char*, initially the address of the IP header ++ B and C are unsigned 32 bit integers, initially zero ++ ++ The instructions are: ++ number B = number; ++ C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3) ++ &number C = C&number ++ <>number C = C>>number ++ @number A = A+C; then do the instruction number ++ Any access of memory outside [skb->head,skb->end] causes the match to fail. ++ Otherwise the result of the computation is the final value of C. ++ ++ Whitespace is allowed but not required in the tests. ++ However the characters that do occur there are likely to require ++ shell quoting, so it's a good idea to enclose the arguments in quotes. ++ ++Example: ++ match IP packets with total length >= 256 ++ The IP header contains a total length field in bytes 2-3. ++ --u32 "0&0xFFFF=0x100:0xFFFF" ++ read bytes 0-3 ++ AND that with FFFF (giving bytes 2-3), ++ and test whether that's in the range [0x100:0xFFFF] ++ ++Example: (more realistic, hence more complicated) ++ match icmp packets with icmp type 0 ++ First test that it's an icmp packet, true iff byte 9 (protocol) = 1 ++ --u32 "6&0xFF=1 && ... ++ read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1 ++ Next test that it's not a fragment. ++ (If so it might be part of such a packet but we can't always tell.) ++ n.b. This test is generally needed if you want to match anything ++ beyond the IP header. ++ The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete ++ packet (not a fragment). Alternatively, you can allow first fragments ++ by only testing the last 5 bits of byte 6. ++ ... 4&0x3FFF=0 && ... ++ Last test: the first byte past the IP header (the type) is 0 ++ This is where we have to use the @syntax. The length of the IP header ++ (IHL) in 32 bit words is stored in the right half of byte 0 of the ++ IP header itself. ++ ... 0>>22&0x3C@0>>24=0" ++ The first 0 means read bytes 0-3, ++ >>22 means shift that 22 bits to the right. Shifting 24 bits would give ++ the first byte, so only 22 bits is four times that plus a few more bits. ++ &3C then eliminates the two extra bits on the right and the first four ++ bits of the first byte. ++ For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long. ++ In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, ++ >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100. ++ @ means to use this number as a new offset into the packet, and read ++ four bytes starting from there. This is the first 4 bytes of the icmp ++ payload, of which byte 0 is the icmp type. Therefore we simply shift ++ the value 24 to the right to throw out all but the first byte and compare ++ the result with 0. ++ ++Example: ++ tcp payload bytes 8-12 is any of 1, 2, 5 or 8 ++ First we test that the packet is a tcp packet (similar to icmp). ++ --u32 "6&0xFF=6 && ... ++ Next, test that it's not a fragment (same as above). ++ ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8" ++ 0>>22&3C as above computes the number of bytes in the IP header. ++ @ makes this the new offset into the packet, which is the start of the ++ tcp header. The length of the tcp header (again in 32 bit words) is ++ the left half of byte 12 of the tcp header. The 12>>26&3C ++ computes this length in bytes (similar to the IP header before). ++ @ makes this the new offset, which is the start of the tcp payload. ++ Finally 8 reads bytes 8-12 of the payload and = checks whether the ++ result is any of 1, 2, 5 or 8 ++*/ ++ ++#include ++#include ++ ++#include ++#include ++ ++/* #include for timing */ ++ ++MODULE_AUTHOR("Don Cohen "); ++MODULE_DESCRIPTION("IP tables u32 matching module"); ++MODULE_LICENSE("GPL"); ++ ++static int ++match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ const struct ipt_u32 *data = matchinfo; ++ int testind, i; ++ unsigned char* origbase = (char*)skb->nh.iph; ++ unsigned char* base = origbase; ++ unsigned char* head = skb->head; ++ unsigned char* end = skb->end; ++ int nnums, nvals; ++ u_int32_t pos, val; ++ /* unsigned long long cycles1, cycles2, cycles3, cycles4; ++ cycles1 = get_cycles(); */ ++ ++ for (testind=0; testind < data->ntests; testind++) { ++ base = origbase; /* reset for each test */ ++ pos = data->tests[testind].location[0].number; ++ if (base+pos+3 > end || base+pos < head) ++ return 0; ++ val = (base[pos]<<24) + (base[pos+1]<<16) + ++ (base[pos+2]<<8) + base[pos+3]; ++ nnums = data->tests[testind].nnums; ++ for (i=1; i < nnums; i++) { ++ u_int32_t number = data->tests[testind].location[i].number; ++ switch (data->tests[testind].location[i].nextop) { ++ case IPT_U32_AND: ++ val = val & number; ++ break; ++ case IPT_U32_LEFTSH: ++ val = val << number; ++ break; ++ case IPT_U32_RIGHTSH: ++ val = val >> number; ++ break; ++ case IPT_U32_AT: ++ base = base + val; ++ pos = number; ++ if (base+pos+3 > end || base+pos < head) ++ return 0; ++ val = (base[pos]<<24) + (base[pos+1]<<16) + ++ (base[pos+2]<<8) + base[pos+3]; ++ break; ++ } ++ } ++ nvals = data->tests[testind].nvalues; ++ for (i=0; i < nvals; i++) { ++ if ((data->tests[testind].value[i].min <= val) && ++ (val <= data->tests[testind].value[i].max)) { ++ break; ++ } ++ } ++ if (i >= data->tests[testind].nvalues) { ++ /* cycles2 = get_cycles(); ++ printk("failed %d in %d cycles\n", testind, ++ cycles2-cycles1); */ ++ return 0; ++ } ++ } ++ /* cycles2 = get_cycles(); ++ printk("succeeded in %d cycles\n", cycles2-cycles1); */ ++ return 1; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32))) ++ return 0; ++ return 1; ++} ++ ++static struct ipt_match u32_match ++= { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&u32_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&u32_match); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/ipt_unclean.c linux-2.4.20/net/ipv4/netfilter/ipt_unclean.c +--- linux-2.4.20.org/net/ipv4/netfilter/ipt_unclean.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv4/netfilter/ipt_unclean.c Wed Sep 24 09:16:24 2003 +@@ -259,6 +259,24 @@ + #define TH_ECE 0x40 + #define TH_CWR 0x80 + ++/* table of valid flag combinations - ECE and CWR are always valid */ ++static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] = ++{ ++ [TH_SYN] = 1, ++ [TH_SYN|TH_ACK] = 1, ++ [TH_RST] = 1, ++ [TH_RST|TH_ACK] = 1, ++ [TH_RST|TH_ACK|TH_PUSH] = 1, ++ [TH_FIN|TH_ACK] = 1, ++ [TH_ACK] = 1, ++ [TH_ACK|TH_PUSH] = 1, ++ [TH_ACK|TH_URG] = 1, ++ [TH_ACK|TH_URG|TH_PUSH] = 1, ++ [TH_FIN|TH_ACK|TH_PUSH] = 1, ++ [TH_FIN|TH_ACK|TH_URG] = 1, ++ [TH_FIN|TH_ACK|TH_URG|TH_PUSH] = 1 ++}; ++ + /* TCP-specific checks. */ + static int + check_tcp(const struct iphdr *iph, +@@ -330,19 +348,7 @@ + + /* CHECK: TCP flags. */ + tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR)); +- if (tcpflags != TH_SYN +- && tcpflags != (TH_SYN|TH_ACK) +- && tcpflags != TH_RST +- && tcpflags != (TH_RST|TH_ACK) +- && tcpflags != (TH_RST|TH_ACK|TH_PUSH) +- && tcpflags != (TH_FIN|TH_ACK) +- && tcpflags != TH_ACK +- && tcpflags != (TH_ACK|TH_PUSH) +- && tcpflags != (TH_ACK|TH_URG) +- && tcpflags != (TH_ACK|TH_URG|TH_PUSH) +- && tcpflags != (TH_FIN|TH_ACK|TH_PUSH) +- && tcpflags != (TH_FIN|TH_ACK|TH_URG) +- && tcpflags != (TH_FIN|TH_ACK|TH_URG|TH_PUSH)) { ++ if (!tcp_valid_flags[tcpflags]) { + limpk("TCP flags bad: %u\n", tcpflags); + return 0; + } +@@ -521,6 +527,16 @@ + return 0; + } + ++ /* CHECK: Do not use what is unused. ++ * First bit of fragmentation flags should be unused. ++ * May be used by OS fingerprinting tools. ++ * 04 Jun 2002, Maciej Soltysiak, solt@dns.toxicfilms.tv ++ */ ++ if (ntohs(iph->frag_off)>>15) { ++ limpk("IP unused bit set\n"); ++ return 0; ++ } ++ + /* Per-protocol checks. */ + switch (iph->protocol) { + case IPPROTO_ICMP: +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/iptable_mangle.c linux-2.4.20/net/ipv4/netfilter/iptable_mangle.c +--- linux-2.4.20.org/net/ipv4/netfilter/iptable_mangle.c Mon Feb 25 19:38:14 2002 ++++ linux-2.4.20/net/ipv4/netfilter/iptable_mangle.c Wed Sep 24 09:16:14 2003 +@@ -170,7 +170,7 @@ + static struct nf_hook_ops ipt_ops[] + = { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, + NF_IP_PRI_MANGLE }, +- { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN, ++ { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_LOCAL_IN, + NF_IP_PRI_MANGLE }, + { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD, + NF_IP_PRI_MANGLE }, +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/iptable_raw.c linux-2.4.20/net/ipv4/netfilter/iptable_raw.c +--- linux-2.4.20.org/net/ipv4/netfilter/iptable_raw.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/iptable_raw.c Wed Sep 24 09:18:12 2003 +@@ -0,0 +1,151 @@ ++/* ++ * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT . ++ * ++ * Copyright (C) 2003 Jozsef Kadlecsik ++ */ ++#include ++#include ++ ++#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) ++ ++/* Standard entry. */ ++struct ipt_standard ++{ ++ struct ipt_entry entry; ++ struct ipt_standard_target target; ++}; ++ ++struct ipt_error_target ++{ ++ struct ipt_entry_target target; ++ char errorname[IPT_FUNCTION_MAXNAMELEN]; ++}; ++ ++struct ipt_error ++{ ++ struct ipt_entry entry; ++ struct ipt_error_target target; ++}; ++ ++static struct ++{ ++ struct ipt_replace repl; ++ struct ipt_standard entries[2]; ++ struct ipt_error term; ++} initial_table __initdata ++= { { "raw", RAW_VALID_HOOKS, 3, ++ sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), ++ { [NF_IP_PRE_ROUTING] 0, ++ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, ++ { [NF_IP_PRE_ROUTING] 0, ++ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, ++ 0, NULL, { } }, ++ { ++ /* PRE_ROUTING */ ++ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ipt_entry), ++ sizeof(struct ipt_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } }, ++ /* LOCAL_OUT */ ++ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ipt_entry), ++ sizeof(struct ipt_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } } ++ }, ++ /* ERROR */ ++ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ipt_entry), ++ sizeof(struct ipt_error), ++ 0, { 0, 0 }, { } }, ++ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, ++ { } }, ++ "ERROR" ++ } ++ } ++}; ++ ++static struct ipt_table packet_raw = { ++ .list = { NULL, NULL }, ++ .name = "raw", ++ .table = &initial_table.repl, ++ .valid_hooks = RAW_VALID_HOOKS, ++ .lock = RW_LOCK_UNLOCKED, ++ .private = NULL, ++ .me = THIS_MODULE ++}; ++ ++/* The work comes in here from netfilter.c. */ ++static unsigned int ++ipt_hook(unsigned int hook, ++ struct sk_buff **pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL); ++} ++ ++/* 'raw' is the very first table. */ ++static struct nf_hook_ops ipt_ops[] = { ++ /* PRE_ROUTING hook */ ++ { .list = { NULL, NULL }, ++ .hook = ipt_hook, ++ .pf = PF_INET, ++ .hooknum = NF_IP_PRE_ROUTING, ++ .priority = NF_IP_PRI_FIRST }, ++ /* LOCAL_OUT hook */ ++ { .list = { NULL, NULL }, ++ .hook = ipt_hook, ++ .pf = PF_INET, ++ .hooknum = NF_IP_LOCAL_OUT, ++ .priority = NF_IP_PRI_FIRST } ++}; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ /* Register table */ ++ ret = ipt_register_table(&packet_raw); ++ if (ret < 0) ++ return ret; ++ ++ /* Register hooks */ ++ ret = nf_register_hook(&ipt_ops[0]); ++ if (ret < 0) ++ goto cleanup_table; ++ ++ ret = nf_register_hook(&ipt_ops[1]); ++ if (ret < 0) ++ goto cleanup_hook0; ++ ++ return ret; ++ ++ cleanup_hook0: ++ nf_unregister_hook(&ipt_ops[0]); ++ cleanup_table: ++ ipt_unregister_table(&packet_raw); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) ++ nf_unregister_hook(&ipt_ops[i]); ++ ++ ipt_unregister_table(&packet_raw); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/nfnetlink.c linux-2.4.20/net/ipv4/netfilter/nfnetlink.c +--- linux-2.4.20.org/net/ipv4/netfilter/nfnetlink.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/nfnetlink.c Wed Sep 24 09:17:51 2003 +@@ -0,0 +1,344 @@ ++/* Netfilter messages via netlink socket. Allows for user space ++ * protocol helpers and general trouble making from userspace. ++ * ++ * (C) 2001 by Jay Schulist , ++ * (C) 2002 by Harald Welte ++ * ++ * Initial netfilter messages via netlink development funded and ++ * generally made possible by Network Robots, Inc. (www.networkrobots.com) ++ * ++ * Further development of this code funded by Astaro AG (http://www.astaro.com) ++ * ++ * This software may be used and distributed according to the terms ++ * of the GNU General Public License, incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++char nfversion[] = "0.11"; ++int nf_debug_level = 1; ++#define nf_debug(level, format, arg...) \ ++ if(nf_debug_level > level) \ ++ printk(__FUNCTION__ ": " format, ## arg) ++ ++static struct sock *nfnl = NULL; ++static LIST_HEAD(subsys_list); ++static struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; ++DECLARE_MUTEX(nfnl_sem); ++ ++void nfnl_lock(void) ++{ ++ nfnl_shlock(); ++ nfnl_exlock(); ++} ++ ++void nfnl_unlock(void) ++{ ++ nfnl_exunlock(); ++ nfnl_shunlock(); ++} ++ ++struct nfnetlink_subsystem *nfnetlink_subsys_alloc(int cb_count) ++{ ++ int size; ++ struct nfnetlink_subsystem *ss; ++ ++ size = sizeof(struct nfnetlink_subsystem) ++ + (cb_count * sizeof(struct nfnl_callback)); ++ ++ ss = kmalloc(size, GFP_KERNEL); ++ if (!ss) ++ return NULL; ++ memset(ss, 0, size); ++ ++ return ss; ++} ++ ++int nfnetlink_subsys_register(struct nfnetlink_subsystem *n) ++{ ++ MOD_INC_USE_COUNT; ++ ++ nf_debug(0, "registering subsystem ID %u\n", n->subsys_id); ++ ++ nfnl_lock(); ++ list_add(&n->list, &subsys_list); ++ subsys_table[n->subsys_id] = n; ++ nfnl_unlock(); ++ ++ return 0; ++} ++ ++int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n) ++{ ++ nf_debug(0, "unregistering subsystem ID %u\n", n->subsys_id); ++ ++ nfnl_lock(); ++ subsys_table[n->subsys_id] = NULL; ++ list_del(&n->list); ++ nfnl_unlock(); ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++struct nfnl_callback *nfnetlink_find_client(u_int16_t nlmsg_type) ++{ ++ struct nfnetlink_subsystem *ss; ++ u_int8_t subsys_id = NFNL_SUBSYS_ID(nlmsg_type); ++ u_int8_t type = NFNL_MSG_TYPE(nlmsg_type); ++ ++ if (subsys_id >= NFNL_SUBSYS_COUNT ++ || subsys_table[subsys_id] == NULL) ++ return NULL; ++ ++ ss = subsys_table[subsys_id]; ++ ++ if (type >= ss->cb_count) { ++ nf_debug(0, "msgtype %u >= %u, returning\n", type, ++ ss->cb_count); ++ return NULL; ++ } ++ ++ return &ss->cb[type]; ++} ++ ++void __nfa_fill(struct sk_buff *skb, int attrtype, int attrlen, ++ const void *data) ++{ ++ struct nfattr *nfa; ++ int size = NFA_LENGTH(attrlen); ++ ++ nfa = (struct nfattr *)skb_put(skb, NFA_ALIGN(size)); ++ nfa->nfa_type = attrtype; ++ nfa->nfa_len = size; ++ memcpy(NFA_DATA(nfa), data, attrlen); ++} ++ ++int nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len) ++{ ++ memset(tb, 0, sizeof(struct nfattr *)*maxattr); ++ ++ while (NFA_OK(nfa, len)) { ++ unsigned flavor = nfa->nfa_type; ++ if (flavor && flavor <= maxattr) ++ tb[flavor-1] = nfa; ++ nfa = NFA_NEXT(nfa, len); ++ } ++ ++ return 0; ++} ++ ++/** ++ * nfnetlink_check_attributes - check and parse nfnetlink attributes ++ * ++ * subsys: nfnl subsystem for which this message is to be parsed ++ * nlmsghdr: netlink message to be checked/parsed ++ * cda: array of pointers, needs to be at least subsys->attr_count big ++ * ++ */ ++int ++nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys, ++ struct nlmsghdr *nlh, struct nfattr *cda[]) ++{ ++ int min_len; ++ ++ /* check attribute lengths. */ ++ min_len = sizeof(struct nfgenmsg); ++ if (nlh->nlmsg_len < min_len) ++ return -EINVAL; ++ ++ if (nlh->nlmsg_len > min_len) { ++ struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); ++ int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); ++ ++ while (NFA_OK(attr, attrlen)) { ++ unsigned flavor = attr->nfa_type; ++ if (flavor) { ++ if (flavor > subsys->attr_count) ++ return -EINVAL; ++ cda[flavor - 1] = attr; ++ } ++ attr = NFA_NEXT(attr, attrlen); ++ } ++ } else ++ return -EINVAL; ++ ++ return 0; ++} ++ ++int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) ++{ ++ int err = 0; ++ ++ NETLINK_CB(skb).dst_groups = group; ++ if (echo) ++ atomic_inc(&skb->users); ++ netlink_broadcast(nfnl, skb, pid, group, GFP_KERNEL); ++ if (echo) ++ err = netlink_unicast(nfnl, skb, pid, MSG_DONTWAIT); ++ ++ return err; ++} ++ ++/* Process one complete nfnetlink message. */ ++static inline int nfnetlink_rcv_msg(struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ struct nfnl_callback *nc; ++ int type, err = 0; ++ ++ nf_debug(0, "entered; subsys=%u, msgtype=%u\n", ++ NFNL_SUBSYS_ID(nlh->nlmsg_type), ++ NFNL_MSG_TYPE(nlh->nlmsg_type)); ++ ++ /* Only requests are handled by kernel now. */ ++ if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { ++ nf_debug(0, "received non-request message\n"); ++ return 0; ++ } ++ ++ /* Unknown message: reply with EINVAL */ ++ type = nlh->nlmsg_type; ++ if (NFNL_SUBSYS_ID(type) > NFNL_SUBSYS_COUNT) { ++ nf_debug(0, "subsys_id > subsys_count\n"); ++ goto err_inval; ++ } ++ ++ /* All the messages must have at least 1 byte length */ ++ if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) { ++ nf_debug(0, "received message was too short\n"); ++ return 0; ++ } ++ ++ nc = nfnetlink_find_client(type); ++ if (!nc) { ++ nf_debug(0, "unable to find client for type %d\n", type); ++ goto err_inval; ++ } ++ ++ if (nc->cap_required && ++ !cap_raised(NETLINK_CB(skb).eff_cap, nc->cap_required)) { ++ nf_debug(0, "permission denied for type %d\n", type); ++ *errp = -EPERM; ++ return -1; ++ } ++ ++ err = nc->call(nfnl, skb, nlh, errp); ++ *errp = err; ++ return err; ++ ++err_inval: ++ *errp = -EINVAL; ++ return -1; ++} ++ ++/* Process one packet of messages. */ ++static inline int nfnetlink_rcv_skb(struct sk_buff *skb) ++{ ++ int err; ++ struct nlmsghdr *nlh; ++ ++ while (skb->len >= NLMSG_SPACE(0)) { ++ u32 rlen; ++ ++ nlh = (struct nlmsghdr *)skb->data; ++ if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ++ || skb->len < nlh->nlmsg_len) ++ return 0; ++ rlen = NLMSG_ALIGN(nlh->nlmsg_len); ++ if (rlen > skb->len) ++ rlen = skb->len; ++ if (nfnetlink_rcv_msg(skb, nlh, &err)) { ++ if (!err) ++ return -1; ++ netlink_ack(skb, nlh, err); ++ } else ++ if (nlh->nlmsg_flags & NLM_F_ACK) ++ netlink_ack(skb, nlh, 0); ++ skb_pull(skb, rlen); ++ } ++ ++ return 0; ++} ++ ++static void nfnetlink_rcv(struct sock *sk, int len) ++{ ++ do { ++ struct sk_buff *skb; ++ ++ if (nfnl_shlock_nowait()) ++ return; ++ ++ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { ++ if (nfnetlink_rcv_skb(skb)) { ++ if (skb->len) ++ skb_queue_head(&sk->receive_queue, skb); ++ else ++ kfree_skb(skb); ++ break; ++ } ++ kfree_skb(skb); ++ } ++ ++ up(&nfnl_sem); ++ } while(nfnl && nfnl->receive_queue.qlen); ++} ++ ++void __exit nfnetlink_exit(void) ++{ ++ printk("Netfilter removing netlink socket.\n"); ++ sock_release(nfnl->socket); ++ return; ++} ++ ++int __init nfnetlink_init(void) ++{ ++ int i; ++ printk("Netfilter messages via NETLINK v%s.\n", nfversion); ++ ++ for (i = 0; i < NFNL_SUBSYS_COUNT; i++) ++ subsys_table[i] = NULL; ++ ++ nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv); ++ if (!nfnl) { ++ printk(KERN_ERR "cannot initialize nfnetlink!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++module_init(nfnetlink_init); ++module_exit(nfnetlink_exit); ++ ++EXPORT_SYMBOL_GPL(nfnetlink_subsys_alloc); ++EXPORT_SYMBOL_GPL(nfnetlink_subsys_register); ++EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); ++EXPORT_SYMBOL_GPL(nfnetlink_check_attributes); ++EXPORT_SYMBOL_GPL(nfnetlink_send); ++EXPORT_SYMBOL_GPL(__nfa_fill); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv4/netfilter/nfnetlink_conntrack.c linux-2.4.20/net/ipv4/netfilter/nfnetlink_conntrack.c +--- linux-2.4.20.org/net/ipv4/netfilter/nfnetlink_conntrack.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv4/netfilter/nfnetlink_conntrack.c Wed Sep 24 09:17:51 2003 +@@ -0,0 +1,715 @@ ++/* Connection tracking via netlink socket. Allows for user space ++ * protocol helpers and general trouble making from userspace. ++ * ++ * (C) 2001 by Jay Schulist ++ * (C) 2002 by Harald Welte ++ * ++ * Initial connection tracking via netlink development funded and ++ * generally made possible by Network Robots, Inc. (www.networkrobots.com) ++ * ++ * Further development of this code funded by Astaro AG (http://www.asaro.com) ++ * ++ * This software may be used and distributed according to the terms ++ * of the GNU General Public License, incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) ++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++char ctversion[] = "0.11"; ++int ct_debug_level = 1; ++#define ct_debug(level, format, arg...) \ ++ if(ct_debug_level > level) \ ++ printk(__FUNCTION__ ": " format, ## arg) ++ ++/* FIXME: this define is just needed for DUMP_TUPLE */ ++#define DEBUGP(format, args...) ct_debug(0, format, ## args) ++ ++static struct nfnetlink_subsystem *ctnl_subsys; ++ ++static int ++ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, ++ int event, ++ int nowait, ++ const struct ip_conntrack *ct, ++ const enum ip_conntrack_info *ctinfo, ++ unsigned char proto, ++ const struct net_device *in, ++ const struct net_device *out) ++{ ++ struct nlmsghdr *nlh; ++ struct nfgenmsg *nfmsg; ++ struct cta_proto cp; ++ unsigned long s; ++ unsigned char *b; ++ ++ b = skb->tail; ++ nlh = NLMSG_PUT(skb, pid, seq, (NFNL_SUBSYS_CTNETLINK<<8)|event, ++ sizeof(struct nfgenmsg)); ++ nfmsg = NLMSG_DATA(nlh); ++ ++ nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; ++ nfmsg->nfgen_family = AF_INET; ++ NFA_PUT(skb, CTA_ORIG, sizeof(struct ip_conntrack_tuple), ++ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ NFA_PUT(skb, CTA_RPLY, sizeof(struct ip_conntrack_tuple), ++ &ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ s = ct->status; ++ NFA_PUT(skb, CTA_STATUS, sizeof(unsigned long), &s); ++ if (in) ++ NFA_PUT(skb, CTA_IIF, IFNAMSIZ, in->name); ++ if (out) ++ NFA_PUT(skb, CTA_OIF, IFNAMSIZ, out->name); ++ if (ctinfo) ++ NFA_PUT(skb, CTA_INFO, sizeof(unsigned long), ctinfo); ++ ++ cp.num_proto = proto; ++ memcpy(&cp.proto, &ct->proto, sizeof (cp.proto)); ++ NFA_PUT(skb, CTA_PROTOINFO, sizeof(cp), &cp); ++ ++ if (ct->helper) { ++ struct cta_help ch; ++ ++ memcpy(&ch.tuple, &ct->helper->tuple, ++ sizeof(struct ip_conntrack_tuple)); ++ memcpy(&ch.mask, &ct->helper->mask, ++ sizeof(struct ip_conntrack_tuple)); ++ strncpy((char *)&ch.name, ct->helper->name, sizeof(ch.name)); ++ memcpy(&ch.help, &ct->help, sizeof(ch.help)); ++ NFA_PUT(skb, CTA_HELPINFO, sizeof(ch), &ch); ++ } ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ if (ct->nat.info.initialized && ct->nat.info.num_manips) { ++ const struct ip_nat_info *nat = &ct->nat.info; ++ struct cta_nat cn; ++ ++ cn.num_manips = nat->num_manips; ++ memcpy(&cn.manips, &nat->manips, (nat->num_manips ++ * sizeof(struct ip_nat_info_manip))); ++ NFA_PUT(skb, CTA_NATINFO, sizeof(struct cta_nat), &cn); ++ } ++#endif /* CONFIG_IP_NF_NAT_NEEDED */ ++ ++ nlh->nlmsg_len = skb->tail - b; ++ return skb->len; ++ ++nlmsg_failure: ++nfattr_failure: ++ skb_trim(skb, b - skb->data); ++ return -1; ++} ++ ++static inline struct sk_buff * ++ctnetlink_event_build_msg(const struct ip_conntrack *ct, ++ const enum ip_conntrack_info ctinfo, ++ const unsigned char proto, ++ const struct net_device *in, ++ const struct net_device *out) ++{ ++ struct sk_buff *skb; ++ int err; ++ ++ skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); ++ if (!skb) ++ return NULL; ++ ++ err = ctnetlink_fill_info(skb, 0, 0, CTNL_MSG_NEWCONNTRACK, 1, ct, ++ &ctinfo, proto, in, out); ++ if (err <= 0) ++ goto nlmsg_failure; ++ return skb; ++ ++nlmsg_failure: ++ return NULL; ++} ++ ++static void ++ctnetlink_create(struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ const struct net_device *in, ++ const struct net_device *out) ++{ ++ u16 proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; ++ struct sk_buff *skb; ++ ++ skb = ctnetlink_event_build_msg(ct, ctinfo, proto, in, out); ++ if (!skb) ++ return; ++ ++ if (proto == IPPROTO_TCP) { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_TCP, 0); ++ return; ++ } else if (proto == IPPROTO_UDP) { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_UDP, 0); ++ return; ++ } else if (proto == IPPROTO_ICMP) { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_ICMP, 0); ++ return; ++ } else { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_OTHER, 0); ++ return; ++ } ++ kfree_skb(skb); ++ return; ++} ++ ++#if 0 ++static void ctnetlink_destroy(struct ip_conntrack *ct) ++{ ++ ctnetlink_create(ct, IP_CT_DELETE, NULL, NULL); ++} ++#endif ++ ++static inline int ctnetlink_kill(const struct ip_conntrack *i, void *data) ++{ ++ struct ip_conntrack *t = (struct ip_conntrack *)data; ++ ++ if (!memcmp(&i->tuplehash[IP_CT_DIR_ORIGINAL], ++ &t->tuplehash[IP_CT_DIR_ORIGINAL], ++ sizeof(struct ip_conntrack_tuple_hash))) { ++ //ip_conntrack_put(t); ++ nf_conntrack_put(&t->infos[0]); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int ++ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ struct ip_conntrack_tuple_hash *h; ++ struct ip_conntrack_tuple *tuple; ++ struct nfattr *cda[CTA_MAX]; ++ ++ ct_debug(0, "entered\n"); ++ ++ if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0) ++ return -EINVAL; ++ ++ if (cda[CTA_ORIG-1]) ++ tuple = NFA_DATA(cda[CTA_ORIG-1]); ++ else { ++ if (cda[CTA_RPLY-1]) ++ tuple = NFA_DATA(cda[CTA_RPLY-1]); ++ else { ++ ct_debug(0, "no tuple found in request\n"); ++ return -EINVAL; ++ } ++ } ++ ++ h = ip_conntrack_find_get(tuple, NULL); ++ if (!h) { ++ ct_debug(0, "tuple not found in conntrack hash:"); ++ DUMP_TUPLE(tuple); ++ return -ENOENT; ++ } ++ ++ ct_debug(0, "calling selective_cleanup\n"); ++ ip_ct_selective_cleanup(ctnetlink_kill, h->ctrack); ++ ++ return 0; ++} ++ ++static int ctnetlink_done(struct netlink_callback *cb) ++{ ++ ct_debug(0, "entering\n"); ++ return 0; ++} ++ ++static int ++ctnetlink_dump_build_msg(const struct ip_conntrack_tuple_hash *hash, ++ struct sk_buff *skb, u32 pid, u32 seq) ++{ ++ struct ip_conntrack *ct; ++ int err, proto; ++ ++ /* Only count originals */ ++ if (DIRECTION(hash)) ++ return 0; ++ ++ ct = hash->ctrack; ++ if (!ct) ++ goto nlmsg_failure; ++ ++ proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; ++ err = ctnetlink_fill_info(skb, pid, seq, CTNL_MSG_NEWCONNTRACK, 1, ++ ct, NULL, proto, NULL, NULL); ++ if (err <= 0) ++ goto nlmsg_failure; ++ return 0; ++ ++nlmsg_failure: ++ if (skb) ++ kfree_skb(skb); ++ return -1; ++} ++ ++static int ++ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ++{ ++ int i; ++ int idx; ++ int s_idx = cb->args[0]; ++ ++ /* Traverse hash; send originals then reply. */ ++ READ_LOCK(&ip_conntrack_lock); ++ for (i = 0, idx = 0; i < ip_conntrack_htable_size; i++, idx++) { ++ if (idx < s_idx) ++ continue; ++ if (LIST_FIND(&ip_conntrack_hash[i], ctnetlink_dump_build_msg, ++ struct ip_conntrack_tuple_hash *, skb, ++ NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq)) ++ continue; ++ } ++ READ_UNLOCK(&ip_conntrack_lock); ++ ++ cb->args[0] = idx; ++ return skb->len; ++} ++ ++static int ++ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ struct ip_conntrack_tuple_hash *h; ++ struct ip_conntrack_tuple *tuple; ++ struct nfattr *cda[CTA_MAX]; ++ struct ip_conntrack *ct; ++ struct sk_buff *skb2 = NULL; ++ int err, proto; ++ ++ ct_debug(0, "entered\n"); ++ ++ if (nlh->nlmsg_flags & NLM_F_DUMP) { ++ struct nfgenmsg *msg = NLMSG_DATA(nlh); ++ u32 rlen; ++ ++ if (msg->nfgen_family != AF_INET) ++ return -EAFNOSUPPORT; ++ ++ ct_debug(0, "starting dump\n"); ++ if ((*errp = netlink_dump_start(ctnl, skb, nlh, ++ ctnetlink_dump_table, ++ ctnetlink_done)) != 0) ++ return -EINVAL; ++ rlen = NLMSG_ALIGN(nlh->nlmsg_len); ++ if (rlen > skb->len) ++ rlen = skb->len; ++ skb_pull(skb, rlen); ++ return 0; ++ } ++ ++ if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0) ++ return -EINVAL; ++ ++ if (cda[CTA_ORIG-1]) ++ tuple = NFA_DATA(cda[CTA_ORIG-1]); ++ else { ++ if (cda[CTA_RPLY-1]) ++ tuple = NFA_DATA(cda[CTA_RPLY-1]); ++ else ++ return -EINVAL; ++ } ++ ++ h = ip_conntrack_find_get(tuple, NULL); ++ if (!h) ++ return -ENOENT; ++ ++ ct = h->ctrack; ++ if (!ct) ++ goto nlmsg_failure; ++ ++ skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); ++ if (!skb2) ++ return -ENOMEM; ++ NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; ++ ++ proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; ++ err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, ++ CTNL_MSG_NEWCONNTRACK, 1, ct, NULL, ++ proto, NULL, NULL); ++ ip_conntrack_put(ct); ++ if (err <= 0) ++ goto nlmsg_failure; ++ ++ err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); ++ if (err < 0) ++ return err; ++ return 0; ++ ++nlmsg_failure: ++ if (skb2) ++ kfree_skb(skb2); ++ return -1; ++} ++ ++/* Finish me: should support NLM_F_CREATE and NLM_F_REPLACE. */ ++static int ++ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ return -EOPNOTSUPP; ++} ++ ++ ++/* EXPECT */ ++ ++static int ++ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, ++ int event, ++ int nowait, ++ const struct ip_conntrack_expect *exp) ++{ ++ struct nlmsghdr *nlh; ++ struct nfgenmsg *nfmsg; ++ unsigned char *b; ++ ++ b = skb->tail; ++ nlh = NLMSG_PUT(skb, pid, seq, (NFNL_SUBSYS_CTNETLINK<<8)|event, ++ sizeof(struct nfgenmsg)); ++ nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; ++ nfmsg = NLMSG_DATA(nlh); ++ nfmsg->nfgen_family = AF_INET; ++ ++ NFA_PUT(skb, CTA_EXP_TUPLE, sizeof(struct ip_conntrack_tuple), ++ &exp->tuple); ++ NFA_PUT(skb, CTA_EXP_MASK, sizeof(struct ip_conntrack_tuple), ++ &exp->mask); ++ NFA_PUT(skb, CTA_EXP_SEQNO, sizeof(u_int32_t), &exp->seq); ++ NFA_PUT(skb, CTA_EXP_HELP, sizeof(union ip_conntrack_expect_help), ++ &exp->help); ++ ++ /* FIXME: proto */ ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++#endif /* CONFIG_IP_NF_NAT_NEEDED */ ++ ++ nlh->nlmsg_len = skb->tail - b; ++ return skb->len; ++ ++nlmsg_failure: ++nfattr_failure: ++ skb_trim(skb, b - skb->data); ++ return -1; ++} ++ ++static inline struct sk_buff * ++ctnetlink_exp_event_build_msg(const struct ip_conntrack_expect *exp) ++{ ++ struct sk_buff *skb; ++ int err; ++ ++ skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); ++ if (!skb) ++ return NULL; ++ ++ err = ctnetlink_exp_fill_info(skb, 0, 0, CTNL_MSG_NEWEXPECT, 1, exp); ++ if (err <= 0) ++ goto nlmsg_failure; ++ return skb; ++ ++nlmsg_failure: ++ if (skb) ++ kfree_skb(skb); ++ return NULL; ++} ++ ++static void ++ctnetlink_exp_create(struct ip_conntrack_expect *exp) ++{ ++ u16 proto = exp->tuple.dst.protonum; ++ struct sk_buff *skb; ++ ++ skb = ctnetlink_exp_event_build_msg(exp); ++ if (!skb) ++ return; ++ ++ if (proto == IPPROTO_TCP) { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_TCP, 0); ++ return; ++ } else if (proto == IPPROTO_UDP) { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_UDP, 0); ++ return; ++ } else if (proto == IPPROTO_ICMP) { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_ICMP, 0); ++ return; ++ } else { ++ nfnetlink_send(skb, 0, NFGRP_IPV4_CT_OTHER, 0); ++ return; ++ } ++ kfree_skb(skb); ++ return; ++} ++ ++ ++static int ++ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ struct ip_conntrack_expect *exp; ++ struct ip_conntrack_tuple *tuple; ++ struct nfattr *cda[CTA_MAX]; ++ ++ if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0) ++ return -EINVAL; ++ ++ if (cda[CTA_ORIG-1]) ++ tuple = NFA_DATA(cda[CTA_ORIG-1]); ++ else { ++ if (cda[CTA_RPLY-1]) ++ tuple = NFA_DATA(cda[CTA_RPLY-1]); ++ else ++ return -EINVAL; ++ } ++ ++ /* bump usage count to 2 */ ++ exp = ip_conntrack_expect_find_get(tuple); ++ if (!exp) ++ return -ENOENT; ++ ++ /* after list removal, usage count == 1 */ ++ ip_conntrack_unexpect_related(exp); ++ /* we have put what we 'get' above. after this line usage count == 0 */ ++ ip_conntrack_expect_put(exp); ++ ++ return 0; ++} ++ ++static int ++ctnetlink_exp_dump_build_msg(const struct ip_conntrack_expect *exp, ++ struct sk_buff *skb, u32 pid, u32 seq) ++{ ++ int err, proto; ++ ++ proto = exp->tuple.dst.protonum; ++ err = ctnetlink_exp_fill_info(skb, pid, seq, CTNL_MSG_NEWEXPECT, 1, ++ exp); ++ if (err <= 0) ++ goto nlmsg_failure; ++ return 0; ++ ++nlmsg_failure: ++ if (skb) ++ kfree_skb(skb); ++ return -1; ++} ++ ++static int ++ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ++{ ++ ct_debug(0, "entered\n"); ++ if (cb->args[0] == 0) { ++ READ_LOCK(&ip_conntrack_lock); ++ LIST_FIND(&ip_conntrack_expect_list, ++ ctnetlink_exp_dump_build_msg, ++ struct ip_conntrack_expect *, skb, ++ NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq); ++ READ_UNLOCK(&ip_conntrack_lock); ++ cb->args[0] = 1; ++ } ++ ct_debug(0, "returning\n"); ++ ++ return skb->len; ++} ++ ++ ++static int ++ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ struct ip_conntrack_expect *exp; ++ struct ip_conntrack_tuple *tuple; ++ struct nfattr *cda[CTA_MAX]; ++ struct sk_buff *skb2 = NULL; ++ int err, proto; ++ ++ ct_debug(0, "entered\n"); ++ ++ if (nlh->nlmsg_flags & NLM_F_DUMP) { ++ struct nfgenmsg *msg = NLMSG_DATA(nlh); ++ u32 rlen; ++ ++ if (msg->nfgen_family != AF_INET) ++ return -EAFNOSUPPORT; ++ ++ ct_debug(0, "starting dump\n"); ++ if ((*errp = netlink_dump_start(ctnl, skb, nlh, ++ ctnetlink_exp_dump_table, ++ ctnetlink_done)) != 0) ++ return -EINVAL; ++ rlen = NLMSG_ALIGN(nlh->nlmsg_len); ++ if (rlen > skb->len) ++ rlen = skb->len; ++ skb_pull(skb, rlen); ++ return 0; ++ } ++ ++ if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0) ++ return -EINVAL; ++ ++ if (cda[CTA_ORIG-1]) ++ tuple = NFA_DATA(cda[CTA_ORIG-1]); ++ else { ++ if (cda[CTA_RPLY-1]) ++ tuple = NFA_DATA(cda[CTA_RPLY-1]); ++ else ++ return -EINVAL; ++ } ++ ++ exp = ip_conntrack_expect_find_get(tuple); ++ if (!exp) ++ return -ENOENT; ++ ++ skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); ++ if (!skb2) ++ return -ENOMEM; ++ NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; ++ proto = exp->tuple.dst.protonum; ++ ++ err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, ++ nlh->nlmsg_seq, CTNL_MSG_NEWEXPECT, ++ 1, exp); ++ if (err <= 0) ++ goto nlmsg_failure; ++ ++ err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); ++ if (err < 0) ++ return err; ++ return 0; ++ ++nlmsg_failure: ++ if (skb2) ++ kfree_skb(skb2); ++ return -1; ++} ++ ++static int ++ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, ++ struct nlmsghdr *nlh, int *errp) ++{ ++ return -EOPNOTSUPP; ++} ++ ++/* struct conntrack_expect stuff */ ++ ++#if 0 ++static struct ip_conntrack_notify ctnl_notify = { { NULL, NULL }, ++ ctnetlink_destroy, ++ ctnetlink_create }; ++ ++static struct ip_conntrack_notify ctnl_exp_notify; ++#endif ++ ++static void __exit ctnetlink_exit(void) ++{ ++ printk("ctnetlink: unregistering with nfnetlink.\n"); ++// ip_conntrack_notify_unregister(&ctnl_exp_notify); ++// ip_conntrack_notify_unregister(&ctnl_notify); ++ nfnetlink_subsys_unregister(ctnl_subsys); ++ kfree(ctnl_subsys); ++ return; ++} ++ ++static int __init ctnetlink_init(void) ++{ ++ int ret; ++ ++ ctnl_subsys = nfnetlink_subsys_alloc(CTNL_MSG_COUNT); ++ if (!ctnl_subsys) { ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ ctnl_subsys->name = "conntrack"; ++ ctnl_subsys->subsys_id = NFNL_SUBSYS_CTNETLINK; ++ ctnl_subsys->cb_count = CTNL_MSG_COUNT; ++ ctnl_subsys->attr_count = CTA_MAX; ++ ctnl_subsys->cb[CTNL_MSG_NEWCONNTRACK].call = ctnetlink_new_conntrack; ++ ctnl_subsys->cb[CTNL_MSG_NEWCONNTRACK].cap_required = CAP_NET_ADMIN; ++ ctnl_subsys->cb[CTNL_MSG_DELCONNTRACK].call = ctnetlink_del_conntrack; ++ ctnl_subsys->cb[CTNL_MSG_DELCONNTRACK].cap_required = CAP_NET_ADMIN; ++ ctnl_subsys->cb[CTNL_MSG_GETCONNTRACK].call = ctnetlink_get_conntrack; ++ ctnl_subsys->cb[CTNL_MSG_GETCONNTRACK].cap_required = 0; ++ ctnl_subsys->cb[CTNL_MSG_NEWEXPECT].call = ctnetlink_new_expect; ++ ctnl_subsys->cb[CTNL_MSG_NEWEXPECT].cap_required = CAP_NET_ADMIN; ++ ctnl_subsys->cb[CTNL_MSG_DELEXPECT].call = ctnetlink_del_expect; ++ ctnl_subsys->cb[CTNL_MSG_DELEXPECT].cap_required = CAP_NET_ADMIN; ++ ctnl_subsys->cb[CTNL_MSG_GETEXPECT].call = ctnetlink_get_expect; ++ ctnl_subsys->cb[CTNL_MSG_GETEXPECT].cap_required = 0; ++ // FIXME: CONFIRM ++ ++ printk("ctnetlink: registering with nfnetlink v%s.\n", ctversion); ++ if (nfnetlink_subsys_register(ctnl_subsys) < 0) { ++ printk("ctnetlink_init: cannot register with nfnetlink.\n"); ++ ret = -1; ++ goto err_free_subsys; ++ } ++ ++ ++#if 0 ++ if (ip_conntrack_notify_register(&ctnl_notify) < 0) { ++ printk("ctnetlink_init: cannot register notifier.\n"); ++ ret = -1; ++ goto err_unreg_subsys; ++ } ++ ++ if (ip_conntrack_notify_register(&ctnl_exp_notify) < 0) { ++ printk("ctnetlink_init: cannot register exp notifier\n"); ++ ret = -1; ++ goto err_unreg_notify; ++ } ++#endif ++ ++ ++ return 0; ++ ++#if 0 ++err_unreg_notify: ++ ip_conntrack_notify_unregister(&ctnl_notify); ++#endif ++err_unreg_subsys: ++ nfnetlink_subsys_unregister(ctnl_subsys); ++err_free_subsys: ++ kfree(ctnl_subsys); ++err_out: ++ return ret; ++} ++ ++module_init(ctnetlink_init); ++module_exit(ctnetlink_exit); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/ip6_output.c linux-2.4.20/net/ipv6/ip6_output.c +--- linux-2.4.20.org/net/ipv6/ip6_output.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv6/ip6_output.c Wed Sep 24 09:16:14 2003 +@@ -132,7 +132,7 @@ + + + #ifdef CONFIG_NETFILTER +-static int route6_me_harder(struct sk_buff *skb) ++int ip6_route_me_harder(struct sk_buff *skb) + { + struct ipv6hdr *iph = skb->nh.ipv6h; + struct dst_entry *dst; +@@ -150,7 +150,7 @@ + + if (dst->error) { + if (net_ratelimit()) +- printk(KERN_DEBUG "route6_me_harder: No more route.\n"); ++ printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); + return -EINVAL; + } + +@@ -166,7 +166,7 @@ + { + #ifdef CONFIG_NETFILTER + if (skb->nfcache & NFC_ALTERED){ +- if (route6_me_harder(skb) != 0){ ++ if (ip6_route_me_harder(skb) != 0){ + kfree_skb(skb); + return -EINVAL; + } +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/Config.in linux-2.4.20/net/ipv6/netfilter/Config.in +--- linux-2.4.20.org/net/ipv6/netfilter/Config.in Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv6/netfilter/Config.in Wed Sep 24 09:18:15 2003 +@@ -15,15 +15,40 @@ + + tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES + if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ tristate 'raw table support (required for TRACE)' CONFIG_IP6_NF_RAW $CONFIG_IP6_NF_IPTABLES ++ fi + # The simple matches. + dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES + dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES ++ dep_tristate ' Condition variable match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES ++ dep_tristate ' Random match support' CONFIG_IP6_NF_MATCH_RANDOM $CONFIG_IP6_NF_IPTABLES ++ dep_tristate ' Nth match support' CONFIG_IP6_NF_MATCH_NTH $CONFIG_IP6_NF_IPTABLES ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' Fuzzy match support' CONFIG_IP6_NF_MATCH_FUZZY $CONFIG_IP6_NF_FILTER ++ fi ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES ++ fi ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' Hop-by-Hop and Dst opts header match (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OPTS $CONFIG_IP6_NF_IPTABLES ++ fi ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' Fragmentation header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_FRAG $CONFIG_IP6_NF_IPTABLES ++ fi ++ dep_tristate ' HL match support' CONFIG_IP6_NF_MATCH_HL $CONFIG_IP6_NF_IPTABLES + dep_tristate ' Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OWNER $CONFIG_IP6_NF_IPTABLES + 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 ' IPv6 Extension Headers Match (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_IPV6HEADER $CONFIG_IP6_NF_IPTABLES ++ fi ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' AH/ESP match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_AHESP $CONFIG_IP6_NF_IPTABLES ++ fi + dep_tristate ' Packet Length match support' CONFIG_IP6_NF_MATCH_LENGTH $CONFIG_IP6_NF_IPTABLES + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' EUI64 address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_EUI64 $CONFIG_IP6_NF_IPTABLES +@@ -39,8 +64,20 @@ + # fi + + # The targets ++ if [ "$CONFIG_IP6_NF_RAW" != "n" ]; then ++ dep_tristate ' TRACE target support' CONFIG_IP6_NF_TARGET_TRACE $CONFIG_IP6_NF_RAW ++ if [ "$CONFIG_IP6_NF_TARGET_TRACE" != "n" ]; then ++ define_bool CONFIG_IP6_NF_TARGET_TRACE_NEEDED y ++ fi ++ fi + 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 ' HL target support' CONFIG_IP6_NF_TARGET_HL $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 + +@@ -55,6 +92,8 @@ + if [ "$CONFIG_IP6_NF_MANGLE" != "n" ]; then + # dep_tristate ' TOS target support' CONFIG_IP6_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE + dep_tristate ' MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE ++ dep_mbool ' ROUTE target support' CONFIG_IP6_NF_TARGET_ROUTE $CONFIG_IP6_NF_MANGLE ++ dep_tristate ' IMQ target support' CONFIG_IP6_NF_TARGET_IMQ $CONFIG_IP6_NF_MANGLE + fi + #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES + fi +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/Makefile linux-2.4.20/net/ipv6/netfilter/Makefile +--- linux-2.4.20.org/net/ipv6/netfilter/Makefile Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv6/netfilter/Makefile Wed Sep 24 09:18:15 2003 +@@ -15,15 +15,33 @@ + obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o + obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o + obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o ++obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o + obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o + obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o ++obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o ++obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o ++obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o ++obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o ++obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o ++obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o + obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.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_ROUTE) += ip6t_ROUTE.o ++obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o ++obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o + obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o + obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o ++obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o ++obj-$(CONFIG_IP6_NF_TARGET_TRACE) += ip6t_TRACE.o ++ ++obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o ++ ++obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o ++obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o ++obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o + + include $(TOPDIR)/Rules.make +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6_queue.c linux-2.4.20/net/ipv6/netfilter/ip6_queue.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6_queue.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv6/netfilter/ip6_queue.c Wed Sep 24 09:16:14 2003 +@@ -305,8 +305,9 @@ + write_lock_bh(&queue_lock); + + if (!peer_pid) +- goto err_out_unlock; ++ goto err_out_free_nskb; + ++ /* netlink_unicast will either free the nskb or attach it to a socket */ + status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT); + if (status < 0) + goto err_out_unlock; +@@ -318,6 +319,9 @@ + write_unlock_bh(&queue_lock); + return status; + ++err_out_free_nskb: ++ kfree_skb(nskb); ++ + err_out_unlock: + write_unlock_bh(&queue_lock); + +@@ -326,45 +330,6 @@ + return status; + } + +-/* +- * Taken from net/ipv6/ip6_output.c +- * +- * We should use the one there, but is defined static +- * so we put this just here and let the things as +- * they are now. +- * +- * If that one is modified, this one should be modified too. +- */ +-static int +-route6_me_harder(struct sk_buff *skb) +-{ +- struct ipv6hdr *iph = skb->nh.ipv6h; +- struct dst_entry *dst; +- struct flowi fl; +- +- fl.proto = iph->nexthdr; +- fl.fl6_dst = &iph->daddr; +- fl.fl6_src = &iph->saddr; +- fl.oif = skb->sk ? skb->sk->bound_dev_if : 0; +- fl.fl6_flowlabel = 0; +- fl.uli_u.ports.dport = 0; +- fl.uli_u.ports.sport = 0; +- +- dst = ip6_route_output(skb->sk, &fl); +- +- if (dst->error) { +- if (net_ratelimit()) +- printk(KERN_DEBUG "route6_me_harder: No more route.\n"); +- return -EINVAL; +- } +- +- /* Drop old route. */ +- dst_release(skb->dst); +- +- skb->dst = dst; +- return 0; +-} +- + static int + ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) + { +@@ -410,7 +375,7 @@ + struct ipv6hdr *iph = e->skb->nh.ipv6h; + if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) || + ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr)) +- return route6_me_harder(e->skb); ++ return ip6_route_me_harder(e->skb); + } + return 0; + } +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6_tables.c linux-2.4.20/net/ipv6/netfilter/ip6_tables.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6_tables.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv6/netfilter/ip6_tables.c Wed Sep 24 09:18:14 2003 +@@ -25,10 +25,21 @@ + #include + + #include ++#include + + #define IPV6_HDR_LEN (sizeof(struct ipv6hdr)) + #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr)) + ++#ifdef CONFIG_IP6_NF_TARGET_TRACE_NEEDED ++static const char *hook6names[] = { ++ [NF_IP6_PRE_ROUTING] "PREROUTING", ++ [NF_IP6_LOCAL_IN] "INPUT", ++ [NF_IP6_FORWARD] "FORWARD", ++ [NF_IP6_LOCAL_OUT] "OUTPUT", ++ [NF_IP6_POST_ROUTING] "POSTROUTING", ++}; ++#endif ++ + /*#define DEBUG_IP_FIREWALL*/ + /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */ + /*#define DEBUG_IP_FIREWALL_USER*/ +@@ -101,10 +112,8 @@ + unsigned int hook_entry[NF_IP6_NUMHOOKS]; + unsigned int underflow[NF_IP6_NUMHOOKS]; + +- char padding[SMP_ALIGN((NF_IP6_NUMHOOKS*2+2)*sizeof(unsigned int))]; +- + /* ip6t_entry tables: one per CPU */ +- char entries[0]; ++ char entries[0] ____cacheline_aligned; + }; + + static LIST_HEAD(ip6t_target); +@@ -322,6 +331,39 @@ + return (struct ip6t_entry *)(base + offset); + } + ++static inline int ++get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, ++ char **chainname, u_int16_t *rulenum) ++{ ++ struct ip6t_entry_target *t; ++ ++ (*rulenum)++; ++ ++ if (s == e) ++ return 1; ++ ++ t = ip6t_get_target(s); ++ if (strcmp(t->u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { ++ *chainname = t->data; ++ (*rulenum) = 0; ++ } ++ ++ return 0; ++} ++ ++/* All zeroes == unconditional rule. */ ++static inline int ++unconditional(const struct ip6t_ip6 *ipv6) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(*ipv6); i++) ++ if (((char *)ipv6)[i]) ++ break; ++ ++ return (i == sizeof(*ipv6)); ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ip6t_do_table(struct sk_buff **pskb, +@@ -398,6 +440,27 @@ + + t = ip6t_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); ++#ifdef CONFIG_IP6_NF_TARGET_TRACE_NEEDED ++ /* The packet traced and the rule isn't an unconditional return/END. */ ++ if (((*pskb)->nfcache & NFC_TRACE) ++ && !(e->target_offset == sizeof(struct ip6t_entry) ++ && (strcmp(t->u.kernel.target->name, ++ IP6T_STANDARD_TARGET) == 0) ++ && !t->u.kernel.target->target ++ && ((struct ip6t_standard_target *)t)->verdict < 0 ++ && unconditional(&e->ipv6))) { ++ char *chainname = (char *) hook6names[hook]; ++ u_int16_t rulenum = 0; ++ ++ IP6T_ENTRY_ITERATE(get_entry(table_base, table->private->hook_entry[hook]), ++ table->private->size, ++ get_chainname_rulenum, ++ e, &chainname, &rulenum); ++ ++ nf_log_ip6_packet(pskb, hook, in, out, "TRACE: %s/%s/%u ", ++ table->name, chainname, rulenum); ++ } ++#endif + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; +@@ -554,19 +617,6 @@ + return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); + } + +-/* All zeroes == unconditional rule. */ +-static inline int +-unconditional(const struct ip6t_ip6 *ipv6) +-{ +- unsigned int i; +- +- for (i = 0; i < sizeof(*ipv6); i++) +- if (((char *)ipv6)[i]) +- break; +- +- return (i == sizeof(*ipv6)); +-} +- + /* Figures out from what hook each rule can be called: returns 0 if + there are loops. Puts hook bitmask in comefrom. */ + static int +@@ -1450,7 +1500,7 @@ + int ret; + struct ip6t_table_info *newinfo; + static struct ip6t_table_info bootstrap +- = { 0, 0, 0, { 0 }, { 0 }, { }, { } }; ++ = { 0, 0, 0, { 0 }, { 0 }, { } }; + + MOD_INC_USE_COUNT; + newinfo = vmalloc(sizeof(struct ip6t_table_info) +@@ -1767,14 +1817,15 @@ + = { { NULL, NULL }, "icmp6", &icmp6_match, &icmp6_checkentry, NULL }; + + #ifdef CONFIG_PROC_FS +-static inline int print_name(const struct ip6t_table *t, ++static inline int print_name(const char *i, + off_t start_offset, char *buffer, int length, + off_t *pos, unsigned int *count) + { + if ((*count)++ >= start_offset) { + unsigned int namelen; + +- namelen = sprintf(buffer + *pos, "%s\n", t->name); ++ namelen = sprintf(buffer + *pos, "%s\n", ++ i + sizeof(struct list_head)); + if (*pos + namelen > length) { + /* Stop iterating */ + return 1; +@@ -1792,7 +1843,7 @@ + if (down_interruptible(&ip6t_mutex) != 0) + return 0; + +- LIST_FIND(&ip6t_tables, print_name, struct ip6t_table *, ++ LIST_FIND(&ip6t_tables, print_name, char *, + offset, buffer, length, &pos, &count); + + up(&ip6t_mutex); +@@ -1801,6 +1852,46 @@ + *start=(char *)((unsigned long)count-offset); + return pos; + } ++ ++static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length) ++{ ++ off_t pos = 0; ++ unsigned int count = 0; ++ ++ if (down_interruptible(&ip6t_mutex) != 0) ++ return 0; ++ ++ LIST_FIND(&ip6t_target, print_name, char *, ++ offset, buffer, length, &pos, &count); ++ ++ up(&ip6t_mutex); ++ ++ *start = (char *)((unsigned long)count - offset); ++ return pos; ++} ++ ++static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length) ++{ ++ off_t pos = 0; ++ unsigned int count = 0; ++ ++ if (down_interruptible(&ip6t_mutex) != 0) ++ return 0; ++ ++ LIST_FIND(&ip6t_match, print_name, char *, ++ offset, buffer, length, &pos, &count); ++ ++ up(&ip6t_mutex); ++ ++ *start = (char *)((unsigned long)count - offset); ++ return pos; ++} ++ ++static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] = ++{ { "ip6_tables_names", ip6t_get_tables }, ++ { "ip6_tables_targets", ip6t_get_targets }, ++ { "ip6_tables_matches", ip6t_get_matches }, ++ { NULL, NULL} }; + #endif /*CONFIG_PROC_FS*/ + + static int __init init(void) +@@ -1826,13 +1917,19 @@ + #ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *proc; +- proc = proc_net_create("ip6_tables_names", 0, +- ip6t_get_tables); +- if (!proc) { +- nf_unregister_sockopt(&ip6t_sockopts); +- return -ENOMEM; ++ int i; ++ ++ for (i = 0; ip6t_proc_entry[i].name; i++) { ++ proc = proc_net_create(ip6t_proc_entry[i].name, 0, ++ ip6t_proc_entry[i].get_info); ++ if (!proc) { ++ while (--i >= 0) ++ proc_net_remove(ip6t_proc_entry[i].name); ++ nf_unregister_sockopt(&ip6t_sockopts); ++ return -ENOMEM; ++ } ++ proc->owner = THIS_MODULE; + } +- proc->owner = THIS_MODULE; + } + #endif + +@@ -1844,7 +1941,11 @@ + { + nf_unregister_sockopt(&ip6t_sockopts); + #ifdef CONFIG_PROC_FS +- proc_net_remove("ip6_tables_names"); ++ { ++ int i; ++ for (i = 0; ip6t_proc_entry[i].name; i++) ++ proc_net_remove(ip6t_proc_entry[i].name); ++ } + #endif + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_HL.c linux-2.4.20/net/ipv6/netfilter/ip6t_HL.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_HL.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_HL.c Wed Sep 24 09:16:28 2003 +@@ -0,0 +1,105 @@ ++/* ++ * Hop Limit modification target for ip6tables ++ * Maciej Soltysiak ++ * Based on HW's TTL module ++ * ++ * This software is distributed under the terms of GNU GPL ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Maciej Soltysiak "); ++MODULE_DESCRIPTION("IP tables Hop Limit modification module"); ++MODULE_LICENSE("GPL"); ++ ++static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum, ++ const struct net_device *in, const struct net_device *out, ++ const void *targinfo, void *userinfo) ++{ ++ struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h; ++ const struct ip6t_HL_info *info = targinfo; ++ u_int16_t diffs[2]; ++ int new_hl; ++ ++ switch (info->mode) { ++ case IP6T_HL_SET: ++ new_hl = info->hop_limit; ++ break; ++ case IP6T_HL_INC: ++ new_hl = ip6h->hop_limit + info->hop_limit; ++ if (new_hl > 255) ++ new_hl = 255; ++ break; ++ case IP6T_HL_DEC: ++ new_hl = ip6h->hop_limit + info->hop_limit; ++ if (new_hl < 0) ++ new_hl = 0; ++ break; ++ default: ++ new_hl = ip6h->hop_limit; ++ break; ++ } ++ ++ if (new_hl != ip6h->hop_limit) { ++ diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF; ++ ip6h->hop_limit = new_hl; ++ diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8); ++ } ++ ++ return IP6T_CONTINUE; ++} ++ ++static int ip6t_hl_checkentry(const char *tablename, ++ const struct ip6t_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ struct ip6t_HL_info *info = targinfo; ++ ++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) { ++ printk(KERN_WARNING "HL: targinfosize %u != %Zu\n", ++ targinfosize, ++ IP6T_ALIGN(sizeof(struct ip6t_HL_info))); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "mangle")) { ++ printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ if (info->mode > IP6T_HL_MAXMODE) { ++ printk(KERN_WARNING "HL: invalid or unknown Mode %u\n", ++ info->mode); ++ return 0; ++ } ++ ++ if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { ++ printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL", ++ ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ip6t_register_target(&ip6t_HL); ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_target(&ip6t_HL); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_IMQ.c linux-2.4.20/net/ipv6/netfilter/ip6t_IMQ.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_IMQ.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_IMQ.c Wed Sep 24 09:17:21 2003 +@@ -0,0 +1,78 @@ ++/* This target marks packets to be enqueued to an imq device */ ++#include ++#include ++#include ++#include ++#include ++ ++static unsigned int imq_target(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *targinfo, ++ void *userinfo) ++{ ++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)targinfo; ++ ++ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE; ++ (*pskb)->nfcache |= NFC_ALTERED; ++ ++ return IP6T_CONTINUE; ++} ++ ++static int imq_checkentry(const char *tablename, ++ const struct ip6t_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ struct ip6t_imq_info *mr; ++ ++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_imq_info))) { ++ printk(KERN_WARNING "IMQ: invalid targinfosize\n"); ++ return 0; ++ } ++ mr = (struct ip6t_imq_info*)targinfo; ++ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk(KERN_WARNING ++ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n", ++ tablename); ++ return 0; ++ } ++ ++ if (mr->todev > IMQ_MAX_DEVS) { ++ printk(KERN_WARNING ++ "IMQ: invalid device specified, highest is %u\n", ++ IMQ_MAX_DEVS); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_target ip6t_imq_reg = { ++ { NULL, NULL}, ++ "IMQ", ++ imq_target, ++ imq_checkentry, ++ NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ if (ip6t_register_target(&ip6t_imq_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_target(&ip6t_imq_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.4.20/net/ipv6/netfilter/ip6t_LOG.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_LOG.c Thu Nov 28 23:53:15 2002 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_LOG.c Wed Sep 24 09:16:23 2003 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + MODULE_AUTHOR("Jan Rekorajski "); + MODULE_DESCRIPTION("IP6 tables LOG target module"); +@@ -89,7 +90,7 @@ + printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); + + /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ +- printk("LEN=%u TC=%u HOPLIMIT=%u FLOWLBL=%u ", ++ printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", + ntohs(ipv6h->payload_len) + sizeof(struct ipv6hdr), + (ntohl(*(u_int32_t *)ipv6h) & 0x0ff00000) >> 20, + ipv6h->hop_limit, +@@ -266,23 +267,21 @@ + } + } + +-static unsigned int +-ip6t_log_target(struct sk_buff **pskb, ++static void ++ip6t_log_packet(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_log_info *loginfo, ++ const char *level_string, ++ const char *prefix) + { + struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h; +- const struct ip6t_log_info *loginfo = targinfo; +- char level_string[4] = "< >"; + +- level_string[1] = '0' + (loginfo->level % 8); + spin_lock_bh(&log_lock); + printk(level_string); + printk("%sIN=%s OUT=%s ", +- loginfo->prefix, ++ prefix == NULL ? loginfo->prefix : prefix, + in ? in->name : "", + out ? out->name : ""); + if (in && !out) { +@@ -329,10 +328,59 @@ + dump_packet(loginfo, ipv6h, 1); + printk("\n"); + spin_unlock_bh(&log_lock); ++} ++ ++static unsigned int ++ip6t_log_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_log_info *loginfo = targinfo; ++ char level_string[4] = "< >"; ++ ++ level_string[1] = '0' + (loginfo->level % 8); ++ ip6t_log_packet(pskb, hooknum, in, out, loginfo, level_string, NULL); + + return IP6T_CONTINUE; + } + ++static void ++ip6_log_packet_fn(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const char *prefix) ++{ ++ struct ip6t_log_info loginfo = { ++ .level = 0, ++ .logflags = IP6T_LOG_MASK, ++ .prefix = "" ++ }; ++ ++ ip6t_log_packet(pskb, hooknum, in, out, &loginfo, KERN_WARNING, prefix); ++} ++ ++static void ++ip6_log_fn(char *pfh, size_t len, ++ const char *prefix) ++{ ++ struct ipv6hdr *ipv6h = (struct ipv6hdr *)pfh; ++ struct ip6t_log_info loginfo = { ++ .level = 0, ++ .logflags = IP6T_LOG_MASK, ++ .prefix = "" ++ }; ++ ++ spin_lock_bh(&log_lock); ++ printk(KERN_WARNING "%s", prefix); ++ dump_packet(&loginfo, ipv6h, 1); ++ printk("\n"); ++ spin_unlock_bh(&log_lock); ++} ++ + static int ip6t_log_checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, +@@ -364,17 +412,21 @@ + static struct ip6t_target ip6t_log_reg + = { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL, + THIS_MODULE }; ++static struct nf_logging_t ip6_logging_fn ++= { ip6_log_packet_fn, ip6_log_fn }; + + static int __init init(void) + { + if (ip6t_register_target(&ip6t_log_reg)) + return -EINVAL; ++ nf_ip6_log_register(&ip6_logging_fn); + + return 0; + } + + static void __exit fini(void) + { ++ nf_ip6_log_unregister(&ip6_logging_fn); + ip6t_unregister_target(&ip6t_log_reg); + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.4.20/net/ipv6/netfilter/ip6t_REJECT.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_REJECT.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_REJECT.c Wed Sep 24 09:16:36 2003 +@@ -0,0 +1,274 @@ ++/* ++ * This is a module which is used for rejecting packets. ++ * Added support for customized reject packets (Jozsef Kadlecsik). ++ * Sun 12 Nov 2000 ++ * Port to IPv6 / ip6tables (Harald Welte ) ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 1 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#if 0 ++/* Send RST reply */ ++static void send_reset(struct sk_buff *oldskb) ++{ ++ struct sk_buff *nskb; ++ struct tcphdr *otcph, *tcph; ++ struct rtable *rt; ++ unsigned int otcplen; ++ int needs_ack; ++ ++ /* IP header checks: fragment, too short. */ ++ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) ++ || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) ++ return; ++ ++ otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl); ++ otcplen = oldskb->len - oldskb->nh.iph->ihl*4; ++ ++ /* No RST for RST. */ ++ if (otcph->rst) ++ return; ++ ++ /* Check checksum. */ ++ if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr, ++ oldskb->nh.iph->daddr, ++ csum_partial((char *)otcph, otcplen, 0)) != 0) ++ return; ++ ++ /* Copy skb (even if skb is about to be dropped, we can't just ++ clone it because there may be other things, such as tcpdump, ++ interested in it) */ ++ nskb = skb_copy(oldskb, GFP_ATOMIC); ++ if (!nskb) ++ return; ++ ++ /* This packet will not be the same as the other: clear nf fields */ ++ nf_conntrack_put(nskb->nfct); ++ nskb->nfct = NULL; ++ nskb->nfcache = 0; ++#ifdef CONFIG_NETFILTER_DEBUG ++ nskb->nf_debug = 0; ++#endif ++ ++ tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); ++ ++ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); ++ tcph->source = xchg(&tcph->dest, tcph->source); ++ ++ /* Truncate to length (no data) */ ++ tcph->doff = sizeof(struct tcphdr)/4; ++ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); ++ nskb->nh.iph->tot_len = htons(nskb->len); ++ ++ if (tcph->ack) { ++ needs_ack = 0; ++ tcph->seq = otcph->ack_seq; ++ tcph->ack_seq = 0; ++ } else { ++ needs_ack = 1; ++ tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin ++ + otcplen - (otcph->doff<<2)); ++ tcph->seq = 0; ++ } ++ ++ /* Reset flags */ ++ ((u_int8_t *)tcph)[13] = 0; ++ tcph->rst = 1; ++ tcph->ack = needs_ack; ++ ++ tcph->window = 0; ++ tcph->urg_ptr = 0; ++ ++ /* Adjust TCP checksum */ ++ tcph->check = 0; ++ tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), ++ nskb->nh.iph->saddr, ++ nskb->nh.iph->daddr, ++ csum_partial((char *)tcph, ++ sizeof(struct tcphdr), 0)); ++ ++ /* Adjust IP TTL, DF */ ++ nskb->nh.iph->ttl = MAXTTL; ++ /* Set DF, id = 0 */ ++ nskb->nh.iph->frag_off = htons(IP_DF); ++ nskb->nh.iph->id = 0; ++ ++ /* Adjust IP checksum */ ++ nskb->nh.iph->check = 0; ++ nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, ++ nskb->nh.iph->ihl); ++ ++ /* Routing */ ++ if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr, ++ RT_TOS(nskb->nh.iph->tos) | RTO_CONN, ++ 0) != 0) ++ goto free_nskb; ++ ++ dst_release(nskb->dst); ++ nskb->dst = &rt->u.dst; ++ ++ /* "Never happens" */ ++ if (nskb->len > nskb->dst->pmtu) ++ goto free_nskb; ++ ++ NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, ++ ip_finish_output); ++ return; ++ ++ free_nskb: ++ kfree_skb(nskb); ++} ++#endif ++ ++static unsigned int reject6_target(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *targinfo, ++ void *userinfo) ++{ ++ const struct ip6t_reject_info *reject = targinfo; ++ ++ /* WARNING: This code causes reentry within ip6tables. ++ This means that the ip6tables jump stack is now crap. We ++ must return an absolute verdict. --RR */ ++ DEBUGP("REJECTv6: calling icmpv6_send\n"); ++ switch (reject->with) { ++ case IP6T_ICMP6_NO_ROUTE: ++ icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out); ++ break; ++ case IP6T_ICMP6_ADM_PROHIBITED: ++ icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out); ++ break; ++ case IP6T_ICMP6_NOT_NEIGHBOUR: ++ icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out); ++ break; ++ case IP6T_ICMP6_ADDR_UNREACH: ++ icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out); ++ break; ++ case IP6T_ICMP6_PORT_UNREACH: ++ icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out); ++ break; ++#if 0 ++ case IPT_ICMP_ECHOREPLY: { ++ struct icmp6hdr *icmph = (struct icmphdr *) ++ ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl); ++ unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; ++ ++ /* Not non-head frags, or truncated */ ++ if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0) ++ && datalen >= 4) { ++ /* Usually I don't like cut & pasting code, ++ but dammit, my party is starting in 45 ++ mins! --RR */ ++ struct icmp_bxm icmp_param; ++ ++ icmp_param.icmph=*icmph; ++ icmp_param.icmph.type=ICMP_ECHOREPLY; ++ icmp_param.data_ptr=(icmph+1); ++ icmp_param.data_len=datalen; ++ icmp_reply(&icmp_param, *pskb); ++ } ++ } ++ break; ++ case IPT_TCP_RESET: ++ send_reset(*pskb); ++ break; ++#endif ++ default: ++ printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with); ++ break; ++ } ++ ++ return NF_DROP; ++} ++ ++static inline int find_ping_match(const struct ip6t_entry_match *m) ++{ ++ const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data; ++ ++ if (strcmp(m->u.kernel.match->name, "icmp6") == 0 ++ && icmpinfo->type == ICMPV6_ECHO_REQUEST ++ && !(icmpinfo->invflags & IP6T_ICMP_INV)) ++ return 1; ++ ++ return 0; ++} ++ ++static int check(const char *tablename, ++ const struct ip6t_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_reject_info *rejinfo = targinfo; ++ ++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) { ++ DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize); ++ return 0; ++ } ++ ++ /* Only allow these for packet filtering. */ ++ if (strcmp(tablename, "filter") != 0) { ++ DEBUGP("REJECTv6: bad table `%s'.\n", tablename); ++ return 0; ++ } ++ if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN) ++ | (1 << NF_IP6_FORWARD) ++ | (1 << NF_IP6_LOCAL_OUT))) != 0) { ++ DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask); ++ return 0; ++ } ++ ++ if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { ++ /* Must specify that it's an ICMP ping packet. */ ++ if (e->ipv6.proto != IPPROTO_ICMPV6 ++ || (e->ipv6.invflags & IP6T_INV_PROTO)) { ++ DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n"); ++ return 0; ++ } ++ /* Must contain ICMP match. */ ++ if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) { ++ DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n"); ++ return 0; ++ } ++ } else if (rejinfo->with == IP6T_TCP_RESET) { ++ /* Must specify that it's a TCP packet */ ++ if (e->ipv6.proto != IPPROTO_TCP ++ || (e->ipv6.invflags & IP6T_INV_PROTO)) { ++ DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n"); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_target ip6t_reject_reg ++= { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ip6t_register_target(&ip6t_reject_reg)) ++ return -EINVAL; ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_target(&ip6t_reject_reg); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.4.20/net/ipv6/netfilter/ip6t_ROUTE.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_ROUTE.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_ROUTE.c Wed Sep 24 09:17:27 2003 +@@ -0,0 +1,289 @@ ++/* ++ * This implements the ROUTE v6 target, which enables you to setup unusual ++ * routes not supported by the standard kernel routing table. ++ * ++ * Copyright (C) 2003 Cedric de Launois ++ * ++ * v 1.0 2003/08/05 ++ * ++ * This software is distributed under GNU GPL v2, 1991 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 1 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#define NIP6(addr) \ ++ ntohs((addr).s6_addr16[0]), \ ++ ntohs((addr).s6_addr16[1]), \ ++ ntohs((addr).s6_addr16[2]), \ ++ ntohs((addr).s6_addr16[3]), \ ++ ntohs((addr).s6_addr16[4]), \ ++ ntohs((addr).s6_addr16[5]), \ ++ ntohs((addr).s6_addr16[6]), \ ++ ntohs((addr).s6_addr16[7]) ++ ++/* Route the packet according to the routing keys specified in ++ * route_info. Keys are : ++ * - ifindex : ++ * 0 if no oif preferred, ++ * otherwise set to the index of the desired oif ++ * - route_info->gw : ++ * 0 if no gateway specified, ++ * otherwise set to the next host to which the pkt must be routed ++ * If success, skb->dev is the output device to which the packet must ++ * be sent and skb->dst is not NULL ++ * ++ * RETURN: 1 if the packet was succesfully routed to the ++ * destination desired ++ * 0 if the kernel routing table could not route the packet ++ * according to the keys specified ++ */ ++static int ++route6(struct sk_buff *skb, ++ unsigned int ifindex, ++ const struct ip6t_route_target_info *route_info) ++{ ++ struct rt6_info *rt = NULL; ++ struct ipv6hdr *ipv6h = skb->nh.ipv6h; ++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw; ++ ++ DEBUGP("ip6t_ROUTE: called with: "); ++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); ++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw)); ++ DEBUGP("OUT=%s\n", route_info->oif); ++ ++ if (ipv6_addr_any(gw)) ++ rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1); ++ else ++ rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1); ++ ++ if (!rt) ++ goto no_route; ++ ++ DEBUGP("ip6t_ROUTE: routing gives: "); ++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr)); ++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway)); ++ DEBUGP("OUT=%s\n", rt->rt6i_dev->name); ++ ++ if (ifindex && rt->rt6i_dev->ifindex!=ifindex) ++ goto wrong_route; ++ ++ if (!rt->rt6i_nexthop) { ++ DEBUGP("ip6t_ROUTE: discovering neighbour\n"); ++ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr); ++ } ++ ++ /* Drop old route. */ ++ dst_release(skb->dst); ++ skb->dst = &rt->u.dst; ++ skb->dev = rt->rt6i_dev; ++ return 1; ++ ++ wrong_route: ++ dst_release(&rt->u.dst); ++ no_route: ++ if (!net_ratelimit()) ++ return 0; ++ ++ printk("ip6t_ROUTE: no explicit route found "); ++ if (ifindex) ++ printk("via interface %s ", route_info->oif); ++ if (!ipv6_addr_any(gw)) ++ printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw)); ++ printk("\n"); ++ return 0; ++} ++ ++ ++/* Stolen from ip6_output_finish ++ * PRE : skb->dev is set to the device we are leaving by ++ * skb->dst is not NULL ++ * POST: the packet is sent with the link layer header pushed ++ * the packet is destroyed ++ */ ++static void ip_direct_send(struct sk_buff *skb) ++{ ++ struct dst_entry *dst = skb->dst; ++ struct hh_cache *hh = dst->hh; ++ ++ if (hh) { ++ read_lock_bh(&hh->hh_lock); ++ memcpy(skb->data - 16, hh->hh_data, 16); ++ read_unlock_bh(&hh->hh_lock); ++ skb_push(skb, hh->hh_len); ++ hh->hh_output(skb); ++ } else if (dst->neighbour) ++ dst->neighbour->output(skb); ++ else { ++ if (net_ratelimit()) ++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n"); ++ kfree_skb(skb); ++ } ++} ++ ++ ++static unsigned int ++route6_oif(const struct ip6t_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ unsigned int ifindex = 0; ++ struct net_device *dev_out = NULL; ++ ++ /* The user set the interface name to use. ++ * Getting the current interface index. ++ */ ++ if ((dev_out = dev_get_by_name(route_info->oif))) { ++ ifindex = dev_out->ifindex; ++ } else { ++ /* Unknown interface name : packet dropped */ ++ if (net_ratelimit()) ++ DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif); ++ ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ return IP6T_CONTINUE; ++ else ++ return NF_DROP; ++ } ++ ++ /* Trying the standard way of routing packets */ ++ if (route6(skb, ifindex, route_info)) { ++ dev_put(dev_out); ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ return IP6T_CONTINUE; ++ ++ ip_direct_send(skb); ++ return NF_STOLEN; ++ } else ++ return NF_DROP; ++} ++ ++ ++static unsigned int ++route6_gw(const struct ip6t_route_target_info *route_info, ++ struct sk_buff *skb) ++{ ++ if (route6(skb, 0, route_info)) { ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ return IP6T_CONTINUE; ++ ++ ip_direct_send(skb); ++ return NF_STOLEN; ++ } else ++ return NF_DROP; ++} ++ ++ ++static unsigned int ++ip6t_route_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_route_target_info *route_info = targinfo; ++ struct sk_buff *skb = *pskb; ++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw; ++ ++ if (route_info->flags & IP6T_ROUTE_CONTINUE) ++ goto do_it; ++ ++ /* If we are at PREROUTING or INPUT hook ++ * the TTL isn't decreased by the IP stack ++ */ ++ if (hooknum == NF_IP6_PRE_ROUTING || ++ hooknum == NF_IP6_LOCAL_IN) { ++ ++ struct ipv6hdr *ipv6h = skb->nh.ipv6h; ++ ++ if (ipv6h->hop_limit <= 1) { ++ /* Force OUTPUT device used as source address */ ++ skb->dev = skb->dst->dev; ++ ++ icmpv6_send(skb, ICMPV6_TIME_EXCEED, ++ ICMPV6_EXC_HOPLIMIT, 0, skb->dev); ++ ++ return NF_DROP; ++ } ++ ++ ipv6h->hop_limit--; ++ } ++ ++ ++ do_it: ++ if (route_info->oif[0]) ++ return route6_oif(route_info, *pskb); ++ ++ if (!ipv6_addr_any(gw)) ++ return route6_gw(route_info, *pskb); ++ ++ if (net_ratelimit()) ++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n"); ++ ++ return IP6T_CONTINUE; ++} ++ ++ ++static int ++ip6t_route_checkentry(const char *tablename, ++ const struct ip6t_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (strcmp(tablename, "mangle") != 0) { ++ printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n"); ++ return 0; ++ } ++ ++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) { ++ printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n", ++ targinfosize, ++ IP6T_ALIGN(sizeof(struct ip6t_route_target_info))); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static struct ip6t_target ip6t_route_reg = { ++ .name = "ROUTE", ++ .target = ip6t_route_target, ++ .checkentry = ip6t_route_checkentry, ++ .me = THIS_MODULE ++}; ++ ++ ++static int __init init(void) ++{ ++ printk(KERN_DEBUG "registering ipv6 ROUTE target\n"); ++ if (ip6t_register_target(&ip6t_route_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_target(&ip6t_route_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_TRACE.c linux-2.4.20/net/ipv6/netfilter/ip6t_TRACE.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_TRACE.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_TRACE.c Wed Sep 24 09:18:14 2003 +@@ -0,0 +1,66 @@ ++/* This is a module which is used for setting ++ * the NFC_TRACE flag in the nfcache field of an skb. ++ */ ++#include ++#include ++ ++#include ++ ++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) ++{ ++ (*pskb)->nfcache |= NFC_TRACE; ++ return IP6T_CONTINUE; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ if (targinfosize != 0) { ++ printk(KERN_WARNING "TRACE: targinfosize %u != 0\n", ++ targinfosize); ++ return 0; ++ } ++ ++ if (strcmp(tablename, "raw") != 0) { ++ printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_target ip6t_trace_reg = { ++ .list = { NULL, NULL }, ++ .name = "TRACE", ++ .target = target, ++ .checkentry = checkentry, ++ .destroy = NULL, ++ .me = THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ip6t_register_target(&ip6t_trace_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_target(&ip6t_trace_reg); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_ah.c linux-2.4.20/net/ipv6/netfilter/ip6t_ah.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_ah.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_ah.c Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,207 @@ ++/* Kernel module to match AH parameters. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("IPv6 AH match"); ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++struct ahhdr { ++ __u8 nexthdr; ++ __u8 hdrlen; ++ __u16 reserved; ++ __u32 spi; ++}; ++ ++/* Returns 1 if the spi is matched by the range, 0 otherwise */ ++static inline int ++spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) ++{ ++ int r=0; ++ DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', ++ min,spi,max); ++ r=(spi >= min && spi <= max) ^ invert; ++ DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); ++ return 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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct ahhdr *ah = NULL; ++ const struct ip6t_ah *ahinfo = matchinfo; ++ unsigned int temp; ++ int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ ++ /*DEBUGP("IPv6 AH entered\n");*/ ++ /* if (opt->auth == 0) return 0; ++ * It does not filled on output */ ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_ah header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(struct ipv6_opt_hdr *)skb->data+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* AH -> evaluate */ ++ if (nexthdr == NEXTHDR_AUTH) { ++ temp |= MASK_AH; ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_ah: new pointer too large! \n"); ++ break; ++ } ++ } ++ ++ /* AH header not found */ ++ if ( temp != MASK_AH ) return 0; ++ ++ if (len < (int)sizeof(struct ahhdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ ah = (struct ahhdr *) (skb->data + ptr); ++ ++ DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); ++ DEBUGP("RES %04X ", ah->reserved); ++ DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); ++ ++ DEBUGP("IPv6 AH spi %02X ", ++ (spi_match(ahinfo->spis[0], ahinfo->spis[1], ++ ntohl(ah->spi), ++ !!(ahinfo->invflags & IP6T_AH_INV_SPI)))); ++ DEBUGP("len %02X %04X %02X ", ++ ahinfo->hdrlen, hdrlen, ++ (!ahinfo->hdrlen || ++ (ahinfo->hdrlen == hdrlen) ^ ++ !!(ahinfo->invflags & IP6T_AH_INV_LEN))); ++ DEBUGP("res %02X %04X %02X\n", ++ ahinfo->hdrres, ah->reserved, ++ !(ahinfo->hdrres && ah->reserved)); ++ ++ return (ah != NULL) ++ && ++ (spi_match(ahinfo->spis[0], ahinfo->spis[1], ++ ntohl(ah->spi), ++ !!(ahinfo->invflags & IP6T_AH_INV_SPI))) ++ && ++ (!ahinfo->hdrlen || ++ (ahinfo->hdrlen == hdrlen) ^ ++ !!(ahinfo->invflags & IP6T_AH_INV_LEN)) ++ && ++ !(ahinfo->hdrres && ah->reserved); ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_ah *ahinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) { ++ DEBUGP("ip6t_ah: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah))); ++ return 0; ++ } ++ if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { ++ DEBUGP("ip6t_ah: unknown flags %X\n", ++ ahinfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match ah_match ++= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&ah_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&ah_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_condition.c linux-2.4.20/net/ipv6/netfilter/ip6t_condition.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_condition.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_condition.c Wed Sep 24 09:17:36 2003 +@@ -0,0 +1,254 @@ ++/*-------------------------------------------*\ ++| Netfilter Condition Module for IPv6 | ++| | ++| Description: This module allows firewall | ++| rules to match using condition variables | ++| stored in /proc files. | ++| | ++| Author: Stephane Ouellette 2003-02-10 | ++| | ++| | ++| This software is distributed under the | ++| terms of the GNU GPL. | ++\*-------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifndef CONFIG_PROC_FS ++#error "Proc file system support is required for this module" ++#endif ++ ++ ++MODULE_AUTHOR("Stephane Ouellette "); ++MODULE_DESCRIPTION("Allows rules to match against condition variables"); ++MODULE_LICENSE("GPL"); ++ ++ ++struct condition_variable { ++ struct condition_variable *next; ++ struct proc_dir_entry *status_proc; ++ atomic_t refcount; ++ int enabled; /* TRUE == 1, FALSE == 0 */ ++}; ++ ++ ++static rwlock_t list_lock; ++static struct condition_variable *head = NULL; ++static struct proc_dir_entry *proc_net_condition = NULL; ++ ++ ++static int ++ipt_condition_read_info(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (offset == 0) { ++ *start = buffer; ++ buffer[0] = (var->enabled) ? '1' : '0'; ++ buffer[1] = '\n'; ++ return 2; ++ } ++ ++ *eof = 1; ++ return 0; ++} ++ ++ ++static int ++ipt_condition_write_info(struct file *file, const char *buffer, ++ unsigned long length, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (length) { ++ /* Match only on the first character */ ++ switch (buffer[0]) { ++ case '0': ++ var->enabled = 0; ++ break; ++ case '1': ++ var->enabled = 1; ++ } ++ } ++ ++ return (int) length; ++} ++ ++ ++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 condition6_info *info = ++ (const struct condition6_info *) matchinfo; ++ struct condition_variable *var; ++ int condition_status = 0; ++ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ condition_status = var->enabled; ++ break; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ return condition_status ^ info->invert; ++} ++ ++ ++ ++static int ++checkentry(const char *tablename, const struct ip6t_ip6 *ip, ++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask) ++{ ++ struct condition6_info *info = ++ (struct condition6_info *) matchinfo; ++ struct condition_variable *var, *newvar; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) ++ return 0; ++ ++ /* The first step is to check if the condition variable already exists. */ ++ /* Here, a read lock is sufficient because we won't change the list */ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ /* At this point, we need to allocate a new condition variable */ ++ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); ++ ++ if (!newvar) ++ return -ENOMEM; ++ ++ /* Create the condition variable's proc file entry */ ++ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); ++ ++ if (!newvar->status_proc) { ++ /* ++ * There are two possibilities: ++ * 1- Another condition variable with the same name has been created, which is valid. ++ * 2- There was a memory allocation error. ++ */ ++ kfree(newvar); ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ return -ENOMEM; ++ } ++ ++ atomic_set(&newvar->refcount, 1); ++ newvar->enabled = 0; ++ newvar->status_proc->owner = THIS_MODULE; ++ newvar->status_proc->data = newvar; ++ wmb(); ++ newvar->status_proc->read_proc = ipt_condition_read_info; ++ newvar->status_proc->write_proc = ipt_condition_write_info; ++ ++ write_lock(&list_lock); ++ ++ newvar->next = head; ++ head = newvar; ++ ++ write_unlock(&list_lock); ++ ++ return 1; ++} ++ ++ ++static void ++destroy(void *matchinfo, unsigned int matchsize) ++{ ++ struct condition6_info *info = ++ (struct condition6_info *) matchinfo; ++ struct condition_variable *var, *prev = NULL; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) ++ return; ++ ++ write_lock(&list_lock); ++ ++ for (var = head; var && strcmp(info->name, var->status_proc->name); ++ prev = var, var = var->next); ++ ++ if (var && atomic_dec_and_test(&var->refcount)) { ++ if (prev) ++ prev->next = var->next; ++ else ++ head = var->next; ++ ++ write_unlock(&list_lock); ++ remove_proc_entry(var->status_proc->name, proc_net_condition); ++ kfree(var); ++ } else ++ write_unlock(&list_lock); ++} ++ ++ ++static struct ip6t_match condition_match = { ++ .name = "condition", ++ .match = &match, ++ .checkentry = &checkentry, ++ .destroy = &destroy, ++ .me = THIS_MODULE ++}; ++ ++ ++static int __init ++init(void) ++{ ++ int errorcode; ++ ++ rwlock_init(&list_lock); ++ proc_net_condition = proc_mkdir("ip6t_condition", proc_net); ++ ++ if (proc_net_condition) { ++ errorcode = ipt_register_match(&condition_match); ++ ++ if (errorcode) ++ remove_proc_entry("ip6t_condition", proc_net); ++ } else ++ errorcode = -EACCES; ++ ++ return errorcode; ++} ++ ++ ++static void __exit ++fini(void) ++{ ++ ipt_unregister_match(&condition_match); ++ remove_proc_entry("ip6t_condition", proc_net); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_dst.c linux-2.4.20/net/ipv6/netfilter/ip6t_dst.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_dst.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_dst.c Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,276 @@ ++/* Kernel module to match Hop-by-Hop and Destination parameters. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define LOW(n) (n & 0x00FF) ++ ++#define HOPBYHOP 0 ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++#if HOPBYHOP ++MODULE_DESCRIPTION("IPv6 HbH match"); ++#else ++MODULE_DESCRIPTION("IPv6 DST match"); ++#endif ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* ++ * (Type & 0xC0) >> 6 ++ * 0 -> ignorable ++ * 1 -> must drop the packet ++ * 2 -> send ICMP PARM PROB regardless and drop packet ++ * 3 -> Send ICMP if not a multicast address and drop packet ++ * (Type & 0x20) >> 5 ++ * 0 -> invariant ++ * 1 -> can change the routing ++ * (Type & 0x1F) Type ++ * 0 -> PAD0 (only 1 byte!) ++ * 1 -> PAD1 LENGTH info (total length = length + 2) ++ * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) ++ * 5 -> RTALERT 2 x x ++ */ ++ ++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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct ipv6_opt_hdr *optsh = NULL; ++ const struct ip6t_opts *optinfo = matchinfo; ++ unsigned int temp; ++ unsigned int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ unsigned int ret = 0; ++ u_int16_t *optdesc = NULL; ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_opts header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(void *)(skb->data)+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* OPTS -> evaluate */ ++#if HOPBYHOP ++ if (nexthdr == NEXTHDR_HOP) { ++ temp |= MASK_HOPOPTS; ++#else ++ if (nexthdr == NEXTHDR_DEST) { ++ temp |= MASK_DSTOPTS; ++#endif ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_opts: new pointer is too large! \n"); ++ break; ++ } ++ } ++ ++ /* OPTIONS header not found */ ++#if HOPBYHOP ++ if ( temp != MASK_HOPOPTS ) return 0; ++#else ++ if ( temp != MASK_DSTOPTS ) return 0; ++#endif ++ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ if (len < hdrlen){ ++ /* Packet smaller than it's length field */ ++ return 0; ++ } ++ ++ optsh=(void *)(skb->data)+ptr; ++ ++ DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); ++ ++ DEBUGP("len %02X %04X %02X ", ++ optinfo->hdrlen, hdrlen, ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); ++ ++ ret = (optsh != NULL) ++ && ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); ++ ++ temp = len = 0; ++ ptr += 2; ++ hdrlen -= 2; ++ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ ++ return ret; ++ } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { ++ DEBUGP("Not strict - not implemented"); ++ } else { ++ DEBUGP("Strict "); ++ DEBUGP("#%d ",optinfo->optsnr); ++ for(temp=0; tempoptsnr; temp++){ ++ optdesc = (void *)(skb->data)+ptr; ++ /* Type check */ ++ if ( (unsigned char)*optdesc != ++ (optinfo->opts[temp] & 0xFF00)>>8 ){ ++ DEBUGP("Tbad %02X %02X\n", ++ (unsigned char)*optdesc, ++ (optinfo->opts[temp] & ++ 0xFF00)>>8); ++ return 0; ++ } else { ++ DEBUGP("Tok "); ++ } ++ /* Length check */ ++ if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && ++ (unsigned char)*optdesc != 0){ ++ if ( ntohs((u16)*optdesc) != ++ optinfo->opts[temp] ){ ++ DEBUGP("Lbad %02X %04X %04X\n", ++ (unsigned char)*optdesc, ++ ntohs((u16)*optdesc), ++ optinfo->opts[temp]); ++ return 0; ++ } else { ++ DEBUGP("Lok "); ++ } ++ } ++ /* Step to the next */ ++ if ((unsigned char)*optdesc == 0){ ++ DEBUGP("PAD0 \n"); ++ ptr++; ++ hdrlen--; ++ } else { ++ ptr += LOW(ntohs(*optdesc)); ++ hdrlen -= LOW(ntohs(*optdesc)); ++ DEBUGP("len%04X \n", ++ LOW(ntohs(*optdesc))); ++ } ++ if (ptr > skb->len || ( !hdrlen && ++ (temp != optinfo->optsnr - 1))) { ++ DEBUGP("new pointer is too large! \n"); ++ break; ++ } ++ } ++ if (temp == optinfo->optsnr) ++ return ret; ++ else return 0; ++ } ++ ++ return 0; ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_opts *optsinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { ++ DEBUGP("ip6t_opts: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); ++ return 0; ++ } ++ if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { ++ DEBUGP("ip6t_opts: unknown flags %X\n", ++ optsinfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match opts_match ++#if HOPBYHOP ++= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE }; ++#else ++= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE }; ++#endif ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&opts_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&opts_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_esp.c linux-2.4.20/net/ipv6/netfilter/ip6t_esp.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_esp.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_esp.c Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,175 @@ ++/* Kernel module to match ESP parameters. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("IPv6 ESP match"); ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++struct esphdr { ++ __u32 spi; ++}; ++ ++/* Returns 1 if the spi is matched by the range, 0 otherwise */ ++static inline int ++spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) ++{ ++ int r=0; ++ DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', ++ min,spi,max); ++ r=(spi >= min && spi <= max) ^ invert; ++ DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); ++ return 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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct esphdr *esp = NULL; ++ const struct ip6t_esp *espinfo = matchinfo; ++ unsigned int temp; ++ int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ ++ /* Make sure this isn't an evil packet */ ++ /*DEBUGP("ipv6_esp entered \n");*/ ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ int hdrlen; ++ ++ DEBUGP("ipv6_esp header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ temp |= MASK_ESP; ++ break; ++ } ++ ++ hdr=(struct ipv6_opt_hdr *)skb->data+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_esp: new pointer too large! \n"); ++ break; ++ } ++ } ++ ++ /* ESP header not found */ ++ if ( temp != MASK_ESP ) return 0; ++ ++ if (len < (int)sizeof(struct esphdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ esp = (struct esphdr *) (skb->data + ptr); ++ ++ DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi)); ++ ++ return (esp != NULL) ++ && spi_match(espinfo->spis[0], espinfo->spis[1], ++ ntohl(esp->spi), ++ !!(espinfo->invflags & IP6T_ESP_INV_SPI)); ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_esp *espinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) { ++ DEBUGP("ip6t_esp: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp))); ++ return 0; ++ } ++ if (espinfo->invflags & ~IP6T_ESP_INV_MASK) { ++ DEBUGP("ip6t_esp: unknown flags %X\n", ++ espinfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match esp_match ++= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&esp_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&esp_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_frag.c linux-2.4.20/net/ipv6/netfilter/ip6t_frag.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_frag.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_frag.c Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,239 @@ ++/* Kernel module to match FRAG parameters. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("IPv6 FRAG match"); ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#if 0 ++#if BYTE_ORDER == BIG_ENDIAN ++#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ ++#define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ ++#define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ ++#else /* BYTE_ORDER == LITTLE_ENDIAN */ ++#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ ++#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ ++#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ ++#endif ++#endif ++ ++#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ ++#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ ++#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ ++ ++struct fraghdr { ++ __u8 nexthdr; ++ __u8 hdrlen; ++ __u16 info; ++ __u32 id; ++}; ++ ++/* Returns 1 if the id is matched by the range, 0 otherwise */ ++static inline int ++id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert) ++{ ++ int r=0; ++ DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', ++ min,id,max); ++ r=(id >= min && id <= max) ^ invert; ++ DEBUGP(" result %s\n",r? "PASS" : "FAILED"); ++ return 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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct fraghdr *frag = NULL; ++ const struct ip6t_frag *fraginfo = matchinfo; ++ unsigned int temp; ++ int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_frag header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(struct ipv6_opt_hdr *)skb->data+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* FRAG -> evaluate */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ temp |= MASK_FRAGMENT; ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_frag: new pointer too large! \n"); ++ break; ++ } ++ } ++ ++ /* FRAG header not found */ ++ if ( temp != MASK_FRAGMENT ) return 0; ++ ++ if (len < (int)sizeof(struct fraghdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ frag = (struct fraghdr *) (skb->data + ptr); ++ ++ DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen); ++ DEBUGP("INFO %04X ", frag->info); ++ DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK); ++ DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK); ++ DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG); ++ DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id)); ++ ++ DEBUGP("IPv6 FRAG id %02X ", ++ (id_match(fraginfo->ids[0], fraginfo->ids[1], ++ ntohl(frag->id), ++ !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))); ++ DEBUGP("len %02X %04X %02X ", ++ fraginfo->hdrlen, hdrlen, ++ (!fraginfo->hdrlen || ++ (fraginfo->hdrlen == hdrlen) ^ ++ !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))); ++ DEBUGP("res %02X %02X %02X ", ++ (fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK, ++ !((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))); ++ DEBUGP("first %02X %02X %02X ", ++ (fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK, ++ !((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))); ++ DEBUGP("mf %02X %02X %02X ", ++ (fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG, ++ !((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))); ++ DEBUGP("last %02X %02X %02X\n", ++ (fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG, ++ !((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG))); ++ ++ return (frag != NULL) ++ && ++ (id_match(fraginfo->ids[0], fraginfo->ids[1], ++ ntohl(frag->id), ++ !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))) ++ && ++ (!fraginfo->hdrlen || ++ (fraginfo->hdrlen == hdrlen) ^ ++ !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)) ++ && ++ !((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)) ++ && ++ !((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)) ++ && ++ !((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))) ++ && ++ !((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)); ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_frag *fraginfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) { ++ DEBUGP("ip6t_frag: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag))); ++ return 0; ++ } ++ if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { ++ DEBUGP("ip6t_frag: unknown flags %X\n", ++ fraginfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match frag_match ++= { { NULL, NULL }, "frag", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&frag_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&frag_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.4.20/net/ipv6/netfilter/ip6t_fuzzy.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_fuzzy.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_fuzzy.c Wed Sep 24 09:16:45 2003 +@@ -0,0 +1,189 @@ ++/* ++ * This module implements a simple TSK FLC ++ * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims ++ * to limit , in an adaptive and flexible way , the packet rate crossing ++ * a given stream . It serves as an initial and very simple (but effective) ++ * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks. ++ * As a matter of fact , Fuzzy Logic can help us to insert any "behavior" ++ * into our code in a precise , adaptive and efficient manner. ++ * The goal is very similar to that of "limit" match , but using techniques of ++ * Fuzzy Control , that allow us to shape the transfer functions precisely , ++ * avoiding over and undershoots - and stuff like that . ++ * ++ * ++ * 2002-08-10 Hime Aguiar e Oliveira Jr. : Initial version. ++ * 2002-08-17 : Changed to eliminate floating point operations . ++ * 2002-08-23 : Coding style changes . ++ * 2003-04-08 Maciej Soltysiak : IPv6 Port ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH ++ Expressed in percentage ++*/ ++ ++#define PAR_LOW 1/100 ++#define PAR_HIGH 1 ++ ++static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED; ++ ++MODULE_AUTHOR("Hime Aguiar e Oliveira Junior "); ++MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); ++MODULE_LICENSE("GPL"); ++ ++static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi) ++{ ++ if (tx >= maxi) return 100; ++ ++ if (tx <= mini) return 0; ++ ++ return ((100 * (tx-mini)) / (maxi-mini)); ++} ++ ++static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi) ++{ ++ if (tx <= mini) return 100; ++ ++ if (tx >= maxi) return 0; ++ ++ return ((100 * (maxi - tx)) / (maxi - mini)); ++ ++} ++ ++static int ++ip6t_fuzzy_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) ++{ ++ /* From userspace */ ++ ++ struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo; ++ ++ u_int8_t random_number; ++ unsigned long amount; ++ u_int8_t howhigh, howlow; ++ ++ ++ spin_lock_bh(&fuzzy_lock); /* Rise the lock */ ++ ++ info->bytes_total += pskb->len; ++ info->packets_total++; ++ ++ info->present_time = jiffies; ++ ++ if (info->present_time >= info->previous_time) ++ amount = info->present_time - info->previous_time; ++ else { ++ /* There was a transition : I choose to re-sample ++ and keep the old acceptance rate... ++ */ ++ ++ amount = 0; ++ info->previous_time = info->present_time; ++ info->bytes_total = info->packets_total = 0; ++ }; ++ ++ if ( amount > HZ/10) {/* More than 100 ms elapsed ... */ ++ ++ info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \ ++ / amount); ++ ++ info->previous_time = info->present_time; ++ info->bytes_total = info->packets_total = 0; ++ ++ howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); ++ howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); ++ ++ info->acceptance_rate = (u_int8_t) \ ++ (howhigh * PAR_LOW + PAR_HIGH * howlow); ++ ++ /* In fact, the above defuzzification would require a denominator ++ * proportional to (howhigh+howlow) but, in this particular case, ++ * that expression is constant. ++ * An imediate consequence is that it is not necessary to call ++ * both mf_high and mf_low - but to keep things understandable, ++ * I did so. ++ */ ++ ++ } ++ ++ spin_unlock_bh(&fuzzy_lock); /* Release the lock */ ++ ++ ++ if (info->acceptance_rate < 100) ++ { ++ get_random_bytes((void *)(&random_number), 1); ++ ++ /* If within the acceptance , it can pass => don't match */ ++ if (random_number <= (255 * info->acceptance_rate) / 100) ++ return 0; ++ else ++ return 1; /* It can't pass (It matches) */ ++ }; ++ ++ return 0; /* acceptance_rate == 100 % => Everything passes ... */ ++ ++} ++ ++static int ++ip6t_fuzzy_checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ ++ const struct ip6t_fuzzy_info *info = matchinfo; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) { ++ printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize, ++ IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))); ++ return 0; ++ } ++ ++ if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE) ++ || (info->minimum_rate >= info->maximum_rate)) { ++ printk("ip6t_fuzzy: BAD limits , please verify !!!\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match ip6t_fuzzy_reg = { ++ {NULL, NULL}, ++ "fuzzy", ++ ip6t_fuzzy_match, ++ ip6t_fuzzy_checkentry, ++ NULL, ++ THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ip6t_register_match(&ip6t_fuzzy_reg)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_match(&ip6t_fuzzy_reg); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_hbh.c linux-2.4.20/net/ipv6/netfilter/ip6t_hbh.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_hbh.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_hbh.c Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,276 @@ ++/* Kernel module to match Hop-by-Hop and Destination parameters. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define LOW(n) (n & 0x00FF) ++ ++#define HOPBYHOP 1 ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++#if HOPBYHOP ++MODULE_DESCRIPTION("IPv6 HbH match"); ++#else ++MODULE_DESCRIPTION("IPv6 DST match"); ++#endif ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* ++ * (Type & 0xC0) >> 6 ++ * 0 -> ignorable ++ * 1 -> must drop the packet ++ * 2 -> send ICMP PARM PROB regardless and drop packet ++ * 3 -> Send ICMP if not a multicast address and drop packet ++ * (Type & 0x20) >> 5 ++ * 0 -> invariant ++ * 1 -> can change the routing ++ * (Type & 0x1F) Type ++ * 0 -> PAD0 (only 1 byte!) ++ * 1 -> PAD1 LENGTH info (total length = length + 2) ++ * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) ++ * 5 -> RTALERT 2 x x ++ */ ++ ++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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct ipv6_opt_hdr *optsh = NULL; ++ const struct ip6t_opts *optinfo = matchinfo; ++ unsigned int temp; ++ unsigned int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ unsigned int ret = 0; ++ u_int16_t *optdesc = NULL; ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_opts header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(void *)(skb->data)+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* OPTS -> evaluate */ ++#if HOPBYHOP ++ if (nexthdr == NEXTHDR_HOP) { ++ temp |= MASK_HOPOPTS; ++#else ++ if (nexthdr == NEXTHDR_DEST) { ++ temp |= MASK_DSTOPTS; ++#endif ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_opts: new pointer is too large! \n"); ++ break; ++ } ++ } ++ ++ /* OPTIONS header not found */ ++#if HOPBYHOP ++ if ( temp != MASK_HOPOPTS ) return 0; ++#else ++ if ( temp != MASK_DSTOPTS ) return 0; ++#endif ++ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ if (len < hdrlen){ ++ /* Packet smaller than it's length field */ ++ return 0; ++ } ++ ++ optsh=(void *)(skb->data)+ptr; ++ ++ DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); ++ ++ DEBUGP("len %02X %04X %02X ", ++ optinfo->hdrlen, hdrlen, ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); ++ ++ ret = (optsh != NULL) ++ && ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); ++ ++ temp = len = 0; ++ ptr += 2; ++ hdrlen -= 2; ++ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ ++ return ret; ++ } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { ++ DEBUGP("Not strict - not implemented"); ++ } else { ++ DEBUGP("Strict "); ++ DEBUGP("#%d ",optinfo->optsnr); ++ for(temp=0; tempoptsnr; temp++){ ++ optdesc = (void *)(skb->data)+ptr; ++ /* Type check */ ++ if ( (unsigned char)*optdesc != ++ (optinfo->opts[temp] & 0xFF00)>>8 ){ ++ DEBUGP("Tbad %02X %02X\n", ++ (unsigned char)*optdesc, ++ (optinfo->opts[temp] & ++ 0xFF00)>>8); ++ return 0; ++ } else { ++ DEBUGP("Tok "); ++ } ++ /* Length check */ ++ if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && ++ (unsigned char)*optdesc != 0){ ++ if ( ntohs((u16)*optdesc) != ++ optinfo->opts[temp] ){ ++ DEBUGP("Lbad %02X %04X %04X\n", ++ (unsigned char)*optdesc, ++ ntohs((u16)*optdesc), ++ optinfo->opts[temp]); ++ return 0; ++ } else { ++ DEBUGP("Lok "); ++ } ++ } ++ /* Step to the next */ ++ if ((unsigned char)*optdesc == 0){ ++ DEBUGP("PAD0 \n"); ++ ptr++; ++ hdrlen--; ++ } else { ++ ptr += LOW(ntohs(*optdesc)); ++ hdrlen -= LOW(ntohs(*optdesc)); ++ DEBUGP("len%04X \n", ++ LOW(ntohs(*optdesc))); ++ } ++ if (ptr > skb->len || ( !hdrlen && ++ (temp != optinfo->optsnr - 1))) { ++ DEBUGP("new pointer is too large! \n"); ++ break; ++ } ++ } ++ if (temp == optinfo->optsnr) ++ return ret; ++ else return 0; ++ } ++ ++ return 0; ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_opts *optsinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { ++ DEBUGP("ip6t_opts: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); ++ return 0; ++ } ++ if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { ++ DEBUGP("ip6t_opts: unknown flags %X\n", ++ optsinfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match opts_match ++#if HOPBYHOP ++= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE }; ++#else ++= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE }; ++#endif ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&opts_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&opts_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_hl.c linux-2.4.20/net/ipv6/netfilter/ip6t_hl.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_hl.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_hl.c Wed Sep 24 09:16:14 2003 +@@ -0,0 +1,74 @@ ++/* ++ * Hop Limit matching module ++ * Maciej Soltysiak ++ * Based on HW's ttl module ++ * ++ * This software is distributed under the terms GNU GPL ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Maciej Soltysiak "); ++MODULE_DESCRIPTION("IP tables Hop Limit matching module"); ++MODULE_LICENSE("GPL"); ++ ++static int match(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *matchinfo, ++ int offset, const void *hdr, u_int16_t datalen, ++ int *hotdrop) ++{ ++ const struct ip6t_hl_info *info = matchinfo; ++ const struct ipv6hdr *ip6h = skb->nh.ipv6h; ++ ++ switch (info->mode) { ++ case IP6T_HL_EQ: ++ return (ip6h->hop_limit == info->hop_limit); ++ break; ++ case IP6T_HL_NE: ++ return (!(ip6h->hop_limit == info->hop_limit)); ++ break; ++ case IP6T_HL_LT: ++ return (ip6h->hop_limit < info->hop_limit); ++ break; ++ case IP6T_HL_GT: ++ return (ip6h->hop_limit > info->hop_limit); ++ break; ++ default: ++ printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", ++ info->mode); ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int checkentry(const char *tablename, const struct ip6t_ip6 *ip, ++ void *matchinfo, unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info))) ++ return 0; ++ ++ return 1; ++} ++ ++static struct ip6t_match hl_match = { { NULL, NULL }, "hl", &match, ++ &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&hl_match); ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_match(&hl_match); ++ ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.4.20/net/ipv6/netfilter/ip6t_ipv6header.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_ipv6header.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_ipv6header.c Wed Sep 24 09:16:26 2003 +@@ -0,0 +1,153 @@ ++/* ipv6header match - matches IPv6 packets based ++on whether they contain certain headers */ ++ ++/* Original idea: Brad Chapman ++ * Rewritten by: Andras Kis-Szabo */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("IPv6 headers match"); ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++static int ++ipv6header_match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ const struct ip6t_ipv6header_info *info = matchinfo; ++ unsigned int temp; ++ int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ ++ /* Make sure this isn't an evil packet */ ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ int hdrlen; ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ temp |= MASK_NONE; ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ temp |= MASK_ESP; ++ break; ++ } ++ ++ hdr=(struct ipv6_opt_hdr *)skb->data+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ temp |= MASK_HOPOPTS; ++ break; ++ case NEXTHDR_ROUTING: ++ temp |= MASK_ROUTING; ++ break; ++ case NEXTHDR_FRAGMENT: ++ temp |= MASK_FRAGMENT; ++ break; ++ case NEXTHDR_AUTH: ++ temp |= MASK_AH; ++ break; ++ case NEXTHDR_DEST: ++ temp |= MASK_DSTOPTS; ++ break; ++ default: ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ break; ++ } ++ } ++ ++ if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) ) ++ temp |= MASK_PROTO; ++ ++ if (info->modeflag) ++ return (!( (temp & info->matchflags) ++ ^ info->matchflags) ^ info->invflags); ++ else ++ return (!( temp ^ info->matchflags) ^ info->invflags); ++} ++ ++static int ++ipv6header_checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ /* Check for obvious errors */ ++ /* This match is valid in all hooks! */ ++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match ++ip6t_ipv6header_match = { ++ { NULL, NULL }, ++ "ipv6header", ++ &ipv6header_match, ++ &ipv6header_checkentry, ++ THIS_MODULE ++}; ++ ++static int __init ipv6header_init(void) ++{ ++ return ip6t_register_match(&ip6t_ipv6header_match); ++} ++ ++static void __exit ipv6header_exit(void) ++{ ++ ip6t_unregister_match(&ip6t_ipv6header_match); ++} ++ ++module_init(ipv6header_init); ++module_exit(ipv6header_exit); ++ +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_nth.c linux-2.4.20/net/ipv6/netfilter/ip6t_nth.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_nth.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_nth.c Wed Sep 24 09:16:55 2003 +@@ -0,0 +1,173 @@ ++/* ++ This is a module which is used for match support for every Nth packet ++ This file is distributed under the terms of the GNU General Public ++ License (GPL). Copies of the GPL can be obtained from: ++ ftp://prep.ai.mit.edu/pub/gnu/GPL ++ ++ 2001-07-18 Fabrice MARIE : initial implementation. ++ 2001-09-20 Richard Wagner (rwagner@cloudnet.com) ++ * added support for multiple counters ++ * added support for matching on individual packets ++ in the counter cycle ++ 2003-04-30 Maciej Soltysiak : IPv6 Port ++ ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++/* ++ * State information. ++ */ ++struct state { ++ spinlock_t lock; ++ u_int16_t number; ++}; ++ ++static struct state states[IP6T_NTH_NUM_COUNTERS]; ++ ++static int ++ip6t_nth_match(const struct sk_buff *pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ /* Parameters from userspace */ ++ const struct ip6t_nth_info *info = matchinfo; ++ unsigned counter = info->counter; ++ if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) ++ { ++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1); ++ return 0; ++ }; ++ ++ spin_lock(&states[counter].lock); ++ ++ /* Are we matching every nth packet?*/ ++ if (info->packet == 0xFF) ++ { ++ /* We're matching every nth packet and only every nth packet*/ ++ /* Do we match or invert match? */ ++ if (info->not == 0) ++ { ++ if (states[counter].number == 0) ++ { ++ ++states[counter].number; ++ goto match; ++ } ++ if (states[counter].number >= info->every) ++ states[counter].number = 0; /* reset the counter */ ++ else ++ ++states[counter].number; ++ goto dontmatch; ++ } ++ else ++ { ++ if (states[counter].number == 0) ++ { ++ ++states[counter].number; ++ goto dontmatch; ++ } ++ if (states[counter].number >= info->every) ++ states[counter].number = 0; ++ else ++ ++states[counter].number; ++ goto match; ++ } ++ } ++ else ++ { ++ /* We're using the --packet, so there must be a rule for every value */ ++ if (states[counter].number == info->packet) ++ { ++ /* only increment the counter when a match happens */ ++ if (states[counter].number >= info->every) ++ states[counter].number = 0; /* reset the counter */ ++ else ++ ++states[counter].number; ++ goto match; ++ } ++ else ++ goto dontmatch; ++ } ++ ++ dontmatch: ++ /* don't match */ ++ spin_unlock(&states[counter].lock); ++ return 0; ++ ++ match: ++ spin_unlock(&states[counter].lock); ++ return 1; ++} ++ ++static int ++ip6t_nth_checkentry(const char *tablename, ++ const struct ip6t_ip6 *e, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ /* Parameters from userspace */ ++ const struct ip6t_nth_info *info = matchinfo; ++ unsigned counter = info->counter; ++ if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) ++ { ++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1); ++ return 0; ++ }; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) { ++ printk("nth: matchsize %u != %u\n", matchsize, ++ IP6T_ALIGN(sizeof(struct ip6t_nth_info))); ++ return 0; ++ } ++ ++ states[counter].number = info->startat; ++ ++ return 1; ++} ++ ++static struct ip6t_match ip6t_nth_reg = { ++ {NULL, NULL}, ++ "nth", ++ ip6t_nth_match, ++ ip6t_nth_checkentry, ++ NULL, ++ THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ unsigned counter; ++ memset(&states, 0, sizeof(states)); ++ if (ip6t_register_match(&ip6t_nth_reg)) ++ return -EINVAL; ++ ++ for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) ++ { ++ spin_lock_init(&(states[counter].lock)); ++ }; ++ ++ printk("ip6t_nth match loaded\n"); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_match(&ip6t_nth_reg); ++ printk("ip6t_nth match unloaded\n"); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_owner.c linux-2.4.20/net/ipv6/netfilter/ip6t_owner.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_owner.c Tue Oct 30 23:08:12 2001 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_owner.c Wed Sep 24 09:17:52 2003 +@@ -16,6 +16,38 @@ + MODULE_LICENSE("GPL"); + + 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; +@@ -119,6 +151,12 @@ + return 0; + } + ++ if(info->match & IP6T_OWNER_COMM) { ++ if (!match_comm(skb, info->comm) ^ ++ !!(info->invert & IP6T_OWNER_COMM)) ++ return 0; ++ } ++ + return 1; + } + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_random.c linux-2.4.20/net/ipv6/netfilter/ip6t_random.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_random.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_random.c Wed Sep 24 09:17:07 2003 +@@ -0,0 +1,97 @@ ++/* ++ 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. ++ 2003-04-30 Maciej Soltysiak : IPv6 Port ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++static int ++ip6t_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 ip6t_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 ++ip6t_rand_checkentry(const char *tablename, ++ const struct ip6t_ip6 *e, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ /* Parameters from userspace */ ++ const struct ip6t_rand_info *info = matchinfo; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rand_info))) { ++ printk("ip6t_random: matchsize %u != %u\n", matchsize, ++ IP6T_ALIGN(sizeof(struct ip6t_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("ip6t_random: invalid average %u\n", info->average); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match ip6t_rand_reg = { ++ {NULL, NULL}, ++ "random", ++ ip6t_rand_match, ++ ip6t_rand_checkentry, ++ NULL, ++ THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ip6t_register_match(&ip6t_rand_reg)) ++ return -EINVAL; ++ ++ printk("ip6t_random match loaded\n"); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ip6t_unregister_match(&ip6t_rand_reg); ++ printk("ip6t_random match unloaded\n"); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6t_rt.c linux-2.4.20/net/ipv6/netfilter/ip6t_rt.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6t_rt.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6t_rt.c Wed Sep 24 09:16:17 2003 +@@ -0,0 +1,294 @@ ++/* Kernel module to match ROUTING parameters. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("IPv6 RT match"); ++MODULE_AUTHOR("Andras Kis-Szabo "); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++/* Returns 1 if the id is matched by the range, 0 otherwise */ ++static inline int ++segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert) ++{ ++ int r=0; ++ DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', ++ min,id,max); ++ r=(id >= min && id <= max) ^ invert; ++ DEBUGP(" result %s\n",r? "PASS" : "FAILED"); ++ return 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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct ipv6_rt_hdr *route = NULL; ++ const struct ip6t_rt *rtinfo = matchinfo; ++ unsigned int temp; ++ unsigned int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ unsigned int ret = 0; ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ip6t_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_rt header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(struct ipv6_opt_hdr *)skb->data+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* ROUTING -> evaluate */ ++ if (nexthdr == NEXTHDR_ROUTING) { ++ temp |= MASK_ROUTING; ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_rt: new pointer is too large! \n"); ++ break; ++ } ++ } ++ ++ /* ROUTING header not found */ ++ if ( temp != MASK_ROUTING ) return 0; ++ ++ if (len < (int)sizeof(struct ipv6_rt_hdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ if (len < hdrlen){ ++ /* Pcket smaller than its length field */ ++ return 0; ++ } ++ ++ route = (struct ipv6_rt_hdr *) (skb->data + ptr); ++ ++ DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen); ++ DEBUGP("TYPE %04X ", route->type); ++ DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left)); ++ ++ DEBUGP("IPv6 RT segsleft %02X ", ++ (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], ++ ntohl(route->segments_left), ++ !!(rtinfo->invflags & IP6T_RT_INV_SGS)))); ++ DEBUGP("type %02X %02X %02X ", ++ rtinfo->rt_type, route->type, ++ (!(rtinfo->flags & IP6T_RT_TYP) || ++ ((rtinfo->rt_type == route->type) ^ ++ !!(rtinfo->invflags & IP6T_RT_INV_TYP)))); ++ DEBUGP("len %02X %04X %02X ", ++ rtinfo->hdrlen, hdrlen, ++ (!(rtinfo->flags & IP6T_RT_LEN) || ++ ((rtinfo->hdrlen == hdrlen) ^ ++ !!(rtinfo->invflags & IP6T_RT_INV_LEN)))); ++ DEBUGP("res %02X %02X %02X ", ++ (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap, ++ !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap))); ++ ++ ret = (route != NULL) ++ && ++ (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], ++ ntohl(route->segments_left), ++ !!(rtinfo->invflags & IP6T_RT_INV_SGS))) ++ && ++ (!(rtinfo->flags & IP6T_RT_LEN) || ++ ((rtinfo->hdrlen == hdrlen) ^ ++ !!(rtinfo->invflags & IP6T_RT_INV_LEN))) ++ && ++ (!(rtinfo->flags & IP6T_RT_TYP) || ++ ((rtinfo->rt_type == route->type) ^ ++ !!(rtinfo->invflags & IP6T_RT_INV_TYP))) ++ && ++ !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)); ++ ++ DEBUGP("#%d ",rtinfo->addrnr); ++ temp = len = ptr = 0; ++ if ( !(rtinfo->flags & IP6T_RT_FST) ){ ++ return ret; ++ } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) { ++ DEBUGP("Not strict "); ++ if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){ ++ DEBUGP("There isn't enough space\n"); ++ return 0; ++ } else { ++ DEBUGP("#%d ",rtinfo->addrnr); ++ ptr = 0; ++ for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){ ++ len = 0; ++ while ((u8)(((struct rt0_hdr *)route)-> ++ addr[temp].s6_addr[len]) == ++ (u8)(rtinfo->addrs[ptr].s6_addr[len])){ ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[ptr].s6_addr[len])); ++ len++; ++ if ( len == 16 ) break; ++ } ++ if (len==16) { ++ DEBUGP("ptr=%d temp=%d;\n",ptr,temp); ++ ptr++; ++ } else { ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[ptr].s6_addr[len])); ++ DEBUGP("!ptr=%d temp=%d;\n",ptr,temp); ++ } ++ if (ptr==rtinfo->addrnr) break; ++ } ++ DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr); ++ if ( (len == 16) && (ptr == rtinfo->addrnr)) ++ return ret; ++ else return 0; ++ } ++ } else { ++ DEBUGP("Strict "); ++ if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){ ++ DEBUGP("There isn't enough space\n"); ++ return 0; ++ } else { ++ DEBUGP("#%d ",rtinfo->addrnr); ++ for(temp=0; tempaddrnr; temp++){ ++ len = 0; ++ while ((u8)(((struct rt0_hdr *)route)-> ++ addr[temp].s6_addr[len]) == ++ (u8)(rtinfo->addrs[temp].s6_addr[len])){ ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[temp].s6_addr[len])); ++ len++; ++ if ( len == 16 ) break; ++ } ++ if (len!=16) { ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[temp].s6_addr[len])); ++ DEBUGP("!len=%d temp=%d;\n",len,temp); ++ break; ++ } ++ } ++ DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr); ++ if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16))) ++ return ret; ++ else return 0; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_rt *rtinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) { ++ DEBUGP("ip6t_rt: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt))); ++ return 0; ++ } ++ if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { ++ DEBUGP("ip6t_rt: unknown flags %X\n", ++ rtinfo->invflags); ++ return 0; ++ } ++ if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) && ++ (!(rtinfo->flags & IP6T_RT_TYP) || ++ (rtinfo->rt_type != 0) || ++ (rtinfo->invflags & IP6T_RT_INV_TYP)) ) { ++ DEBUGP("`--rt-type 0' required before `--rt-0-*'"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match rt_match ++= { { NULL, NULL }, "rt", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&rt_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&rt_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6table_mangle.c linux-2.4.20/net/ipv6/netfilter/ip6table_mangle.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6table_mangle.c Mon Feb 25 19:38:14 2002 ++++ linux-2.4.20/net/ipv6/netfilter/ip6table_mangle.c Wed Sep 24 09:16:14 2003 +@@ -157,7 +157,7 @@ + hop_limit = (*pskb)->nh.ipv6h->hop_limit; + + /* flowlabel and prio (includes version, which shouldn't change either */ +- flowlabel = (u_int32_t) (*pskb)->nh.ipv6h; ++ flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h); + + ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); + +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/ipv6/netfilter/ip6table_raw.c linux-2.4.20/net/ipv6/netfilter/ip6table_raw.c +--- linux-2.4.20.org/net/ipv6/netfilter/ip6table_raw.c Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/net/ipv6/netfilter/ip6table_raw.c Wed Sep 24 09:18:14 2003 +@@ -0,0 +1,156 @@ ++/* ++ * IPv6 raw table, a port of the IPv4 raw table to IPv6 ++ * ++ * Copyright (C) 2003 Jozsef Kadlecsik ++ */ ++#include ++#include ++ ++#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT)) ++ ++#if 0 ++#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args) ++#else ++#define DEBUGP(x, args...) ++#endif ++ ++/* Standard entry. */ ++struct ip6t_standard ++{ ++ struct ip6t_entry entry; ++ struct ip6t_standard_target target; ++}; ++ ++struct ip6t_error_target ++{ ++ struct ip6t_entry_target target; ++ char errorname[IP6T_FUNCTION_MAXNAMELEN]; ++}; ++ ++struct ip6t_error ++{ ++ struct ip6t_entry entry; ++ struct ip6t_error_target target; ++}; ++ ++static struct ++{ ++ struct ip6t_replace repl; ++ struct ip6t_standard entries[2]; ++ struct ip6t_error term; ++} initial_table __initdata ++= { { "raw", RAW_VALID_HOOKS, 3, ++ sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error), ++ { [NF_IP6_PRE_ROUTING] 0, ++ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) }, ++ { [NF_IP6_PRE_ROUTING] 0, ++ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) }, ++ 0, NULL, { } }, ++ { ++ /* PRE_ROUTING */ ++ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ip6t_entry), ++ sizeof(struct ip6t_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } }, ++ /* LOCAL_OUT */ ++ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ip6t_entry), ++ sizeof(struct ip6t_standard), ++ 0, { 0, 0 }, { } }, ++ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, ++ -NF_ACCEPT - 1 } }, ++ }, ++ /* ERROR */ ++ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, ++ 0, ++ sizeof(struct ip6t_entry), ++ sizeof(struct ip6t_error), ++ 0, { 0, 0 }, { } }, ++ { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, ++ { } }, ++ "ERROR" ++ } ++ } ++}; ++ ++static struct ip6t_table packet_raw = { ++ .list = { NULL, NULL }, ++ .name = "raw", ++ .table = &initial_table.repl, ++ .valid_hooks = RAW_VALID_HOOKS, ++ .lock = RW_LOCK_UNLOCKED, ++ .private = NULL, ++ .me = THIS_MODULE ++}; ++ ++/* The work comes in here from netfilter.c. */ ++static unsigned int ++ip6t_hook(unsigned int hook, ++ struct sk_buff **pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL); ++} ++ ++static struct nf_hook_ops ip6t_ops[] = { ++ /* PRE_ROUTING */ ++ { .list = { NULL, NULL }, ++ .hook = ip6t_hook, ++ .pf = PF_INET6, ++ .hooknum = NF_IP6_PRE_ROUTING, ++ .priority = NF_IP6_PRI_FIRST }, ++ /* LOCAL_OUT */ ++ { .list = { NULL, NULL }, ++ .hook = ip6t_hook, ++ .pf = PF_INET6, ++ .hooknum = NF_IP6_LOCAL_OUT, ++ .priority = NF_IP6_PRI_FIRST } ++}; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ /* Register table */ ++ ret = ip6t_register_table(&packet_raw); ++ if (ret < 0) ++ return ret; ++ ++ /* Register hooks */ ++ ret = nf_register_hook(&ip6t_ops[0]); ++ if (ret < 0) ++ goto cleanup_table; ++ ++ ret = nf_register_hook(&ip6t_ops[1]); ++ if (ret < 0) ++ goto cleanup_hook0; ++ ++ return ret; ++ ++ cleanup_hook0: ++ nf_unregister_hook(&ip6t_ops[0]); ++ cleanup_table: ++ ip6t_unregister_table(&packet_raw); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) ++ nf_unregister_hook(&ip6t_ops[i]); ++ ++ ip6t_unregister_table(&packet_raw); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nur --exclude '*.orig' linux-2.4.20.org/net/netsyms.c linux-2.4.20/net/netsyms.c +--- linux-2.4.20.org/net/netsyms.c Wed Sep 24 08:52:55 2003 ++++ linux-2.4.20/net/netsyms.c Wed Sep 24 09:26:45 2003 +@@ -296,6 +296,9 @@ + EXPORT_SYMBOL(unregister_inet6addr_notifier); + #include + EXPORT_SYMBOL(ip6_route_output); ++#ifdef CONFIG_NETFILTER ++EXPORT_SYMBOL(ip6_route_me_harder); ++#endif + #endif + #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE) + /* inet functions common to v4 and v6 */ +@@ -571,6 +574,7 @@ + #endif + #ifdef CONFIG_NETFILTER + #include ++#include + EXPORT_SYMBOL(nf_register_hook); + EXPORT_SYMBOL(nf_unregister_hook); + EXPORT_SYMBOL(nf_register_sockopt); +@@ -583,6 +587,10 @@ + EXPORT_SYMBOL(nf_setsockopt); + EXPORT_SYMBOL(nf_getsockopt); + EXPORT_SYMBOL(ip_ct_attach); ++EXPORT_SYMBOL(nf_log_register); ++EXPORT_SYMBOL(nf_log_unregister); ++EXPORT_SYMBOL(nf_log_packet); ++EXPORT_SYMBOL(nf_log); + #ifdef CONFIG_INET + #include + EXPORT_SYMBOL(ip_route_me_harder); +@@ -593,13 +601,6 @@ + + EXPORT_SYMBOL(softnet_data); + +-#if defined(CONFIG_IP_NF_MATCH_STEALTH_MODULE) +-#if !defined (CONFIG_IPV6_MODULE) && !defined (CONFIG_KHTTPD) && !defined (CONFIG_KHTTPD_MODULE) +-EXPORT_SYMBOL(tcp_v4_lookup_listener); +-#endif +-extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); +-EXPORT_SYMBOL(udp_v4_lookup); +-#endif + + #if defined(CONFIG_GRKERNSEC_RANDID) + EXPORT_SYMBOL(ip_randomid); +@@ -641,4 +642,28 @@ + EXPORT_SYMBOL(wireless_send_event); + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + ++#if defined(CONFIG_IP_NF_MATCH_STEALTH_MODULE) ++#if !defined (CONFIG_IPV6_MODULE) && !defined (CONFIG_KHTTPD) && !defined (CONFIG_KHTTPD_MODULE) ++EXPORT_SYMBOL(tcp_v4_lookup_listener); ++#endif ++#endif ++ ++#if defined(CONFIG_IP_NF_MATCH_STEALTH_MODULE) ++extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); ++#endif ++ ++#if defined(CONFIG_IP_NF_MATCH_STEALTH_MODULE)||defined(CONFIG_IP_NF_MATCH_OWNER)||defined(CONFIG_IP_NF_MATCH_OWNER_MODULE) ++EXPORT_SYMBOL(udp_v4_lookup); ++#endif ++ ++#if defined(CONFIG_IP_NF_MATCH_OWNER)||defined(CONFIG_IP_NF_MATCH_OWNER_MODULE) ++EXPORT_SYMBOL(tcp_v4_lookup); ++#endif /* CONFIG_IP_NF_MATCH_OWNER */ ++ ++#if defined(CONFIG_IP_NF_MATCH_OWNER)||defined(CONFIG_IP_NF_MATCH_OWNER_MODULE) ++#if !(defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)) ++EXPORT_SYMBOL(tcp_timewait_cachep); ++#endif ++#endif /* CONFIG_IP_NF_MATCH_OWNER */ ++ + #endif /* CONFIG_NET */ +diff -Nur --exclude '*.orig' linux-2.4.20.org/netfilter-patch-o-matic/patches linux-2.4.20/netfilter-patch-o-matic/patches +--- linux-2.4.20.org/netfilter-patch-o-matic/patches Thu Jan 1 00:00:00 1970 ++++ linux-2.4.20/netfilter-patch-o-matic/patches Wed Sep 24 09:20:32 2003 +@@ -0,0 +1,84 @@ ++./submitted/01_2.4.19.patch ++./submitted/02_2.4.20.patch ++./submitted/03_2.4.21.patch ++./submitted/04_2.4.22.patch ++./submitted/44_backport_ah_esp_fixes.patch ++./submitted/45_masq_routing_check.patch ++./submitted/54_ip_nat-macro-args.patch ++./submitted/58-ip_conntrack-macro-args.patch ++./submitted/60_nat_tftp-remove-warning.patch ++./submitted/72_recent_procfs_fix.patch ++./submitted/73_ipt_MASQUERADE-oif.patch ++./submitted/74_nat-range-fix.patch ++./submitted/75_REJECT_localpmtu-fix.patch ++./submitted/76_snmp-checksum_h-fix.patch ++./pending/39_ip_conntrack-proc.patch ++./pending/40_nf-log.patch ++./pending/40_nf-log.patch.ipv6 ++./pending/55_ipt_unclean-tcp-flag-table.patch ++./pending/59_ip_nat_h-unused-var.patch ++./pending/61-remove-memsets.patch ++./pending/63_getorigdst-tuple-zero.patch ++./pending/64_masquerade-sameip-noflush.patch ++./pending/65_irc-conntrack-mirc-serverlookup.patch ++./pending/66_ipv6header.patch ++./pending/67_nolocalout.patch ++./pending/68_local-nullbinding.patch ++./base/HL.patch.ipv6 ++./base/IPV4OPTSSTRIP.patch ++./base/NETLINK.patch ++./base/NETMAP.patch ++./base/REJECT.patch.ipv6 ++./base/SAME.patch ++./base/TTL.patch ++./base/connlimit.patch ++./base/fuzzy.patch ++./base/fuzzy6.patch.ipv6 ++./base/iprange.patch ++./base/ipv4options.patch ++./base/mport.patch ++./base/nth.patch ++./base/nth6.patch.ipv6 ++./base/osf.patch ++./base/pool.patch ++./base/psd.patch ++./base/quota.patch ++./base/random.patch ++./base/random6.patch.ipv6 ++./base/realm.patch ++./base/time.patch ++./base/u32.patch ++./extra/CLASSIFY.patch ++./extra/CONNMARK.patch ++./extra/IMQ.patch ++./extra/IMQ.patch.ipv6 ++./extra/IPMARK.patch ++./extra/ROUTE.patch ++./extra/ROUTE.patch.ipv6 ++./extra/TCPLAG.patch ++./extra/XOR.patch ++./extra/addrtype.patch ++./extra/condition.patch ++./extra/condition6.patch.ipv6 ++./extra/cuseeme-nat.patch ++./extra/eggdrop-conntrack.patch ++./extra/h323-conntrack-nat.patch ++./extra/ipt_TARPIT.patch ++./extra/iptables-loopcheck-speedup.patch ++./extra/mms-conntrack-nat.patch ++./extra/netfilter-docbook.patch ++./extra/nfnetlink-ctnetlink-0.11.patch ++./extra/owner-socketlookup.patch ++./extra/ownercmd.patch.ipv6 ++./extra/pptp-conntrack-nat.patch ++./extra/quake3-conntrack.patch ++./extra/rpc.patch ++./extra/rsh.patch ++./extra/string.patch ++./extra/talk-conntrack-nat.patch ++./userspace/ipt_REJECT-fake-source.patch ++./userspace/mark-bitwise-ops.patch ++./userspace/raw.patch ++./userspace/raw.patch.ipv6 ++./optimizations/ip_ct_refresh_optimization.patch ++./optimizations/ip_ct_refresh_optimization_pptp.patch -- 2.44.0