aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/ip_fragment.c2
-rw-r--r--net/ipv4/netfilter/Kconfig20
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_amanda.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c38
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_irc.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netbios_ns.c131
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c13
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_tftp.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_rule.c21
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c8
14 files changed, 213 insertions, 28 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 9e6e683cc3..e7d26d9943 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -457,7 +457,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
457 457
458 if (pskb_pull(skb, ihl) == NULL) 458 if (pskb_pull(skb, ihl) == NULL)
459 goto err; 459 goto err;
460 if (pskb_trim(skb, end-offset)) 460 if (pskb_trim_rcsum(skb, end-offset))
461 goto err; 461 goto err;
462 462
463 /* Find out which fragments are in front and at the back of us 463 /* Find out which fragments are in front and at the back of us
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index e046f55218..30aa8e2ee2 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -34,6 +34,7 @@ config IP_NF_CT_ACCT
34 34
35config IP_NF_CONNTRACK_MARK 35config IP_NF_CONNTRACK_MARK
36 bool 'Connection mark tracking support' 36 bool 'Connection mark tracking support'
37 depends on IP_NF_CONNTRACK
37 help 38 help
38 This option enables support for connection marks, used by the 39 This option enables support for connection marks, used by the
39 `CONNMARK' target and `connmark' match. Similar to the mark value 40 `CONNMARK' target and `connmark' match. Similar to the mark value
@@ -85,6 +86,25 @@ config IP_NF_IRC
85 86
86 To compile it as a module, choose M here. If unsure, say Y. 87 To compile it as a module, choose M here. If unsure, say Y.
87 88
89config IP_NF_NETBIOS_NS
90 tristate "NetBIOS name service protocol support (EXPERIMENTAL)"
91 depends on IP_NF_CONNTRACK && EXPERIMENTAL
92 help
93 NetBIOS name service requests are sent as broadcast messages from an
94 unprivileged port and responded to with unicast messages to the
95 same port. This make them hard to firewall properly because connection
96 tracking doesn't deal with broadcasts. This helper tracks locally
97 originating NetBIOS name service requests and the corresponding
98 responses. It relies on correct IP address configuration, specifically
99 netmask and broadcast address. When properly configured, the output
100 of "ip address show" should look similar to this:
101
102 $ ip -4 address show eth0
103 4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
104 inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0
105
106 To compile it as a module, choose M here. If unsure, say N.
107
88config IP_NF_TFTP 108config IP_NF_TFTP
89 tristate "TFTP protocol support" 109 tristate "TFTP protocol support"
90 depends on IP_NF_CONNTRACK 110 depends on IP_NF_CONNTRACK
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index a7bd38f505..1ba0db7468 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
21obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o 21obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
22obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o 22obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
23obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o 23obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
24obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
24 25
25# NAT helpers 26# NAT helpers
26obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o 27obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
index be4c9eb324..dc20881004 100644
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -108,6 +108,7 @@ static int help(struct sk_buff **pskb,
108 } 108 }
109 109
110 exp->expectfn = NULL; 110 exp->expectfn = NULL;
111 exp->flags = 0;
111 112
112 exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; 113 exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
113 exp->tuple.src.u.tcp.port = 0; 114 exp->tuple.src.u.tcp.port = 0;
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index a064860019..19cba16e6e 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -197,7 +197,7 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
197 197
198 198
199/* ip_conntrack_expect helper functions */ 199/* ip_conntrack_expect helper functions */
200static void unlink_expect(struct ip_conntrack_expect *exp) 200void ip_ct_unlink_expect(struct ip_conntrack_expect *exp)
201{ 201{
202 ASSERT_WRITE_LOCK(&ip_conntrack_lock); 202 ASSERT_WRITE_LOCK(&ip_conntrack_lock);
203 IP_NF_ASSERT(!timer_pending(&exp->timeout)); 203 IP_NF_ASSERT(!timer_pending(&exp->timeout));
@@ -207,18 +207,12 @@ static void unlink_expect(struct ip_conntrack_expect *exp)
207 ip_conntrack_expect_put(exp); 207 ip_conntrack_expect_put(exp);
208} 208}
209 209
210void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp)
211{
212 unlink_expect(exp);
213 ip_conntrack_expect_put(exp);
214}
215
216static void expectation_timed_out(unsigned long ul_expect) 210static void expectation_timed_out(unsigned long ul_expect)
217{ 211{
218 struct ip_conntrack_expect *exp = (void *)ul_expect; 212 struct ip_conntrack_expect *exp = (void *)ul_expect;
219 213
220 write_lock_bh(&ip_conntrack_lock); 214 write_lock_bh(&ip_conntrack_lock);
221 unlink_expect(exp); 215 ip_ct_unlink_expect(exp);
222 write_unlock_bh(&ip_conntrack_lock); 216 write_unlock_bh(&ip_conntrack_lock);
223 ip_conntrack_expect_put(exp); 217 ip_conntrack_expect_put(exp);
224} 218}
@@ -264,10 +258,14 @@ find_expectation(const struct ip_conntrack_tuple *tuple)
264 master ct never got confirmed, we'd hold a reference to it 258 master ct never got confirmed, we'd hold a reference to it
265 and weird things would happen to future packets). */ 259 and weird things would happen to future packets). */
266 if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) 260 if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
267 && is_confirmed(i->master) 261 && is_confirmed(i->master)) {
268 && del_timer(&i->timeout)) { 262 if (i->flags & IP_CT_EXPECT_PERMANENT) {
269 unlink_expect(i); 263 atomic_inc(&i->use);
270 return i; 264 return i;
265 } else if (del_timer(&i->timeout)) {
266 ip_ct_unlink_expect(i);
267 return i;
268 }
271 } 269 }
272 } 270 }
273 return NULL; 271 return NULL;
@@ -284,7 +282,7 @@ void ip_ct_remove_expectations(struct ip_conntrack *ct)
284 282
285 list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) { 283 list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) {
286 if (i->master == ct && del_timer(&i->timeout)) { 284 if (i->master == ct && del_timer(&i->timeout)) {
287 unlink_expect(i); 285 ip_ct_unlink_expect(i);
288 ip_conntrack_expect_put(i); 286 ip_conntrack_expect_put(i);
289 } 287 }
290 } 288 }
@@ -925,7 +923,7 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp)
925 /* choose the the oldest expectation to evict */ 923 /* choose the the oldest expectation to evict */
926 list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { 924 list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
927 if (expect_matches(i, exp) && del_timer(&i->timeout)) { 925 if (expect_matches(i, exp) && del_timer(&i->timeout)) {
928 unlink_expect(i); 926 ip_ct_unlink_expect(i);
929 write_unlock_bh(&ip_conntrack_lock); 927 write_unlock_bh(&ip_conntrack_lock);
930 ip_conntrack_expect_put(i); 928 ip_conntrack_expect_put(i);
931 return; 929 return;
@@ -934,6 +932,9 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp)
934 write_unlock_bh(&ip_conntrack_lock); 932 write_unlock_bh(&ip_conntrack_lock);
935} 933}
936 934
935/* We don't increase the master conntrack refcount for non-fulfilled
936 * conntracks. During the conntrack destruction, the expectations are
937 * always killed before the conntrack itself */
937struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me) 938struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
938{ 939{
939 struct ip_conntrack_expect *new; 940 struct ip_conntrack_expect *new;
@@ -944,17 +945,14 @@ struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
944 return NULL; 945 return NULL;
945 } 946 }
946 new->master = me; 947 new->master = me;
947 atomic_inc(&new->master->ct_general.use);
948 atomic_set(&new->use, 1); 948 atomic_set(&new->use, 1);
949 return new; 949 return new;
950} 950}
951 951
952void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) 952void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
953{ 953{
954 if (atomic_dec_and_test(&exp->use)) { 954 if (atomic_dec_and_test(&exp->use))
955 ip_conntrack_put(exp->master);
956 kmem_cache_free(ip_conntrack_expect_cachep, exp); 955 kmem_cache_free(ip_conntrack_expect_cachep, exp);
957 }
958} 956}
959 957
960static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp) 958static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
@@ -982,7 +980,7 @@ static void evict_oldest_expect(struct ip_conntrack *master)
982 list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { 980 list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
983 if (i->master == master) { 981 if (i->master == master) {
984 if (del_timer(&i->timeout)) { 982 if (del_timer(&i->timeout)) {
985 unlink_expect(i); 983 ip_ct_unlink_expect(i);
986 ip_conntrack_expect_put(i); 984 ip_conntrack_expect_put(i);
987 } 985 }
988 break; 986 break;
@@ -1099,7 +1097,7 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
1099 /* Get rid of expectations */ 1097 /* Get rid of expectations */
1100 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) { 1098 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
1101 if (exp->master->helper == me && del_timer(&exp->timeout)) { 1099 if (exp->master->helper == me && del_timer(&exp->timeout)) {
1102 unlink_expect(exp); 1100 ip_ct_unlink_expect(exp);
1103 ip_conntrack_expect_put(exp); 1101 ip_conntrack_expect_put(exp);
1104 } 1102 }
1105 } 1103 }
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 3a2627db17..1b79ec3608 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -421,6 +421,7 @@ static int help(struct sk_buff **pskb,
421 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); 421 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
422 422
423 exp->expectfn = NULL; 423 exp->expectfn = NULL;
424 exp->flags = 0;
424 425
425 /* Now, NAT might want to mangle the packet, and register the 426 /* Now, NAT might want to mangle the packet, and register the
426 * (possibly changed) expectation itself. */ 427 * (possibly changed) expectation itself. */
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index 25438eec21..d7a8a98c05 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -221,6 +221,7 @@ static int help(struct sk_buff **pskb,
221 { { 0, { 0 } }, 221 { { 0, { 0 } },
222 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); 222 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
223 exp->expectfn = NULL; 223 exp->expectfn = NULL;
224 exp->flags = 0;
224 if (ip_nat_irc_hook) 225 if (ip_nat_irc_hook)
225 ret = ip_nat_irc_hook(pskb, ctinfo, 226 ret = ip_nat_irc_hook(pskb, ctinfo,
226 addr_beg_p - ib_ptr, 227 addr_beg_p - ib_ptr,
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
new file mode 100644
index 0000000000..2b5cf9c513
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
@@ -0,0 +1,131 @@
1/*
2 * NetBIOS name service broadcast connection tracking helper
3 *
4 * (c) 2005 Patrick McHardy <kaber@trash.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11/*
12 * This helper tracks locally originating NetBIOS name service
13 * requests by issuing permanent expectations (valid until
14 * timing out) matching all reply connections from the
15 * destination network. The only NetBIOS specific thing is
16 * actually the port number.
17 */
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/skbuff.h>
22#include <linux/netdevice.h>
23#include <linux/inetdevice.h>
24#include <linux/in.h>
25#include <linux/ip.h>
26#include <linux/udp.h>
27#include <net/route.h>
28
29#include <linux/netfilter.h>
30#include <linux/netfilter_ipv4.h>
31#include <linux/netfilter_ipv4/ip_conntrack.h>
32#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
33
34MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
35MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
36MODULE_LICENSE("GPL");
37
38static unsigned int timeout = 3;
39module_param(timeout, int, 0600);
40MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
41
42static int help(struct sk_buff **pskb,
43 struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
44{
45 struct ip_conntrack_expect *exp;
46 struct iphdr *iph = (*pskb)->nh.iph;
47 struct udphdr _uh, *uh;
48 struct rtable *rt = (struct rtable *)(*pskb)->dst;
49 struct in_device *in_dev;
50 u_int32_t mask = 0;
51
52 /* we're only interested in locally generated packets */
53 if ((*pskb)->sk == NULL)
54 goto out;
55 if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST))
56 goto out;
57 if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
58 goto out;
59
60 rcu_read_lock();
61 in_dev = __in_dev_get(rt->u.dst.dev);
62 if (in_dev != NULL) {
63 for_primary_ifa(in_dev) {
64 if (ifa->ifa_broadcast == iph->daddr) {
65 mask = ifa->ifa_mask;
66 break;
67 }
68 } endfor_ifa(in_dev);
69 }
70 rcu_read_unlock();
71
72 if (mask == 0)
73 goto out;
74
75 uh = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_uh), &_uh);
76 BUG_ON(uh == NULL);
77
78 exp = ip_conntrack_expect_alloc(ct);
79 if (exp == NULL)
80 goto out;
81 memset(&exp->tuple, 0, sizeof(exp->tuple));
82 exp->tuple.src.ip = iph->daddr & mask;
83 exp->tuple.dst.ip = iph->saddr;
84 exp->tuple.dst.u.udp.port = uh->source;
85 exp->tuple.dst.protonum = IPPROTO_UDP;
86
87 memset(&exp->mask, 0, sizeof(exp->mask));
88 exp->mask.src.ip = mask;
89 exp->mask.dst.ip = 0xFFFFFFFF;
90 exp->mask.dst.u.udp.port = 0xFFFF;
91 exp->mask.dst.protonum = 0xFF;
92
93 exp->expectfn = NULL;
94 exp->flags = IP_CT_EXPECT_PERMANENT;
95
96 ip_conntrack_expect_related(exp);
97 ip_conntrack_expect_put(exp);
98
99 ip_ct_refresh_acct(ct, ctinfo, NULL, timeout * HZ);
100out:
101 return NF_ACCEPT;
102}
103
104static struct ip_conntrack_helper helper = {
105 .name = "netbios-ns",
106 .tuple = {
107 .src.u.udp.port = __constant_htons(137),
108 .dst.protonum = IPPROTO_UDP,
109 },
110 .mask = {
111 .src.u.udp.port = 0xFFFF,
112 .dst.protonum = 0xFF,
113 },
114 .max_expected = 1,
115 .me = THIS_MODULE,
116 .help = help,
117};
118
119static int __init init(void)
120{
121 helper.timeout = timeout;
122 return ip_conntrack_helper_register(&helper);
123}
124
125static void __exit fini(void)
126{
127 ip_conntrack_helper_unregister(&helper);
128}
129
130module_init(init);
131module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index a4e9278db4..15aef35647 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1349,8 +1349,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1349 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, 1349 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1350 list) { 1350 list) {
1351 if (exp->master->helper == h 1351 if (exp->master->helper == h
1352 && del_timer(&exp->timeout)) 1352 && del_timer(&exp->timeout)) {
1353 __ip_ct_expect_unlink_destroy(exp); 1353 ip_ct_unlink_expect(exp);
1354 ip_conntrack_expect_put(exp);
1355 }
1354 } 1356 }
1355 write_unlock(&ip_conntrack_lock); 1357 write_unlock(&ip_conntrack_lock);
1356 } else { 1358 } else {
@@ -1358,8 +1360,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1358 write_lock_bh(&ip_conntrack_lock); 1360 write_lock_bh(&ip_conntrack_lock);
1359 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, 1361 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1360 list) { 1362 list) {
1361 if (del_timer(&exp->timeout)) 1363 if (del_timer(&exp->timeout)) {
1362 __ip_ct_expect_unlink_destroy(exp); 1364 ip_ct_unlink_expect(exp);
1365 ip_conntrack_expect_put(exp);
1366 }
1363 } 1367 }
1364 write_unlock_bh(&ip_conntrack_lock); 1368 write_unlock_bh(&ip_conntrack_lock);
1365 } 1369 }
@@ -1413,6 +1417,7 @@ ctnetlink_create_expect(struct nfattr *cda[])
1413 } 1417 }
1414 1418
1415 exp->expectfn = NULL; 1419 exp->expectfn = NULL;
1420 exp->flags = 0;
1416 exp->master = ct; 1421 exp->master = ct;
1417 memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); 1422 memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
1418 memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); 1423 memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index f23ef1f88c..1985abc59d 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -349,6 +349,7 @@ static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
349 return 0; 349 return 0;
350 350
351nfattr_failure: 351nfattr_failure:
352 read_unlock_bh(&tcp_lock);
352 return -1; 353 return -1;
353} 354}
354#endif 355#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index ee5895afd0..ae3e3e655d 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -998,7 +998,7 @@ EXPORT_SYMBOL(ip_conntrack_expect_related);
998EXPORT_SYMBOL(ip_conntrack_unexpect_related); 998EXPORT_SYMBOL(ip_conntrack_unexpect_related);
999EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); 999EXPORT_SYMBOL_GPL(ip_conntrack_expect_list);
1000EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); 1000EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find);
1001EXPORT_SYMBOL_GPL(__ip_ct_expect_unlink_destroy); 1001EXPORT_SYMBOL_GPL(ip_ct_unlink_expect);
1002 1002
1003EXPORT_SYMBOL(ip_conntrack_tuple_taken); 1003EXPORT_SYMBOL(ip_conntrack_tuple_taken);
1004EXPORT_SYMBOL(ip_ct_gather_frags); 1004EXPORT_SYMBOL(ip_ct_gather_frags);
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
index f8ff170f39..d2b5905334 100644
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
@@ -75,6 +75,7 @@ static int tftp_help(struct sk_buff **pskb,
75 exp->mask.dst.u.udp.port = 0xffff; 75 exp->mask.dst.u.udp.port = 0xffff;
76 exp->mask.dst.protonum = 0xff; 76 exp->mask.dst.protonum = 0xff;
77 exp->expectfn = NULL; 77 exp->expectfn = NULL;
78 exp->flags = 0;
78 79
79 DEBUGP("expect: "); 80 DEBUGP("expect: ");
80 DUMP_TUPLE(&exp->tuple); 81 DUMP_TUPLE(&exp->tuple);
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index 60d70fa41a..cb66b8bdde 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -255,6 +255,27 @@ alloc_null_binding(struct ip_conntrack *conntrack,
255 return ip_nat_setup_info(conntrack, &range, hooknum); 255 return ip_nat_setup_info(conntrack, &range, hooknum);
256} 256}
257 257
258unsigned int
259alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
260 struct ip_nat_info *info,
261 unsigned int hooknum)
262{
263 u_int32_t ip
264 = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
265 ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
266 : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
267 u_int16_t all
268 = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
269 ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
270 : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
271 struct ip_nat_range range
272 = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
273
274 DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
275 conntrack, NIPQUAD(ip));
276 return ip_nat_setup_info(conntrack, &range, hooknum);
277}
278
258int ip_nat_rule_find(struct sk_buff **pskb, 279int ip_nat_rule_find(struct sk_buff **pskb,
259 unsigned int hooknum, 280 unsigned int hooknum,
260 const struct net_device *in, 281 const struct net_device *in,
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 89db052add..0ff368b131 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -123,8 +123,12 @@ ip_nat_fn(unsigned int hooknum,
123 if (!ip_nat_initialized(ct, maniptype)) { 123 if (!ip_nat_initialized(ct, maniptype)) {
124 unsigned int ret; 124 unsigned int ret;
125 125
126 /* LOCAL_IN hook doesn't have a chain! */ 126 if (unlikely(is_confirmed(ct)))
127 if (hooknum == NF_IP_LOCAL_IN) 127 /* NAT module was loaded late */
128 ret = alloc_null_binding_confirmed(ct, info,
129 hooknum);
130 else if (hooknum == NF_IP_LOCAL_IN)
131 /* LOCAL_IN hook doesn't have a chain! */
128 ret = alloc_null_binding(ct, info, hooknum); 132 ret = alloc_null_binding(ct, info, hooknum);
129 else 133 else
130 ret = ip_nat_rule_find(pskb, hooknum, 134 ret = ip_nat_rule_find(pskb, hooknum,