aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorYasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>2005-11-09 19:38:16 -0500
committerDavid S. Miller <davem@davemloft.net>2005-11-09 19:38:16 -0500
commit9fb9cbb1082d6b31fb45aa1a14432449a0df6cf1 (patch)
treec964a62bdd766eca436c30f51a9e33e2b798b0a6 /net/ipv4
parent6730c3c14421b7c924d06e31bb66e0adad225547 (diff)
[NETFILTER]: Add nf_conntrack subsystem.
The existing connection tracking subsystem in netfilter can only handle ipv4. There were basically two choices present to add connection tracking support for ipv6. We could either duplicate all of the ipv4 connection tracking code into an ipv6 counterpart, or (the choice taken by these patches) we could design a generic layer that could handle both ipv4 and ipv6 and thus requiring only one sub-protocol (TCP, UDP, etc.) connection tracking helper module to be written. In fact nf_conntrack is capable of working with any layer 3 protocol. The existing ipv4 specific conntrack code could also not deal with the pecularities of doing connection tracking on ipv6, which is also cured here. For example, these issues include: 1) ICMPv6 handling, which is used for neighbour discovery in ipv6 thus some messages such as these should not participate in connection tracking since effectively they are like ARP messages 2) fragmentation must be handled differently in ipv6, because the simplistic "defrag, connection track and NAT, refrag" (which the existing ipv4 connection tracking does) approach simply isn't feasible in ipv6 3) ipv6 extension header parsing must occur at the correct spots before and after connection tracking decisions, and there were no provisions for this in the existing connection tracking design 4) ipv6 has no need for stateful NAT The ipv4 specific conntrack layer is kept around, until all of the ipv4 specific conntrack helpers are ported over to nf_conntrack and it is feature complete. Once that occurs, the old conntrack stuff will get placed into the feature-removal-schedule and we will fully kill it off 6 months later. Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/Kconfig41
-rw-r--r--net/ipv4/netfilter/Makefile6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c2
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c12
-rw-r--r--net/ipv4/netfilter/ipt_CONNMARK.c22
-rw-r--r--net/ipv4/netfilter/ipt_NOTRACK.c4
-rw-r--r--net/ipv4/netfilter/ipt_connbytes.c39
-rw-r--r--net/ipv4/netfilter/ipt_connmark.c10
-rw-r--r--net/ipv4/netfilter/ipt_conntrack.c96
-rw-r--r--net/ipv4/netfilter/ipt_helper.c54
-rw-r--r--net/ipv4/netfilter/ipt_state.c6
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c571
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c301
13 files changed, 1106 insertions, 58 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 7d917e4ce1d9..9d3c8b5f327e 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -5,6 +5,20 @@
5menu "IP: Netfilter Configuration" 5menu "IP: Netfilter Configuration"
6 depends on INET && NETFILTER 6 depends on INET && NETFILTER
7 7
8config NF_CONNTRACK_IPV4
9 tristate "IPv4 support for new connection tracking (EXPERIMENTAL)"
10 depends on EXPERIMENTAL && NF_CONNTRACK
11 ---help---
12 Connection tracking keeps a record of what packets have passed
13 through your machine, in order to figure out how they are related
14 into connections.
15
16 This is IPv4 support on Layer 3 independent connection tracking.
17 Layer 3 independent connection tracking is experimental scheme
18 which generalize ip_conntrack to support other layer 3 protocols.
19
20 To compile it as a module, choose M here. If unsure, say N.
21
8# connection tracking, helpers and protocols 22# connection tracking, helpers and protocols
9config IP_NF_CONNTRACK 23config IP_NF_CONNTRACK
10 tristate "Connection tracking (required for masq/NAT)" 24 tristate "Connection tracking (required for masq/NAT)"
@@ -209,8 +223,8 @@ config IP_NF_MATCH_PKTTYPE
209 tristate "Packet type match support" 223 tristate "Packet type match support"
210 depends on IP_NF_IPTABLES 224 depends on IP_NF_IPTABLES
211 help 225 help
212 Packet type matching allows you to match a packet by 226 Packet type matching allows you to match a packet by
213 its "class", eg. BROADCAST, MULTICAST, ... 227 its "class", eg. BROADCAST, MULTICAST, ...
214 228
215 Typical usage: 229 Typical usage:
216 iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG 230 iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
@@ -317,7 +331,8 @@ config IP_NF_MATCH_TCPMSS
317 331
318config IP_NF_MATCH_HELPER 332config IP_NF_MATCH_HELPER
319 tristate "Helper match support" 333 tristate "Helper match support"
320 depends on IP_NF_CONNTRACK && IP_NF_IPTABLES 334 depends on IP_NF_IPTABLES
335 depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
321 help 336 help
322 Helper matching allows you to match packets in dynamic connections 337 Helper matching allows you to match packets in dynamic connections
323 tracked by a conntrack-helper, ie. ip_conntrack_ftp 338 tracked by a conntrack-helper, ie. ip_conntrack_ftp
@@ -326,7 +341,8 @@ config IP_NF_MATCH_HELPER
326 341
327config IP_NF_MATCH_STATE 342config IP_NF_MATCH_STATE
328 tristate "Connection state match support" 343 tristate "Connection state match support"
329 depends on IP_NF_CONNTRACK && IP_NF_IPTABLES 344 depends on IP_NF_IPTABLES
345 depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
330 help 346 help
331 Connection state matching allows you to match packets based on their 347 Connection state matching allows you to match packets based on their
332 relationship to a tracked connection (ie. previous packets). This 348 relationship to a tracked connection (ie. previous packets). This
@@ -336,7 +352,8 @@ config IP_NF_MATCH_STATE
336 352
337config IP_NF_MATCH_CONNTRACK 353config IP_NF_MATCH_CONNTRACK
338 tristate "Connection tracking match support" 354 tristate "Connection tracking match support"
339 depends on IP_NF_CONNTRACK && IP_NF_IPTABLES 355 depends on IP_NF_IPTABLES
356 depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
340 help 357 help
341 This is a general conntrack match module, a superset of the state match. 358 This is a general conntrack match module, a superset of the state match.
342 359
@@ -422,7 +439,8 @@ config IP_NF_MATCH_COMMENT
422 439
423config IP_NF_MATCH_CONNMARK 440config IP_NF_MATCH_CONNMARK
424 tristate 'Connection mark match support' 441 tristate 'Connection mark match support'
425 depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES 442 depends on IP_NF_IPTABLES
443 depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
426 help 444 help
427 This option adds a `connmark' match, which allows you to match the 445 This option adds a `connmark' match, which allows you to match the
428 connection mark value previously set for the session by `CONNMARK'. 446 connection mark value previously set for the session by `CONNMARK'.
@@ -433,7 +451,8 @@ config IP_NF_MATCH_CONNMARK
433 451
434config IP_NF_MATCH_CONNBYTES 452config IP_NF_MATCH_CONNBYTES
435 tristate 'Connection byte/packet counter match support' 453 tristate 'Connection byte/packet counter match support'
436 depends on IP_NF_CT_ACCT && IP_NF_IPTABLES 454 depends on IP_NF_IPTABLES
455 depends on IP_NF_CT_ACCT || (NF_CT_ACCT && NF_CONNTRACK_IPV4)
437 help 456 help
438 This option adds a `connbytes' match, which allows you to match the 457 This option adds a `connbytes' match, which allows you to match the
439 number of bytes and/or packets for each direction within a connection. 458 number of bytes and/or packets for each direction within a connection.
@@ -747,7 +766,8 @@ config IP_NF_TARGET_TTL
747 766
748config IP_NF_TARGET_CONNMARK 767config IP_NF_TARGET_CONNMARK
749 tristate 'CONNMARK target support' 768 tristate 'CONNMARK target support'
750 depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE 769 depends on IP_NF_MANGLE
770 depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
751 help 771 help
752 This option adds a `CONNMARK' target, which allows one to manipulate 772 This option adds a `CONNMARK' target, which allows one to manipulate
753 the connection mark value. Similar to the MARK target, but 773 the connection mark value. Similar to the MARK target, but
@@ -759,7 +779,8 @@ config IP_NF_TARGET_CONNMARK
759 779
760config IP_NF_TARGET_CLUSTERIP 780config IP_NF_TARGET_CLUSTERIP
761 tristate "CLUSTERIP target support (EXPERIMENTAL)" 781 tristate "CLUSTERIP target support (EXPERIMENTAL)"
762 depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES && EXPERIMENTAL 782 depends on IP_NF_IPTABLES && EXPERIMENTAL
783 depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
763 help 784 help
764 The CLUSTERIP target allows you to build load-balancing clusters of 785 The CLUSTERIP target allows you to build load-balancing clusters of
765 network servers without having a dedicated load-balancing 786 network servers without having a dedicated load-balancing
@@ -782,7 +803,7 @@ config IP_NF_RAW
782config IP_NF_TARGET_NOTRACK 803config IP_NF_TARGET_NOTRACK
783 tristate 'NOTRACK target support' 804 tristate 'NOTRACK target support'
784 depends on IP_NF_RAW 805 depends on IP_NF_RAW
785 depends on IP_NF_CONNTRACK 806 depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
786 help 807 help
787 The NOTRACK target allows a select rule to specify 808 The NOTRACK target allows a select rule to specify
788 which packets *not* to enter the conntrack/NAT 809 which packets *not* to enter the conntrack/NAT
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index dab4b58dd31e..058c48e258fc 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -103,3 +103,9 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
103obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o 103obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
104 104
105obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o 105obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
106
107# objects for l3 independent conntrack
108nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
109
110# l3 independent conntrack
111obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 5c1c0a3d1c4b..d2a4fec22862 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1376,7 +1376,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1376 ip_conntrack_expect_put(exp); 1376 ip_conntrack_expect_put(exp);
1377 } 1377 }
1378 } 1378 }
1379 write_unlock(&ip_conntrack_lock); 1379 write_unlock_bh(&ip_conntrack_lock);
1380 } else { 1380 } else {
1381 /* This basically means we have to flush everything*/ 1381 /* This basically means we have to flush everything*/
1382 write_lock_bh(&ip_conntrack_lock); 1382 write_lock_bh(&ip_conntrack_lock);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 9bcb398fbc1f..45c52d8f4d99 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -29,7 +29,7 @@
29 29
30#include <linux/netfilter_ipv4/ip_tables.h> 30#include <linux/netfilter_ipv4/ip_tables.h>
31#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> 31#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
32#include <linux/netfilter_ipv4/ip_conntrack.h> 32#include <net/netfilter/nf_conntrack_compat.h>
33 33
34#define CLUSTERIP_VERSION "0.8" 34#define CLUSTERIP_VERSION "0.8"
35 35
@@ -316,14 +316,14 @@ target(struct sk_buff **pskb,
316{ 316{
317 const struct ipt_clusterip_tgt_info *cipinfo = targinfo; 317 const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
318 enum ip_conntrack_info ctinfo; 318 enum ip_conntrack_info ctinfo;
319 struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); 319 u_int32_t *mark, hash;
320 u_int32_t hash;
321 320
322 /* don't need to clusterip_config_get() here, since refcount 321 /* don't need to clusterip_config_get() here, since refcount
323 * is only decremented by destroy() - and ip_tables guarantees 322 * is only decremented by destroy() - and ip_tables guarantees
324 * that the ->target() function isn't called after ->destroy() */ 323 * that the ->target() function isn't called after ->destroy() */
325 324
326 if (!ct) { 325 mark = nf_ct_get_mark((*pskb), &ctinfo);
326 if (mark == NULL) {
327 printk(KERN_ERR "CLUSTERIP: no conntrack!\n"); 327 printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
328 /* FIXME: need to drop invalid ones, since replies 328 /* FIXME: need to drop invalid ones, since replies
329 * to outgoing connections of other nodes will be 329 * to outgoing connections of other nodes will be
@@ -346,7 +346,7 @@ target(struct sk_buff **pskb,
346 346
347 switch (ctinfo) { 347 switch (ctinfo) {
348 case IP_CT_NEW: 348 case IP_CT_NEW:
349 ct->mark = hash; 349 *mark = hash;
350 break; 350 break;
351 case IP_CT_RELATED: 351 case IP_CT_RELATED:
352 case IP_CT_RELATED+IP_CT_IS_REPLY: 352 case IP_CT_RELATED+IP_CT_IS_REPLY:
@@ -363,7 +363,7 @@ target(struct sk_buff **pskb,
363#ifdef DEBUG_CLUSTERP 363#ifdef DEBUG_CLUSTERP
364 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 364 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
365#endif 365#endif
366 DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark); 366 DEBUGP("hash=%u ct_hash=%u ", hash, *mark);
367 if (!clusterip_responsible(cipinfo->config, hash)) { 367 if (!clusterip_responsible(cipinfo->config, hash)) {
368 DEBUGP("not responsible\n"); 368 DEBUGP("not responsible\n");
369 return NF_DROP; 369 return NF_DROP;
diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c
index 05d66ab59424..8acac5a40a92 100644
--- a/net/ipv4/netfilter/ipt_CONNMARK.c
+++ b/net/ipv4/netfilter/ipt_CONNMARK.c
@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL");
29 29
30#include <linux/netfilter_ipv4/ip_tables.h> 30#include <linux/netfilter_ipv4/ip_tables.h>
31#include <linux/netfilter_ipv4/ipt_CONNMARK.h> 31#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
32#include <linux/netfilter_ipv4/ip_conntrack.h> 32#include <net/netfilter/nf_conntrack_compat.h>
33 33
34static unsigned int 34static unsigned int
35target(struct sk_buff **pskb, 35target(struct sk_buff **pskb,
@@ -43,24 +43,24 @@ target(struct sk_buff **pskb,
43 u_int32_t diff; 43 u_int32_t diff;
44 u_int32_t nfmark; 44 u_int32_t nfmark;
45 u_int32_t newmark; 45 u_int32_t newmark;
46 u_int32_t ctinfo;
47 u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
46 48
47 enum ip_conntrack_info ctinfo; 49 if (ctmark) {
48 struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
49 if (ct) {
50 switch(markinfo->mode) { 50 switch(markinfo->mode) {
51 case IPT_CONNMARK_SET: 51 case IPT_CONNMARK_SET:
52 newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; 52 newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
53 if (newmark != ct->mark) 53 if (newmark != *ctmark)
54 ct->mark = newmark; 54 *ctmark = newmark;
55 break; 55 break;
56 case IPT_CONNMARK_SAVE: 56 case IPT_CONNMARK_SAVE:
57 newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); 57 newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
58 if (ct->mark != newmark) 58 if (*ctmark != newmark)
59 ct->mark = newmark; 59 *ctmark = newmark;
60 break; 60 break;
61 case IPT_CONNMARK_RESTORE: 61 case IPT_CONNMARK_RESTORE:
62 nfmark = (*pskb)->nfmark; 62 nfmark = (*pskb)->nfmark;
63 diff = (ct->mark ^ nfmark) & markinfo->mask; 63 diff = (*ctmark ^ nfmark) & markinfo->mask;
64 if (diff != 0) 64 if (diff != 0)
65 (*pskb)->nfmark = nfmark ^ diff; 65 (*pskb)->nfmark = nfmark ^ diff;
66 break; 66 break;
diff --git a/net/ipv4/netfilter/ipt_NOTRACK.c b/net/ipv4/netfilter/ipt_NOTRACK.c
index a4bb9b3bc292..e3c69d072c6e 100644
--- a/net/ipv4/netfilter/ipt_NOTRACK.c
+++ b/net/ipv4/netfilter/ipt_NOTRACK.c
@@ -5,7 +5,7 @@
5#include <linux/skbuff.h> 5#include <linux/skbuff.h>
6 6
7#include <linux/netfilter_ipv4/ip_tables.h> 7#include <linux/netfilter_ipv4/ip_tables.h>
8#include <linux/netfilter_ipv4/ip_conntrack.h> 8#include <net/netfilter/nf_conntrack_compat.h>
9 9
10static unsigned int 10static unsigned int
11target(struct sk_buff **pskb, 11target(struct sk_buff **pskb,
@@ -23,7 +23,7 @@ target(struct sk_buff **pskb,
23 If there is a real ct entry correspondig to this packet, 23 If there is a real ct entry correspondig to this packet,
24 it'll hang aroun till timing out. We don't deal with it 24 it'll hang aroun till timing out. We don't deal with it
25 for performance reasons. JK */ 25 for performance reasons. JK */
26 (*pskb)->nfct = &ip_conntrack_untracked.ct_general; 26 nf_ct_untrack(*pskb);
27 (*pskb)->nfctinfo = IP_CT_NEW; 27 (*pskb)->nfctinfo = IP_CT_NEW;
28 nf_conntrack_get((*pskb)->nfct); 28 nf_conntrack_get((*pskb)->nfct);
29 29
diff --git a/net/ipv4/netfilter/ipt_connbytes.c b/net/ipv4/netfilter/ipt_connbytes.c
index df4a42c6da22..d68a048b7176 100644
--- a/net/ipv4/netfilter/ipt_connbytes.c
+++ b/net/ipv4/netfilter/ipt_connbytes.c
@@ -10,7 +10,7 @@
10 */ 10 */
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/skbuff.h> 12#include <linux/skbuff.h>
13#include <linux/netfilter_ipv4/ip_conntrack.h> 13#include <net/netfilter/nf_conntrack_compat.h>
14#include <linux/netfilter_ipv4/ip_tables.h> 14#include <linux/netfilter_ipv4/ip_tables.h>
15#include <linux/netfilter_ipv4/ipt_connbytes.h> 15#include <linux/netfilter_ipv4/ipt_connbytes.h>
16 16
@@ -46,60 +46,59 @@ match(const struct sk_buff *skb,
46 int *hotdrop) 46 int *hotdrop)
47{ 47{
48 const struct ipt_connbytes_info *sinfo = matchinfo; 48 const struct ipt_connbytes_info *sinfo = matchinfo;
49 enum ip_conntrack_info ctinfo;
50 struct ip_conntrack *ct;
51 u_int64_t what = 0; /* initialize to make gcc happy */ 49 u_int64_t what = 0; /* initialize to make gcc happy */
50 const struct ip_conntrack_counter *counters;
52 51
53 if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo))) 52 if (!(counters = nf_ct_get_counters(skb)))
54 return 0; /* no match */ 53 return 0; /* no match */
55 54
56 switch (sinfo->what) { 55 switch (sinfo->what) {
57 case IPT_CONNBYTES_PKTS: 56 case IPT_CONNBYTES_PKTS:
58 switch (sinfo->direction) { 57 switch (sinfo->direction) {
59 case IPT_CONNBYTES_DIR_ORIGINAL: 58 case IPT_CONNBYTES_DIR_ORIGINAL:
60 what = ct->counters[IP_CT_DIR_ORIGINAL].packets; 59 what = counters[IP_CT_DIR_ORIGINAL].packets;
61 break; 60 break;
62 case IPT_CONNBYTES_DIR_REPLY: 61 case IPT_CONNBYTES_DIR_REPLY:
63 what = ct->counters[IP_CT_DIR_REPLY].packets; 62 what = counters[IP_CT_DIR_REPLY].packets;
64 break; 63 break;
65 case IPT_CONNBYTES_DIR_BOTH: 64 case IPT_CONNBYTES_DIR_BOTH:
66 what = ct->counters[IP_CT_DIR_ORIGINAL].packets; 65 what = counters[IP_CT_DIR_ORIGINAL].packets;
67 what += ct->counters[IP_CT_DIR_REPLY].packets; 66 what += counters[IP_CT_DIR_REPLY].packets;
68 break; 67 break;
69 } 68 }
70 break; 69 break;
71 case IPT_CONNBYTES_BYTES: 70 case IPT_CONNBYTES_BYTES:
72 switch (sinfo->direction) { 71 switch (sinfo->direction) {
73 case IPT_CONNBYTES_DIR_ORIGINAL: 72 case IPT_CONNBYTES_DIR_ORIGINAL:
74 what = ct->counters[IP_CT_DIR_ORIGINAL].bytes; 73 what = counters[IP_CT_DIR_ORIGINAL].bytes;
75 break; 74 break;
76 case IPT_CONNBYTES_DIR_REPLY: 75 case IPT_CONNBYTES_DIR_REPLY:
77 what = ct->counters[IP_CT_DIR_REPLY].bytes; 76 what = counters[IP_CT_DIR_REPLY].bytes;
78 break; 77 break;
79 case IPT_CONNBYTES_DIR_BOTH: 78 case IPT_CONNBYTES_DIR_BOTH:
80 what = ct->counters[IP_CT_DIR_ORIGINAL].bytes; 79 what = counters[IP_CT_DIR_ORIGINAL].bytes;
81 what += ct->counters[IP_CT_DIR_REPLY].bytes; 80 what += counters[IP_CT_DIR_REPLY].bytes;
82 break; 81 break;
83 } 82 }
84 break; 83 break;
85 case IPT_CONNBYTES_AVGPKT: 84 case IPT_CONNBYTES_AVGPKT:
86 switch (sinfo->direction) { 85 switch (sinfo->direction) {
87 case IPT_CONNBYTES_DIR_ORIGINAL: 86 case IPT_CONNBYTES_DIR_ORIGINAL:
88 what = div64_64(ct->counters[IP_CT_DIR_ORIGINAL].bytes, 87 what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
89 ct->counters[IP_CT_DIR_ORIGINAL].packets); 88 counters[IP_CT_DIR_ORIGINAL].packets);
90 break; 89 break;
91 case IPT_CONNBYTES_DIR_REPLY: 90 case IPT_CONNBYTES_DIR_REPLY:
92 what = div64_64(ct->counters[IP_CT_DIR_REPLY].bytes, 91 what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
93 ct->counters[IP_CT_DIR_REPLY].packets); 92 counters[IP_CT_DIR_REPLY].packets);
94 break; 93 break;
95 case IPT_CONNBYTES_DIR_BOTH: 94 case IPT_CONNBYTES_DIR_BOTH:
96 { 95 {
97 u_int64_t bytes; 96 u_int64_t bytes;
98 u_int64_t pkts; 97 u_int64_t pkts;
99 bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes + 98 bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
100 ct->counters[IP_CT_DIR_REPLY].bytes; 99 counters[IP_CT_DIR_REPLY].bytes;
101 pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets+ 100 pkts = counters[IP_CT_DIR_ORIGINAL].packets+
102 ct->counters[IP_CT_DIR_REPLY].packets; 101 counters[IP_CT_DIR_REPLY].packets;
103 102
104 /* FIXME_THEORETICAL: what to do if sum 103 /* FIXME_THEORETICAL: what to do if sum
105 * overflows ? */ 104 * overflows ? */
diff --git a/net/ipv4/netfilter/ipt_connmark.c b/net/ipv4/netfilter/ipt_connmark.c
index bf8de47ce004..5306ef293b92 100644
--- a/net/ipv4/netfilter/ipt_connmark.c
+++ b/net/ipv4/netfilter/ipt_connmark.c
@@ -28,7 +28,7 @@ MODULE_LICENSE("GPL");
28 28
29#include <linux/netfilter_ipv4/ip_tables.h> 29#include <linux/netfilter_ipv4/ip_tables.h>
30#include <linux/netfilter_ipv4/ipt_connmark.h> 30#include <linux/netfilter_ipv4/ipt_connmark.h>
31#include <linux/netfilter_ipv4/ip_conntrack.h> 31#include <net/netfilter/nf_conntrack_compat.h>
32 32
33static int 33static int
34match(const struct sk_buff *skb, 34match(const struct sk_buff *skb,
@@ -39,12 +39,12 @@ match(const struct sk_buff *skb,
39 int *hotdrop) 39 int *hotdrop)
40{ 40{
41 const struct ipt_connmark_info *info = matchinfo; 41 const struct ipt_connmark_info *info = matchinfo;
42 enum ip_conntrack_info ctinfo; 42 u_int32_t ctinfo;
43 struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); 43 const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
44 if (!ct) 44 if (!ctmark)
45 return 0; 45 return 0;
46 46
47 return ((ct->mark & info->mask) == info->mark) ^ info->invert; 47 return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
48} 48}
49 49
50static int 50static int
diff --git a/net/ipv4/netfilter/ipt_conntrack.c b/net/ipv4/netfilter/ipt_conntrack.c
index c1d22801b7cf..c8d18705469b 100644
--- a/net/ipv4/netfilter/ipt_conntrack.c
+++ b/net/ipv4/netfilter/ipt_conntrack.c
@@ -10,7 +10,14 @@
10 10
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/skbuff.h> 12#include <linux/skbuff.h>
13
14#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
13#include <linux/netfilter_ipv4/ip_conntrack.h> 15#include <linux/netfilter_ipv4/ip_conntrack.h>
16#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
17#else
18#include <net/netfilter/nf_conntrack.h>
19#endif
20
14#include <linux/netfilter_ipv4/ip_tables.h> 21#include <linux/netfilter_ipv4/ip_tables.h>
15#include <linux/netfilter_ipv4/ipt_conntrack.h> 22#include <linux/netfilter_ipv4/ipt_conntrack.h>
16 23
@@ -18,6 +25,8 @@ MODULE_LICENSE("GPL");
18MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); 25MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
19MODULE_DESCRIPTION("iptables connection tracking match module"); 26MODULE_DESCRIPTION("iptables connection tracking match module");
20 27
28#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
29
21static int 30static int
22match(const struct sk_buff *skb, 31match(const struct sk_buff *skb,
23 const struct net_device *in, 32 const struct net_device *in,
@@ -102,6 +111,93 @@ match(const struct sk_buff *skb,
102 return 1; 111 return 1;
103} 112}
104 113
114#else /* CONFIG_IP_NF_CONNTRACK */
115static int
116match(const struct sk_buff *skb,
117 const struct net_device *in,
118 const struct net_device *out,
119 const void *matchinfo,
120 int offset,
121 int *hotdrop)
122{
123 const struct ipt_conntrack_info *sinfo = matchinfo;
124 struct nf_conn *ct;
125 enum ip_conntrack_info ctinfo;
126 unsigned int statebit;
127
128 ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
129
130#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
131
132 if (ct == &nf_conntrack_untracked)
133 statebit = IPT_CONNTRACK_STATE_UNTRACKED;
134 else if (ct)
135 statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
136 else
137 statebit = IPT_CONNTRACK_STATE_INVALID;
138
139 if(sinfo->flags & IPT_CONNTRACK_STATE) {
140 if (ct) {
141 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
142 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
143 statebit |= IPT_CONNTRACK_STATE_SNAT;
144
145 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
146 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
147 statebit |= IPT_CONNTRACK_STATE_DNAT;
148 }
149
150 if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
151 return 0;
152 }
153
154 if(sinfo->flags & IPT_CONNTRACK_PROTO) {
155 if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
156 return 0;
157 }
158
159 if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
160 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
161 return 0;
162 }
163
164 if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
165 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
166 return 0;
167 }
168
169 if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
170 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
171 return 0;
172 }
173
174 if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
175 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
176 return 0;
177 }
178
179 if(sinfo->flags & IPT_CONNTRACK_STATUS) {
180 if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
181 return 0;
182 }
183
184 if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
185 unsigned long expires;
186
187 if(!ct)
188 return 0;
189
190 expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
191
192 if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
193 return 0;
194 }
195
196 return 1;
197}
198
199#endif /* CONFIG_NF_IP_CONNTRACK */
200
105static int check(const char *tablename, 201static int check(const char *tablename,
106 const struct ipt_ip *ip, 202 const struct ipt_ip *ip,
107 void *matchinfo, 203 void *matchinfo,
diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c
index 3e7dd014de43..bf14e1c7798a 100644
--- a/net/ipv4/netfilter/ipt_helper.c
+++ b/net/ipv4/netfilter/ipt_helper.c
@@ -13,9 +13,15 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/skbuff.h> 14#include <linux/skbuff.h>
15#include <linux/netfilter.h> 15#include <linux/netfilter.h>
16#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
16#include <linux/netfilter_ipv4/ip_conntrack.h> 17#include <linux/netfilter_ipv4/ip_conntrack.h>
17#include <linux/netfilter_ipv4/ip_conntrack_core.h> 18#include <linux/netfilter_ipv4/ip_conntrack_core.h>
18#include <linux/netfilter_ipv4/ip_conntrack_helper.h> 19#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
20#else
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_conntrack_core.h>
23#include <net/netfilter/nf_conntrack_helper.h>
24#endif
19#include <linux/netfilter_ipv4/ip_tables.h> 25#include <linux/netfilter_ipv4/ip_tables.h>
20#include <linux/netfilter_ipv4/ipt_helper.h> 26#include <linux/netfilter_ipv4/ipt_helper.h>
21 27
@@ -29,6 +35,7 @@ MODULE_DESCRIPTION("iptables helper match module");
29#define DEBUGP(format, args...) 35#define DEBUGP(format, args...)
30#endif 36#endif
31 37
38#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
32static int 39static int
33match(const struct sk_buff *skb, 40match(const struct sk_buff *skb,
34 const struct net_device *in, 41 const struct net_device *in,
@@ -73,6 +80,53 @@ out_unlock:
73 return ret; 80 return ret;
74} 81}
75 82
83#else /* CONFIG_IP_NF_CONNTRACK */
84
85static int
86match(const struct sk_buff *skb,
87 const struct net_device *in,
88 const struct net_device *out,
89 const void *matchinfo,
90 int offset,
91 int *hotdrop)
92{
93 const struct ipt_helper_info *info = matchinfo;
94 struct nf_conn *ct;
95 enum ip_conntrack_info ctinfo;
96 int ret = info->invert;
97
98 ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
99 if (!ct) {
100 DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
101 return ret;
102 }
103
104 if (!ct->master) {
105 DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
106 return ret;
107 }
108
109 read_lock_bh(&nf_conntrack_lock);
110 if (!ct->master->helper) {
111 DEBUGP("ipt_helper: master ct %p has no helper\n",
112 exp->expectant);
113 goto out_unlock;
114 }
115
116 DEBUGP("master's name = %s , info->name = %s\n",
117 ct->master->helper->name, info->name);
118
119 if (info->name[0] == '\0')
120 ret ^= 1;
121 else
122 ret ^= !strncmp(ct->master->helper->name, info->name,
123 strlen(ct->master->helper->name));
124out_unlock:
125 read_unlock_bh(&nf_conntrack_lock);
126 return ret;
127}
128#endif
129
76static int check(const char *tablename, 130static int check(const char *tablename,
77 const struct ipt_ip *ip, 131 const struct ipt_ip *ip,
78 void *matchinfo, 132 void *matchinfo,
diff --git a/net/ipv4/netfilter/ipt_state.c b/net/ipv4/netfilter/ipt_state.c
index b1511b97ea5f..4d7f16b70cec 100644
--- a/net/ipv4/netfilter/ipt_state.c
+++ b/net/ipv4/netfilter/ipt_state.c
@@ -10,7 +10,7 @@
10 10
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/skbuff.h> 12#include <linux/skbuff.h>
13#include <linux/netfilter_ipv4/ip_conntrack.h> 13#include <net/netfilter/nf_conntrack_compat.h>
14#include <linux/netfilter_ipv4/ip_tables.h> 14#include <linux/netfilter_ipv4/ip_tables.h>
15#include <linux/netfilter_ipv4/ipt_state.h> 15#include <linux/netfilter_ipv4/ipt_state.h>
16 16
@@ -30,9 +30,9 @@ match(const struct sk_buff *skb,
30 enum ip_conntrack_info ctinfo; 30 enum ip_conntrack_info ctinfo;
31 unsigned int statebit; 31 unsigned int statebit;
32 32
33 if (skb->nfct == &ip_conntrack_untracked.ct_general) 33 if (nf_ct_is_untracked(skb))
34 statebit = IPT_STATE_UNTRACKED; 34 statebit = IPT_STATE_UNTRACKED;
35 else if (!ip_conntrack_get(skb, &ctinfo)) 35 else if (!nf_ct_get_ctinfo(skb, &ctinfo))
36 statebit = IPT_STATE_INVALID; 36 statebit = IPT_STATE_INVALID;
37 else 37 else
38 statebit = IPT_STATE_BIT(ctinfo); 38 statebit = IPT_STATE_BIT(ctinfo);
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
new file mode 100644
index 000000000000..8202c1c0afad
--- /dev/null
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -0,0 +1,571 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
9 * - move L3 protocol dependent part to this file.
10 * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
11 * - add get_features() to support various size of conntrack
12 * structures.
13 *
14 * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c
15 */
16
17#include <linux/config.h>
18#include <linux/types.h>
19#include <linux/ip.h>
20#include <linux/netfilter.h>
21#include <linux/module.h>
22#include <linux/skbuff.h>
23#include <linux/icmp.h>
24#include <linux/sysctl.h>
25#include <net/ip.h>
26
27#include <linux/netfilter_ipv4.h>
28#include <net/netfilter/nf_conntrack.h>
29#include <net/netfilter/nf_conntrack_helper.h>
30#include <net/netfilter/nf_conntrack_protocol.h>
31#include <net/netfilter/nf_conntrack_l3proto.h>
32#include <net/netfilter/nf_conntrack_core.h>
33#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
34
35#if 0
36#define DEBUGP printk
37#else
38#define DEBUGP(format, args...)
39#endif
40
41DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
42
43static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
44 struct nf_conntrack_tuple *tuple)
45{
46 u_int32_t _addrs[2], *ap;
47 ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
48 sizeof(u_int32_t) * 2, _addrs);
49 if (ap == NULL)
50 return 0;
51
52 tuple->src.u3.ip = ap[0];
53 tuple->dst.u3.ip = ap[1];
54
55 return 1;
56}
57
58static int ipv4_invert_tuple(struct nf_conntrack_tuple *tuple,
59 const struct nf_conntrack_tuple *orig)
60{
61 tuple->src.u3.ip = orig->dst.u3.ip;
62 tuple->dst.u3.ip = orig->src.u3.ip;
63
64 return 1;
65}
66
67static int ipv4_print_tuple(struct seq_file *s,
68 const struct nf_conntrack_tuple *tuple)
69{
70 return seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
71 NIPQUAD(tuple->src.u3.ip),
72 NIPQUAD(tuple->dst.u3.ip));
73}
74
75static int ipv4_print_conntrack(struct seq_file *s,
76 const struct nf_conn *conntrack)
77{
78 return 0;
79}
80
81/* Returns new sk_buff, or NULL */
82static struct sk_buff *
83nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
84{
85 skb_orphan(skb);
86
87 local_bh_disable();
88 skb = ip_defrag(skb, user);
89 local_bh_enable();
90
91 if (skb)
92 ip_send_check(skb->nh.iph);
93
94 return skb;
95}
96
97static int
98ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
99 u_int8_t *protonum)
100{
101 /* Never happen */
102 if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
103 if (net_ratelimit()) {
104 printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n",
105 (*pskb)->nh.iph->protocol, hooknum);
106 }
107 return -NF_DROP;
108 }
109
110 *dataoff = (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4;
111 *protonum = (*pskb)->nh.iph->protocol;
112
113 return NF_ACCEPT;
114}
115
116int nat_module_is_loaded = 0;
117static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple)
118{
119 if (nat_module_is_loaded)
120 return NF_CT_F_NAT;
121
122 return NF_CT_F_BASIC;
123}
124
125static unsigned int ipv4_confirm(unsigned int hooknum,
126 struct sk_buff **pskb,
127 const struct net_device *in,
128 const struct net_device *out,
129 int (*okfn)(struct sk_buff *))
130{
131 /* We've seen it coming out the other side: confirm it */
132 return nf_conntrack_confirm(pskb);
133}
134
135static unsigned int ipv4_conntrack_help(unsigned int hooknum,
136 struct sk_buff **pskb,
137 const struct net_device *in,
138 const struct net_device *out,
139 int (*okfn)(struct sk_buff *))
140{
141 struct nf_conn *ct;
142 enum ip_conntrack_info ctinfo;
143
144 /* This is where we call the helper: as the packet goes out. */
145 ct = nf_ct_get(*pskb, &ctinfo);
146 if (ct && ct->helper) {
147 unsigned int ret;
148 ret = ct->helper->help(pskb,
149 (*pskb)->nh.raw - (*pskb)->data
150 + (*pskb)->nh.iph->ihl*4,
151 ct, ctinfo);
152 if (ret != NF_ACCEPT)
153 return ret;
154 }
155 return NF_ACCEPT;
156}
157
158static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
159 struct sk_buff **pskb,
160 const struct net_device *in,
161 const struct net_device *out,
162 int (*okfn)(struct sk_buff *))
163{
164#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
165 /* Previously seen (loopback)? Ignore. Do this before
166 fragment check. */
167 if ((*pskb)->nfct)
168 return NF_ACCEPT;
169#endif
170
171 /* Gather fragments. */
172 if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
173 *pskb = nf_ct_ipv4_gather_frags(*pskb,
174 hooknum == NF_IP_PRE_ROUTING ?
175 IP_DEFRAG_CONNTRACK_IN :
176 IP_DEFRAG_CONNTRACK_OUT);
177 if (!*pskb)
178 return NF_STOLEN;
179 }
180 return NF_ACCEPT;
181}
182
183static unsigned int ipv4_refrag(unsigned int hooknum,
184 struct sk_buff **pskb,
185 const struct net_device *in,
186 const struct net_device *out,
187 int (*okfn)(struct sk_buff *))
188{
189 struct rtable *rt = (struct rtable *)(*pskb)->dst;
190
191 /* We've seen it coming out the other side: confirm */
192 if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
193 return NF_DROP;
194
195 /* Local packets are never produced too large for their
196 interface. We degfragment them at LOCAL_OUT, however,
197 so we have to refragment them here. */
198 if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
199 !skb_shinfo(*pskb)->tso_size) {
200 /* No hook can be after us, so this should be OK. */
201 ip_fragment(*pskb, okfn);
202 return NF_STOLEN;
203 }
204 return NF_ACCEPT;
205}
206
207static unsigned int ipv4_conntrack_in(unsigned int hooknum,
208 struct sk_buff **pskb,
209 const struct net_device *in,
210 const struct net_device *out,
211 int (*okfn)(struct sk_buff *))
212{
213 return nf_conntrack_in(PF_INET, hooknum, pskb);
214}
215
216static unsigned int ipv4_conntrack_local(unsigned int hooknum,
217 struct sk_buff **pskb,
218 const struct net_device *in,
219 const struct net_device *out,
220 int (*okfn)(struct sk_buff *))
221{
222 /* root is playing with raw sockets. */
223 if ((*pskb)->len < sizeof(struct iphdr)
224 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
225 if (net_ratelimit())
226 printk("ipt_hook: happy cracking.\n");
227 return NF_ACCEPT;
228 }
229 return nf_conntrack_in(PF_INET, hooknum, pskb);
230}
231
232/* Connection tracking may drop packets, but never alters them, so
233 make it the first hook. */
234static struct nf_hook_ops ipv4_conntrack_defrag_ops = {
235 .hook = ipv4_conntrack_defrag,
236 .owner = THIS_MODULE,
237 .pf = PF_INET,
238 .hooknum = NF_IP_PRE_ROUTING,
239 .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
240};
241
242static struct nf_hook_ops ipv4_conntrack_in_ops = {
243 .hook = ipv4_conntrack_in,
244 .owner = THIS_MODULE,
245 .pf = PF_INET,
246 .hooknum = NF_IP_PRE_ROUTING,
247 .priority = NF_IP_PRI_CONNTRACK,
248};
249
250static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = {
251 .hook = ipv4_conntrack_defrag,
252 .owner = THIS_MODULE,
253 .pf = PF_INET,
254 .hooknum = NF_IP_LOCAL_OUT,
255 .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
256};
257
258static struct nf_hook_ops ipv4_conntrack_local_out_ops = {
259 .hook = ipv4_conntrack_local,
260 .owner = THIS_MODULE,
261 .pf = PF_INET,
262 .hooknum = NF_IP_LOCAL_OUT,
263 .priority = NF_IP_PRI_CONNTRACK,
264};
265
266/* helpers */
267static struct nf_hook_ops ipv4_conntrack_helper_out_ops = {
268 .hook = ipv4_conntrack_help,
269 .owner = THIS_MODULE,
270 .pf = PF_INET,
271 .hooknum = NF_IP_POST_ROUTING,
272 .priority = NF_IP_PRI_CONNTRACK_HELPER,
273};
274
275static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
276 .hook = ipv4_conntrack_help,
277 .owner = THIS_MODULE,
278 .pf = PF_INET,
279 .hooknum = NF_IP_LOCAL_IN,
280 .priority = NF_IP_PRI_CONNTRACK_HELPER,
281};
282
283
284/* Refragmenter; last chance. */
285static struct nf_hook_ops ipv4_conntrack_out_ops = {
286 .hook = ipv4_refrag,
287 .owner = THIS_MODULE,
288 .pf = PF_INET,
289 .hooknum = NF_IP_POST_ROUTING,
290 .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
291};
292
293static struct nf_hook_ops ipv4_conntrack_local_in_ops = {
294 .hook = ipv4_confirm,
295 .owner = THIS_MODULE,
296 .pf = PF_INET,
297 .hooknum = NF_IP_LOCAL_IN,
298 .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
299};
300
301#ifdef CONFIG_SYSCTL
302/* From nf_conntrack_proto_icmp.c */
303extern unsigned long nf_ct_icmp_timeout;
304static struct ctl_table_header *nf_ct_ipv4_sysctl_header;
305
306static ctl_table nf_ct_sysctl_table[] = {
307 {
308 .ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT,
309 .procname = "nf_conntrack_icmp_timeout",
310 .data = &nf_ct_icmp_timeout,
311 .maxlen = sizeof(unsigned int),
312 .mode = 0644,
313 .proc_handler = &proc_dointvec_jiffies,
314 },
315 { .ctl_name = 0 }
316};
317
318static ctl_table nf_ct_netfilter_table[] = {
319 {
320 .ctl_name = NET_NETFILTER,
321 .procname = "netfilter",
322 .mode = 0555,
323 .child = nf_ct_sysctl_table,
324 },
325 { .ctl_name = 0 }
326};
327
328static ctl_table nf_ct_net_table[] = {
329 {
330 .ctl_name = CTL_NET,
331 .procname = "net",
332 .mode = 0555,
333 .child = nf_ct_netfilter_table,
334 },
335 { .ctl_name = 0 }
336};
337#endif
338
339/* Fast function for those who don't want to parse /proc (and I don't
340 blame them). */
341/* Reversing the socket's dst/src point of view gives us the reply
342 mapping. */
343static int
344getorigdst(struct sock *sk, int optval, void __user *user, int *len)
345{
346 struct inet_sock *inet = inet_sk(sk);
347 struct nf_conntrack_tuple_hash *h;
348 struct nf_conntrack_tuple tuple;
349
350 NF_CT_TUPLE_U_BLANK(&tuple);
351 tuple.src.u3.ip = inet->rcv_saddr;
352 tuple.src.u.tcp.port = inet->sport;
353 tuple.dst.u3.ip = inet->daddr;
354 tuple.dst.u.tcp.port = inet->dport;
355 tuple.src.l3num = PF_INET;
356 tuple.dst.protonum = IPPROTO_TCP;
357
358 /* We only do TCP at the moment: is there a better way? */
359 if (strcmp(sk->sk_prot->name, "TCP")) {
360 DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
361 return -ENOPROTOOPT;
362 }
363
364 if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
365 DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
366 *len, sizeof(struct sockaddr_in));
367 return -EINVAL;
368 }
369
370 h = nf_conntrack_find_get(&tuple, NULL);
371 if (h) {
372 struct sockaddr_in sin;
373 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
374
375 sin.sin_family = AF_INET;
376 sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
377 .tuple.dst.u.tcp.port;
378 sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
379 .tuple.dst.u3.ip;
380
381 DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
382 NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
383 nf_ct_put(ct);
384 if (copy_to_user(user, &sin, sizeof(sin)) != 0)
385 return -EFAULT;
386 else
387 return 0;
388 }
389 DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
390 NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port),
391 NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port));
392 return -ENOENT;
393}
394
395static struct nf_sockopt_ops so_getorigdst = {
396 .pf = PF_INET,
397 .get_optmin = SO_ORIGINAL_DST,
398 .get_optmax = SO_ORIGINAL_DST+1,
399 .get = &getorigdst,
400};
401
402struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
403 .l3proto = PF_INET,
404 .name = "ipv4",
405 .pkt_to_tuple = ipv4_pkt_to_tuple,
406 .invert_tuple = ipv4_invert_tuple,
407 .print_tuple = ipv4_print_tuple,
408 .print_conntrack = ipv4_print_conntrack,
409 .prepare = ipv4_prepare,
410 .get_features = ipv4_get_features,
411 .me = THIS_MODULE,
412};
413
414extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4;
415extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
416extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp;
417static int init_or_cleanup(int init)
418{
419 int ret = 0;
420
421 if (!init) goto cleanup;
422
423 ret = nf_register_sockopt(&so_getorigdst);
424 if (ret < 0) {
425 printk(KERN_ERR "Unable to register netfilter socket option\n");
426 goto cleanup_nothing;
427 }
428
429 ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4);
430 if (ret < 0) {
431 printk("nf_conntrack_ipv4: can't register tcp.\n");
432 goto cleanup_sockopt;
433 }
434
435 ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4);
436 if (ret < 0) {
437 printk("nf_conntrack_ipv4: can't register udp.\n");
438 goto cleanup_tcp;
439 }
440
441 ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp);
442 if (ret < 0) {
443 printk("nf_conntrack_ipv4: can't register icmp.\n");
444 goto cleanup_udp;
445 }
446
447 ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
448 if (ret < 0) {
449 printk("nf_conntrack_ipv4: can't register ipv4\n");
450 goto cleanup_icmp;
451 }
452
453 ret = nf_register_hook(&ipv4_conntrack_defrag_ops);
454 if (ret < 0) {
455 printk("nf_conntrack_ipv4: can't register pre-routing defrag hook.\n");
456 goto cleanup_ipv4;
457 }
458 ret = nf_register_hook(&ipv4_conntrack_defrag_local_out_ops);
459 if (ret < 0) {
460 printk("nf_conntrack_ipv4: can't register local_out defrag hook.\n");
461 goto cleanup_defragops;
462 }
463
464 ret = nf_register_hook(&ipv4_conntrack_in_ops);
465 if (ret < 0) {
466 printk("nf_conntrack_ipv4: can't register pre-routing hook.\n");
467 goto cleanup_defraglocalops;
468 }
469
470 ret = nf_register_hook(&ipv4_conntrack_local_out_ops);
471 if (ret < 0) {
472 printk("nf_conntrack_ipv4: can't register local out hook.\n");
473 goto cleanup_inops;
474 }
475
476 ret = nf_register_hook(&ipv4_conntrack_helper_in_ops);
477 if (ret < 0) {
478 printk("nf_conntrack_ipv4: can't register local helper hook.\n");
479 goto cleanup_inandlocalops;
480 }
481
482 ret = nf_register_hook(&ipv4_conntrack_helper_out_ops);
483 if (ret < 0) {
484 printk("nf_conntrack_ipv4: can't register postrouting helper hook.\n");
485 goto cleanup_helperinops;
486 }
487
488 ret = nf_register_hook(&ipv4_conntrack_out_ops);
489 if (ret < 0) {
490 printk("nf_conntrack_ipv4: can't register post-routing hook.\n");
491 goto cleanup_helperoutops;
492 }
493
494 ret = nf_register_hook(&ipv4_conntrack_local_in_ops);
495 if (ret < 0) {
496 printk("nf_conntrack_ipv4: can't register local in hook.\n");
497 goto cleanup_inoutandlocalops;
498 }
499
500#ifdef CONFIG_SYSCTL
501 nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
502 if (nf_ct_ipv4_sysctl_header == NULL) {
503 printk("nf_conntrack: can't register to sysctl.\n");
504 ret = -ENOMEM;
505 goto cleanup_localinops;
506 }
507#endif
508
509 /* For use by REJECT target */
510 ip_ct_attach = __nf_conntrack_attach;
511
512 return ret;
513
514 cleanup:
515 synchronize_net();
516 ip_ct_attach = NULL;
517#ifdef CONFIG_SYSCTL
518 unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
519 cleanup_localinops:
520#endif
521 nf_unregister_hook(&ipv4_conntrack_local_in_ops);
522 cleanup_inoutandlocalops:
523 nf_unregister_hook(&ipv4_conntrack_out_ops);
524 cleanup_helperoutops:
525 nf_unregister_hook(&ipv4_conntrack_helper_out_ops);
526 cleanup_helperinops:
527 nf_unregister_hook(&ipv4_conntrack_helper_in_ops);
528 cleanup_inandlocalops:
529 nf_unregister_hook(&ipv4_conntrack_local_out_ops);
530 cleanup_inops:
531 nf_unregister_hook(&ipv4_conntrack_in_ops);
532 cleanup_defraglocalops:
533 nf_unregister_hook(&ipv4_conntrack_defrag_local_out_ops);
534 cleanup_defragops:
535 nf_unregister_hook(&ipv4_conntrack_defrag_ops);
536 cleanup_ipv4:
537 nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
538 cleanup_icmp:
539 nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp);
540 cleanup_udp:
541 nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4);
542 cleanup_tcp:
543 nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
544 cleanup_sockopt:
545 nf_unregister_sockopt(&so_getorigdst);
546 cleanup_nothing:
547 return ret;
548}
549
550MODULE_LICENSE("GPL");
551
552static int __init init(void)
553{
554 need_nf_conntrack();
555 return init_or_cleanup(1);
556}
557
558static void __exit fini(void)
559{
560 init_or_cleanup(0);
561}
562
563module_init(init);
564module_exit(fini);
565
566void need_ip_conntrack(void)
567{
568}
569
570EXPORT_SYMBOL(need_ip_conntrack);
571EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
new file mode 100644
index 000000000000..7ddb5c08f7b8
--- /dev/null
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -0,0 +1,301 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
9 * - enable working with Layer 3 protocol independent connection tracking.
10 *
11 * Derived from net/ipv4/netfilter/ip_conntrack_proto_icmp.c
12 */
13
14#include <linux/types.h>
15#include <linux/sched.h>
16#include <linux/timer.h>
17#include <linux/netfilter.h>
18#include <linux/in.h>
19#include <linux/icmp.h>
20#include <linux/seq_file.h>
21#include <net/ip.h>
22#include <net/checksum.h>
23#include <linux/netfilter_ipv4.h>
24#include <net/netfilter/nf_conntrack_tuple.h>
25#include <net/netfilter/nf_conntrack_protocol.h>
26#include <net/netfilter/nf_conntrack_core.h>
27
28unsigned long nf_ct_icmp_timeout = 30*HZ;
29
30#if 0
31#define DEBUGP printk
32#else
33#define DEBUGP(format, args...)
34#endif
35
36static int icmp_pkt_to_tuple(const struct sk_buff *skb,
37 unsigned int dataoff,
38 struct nf_conntrack_tuple *tuple)
39{
40 struct icmphdr _hdr, *hp;
41
42 hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
43 if (hp == NULL)
44 return 0;
45
46 tuple->dst.u.icmp.type = hp->type;
47 tuple->src.u.icmp.id = hp->un.echo.id;
48 tuple->dst.u.icmp.code = hp->code;
49
50 return 1;
51}
52
53static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
54 const struct nf_conntrack_tuple *orig)
55{
56 /* Add 1; spaces filled with 0. */
57 static u_int8_t invmap[]
58 = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
59 [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
60 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
61 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
62 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
63 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
64 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
65 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
66
67 if (orig->dst.u.icmp.type >= sizeof(invmap)
68 || !invmap[orig->dst.u.icmp.type])
69 return 0;
70
71 tuple->src.u.icmp.id = orig->src.u.icmp.id;
72 tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
73 tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
74 return 1;
75}
76
77/* Print out the per-protocol part of the tuple. */
78static int icmp_print_tuple(struct seq_file *s,
79 const struct nf_conntrack_tuple *tuple)
80{
81 return seq_printf(s, "type=%u code=%u id=%u ",
82 tuple->dst.u.icmp.type,
83 tuple->dst.u.icmp.code,
84 ntohs(tuple->src.u.icmp.id));
85}
86
87/* Print out the private part of the conntrack. */
88static int icmp_print_conntrack(struct seq_file *s,
89 const struct nf_conn *conntrack)
90{
91 return 0;
92}
93
94/* Returns verdict for packet, or -1 for invalid. */
95static int icmp_packet(struct nf_conn *ct,
96 const struct sk_buff *skb,
97 unsigned int dataoff,
98 enum ip_conntrack_info ctinfo,
99 int pf,
100 unsigned int hooknum)
101{
102 /* Try to delete connection immediately after all replies:
103 won't actually vanish as we still have skb, and del_timer
104 means this will only run once even if count hits zero twice
105 (theoretically possible with SMP) */
106 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
107 if (atomic_dec_and_test(&ct->proto.icmp.count)
108 && del_timer(&ct->timeout))
109 ct->timeout.function((unsigned long)ct);
110 } else {
111 atomic_inc(&ct->proto.icmp.count);
112 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
113 nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
114 }
115
116 return NF_ACCEPT;
117}
118
119/* Called when a new connection for this protocol found. */
120static int icmp_new(struct nf_conn *conntrack,
121 const struct sk_buff *skb, unsigned int dataoff)
122{
123 static u_int8_t valid_new[]
124 = { [ICMP_ECHO] = 1,
125 [ICMP_TIMESTAMP] = 1,
126 [ICMP_INFO_REQUEST] = 1,
127 [ICMP_ADDRESS] = 1 };
128
129 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
130 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
131 /* Can't create a new ICMP `conn' with this. */
132 DEBUGP("icmp: can't create new conn with type %u\n",
133 conntrack->tuplehash[0].tuple.dst.u.icmp.type);
134 NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
135 return 0;
136 }
137 atomic_set(&conntrack->proto.icmp.count, 0);
138 return 1;
139}
140
141extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
142/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
143static int
144icmp_error_message(struct sk_buff *skb,
145 enum ip_conntrack_info *ctinfo,
146 unsigned int hooknum)
147{
148 struct nf_conntrack_tuple innertuple, origtuple;
149 struct {
150 struct icmphdr icmp;
151 struct iphdr ip;
152 } _in, *inside;
153 struct nf_conntrack_protocol *innerproto;
154 struct nf_conntrack_tuple_hash *h;
155 int dataoff;
156
157 NF_CT_ASSERT(skb->nfct == NULL);
158
159 /* Not enough header? */
160 inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
161 if (inside == NULL)
162 return -NF_ACCEPT;
163
164 /* Ignore ICMP's containing fragments (shouldn't happen) */
165 if (inside->ip.frag_off & htons(IP_OFFSET)) {
166 DEBUGP("icmp_error_message: fragment of proto %u\n",
167 inside->ip.protocol);
168 return -NF_ACCEPT;
169 }
170
171 innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol);
172 dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
173 /* Are they talking about one of our connections? */
174 if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
175 inside->ip.protocol, &origtuple,
176 &nf_conntrack_l3proto_ipv4, innerproto)) {
177 DEBUGP("icmp_error_message: ! get_tuple p=%u",
178 inside->ip.protocol);
179 return -NF_ACCEPT;
180 }
181
182 /* Ordinarily, we'd expect the inverted tupleproto, but it's
183 been preserved inside the ICMP. */
184 if (!nf_ct_invert_tuple(&innertuple, &origtuple,
185 &nf_conntrack_l3proto_ipv4, innerproto)) {
186 DEBUGP("icmp_error_message: no match\n");
187 return -NF_ACCEPT;
188 }
189
190 *ctinfo = IP_CT_RELATED;
191
192 h = nf_conntrack_find_get(&innertuple, NULL);
193 if (!h) {
194 /* Locally generated ICMPs will match inverted if they
195 haven't been SNAT'ed yet */
196 /* FIXME: NAT code has to handle half-done double NAT --RR */
197 if (hooknum == NF_IP_LOCAL_OUT)
198 h = nf_conntrack_find_get(&origtuple, NULL);
199
200 if (!h) {
201 DEBUGP("icmp_error_message: no match\n");
202 return -NF_ACCEPT;
203 }
204
205 /* Reverse direction from that found */
206 if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
207 *ctinfo += IP_CT_IS_REPLY;
208 } else {
209 if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
210 *ctinfo += IP_CT_IS_REPLY;
211 }
212
213 /* Update skb to refer to this connection */
214 skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
215 skb->nfctinfo = *ctinfo;
216 return -NF_ACCEPT;
217}
218
219/* Small and modified version of icmp_rcv */
220static int
221icmp_error(struct sk_buff *skb, unsigned int dataoff,
222 enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
223{
224 struct icmphdr _ih, *icmph;
225
226 /* Not enough header? */
227 icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
228 if (icmph == NULL) {
229 if (LOG_INVALID(IPPROTO_ICMP))
230 nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
231 "nf_ct_icmp: short packet ");
232 return -NF_ACCEPT;
233 }
234
235 /* See ip_conntrack_proto_tcp.c */
236 if (hooknum != NF_IP_PRE_ROUTING)
237 goto checksum_skipped;
238
239 switch (skb->ip_summed) {
240 case CHECKSUM_HW:
241 if (!(u16)csum_fold(skb->csum))
242 break;
243 if (LOG_INVALID(IPPROTO_ICMP))
244 nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
245 "nf_ct_icmp: bad HW ICMP checksum ");
246 return -NF_ACCEPT;
247 case CHECKSUM_NONE:
248 if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
249 if (LOG_INVALID(IPPROTO_ICMP))
250 nf_log_packet(PF_INET, 0, skb, NULL, NULL,
251 NULL,
252 "nf_ct_icmp: bad ICMP checksum ");
253 return -NF_ACCEPT;
254 }
255 default:
256 break;
257 }
258
259checksum_skipped:
260 /*
261 * 18 is the highest 'known' ICMP type. Anything else is a mystery
262 *
263 * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently
264 * discarded.
265 */
266 if (icmph->type > NR_ICMP_TYPES) {
267 if (LOG_INVALID(IPPROTO_ICMP))
268 nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
269 "nf_ct_icmp: invalid ICMP type ");
270 return -NF_ACCEPT;
271 }
272
273 /* Need to track icmp error message? */
274 if (icmph->type != ICMP_DEST_UNREACH
275 && icmph->type != ICMP_SOURCE_QUENCH
276 && icmph->type != ICMP_TIME_EXCEEDED
277 && icmph->type != ICMP_PARAMETERPROB
278 && icmph->type != ICMP_REDIRECT)
279 return NF_ACCEPT;
280
281 return icmp_error_message(skb, ctinfo, hooknum);
282}
283
284struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
285{
286 .list = { NULL, NULL },
287 .l3proto = PF_INET,
288 .proto = IPPROTO_ICMP,
289 .name = "icmp",
290 .pkt_to_tuple = icmp_pkt_to_tuple,
291 .invert_tuple = icmp_invert_tuple,
292 .print_tuple = icmp_print_tuple,
293 .print_conntrack = icmp_print_conntrack,
294 .packet = icmp_packet,
295 .new = icmp_new,
296 .error = icmp_error,
297 .destroy = NULL,
298 .me = NULL
299};
300
301EXPORT_SYMBOL(nf_conntrack_protocol_icmp);