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