commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / net / ipv4 / netfilter / ip_nat_proto_tcp.c
1 #include <linux/types.h>
2 #include <linux/init.h>
3 #include <linux/netfilter.h>
4 #include <linux/ip.h>
5 #include <linux/tcp.h>
6 #include <linux/if.h>
7 #include <linux/netfilter_ipv4/ip_nat.h>
8 #include <linux/netfilter_ipv4/ip_nat_rule.h>
9 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
10 #include <linux/netfilter_ipv4/ip_nat_core.h>
11
12 static int
13 tcp_in_range(const struct ip_conntrack_tuple *tuple,
14              enum ip_nat_manip_type maniptype,
15              const union ip_conntrack_manip_proto *min,
16              const union ip_conntrack_manip_proto *max)
17 {
18         u_int16_t port;
19
20         if (maniptype == IP_NAT_MANIP_SRC)
21                 port = tuple->src.u.tcp.port;
22         else
23                 port = tuple->dst.u.tcp.port;
24
25         return ntohs(port) >= ntohs(min->tcp.port)
26                 && ntohs(port) <= ntohs(max->tcp.port);
27 }
28
29 static int
30 tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
31                  const struct ip_nat_range *range,
32                  enum ip_nat_manip_type maniptype,
33                  const struct ip_conntrack *conntrack)
34 {
35         static u_int16_t port, *portptr;
36         unsigned int range_size, min, i;
37
38         if (maniptype == IP_NAT_MANIP_SRC)
39                 portptr = &tuple->src.u.tcp.port;
40         else
41                 portptr = &tuple->dst.u.tcp.port;
42
43         /* If no range specified... */
44         if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
45                 /* If it's dst rewrite, can't change port */
46                 if (maniptype == IP_NAT_MANIP_DST)
47                         return 0;
48
49                 /* Map privileged onto privileged. */
50                 if (ntohs(*portptr) < 1024) {
51                         /* Loose convention: >> 512 is credential passing */
52                         if (ntohs(*portptr)<512) {
53                                 min = 1;
54                                 range_size = 511 - min + 1;
55                         } else {
56                                 min = 600;
57                                 range_size = 1023 - min + 1;
58                         }
59                 } else {
60                         min = 1024;
61                         range_size = 65535 - 1024 + 1;
62                 }
63         } else {
64                 min = ntohs(range->min.tcp.port);
65                 range_size = ntohs(range->max.tcp.port) - min + 1;
66         }
67
68         for (i = 0; i < range_size; i++, port++) {
69                 *portptr = htons(min + port % range_size);
70                 if (!ip_nat_used_tuple(tuple, conntrack)) {
71                         return 1;
72                 }
73         }
74         return 0;
75 }
76
77 static int
78 tcp_manip_pkt(struct sk_buff **pskb,
79               unsigned int hdroff,
80               const struct ip_conntrack_manip *manip,
81               enum ip_nat_manip_type maniptype)
82 {
83         struct tcphdr *hdr;
84         u_int32_t oldip;
85         u_int16_t *portptr, oldport;
86         int hdrsize = 8; /* TCP connection tracking guarantees this much */
87
88         /* this could be a inner header returned in icmp packet; in such
89            cases we cannot update the checksum field since it is outside of
90            the 8 bytes of transport layer headers we are guaranteed */
91         if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
92                 hdrsize = sizeof(struct tcphdr);
93
94         if (!skb_ip_make_writable(pskb, hdroff + hdrsize))
95                 return 0;
96
97         hdr = (void *)(*pskb)->data + hdroff;
98
99         if (maniptype == IP_NAT_MANIP_SRC) {
100                 /* Get rid of src ip and src pt */
101                 oldip = (*pskb)->nh.iph->saddr;
102                 portptr = &hdr->source;
103         } else {
104                 /* Get rid of dst ip and dst pt */
105                 oldip = (*pskb)->nh.iph->daddr;
106                 portptr = &hdr->dest;
107         }
108
109         oldport = *portptr;
110         *portptr = manip->u.tcp.port;
111
112         if (hdrsize < sizeof(*hdr))
113                 return 1;
114
115         hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
116                                         ip_nat_cheat_check(oldport ^ 0xFFFF,
117                                                            manip->u.tcp.port,
118                                                            hdr->check));
119         return 1;
120 }
121
122 static unsigned int
123 tcp_print(char *buffer,
124           const struct ip_conntrack_tuple *match,
125           const struct ip_conntrack_tuple *mask)
126 {
127         unsigned int len = 0;
128
129         if (mask->src.u.tcp.port)
130                 len += sprintf(buffer + len, "srcpt=%u ",
131                                ntohs(match->src.u.tcp.port));
132
133
134         if (mask->dst.u.tcp.port)
135                 len += sprintf(buffer + len, "dstpt=%u ",
136                                ntohs(match->dst.u.tcp.port));
137
138         return len;
139 }
140
141 static unsigned int
142 tcp_print_range(char *buffer, const struct ip_nat_range *range)
143 {
144         if (range->min.tcp.port != 0 || range->max.tcp.port != 0xFFFF) {
145                 if (range->min.tcp.port == range->max.tcp.port)
146                         return sprintf(buffer, "port %u ",
147                                        ntohs(range->min.tcp.port));
148                 else
149                         return sprintf(buffer, "ports %u-%u ",
150                                        ntohs(range->min.tcp.port),
151                                        ntohs(range->max.tcp.port));
152         }
153         else return 0;
154 }
155
156 struct ip_nat_protocol ip_nat_protocol_tcp
157 = { { NULL, NULL }, "TCP", IPPROTO_TCP,
158     tcp_manip_pkt,
159     tcp_in_range,
160     tcp_unique_tuple,
161     tcp_print,
162     tcp_print_range
163 };