Blame view

net/ipv4/netfilter/nf_nat_proto_tcp.c 4 KB
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
1
2
3
4
5
6
7
8
9
10
  /* (C) 1999-2001 Paul `Rusty' Russell
   * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/types.h>
  #include <linux/init.h>
41f4689a7   Eric Leblond   [NETFILTER]: NAT:...
11
  #include <linux/random.h>
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  #include <linux/ip.h>
  #include <linux/tcp.h>
  
  #include <linux/netfilter.h>
  #include <linux/netfilter/nfnetlink_conntrack.h>
  #include <net/netfilter/nf_nat.h>
  #include <net/netfilter/nf_nat_rule.h>
  #include <net/netfilter/nf_nat_protocol.h>
  #include <net/netfilter/nf_nat_core.h>
  
  static int
  tcp_in_range(const struct nf_conntrack_tuple *tuple,
  	     enum nf_nat_manip_type maniptype,
  	     const union nf_conntrack_man_proto *min,
  	     const union nf_conntrack_man_proto *max)
  {
  	__be16 port;
  
  	if (maniptype == IP_NAT_MANIP_SRC)
  		port = tuple->src.u.tcp.port;
  	else
  		port = tuple->dst.u.tcp.port;
  
  	return ntohs(port) >= ntohs(min->tcp.port) &&
  	       ntohs(port) <= ntohs(max->tcp.port);
  }
  
  static int
  tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
  		 const struct nf_nat_range *range,
  		 enum nf_nat_manip_type maniptype,
  		 const struct nf_conn *ct)
  {
  	static u_int16_t port;
  	__be16 *portptr;
  	unsigned int range_size, min, i;
  
  	if (maniptype == IP_NAT_MANIP_SRC)
  		portptr = &tuple->src.u.tcp.port;
  	else
  		portptr = &tuple->dst.u.tcp.port;
  
  	/* If no range specified... */
  	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
  		/* If it's dst rewrite, can't change port */
  		if (maniptype == IP_NAT_MANIP_DST)
  			return 0;
  
  		/* Map privileged onto privileged. */
  		if (ntohs(*portptr) < 1024) {
  			/* Loose convention: >> 512 is credential passing */
  			if (ntohs(*portptr)<512) {
  				min = 1;
  				range_size = 511 - min + 1;
  			} else {
  				min = 600;
  				range_size = 1023 - min + 1;
  			}
  		} else {
  			min = 1024;
  			range_size = 65535 - 1024 + 1;
  		}
  	} else {
  		min = ntohs(range->min.tcp.port);
  		range_size = ntohs(range->max.tcp.port) - min + 1;
  	}
41f4689a7   Eric Leblond   [NETFILTER]: NAT:...
78
79
  	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
  		port =  net_random();
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
80
81
82
83
84
85
86
87
88
  	for (i = 0; i < range_size; i++, port++) {
  		*portptr = htons(min + port % range_size);
  		if (!nf_nat_used_tuple(tuple, ct))
  			return 1;
  	}
  	return 0;
  }
  
  static int
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
89
  tcp_manip_pkt(struct sk_buff *skb,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
90
91
92
93
  	      unsigned int iphdroff,
  	      const struct nf_conntrack_tuple *tuple,
  	      enum nf_nat_manip_type maniptype)
  {
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
94
  	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
95
96
97
98
99
100
101
102
103
  	struct tcphdr *hdr;
  	unsigned int hdroff = iphdroff + iph->ihl*4;
  	__be32 oldip, newip;
  	__be16 *portptr, newport, oldport;
  	int hdrsize = 8; /* TCP connection tracking guarantees this much */
  
  	/* this could be a inner header returned in icmp packet; in such
  	   cases we cannot update the checksum field since it is outside of
  	   the 8 bytes of transport layer headers we are guaranteed */
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
104
  	if (skb->len >= hdroff + sizeof(struct tcphdr))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
105
  		hdrsize = sizeof(struct tcphdr);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
106
  	if (!skb_make_writable(skb, hdroff + hdrsize))
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
107
  		return 0;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
108
109
  	iph = (struct iphdr *)(skb->data + iphdroff);
  	hdr = (struct tcphdr *)(skb->data + hdroff);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  
  	if (maniptype == IP_NAT_MANIP_SRC) {
  		/* Get rid of src ip and src pt */
  		oldip = iph->saddr;
  		newip = tuple->src.u3.ip;
  		newport = tuple->src.u.tcp.port;
  		portptr = &hdr->source;
  	} else {
  		/* Get rid of dst ip and dst pt */
  		oldip = iph->daddr;
  		newip = tuple->dst.u3.ip;
  		newport = tuple->dst.u.tcp.port;
  		portptr = &hdr->dest;
  	}
  
  	oldport = *portptr;
  	*portptr = newport;
  
  	if (hdrsize < sizeof(*hdr))
  		return 1;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
130
131
  	nf_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
  	nf_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0);
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
132
133
134
135
136
137
138
139
140
141
  	return 1;
  }
  
  struct nf_nat_protocol nf_nat_protocol_tcp = {
  	.name			= "TCP",
  	.protonum		= IPPROTO_TCP,
  	.me			= THIS_MODULE,
  	.manip_pkt		= tcp_manip_pkt,
  	.in_range		= tcp_in_range,
  	.unique_tuple		= tcp_unique_tuple,
e281db5cd   Patrick McHardy   [NETFILTER]: nf_c...
142
  #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
fdf708322   Patrick McHardy   [NETFILTER]: nfne...
143
144
  	.range_to_nlattr	= nf_nat_port_range_to_nlattr,
  	.nlattr_to_range	= nf_nat_port_nlattr_to_range,
5b1158e90   Jozsef Kadlecsik   [NETFILTER]: Add ...
145
146
  #endif
  };