Commit | Line | Data |
---|---|---|
5b1158e9 JK |
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> | |
bc3b2d7f | 11 | #include <linux/export.h> |
5b1158e9 JK |
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 | ||
937e0dfd | 22 | static u_int16_t tcp_port_rover; |
5b1158e9 | 23 | |
f43dc98b | 24 | static void |
5b1158e9 | 25 | tcp_unique_tuple(struct nf_conntrack_tuple *tuple, |
cbc9f2f4 | 26 | const struct nf_nat_ipv4_range *range, |
5b1158e9 JK |
27 | enum nf_nat_manip_type maniptype, |
28 | const struct nf_conn *ct) | |
29 | { | |
f43dc98b | 30 | nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover); |
5b1158e9 JK |
31 | } |
32 | ||
f2ea825f | 33 | static bool |
3db05fea | 34 | tcp_manip_pkt(struct sk_buff *skb, |
5b1158e9 JK |
35 | unsigned int iphdroff, |
36 | const struct nf_conntrack_tuple *tuple, | |
37 | enum nf_nat_manip_type maniptype) | |
38 | { | |
82f568fc | 39 | const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); |
5b1158e9 JK |
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 */ | |
3db05fea | 49 | if (skb->len >= hdroff + sizeof(struct tcphdr)) |
5b1158e9 JK |
50 | hdrsize = sizeof(struct tcphdr); |
51 | ||
3db05fea | 52 | if (!skb_make_writable(skb, hdroff + hdrsize)) |
f2ea825f | 53 | return false; |
5b1158e9 | 54 | |
3db05fea HX |
55 | iph = (struct iphdr *)(skb->data + iphdroff); |
56 | hdr = (struct tcphdr *)(skb->data + hdroff); | |
5b1158e9 | 57 | |
cbc9f2f4 | 58 | if (maniptype == NF_NAT_MANIP_SRC) { |
5b1158e9 JK |
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)) | |
f2ea825f | 76 | return true; |
5b1158e9 | 77 | |
be0ea7d5 PM |
78 | inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1); |
79 | inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0); | |
f2ea825f | 80 | return true; |
5b1158e9 JK |
81 | } |
82 | ||
2b628a08 | 83 | const struct nf_nat_protocol nf_nat_protocol_tcp = { |
5b1158e9 | 84 | .protonum = IPPROTO_TCP, |
5b1158e9 | 85 | .manip_pkt = tcp_manip_pkt, |
937e0dfd | 86 | .in_range = nf_nat_proto_in_range, |
5b1158e9 | 87 | .unique_tuple = tcp_unique_tuple, |
e281db5c | 88 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
535b57c7 | 89 | .nlattr_to_range = nf_nat_proto_nlattr_to_range, |
5b1158e9 JK |
90 | #endif |
91 | }; |