diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 41 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 6 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_netlink.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_CLUSTERIP.c | 12 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_CONNMARK.c | 22 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_NOTRACK.c | 4 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_connbytes.c | 39 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_connmark.c | 10 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_conntrack.c | 96 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_helper.c | 54 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_state.c | 6 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 571 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 301 |
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 @@ | |||
5 | menu "IP: Netfilter Configuration" | 5 | menu "IP: Netfilter Configuration" |
6 | depends on INET && NETFILTER | 6 | depends on INET && NETFILTER |
7 | 7 | ||
8 | config 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 |
9 | config IP_NF_CONNTRACK | 23 | config 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 | ||
318 | config IP_NF_MATCH_HELPER | 332 | config 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 | ||
327 | config IP_NF_MATCH_STATE | 342 | config 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 | ||
337 | config IP_NF_MATCH_CONNTRACK | 353 | config 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 | ||
423 | config IP_NF_MATCH_CONNMARK | 440 | config 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 | ||
434 | config IP_NF_MATCH_CONNBYTES | 452 | config 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 | ||
748 | config IP_NF_TARGET_CONNMARK | 767 | config 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 | ||
760 | config IP_NF_TARGET_CLUSTERIP | 780 | config 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 | |||
782 | config IP_NF_TARGET_NOTRACK | 803 | config 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 | |||
103 | obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o | 103 | obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o |
104 | 104 | ||
105 | obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o | 105 | obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o |
106 | |||
107 | # objects for l3 independent conntrack | ||
108 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o | ||
109 | |||
110 | # l3 independent conntrack | ||
111 | obj-$(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 | ||
34 | static unsigned int | 34 | static unsigned int |
35 | target(struct sk_buff **pskb, | 35 | target(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 | ||
10 | static unsigned int | 10 | static unsigned int |
11 | target(struct sk_buff **pskb, | 11 | target(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 | ||
33 | static int | 33 | static int |
34 | match(const struct sk_buff *skb, | 34 | match(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 | ||
50 | static int | 50 | static 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"); | |||
18 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | 25 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); |
19 | MODULE_DESCRIPTION("iptables connection tracking match module"); | 26 | MODULE_DESCRIPTION("iptables connection tracking match module"); |
20 | 27 | ||
28 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
29 | |||
21 | static int | 30 | static int |
22 | match(const struct sk_buff *skb, | 31 | match(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 */ | ||
115 | static int | ||
116 | match(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 | |||
105 | static int check(const char *tablename, | 201 | static 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) | ||
32 | static int | 39 | static int |
33 | match(const struct sk_buff *skb, | 40 | match(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 | |||
85 | static int | ||
86 | match(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)); | ||
124 | out_unlock: | ||
125 | read_unlock_bh(&nf_conntrack_lock); | ||
126 | return ret; | ||
127 | } | ||
128 | #endif | ||
129 | |||
76 | static int check(const char *tablename, | 130 | static 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 | |||
41 | DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat); | ||
42 | |||
43 | static 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 | |||
58 | static 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 | |||
67 | static 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 | |||
75 | static 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 */ | ||
82 | static struct sk_buff * | ||
83 | nf_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 | |||
97 | static int | ||
98 | ipv4_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 | |||
116 | int nat_module_is_loaded = 0; | ||
117 | static 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 | |||
125 | static 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 | |||
135 | static 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 | |||
158 | static 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 | |||
183 | static 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 | |||
207 | static 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 | |||
216 | static 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. */ | ||
234 | static 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 | |||
242 | static 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 | |||
250 | static 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 | |||
258 | static 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 */ | ||
267 | static 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 | |||
275 | static 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. */ | ||
285 | static 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 | |||
293 | static 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 */ | ||
303 | extern unsigned long nf_ct_icmp_timeout; | ||
304 | static struct ctl_table_header *nf_ct_ipv4_sysctl_header; | ||
305 | |||
306 | static 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 | |||
318 | static 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 | |||
328 | static 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. */ | ||
343 | static int | ||
344 | getorigdst(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 | |||
395 | static 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 | |||
402 | struct 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 | |||
414 | extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4; | ||
415 | extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4; | ||
416 | extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp; | ||
417 | static 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 | |||
550 | MODULE_LICENSE("GPL"); | ||
551 | |||
552 | static int __init init(void) | ||
553 | { | ||
554 | need_nf_conntrack(); | ||
555 | return init_or_cleanup(1); | ||
556 | } | ||
557 | |||
558 | static void __exit fini(void) | ||
559 | { | ||
560 | init_or_cleanup(0); | ||
561 | } | ||
562 | |||
563 | module_init(init); | ||
564 | module_exit(fini); | ||
565 | |||
566 | void need_ip_conntrack(void) | ||
567 | { | ||
568 | } | ||
569 | |||
570 | EXPORT_SYMBOL(need_ip_conntrack); | ||
571 | EXPORT_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 | |||
28 | unsigned 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 | |||
36 | static 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 | |||
53 | static 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. */ | ||
78 | static 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. */ | ||
88 | static 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. */ | ||
95 | static 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. */ | ||
120 | static 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 | |||
141 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; | ||
142 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ | ||
143 | static int | ||
144 | icmp_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 */ | ||
220 | static int | ||
221 | icmp_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 | |||
259 | checksum_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 | |||
284 | struct 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 | |||
301 | EXPORT_SYMBOL(nf_conntrack_protocol_icmp); | ||