2b52a7c9ec7b004561f00ad3306da1dae7dea04f
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_conntrack_gre.c
1 /*
2  * ip_conntrack_proto_gre.c - Version 1.2 
3  *
4  * Connection tracking protocol helper module for GRE.
5  *
6  * GRE is a generic encapsulation protocol, which is generally not very
7  * suited for NAT, as it has no protocol-specific part as port numbers.
8  *
9  * It has an optional key field, which may help us distinguishing two 
10  * connections between the same two hosts.
11  *
12  * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 
13  *
14  * PPTP is built on top of a modified version of GRE, and has a mandatory
15  * field called "CallID", which serves us for the same purpose as the key
16  * field in plain GRE.
17  *
18  * Documentation about PPTP can be found in RFC 2637
19  *
20  * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
21  *
22  * Development of this code funded by Astaro AG (http://www.astaro.com/)
23  *
24  */
25
26 #include <linux/config.h>
27 #include <linux/module.h>
28 #include <linux/types.h>
29 #include <linux/timer.h>
30 #include <linux/netfilter.h>
31 #include <linux/ip.h>
32 #include <linux/in.h>
33 #include <linux/list.h>
34
35 #include <linux/netfilter_ipv4/lockhelp.h>
36
37 DECLARE_RWLOCK(ip_ct_gre_lock);
38 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
39 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
40
41 #include <linux/netfilter_ipv4/listhelp.h>
42 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
43 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
44 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
45
46 #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
47 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
48
49 MODULE_LICENSE("GPL");
50 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
51 MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
52
53 /* shamelessly stolen from ip_conntrack_proto_udp.c */
54 #define GRE_TIMEOUT             (30*HZ)
55 #define GRE_STREAM_TIMEOUT      (180*HZ)
56
57 #if 0
58 #define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
59                                        ": " format, ## args)
60 #define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
61                         NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
62                         NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \
63                         (x)->dst.u.gre.version, \
64                         ntohs((x)->dst.u.gre.protocol))
65 #else
66 #define DEBUGP(x, args...)
67 #define DUMP_TUPLE_GRE(x)
68 #endif
69                                 
70 /* GRE KEYMAP HANDLING FUNCTIONS */
71 static LIST_HEAD(gre_keymap_list);
72
73 static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
74                                 const struct ip_conntrack_tuple *t)
75 {
76         return ((km->tuple.src.ip == t->src.ip) &&
77                 (km->tuple.dst.ip == t->dst.ip) &&
78                 (km->tuple.dst.protonum == t->dst.protonum) &&
79                 (km->tuple.dst.u.all == t->dst.u.all));
80 }
81
82 /* look up the source key for a given tuple */
83 static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
84 {
85         struct ip_ct_gre_keymap *km;
86         u_int32_t key;
87
88         READ_LOCK(&ip_ct_gre_lock);
89         km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
90                         struct ip_ct_gre_keymap *, t);
91         if (!km) {
92                 READ_UNLOCK(&ip_ct_gre_lock);
93                 return 0;
94         }
95
96         key = km->tuple.src.u.gre.key;
97         READ_UNLOCK(&ip_ct_gre_lock);
98
99         return key;
100 }
101
102 /* add a single keymap entry, associate with specified expect */
103 int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
104                          struct ip_conntrack_tuple *t, int reply)
105 {
106         struct ip_ct_gre_keymap *km;
107
108         km = kmalloc(sizeof(*km), GFP_ATOMIC);
109         if (!km)
110                 return -1;
111
112         /* initializing list head should be sufficient */
113         memset(km, 0, sizeof(*km));
114
115         memcpy(&km->tuple, t, sizeof(*t));
116
117         if (!reply)
118                 exp->proto.gre.keymap_orig = km;
119         else
120                 exp->proto.gre.keymap_reply = km;
121
122         DEBUGP("adding new entry %p: ", km);
123         DUMP_TUPLE_GRE(&km->tuple);
124
125         WRITE_LOCK(&ip_ct_gre_lock);
126         list_append(&gre_keymap_list, km);
127         WRITE_UNLOCK(&ip_ct_gre_lock);
128
129         return 0;
130 }
131
132 /* change the tuple of a keymap entry (used by nat helper) */
133 void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
134                              struct ip_conntrack_tuple *t)
135 {
136         DEBUGP("changing entry %p to: ", km);
137         DUMP_TUPLE_GRE(t);
138
139         WRITE_LOCK(&ip_ct_gre_lock);
140         memcpy(&km->tuple, t, sizeof(km->tuple));
141         WRITE_UNLOCK(&ip_ct_gre_lock);
142 }
143
144 /* destroy the keymap entries associated with specified expect */
145 void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
146 {
147         DEBUGP("entering for exp %p\n", exp);
148         WRITE_LOCK(&ip_ct_gre_lock);
149         if (exp->proto.gre.keymap_orig) {
150                 DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
151                 list_del(&exp->proto.gre.keymap_orig->list);
152                 kfree(exp->proto.gre.keymap_orig);
153                 exp->proto.gre.keymap_orig = NULL;
154         }
155         if (exp->proto.gre.keymap_reply) {
156                 DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
157                 list_del(&exp->proto.gre.keymap_reply->list);
158                 kfree(exp->proto.gre.keymap_reply);
159                 exp->proto.gre.keymap_reply = NULL;
160         }
161         WRITE_UNLOCK(&ip_ct_gre_lock);
162 }
163
164
165 /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
166
167 /* invert gre part of tuple */
168 static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
169                             const struct ip_conntrack_tuple *orig)
170 {
171         tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol;
172         tuple->dst.u.gre.version = orig->dst.u.gre.version;
173
174         tuple->dst.u.gre.key = orig->src.u.gre.key;
175         tuple->src.u.gre.key = orig->dst.u.gre.key;
176
177         return 1;
178 }
179
180 /* gre hdr info to tuple */
181 static int gre_pkt_to_tuple(const struct sk_buff *skb,
182                            unsigned int dataoff,
183                            struct ip_conntrack_tuple *tuple)
184      /*(const void *datah, size_t datalen,
185        struct ip_conntrack_tuple *tuple) */
186 {
187   /*    struct gre_hdr *grehdr = (struct gre_hdr *) datah;
188         struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
189         u_int32_t srckey;*/
190         struct gre_hdr grehdr;
191         struct gre_hdr_pptp pgrehdr;
192         u_int32_t srckey;
193
194         if (skb_copy_bits(skb, dataoff, &grehdr, sizeof(struct gre_hdr)) != 0)
195                 return 0;
196         if (skb_copy_bits(skb, dataoff, &pgrehdr, sizeof(struct gre_hdr_pptp)) != 0)
197                 return 0;
198
199         /* core guarantees 8 protocol bytes, no need for size check */
200
201         tuple->dst.u.gre.version = grehdr.version; 
202         tuple->dst.u.gre.protocol = grehdr.protocol;
203
204         switch (grehdr.version) {
205                 case GRE_VERSION_1701:
206                         if (!grehdr.key) {
207                                 DEBUGP("Can't track GRE without key\n");
208                                 return 0;
209                         }
210                         tuple->dst.u.gre.key = *(gre_key(&grehdr));
211                         break;
212
213                 case GRE_VERSION_PPTP:
214                         if (ntohs(grehdr.protocol) != GRE_PROTOCOL_PPTP) {
215                                 DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
216                                 return 0;
217                         }
218                         tuple->dst.u.gre.key = htonl(ntohs(pgrehdr.call_id));
219                         break;
220
221                 default:
222                         printk(KERN_WARNING "unknown GRE version %hu\n",
223                                 tuple->dst.u.gre.version);
224                         return 0;
225         }
226
227         srckey = gre_keymap_lookup(tuple);
228
229 #if 0
230         DEBUGP("found src key %x for tuple ", ntohl(srckey));
231         DUMP_TUPLE_GRE(tuple);
232 #endif
233         tuple->src.u.gre.key = srckey;
234
235         return 1;
236 }
237
238 /* print gre part of tuple */
239 static unsigned int gre_print_tuple(char *buffer,
240                                     const struct ip_conntrack_tuple *tuple)
241 {
242         return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ", 
243                         tuple->dst.u.gre.version,
244                         ntohs(tuple->dst.u.gre.protocol),
245                         ntohl(tuple->src.u.gre.key),
246                         ntohl(tuple->dst.u.gre.key));
247 }
248
249 /* print private data for conntrack */
250 static unsigned int gre_print_conntrack(char *buffer,
251                                         const struct ip_conntrack *ct)
252 {
253         return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
254                        (ct->proto.gre.timeout / HZ),
255                        (ct->proto.gre.stream_timeout / HZ));
256 }
257
258 /* Returns verdict for packet, and may modify conntrack */
259 static int gre_packet(struct ip_conntrack *ct,
260                       const struct sk_buff *skb,
261                       enum ip_conntrack_info conntrackinfo)
262 {
263         /* If we've seen traffic both ways, this is a GRE connection.
264          * Extend timeout. */
265         if (ct->status & IPS_SEEN_REPLY) {
266                 ip_ct_refresh(ct, ct->proto.gre.stream_timeout);
267                 /* Also, more likely to be important, and not a probe. */
268                 set_bit(IPS_ASSURED_BIT, &ct->status);
269         } else
270                 ip_ct_refresh(ct, ct->proto.gre.timeout);
271         
272         return NF_ACCEPT;
273 }
274
275 /* Called when a new connection for this protocol found. */
276 static int gre_new(struct ip_conntrack *ct,
277                    const struct sk_buff *skb)
278
279         DEBUGP(": ");
280         DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
281
282         /* initialize to sane value.  Ideally a conntrack helper
283          * (e.g. in case of pptp) is increasing them */
284         ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
285         ct->proto.gre.timeout = GRE_TIMEOUT;
286
287         return 1;
288 }
289
290 /* Called when a conntrack entry has already been removed from the hashes
291  * and is about to be deleted from memory */
292 static void gre_destroy(struct ip_conntrack *ct)
293 {
294         struct ip_conntrack_expect *master = ct->master;
295
296         DEBUGP(" entering\n");
297
298         if (!master) {
299                 DEBUGP("no master exp for ct %p\n", ct);
300                 return;
301         }
302
303         ip_ct_gre_keymap_destroy(master);
304 }
305
306 /* protocol helper struct */
307 static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
308                                             "gre", 
309                                             gre_pkt_to_tuple,
310                                             gre_invert_tuple,
311                                             gre_print_tuple,
312                                             gre_print_conntrack,
313                                             gre_packet,
314                                             gre_new,
315                                             gre_destroy,
316                                             NULL,
317                                             THIS_MODULE };
318
319 /* ip_conntrack_proto_gre initialization */
320 static int __init init(void)
321 {
322         int retcode;
323
324         return 0;
325         if ((retcode = ip_conntrack_protocol_register(&gre))) {
326                 printk(KERN_ERR "Unable to register conntrack protocol "
327                                 "helper for gre: %d\n", retcode);
328                 return -EIO;
329         }
330
331         return 0;
332 }
333
334 static void __exit fini(void)
335 {
336         struct list_head *pos, *n;
337
338         return 0;
339         /* delete all keymap entries */
340         WRITE_LOCK(&ip_ct_gre_lock);
341         list_for_each_safe(pos, n, &gre_keymap_list) {
342                 DEBUGP("deleting keymap %p at module unload time\n", pos);
343                 list_del(pos);
344                 kfree(pos);
345         }
346         WRITE_UNLOCK(&ip_ct_gre_lock);
347
348         ip_conntrack_protocol_unregister(&gre); 
349 }
350
351 EXPORT_SYMBOL(ip_ct_gre_keymap_add);
352 EXPORT_SYMBOL(ip_ct_gre_keymap_change);
353 EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
354
355 module_init(init);
356 module_exit(fini);