aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/ip_fragment.c8
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv4/netfilter.c41
-rw-r--r--net/ipv4/netfilter/Kconfig69
-rw-r--r--net/ipv4/netfilter/Makefile16
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c18
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c15
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c15
-rw-r--r--net/ipv4/netfilter/iptable_nat.c (renamed from net/ipv4/netfilter/nf_nat_standalone.c)264
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c8
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c85
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c763
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c137
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c71
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c458
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c99
-rw-r--r--net/ipv4/netfilter/nf_nat_l3proto_ipv4.c281
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c21
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_common.c114
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_dccp.c106
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c30
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_icmp.c24
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_sctp.c96
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_tcp.c91
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udp.c82
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udplite.c98
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_unknown.c52
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c214
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c572
-rw-r--r--net/ipv4/netfilter/nf_nat_tftp.c51
30 files changed, 545 insertions, 3358 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 8d07c973409c..fa6a12c51066 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -523,6 +523,10 @@ found:
523 if (offset == 0) 523 if (offset == 0)
524 qp->q.last_in |= INET_FRAG_FIRST_IN; 524 qp->q.last_in |= INET_FRAG_FIRST_IN;
525 525
526 if (ip_hdr(skb)->frag_off & htons(IP_DF) &&
527 skb->len + ihl > qp->q.max_size)
528 qp->q.max_size = skb->len + ihl;
529
526 if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && 530 if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
527 qp->q.meat == qp->q.len) 531 qp->q.meat == qp->q.len)
528 return ip_frag_reasm(qp, prev, dev); 532 return ip_frag_reasm(qp, prev, dev);
@@ -646,9 +650,11 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
646 head->next = NULL; 650 head->next = NULL;
647 head->dev = dev; 651 head->dev = dev;
648 head->tstamp = qp->q.stamp; 652 head->tstamp = qp->q.stamp;
653 IPCB(head)->frag_max_size = qp->q.max_size;
649 654
650 iph = ip_hdr(head); 655 iph = ip_hdr(head);
651 iph->frag_off = 0; 656 /* max_size != 0 implies at least one fragment had IP_DF set */
657 iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0;
652 iph->tot_len = htons(len); 658 iph->tot_len = htons(len);
653 iph->tos |= ecn; 659 iph->tos |= ecn;
654 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); 660 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index c196d749daf2..a5beab1dc958 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -467,7 +467,9 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
467 467
468 iph = ip_hdr(skb); 468 iph = ip_hdr(skb);
469 469
470 if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) { 470 if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) ||
471 (IPCB(skb)->frag_max_size &&
472 IPCB(skb)->frag_max_size > dst_mtu(&rt->dst)))) {
471 IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); 473 IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
472 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 474 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
473 htonl(ip_skb_dst_mtu(skb))); 475 htonl(ip_skb_dst_mtu(skb)));
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index ed1b36783192..4c0cf63dd92e 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -72,43 +72,6 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
72} 72}
73EXPORT_SYMBOL(ip_route_me_harder); 73EXPORT_SYMBOL(ip_route_me_harder);
74 74
75#ifdef CONFIG_XFRM
76int ip_xfrm_me_harder(struct sk_buff *skb)
77{
78 struct flowi fl;
79 unsigned int hh_len;
80 struct dst_entry *dst;
81
82 if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
83 return 0;
84 if (xfrm_decode_session(skb, &fl, AF_INET) < 0)
85 return -1;
86
87 dst = skb_dst(skb);
88 if (dst->xfrm)
89 dst = ((struct xfrm_dst *)dst)->route;
90 dst_hold(dst);
91
92 dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
93 if (IS_ERR(dst))
94 return -1;
95
96 skb_dst_drop(skb);
97 skb_dst_set(skb, dst);
98
99 /* Change in oif may mean change in hh_len. */
100 hh_len = skb_dst(skb)->dev->hard_header_len;
101 if (skb_headroom(skb) < hh_len &&
102 pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
103 return -1;
104 return 0;
105}
106EXPORT_SYMBOL(ip_xfrm_me_harder);
107#endif
108
109void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
110EXPORT_SYMBOL(ip_nat_decode_session);
111
112/* 75/*
113 * Extra routing may needed on local out, as the QUEUE target never 76 * Extra routing may needed on local out, as the QUEUE target never
114 * returns control to the table. 77 * returns control to the table.
@@ -225,12 +188,12 @@ static const struct nf_afinfo nf_ip_afinfo = {
225 .route_key_size = sizeof(struct ip_rt_info), 188 .route_key_size = sizeof(struct ip_rt_info),
226}; 189};
227 190
228static int ipv4_netfilter_init(void) 191static int __init ipv4_netfilter_init(void)
229{ 192{
230 return nf_register_afinfo(&nf_ip_afinfo); 193 return nf_register_afinfo(&nf_ip_afinfo);
231} 194}
232 195
233static void ipv4_netfilter_fini(void) 196static void __exit ipv4_netfilter_fini(void)
234{ 197{
235 nf_unregister_afinfo(&nf_ip_afinfo); 198 nf_unregister_afinfo(&nf_ip_afinfo);
236} 199}
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index fcc543cd987a..131e53702e77 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -143,25 +143,22 @@ config IP_NF_TARGET_ULOG
143 To compile it as a module, choose M here. If unsure, say N. 143 To compile it as a module, choose M here. If unsure, say N.
144 144
145# NAT + specific targets: nf_conntrack 145# NAT + specific targets: nf_conntrack
146config NF_NAT 146config NF_NAT_IPV4
147 tristate "Full NAT" 147 tristate "IPv4 NAT"
148 depends on NF_CONNTRACK_IPV4 148 depends on NF_CONNTRACK_IPV4
149 default m if NETFILTER_ADVANCED=n 149 default m if NETFILTER_ADVANCED=n
150 select NF_NAT
150 help 151 help
151 The Full NAT option allows masquerading, port forwarding and other 152 The IPv4 NAT option allows masquerading, port forwarding and other
152 forms of full Network Address Port Translation. It is controlled by 153 forms of full Network Address Port Translation. It is controlled by
153 the `nat' table in iptables: see the man page for iptables(8). 154 the `nat' table in iptables: see the man page for iptables(8).
154 155
155 To compile it as a module, choose M here. If unsure, say N. 156 To compile it as a module, choose M here. If unsure, say N.
156 157
157config NF_NAT_NEEDED 158if NF_NAT_IPV4
158 bool
159 depends on NF_NAT
160 default y
161 159
162config IP_NF_TARGET_MASQUERADE 160config IP_NF_TARGET_MASQUERADE
163 tristate "MASQUERADE target support" 161 tristate "MASQUERADE target support"
164 depends on NF_NAT
165 default m if NETFILTER_ADVANCED=n 162 default m if NETFILTER_ADVANCED=n
166 help 163 help
167 Masquerading is a special case of NAT: all outgoing connections are 164 Masquerading is a special case of NAT: all outgoing connections are
@@ -174,7 +171,6 @@ config IP_NF_TARGET_MASQUERADE
174 171
175config IP_NF_TARGET_NETMAP 172config IP_NF_TARGET_NETMAP
176 tristate "NETMAP target support" 173 tristate "NETMAP target support"
177 depends on NF_NAT
178 depends on NETFILTER_ADVANCED 174 depends on NETFILTER_ADVANCED
179 help 175 help
180 NETMAP is an implementation of static 1:1 NAT mapping of network 176 NETMAP is an implementation of static 1:1 NAT mapping of network
@@ -185,7 +181,6 @@ config IP_NF_TARGET_NETMAP
185 181
186config IP_NF_TARGET_REDIRECT 182config IP_NF_TARGET_REDIRECT
187 tristate "REDIRECT target support" 183 tristate "REDIRECT target support"
188 depends on NF_NAT
189 depends on NETFILTER_ADVANCED 184 depends on NETFILTER_ADVANCED
190 help 185 help
191 REDIRECT is a special case of NAT: all incoming connections are 186 REDIRECT is a special case of NAT: all incoming connections are
@@ -195,9 +190,11 @@ config IP_NF_TARGET_REDIRECT
195 190
196 To compile it as a module, choose M here. If unsure, say N. 191 To compile it as a module, choose M here. If unsure, say N.
197 192
193endif
194
198config NF_NAT_SNMP_BASIC 195config NF_NAT_SNMP_BASIC
199 tristate "Basic SNMP-ALG support" 196 tristate "Basic SNMP-ALG support"
200 depends on NF_CONNTRACK_SNMP && NF_NAT 197 depends on NF_CONNTRACK_SNMP && NF_NAT_IPV4
201 depends on NETFILTER_ADVANCED 198 depends on NETFILTER_ADVANCED
202 default NF_NAT && NF_CONNTRACK_SNMP 199 default NF_NAT && NF_CONNTRACK_SNMP
203 ---help--- 200 ---help---
@@ -219,61 +216,21 @@ config NF_NAT_SNMP_BASIC
219# <expr> '&&' <expr> (6) 216# <expr> '&&' <expr> (6)
220# 217#
221# (6) Returns the result of min(/expr/, /expr/). 218# (6) Returns the result of min(/expr/, /expr/).
222config NF_NAT_PROTO_DCCP
223 tristate
224 depends on NF_NAT && NF_CT_PROTO_DCCP
225 default NF_NAT && NF_CT_PROTO_DCCP
226 219
227config NF_NAT_PROTO_GRE 220config NF_NAT_PROTO_GRE
228 tristate 221 tristate
229 depends on NF_NAT && NF_CT_PROTO_GRE 222 depends on NF_NAT_IPV4 && NF_CT_PROTO_GRE
230
231config NF_NAT_PROTO_UDPLITE
232 tristate
233 depends on NF_NAT && NF_CT_PROTO_UDPLITE
234 default NF_NAT && NF_CT_PROTO_UDPLITE
235
236config NF_NAT_PROTO_SCTP
237 tristate
238 default NF_NAT && NF_CT_PROTO_SCTP
239 depends on NF_NAT && NF_CT_PROTO_SCTP
240 select LIBCRC32C
241
242config NF_NAT_FTP
243 tristate
244 depends on NF_CONNTRACK && NF_NAT
245 default NF_NAT && NF_CONNTRACK_FTP
246
247config NF_NAT_IRC
248 tristate
249 depends on NF_CONNTRACK && NF_NAT
250 default NF_NAT && NF_CONNTRACK_IRC
251
252config NF_NAT_TFTP
253 tristate
254 depends on NF_CONNTRACK && NF_NAT
255 default NF_NAT && NF_CONNTRACK_TFTP
256
257config NF_NAT_AMANDA
258 tristate
259 depends on NF_CONNTRACK && NF_NAT
260 default NF_NAT && NF_CONNTRACK_AMANDA
261 223
262config NF_NAT_PPTP 224config NF_NAT_PPTP
263 tristate 225 tristate
264 depends on NF_CONNTRACK && NF_NAT 226 depends on NF_CONNTRACK && NF_NAT_IPV4
265 default NF_NAT && NF_CONNTRACK_PPTP 227 default NF_NAT_IPV4 && NF_CONNTRACK_PPTP
266 select NF_NAT_PROTO_GRE 228 select NF_NAT_PROTO_GRE
267 229
268config NF_NAT_H323 230config NF_NAT_H323
269 tristate 231 tristate
270 depends on NF_CONNTRACK && NF_NAT 232 depends on NF_CONNTRACK && NF_NAT_IPV4
271 default NF_NAT && NF_CONNTRACK_H323 233 default NF_NAT_IPV4 && NF_CONNTRACK_H323
272
273config NF_NAT_SIP
274 tristate
275 depends on NF_CONNTRACK && NF_NAT
276 default NF_NAT && NF_CONNTRACK_SIP
277 234
278# mangle + specific targets 235# mangle + specific targets
279config IP_NF_MANGLE 236config IP_NF_MANGLE
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index c20674dc9452..b7dd18987237 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -10,32 +10,22 @@ nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o
10endif 10endif
11endif 11endif
12 12
13nf_nat-y := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_common.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
14iptable_nat-y := nf_nat_rule.o nf_nat_standalone.o
15
16# connection tracking 13# connection tracking
17obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o 14obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
18 15
19obj-$(CONFIG_NF_NAT) += nf_nat.o 16nf_nat_ipv4-y := nf_nat_l3proto_ipv4.o nf_nat_proto_icmp.o
17obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o
20 18
21# defrag 19# defrag
22obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o 20obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
23 21
24# NAT helpers (nf_conntrack) 22# NAT helpers (nf_conntrack)
25obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
26obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
27obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 23obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
28obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
29obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 24obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
30obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o
31obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o 25obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
32obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
33 26
34# NAT protocols (nf_nat) 27# NAT protocols (nf_nat)
35obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
36obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 28obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
37obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
38obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
39 29
40# generic IP tables 30# generic IP tables
41obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o 31obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
@@ -43,7 +33,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
43# the three instances of ip_tables 33# the three instances of ip_tables
44obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o 34obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
45obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o 35obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
46obj-$(CONFIG_NF_NAT) += iptable_nat.o 36obj-$(CONFIG_NF_NAT_IPV4) += iptable_nat.o
47obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o 37obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
48obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o 38obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
49 39
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index cbb6a1a6f6f7..5d5d4d1be9c2 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -19,9 +19,9 @@
19#include <net/ip.h> 19#include <net/ip.h>
20#include <net/checksum.h> 20#include <net/checksum.h>
21#include <net/route.h> 21#include <net/route.h>
22#include <net/netfilter/nf_nat_rule.h>
23#include <linux/netfilter_ipv4.h> 22#include <linux/netfilter_ipv4.h>
24#include <linux/netfilter/x_tables.h> 23#include <linux/netfilter/x_tables.h>
24#include <net/netfilter/nf_nat.h>
25 25
26MODULE_LICENSE("GPL"); 26MODULE_LICENSE("GPL");
27MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 27MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -49,7 +49,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
49 struct nf_conn *ct; 49 struct nf_conn *ct;
50 struct nf_conn_nat *nat; 50 struct nf_conn_nat *nat;
51 enum ip_conntrack_info ctinfo; 51 enum ip_conntrack_info ctinfo;
52 struct nf_nat_ipv4_range newrange; 52 struct nf_nat_range newrange;
53 const struct nf_nat_ipv4_multi_range_compat *mr; 53 const struct nf_nat_ipv4_multi_range_compat *mr;
54 const struct rtable *rt; 54 const struct rtable *rt;
55 __be32 newsrc, nh; 55 __be32 newsrc, nh;
@@ -80,10 +80,13 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
80 nat->masq_index = par->out->ifindex; 80 nat->masq_index = par->out->ifindex;
81 81
82 /* Transfer from original range. */ 82 /* Transfer from original range. */
83 newrange = ((struct nf_nat_ipv4_range) 83 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
84 { mr->range[0].flags | NF_NAT_RANGE_MAP_IPS, 84 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
85 newsrc, newsrc, 85 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
86 mr->range[0].min, mr->range[0].max }); 86 newrange.min_addr.ip = newsrc;
87 newrange.max_addr.ip = newsrc;
88 newrange.min_proto = mr->range[0].min;
89 newrange.max_proto = mr->range[0].max;
87 90
88 /* Hand modified range to generic setup. */ 91 /* Hand modified range to generic setup. */
89 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); 92 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
@@ -96,7 +99,8 @@ device_cmp(struct nf_conn *i, void *ifindex)
96 99
97 if (!nat) 100 if (!nat)
98 return 0; 101 return 0;
99 102 if (nf_ct_l3num(i) != NFPROTO_IPV4)
103 return 0;
100 return nat->masq_index == (int)(long)ifindex; 104 return nat->masq_index == (int)(long)ifindex;
101} 105}
102 106
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index b5bfbbabf70d..85028dc0425d 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -16,7 +16,7 @@
16#include <linux/netfilter.h> 16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv4.h> 17#include <linux/netfilter_ipv4.h>
18#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter/x_tables.h>
19#include <net/netfilter/nf_nat_rule.h> 19#include <net/netfilter/nf_nat.h>
20 20
21MODULE_LICENSE("GPL"); 21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>"); 22MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
@@ -44,7 +44,7 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
44 enum ip_conntrack_info ctinfo; 44 enum ip_conntrack_info ctinfo;
45 __be32 new_ip, netmask; 45 __be32 new_ip, netmask;
46 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 46 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
47 struct nf_nat_ipv4_range newrange; 47 struct nf_nat_range newrange;
48 48
49 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 49 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
50 par->hooknum == NF_INET_POST_ROUTING || 50 par->hooknum == NF_INET_POST_ROUTING ||
@@ -61,10 +61,13 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
61 new_ip = ip_hdr(skb)->saddr & ~netmask; 61 new_ip = ip_hdr(skb)->saddr & ~netmask;
62 new_ip |= mr->range[0].min_ip & netmask; 62 new_ip |= mr->range[0].min_ip & netmask;
63 63
64 newrange = ((struct nf_nat_ipv4_range) 64 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
65 { mr->range[0].flags | NF_NAT_RANGE_MAP_IPS, 65 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
66 new_ip, new_ip, 66 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
67 mr->range[0].min, mr->range[0].max }); 67 newrange.min_addr.ip = new_ip;
68 newrange.max_addr.ip = new_ip;
69 newrange.min_proto = mr->range[0].min;
70 newrange.max_proto = mr->range[0].max;
68 71
69 /* Hand modified range to generic setup. */ 72 /* Hand modified range to generic setup. */
70 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); 73 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 7c0103a5203e..11407d7d2472 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -19,7 +19,7 @@
19#include <net/checksum.h> 19#include <net/checksum.h>
20#include <linux/netfilter_ipv4.h> 20#include <linux/netfilter_ipv4.h>
21#include <linux/netfilter/x_tables.h> 21#include <linux/netfilter/x_tables.h>
22#include <net/netfilter/nf_nat_rule.h> 22#include <net/netfilter/nf_nat.h>
23 23
24MODULE_LICENSE("GPL"); 24MODULE_LICENSE("GPL");
25MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 25MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -48,7 +48,7 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
48 enum ip_conntrack_info ctinfo; 48 enum ip_conntrack_info ctinfo;
49 __be32 newdst; 49 __be32 newdst;
50 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; 50 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
51 struct nf_nat_ipv4_range newrange; 51 struct nf_nat_range newrange;
52 52
53 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 53 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
54 par->hooknum == NF_INET_LOCAL_OUT); 54 par->hooknum == NF_INET_LOCAL_OUT);
@@ -76,10 +76,13 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
76 } 76 }
77 77
78 /* Transfer from original range. */ 78 /* Transfer from original range. */
79 newrange = ((struct nf_nat_ipv4_range) 79 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
80 { mr->range[0].flags | NF_NAT_RANGE_MAP_IPS, 80 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
81 newdst, newdst, 81 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
82 mr->range[0].min, mr->range[0].max }); 82 newrange.min_addr.ip = newdst;
83 newrange.max_addr.ip = newdst;
84 newrange.min_proto = mr->range[0].min;
85 newrange.max_proto = mr->range[0].max;
83 86
84 /* Hand modified range to generic setup. */ 87 /* Hand modified range to generic setup. */
85 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); 88 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/iptable_nat.c
index 3828a4229822..9e0ffaf1d942 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -1,84 +1,71 @@
1/* (C) 1999-2001 Paul `Rusty' Russell 1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2011 Patrick McHardy <kaber@trash.net>
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify 5 * 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 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
7 */ 8 */
8#include <linux/types.h> 9
9#include <linux/icmp.h> 10#include <linux/module.h>
10#include <linux/gfp.h>
11#include <linux/ip.h>
12#include <linux/netfilter.h> 11#include <linux/netfilter.h>
13#include <linux/netfilter_ipv4.h> 12#include <linux/netfilter_ipv4.h>
14#include <linux/module.h> 13#include <linux/netfilter_ipv4/ip_tables.h>
15#include <linux/skbuff.h> 14#include <linux/ip.h>
16#include <linux/proc_fs.h>
17#include <net/ip.h> 15#include <net/ip.h>
18#include <net/checksum.h>
19#include <linux/spinlock.h>
20 16
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_conntrack_core.h>
23#include <net/netfilter/nf_conntrack_extend.h>
24#include <net/netfilter/nf_nat.h> 17#include <net/netfilter/nf_nat.h>
25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_nat_protocol.h>
27#include <net/netfilter/nf_nat_core.h> 18#include <net/netfilter/nf_nat_core.h>
28#include <net/netfilter/nf_nat_helper.h> 19#include <net/netfilter/nf_nat_l3proto.h>
29#include <linux/netfilter_ipv4/ip_tables.h> 20
21static const struct xt_table nf_nat_ipv4_table = {
22 .name = "nat",
23 .valid_hooks = (1 << NF_INET_PRE_ROUTING) |
24 (1 << NF_INET_POST_ROUTING) |
25 (1 << NF_INET_LOCAL_OUT) |
26 (1 << NF_INET_LOCAL_IN),
27 .me = THIS_MODULE,
28 .af = NFPROTO_IPV4,
29};
30 30
31#ifdef CONFIG_XFRM 31static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
32static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
33{ 32{
34 struct flowi4 *fl4 = &fl->u.ip4; 33 /* Force range to this IP; let proto decide mapping for
35 const struct nf_conn *ct; 34 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
36 const struct nf_conntrack_tuple *t; 35 */
37 enum ip_conntrack_info ctinfo; 36 struct nf_nat_range range;
38 enum ip_conntrack_dir dir; 37
39 unsigned long statusbit; 38 range.flags = 0;
40 39 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
41 ct = nf_ct_get(skb, &ctinfo); 40 HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
42 if (ct == NULL) 41 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
43 return; 42 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
44 dir = CTINFO2DIR(ctinfo); 43
45 t = &ct->tuplehash[dir].tuple; 44 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
46 45}
47 if (dir == IP_CT_DIR_ORIGINAL)
48 statusbit = IPS_DST_NAT;
49 else
50 statusbit = IPS_SRC_NAT;
51
52 if (ct->status & statusbit) {
53 fl4->daddr = t->dst.u3.ip;
54 if (t->dst.protonum == IPPROTO_TCP ||
55 t->dst.protonum == IPPROTO_UDP ||
56 t->dst.protonum == IPPROTO_UDPLITE ||
57 t->dst.protonum == IPPROTO_DCCP ||
58 t->dst.protonum == IPPROTO_SCTP)
59 fl4->fl4_dport = t->dst.u.tcp.port;
60 }
61 46
62 statusbit ^= IPS_NAT_MASK; 47static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
48 const struct net_device *in,
49 const struct net_device *out,
50 struct nf_conn *ct)
51{
52 struct net *net = nf_ct_net(ct);
53 unsigned int ret;
63 54
64 if (ct->status & statusbit) { 55 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
65 fl4->saddr = t->src.u3.ip; 56 if (ret == NF_ACCEPT) {
66 if (t->dst.protonum == IPPROTO_TCP || 57 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
67 t->dst.protonum == IPPROTO_UDP || 58 ret = alloc_null_binding(ct, hooknum);
68 t->dst.protonum == IPPROTO_UDPLITE ||
69 t->dst.protonum == IPPROTO_DCCP ||
70 t->dst.protonum == IPPROTO_SCTP)
71 fl4->fl4_sport = t->src.u.tcp.port;
72 } 59 }
60 return ret;
73} 61}
74#endif
75 62
76static unsigned int 63static unsigned int
77nf_nat_fn(unsigned int hooknum, 64nf_nat_ipv4_fn(unsigned int hooknum,
78 struct sk_buff *skb, 65 struct sk_buff *skb,
79 const struct net_device *in, 66 const struct net_device *in,
80 const struct net_device *out, 67 const struct net_device *out,
81 int (*okfn)(struct sk_buff *)) 68 int (*okfn)(struct sk_buff *))
82{ 69{
83 struct nf_conn *ct; 70 struct nf_conn *ct;
84 enum ip_conntrack_info ctinfo; 71 enum ip_conntrack_info ctinfo;
@@ -87,14 +74,16 @@ nf_nat_fn(unsigned int hooknum,
87 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 74 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
88 75
89 /* We never see fragments: conntrack defrags on pre-routing 76 /* We never see fragments: conntrack defrags on pre-routing
90 and local-out, and nf_nat_out protects post-routing. */ 77 * and local-out, and nf_nat_out protects post-routing.
78 */
91 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb))); 79 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb)));
92 80
93 ct = nf_ct_get(skb, &ctinfo); 81 ct = nf_ct_get(skb, &ctinfo);
94 /* Can't track? It's not due to stress, or conntrack would 82 /* Can't track? It's not due to stress, or conntrack would
95 have dropped it. Hence it's the user's responsibilty to 83 * have dropped it. Hence it's the user's responsibilty to
96 packet filter it out, or implement conntrack/NAT for that 84 * packet filter it out, or implement conntrack/NAT for that
97 protocol. 8) --RR */ 85 * protocol. 8) --RR
86 */
98 if (!ct) 87 if (!ct)
99 return NF_ACCEPT; 88 return NF_ACCEPT;
100 89
@@ -118,17 +107,17 @@ nf_nat_fn(unsigned int hooknum,
118 case IP_CT_RELATED: 107 case IP_CT_RELATED:
119 case IP_CT_RELATED_REPLY: 108 case IP_CT_RELATED_REPLY:
120 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 109 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
121 if (!nf_nat_icmp_reply_translation(ct, ctinfo, 110 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
122 hooknum, skb)) 111 hooknum))
123 return NF_DROP; 112 return NF_DROP;
124 else 113 else
125 return NF_ACCEPT; 114 return NF_ACCEPT;
126 } 115 }
127 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 116 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
128 case IP_CT_NEW: 117 case IP_CT_NEW:
129
130 /* Seen it before? This can happen for loopback, retrans, 118 /* Seen it before? This can happen for loopback, retrans,
131 or local packets.. */ 119 * or local packets.
120 */
132 if (!nf_nat_initialized(ct, maniptype)) { 121 if (!nf_nat_initialized(ct, maniptype)) {
133 unsigned int ret; 122 unsigned int ret;
134 123
@@ -151,16 +140,16 @@ nf_nat_fn(unsigned int hooknum,
151} 140}
152 141
153static unsigned int 142static unsigned int
154nf_nat_in(unsigned int hooknum, 143nf_nat_ipv4_in(unsigned int hooknum,
155 struct sk_buff *skb, 144 struct sk_buff *skb,
156 const struct net_device *in, 145 const struct net_device *in,
157 const struct net_device *out, 146 const struct net_device *out,
158 int (*okfn)(struct sk_buff *)) 147 int (*okfn)(struct sk_buff *))
159{ 148{
160 unsigned int ret; 149 unsigned int ret;
161 __be32 daddr = ip_hdr(skb)->daddr; 150 __be32 daddr = ip_hdr(skb)->daddr;
162 151
163 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 152 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn);
164 if (ret != NF_DROP && ret != NF_STOLEN && 153 if (ret != NF_DROP && ret != NF_STOLEN &&
165 daddr != ip_hdr(skb)->daddr) 154 daddr != ip_hdr(skb)->daddr)
166 skb_dst_drop(skb); 155 skb_dst_drop(skb);
@@ -169,11 +158,11 @@ nf_nat_in(unsigned int hooknum,
169} 158}
170 159
171static unsigned int 160static unsigned int
172nf_nat_out(unsigned int hooknum, 161nf_nat_ipv4_out(unsigned int hooknum,
173 struct sk_buff *skb, 162 struct sk_buff *skb,
174 const struct net_device *in, 163 const struct net_device *in,
175 const struct net_device *out, 164 const struct net_device *out,
176 int (*okfn)(struct sk_buff *)) 165 int (*okfn)(struct sk_buff *))
177{ 166{
178#ifdef CONFIG_XFRM 167#ifdef CONFIG_XFRM
179 const struct nf_conn *ct; 168 const struct nf_conn *ct;
@@ -186,29 +175,30 @@ nf_nat_out(unsigned int hooknum,
186 ip_hdrlen(skb) < sizeof(struct iphdr)) 175 ip_hdrlen(skb) < sizeof(struct iphdr))
187 return NF_ACCEPT; 176 return NF_ACCEPT;
188 177
189 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 178 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn);
190#ifdef CONFIG_XFRM 179#ifdef CONFIG_XFRM
191 if (ret != NF_DROP && ret != NF_STOLEN && 180 if (ret != NF_DROP && ret != NF_STOLEN &&
181 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
192 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 182 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
193 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 183 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
194 184
195 if ((ct->tuplehash[dir].tuple.src.u3.ip != 185 if ((ct->tuplehash[dir].tuple.src.u3.ip !=
196 ct->tuplehash[!dir].tuple.dst.u3.ip) || 186 ct->tuplehash[!dir].tuple.dst.u3.ip) ||
197 (ct->tuplehash[dir].tuple.src.u.all != 187 (ct->tuplehash[dir].tuple.src.u.all !=
198 ct->tuplehash[!dir].tuple.dst.u.all) 188 ct->tuplehash[!dir].tuple.dst.u.all))
199 ) 189 if (nf_xfrm_me_harder(skb, AF_INET) < 0)
200 return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP; 190 ret = NF_DROP;
201 } 191 }
202#endif 192#endif
203 return ret; 193 return ret;
204} 194}
205 195
206static unsigned int 196static unsigned int
207nf_nat_local_fn(unsigned int hooknum, 197nf_nat_ipv4_local_fn(unsigned int hooknum,
208 struct sk_buff *skb, 198 struct sk_buff *skb,
209 const struct net_device *in, 199 const struct net_device *in,
210 const struct net_device *out, 200 const struct net_device *out,
211 int (*okfn)(struct sk_buff *)) 201 int (*okfn)(struct sk_buff *))
212{ 202{
213 const struct nf_conn *ct; 203 const struct nf_conn *ct;
214 enum ip_conntrack_info ctinfo; 204 enum ip_conntrack_info ctinfo;
@@ -219,7 +209,7 @@ nf_nat_local_fn(unsigned int hooknum,
219 ip_hdrlen(skb) < sizeof(struct iphdr)) 209 ip_hdrlen(skb) < sizeof(struct iphdr))
220 return NF_ACCEPT; 210 return NF_ACCEPT;
221 211
222 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 212 ret = nf_nat_ipv4_fn(hooknum, skb, in, out, okfn);
223 if (ret != NF_DROP && ret != NF_STOLEN && 213 if (ret != NF_DROP && ret != NF_STOLEN &&
224 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 214 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
225 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 215 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -230,21 +220,20 @@ nf_nat_local_fn(unsigned int hooknum,
230 ret = NF_DROP; 220 ret = NF_DROP;
231 } 221 }
232#ifdef CONFIG_XFRM 222#ifdef CONFIG_XFRM
233 else if (ct->tuplehash[dir].tuple.dst.u.all != 223 else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
224 ct->tuplehash[dir].tuple.dst.u.all !=
234 ct->tuplehash[!dir].tuple.src.u.all) 225 ct->tuplehash[!dir].tuple.src.u.all)
235 if (ip_xfrm_me_harder(skb)) 226 if (nf_xfrm_me_harder(skb, AF_INET) < 0)
236 ret = NF_DROP; 227 ret = NF_DROP;
237#endif 228#endif
238 } 229 }
239 return ret; 230 return ret;
240} 231}
241 232
242/* We must be after connection tracking and before packet filtering. */ 233static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
243
244static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
245 /* Before packet filtering, change destination */ 234 /* Before packet filtering, change destination */
246 { 235 {
247 .hook = nf_nat_in, 236 .hook = nf_nat_ipv4_in,
248 .owner = THIS_MODULE, 237 .owner = THIS_MODULE,
249 .pf = NFPROTO_IPV4, 238 .pf = NFPROTO_IPV4,
250 .hooknum = NF_INET_PRE_ROUTING, 239 .hooknum = NF_INET_PRE_ROUTING,
@@ -252,7 +241,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
252 }, 241 },
253 /* After packet filtering, change source */ 242 /* After packet filtering, change source */
254 { 243 {
255 .hook = nf_nat_out, 244 .hook = nf_nat_ipv4_out,
256 .owner = THIS_MODULE, 245 .owner = THIS_MODULE,
257 .pf = NFPROTO_IPV4, 246 .pf = NFPROTO_IPV4,
258 .hooknum = NF_INET_POST_ROUTING, 247 .hooknum = NF_INET_POST_ROUTING,
@@ -260,7 +249,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
260 }, 249 },
261 /* Before packet filtering, change destination */ 250 /* Before packet filtering, change destination */
262 { 251 {
263 .hook = nf_nat_local_fn, 252 .hook = nf_nat_ipv4_local_fn,
264 .owner = THIS_MODULE, 253 .owner = THIS_MODULE,
265 .pf = NFPROTO_IPV4, 254 .pf = NFPROTO_IPV4,
266 .hooknum = NF_INET_LOCAL_OUT, 255 .hooknum = NF_INET_LOCAL_OUT,
@@ -268,7 +257,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
268 }, 257 },
269 /* After packet filtering, change source */ 258 /* After packet filtering, change source */
270 { 259 {
271 .hook = nf_nat_fn, 260 .hook = nf_nat_ipv4_fn,
272 .owner = THIS_MODULE, 261 .owner = THIS_MODULE,
273 .pf = NFPROTO_IPV4, 262 .pf = NFPROTO_IPV4,
274 .hooknum = NF_INET_LOCAL_IN, 263 .hooknum = NF_INET_LOCAL_IN,
@@ -276,51 +265,56 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
276 }, 265 },
277}; 266};
278 267
279static int __init nf_nat_standalone_init(void) 268static int __net_init iptable_nat_net_init(struct net *net)
280{ 269{
281 int ret = 0; 270 struct ipt_replace *repl;
271
272 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
273 if (repl == NULL)
274 return -ENOMEM;
275 net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
276 kfree(repl);
277 if (IS_ERR(net->ipv4.nat_table))
278 return PTR_ERR(net->ipv4.nat_table);
279 return 0;
280}
282 281
283 need_ipv4_conntrack(); 282static void __net_exit iptable_nat_net_exit(struct net *net)
283{
284 ipt_unregister_table(net, net->ipv4.nat_table);
285}
284 286
285#ifdef CONFIG_XFRM 287static struct pernet_operations iptable_nat_net_ops = {
286 BUG_ON(ip_nat_decode_session != NULL); 288 .init = iptable_nat_net_init,
287 RCU_INIT_POINTER(ip_nat_decode_session, nat_decode_session); 289 .exit = iptable_nat_net_exit,
288#endif 290};
289 ret = nf_nat_rule_init();
290 if (ret < 0) {
291 pr_err("nf_nat_init: can't setup rules.\n");
292 goto cleanup_decode_session;
293 }
294 ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
295 if (ret < 0) {
296 pr_err("nf_nat_init: can't register hooks.\n");
297 goto cleanup_rule_init;
298 }
299 return ret;
300 291
301 cleanup_rule_init: 292static int __init iptable_nat_init(void)
302 nf_nat_rule_cleanup(); 293{
303 cleanup_decode_session: 294 int err;
304#ifdef CONFIG_XFRM 295
305 RCU_INIT_POINTER(ip_nat_decode_session, NULL); 296 err = register_pernet_subsys(&iptable_nat_net_ops);
306 synchronize_net(); 297 if (err < 0)
307#endif 298 goto err1;
308 return ret; 299
300 err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
301 if (err < 0)
302 goto err2;
303 return 0;
304
305err2:
306 unregister_pernet_subsys(&iptable_nat_net_ops);
307err1:
308 return err;
309} 309}
310 310
311static void __exit nf_nat_standalone_fini(void) 311static void __exit iptable_nat_exit(void)
312{ 312{
313 nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); 313 nf_unregister_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
314 nf_nat_rule_cleanup(); 314 unregister_pernet_subsys(&iptable_nat_net_ops);
315#ifdef CONFIG_XFRM
316 RCU_INIT_POINTER(ip_nat_decode_session, NULL);
317 synchronize_net();
318#endif
319 /* Conntrack caches are unregistered in nf_conntrack_cleanup */
320} 315}
321 316
322module_init(nf_nat_standalone_init); 317module_init(iptable_nat_init);
323module_exit(nf_nat_standalone_fini); 318module_exit(iptable_nat_exit);
324 319
325MODULE_LICENSE("GPL"); 320MODULE_LICENSE("GPL");
326MODULE_ALIAS("ip_nat");
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index e7ff2dcab6ce..fcdd0c2406e6 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -29,11 +29,6 @@
29#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 29#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
30#include <net/netfilter/nf_log.h> 30#include <net/netfilter/nf_log.h>
31 31
32int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
33 struct nf_conn *ct,
34 enum ip_conntrack_info ctinfo);
35EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
36
37static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, 32static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
38 struct nf_conntrack_tuple *tuple) 33 struct nf_conntrack_tuple *tuple)
39{ 34{
@@ -149,7 +144,8 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
149 typeof(nf_nat_seq_adjust_hook) seq_adjust; 144 typeof(nf_nat_seq_adjust_hook) seq_adjust;
150 145
151 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); 146 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
152 if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) { 147 if (!seq_adjust ||
148 !seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
153 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 149 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
154 return NF_DROP; 150 return NF_DROP;
155 } 151 }
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
deleted file mode 100644
index 3c04d24e2976..000000000000
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ /dev/null
@@ -1,85 +0,0 @@
1/* Amanda extension for TCP NAT alteration.
2 * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
3 * based on a copy of HW's ip_nat_irc.c as well as other modules
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/udp.h>
15
16#include <net/netfilter/nf_conntrack_helper.h>
17#include <net/netfilter/nf_conntrack_expect.h>
18#include <net/netfilter/nf_nat_helper.h>
19#include <net/netfilter/nf_nat_rule.h>
20#include <linux/netfilter/nf_conntrack_amanda.h>
21
22MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
23MODULE_DESCRIPTION("Amanda NAT helper");
24MODULE_LICENSE("GPL");
25MODULE_ALIAS("ip_nat_amanda");
26
27static unsigned int help(struct sk_buff *skb,
28 enum ip_conntrack_info ctinfo,
29 unsigned int matchoff,
30 unsigned int matchlen,
31 struct nf_conntrack_expect *exp)
32{
33 char buffer[sizeof("65535")];
34 u_int16_t port;
35 unsigned int ret;
36
37 /* Connection comes from client. */
38 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
39 exp->dir = IP_CT_DIR_ORIGINAL;
40
41 /* When you see the packet, we need to NAT it the same as the
42 * this one (ie. same IP: it will be TCP and master is UDP). */
43 exp->expectfn = nf_nat_follow_master;
44
45 /* Try to get same port: if not, try to change it. */
46 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
47 int res;
48
49 exp->tuple.dst.u.tcp.port = htons(port);
50 res = nf_ct_expect_related(exp);
51 if (res == 0)
52 break;
53 else if (res != -EBUSY) {
54 port = 0;
55 break;
56 }
57 }
58
59 if (port == 0)
60 return NF_DROP;
61
62 sprintf(buffer, "%u", port);
63 ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
64 matchoff, matchlen,
65 buffer, strlen(buffer));
66 if (ret != NF_ACCEPT)
67 nf_ct_unexpect_related(exp);
68 return ret;
69}
70
71static void __exit nf_nat_amanda_fini(void)
72{
73 RCU_INIT_POINTER(nf_nat_amanda_hook, NULL);
74 synchronize_rcu();
75}
76
77static int __init nf_nat_amanda_init(void)
78{
79 BUG_ON(nf_nat_amanda_hook != NULL);
80 RCU_INIT_POINTER(nf_nat_amanda_hook, help);
81 return 0;
82}
83
84module_init(nf_nat_amanda_init);
85module_exit(nf_nat_amanda_fini);
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
deleted file mode 100644
index 44b082fd48ab..000000000000
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ /dev/null
@@ -1,763 +0,0 @@
1/* NAT for netfilter; shared with compatibility layer. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/timer.h>
14#include <linux/skbuff.h>
15#include <linux/gfp.h>
16#include <net/checksum.h>
17#include <net/icmp.h>
18#include <net/ip.h>
19#include <net/tcp.h> /* For tcp_prot in getorigdst */
20#include <linux/icmp.h>
21#include <linux/udp.h>
22#include <linux/jhash.h>
23
24#include <linux/netfilter_ipv4.h>
25#include <net/netfilter/nf_conntrack.h>
26#include <net/netfilter/nf_conntrack_core.h>
27#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/nf_nat_protocol.h>
29#include <net/netfilter/nf_nat_core.h>
30#include <net/netfilter/nf_nat_helper.h>
31#include <net/netfilter/nf_conntrack_helper.h>
32#include <net/netfilter/nf_conntrack_l3proto.h>
33#include <net/netfilter/nf_conntrack_zones.h>
34
35static DEFINE_SPINLOCK(nf_nat_lock);
36
37static struct nf_conntrack_l3proto *l3proto __read_mostly;
38
39#define MAX_IP_NAT_PROTO 256
40static const struct nf_nat_protocol __rcu *nf_nat_protos[MAX_IP_NAT_PROTO]
41 __read_mostly;
42
43static inline const struct nf_nat_protocol *
44__nf_nat_proto_find(u_int8_t protonum)
45{
46 return rcu_dereference(nf_nat_protos[protonum]);
47}
48
49/* We keep an extra hash for each conntrack, for fast searching. */
50static inline unsigned int
51hash_by_src(const struct net *net, u16 zone,
52 const struct nf_conntrack_tuple *tuple)
53{
54 unsigned int hash;
55
56 /* Original src, to ensure we map it consistently if poss. */
57 hash = jhash_3words((__force u32)tuple->src.u3.ip,
58 (__force u32)tuple->src.u.all ^ zone,
59 tuple->dst.protonum, nf_conntrack_hash_rnd);
60 return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
61}
62
63/* Is this tuple already taken? (not by us) */
64int
65nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
66 const struct nf_conn *ignored_conntrack)
67{
68 /* Conntrack tracking doesn't keep track of outgoing tuples; only
69 incoming ones. NAT means they don't have a fixed mapping,
70 so we invert the tuple and look for the incoming reply.
71
72 We could keep a separate hash if this proves too slow. */
73 struct nf_conntrack_tuple reply;
74
75 nf_ct_invert_tuplepr(&reply, tuple);
76 return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
77}
78EXPORT_SYMBOL(nf_nat_used_tuple);
79
80/* If we source map this tuple so reply looks like reply_tuple, will
81 * that meet the constraints of range. */
82static int
83in_range(const struct nf_conntrack_tuple *tuple,
84 const struct nf_nat_ipv4_range *range)
85{
86 const struct nf_nat_protocol *proto;
87 int ret = 0;
88
89 /* If we are supposed to map IPs, then we must be in the
90 range specified, otherwise let this drag us onto a new src IP. */
91 if (range->flags & NF_NAT_RANGE_MAP_IPS) {
92 if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) ||
93 ntohl(tuple->src.u3.ip) > ntohl(range->max_ip))
94 return 0;
95 }
96
97 rcu_read_lock();
98 proto = __nf_nat_proto_find(tuple->dst.protonum);
99 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) ||
100 proto->in_range(tuple, NF_NAT_MANIP_SRC,
101 &range->min, &range->max))
102 ret = 1;
103 rcu_read_unlock();
104
105 return ret;
106}
107
108static inline int
109same_src(const struct nf_conn *ct,
110 const struct nf_conntrack_tuple *tuple)
111{
112 const struct nf_conntrack_tuple *t;
113
114 t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
115 return (t->dst.protonum == tuple->dst.protonum &&
116 t->src.u3.ip == tuple->src.u3.ip &&
117 t->src.u.all == tuple->src.u.all);
118}
119
120/* Only called for SRC manip */
121static int
122find_appropriate_src(struct net *net, u16 zone,
123 const struct nf_conntrack_tuple *tuple,
124 struct nf_conntrack_tuple *result,
125 const struct nf_nat_ipv4_range *range)
126{
127 unsigned int h = hash_by_src(net, zone, tuple);
128 const struct nf_conn_nat *nat;
129 const struct nf_conn *ct;
130 const struct hlist_node *n;
131
132 rcu_read_lock();
133 hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
134 ct = nat->ct;
135 if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
136 /* Copy source part from reply tuple. */
137 nf_ct_invert_tuplepr(result,
138 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
139 result->dst = tuple->dst;
140
141 if (in_range(result, range)) {
142 rcu_read_unlock();
143 return 1;
144 }
145 }
146 }
147 rcu_read_unlock();
148 return 0;
149}
150
151/* For [FUTURE] fragmentation handling, we want the least-used
152 src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
153 if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
154 1-65535, we don't do pro-rata allocation based on ports; we choose
155 the ip with the lowest src-ip/dst-ip/proto usage.
156*/
157static void
158find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
159 const struct nf_nat_ipv4_range *range,
160 const struct nf_conn *ct,
161 enum nf_nat_manip_type maniptype)
162{
163 __be32 *var_ipp;
164 /* Host order */
165 u_int32_t minip, maxip, j;
166
167 /* No IP mapping? Do nothing. */
168 if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
169 return;
170
171 if (maniptype == NF_NAT_MANIP_SRC)
172 var_ipp = &tuple->src.u3.ip;
173 else
174 var_ipp = &tuple->dst.u3.ip;
175
176 /* Fast path: only one choice. */
177 if (range->min_ip == range->max_ip) {
178 *var_ipp = range->min_ip;
179 return;
180 }
181
182 /* Hashing source and destination IPs gives a fairly even
183 * spread in practice (if there are a small number of IPs
184 * involved, there usually aren't that many connections
185 * anyway). The consistency means that servers see the same
186 * client coming from the same IP (some Internet Banking sites
187 * like this), even across reboots. */
188 minip = ntohl(range->min_ip);
189 maxip = ntohl(range->max_ip);
190 j = jhash_2words((__force u32)tuple->src.u3.ip,
191 range->flags & NF_NAT_RANGE_PERSISTENT ?
192 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
193 j = ((u64)j * (maxip - minip + 1)) >> 32;
194 *var_ipp = htonl(minip + j);
195}
196
197/* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING,
198 * we change the source to map into the range. For NF_INET_PRE_ROUTING
199 * and NF_INET_LOCAL_OUT, we change the destination to map into the
200 * range. It might not be possible to get a unique tuple, but we try.
201 * At worst (or if we race), we will end up with a final duplicate in
202 * __ip_conntrack_confirm and drop the packet. */
203static void
204get_unique_tuple(struct nf_conntrack_tuple *tuple,
205 const struct nf_conntrack_tuple *orig_tuple,
206 const struct nf_nat_ipv4_range *range,
207 struct nf_conn *ct,
208 enum nf_nat_manip_type maniptype)
209{
210 struct net *net = nf_ct_net(ct);
211 const struct nf_nat_protocol *proto;
212 u16 zone = nf_ct_zone(ct);
213
214 /* 1) If this srcip/proto/src-proto-part is currently mapped,
215 and that same mapping gives a unique tuple within the given
216 range, use that.
217
218 This is only required for source (ie. NAT/masq) mappings.
219 So far, we don't do local source mappings, so multiple
220 manips not an issue. */
221 if (maniptype == NF_NAT_MANIP_SRC &&
222 !(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) {
223 /* try the original tuple first */
224 if (in_range(orig_tuple, range)) {
225 if (!nf_nat_used_tuple(orig_tuple, ct)) {
226 *tuple = *orig_tuple;
227 return;
228 }
229 } else if (find_appropriate_src(net, zone, orig_tuple, tuple,
230 range)) {
231 pr_debug("get_unique_tuple: Found current src map\n");
232 if (!nf_nat_used_tuple(tuple, ct))
233 return;
234 }
235 }
236
237 /* 2) Select the least-used IP/proto combination in the given
238 range. */
239 *tuple = *orig_tuple;
240 find_best_ips_proto(zone, tuple, range, ct, maniptype);
241
242 /* 3) The per-protocol part of the manip is made to map into
243 the range to make a unique tuple. */
244
245 rcu_read_lock();
246 proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
247
248 /* Only bother mapping if it's not already in range and unique */
249 if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM)) {
250 if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
251 if (proto->in_range(tuple, maniptype, &range->min,
252 &range->max) &&
253 (range->min.all == range->max.all ||
254 !nf_nat_used_tuple(tuple, ct)))
255 goto out;
256 } else if (!nf_nat_used_tuple(tuple, ct)) {
257 goto out;
258 }
259 }
260
261 /* Last change: get protocol to try to obtain unique tuple. */
262 proto->unique_tuple(tuple, range, maniptype, ct);
263out:
264 rcu_read_unlock();
265}
266
267unsigned int
268nf_nat_setup_info(struct nf_conn *ct,
269 const struct nf_nat_ipv4_range *range,
270 enum nf_nat_manip_type maniptype)
271{
272 struct net *net = nf_ct_net(ct);
273 struct nf_conntrack_tuple curr_tuple, new_tuple;
274 struct nf_conn_nat *nat;
275
276 /* nat helper or nfctnetlink also setup binding */
277 nat = nfct_nat(ct);
278 if (!nat) {
279 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
280 if (nat == NULL) {
281 pr_debug("failed to add NAT extension\n");
282 return NF_ACCEPT;
283 }
284 }
285
286 NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC ||
287 maniptype == NF_NAT_MANIP_DST);
288 BUG_ON(nf_nat_initialized(ct, maniptype));
289
290 /* What we've got will look like inverse of reply. Normally
291 this is what is in the conntrack, except for prior
292 manipulations (future optimization: if num_manips == 0,
293 orig_tp =
294 conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
295 nf_ct_invert_tuplepr(&curr_tuple,
296 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
297
298 get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
299
300 if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
301 struct nf_conntrack_tuple reply;
302
303 /* Alter conntrack table so will recognize replies. */
304 nf_ct_invert_tuplepr(&reply, &new_tuple);
305 nf_conntrack_alter_reply(ct, &reply);
306
307 /* Non-atomic: we own this at the moment. */
308 if (maniptype == NF_NAT_MANIP_SRC)
309 ct->status |= IPS_SRC_NAT;
310 else
311 ct->status |= IPS_DST_NAT;
312 }
313
314 if (maniptype == NF_NAT_MANIP_SRC) {
315 unsigned int srchash;
316
317 srchash = hash_by_src(net, nf_ct_zone(ct),
318 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
319 spin_lock_bh(&nf_nat_lock);
320 /* nf_conntrack_alter_reply might re-allocate extension area */
321 nat = nfct_nat(ct);
322 nat->ct = ct;
323 hlist_add_head_rcu(&nat->bysource,
324 &net->ipv4.nat_bysource[srchash]);
325 spin_unlock_bh(&nf_nat_lock);
326 }
327
328 /* It's done. */
329 if (maniptype == NF_NAT_MANIP_DST)
330 ct->status |= IPS_DST_NAT_DONE;
331 else
332 ct->status |= IPS_SRC_NAT_DONE;
333
334 return NF_ACCEPT;
335}
336EXPORT_SYMBOL(nf_nat_setup_info);
337
338/* Returns true if succeeded. */
339static bool
340manip_pkt(u_int16_t proto,
341 struct sk_buff *skb,
342 unsigned int iphdroff,
343 const struct nf_conntrack_tuple *target,
344 enum nf_nat_manip_type maniptype)
345{
346 struct iphdr *iph;
347 const struct nf_nat_protocol *p;
348
349 if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
350 return false;
351
352 iph = (void *)skb->data + iphdroff;
353
354 /* Manipulate protcol part. */
355
356 /* rcu_read_lock()ed by nf_hook_slow */
357 p = __nf_nat_proto_find(proto);
358 if (!p->manip_pkt(skb, iphdroff, target, maniptype))
359 return false;
360
361 iph = (void *)skb->data + iphdroff;
362
363 if (maniptype == NF_NAT_MANIP_SRC) {
364 csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
365 iph->saddr = target->src.u3.ip;
366 } else {
367 csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
368 iph->daddr = target->dst.u3.ip;
369 }
370 return true;
371}
372
373/* Do packet manipulations according to nf_nat_setup_info. */
374unsigned int nf_nat_packet(struct nf_conn *ct,
375 enum ip_conntrack_info ctinfo,
376 unsigned int hooknum,
377 struct sk_buff *skb)
378{
379 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
380 unsigned long statusbit;
381 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);
382
383 if (mtype == NF_NAT_MANIP_SRC)
384 statusbit = IPS_SRC_NAT;
385 else
386 statusbit = IPS_DST_NAT;
387
388 /* Invert if this is reply dir. */
389 if (dir == IP_CT_DIR_REPLY)
390 statusbit ^= IPS_NAT_MASK;
391
392 /* Non-atomic: these bits don't change. */
393 if (ct->status & statusbit) {
394 struct nf_conntrack_tuple target;
395
396 /* We are aiming to look like inverse of other direction. */
397 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
398
399 if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype))
400 return NF_DROP;
401 }
402 return NF_ACCEPT;
403}
404EXPORT_SYMBOL_GPL(nf_nat_packet);
405
406/* Dir is direction ICMP is coming from (opposite to packet it contains) */
407int nf_nat_icmp_reply_translation(struct nf_conn *ct,
408 enum ip_conntrack_info ctinfo,
409 unsigned int hooknum,
410 struct sk_buff *skb)
411{
412 struct {
413 struct icmphdr icmp;
414 struct iphdr ip;
415 } *inside;
416 struct nf_conntrack_tuple target;
417 int hdrlen = ip_hdrlen(skb);
418 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
419 unsigned long statusbit;
420 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
421
422 if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
423 return 0;
424
425 inside = (void *)skb->data + hdrlen;
426
427 /* We're actually going to mangle it beyond trivial checksum
428 adjustment, so make sure the current checksum is correct. */
429 if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
430 return 0;
431
432 /* Must be RELATED */
433 NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED ||
434 skb->nfctinfo == IP_CT_RELATED_REPLY);
435
436 /* Redirects on non-null nats must be dropped, else they'll
437 start talking to each other without our translation, and be
438 confused... --RR */
439 if (inside->icmp.type == ICMP_REDIRECT) {
440 /* If NAT isn't finished, assume it and drop. */
441 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
442 return 0;
443
444 if (ct->status & IPS_NAT_MASK)
445 return 0;
446 }
447
448 if (manip == NF_NAT_MANIP_SRC)
449 statusbit = IPS_SRC_NAT;
450 else
451 statusbit = IPS_DST_NAT;
452
453 /* Invert if this is reply dir. */
454 if (dir == IP_CT_DIR_REPLY)
455 statusbit ^= IPS_NAT_MASK;
456
457 if (!(ct->status & statusbit))
458 return 1;
459
460 pr_debug("icmp_reply_translation: translating error %p manip %u "
461 "dir %s\n", skb, manip,
462 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
463
464 /* Change inner back to look like incoming packet. We do the
465 opposite manip on this hook to normal, because it might not
466 pass all hooks (locally-generated ICMP). Consider incoming
467 packet: PREROUTING (DST manip), routing produces ICMP, goes
468 through POSTROUTING (which must correct the DST manip). */
469 if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp),
470 &ct->tuplehash[!dir].tuple, !manip))
471 return 0;
472
473 if (skb->ip_summed != CHECKSUM_PARTIAL) {
474 /* Reloading "inside" here since manip_pkt inner. */
475 inside = (void *)skb->data + hdrlen;
476 inside->icmp.checksum = 0;
477 inside->icmp.checksum =
478 csum_fold(skb_checksum(skb, hdrlen,
479 skb->len - hdrlen, 0));
480 }
481
482 /* Change outer to look the reply to an incoming packet
483 * (proto 0 means don't invert per-proto part). */
484 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
485 if (!manip_pkt(0, skb, 0, &target, manip))
486 return 0;
487
488 return 1;
489}
490EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
491
492/* Protocol registration. */
493int nf_nat_protocol_register(const struct nf_nat_protocol *proto)
494{
495 int ret = 0;
496
497 spin_lock_bh(&nf_nat_lock);
498 if (rcu_dereference_protected(
499 nf_nat_protos[proto->protonum],
500 lockdep_is_held(&nf_nat_lock)
501 ) != &nf_nat_unknown_protocol) {
502 ret = -EBUSY;
503 goto out;
504 }
505 RCU_INIT_POINTER(nf_nat_protos[proto->protonum], proto);
506 out:
507 spin_unlock_bh(&nf_nat_lock);
508 return ret;
509}
510EXPORT_SYMBOL(nf_nat_protocol_register);
511
512/* No one stores the protocol anywhere; simply delete it. */
513void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
514{
515 spin_lock_bh(&nf_nat_lock);
516 RCU_INIT_POINTER(nf_nat_protos[proto->protonum],
517 &nf_nat_unknown_protocol);
518 spin_unlock_bh(&nf_nat_lock);
519 synchronize_rcu();
520}
521EXPORT_SYMBOL(nf_nat_protocol_unregister);
522
523/* No one using conntrack by the time this called. */
524static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
525{
526 struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
527
528 if (nat == NULL || nat->ct == NULL)
529 return;
530
531 NF_CT_ASSERT(nat->ct->status & IPS_SRC_NAT_DONE);
532
533 spin_lock_bh(&nf_nat_lock);
534 hlist_del_rcu(&nat->bysource);
535 spin_unlock_bh(&nf_nat_lock);
536}
537
538static void nf_nat_move_storage(void *new, void *old)
539{
540 struct nf_conn_nat *new_nat = new;
541 struct nf_conn_nat *old_nat = old;
542 struct nf_conn *ct = old_nat->ct;
543
544 if (!ct || !(ct->status & IPS_SRC_NAT_DONE))
545 return;
546
547 spin_lock_bh(&nf_nat_lock);
548 hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
549 spin_unlock_bh(&nf_nat_lock);
550}
551
552static struct nf_ct_ext_type nat_extend __read_mostly = {
553 .len = sizeof(struct nf_conn_nat),
554 .align = __alignof__(struct nf_conn_nat),
555 .destroy = nf_nat_cleanup_conntrack,
556 .move = nf_nat_move_storage,
557 .id = NF_CT_EXT_NAT,
558 .flags = NF_CT_EXT_F_PREALLOC,
559};
560
561#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
562
563#include <linux/netfilter/nfnetlink.h>
564#include <linux/netfilter/nfnetlink_conntrack.h>
565
566static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
567 [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
568 [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
569};
570
571static int nfnetlink_parse_nat_proto(struct nlattr *attr,
572 const struct nf_conn *ct,
573 struct nf_nat_ipv4_range *range)
574{
575 struct nlattr *tb[CTA_PROTONAT_MAX+1];
576 const struct nf_nat_protocol *npt;
577 int err;
578
579 err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
580 if (err < 0)
581 return err;
582
583 rcu_read_lock();
584 npt = __nf_nat_proto_find(nf_ct_protonum(ct));
585 if (npt->nlattr_to_range)
586 err = npt->nlattr_to_range(tb, range);
587 rcu_read_unlock();
588 return err;
589}
590
591static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
592 [CTA_NAT_MINIP] = { .type = NLA_U32 },
593 [CTA_NAT_MAXIP] = { .type = NLA_U32 },
594 [CTA_NAT_PROTO] = { .type = NLA_NESTED },
595};
596
597static int
598nfnetlink_parse_nat(const struct nlattr *nat,
599 const struct nf_conn *ct, struct nf_nat_ipv4_range *range)
600{
601 struct nlattr *tb[CTA_NAT_MAX+1];
602 int err;
603
604 memset(range, 0, sizeof(*range));
605
606 err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
607 if (err < 0)
608 return err;
609
610 if (tb[CTA_NAT_MINIP])
611 range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
612
613 if (!tb[CTA_NAT_MAXIP])
614 range->max_ip = range->min_ip;
615 else
616 range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
617
618 if (range->min_ip)
619 range->flags |= NF_NAT_RANGE_MAP_IPS;
620
621 if (!tb[CTA_NAT_PROTO])
622 return 0;
623
624 err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
625 if (err < 0)
626 return err;
627
628 return 0;
629}
630
631static int
632nfnetlink_parse_nat_setup(struct nf_conn *ct,
633 enum nf_nat_manip_type manip,
634 const struct nlattr *attr)
635{
636 struct nf_nat_ipv4_range range;
637
638 if (nfnetlink_parse_nat(attr, ct, &range) < 0)
639 return -EINVAL;
640 if (nf_nat_initialized(ct, manip))
641 return -EEXIST;
642
643 return nf_nat_setup_info(ct, &range, manip);
644}
645#else
646static int
647nfnetlink_parse_nat_setup(struct nf_conn *ct,
648 enum nf_nat_manip_type manip,
649 const struct nlattr *attr)
650{
651 return -EOPNOTSUPP;
652}
653#endif
654
655static int __net_init nf_nat_net_init(struct net *net)
656{
657 /* Leave them the same for the moment. */
658 net->ipv4.nat_htable_size = net->ct.htable_size;
659 net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&net->ipv4.nat_htable_size, 0);
660 if (!net->ipv4.nat_bysource)
661 return -ENOMEM;
662 return 0;
663}
664
665/* Clear NAT section of all conntracks, in case we're loaded again. */
666static int clean_nat(struct nf_conn *i, void *data)
667{
668 struct nf_conn_nat *nat = nfct_nat(i);
669
670 if (!nat)
671 return 0;
672 memset(nat, 0, sizeof(*nat));
673 i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
674 return 0;
675}
676
677static void __net_exit nf_nat_net_exit(struct net *net)
678{
679 nf_ct_iterate_cleanup(net, &clean_nat, NULL);
680 synchronize_rcu();
681 nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_htable_size);
682}
683
684static struct pernet_operations nf_nat_net_ops = {
685 .init = nf_nat_net_init,
686 .exit = nf_nat_net_exit,
687};
688
689static struct nf_ct_helper_expectfn follow_master_nat = {
690 .name = "nat-follow-master",
691 .expectfn = nf_nat_follow_master,
692};
693
694static struct nfq_ct_nat_hook nfq_ct_nat = {
695 .seq_adjust = nf_nat_tcp_seq_adjust,
696};
697
698static int __init nf_nat_init(void)
699{
700 size_t i;
701 int ret;
702
703 need_ipv4_conntrack();
704
705 ret = nf_ct_extend_register(&nat_extend);
706 if (ret < 0) {
707 printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
708 return ret;
709 }
710
711 ret = register_pernet_subsys(&nf_nat_net_ops);
712 if (ret < 0)
713 goto cleanup_extend;
714
715 /* Sew in builtin protocols. */
716 spin_lock_bh(&nf_nat_lock);
717 for (i = 0; i < MAX_IP_NAT_PROTO; i++)
718 RCU_INIT_POINTER(nf_nat_protos[i], &nf_nat_unknown_protocol);
719 RCU_INIT_POINTER(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
720 RCU_INIT_POINTER(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
721 RCU_INIT_POINTER(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
722 spin_unlock_bh(&nf_nat_lock);
723
724 /* Initialize fake conntrack so that NAT will skip it */
725 nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
726
727 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
728
729 nf_ct_helper_expectfn_register(&follow_master_nat);
730
731 BUG_ON(nf_nat_seq_adjust_hook != NULL);
732 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
733 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
734 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook,
735 nfnetlink_parse_nat_setup);
736 BUG_ON(nf_ct_nat_offset != NULL);
737 RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset);
738 RCU_INIT_POINTER(nfq_ct_nat_hook, &nfq_ct_nat);
739 return 0;
740
741 cleanup_extend:
742 nf_ct_extend_unregister(&nat_extend);
743 return ret;
744}
745
746static void __exit nf_nat_cleanup(void)
747{
748 unregister_pernet_subsys(&nf_nat_net_ops);
749 nf_ct_l3proto_put(l3proto);
750 nf_ct_extend_unregister(&nat_extend);
751 nf_ct_helper_expectfn_unregister(&follow_master_nat);
752 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL);
753 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
754 RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
755 RCU_INIT_POINTER(nfq_ct_nat_hook, NULL);
756 synchronize_net();
757}
758
759MODULE_LICENSE("GPL");
760MODULE_ALIAS("nf-nat-ipv4");
761
762module_init(nf_nat_init);
763module_exit(nf_nat_cleanup);
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
deleted file mode 100644
index e462a957d080..000000000000
--- a/net/ipv4/netfilter/nf_nat_ftp.c
+++ /dev/null
@@ -1,137 +0,0 @@
1/* FTP extension for TCP NAT alteration. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/ip.h>
14#include <linux/tcp.h>
15#include <linux/netfilter_ipv4.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_conntrack_helper.h>
20#include <net/netfilter/nf_conntrack_expect.h>
21#include <linux/netfilter/nf_conntrack_ftp.h>
22
23MODULE_LICENSE("GPL");
24MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
25MODULE_DESCRIPTION("ftp NAT helper");
26MODULE_ALIAS("ip_nat_ftp");
27
28/* FIXME: Time out? --RR */
29
30static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
31 char *buffer, size_t buflen,
32 __be32 addr, u16 port)
33{
34 switch (type) {
35 case NF_CT_FTP_PORT:
36 case NF_CT_FTP_PASV:
37 return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u",
38 ((unsigned char *)&addr)[0],
39 ((unsigned char *)&addr)[1],
40 ((unsigned char *)&addr)[2],
41 ((unsigned char *)&addr)[3],
42 port >> 8,
43 port & 0xFF);
44 case NF_CT_FTP_EPRT:
45 return snprintf(buffer, buflen, "|1|%pI4|%u|", &addr, port);
46 case NF_CT_FTP_EPSV:
47 return snprintf(buffer, buflen, "|||%u|", port);
48 }
49
50 return 0;
51}
52
53/* So, this packet has hit the connection tracking matching code.
54 Mangle it, and change the expectation to match the new version. */
55static unsigned int nf_nat_ftp(struct sk_buff *skb,
56 enum ip_conntrack_info ctinfo,
57 enum nf_ct_ftp_type type,
58 unsigned int matchoff,
59 unsigned int matchlen,
60 struct nf_conntrack_expect *exp)
61{
62 __be32 newip;
63 u_int16_t port;
64 int dir = CTINFO2DIR(ctinfo);
65 struct nf_conn *ct = exp->master;
66 char buffer[sizeof("|1|255.255.255.255|65535|")];
67 unsigned int buflen;
68
69 pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
70
71 /* Connection will come from wherever this packet goes, hence !dir */
72 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
73 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
74 exp->dir = !dir;
75
76 /* When you see the packet, we need to NAT it the same as the
77 * this one. */
78 exp->expectfn = nf_nat_follow_master;
79
80 /* Try to get same port: if not, try to change it. */
81 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
82 int ret;
83
84 exp->tuple.dst.u.tcp.port = htons(port);
85 ret = nf_ct_expect_related(exp);
86 if (ret == 0)
87 break;
88 else if (ret != -EBUSY) {
89 port = 0;
90 break;
91 }
92 }
93
94 if (port == 0)
95 return NF_DROP;
96
97 buflen = nf_nat_ftp_fmt_cmd(type, buffer, sizeof(buffer), newip, port);
98 if (!buflen)
99 goto out;
100
101 pr_debug("calling nf_nat_mangle_tcp_packet\n");
102
103 if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
104 matchlen, buffer, buflen))
105 goto out;
106
107 return NF_ACCEPT;
108
109out:
110 nf_ct_unexpect_related(exp);
111 return NF_DROP;
112}
113
114static void __exit nf_nat_ftp_fini(void)
115{
116 RCU_INIT_POINTER(nf_nat_ftp_hook, NULL);
117 synchronize_rcu();
118}
119
120static int __init nf_nat_ftp_init(void)
121{
122 BUG_ON(nf_nat_ftp_hook != NULL);
123 RCU_INIT_POINTER(nf_nat_ftp_hook, nf_nat_ftp);
124 return 0;
125}
126
127/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
128static int warn_set(const char *val, struct kernel_param *kp)
129{
130 printk(KERN_INFO KBUILD_MODNAME
131 ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
132 return 0;
133}
134module_param_call(ports, warn_set, NULL, NULL, 0);
135
136module_init(nf_nat_ftp_init);
137module_exit(nf_nat_ftp_fini);
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index c6784a18c1c4..9c3db10b22d3 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -15,13 +15,12 @@
15 15
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.h> 17#include <net/netfilter/nf_nat_helper.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_conntrack_helper.h> 18#include <net/netfilter/nf_conntrack_helper.h>
20#include <net/netfilter/nf_conntrack_expect.h> 19#include <net/netfilter/nf_conntrack_expect.h>
21#include <linux/netfilter/nf_conntrack_h323.h> 20#include <linux/netfilter/nf_conntrack_h323.h>
22 21
23/****************************************************************************/ 22/****************************************************************************/
24static int set_addr(struct sk_buff *skb, 23static int set_addr(struct sk_buff *skb, unsigned int protoff,
25 unsigned char **data, int dataoff, 24 unsigned char **data, int dataoff,
26 unsigned int addroff, __be32 ip, __be16 port) 25 unsigned int addroff, __be32 ip, __be16 port)
27{ 26{
@@ -40,7 +39,7 @@ static int set_addr(struct sk_buff *skb,
40 39
41 if (ip_hdr(skb)->protocol == IPPROTO_TCP) { 40 if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
42 if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 41 if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
43 addroff, sizeof(buf), 42 protoff, addroff, sizeof(buf),
44 (char *) &buf, sizeof(buf))) { 43 (char *) &buf, sizeof(buf))) {
45 net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_tcp_packet error\n"); 44 net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_tcp_packet error\n");
46 return -1; 45 return -1;
@@ -54,7 +53,7 @@ static int set_addr(struct sk_buff *skb,
54 *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff; 53 *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
55 } else { 54 } else {
56 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, 55 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
57 addroff, sizeof(buf), 56 protoff, addroff, sizeof(buf),
58 (char *) &buf, sizeof(buf))) { 57 (char *) &buf, sizeof(buf))) {
59 net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_udp_packet error\n"); 58 net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_udp_packet error\n");
60 return -1; 59 return -1;
@@ -69,22 +68,22 @@ static int set_addr(struct sk_buff *skb,
69} 68}
70 69
71/****************************************************************************/ 70/****************************************************************************/
72static int set_h225_addr(struct sk_buff *skb, 71static int set_h225_addr(struct sk_buff *skb, unsigned int protoff,
73 unsigned char **data, int dataoff, 72 unsigned char **data, int dataoff,
74 TransportAddress *taddr, 73 TransportAddress *taddr,
75 union nf_inet_addr *addr, __be16 port) 74 union nf_inet_addr *addr, __be16 port)
76{ 75{
77 return set_addr(skb, data, dataoff, taddr->ipAddress.ip, 76 return set_addr(skb, protoff, data, dataoff, taddr->ipAddress.ip,
78 addr->ip, port); 77 addr->ip, port);
79} 78}
80 79
81/****************************************************************************/ 80/****************************************************************************/
82static int set_h245_addr(struct sk_buff *skb, 81static int set_h245_addr(struct sk_buff *skb, unsigned protoff,
83 unsigned char **data, int dataoff, 82 unsigned char **data, int dataoff,
84 H245_TransportAddress *taddr, 83 H245_TransportAddress *taddr,
85 union nf_inet_addr *addr, __be16 port) 84 union nf_inet_addr *addr, __be16 port)
86{ 85{
87 return set_addr(skb, data, dataoff, 86 return set_addr(skb, protoff, data, dataoff,
88 taddr->unicastAddress.iPAddress.network, 87 taddr->unicastAddress.iPAddress.network,
89 addr->ip, port); 88 addr->ip, port);
90} 89}
@@ -92,7 +91,7 @@ static int set_h245_addr(struct sk_buff *skb,
92/****************************************************************************/ 91/****************************************************************************/
93static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, 92static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
94 enum ip_conntrack_info ctinfo, 93 enum ip_conntrack_info ctinfo,
95 unsigned char **data, 94 unsigned int protoff, unsigned char **data,
96 TransportAddress *taddr, int count) 95 TransportAddress *taddr, int count)
97{ 96{
98 const struct nf_ct_h323_master *info = nfct_help_data(ct); 97 const struct nf_ct_h323_master *info = nfct_help_data(ct);
@@ -118,7 +117,8 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
118 &addr.ip, port, 117 &addr.ip, port,
119 &ct->tuplehash[!dir].tuple.dst.u3.ip, 118 &ct->tuplehash[!dir].tuple.dst.u3.ip,
120 info->sig_port[!dir]); 119 info->sig_port[!dir]);
121 return set_h225_addr(skb, data, 0, &taddr[i], 120 return set_h225_addr(skb, protoff, data, 0,
121 &taddr[i],
122 &ct->tuplehash[!dir]. 122 &ct->tuplehash[!dir].
123 tuple.dst.u3, 123 tuple.dst.u3,
124 info->sig_port[!dir]); 124 info->sig_port[!dir]);
@@ -129,7 +129,8 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
129 &addr.ip, port, 129 &addr.ip, port,
130 &ct->tuplehash[!dir].tuple.src.u3.ip, 130 &ct->tuplehash[!dir].tuple.src.u3.ip,
131 info->sig_port[!dir]); 131 info->sig_port[!dir]);
132 return set_h225_addr(skb, data, 0, &taddr[i], 132 return set_h225_addr(skb, protoff, data, 0,
133 &taddr[i],
133 &ct->tuplehash[!dir]. 134 &ct->tuplehash[!dir].
134 tuple.src.u3, 135 tuple.src.u3,
135 info->sig_port[!dir]); 136 info->sig_port[!dir]);
@@ -143,7 +144,7 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
143/****************************************************************************/ 144/****************************************************************************/
144static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct, 145static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
145 enum ip_conntrack_info ctinfo, 146 enum ip_conntrack_info ctinfo,
146 unsigned char **data, 147 unsigned int protoff, unsigned char **data,
147 TransportAddress *taddr, int count) 148 TransportAddress *taddr, int count)
148{ 149{
149 int dir = CTINFO2DIR(ctinfo); 150 int dir = CTINFO2DIR(ctinfo);
@@ -159,7 +160,7 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
159 &addr.ip, ntohs(port), 160 &addr.ip, ntohs(port),
160 &ct->tuplehash[!dir].tuple.dst.u3.ip, 161 &ct->tuplehash[!dir].tuple.dst.u3.ip,
161 ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port)); 162 ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port));
162 return set_h225_addr(skb, data, 0, &taddr[i], 163 return set_h225_addr(skb, protoff, data, 0, &taddr[i],
163 &ct->tuplehash[!dir].tuple.dst.u3, 164 &ct->tuplehash[!dir].tuple.dst.u3,
164 ct->tuplehash[!dir].tuple. 165 ct->tuplehash[!dir].tuple.
165 dst.u.udp.port); 166 dst.u.udp.port);
@@ -172,7 +173,7 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
172/****************************************************************************/ 173/****************************************************************************/
173static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, 174static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
174 enum ip_conntrack_info ctinfo, 175 enum ip_conntrack_info ctinfo,
175 unsigned char **data, int dataoff, 176 unsigned int protoff, unsigned char **data, int dataoff,
176 H245_TransportAddress *taddr, 177 H245_TransportAddress *taddr,
177 __be16 port, __be16 rtp_port, 178 __be16 port, __be16 rtp_port,
178 struct nf_conntrack_expect *rtp_exp, 179 struct nf_conntrack_expect *rtp_exp,
@@ -244,7 +245,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
244 } 245 }
245 246
246 /* Modify signal */ 247 /* Modify signal */
247 if (set_h245_addr(skb, data, dataoff, taddr, 248 if (set_h245_addr(skb, protoff, data, dataoff, taddr,
248 &ct->tuplehash[!dir].tuple.dst.u3, 249 &ct->tuplehash[!dir].tuple.dst.u3,
249 htons((port & htons(1)) ? nated_port + 1 : 250 htons((port & htons(1)) ? nated_port + 1 :
250 nated_port)) == 0) { 251 nated_port)) == 0) {
@@ -275,7 +276,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
275/****************************************************************************/ 276/****************************************************************************/
276static int nat_t120(struct sk_buff *skb, struct nf_conn *ct, 277static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
277 enum ip_conntrack_info ctinfo, 278 enum ip_conntrack_info ctinfo,
278 unsigned char **data, int dataoff, 279 unsigned int protoff, unsigned char **data, int dataoff,
279 H245_TransportAddress *taddr, __be16 port, 280 H245_TransportAddress *taddr, __be16 port,
280 struct nf_conntrack_expect *exp) 281 struct nf_conntrack_expect *exp)
281{ 282{
@@ -307,7 +308,7 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
307 } 308 }
308 309
309 /* Modify signal */ 310 /* Modify signal */
310 if (set_h245_addr(skb, data, dataoff, taddr, 311 if (set_h245_addr(skb, protoff, data, dataoff, taddr,
311 &ct->tuplehash[!dir].tuple.dst.u3, 312 &ct->tuplehash[!dir].tuple.dst.u3,
312 htons(nated_port)) < 0) { 313 htons(nated_port)) < 0) {
313 nf_ct_unexpect_related(exp); 314 nf_ct_unexpect_related(exp);
@@ -326,7 +327,7 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
326/****************************************************************************/ 327/****************************************************************************/
327static int nat_h245(struct sk_buff *skb, struct nf_conn *ct, 328static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
328 enum ip_conntrack_info ctinfo, 329 enum ip_conntrack_info ctinfo,
329 unsigned char **data, int dataoff, 330 unsigned int protoff, unsigned char **data, int dataoff,
330 TransportAddress *taddr, __be16 port, 331 TransportAddress *taddr, __be16 port,
331 struct nf_conntrack_expect *exp) 332 struct nf_conntrack_expect *exp)
332{ 333{
@@ -363,7 +364,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
363 } 364 }
364 365
365 /* Modify signal */ 366 /* Modify signal */
366 if (set_h225_addr(skb, data, dataoff, taddr, 367 if (set_h225_addr(skb, protoff, data, dataoff, taddr,
367 &ct->tuplehash[!dir].tuple.dst.u3, 368 &ct->tuplehash[!dir].tuple.dst.u3,
368 htons(nated_port)) == 0) { 369 htons(nated_port)) == 0) {
369 /* Save ports */ 370 /* Save ports */
@@ -390,7 +391,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
390static void ip_nat_q931_expect(struct nf_conn *new, 391static void ip_nat_q931_expect(struct nf_conn *new,
391 struct nf_conntrack_expect *this) 392 struct nf_conntrack_expect *this)
392{ 393{
393 struct nf_nat_ipv4_range range; 394 struct nf_nat_range range;
394 395
395 if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ 396 if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */
396 nf_nat_follow_master(new, this); 397 nf_nat_follow_master(new, this);
@@ -402,21 +403,23 @@ static void ip_nat_q931_expect(struct nf_conn *new,
402 403
403 /* Change src to where master sends to */ 404 /* Change src to where master sends to */
404 range.flags = NF_NAT_RANGE_MAP_IPS; 405 range.flags = NF_NAT_RANGE_MAP_IPS;
405 range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; 406 range.min_addr = range.max_addr =
407 new->tuplehash[!this->dir].tuple.src.u3;
406 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC); 408 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
407 409
408 /* For DST manip, map port here to where it's expected. */ 410 /* For DST manip, map port here to where it's expected. */
409 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 411 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
410 range.min = range.max = this->saved_proto; 412 range.min_proto = range.max_proto = this->saved_proto;
411 range.min_ip = range.max_ip = 413 range.min_addr = range.max_addr =
412 new->master->tuplehash[!this->dir].tuple.src.u3.ip; 414 new->master->tuplehash[!this->dir].tuple.src.u3;
413 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST); 415 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
414} 416}
415 417
416/****************************************************************************/ 418/****************************************************************************/
417static int nat_q931(struct sk_buff *skb, struct nf_conn *ct, 419static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
418 enum ip_conntrack_info ctinfo, 420 enum ip_conntrack_info ctinfo,
419 unsigned char **data, TransportAddress *taddr, int idx, 421 unsigned int protoff, unsigned char **data,
422 TransportAddress *taddr, int idx,
420 __be16 port, struct nf_conntrack_expect *exp) 423 __be16 port, struct nf_conntrack_expect *exp)
421{ 424{
422 struct nf_ct_h323_master *info = nfct_help_data(ct); 425 struct nf_ct_h323_master *info = nfct_help_data(ct);
@@ -453,7 +456,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
453 } 456 }
454 457
455 /* Modify signal */ 458 /* Modify signal */
456 if (set_h225_addr(skb, data, 0, &taddr[idx], 459 if (set_h225_addr(skb, protoff, data, 0, &taddr[idx],
457 &ct->tuplehash[!dir].tuple.dst.u3, 460 &ct->tuplehash[!dir].tuple.dst.u3,
458 htons(nated_port)) == 0) { 461 htons(nated_port)) == 0) {
459 /* Save ports */ 462 /* Save ports */
@@ -464,7 +467,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
464 if (idx > 0 && 467 if (idx > 0 &&
465 get_h225_addr(ct, *data, &taddr[0], &addr, &port) && 468 get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
466 (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { 469 (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
467 set_h225_addr(skb, data, 0, &taddr[0], 470 set_h225_addr(skb, protoff, data, 0, &taddr[0],
468 &ct->tuplehash[!dir].tuple.dst.u3, 471 &ct->tuplehash[!dir].tuple.dst.u3,
469 info->sig_port[!dir]); 472 info->sig_port[!dir]);
470 } 473 }
@@ -487,26 +490,28 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
487static void ip_nat_callforwarding_expect(struct nf_conn *new, 490static void ip_nat_callforwarding_expect(struct nf_conn *new,
488 struct nf_conntrack_expect *this) 491 struct nf_conntrack_expect *this)
489{ 492{
490 struct nf_nat_ipv4_range range; 493 struct nf_nat_range range;
491 494
492 /* This must be a fresh one. */ 495 /* This must be a fresh one. */
493 BUG_ON(new->status & IPS_NAT_DONE_MASK); 496 BUG_ON(new->status & IPS_NAT_DONE_MASK);
494 497
495 /* Change src to where master sends to */ 498 /* Change src to where master sends to */
496 range.flags = NF_NAT_RANGE_MAP_IPS; 499 range.flags = NF_NAT_RANGE_MAP_IPS;
497 range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; 500 range.min_addr = range.max_addr =
501 new->tuplehash[!this->dir].tuple.src.u3;
498 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC); 502 nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
499 503
500 /* For DST manip, map port here to where it's expected. */ 504 /* For DST manip, map port here to where it's expected. */
501 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 505 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
502 range.min = range.max = this->saved_proto; 506 range.min_proto = range.max_proto = this->saved_proto;
503 range.min_ip = range.max_ip = this->saved_ip; 507 range.min_addr = range.max_addr = this->saved_addr;
504 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST); 508 nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
505} 509}
506 510
507/****************************************************************************/ 511/****************************************************************************/
508static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, 512static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
509 enum ip_conntrack_info ctinfo, 513 enum ip_conntrack_info ctinfo,
514 unsigned int protoff,
510 unsigned char **data, int dataoff, 515 unsigned char **data, int dataoff,
511 TransportAddress *taddr, __be16 port, 516 TransportAddress *taddr, __be16 port,
512 struct nf_conntrack_expect *exp) 517 struct nf_conntrack_expect *exp)
@@ -515,7 +520,7 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
515 u_int16_t nated_port; 520 u_int16_t nated_port;
516 521
517 /* Set expectations for NAT */ 522 /* Set expectations for NAT */
518 exp->saved_ip = exp->tuple.dst.u3.ip; 523 exp->saved_addr = exp->tuple.dst.u3;
519 exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; 524 exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
520 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; 525 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
521 exp->expectfn = ip_nat_callforwarding_expect; 526 exp->expectfn = ip_nat_callforwarding_expect;
@@ -541,7 +546,7 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
541 } 546 }
542 547
543 /* Modify signal */ 548 /* Modify signal */
544 if (!set_h225_addr(skb, data, dataoff, taddr, 549 if (!set_h225_addr(skb, protoff, data, dataoff, taddr,
545 &ct->tuplehash[!dir].tuple.dst.u3, 550 &ct->tuplehash[!dir].tuple.dst.u3,
546 htons(nated_port)) == 0) { 551 htons(nated_port)) == 0) {
547 nf_ct_unexpect_related(exp); 552 nf_ct_unexpect_related(exp);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
deleted file mode 100644
index 2e59ad0b90ca..000000000000
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ /dev/null
@@ -1,458 +0,0 @@
1/* ip_nat_helper.c - generic support functions for NAT helpers
2 *
3 * (C) 2000-2002 Harald Welte <laforge@netfilter.org>
4 * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/gfp.h>
12#include <linux/kmod.h>
13#include <linux/types.h>
14#include <linux/timer.h>
15#include <linux/skbuff.h>
16#include <linux/tcp.h>
17#include <linux/udp.h>
18#include <net/checksum.h>
19#include <net/tcp.h>
20#include <net/route.h>
21
22#include <linux/netfilter_ipv4.h>
23#include <net/netfilter/nf_conntrack.h>
24#include <net/netfilter/nf_conntrack_helper.h>
25#include <net/netfilter/nf_conntrack_ecache.h>
26#include <net/netfilter/nf_conntrack_expect.h>
27#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/nf_nat_protocol.h>
29#include <net/netfilter/nf_nat_core.h>
30#include <net/netfilter/nf_nat_helper.h>
31
32#define DUMP_OFFSET(x) \
33 pr_debug("offset_before=%d, offset_after=%d, correction_pos=%u\n", \
34 x->offset_before, x->offset_after, x->correction_pos);
35
36static DEFINE_SPINLOCK(nf_nat_seqofs_lock);
37
38/* Setup TCP sequence correction given this change at this sequence */
39static inline void
40adjust_tcp_sequence(u32 seq,
41 int sizediff,
42 struct nf_conn *ct,
43 enum ip_conntrack_info ctinfo)
44{
45 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
46 struct nf_conn_nat *nat = nfct_nat(ct);
47 struct nf_nat_seq *this_way = &nat->seq[dir];
48
49 pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
50 seq, sizediff);
51
52 pr_debug("adjust_tcp_sequence: Seq_offset before: ");
53 DUMP_OFFSET(this_way);
54
55 spin_lock_bh(&nf_nat_seqofs_lock);
56
57 /* SYN adjust. If it's uninitialized, or this is after last
58 * correction, record it: we don't handle more than one
59 * adjustment in the window, but do deal with common case of a
60 * retransmit */
61 if (this_way->offset_before == this_way->offset_after ||
62 before(this_way->correction_pos, seq)) {
63 this_way->correction_pos = seq;
64 this_way->offset_before = this_way->offset_after;
65 this_way->offset_after += sizediff;
66 }
67 spin_unlock_bh(&nf_nat_seqofs_lock);
68
69 pr_debug("adjust_tcp_sequence: Seq_offset after: ");
70 DUMP_OFFSET(this_way);
71}
72
73/* Get the offset value, for conntrack */
74s16 nf_nat_get_offset(const struct nf_conn *ct,
75 enum ip_conntrack_dir dir,
76 u32 seq)
77{
78 struct nf_conn_nat *nat = nfct_nat(ct);
79 struct nf_nat_seq *this_way;
80 s16 offset;
81
82 if (!nat)
83 return 0;
84
85 this_way = &nat->seq[dir];
86 spin_lock_bh(&nf_nat_seqofs_lock);
87 offset = after(seq, this_way->correction_pos)
88 ? this_way->offset_after : this_way->offset_before;
89 spin_unlock_bh(&nf_nat_seqofs_lock);
90
91 return offset;
92}
93EXPORT_SYMBOL_GPL(nf_nat_get_offset);
94
95/* Frobs data inside this packet, which is linear. */
96static void mangle_contents(struct sk_buff *skb,
97 unsigned int dataoff,
98 unsigned int match_offset,
99 unsigned int match_len,
100 const char *rep_buffer,
101 unsigned int rep_len)
102{
103 unsigned char *data;
104
105 BUG_ON(skb_is_nonlinear(skb));
106 data = skb_network_header(skb) + dataoff;
107
108 /* move post-replacement */
109 memmove(data + match_offset + rep_len,
110 data + match_offset + match_len,
111 skb->tail - (skb->network_header + dataoff +
112 match_offset + match_len));
113
114 /* insert data from buffer */
115 memcpy(data + match_offset, rep_buffer, rep_len);
116
117 /* update skb info */
118 if (rep_len > match_len) {
119 pr_debug("nf_nat_mangle_packet: Extending packet by "
120 "%u from %u bytes\n", rep_len - match_len, skb->len);
121 skb_put(skb, rep_len - match_len);
122 } else {
123 pr_debug("nf_nat_mangle_packet: Shrinking packet from "
124 "%u from %u bytes\n", match_len - rep_len, skb->len);
125 __skb_trim(skb, skb->len + rep_len - match_len);
126 }
127
128 /* fix IP hdr checksum information */
129 ip_hdr(skb)->tot_len = htons(skb->len);
130 ip_send_check(ip_hdr(skb));
131}
132
133/* Unusual, but possible case. */
134static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
135{
136 if (skb->len + extra > 65535)
137 return 0;
138
139 if (pskb_expand_head(skb, 0, extra - skb_tailroom(skb), GFP_ATOMIC))
140 return 0;
141
142 return 1;
143}
144
145void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
146 __be32 seq, s16 off)
147{
148 if (!off)
149 return;
150 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
151 adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo);
152 nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
153}
154EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
155
156void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
157 u32 ctinfo, int off)
158{
159 const struct tcphdr *th;
160
161 if (nf_ct_protonum(ct) != IPPROTO_TCP)
162 return;
163
164 th = (struct tcphdr *)(skb_network_header(skb)+ ip_hdrlen(skb));
165 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
166}
167EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust);
168
169static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data,
170 int datalen, __sum16 *check, int oldlen)
171{
172 struct rtable *rt = skb_rtable(skb);
173
174 if (skb->ip_summed != CHECKSUM_PARTIAL) {
175 if (!(rt->rt_flags & RTCF_LOCAL) &&
176 (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
177 skb->ip_summed = CHECKSUM_PARTIAL;
178 skb->csum_start = skb_headroom(skb) +
179 skb_network_offset(skb) +
180 iph->ihl * 4;
181 skb->csum_offset = (void *)check - data;
182 *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
183 datalen, iph->protocol, 0);
184 } else {
185 *check = 0;
186 *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
187 datalen, iph->protocol,
188 csum_partial(data, datalen,
189 0));
190 if (iph->protocol == IPPROTO_UDP && !*check)
191 *check = CSUM_MANGLED_0;
192 }
193 } else
194 inet_proto_csum_replace2(check, skb,
195 htons(oldlen), htons(datalen), 1);
196}
197
198/* Generic function for mangling variable-length address changes inside
199 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
200 * command in FTP).
201 *
202 * Takes care about all the nasty sequence number changes, checksumming,
203 * skb enlargement, ...
204 *
205 * */
206int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
207 struct nf_conn *ct,
208 enum ip_conntrack_info ctinfo,
209 unsigned int match_offset,
210 unsigned int match_len,
211 const char *rep_buffer,
212 unsigned int rep_len, bool adjust)
213{
214 struct iphdr *iph;
215 struct tcphdr *tcph;
216 int oldlen, datalen;
217
218 if (!skb_make_writable(skb, skb->len))
219 return 0;
220
221 if (rep_len > match_len &&
222 rep_len - match_len > skb_tailroom(skb) &&
223 !enlarge_skb(skb, rep_len - match_len))
224 return 0;
225
226 SKB_LINEAR_ASSERT(skb);
227
228 iph = ip_hdr(skb);
229 tcph = (void *)iph + iph->ihl*4;
230
231 oldlen = skb->len - iph->ihl*4;
232 mangle_contents(skb, iph->ihl*4 + tcph->doff*4,
233 match_offset, match_len, rep_buffer, rep_len);
234
235 datalen = skb->len - iph->ihl*4;
236 nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen);
237
238 if (adjust && rep_len != match_len)
239 nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
240 (int)rep_len - (int)match_len);
241
242 return 1;
243}
244EXPORT_SYMBOL(__nf_nat_mangle_tcp_packet);
245
246/* Generic function for mangling variable-length address changes inside
247 * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
248 * command in the Amanda protocol)
249 *
250 * Takes care about all the nasty sequence number changes, checksumming,
251 * skb enlargement, ...
252 *
253 * XXX - This function could be merged with nf_nat_mangle_tcp_packet which
254 * should be fairly easy to do.
255 */
256int
257nf_nat_mangle_udp_packet(struct sk_buff *skb,
258 struct nf_conn *ct,
259 enum ip_conntrack_info ctinfo,
260 unsigned int match_offset,
261 unsigned int match_len,
262 const char *rep_buffer,
263 unsigned int rep_len)
264{
265 struct iphdr *iph;
266 struct udphdr *udph;
267 int datalen, oldlen;
268
269 if (!skb_make_writable(skb, skb->len))
270 return 0;
271
272 if (rep_len > match_len &&
273 rep_len - match_len > skb_tailroom(skb) &&
274 !enlarge_skb(skb, rep_len - match_len))
275 return 0;
276
277 iph = ip_hdr(skb);
278 udph = (void *)iph + iph->ihl*4;
279
280 oldlen = skb->len - iph->ihl*4;
281 mangle_contents(skb, iph->ihl*4 + sizeof(*udph),
282 match_offset, match_len, rep_buffer, rep_len);
283
284 /* update the length of the UDP packet */
285 datalen = skb->len - iph->ihl*4;
286 udph->len = htons(datalen);
287
288 /* fix udp checksum if udp checksum was previously calculated */
289 if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
290 return 1;
291
292 nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen);
293
294 return 1;
295}
296EXPORT_SYMBOL(nf_nat_mangle_udp_packet);
297
298/* Adjust one found SACK option including checksum correction */
299static void
300sack_adjust(struct sk_buff *skb,
301 struct tcphdr *tcph,
302 unsigned int sackoff,
303 unsigned int sackend,
304 struct nf_nat_seq *natseq)
305{
306 while (sackoff < sackend) {
307 struct tcp_sack_block_wire *sack;
308 __be32 new_start_seq, new_end_seq;
309
310 sack = (void *)skb->data + sackoff;
311 if (after(ntohl(sack->start_seq) - natseq->offset_before,
312 natseq->correction_pos))
313 new_start_seq = htonl(ntohl(sack->start_seq)
314 - natseq->offset_after);
315 else
316 new_start_seq = htonl(ntohl(sack->start_seq)
317 - natseq->offset_before);
318
319 if (after(ntohl(sack->end_seq) - natseq->offset_before,
320 natseq->correction_pos))
321 new_end_seq = htonl(ntohl(sack->end_seq)
322 - natseq->offset_after);
323 else
324 new_end_seq = htonl(ntohl(sack->end_seq)
325 - natseq->offset_before);
326
327 pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
328 ntohl(sack->start_seq), new_start_seq,
329 ntohl(sack->end_seq), new_end_seq);
330
331 inet_proto_csum_replace4(&tcph->check, skb,
332 sack->start_seq, new_start_seq, 0);
333 inet_proto_csum_replace4(&tcph->check, skb,
334 sack->end_seq, new_end_seq, 0);
335 sack->start_seq = new_start_seq;
336 sack->end_seq = new_end_seq;
337 sackoff += sizeof(*sack);
338 }
339}
340
341/* TCP SACK sequence number adjustment */
342static inline unsigned int
343nf_nat_sack_adjust(struct sk_buff *skb,
344 struct tcphdr *tcph,
345 struct nf_conn *ct,
346 enum ip_conntrack_info ctinfo)
347{
348 unsigned int dir, optoff, optend;
349 struct nf_conn_nat *nat = nfct_nat(ct);
350
351 optoff = ip_hdrlen(skb) + sizeof(struct tcphdr);
352 optend = ip_hdrlen(skb) + tcph->doff * 4;
353
354 if (!skb_make_writable(skb, optend))
355 return 0;
356
357 dir = CTINFO2DIR(ctinfo);
358
359 while (optoff < optend) {
360 /* Usually: option, length. */
361 unsigned char *op = skb->data + optoff;
362
363 switch (op[0]) {
364 case TCPOPT_EOL:
365 return 1;
366 case TCPOPT_NOP:
367 optoff++;
368 continue;
369 default:
370 /* no partial options */
371 if (optoff + 1 == optend ||
372 optoff + op[1] > optend ||
373 op[1] < 2)
374 return 0;
375 if (op[0] == TCPOPT_SACK &&
376 op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
377 ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
378 sack_adjust(skb, tcph, optoff+2,
379 optoff+op[1], &nat->seq[!dir]);
380 optoff += op[1];
381 }
382 }
383 return 1;
384}
385
386/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
387int
388nf_nat_seq_adjust(struct sk_buff *skb,
389 struct nf_conn *ct,
390 enum ip_conntrack_info ctinfo)
391{
392 struct tcphdr *tcph;
393 int dir;
394 __be32 newseq, newack;
395 s16 seqoff, ackoff;
396 struct nf_conn_nat *nat = nfct_nat(ct);
397 struct nf_nat_seq *this_way, *other_way;
398
399 dir = CTINFO2DIR(ctinfo);
400
401 this_way = &nat->seq[dir];
402 other_way = &nat->seq[!dir];
403
404 if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
405 return 0;
406
407 tcph = (void *)skb->data + ip_hdrlen(skb);
408 if (after(ntohl(tcph->seq), this_way->correction_pos))
409 seqoff = this_way->offset_after;
410 else
411 seqoff = this_way->offset_before;
412
413 if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
414 other_way->correction_pos))
415 ackoff = other_way->offset_after;
416 else
417 ackoff = other_way->offset_before;
418
419 newseq = htonl(ntohl(tcph->seq) + seqoff);
420 newack = htonl(ntohl(tcph->ack_seq) - ackoff);
421
422 inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
423 inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
424
425 pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
426 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
427 ntohl(newack));
428
429 tcph->seq = newseq;
430 tcph->ack_seq = newack;
431
432 return nf_nat_sack_adjust(skb, tcph, ct, ctinfo);
433}
434
435/* Setup NAT on this expected conntrack so it follows master. */
436/* If we fail to get a free NAT slot, we'll get dropped on confirm */
437void nf_nat_follow_master(struct nf_conn *ct,
438 struct nf_conntrack_expect *exp)
439{
440 struct nf_nat_ipv4_range range;
441
442 /* This must be a fresh one. */
443 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
444
445 /* Change src to where master sends to */
446 range.flags = NF_NAT_RANGE_MAP_IPS;
447 range.min_ip = range.max_ip
448 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
449 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
450
451 /* For DST manip, map port here to where it's expected. */
452 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
453 range.min = range.max = exp->saved_proto;
454 range.min_ip = range.max_ip
455 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip;
456 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
457}
458EXPORT_SYMBOL(nf_nat_follow_master);
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
deleted file mode 100644
index 979ae165f4ef..000000000000
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ /dev/null
@@ -1,99 +0,0 @@
1/* IRC extension for TCP NAT alteration.
2 *
3 * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
5 * based on a copy of RR's ip_nat_ftp.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/tcp.h>
16#include <linux/kernel.h>
17
18#include <net/netfilter/nf_nat.h>
19#include <net/netfilter/nf_nat_helper.h>
20#include <net/netfilter/nf_nat_rule.h>
21#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h>
23#include <linux/netfilter/nf_conntrack_irc.h>
24
25MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
26MODULE_DESCRIPTION("IRC (DCC) NAT helper");
27MODULE_LICENSE("GPL");
28MODULE_ALIAS("ip_nat_irc");
29
30static unsigned int help(struct sk_buff *skb,
31 enum ip_conntrack_info ctinfo,
32 unsigned int matchoff,
33 unsigned int matchlen,
34 struct nf_conntrack_expect *exp)
35{
36 char buffer[sizeof("4294967296 65635")];
37 u_int32_t ip;
38 u_int16_t port;
39 unsigned int ret;
40
41 /* Reply comes from server. */
42 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
43 exp->dir = IP_CT_DIR_REPLY;
44 exp->expectfn = nf_nat_follow_master;
45
46 /* Try to get same port: if not, try to change it. */
47 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
48 int ret;
49
50 exp->tuple.dst.u.tcp.port = htons(port);
51 ret = nf_ct_expect_related(exp);
52 if (ret == 0)
53 break;
54 else if (ret != -EBUSY) {
55 port = 0;
56 break;
57 }
58 }
59
60 if (port == 0)
61 return NF_DROP;
62
63 ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip);
64 sprintf(buffer, "%u %u", ip, port);
65 pr_debug("nf_nat_irc: inserting '%s' == %pI4, port %u\n",
66 buffer, &ip, port);
67
68 ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
69 matchoff, matchlen, buffer,
70 strlen(buffer));
71 if (ret != NF_ACCEPT)
72 nf_ct_unexpect_related(exp);
73 return ret;
74}
75
76static void __exit nf_nat_irc_fini(void)
77{
78 RCU_INIT_POINTER(nf_nat_irc_hook, NULL);
79 synchronize_rcu();
80}
81
82static int __init nf_nat_irc_init(void)
83{
84 BUG_ON(nf_nat_irc_hook != NULL);
85 RCU_INIT_POINTER(nf_nat_irc_hook, help);
86 return 0;
87}
88
89/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
90static int warn_set(const char *val, struct kernel_param *kp)
91{
92 printk(KERN_INFO KBUILD_MODNAME
93 ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
94 return 0;
95}
96module_param_call(ports, warn_set, NULL, NULL, 0);
97
98module_init(nf_nat_irc_init);
99module_exit(nf_nat_irc_fini);
diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
new file mode 100644
index 000000000000..d8b2e14efddc
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
@@ -0,0 +1,281 @@
1/*
2 * (C) 1999-2001 Paul `Rusty' Russell
3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4 * (C) 2011 Patrick McHardy <kaber@trash.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/types.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/ip.h>
15#include <linux/icmp.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv4.h>
18#include <net/secure_seq.h>
19#include <net/checksum.h>
20#include <net/route.h>
21#include <net/ip.h>
22
23#include <net/netfilter/nf_conntrack_core.h>
24#include <net/netfilter/nf_conntrack.h>
25#include <net/netfilter/nf_nat_core.h>
26#include <net/netfilter/nf_nat_l3proto.h>
27#include <net/netfilter/nf_nat_l4proto.h>
28
29static const struct nf_nat_l3proto nf_nat_l3proto_ipv4;
30
31#ifdef CONFIG_XFRM
32static void nf_nat_ipv4_decode_session(struct sk_buff *skb,
33 const struct nf_conn *ct,
34 enum ip_conntrack_dir dir,
35 unsigned long statusbit,
36 struct flowi *fl)
37{
38 const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
39 struct flowi4 *fl4 = &fl->u.ip4;
40
41 if (ct->status & statusbit) {
42 fl4->daddr = t->dst.u3.ip;
43 if (t->dst.protonum == IPPROTO_TCP ||
44 t->dst.protonum == IPPROTO_UDP ||
45 t->dst.protonum == IPPROTO_UDPLITE ||
46 t->dst.protonum == IPPROTO_DCCP ||
47 t->dst.protonum == IPPROTO_SCTP)
48 fl4->fl4_dport = t->dst.u.all;
49 }
50
51 statusbit ^= IPS_NAT_MASK;
52
53 if (ct->status & statusbit) {
54 fl4->saddr = t->src.u3.ip;
55 if (t->dst.protonum == IPPROTO_TCP ||
56 t->dst.protonum == IPPROTO_UDP ||
57 t->dst.protonum == IPPROTO_UDPLITE ||
58 t->dst.protonum == IPPROTO_DCCP ||
59 t->dst.protonum == IPPROTO_SCTP)
60 fl4->fl4_sport = t->src.u.all;
61 }
62}
63#endif /* CONFIG_XFRM */
64
65static bool nf_nat_ipv4_in_range(const struct nf_conntrack_tuple *t,
66 const struct nf_nat_range *range)
67{
68 return ntohl(t->src.u3.ip) >= ntohl(range->min_addr.ip) &&
69 ntohl(t->src.u3.ip) <= ntohl(range->max_addr.ip);
70}
71
72static u32 nf_nat_ipv4_secure_port(const struct nf_conntrack_tuple *t,
73 __be16 dport)
74{
75 return secure_ipv4_port_ephemeral(t->src.u3.ip, t->dst.u3.ip, dport);
76}
77
78static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
79 unsigned int iphdroff,
80 const struct nf_nat_l4proto *l4proto,
81 const struct nf_conntrack_tuple *target,
82 enum nf_nat_manip_type maniptype)
83{
84 struct iphdr *iph;
85 unsigned int hdroff;
86
87 if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
88 return false;
89
90 iph = (void *)skb->data + iphdroff;
91 hdroff = iphdroff + iph->ihl * 4;
92
93 if (!l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv4, iphdroff, hdroff,
94 target, maniptype))
95 return false;
96 iph = (void *)skb->data + iphdroff;
97
98 if (maniptype == NF_NAT_MANIP_SRC) {
99 csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
100 iph->saddr = target->src.u3.ip;
101 } else {
102 csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
103 iph->daddr = target->dst.u3.ip;
104 }
105 return true;
106}
107
108static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
109 unsigned int iphdroff, __sum16 *check,
110 const struct nf_conntrack_tuple *t,
111 enum nf_nat_manip_type maniptype)
112{
113 struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
114 __be32 oldip, newip;
115
116 if (maniptype == NF_NAT_MANIP_SRC) {
117 oldip = iph->saddr;
118 newip = t->src.u3.ip;
119 } else {
120 oldip = iph->daddr;
121 newip = t->dst.u3.ip;
122 }
123 inet_proto_csum_replace4(check, skb, oldip, newip, 1);
124}
125
126static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
127 u8 proto, void *data, __sum16 *check,
128 int datalen, int oldlen)
129{
130 const struct iphdr *iph = ip_hdr(skb);
131 struct rtable *rt = skb_rtable(skb);
132
133 if (skb->ip_summed != CHECKSUM_PARTIAL) {
134 if (!(rt->rt_flags & RTCF_LOCAL) &&
135 (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
136 skb->ip_summed = CHECKSUM_PARTIAL;
137 skb->csum_start = skb_headroom(skb) +
138 skb_network_offset(skb) +
139 ip_hdrlen(skb);
140 skb->csum_offset = (void *)check - data;
141 *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
142 datalen, proto, 0);
143 } else {
144 *check = 0;
145 *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
146 datalen, proto,
147 csum_partial(data, datalen,
148 0));
149 if (proto == IPPROTO_UDP && !*check)
150 *check = CSUM_MANGLED_0;
151 }
152 } else
153 inet_proto_csum_replace2(check, skb,
154 htons(oldlen), htons(datalen), 1);
155}
156
157static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[],
158 struct nf_nat_range *range)
159{
160 if (tb[CTA_NAT_V4_MINIP]) {
161 range->min_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MINIP]);
162 range->flags |= NF_NAT_RANGE_MAP_IPS;
163 }
164
165 if (tb[CTA_NAT_V4_MAXIP])
166 range->max_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MAXIP]);
167 else
168 range->max_addr.ip = range->min_addr.ip;
169
170 return 0;
171}
172
173static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = {
174 .l3proto = NFPROTO_IPV4,
175 .in_range = nf_nat_ipv4_in_range,
176 .secure_port = nf_nat_ipv4_secure_port,
177 .manip_pkt = nf_nat_ipv4_manip_pkt,
178 .csum_update = nf_nat_ipv4_csum_update,
179 .csum_recalc = nf_nat_ipv4_csum_recalc,
180 .nlattr_to_range = nf_nat_ipv4_nlattr_to_range,
181#ifdef CONFIG_XFRM
182 .decode_session = nf_nat_ipv4_decode_session,
183#endif
184};
185
186int nf_nat_icmp_reply_translation(struct sk_buff *skb,
187 struct nf_conn *ct,
188 enum ip_conntrack_info ctinfo,
189 unsigned int hooknum)
190{
191 struct {
192 struct icmphdr icmp;
193 struct iphdr ip;
194 } *inside;
195 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
196 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
197 unsigned int hdrlen = ip_hdrlen(skb);
198 const struct nf_nat_l4proto *l4proto;
199 struct nf_conntrack_tuple target;
200 unsigned long statusbit;
201
202 NF_CT_ASSERT(ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY);
203
204 if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
205 return 0;
206 if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
207 return 0;
208
209 inside = (void *)skb->data + hdrlen;
210 if (inside->icmp.type == ICMP_REDIRECT) {
211 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
212 return 0;
213 if (ct->status & IPS_NAT_MASK)
214 return 0;
215 }
216
217 if (manip == NF_NAT_MANIP_SRC)
218 statusbit = IPS_SRC_NAT;
219 else
220 statusbit = IPS_DST_NAT;
221
222 /* Invert if this is reply direction */
223 if (dir == IP_CT_DIR_REPLY)
224 statusbit ^= IPS_NAT_MASK;
225
226 if (!(ct->status & statusbit))
227 return 1;
228
229 l4proto = __nf_nat_l4proto_find(NFPROTO_IPV4, inside->ip.protocol);
230 if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
231 l4proto, &ct->tuplehash[!dir].tuple, !manip))
232 return 0;
233
234 if (skb->ip_summed != CHECKSUM_PARTIAL) {
235 /* Reloading "inside" here since manip_pkt may reallocate */
236 inside = (void *)skb->data + hdrlen;
237 inside->icmp.checksum = 0;
238 inside->icmp.checksum =
239 csum_fold(skb_checksum(skb, hdrlen,
240 skb->len - hdrlen, 0));
241 }
242
243 /* Change outer to look like the reply to an incoming packet */
244 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
245 l4proto = __nf_nat_l4proto_find(NFPROTO_IPV4, 0);
246 if (!nf_nat_ipv4_manip_pkt(skb, 0, l4proto, &target, manip))
247 return 0;
248
249 return 1;
250}
251EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
252
253static int __init nf_nat_l3proto_ipv4_init(void)
254{
255 int err;
256
257 err = nf_nat_l4proto_register(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
258 if (err < 0)
259 goto err1;
260 err = nf_nat_l3proto_register(&nf_nat_l3proto_ipv4);
261 if (err < 0)
262 goto err2;
263 return err;
264
265err2:
266 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
267err1:
268 return err;
269}
270
271static void __exit nf_nat_l3proto_ipv4_exit(void)
272{
273 nf_nat_l3proto_unregister(&nf_nat_l3proto_ipv4);
274 nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
275}
276
277MODULE_LICENSE("GPL");
278MODULE_ALIAS("nf-nat-" __stringify(AF_INET));
279
280module_init(nf_nat_l3proto_ipv4_init);
281module_exit(nf_nat_l3proto_ipv4_exit);
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 388140881ebe..a06d7d74817d 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -22,7 +22,6 @@
22 22
23#include <net/netfilter/nf_nat.h> 23#include <net/netfilter/nf_nat.h>
24#include <net/netfilter/nf_nat_helper.h> 24#include <net/netfilter/nf_nat_helper.h>
25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_conntrack_helper.h> 25#include <net/netfilter/nf_conntrack_helper.h>
27#include <net/netfilter/nf_conntrack_expect.h> 26#include <net/netfilter/nf_conntrack_expect.h>
28#include <net/netfilter/nf_conntrack_zones.h> 27#include <net/netfilter/nf_conntrack_zones.h>
@@ -47,7 +46,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
47 struct nf_conntrack_tuple t; 46 struct nf_conntrack_tuple t;
48 const struct nf_ct_pptp_master *ct_pptp_info; 47 const struct nf_ct_pptp_master *ct_pptp_info;
49 const struct nf_nat_pptp *nat_pptp_info; 48 const struct nf_nat_pptp *nat_pptp_info;
50 struct nf_nat_ipv4_range range; 49 struct nf_nat_range range;
51 50
52 ct_pptp_info = nfct_help_data(master); 51 ct_pptp_info = nfct_help_data(master);
53 nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; 52 nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
@@ -89,21 +88,21 @@ static void pptp_nat_expected(struct nf_conn *ct,
89 88
90 /* Change src to where master sends to */ 89 /* Change src to where master sends to */
91 range.flags = NF_NAT_RANGE_MAP_IPS; 90 range.flags = NF_NAT_RANGE_MAP_IPS;
92 range.min_ip = range.max_ip 91 range.min_addr = range.max_addr
93 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 92 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
94 if (exp->dir == IP_CT_DIR_ORIGINAL) { 93 if (exp->dir == IP_CT_DIR_ORIGINAL) {
95 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 94 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
96 range.min = range.max = exp->saved_proto; 95 range.min_proto = range.max_proto = exp->saved_proto;
97 } 96 }
98 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); 97 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
99 98
100 /* For DST manip, map port here to where it's expected. */ 99 /* For DST manip, map port here to where it's expected. */
101 range.flags = NF_NAT_RANGE_MAP_IPS; 100 range.flags = NF_NAT_RANGE_MAP_IPS;
102 range.min_ip = range.max_ip 101 range.min_addr = range.max_addr
103 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; 102 = ct->master->tuplehash[!exp->dir].tuple.src.u3;
104 if (exp->dir == IP_CT_DIR_REPLY) { 103 if (exp->dir == IP_CT_DIR_REPLY) {
105 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 104 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
106 range.min = range.max = exp->saved_proto; 105 range.min_proto = range.max_proto = exp->saved_proto;
107 } 106 }
108 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); 107 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
109} 108}
@@ -113,6 +112,7 @@ static int
113pptp_outbound_pkt(struct sk_buff *skb, 112pptp_outbound_pkt(struct sk_buff *skb,
114 struct nf_conn *ct, 113 struct nf_conn *ct,
115 enum ip_conntrack_info ctinfo, 114 enum ip_conntrack_info ctinfo,
115 unsigned int protoff,
116 struct PptpControlHeader *ctlh, 116 struct PptpControlHeader *ctlh,
117 union pptp_ctrl_union *pptpReq) 117 union pptp_ctrl_union *pptpReq)
118 118
@@ -175,7 +175,7 @@ pptp_outbound_pkt(struct sk_buff *skb,
175 ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); 175 ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
176 176
177 /* mangle packet */ 177 /* mangle packet */
178 if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 178 if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
179 cid_off + sizeof(struct pptp_pkt_hdr) + 179 cid_off + sizeof(struct pptp_pkt_hdr) +
180 sizeof(struct PptpControlHeader), 180 sizeof(struct PptpControlHeader),
181 sizeof(new_callid), (char *)&new_callid, 181 sizeof(new_callid), (char *)&new_callid,
@@ -216,6 +216,7 @@ static int
216pptp_inbound_pkt(struct sk_buff *skb, 216pptp_inbound_pkt(struct sk_buff *skb,
217 struct nf_conn *ct, 217 struct nf_conn *ct,
218 enum ip_conntrack_info ctinfo, 218 enum ip_conntrack_info ctinfo,
219 unsigned int protoff,
219 struct PptpControlHeader *ctlh, 220 struct PptpControlHeader *ctlh,
220 union pptp_ctrl_union *pptpReq) 221 union pptp_ctrl_union *pptpReq)
221{ 222{
@@ -268,7 +269,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
268 pr_debug("altering peer call id from 0x%04x to 0x%04x\n", 269 pr_debug("altering peer call id from 0x%04x to 0x%04x\n",
269 ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); 270 ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
270 271
271 if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 272 if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
272 pcid_off + sizeof(struct pptp_pkt_hdr) + 273 pcid_off + sizeof(struct pptp_pkt_hdr) +
273 sizeof(struct PptpControlHeader), 274 sizeof(struct PptpControlHeader),
274 sizeof(new_pcid), (char *)&new_pcid, 275 sizeof(new_pcid), (char *)&new_pcid,
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
deleted file mode 100644
index 9993bc93e102..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ /dev/null
@@ -1,114 +0,0 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2008 Patrick McHardy <kaber@trash.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/types.h>
11#include <linux/random.h>
12#include <linux/ip.h>
13
14#include <linux/netfilter.h>
15#include <linux/export.h>
16#include <net/secure_seq.h>
17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_core.h>
19#include <net/netfilter/nf_nat_rule.h>
20#include <net/netfilter/nf_nat_protocol.h>
21
22bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple,
23 enum nf_nat_manip_type maniptype,
24 const union nf_conntrack_man_proto *min,
25 const union nf_conntrack_man_proto *max)
26{
27 __be16 port;
28
29 if (maniptype == NF_NAT_MANIP_SRC)
30 port = tuple->src.u.all;
31 else
32 port = tuple->dst.u.all;
33
34 return ntohs(port) >= ntohs(min->all) &&
35 ntohs(port) <= ntohs(max->all);
36}
37EXPORT_SYMBOL_GPL(nf_nat_proto_in_range);
38
39void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
40 const struct nf_nat_ipv4_range *range,
41 enum nf_nat_manip_type maniptype,
42 const struct nf_conn *ct,
43 u_int16_t *rover)
44{
45 unsigned int range_size, min, i;
46 __be16 *portptr;
47 u_int16_t off;
48
49 if (maniptype == NF_NAT_MANIP_SRC)
50 portptr = &tuple->src.u.all;
51 else
52 portptr = &tuple->dst.u.all;
53
54 /* If no range specified... */
55 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) {
56 /* If it's dst rewrite, can't change port */
57 if (maniptype == NF_NAT_MANIP_DST)
58 return;
59
60 if (ntohs(*portptr) < 1024) {
61 /* Loose convention: >> 512 is credential passing */
62 if (ntohs(*portptr) < 512) {
63 min = 1;
64 range_size = 511 - min + 1;
65 } else {
66 min = 600;
67 range_size = 1023 - min + 1;
68 }
69 } else {
70 min = 1024;
71 range_size = 65535 - 1024 + 1;
72 }
73 } else {
74 min = ntohs(range->min.all);
75 range_size = ntohs(range->max.all) - min + 1;
76 }
77
78 if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
79 off = secure_ipv4_port_ephemeral(tuple->src.u3.ip, tuple->dst.u3.ip,
80 maniptype == NF_NAT_MANIP_SRC
81 ? tuple->dst.u.all
82 : tuple->src.u.all);
83 else
84 off = *rover;
85
86 for (i = 0; ; ++off) {
87 *portptr = htons(min + off % range_size);
88 if (++i != range_size && nf_nat_used_tuple(tuple, ct))
89 continue;
90 if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM))
91 *rover = off;
92 return;
93 }
94 return;
95}
96EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple);
97
98#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
99int nf_nat_proto_nlattr_to_range(struct nlattr *tb[],
100 struct nf_nat_ipv4_range *range)
101{
102 if (tb[CTA_PROTONAT_PORT_MIN]) {
103 range->min.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]);
104 range->max.all = range->min.tcp.port;
105 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
106 }
107 if (tb[CTA_PROTONAT_PORT_MAX]) {
108 range->max.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]);
109 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
110 }
111 return 0;
112}
113EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range);
114#endif
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c
deleted file mode 100644
index 3f67138d187c..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_dccp.c
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 * DCCP NAT protocol helper
3 *
4 * Copyright (c) 2005, 2006. 2008 Patrick McHardy <kaber@trash.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/skbuff.h>
16#include <linux/ip.h>
17#include <linux/dccp.h>
18
19#include <net/netfilter/nf_conntrack.h>
20#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_protocol.h>
22
23static u_int16_t dccp_port_rover;
24
25static void
26dccp_unique_tuple(struct nf_conntrack_tuple *tuple,
27 const struct nf_nat_ipv4_range *range,
28 enum nf_nat_manip_type maniptype,
29 const struct nf_conn *ct)
30{
31 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
32 &dccp_port_rover);
33}
34
35static bool
36dccp_manip_pkt(struct sk_buff *skb,
37 unsigned int iphdroff,
38 const struct nf_conntrack_tuple *tuple,
39 enum nf_nat_manip_type maniptype)
40{
41 const struct iphdr *iph = (const void *)(skb->data + iphdroff);
42 struct dccp_hdr *hdr;
43 unsigned int hdroff = iphdroff + iph->ihl * 4;
44 __be32 oldip, newip;
45 __be16 *portptr, oldport, newport;
46 int hdrsize = 8; /* DCCP connection tracking guarantees this much */
47
48 if (skb->len >= hdroff + sizeof(struct dccp_hdr))
49 hdrsize = sizeof(struct dccp_hdr);
50
51 if (!skb_make_writable(skb, hdroff + hdrsize))
52 return false;
53
54 iph = (struct iphdr *)(skb->data + iphdroff);
55 hdr = (struct dccp_hdr *)(skb->data + hdroff);
56
57 if (maniptype == NF_NAT_MANIP_SRC) {
58 oldip = iph->saddr;
59 newip = tuple->src.u3.ip;
60 newport = tuple->src.u.dccp.port;
61 portptr = &hdr->dccph_sport;
62 } else {
63 oldip = iph->daddr;
64 newip = tuple->dst.u3.ip;
65 newport = tuple->dst.u.dccp.port;
66 portptr = &hdr->dccph_dport;
67 }
68
69 oldport = *portptr;
70 *portptr = newport;
71
72 if (hdrsize < sizeof(*hdr))
73 return true;
74
75 inet_proto_csum_replace4(&hdr->dccph_checksum, skb, oldip, newip, 1);
76 inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport,
77 0);
78 return true;
79}
80
81static const struct nf_nat_protocol nf_nat_protocol_dccp = {
82 .protonum = IPPROTO_DCCP,
83 .manip_pkt = dccp_manip_pkt,
84 .in_range = nf_nat_proto_in_range,
85 .unique_tuple = dccp_unique_tuple,
86#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
87 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
88#endif
89};
90
91static int __init nf_nat_proto_dccp_init(void)
92{
93 return nf_nat_protocol_register(&nf_nat_protocol_dccp);
94}
95
96static void __exit nf_nat_proto_dccp_fini(void)
97{
98 nf_nat_protocol_unregister(&nf_nat_protocol_dccp);
99}
100
101module_init(nf_nat_proto_dccp_init);
102module_exit(nf_nat_proto_dccp_fini);
103
104MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
105MODULE_DESCRIPTION("DCCP NAT protocol helper");
106MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index 46ba0b9ab985..ea44f02563b5 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -28,8 +28,7 @@
28#include <linux/ip.h> 28#include <linux/ip.h>
29 29
30#include <net/netfilter/nf_nat.h> 30#include <net/netfilter/nf_nat.h>
31#include <net/netfilter/nf_nat_rule.h> 31#include <net/netfilter/nf_nat_l4proto.h>
32#include <net/netfilter/nf_nat_protocol.h>
33#include <linux/netfilter/nf_conntrack_proto_gre.h> 32#include <linux/netfilter/nf_conntrack_proto_gre.h>
34 33
35MODULE_LICENSE("GPL"); 34MODULE_LICENSE("GPL");
@@ -38,8 +37,9 @@ MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
38 37
39/* generate unique tuple ... */ 38/* generate unique tuple ... */
40static void 39static void
41gre_unique_tuple(struct nf_conntrack_tuple *tuple, 40gre_unique_tuple(const struct nf_nat_l3proto *l3proto,
42 const struct nf_nat_ipv4_range *range, 41 struct nf_conntrack_tuple *tuple,
42 const struct nf_nat_range *range,
43 enum nf_nat_manip_type maniptype, 43 enum nf_nat_manip_type maniptype,
44 const struct nf_conn *ct) 44 const struct nf_conn *ct)
45{ 45{
@@ -62,8 +62,8 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
62 min = 1; 62 min = 1;
63 range_size = 0xffff; 63 range_size = 0xffff;
64 } else { 64 } else {
65 min = ntohs(range->min.gre.key); 65 min = ntohs(range->min_proto.gre.key);
66 range_size = ntohs(range->max.gre.key) - min + 1; 66 range_size = ntohs(range->max_proto.gre.key) - min + 1;
67 } 67 }
68 68
69 pr_debug("min = %u, range_size = %u\n", min, range_size); 69 pr_debug("min = %u, range_size = %u\n", min, range_size);
@@ -80,14 +80,14 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
80 80
81/* manipulate a GRE packet according to maniptype */ 81/* manipulate a GRE packet according to maniptype */
82static bool 82static bool
83gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, 83gre_manip_pkt(struct sk_buff *skb,
84 const struct nf_nat_l3proto *l3proto,
85 unsigned int iphdroff, unsigned int hdroff,
84 const struct nf_conntrack_tuple *tuple, 86 const struct nf_conntrack_tuple *tuple,
85 enum nf_nat_manip_type maniptype) 87 enum nf_nat_manip_type maniptype)
86{ 88{
87 const struct gre_hdr *greh; 89 const struct gre_hdr *greh;
88 struct gre_hdr_pptp *pgreh; 90 struct gre_hdr_pptp *pgreh;
89 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
90 unsigned int hdroff = iphdroff + iph->ihl * 4;
91 91
92 /* pgreh includes two optional 32bit fields which are not required 92 /* pgreh includes two optional 32bit fields which are not required
93 * to be there. That's where the magic '8' comes from */ 93 * to be there. That's where the magic '8' comes from */
@@ -117,24 +117,24 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
117 return true; 117 return true;
118} 118}
119 119
120static const struct nf_nat_protocol gre = { 120static const struct nf_nat_l4proto gre = {
121 .protonum = IPPROTO_GRE, 121 .l4proto = IPPROTO_GRE,
122 .manip_pkt = gre_manip_pkt, 122 .manip_pkt = gre_manip_pkt,
123 .in_range = nf_nat_proto_in_range, 123 .in_range = nf_nat_l4proto_in_range,
124 .unique_tuple = gre_unique_tuple, 124 .unique_tuple = gre_unique_tuple,
125#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 125#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
126 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 126 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
127#endif 127#endif
128}; 128};
129 129
130static int __init nf_nat_proto_gre_init(void) 130static int __init nf_nat_proto_gre_init(void)
131{ 131{
132 return nf_nat_protocol_register(&gre); 132 return nf_nat_l4proto_register(NFPROTO_IPV4, &gre);
133} 133}
134 134
135static void __exit nf_nat_proto_gre_fini(void) 135static void __exit nf_nat_proto_gre_fini(void)
136{ 136{
137 nf_nat_protocol_unregister(&gre); 137 nf_nat_l4proto_unregister(NFPROTO_IPV4, &gre);
138} 138}
139 139
140module_init(nf_nat_proto_gre_init); 140module_init(nf_nat_proto_gre_init);
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index b35172851bae..eb303471bcf6 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -15,8 +15,7 @@
15#include <linux/netfilter.h> 15#include <linux/netfilter.h>
16#include <net/netfilter/nf_nat.h> 16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_core.h> 17#include <net/netfilter/nf_nat_core.h>
18#include <net/netfilter/nf_nat_rule.h> 18#include <net/netfilter/nf_nat_l4proto.h>
19#include <net/netfilter/nf_nat_protocol.h>
20 19
21static bool 20static bool
22icmp_in_range(const struct nf_conntrack_tuple *tuple, 21icmp_in_range(const struct nf_conntrack_tuple *tuple,
@@ -29,8 +28,9 @@ icmp_in_range(const struct nf_conntrack_tuple *tuple,
29} 28}
30 29
31static void 30static void
32icmp_unique_tuple(struct nf_conntrack_tuple *tuple, 31icmp_unique_tuple(const struct nf_nat_l3proto *l3proto,
33 const struct nf_nat_ipv4_range *range, 32 struct nf_conntrack_tuple *tuple,
33 const struct nf_nat_range *range,
34 enum nf_nat_manip_type maniptype, 34 enum nf_nat_manip_type maniptype,
35 const struct nf_conn *ct) 35 const struct nf_conn *ct)
36{ 36{
@@ -38,13 +38,14 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
38 unsigned int range_size; 38 unsigned int range_size;
39 unsigned int i; 39 unsigned int i;
40 40
41 range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; 41 range_size = ntohs(range->max_proto.icmp.id) -
42 ntohs(range->min_proto.icmp.id) + 1;
42 /* If no range specified... */ 43 /* If no range specified... */
43 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) 44 if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED))
44 range_size = 0xFFFF; 45 range_size = 0xFFFF;
45 46
46 for (i = 0; ; ++id) { 47 for (i = 0; ; ++id) {
47 tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + 48 tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) +
48 (id % range_size)); 49 (id % range_size));
49 if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) 50 if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
50 return; 51 return;
@@ -54,13 +55,12 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
54 55
55static bool 56static bool
56icmp_manip_pkt(struct sk_buff *skb, 57icmp_manip_pkt(struct sk_buff *skb,
57 unsigned int iphdroff, 58 const struct nf_nat_l3proto *l3proto,
59 unsigned int iphdroff, unsigned int hdroff,
58 const struct nf_conntrack_tuple *tuple, 60 const struct nf_conntrack_tuple *tuple,
59 enum nf_nat_manip_type maniptype) 61 enum nf_nat_manip_type maniptype)
60{ 62{
61 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
62 struct icmphdr *hdr; 63 struct icmphdr *hdr;
63 unsigned int hdroff = iphdroff + iph->ihl*4;
64 64
65 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 65 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
66 return false; 66 return false;
@@ -72,12 +72,12 @@ icmp_manip_pkt(struct sk_buff *skb,
72 return true; 72 return true;
73} 73}
74 74
75const struct nf_nat_protocol nf_nat_protocol_icmp = { 75const struct nf_nat_l4proto nf_nat_l4proto_icmp = {
76 .protonum = IPPROTO_ICMP, 76 .l4proto = IPPROTO_ICMP,
77 .manip_pkt = icmp_manip_pkt, 77 .manip_pkt = icmp_manip_pkt,
78 .in_range = icmp_in_range, 78 .in_range = icmp_in_range,
79 .unique_tuple = icmp_unique_tuple, 79 .unique_tuple = icmp_unique_tuple,
80#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 80#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
81 .nlattr_to_range = nf_nat_proto_nlattr_to_range, 81 .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
82#endif 82#endif
83}; 83};
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c
deleted file mode 100644
index 3cce9b6c1c29..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_sctp.c
+++ /dev/null
@@ -1,96 +0,0 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
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
9#include <linux/types.h>
10#include <linux/init.h>
11#include <linux/ip.h>
12#include <linux/sctp.h>
13#include <linux/module.h>
14#include <net/sctp/checksum.h>
15
16#include <net/netfilter/nf_nat_protocol.h>
17
18static u_int16_t nf_sctp_port_rover;
19
20static void
21sctp_unique_tuple(struct nf_conntrack_tuple *tuple,
22 const struct nf_nat_ipv4_range *range,
23 enum nf_nat_manip_type maniptype,
24 const struct nf_conn *ct)
25{
26 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
27 &nf_sctp_port_rover);
28}
29
30static bool
31sctp_manip_pkt(struct sk_buff *skb,
32 unsigned int iphdroff,
33 const struct nf_conntrack_tuple *tuple,
34 enum nf_nat_manip_type maniptype)
35{
36 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
37 struct sk_buff *frag;
38 sctp_sctphdr_t *hdr;
39 unsigned int hdroff = iphdroff + iph->ihl*4;
40 __be32 oldip, newip;
41 __be32 crc32;
42
43 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
44 return false;
45
46 iph = (struct iphdr *)(skb->data + iphdroff);
47 hdr = (struct sctphdr *)(skb->data + hdroff);
48
49 if (maniptype == NF_NAT_MANIP_SRC) {
50 /* Get rid of src ip and src pt */
51 oldip = iph->saddr;
52 newip = tuple->src.u3.ip;
53 hdr->source = tuple->src.u.sctp.port;
54 } else {
55 /* Get rid of dst ip and dst pt */
56 oldip = iph->daddr;
57 newip = tuple->dst.u3.ip;
58 hdr->dest = tuple->dst.u.sctp.port;
59 }
60
61 crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff);
62 skb_walk_frags(skb, frag)
63 crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag),
64 crc32);
65 crc32 = sctp_end_cksum(crc32);
66 hdr->checksum = crc32;
67
68 return true;
69}
70
71static const struct nf_nat_protocol nf_nat_protocol_sctp = {
72 .protonum = IPPROTO_SCTP,
73 .manip_pkt = sctp_manip_pkt,
74 .in_range = nf_nat_proto_in_range,
75 .unique_tuple = sctp_unique_tuple,
76#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
77 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
78#endif
79};
80
81static int __init nf_nat_proto_sctp_init(void)
82{
83 return nf_nat_protocol_register(&nf_nat_protocol_sctp);
84}
85
86static void __exit nf_nat_proto_sctp_exit(void)
87{
88 nf_nat_protocol_unregister(&nf_nat_protocol_sctp);
89}
90
91module_init(nf_nat_proto_sctp_init);
92module_exit(nf_nat_proto_sctp_exit);
93
94MODULE_LICENSE("GPL");
95MODULE_DESCRIPTION("SCTP NAT protocol helper");
96MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
deleted file mode 100644
index 9fb4b4e72bbf..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ /dev/null
@@ -1,91 +0,0 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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
9#include <linux/types.h>
10#include <linux/init.h>
11#include <linux/export.h>
12#include <linux/ip.h>
13#include <linux/tcp.h>
14
15#include <linux/netfilter.h>
16#include <linux/netfilter/nfnetlink_conntrack.h>
17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_nat_protocol.h>
20#include <net/netfilter/nf_nat_core.h>
21
22static u_int16_t tcp_port_rover;
23
24static void
25tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
26 const struct nf_nat_ipv4_range *range,
27 enum nf_nat_manip_type maniptype,
28 const struct nf_conn *ct)
29{
30 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover);
31}
32
33static bool
34tcp_manip_pkt(struct sk_buff *skb,
35 unsigned int iphdroff,
36 const struct nf_conntrack_tuple *tuple,
37 enum nf_nat_manip_type maniptype)
38{
39 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
40 struct tcphdr *hdr;
41 unsigned int hdroff = iphdroff + iph->ihl*4;
42 __be32 oldip, newip;
43 __be16 *portptr, newport, oldport;
44 int hdrsize = 8; /* TCP connection tracking guarantees this much */
45
46 /* this could be a inner header returned in icmp packet; in such
47 cases we cannot update the checksum field since it is outside of
48 the 8 bytes of transport layer headers we are guaranteed */
49 if (skb->len >= hdroff + sizeof(struct tcphdr))
50 hdrsize = sizeof(struct tcphdr);
51
52 if (!skb_make_writable(skb, hdroff + hdrsize))
53 return false;
54
55 iph = (struct iphdr *)(skb->data + iphdroff);
56 hdr = (struct tcphdr *)(skb->data + hdroff);
57
58 if (maniptype == NF_NAT_MANIP_SRC) {
59 /* Get rid of src ip and src pt */
60 oldip = iph->saddr;
61 newip = tuple->src.u3.ip;
62 newport = tuple->src.u.tcp.port;
63 portptr = &hdr->source;
64 } else {
65 /* Get rid of dst ip and dst pt */
66 oldip = iph->daddr;
67 newip = tuple->dst.u3.ip;
68 newport = tuple->dst.u.tcp.port;
69 portptr = &hdr->dest;
70 }
71
72 oldport = *portptr;
73 *portptr = newport;
74
75 if (hdrsize < sizeof(*hdr))
76 return true;
77
78 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
79 inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0);
80 return true;
81}
82
83const struct nf_nat_protocol nf_nat_protocol_tcp = {
84 .protonum = IPPROTO_TCP,
85 .manip_pkt = tcp_manip_pkt,
86 .in_range = nf_nat_proto_in_range,
87 .unique_tuple = tcp_unique_tuple,
88#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
89 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
90#endif
91};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
deleted file mode 100644
index 9883336e628f..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ /dev/null
@@ -1,82 +0,0 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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
9#include <linux/types.h>
10#include <linux/export.h>
11#include <linux/init.h>
12#include <linux/ip.h>
13#include <linux/udp.h>
14
15#include <linux/netfilter.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_core.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_nat_protocol.h>
20
21static u_int16_t udp_port_rover;
22
23static void
24udp_unique_tuple(struct nf_conntrack_tuple *tuple,
25 const struct nf_nat_ipv4_range *range,
26 enum nf_nat_manip_type maniptype,
27 const struct nf_conn *ct)
28{
29 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &udp_port_rover);
30}
31
32static bool
33udp_manip_pkt(struct sk_buff *skb,
34 unsigned int iphdroff,
35 const struct nf_conntrack_tuple *tuple,
36 enum nf_nat_manip_type maniptype)
37{
38 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
39 struct udphdr *hdr;
40 unsigned int hdroff = iphdroff + iph->ihl*4;
41 __be32 oldip, newip;
42 __be16 *portptr, newport;
43
44 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
45 return false;
46
47 iph = (struct iphdr *)(skb->data + iphdroff);
48 hdr = (struct udphdr *)(skb->data + hdroff);
49
50 if (maniptype == NF_NAT_MANIP_SRC) {
51 /* Get rid of src ip and src pt */
52 oldip = iph->saddr;
53 newip = tuple->src.u3.ip;
54 newport = tuple->src.u.udp.port;
55 portptr = &hdr->source;
56 } else {
57 /* Get rid of dst ip and dst pt */
58 oldip = iph->daddr;
59 newip = tuple->dst.u3.ip;
60 newport = tuple->dst.u.udp.port;
61 portptr = &hdr->dest;
62 }
63 if (hdr->check || skb->ip_summed == CHECKSUM_PARTIAL) {
64 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
65 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
66 0);
67 if (!hdr->check)
68 hdr->check = CSUM_MANGLED_0;
69 }
70 *portptr = newport;
71 return true;
72}
73
74const struct nf_nat_protocol nf_nat_protocol_udp = {
75 .protonum = IPPROTO_UDP,
76 .manip_pkt = udp_manip_pkt,
77 .in_range = nf_nat_proto_in_range,
78 .unique_tuple = udp_unique_tuple,
79#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
80 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
81#endif
82};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c
deleted file mode 100644
index d24d10a7beb2..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_udplite.c
+++ /dev/null
@@ -1,98 +0,0 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2008 Patrick McHardy <kaber@trash.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/types.h>
11#include <linux/init.h>
12#include <linux/ip.h>
13#include <linux/udp.h>
14
15#include <linux/netfilter.h>
16#include <linux/module.h>
17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_protocol.h>
19
20static u_int16_t udplite_port_rover;
21
22static void
23udplite_unique_tuple(struct nf_conntrack_tuple *tuple,
24 const struct nf_nat_ipv4_range *range,
25 enum nf_nat_manip_type maniptype,
26 const struct nf_conn *ct)
27{
28 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
29 &udplite_port_rover);
30}
31
32static bool
33udplite_manip_pkt(struct sk_buff *skb,
34 unsigned int iphdroff,
35 const struct nf_conntrack_tuple *tuple,
36 enum nf_nat_manip_type maniptype)
37{
38 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
39 struct udphdr *hdr;
40 unsigned int hdroff = iphdroff + iph->ihl*4;
41 __be32 oldip, newip;
42 __be16 *portptr, newport;
43
44 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
45 return false;
46
47 iph = (struct iphdr *)(skb->data + iphdroff);
48 hdr = (struct udphdr *)(skb->data + hdroff);
49
50 if (maniptype == NF_NAT_MANIP_SRC) {
51 /* Get rid of src ip and src pt */
52 oldip = iph->saddr;
53 newip = tuple->src.u3.ip;
54 newport = tuple->src.u.udp.port;
55 portptr = &hdr->source;
56 } else {
57 /* Get rid of dst ip and dst pt */
58 oldip = iph->daddr;
59 newip = tuple->dst.u3.ip;
60 newport = tuple->dst.u.udp.port;
61 portptr = &hdr->dest;
62 }
63
64 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
65 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 0);
66 if (!hdr->check)
67 hdr->check = CSUM_MANGLED_0;
68
69 *portptr = newport;
70 return true;
71}
72
73static const struct nf_nat_protocol nf_nat_protocol_udplite = {
74 .protonum = IPPROTO_UDPLITE,
75 .manip_pkt = udplite_manip_pkt,
76 .in_range = nf_nat_proto_in_range,
77 .unique_tuple = udplite_unique_tuple,
78#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
79 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
80#endif
81};
82
83static int __init nf_nat_proto_udplite_init(void)
84{
85 return nf_nat_protocol_register(&nf_nat_protocol_udplite);
86}
87
88static void __exit nf_nat_proto_udplite_fini(void)
89{
90 nf_nat_protocol_unregister(&nf_nat_protocol_udplite);
91}
92
93module_init(nf_nat_proto_udplite_init);
94module_exit(nf_nat_proto_udplite_fini);
95
96MODULE_LICENSE("GPL");
97MODULE_DESCRIPTION("UDP-Lite NAT protocol helper");
98MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c
deleted file mode 100644
index e0afe8112b1c..000000000000
--- a/net/ipv4/netfilter/nf_nat_proto_unknown.c
+++ /dev/null
@@ -1,52 +0,0 @@
1/* The "unknown" protocol. This is what is used for protocols we
2 * don't understand. It's returned by ip_ct_find_proto().
3 */
4
5/* (C) 1999-2001 Paul `Rusty' Russell
6 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/types.h>
14#include <linux/init.h>
15
16#include <linux/netfilter.h>
17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_nat_protocol.h>
20
21static bool unknown_in_range(const struct nf_conntrack_tuple *tuple,
22 enum nf_nat_manip_type manip_type,
23 const union nf_conntrack_man_proto *min,
24 const union nf_conntrack_man_proto *max)
25{
26 return true;
27}
28
29static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
30 const struct nf_nat_ipv4_range *range,
31 enum nf_nat_manip_type maniptype,
32 const struct nf_conn *ct)
33{
34 /* Sorry: we can't help you; if it's not unique, we can't frob
35 anything. */
36 return;
37}
38
39static bool
40unknown_manip_pkt(struct sk_buff *skb,
41 unsigned int iphdroff,
42 const struct nf_conntrack_tuple *tuple,
43 enum nf_nat_manip_type maniptype)
44{
45 return true;
46}
47
48const struct nf_nat_protocol nf_nat_unknown_protocol = {
49 .manip_pkt = unknown_manip_pkt,
50 .in_range = unknown_in_range,
51 .unique_tuple = unknown_unique_tuple,
52};
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
deleted file mode 100644
index d2a9dc314e0e..000000000000
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ /dev/null
@@ -1,214 +0,0 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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
9/* Everything about the rules for NAT. */
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11#include <linux/types.h>
12#include <linux/ip.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter_ipv4.h>
15#include <linux/module.h>
16#include <linux/kmod.h>
17#include <linux/skbuff.h>
18#include <linux/proc_fs.h>
19#include <linux/slab.h>
20#include <net/checksum.h>
21#include <net/route.h>
22#include <linux/bitops.h>
23
24#include <linux/netfilter_ipv4/ip_tables.h>
25#include <net/netfilter/nf_nat.h>
26#include <net/netfilter/nf_nat_core.h>
27#include <net/netfilter/nf_nat_rule.h>
28
29#define NAT_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
30 (1 << NF_INET_POST_ROUTING) | \
31 (1 << NF_INET_LOCAL_OUT) | \
32 (1 << NF_INET_LOCAL_IN))
33
34static const struct xt_table nat_table = {
35 .name = "nat",
36 .valid_hooks = NAT_VALID_HOOKS,
37 .me = THIS_MODULE,
38 .af = NFPROTO_IPV4,
39};
40
41/* Source NAT */
42static unsigned int
43ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
44{
45 struct nf_conn *ct;
46 enum ip_conntrack_info ctinfo;
47 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
48
49 NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING ||
50 par->hooknum == NF_INET_LOCAL_IN);
51
52 ct = nf_ct_get(skb, &ctinfo);
53
54 /* Connection must be valid and new. */
55 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
56 ctinfo == IP_CT_RELATED_REPLY));
57 NF_CT_ASSERT(par->out != NULL);
58
59 return nf_nat_setup_info(ct, &mr->range[0], NF_NAT_MANIP_SRC);
60}
61
62static unsigned int
63ipt_dnat_target(struct sk_buff *skb, const struct xt_action_param *par)
64{
65 struct nf_conn *ct;
66 enum ip_conntrack_info ctinfo;
67 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
68
69 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
70 par->hooknum == NF_INET_LOCAL_OUT);
71
72 ct = nf_ct_get(skb, &ctinfo);
73
74 /* Connection must be valid and new. */
75 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
76
77 return nf_nat_setup_info(ct, &mr->range[0], NF_NAT_MANIP_DST);
78}
79
80static int ipt_snat_checkentry(const struct xt_tgchk_param *par)
81{
82 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
83
84 /* Must be a valid range */
85 if (mr->rangesize != 1) {
86 pr_info("SNAT: multiple ranges no longer supported\n");
87 return -EINVAL;
88 }
89 return 0;
90}
91
92static int ipt_dnat_checkentry(const struct xt_tgchk_param *par)
93{
94 const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
95
96 /* Must be a valid range */
97 if (mr->rangesize != 1) {
98 pr_info("DNAT: multiple ranges no longer supported\n");
99 return -EINVAL;
100 }
101 return 0;
102}
103
104static unsigned int
105alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
106{
107 /* Force range to this IP; let proto decide mapping for
108 per-proto parts (hence not NF_NAT_RANGE_PROTO_SPECIFIED).
109 */
110 struct nf_nat_ipv4_range range;
111
112 range.flags = 0;
113 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
114 HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
115 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
116 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
117
118 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
119}
120
121int nf_nat_rule_find(struct sk_buff *skb,
122 unsigned int hooknum,
123 const struct net_device *in,
124 const struct net_device *out,
125 struct nf_conn *ct)
126{
127 struct net *net = nf_ct_net(ct);
128 int ret;
129
130 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
131
132 if (ret == NF_ACCEPT) {
133 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
134 /* NUL mapping */
135 ret = alloc_null_binding(ct, hooknum);
136 }
137 return ret;
138}
139
140static struct xt_target ipt_snat_reg __read_mostly = {
141 .name = "SNAT",
142 .target = ipt_snat_target,
143 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
144 .table = "nat",
145 .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN),
146 .checkentry = ipt_snat_checkentry,
147 .family = AF_INET,
148};
149
150static struct xt_target ipt_dnat_reg __read_mostly = {
151 .name = "DNAT",
152 .target = ipt_dnat_target,
153 .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
154 .table = "nat",
155 .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
156 .checkentry = ipt_dnat_checkentry,
157 .family = AF_INET,
158};
159
160static int __net_init nf_nat_rule_net_init(struct net *net)
161{
162 struct ipt_replace *repl;
163
164 repl = ipt_alloc_initial_table(&nat_table);
165 if (repl == NULL)
166 return -ENOMEM;
167 net->ipv4.nat_table = ipt_register_table(net, &nat_table, repl);
168 kfree(repl);
169 if (IS_ERR(net->ipv4.nat_table))
170 return PTR_ERR(net->ipv4.nat_table);
171 return 0;
172}
173
174static void __net_exit nf_nat_rule_net_exit(struct net *net)
175{
176 ipt_unregister_table(net, net->ipv4.nat_table);
177}
178
179static struct pernet_operations nf_nat_rule_net_ops = {
180 .init = nf_nat_rule_net_init,
181 .exit = nf_nat_rule_net_exit,
182};
183
184int __init nf_nat_rule_init(void)
185{
186 int ret;
187
188 ret = register_pernet_subsys(&nf_nat_rule_net_ops);
189 if (ret != 0)
190 goto out;
191 ret = xt_register_target(&ipt_snat_reg);
192 if (ret != 0)
193 goto unregister_table;
194
195 ret = xt_register_target(&ipt_dnat_reg);
196 if (ret != 0)
197 goto unregister_snat;
198
199 return ret;
200
201 unregister_snat:
202 xt_unregister_target(&ipt_snat_reg);
203 unregister_table:
204 unregister_pernet_subsys(&nf_nat_rule_net_ops);
205 out:
206 return ret;
207}
208
209void nf_nat_rule_cleanup(void)
210{
211 xt_unregister_target(&ipt_dnat_reg);
212 xt_unregister_target(&ipt_snat_reg);
213 unregister_pernet_subsys(&nf_nat_rule_net_ops);
214}
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
deleted file mode 100644
index 9c87cde28ff8..000000000000
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ /dev/null
@@ -1,572 +0,0 @@
1/* SIP extension for NAT alteration.
2 *
3 * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
4 * based on RR's ip_nat_ftp.c and other modules.
5 * (C) 2007 United Security Providers
6 * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/skbuff.h>
15#include <linux/ip.h>
16#include <net/ip.h>
17#include <linux/udp.h>
18#include <linux/tcp.h>
19
20#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_helper.h>
22#include <net/netfilter/nf_nat_rule.h>
23#include <net/netfilter/nf_conntrack_helper.h>
24#include <net/netfilter/nf_conntrack_expect.h>
25#include <linux/netfilter/nf_conntrack_sip.h>
26
27MODULE_LICENSE("GPL");
28MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
29MODULE_DESCRIPTION("SIP NAT helper");
30MODULE_ALIAS("ip_nat_sip");
31
32
33static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
34 const char **dptr, unsigned int *datalen,
35 unsigned int matchoff, unsigned int matchlen,
36 const char *buffer, unsigned int buflen)
37{
38 enum ip_conntrack_info ctinfo;
39 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
40 struct tcphdr *th;
41 unsigned int baseoff;
42
43 if (nf_ct_protonum(ct) == IPPROTO_TCP) {
44 th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
45 baseoff = ip_hdrlen(skb) + th->doff * 4;
46 matchoff += dataoff - baseoff;
47
48 if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
49 matchoff, matchlen,
50 buffer, buflen, false))
51 return 0;
52 } else {
53 baseoff = ip_hdrlen(skb) + sizeof(struct udphdr);
54 matchoff += dataoff - baseoff;
55
56 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
57 matchoff, matchlen,
58 buffer, buflen))
59 return 0;
60 }
61
62 /* Reload data pointer and adjust datalen value */
63 *dptr = skb->data + dataoff;
64 *datalen += buflen - matchlen;
65 return 1;
66}
67
68static int map_addr(struct sk_buff *skb, unsigned int dataoff,
69 const char **dptr, unsigned int *datalen,
70 unsigned int matchoff, unsigned int matchlen,
71 union nf_inet_addr *addr, __be16 port)
72{
73 enum ip_conntrack_info ctinfo;
74 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
75 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
76 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
77 unsigned int buflen;
78 __be32 newaddr;
79 __be16 newport;
80
81 if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip &&
82 ct->tuplehash[dir].tuple.src.u.udp.port == port) {
83 newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip;
84 newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
85 } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
86 ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
87 newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
88 newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
89 } else
90 return 1;
91
92 if (newaddr == addr->ip && newport == port)
93 return 1;
94
95 buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport));
96
97 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
98 buffer, buflen);
99}
100
101static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff,
102 const char **dptr, unsigned int *datalen,
103 enum sip_header_types type)
104{
105 enum ip_conntrack_info ctinfo;
106 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
107 unsigned int matchlen, matchoff;
108 union nf_inet_addr addr;
109 __be16 port;
110
111 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
112 &matchoff, &matchlen, &addr, &port) <= 0)
113 return 1;
114 return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
115 &addr, port);
116}
117
118static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
119 const char **dptr, unsigned int *datalen)
120{
121 enum ip_conntrack_info ctinfo;
122 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
123 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
124 unsigned int coff, matchoff, matchlen;
125 enum sip_header_types hdr;
126 union nf_inet_addr addr;
127 __be16 port;
128 int request, in_header;
129
130 /* Basic rules: requests and responses. */
131 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
132 if (ct_sip_parse_request(ct, *dptr, *datalen,
133 &matchoff, &matchlen,
134 &addr, &port) > 0 &&
135 !map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
136 &addr, port))
137 return NF_DROP;
138 request = 1;
139 } else
140 request = 0;
141
142 if (nf_ct_protonum(ct) == IPPROTO_TCP)
143 hdr = SIP_HDR_VIA_TCP;
144 else
145 hdr = SIP_HDR_VIA_UDP;
146
147 /* Translate topmost Via header and parameters */
148 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
149 hdr, NULL, &matchoff, &matchlen,
150 &addr, &port) > 0) {
151 unsigned int olen, matchend, poff, plen, buflen, n;
152 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
153
154 /* We're only interested in headers related to this
155 * connection */
156 if (request) {
157 if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip ||
158 port != ct->tuplehash[dir].tuple.src.u.udp.port)
159 goto next;
160 } else {
161 if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip ||
162 port != ct->tuplehash[dir].tuple.dst.u.udp.port)
163 goto next;
164 }
165
166 olen = *datalen;
167 if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
168 &addr, port))
169 return NF_DROP;
170
171 matchend = matchoff + matchlen + *datalen - olen;
172
173 /* The maddr= parameter (RFC 2361) specifies where to send
174 * the reply. */
175 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
176 "maddr=", &poff, &plen,
177 &addr, true) > 0 &&
178 addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
179 addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
180 buflen = sprintf(buffer, "%pI4",
181 &ct->tuplehash[!dir].tuple.dst.u3.ip);
182 if (!mangle_packet(skb, dataoff, dptr, datalen,
183 poff, plen, buffer, buflen))
184 return NF_DROP;
185 }
186
187 /* The received= parameter (RFC 2361) contains the address
188 * from which the server received the request. */
189 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
190 "received=", &poff, &plen,
191 &addr, false) > 0 &&
192 addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
193 addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
194 buflen = sprintf(buffer, "%pI4",
195 &ct->tuplehash[!dir].tuple.src.u3.ip);
196 if (!mangle_packet(skb, dataoff, dptr, datalen,
197 poff, plen, buffer, buflen))
198 return NF_DROP;
199 }
200
201 /* The rport= parameter (RFC 3581) contains the port number
202 * from which the server received the request. */
203 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
204 "rport=", &poff, &plen,
205 &n) > 0 &&
206 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
207 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
208 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
209 buflen = sprintf(buffer, "%u", ntohs(p));
210 if (!mangle_packet(skb, dataoff, dptr, datalen,
211 poff, plen, buffer, buflen))
212 return NF_DROP;
213 }
214 }
215
216next:
217 /* Translate Contact headers */
218 coff = 0;
219 in_header = 0;
220 while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
221 SIP_HDR_CONTACT, &in_header,
222 &matchoff, &matchlen,
223 &addr, &port) > 0) {
224 if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
225 &addr, port))
226 return NF_DROP;
227 }
228
229 if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) ||
230 !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
231 return NF_DROP;
232
233 return NF_ACCEPT;
234}
235
236static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off)
237{
238 enum ip_conntrack_info ctinfo;
239 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
240 const struct tcphdr *th;
241
242 if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
243 return;
244
245 th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
246 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
247}
248
249/* Handles expected signalling connections and media streams */
250static void ip_nat_sip_expected(struct nf_conn *ct,
251 struct nf_conntrack_expect *exp)
252{
253 struct nf_nat_ipv4_range range;
254
255 /* This must be a fresh one. */
256 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
257
258 /* For DST manip, map port here to where it's expected. */
259 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
260 range.min = range.max = exp->saved_proto;
261 range.min_ip = range.max_ip = exp->saved_ip;
262 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
263
264 /* Change src to where master sends to, but only if the connection
265 * actually came from the same source. */
266 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
267 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
268 range.flags = NF_NAT_RANGE_MAP_IPS;
269 range.min_ip = range.max_ip
270 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
271 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
272 }
273}
274
275static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
276 const char **dptr, unsigned int *datalen,
277 struct nf_conntrack_expect *exp,
278 unsigned int matchoff,
279 unsigned int matchlen)
280{
281 enum ip_conntrack_info ctinfo;
282 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
283 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
284 __be32 newip;
285 u_int16_t port;
286 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
287 unsigned int buflen;
288
289 /* Connection will come from reply */
290 if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
291 newip = exp->tuple.dst.u3.ip;
292 else
293 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
294
295 /* If the signalling port matches the connection's source port in the
296 * original direction, try to use the destination port in the opposite
297 * direction. */
298 if (exp->tuple.dst.u.udp.port ==
299 ct->tuplehash[dir].tuple.src.u.udp.port)
300 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
301 else
302 port = ntohs(exp->tuple.dst.u.udp.port);
303
304 exp->saved_ip = exp->tuple.dst.u3.ip;
305 exp->tuple.dst.u3.ip = newip;
306 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
307 exp->dir = !dir;
308 exp->expectfn = ip_nat_sip_expected;
309
310 for (; port != 0; port++) {
311 int ret;
312
313 exp->tuple.dst.u.udp.port = htons(port);
314 ret = nf_ct_expect_related(exp);
315 if (ret == 0)
316 break;
317 else if (ret != -EBUSY) {
318 port = 0;
319 break;
320 }
321 }
322
323 if (port == 0)
324 return NF_DROP;
325
326 if (exp->tuple.dst.u3.ip != exp->saved_ip ||
327 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
328 buflen = sprintf(buffer, "%pI4:%u", &newip, port);
329 if (!mangle_packet(skb, dataoff, dptr, datalen,
330 matchoff, matchlen, buffer, buflen))
331 goto err;
332 }
333 return NF_ACCEPT;
334
335err:
336 nf_ct_unexpect_related(exp);
337 return NF_DROP;
338}
339
340static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff,
341 const char **dptr, unsigned int *datalen)
342{
343 enum ip_conntrack_info ctinfo;
344 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
345 unsigned int matchoff, matchlen;
346 char buffer[sizeof("65536")];
347 int buflen, c_len;
348
349 /* Get actual SDP length */
350 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
351 SDP_HDR_VERSION, SDP_HDR_UNSPEC,
352 &matchoff, &matchlen) <= 0)
353 return 0;
354 c_len = *datalen - matchoff + strlen("v=");
355
356 /* Now, update SDP length */
357 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
358 &matchoff, &matchlen) <= 0)
359 return 0;
360
361 buflen = sprintf(buffer, "%u", c_len);
362 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
363 buffer, buflen);
364}
365
366static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
367 const char **dptr, unsigned int *datalen,
368 unsigned int sdpoff,
369 enum sdp_header_types type,
370 enum sdp_header_types term,
371 char *buffer, int buflen)
372{
373 enum ip_conntrack_info ctinfo;
374 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
375 unsigned int matchlen, matchoff;
376
377 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
378 &matchoff, &matchlen) <= 0)
379 return -ENOENT;
380 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
381 buffer, buflen) ? 0 : -EINVAL;
382}
383
384static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff,
385 const char **dptr, unsigned int *datalen,
386 unsigned int sdpoff,
387 enum sdp_header_types type,
388 enum sdp_header_types term,
389 const union nf_inet_addr *addr)
390{
391 char buffer[sizeof("nnn.nnn.nnn.nnn")];
392 unsigned int buflen;
393
394 buflen = sprintf(buffer, "%pI4", &addr->ip);
395 if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term,
396 buffer, buflen))
397 return 0;
398
399 return mangle_content_len(skb, dataoff, dptr, datalen);
400}
401
402static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff,
403 const char **dptr, unsigned int *datalen,
404 unsigned int matchoff,
405 unsigned int matchlen,
406 u_int16_t port)
407{
408 char buffer[sizeof("nnnnn")];
409 unsigned int buflen;
410
411 buflen = sprintf(buffer, "%u", port);
412 if (!mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
413 buffer, buflen))
414 return 0;
415
416 return mangle_content_len(skb, dataoff, dptr, datalen);
417}
418
419static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff,
420 const char **dptr, unsigned int *datalen,
421 unsigned int sdpoff,
422 const union nf_inet_addr *addr)
423{
424 char buffer[sizeof("nnn.nnn.nnn.nnn")];
425 unsigned int buflen;
426
427 /* Mangle session description owner and contact addresses */
428 buflen = sprintf(buffer, "%pI4", &addr->ip);
429 if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
430 SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
431 buffer, buflen))
432 return 0;
433
434 switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
435 SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
436 buffer, buflen)) {
437 case 0:
438 /*
439 * RFC 2327:
440 *
441 * Session description
442 *
443 * c=* (connection information - not required if included in all media)
444 */
445 case -ENOENT:
446 break;
447 default:
448 return 0;
449 }
450
451 return mangle_content_len(skb, dataoff, dptr, datalen);
452}
453
454/* So, this packet has hit the connection tracking matching code.
455 Mangle it, and change the expectation to match the new version. */
456static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
457 const char **dptr, unsigned int *datalen,
458 struct nf_conntrack_expect *rtp_exp,
459 struct nf_conntrack_expect *rtcp_exp,
460 unsigned int mediaoff,
461 unsigned int medialen,
462 union nf_inet_addr *rtp_addr)
463{
464 enum ip_conntrack_info ctinfo;
465 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
466 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
467 u_int16_t port;
468
469 /* Connection will come from reply */
470 if (ct->tuplehash[dir].tuple.src.u3.ip ==
471 ct->tuplehash[!dir].tuple.dst.u3.ip)
472 rtp_addr->ip = rtp_exp->tuple.dst.u3.ip;
473 else
474 rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
475
476 rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
477 rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
478 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
479 rtp_exp->dir = !dir;
480 rtp_exp->expectfn = ip_nat_sip_expected;
481
482 rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
483 rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
484 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
485 rtcp_exp->dir = !dir;
486 rtcp_exp->expectfn = ip_nat_sip_expected;
487
488 /* Try to get same pair of ports: if not, try to change them. */
489 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
490 port != 0; port += 2) {
491 int ret;
492
493 rtp_exp->tuple.dst.u.udp.port = htons(port);
494 ret = nf_ct_expect_related(rtp_exp);
495 if (ret == -EBUSY)
496 continue;
497 else if (ret < 0) {
498 port = 0;
499 break;
500 }
501 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
502 ret = nf_ct_expect_related(rtcp_exp);
503 if (ret == 0)
504 break;
505 else if (ret == -EBUSY) {
506 nf_ct_unexpect_related(rtp_exp);
507 continue;
508 } else if (ret < 0) {
509 nf_ct_unexpect_related(rtp_exp);
510 port = 0;
511 break;
512 }
513 }
514
515 if (port == 0)
516 goto err1;
517
518 /* Update media port. */
519 if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
520 !ip_nat_sdp_port(skb, dataoff, dptr, datalen,
521 mediaoff, medialen, port))
522 goto err2;
523
524 return NF_ACCEPT;
525
526err2:
527 nf_ct_unexpect_related(rtp_exp);
528 nf_ct_unexpect_related(rtcp_exp);
529err1:
530 return NF_DROP;
531}
532
533static struct nf_ct_helper_expectfn sip_nat = {
534 .name = "sip",
535 .expectfn = ip_nat_sip_expected,
536};
537
538static void __exit nf_nat_sip_fini(void)
539{
540 RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
541 RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL);
542 RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL);
543 RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL);
544 RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
545 RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
546 RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
547 nf_ct_helper_expectfn_unregister(&sip_nat);
548 synchronize_rcu();
549}
550
551static int __init nf_nat_sip_init(void)
552{
553 BUG_ON(nf_nat_sip_hook != NULL);
554 BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
555 BUG_ON(nf_nat_sip_expect_hook != NULL);
556 BUG_ON(nf_nat_sdp_addr_hook != NULL);
557 BUG_ON(nf_nat_sdp_port_hook != NULL);
558 BUG_ON(nf_nat_sdp_session_hook != NULL);
559 BUG_ON(nf_nat_sdp_media_hook != NULL);
560 RCU_INIT_POINTER(nf_nat_sip_hook, ip_nat_sip);
561 RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust);
562 RCU_INIT_POINTER(nf_nat_sip_expect_hook, ip_nat_sip_expect);
563 RCU_INIT_POINTER(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
564 RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port);
565 RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session);
566 RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media);
567 nf_ct_helper_expectfn_register(&sip_nat);
568 return 0;
569}
570
571module_init(nf_nat_sip_init);
572module_exit(nf_nat_sip_fini);
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
deleted file mode 100644
index 9dbb8d284f99..000000000000
--- a/net/ipv4/netfilter/nf_nat_tftp.c
+++ /dev/null
@@ -1,51 +0,0 @@
1/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 */
7
8#include <linux/module.h>
9#include <linux/udp.h>
10
11#include <net/netfilter/nf_conntrack_helper.h>
12#include <net/netfilter/nf_conntrack_expect.h>
13#include <net/netfilter/nf_nat_helper.h>
14#include <net/netfilter/nf_nat_rule.h>
15#include <linux/netfilter/nf_conntrack_tftp.h>
16
17MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
18MODULE_DESCRIPTION("TFTP NAT helper");
19MODULE_LICENSE("GPL");
20MODULE_ALIAS("ip_nat_tftp");
21
22static unsigned int help(struct sk_buff *skb,
23 enum ip_conntrack_info ctinfo,
24 struct nf_conntrack_expect *exp)
25{
26 const struct nf_conn *ct = exp->master;
27
28 exp->saved_proto.udp.port
29 = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
30 exp->dir = IP_CT_DIR_REPLY;
31 exp->expectfn = nf_nat_follow_master;
32 if (nf_ct_expect_related(exp) != 0)
33 return NF_DROP;
34 return NF_ACCEPT;
35}
36
37static void __exit nf_nat_tftp_fini(void)
38{
39 RCU_INIT_POINTER(nf_nat_tftp_hook, NULL);
40 synchronize_rcu();
41}
42
43static int __init nf_nat_tftp_init(void)
44{
45 BUG_ON(nf_nat_tftp_hook != NULL);
46 RCU_INIT_POINTER(nf_nat_tftp_hook, help);
47 return 0;
48}
49
50module_init(nf_nat_tftp_init);
51module_exit(nf_nat_tftp_fini);