Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nf_nat_proto_tcp.c
Go to the documentation of this file.
1 /* (C) 1999-2001 Paul `Rusty' Russell
2  * (C) 2002-2006 Netfilter Core Team <[email protected]>
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/tcp.h>
13 
14 #include <linux/netfilter.h>
16 #include <net/netfilter/nf_nat.h>
20 
21 static u16 tcp_port_rover;
22 
23 static void
24 tcp_unique_tuple(const struct nf_nat_l3proto *l3proto,
25  struct nf_conntrack_tuple *tuple,
26  const struct nf_nat_range *range,
27  enum nf_nat_manip_type maniptype,
28  const struct nf_conn *ct)
29 {
30  nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
31  &tcp_port_rover);
32 }
33 
34 static bool
35 tcp_manip_pkt(struct sk_buff *skb,
36  const struct nf_nat_l3proto *l3proto,
37  unsigned int iphdroff, unsigned int hdroff,
38  const struct nf_conntrack_tuple *tuple,
39  enum nf_nat_manip_type maniptype)
40 {
41  struct tcphdr *hdr;
42  __be16 *portptr, newport, oldport;
43  int hdrsize = 8; /* TCP connection tracking guarantees this much */
44 
45  /* this could be a inner header returned in icmp packet; in such
46  cases we cannot update the checksum field since it is outside of
47  the 8 bytes of transport layer headers we are guaranteed */
48  if (skb->len >= hdroff + sizeof(struct tcphdr))
49  hdrsize = sizeof(struct tcphdr);
50 
51  if (!skb_make_writable(skb, hdroff + hdrsize))
52  return false;
53 
54  hdr = (struct tcphdr *)(skb->data + hdroff);
55 
56  if (maniptype == NF_NAT_MANIP_SRC) {
57  /* Get rid of src port */
58  newport = tuple->src.u.tcp.port;
59  portptr = &hdr->source;
60  } else {
61  /* Get rid of dst port */
62  newport = tuple->dst.u.tcp.port;
63  portptr = &hdr->dest;
64  }
65 
66  oldport = *portptr;
67  *portptr = newport;
68 
69  if (hdrsize < sizeof(*hdr))
70  return true;
71 
72  l3proto->csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
73  inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0);
74  return true;
75 }
76 
78  .l4proto = IPPROTO_TCP,
79  .manip_pkt = tcp_manip_pkt,
80  .in_range = nf_nat_l4proto_in_range,
81  .unique_tuple = tcp_unique_tuple,
82 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
83  .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
84 #endif
85 };