diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2006-12-03 01:07:13 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-12-03 01:07:13 -0500 |
commit | 5b1158e909ecbe1a052203e0d8df15633f829930 (patch) | |
tree | 1d29320fd6184b982b1a8a83e7e1e9f25537d3ff /net/ipv4/netfilter/nf_nat_proto_tcp.c | |
parent | d2483ddefd38b06053cdce7206382ca61f6282b1 (diff) |
[NETFILTER]: Add NAT support for nf_conntrack
Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik,
Yasuyuki Kozakai, Martin Josefsson and myself.
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/netfilter/nf_nat_proto_tcp.c')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_proto_tcp.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c new file mode 100644 index 00000000000..7e26a7e9bee --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c | |||
@@ -0,0 +1,148 @@ | |||
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/ip.h> | ||
12 | #include <linux/tcp.h> | ||
13 | |||
14 | #include <linux/netfilter.h> | ||
15 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/nf_nat_rule.h> | ||
18 | #include <net/netfilter/nf_nat_protocol.h> | ||
19 | #include <net/netfilter/nf_nat_core.h> | ||
20 | |||
21 | static int | ||
22 | tcp_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 == IP_NAT_MANIP_SRC) | ||
30 | port = tuple->src.u.tcp.port; | ||
31 | else | ||
32 | port = tuple->dst.u.tcp.port; | ||
33 | |||
34 | return ntohs(port) >= ntohs(min->tcp.port) && | ||
35 | ntohs(port) <= ntohs(max->tcp.port); | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | tcp_unique_tuple(struct nf_conntrack_tuple *tuple, | ||
40 | const struct nf_nat_range *range, | ||
41 | enum nf_nat_manip_type maniptype, | ||
42 | const struct nf_conn *ct) | ||
43 | { | ||
44 | static u_int16_t port; | ||
45 | __be16 *portptr; | ||
46 | unsigned int range_size, min, i; | ||
47 | |||
48 | if (maniptype == IP_NAT_MANIP_SRC) | ||
49 | portptr = &tuple->src.u.tcp.port; | ||
50 | else | ||
51 | portptr = &tuple->dst.u.tcp.port; | ||
52 | |||
53 | /* If no range specified... */ | ||
54 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
55 | /* If it's dst rewrite, can't change port */ | ||
56 | if (maniptype == IP_NAT_MANIP_DST) | ||
57 | return 0; | ||
58 | |||
59 | /* Map privileged onto privileged. */ | ||
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.tcp.port); | ||
75 | range_size = ntohs(range->max.tcp.port) - min + 1; | ||
76 | } | ||
77 | |||
78 | for (i = 0; i < range_size; i++, port++) { | ||
79 | *portptr = htons(min + port % range_size); | ||
80 | if (!nf_nat_used_tuple(tuple, ct)) | ||
81 | return 1; | ||
82 | } | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | tcp_manip_pkt(struct sk_buff **pskb, | ||
88 | unsigned int iphdroff, | ||
89 | const struct nf_conntrack_tuple *tuple, | ||
90 | enum nf_nat_manip_type maniptype) | ||
91 | { | ||
92 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
93 | struct tcphdr *hdr; | ||
94 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
95 | __be32 oldip, newip; | ||
96 | __be16 *portptr, newport, oldport; | ||
97 | int hdrsize = 8; /* TCP connection tracking guarantees this much */ | ||
98 | |||
99 | /* this could be a inner header returned in icmp packet; in such | ||
100 | cases we cannot update the checksum field since it is outside of | ||
101 | the 8 bytes of transport layer headers we are guaranteed */ | ||
102 | if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) | ||
103 | hdrsize = sizeof(struct tcphdr); | ||
104 | |||
105 | if (!skb_make_writable(pskb, hdroff + hdrsize)) | ||
106 | return 0; | ||
107 | |||
108 | iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
109 | hdr = (struct tcphdr *)((*pskb)->data + hdroff); | ||
110 | |||
111 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
112 | /* Get rid of src ip and src pt */ | ||
113 | oldip = iph->saddr; | ||
114 | newip = tuple->src.u3.ip; | ||
115 | newport = tuple->src.u.tcp.port; | ||
116 | portptr = &hdr->source; | ||
117 | } else { | ||
118 | /* Get rid of dst ip and dst pt */ | ||
119 | oldip = iph->daddr; | ||
120 | newip = tuple->dst.u3.ip; | ||
121 | newport = tuple->dst.u.tcp.port; | ||
122 | portptr = &hdr->dest; | ||
123 | } | ||
124 | |||
125 | oldport = *portptr; | ||
126 | *portptr = newport; | ||
127 | |||
128 | if (hdrsize < sizeof(*hdr)) | ||
129 | return 1; | ||
130 | |||
131 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); | ||
132 | nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | struct nf_nat_protocol nf_nat_protocol_tcp = { | ||
137 | .name = "TCP", | ||
138 | .protonum = IPPROTO_TCP, | ||
139 | .me = THIS_MODULE, | ||
140 | .manip_pkt = tcp_manip_pkt, | ||
141 | .in_range = tcp_in_range, | ||
142 | .unique_tuple = tcp_unique_tuple, | ||
143 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
144 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
145 | .range_to_nfattr = nf_nat_port_range_to_nfattr, | ||
146 | .nfattr_to_range = nf_nat_port_nfattr_to_range, | ||
147 | #endif | ||
148 | }; | ||