2 * ip_conntrack_proto_gre.c - Version 3.0
4 * Connection tracking protocol helper module for GRE.
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.
9 * It has an optional key field, which may help us distinguishing two
10 * connections between the same two hosts.
12 * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
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
18 * Documentation about PPTP can be found in RFC 2637
20 * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
22 * Development of this code funded by Astaro AG (http://www.astaro.com/)
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>
33 #include <linux/list.h>
35 #include <linux/netfilter_ipv4/lockhelp.h>
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)
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>
46 #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
47 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
49 MODULE_LICENSE("GPL");
50 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
51 MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
53 /* shamelessly stolen from ip_conntrack_proto_udp.c */
54 #define GRE_TIMEOUT (30*HZ)
55 #define GRE_STREAM_TIMEOUT (180*HZ)
58 #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
59 #define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \
60 NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \
61 NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key))
63 #define DEBUGP(x, args...)
64 #define DUMP_TUPLE_GRE(x)
67 /* GRE KEYMAP HANDLING FUNCTIONS */
68 static LIST_HEAD(gre_keymap_list);
70 static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
71 const struct ip_conntrack_tuple *t)
73 return ((km->tuple.src.ip == t->src.ip) &&
74 (km->tuple.dst.ip == t->dst.ip) &&
75 (km->tuple.dst.protonum == t->dst.protonum) &&
76 (km->tuple.dst.u.all == t->dst.u.all));
79 /* look up the source key for a given tuple */
80 static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
82 struct ip_ct_gre_keymap *km;
85 READ_LOCK(&ip_ct_gre_lock);
86 km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
87 struct ip_ct_gre_keymap *, t);
89 key = km->tuple.src.u.gre.key;
90 READ_UNLOCK(&ip_ct_gre_lock);
92 DEBUGP("lookup src key 0x%x up key for ", key);
98 /* add a single keymap entry, associate with specified master ct */
100 ip_ct_gre_keymap_add(struct ip_conntrack *ct,
101 struct ip_conntrack_tuple *t, int reply)
103 struct ip_ct_gre_keymap *km, *old;
105 if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
106 DEBUGP("refusing to add GRE keymap to non-pptp session\n");
110 km = kmalloc(sizeof(*km), GFP_ATOMIC);
114 /* initializing list head should be sufficient */
115 memset(km, 0, sizeof(*km));
117 memcpy(&km->tuple, t, sizeof(*t));
120 if (ct->help.ct_pptp_info.keymap_orig) {
123 /* check whether it's a retransmission */
124 old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
125 struct ip_ct_gre_keymap *, t);
126 if (old == ct->help.ct_pptp_info.keymap_orig) {
127 DEBUGP("retransmission\n");
131 DEBUGP("trying to override keymap_orig for ct %p\n",
135 ct->help.ct_pptp_info.keymap_orig = km;
137 if (ct->help.ct_pptp_info.keymap_reply) {
140 /* check whether it's a retransmission */
141 old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
142 struct ip_ct_gre_keymap *, t);
143 if (old == ct->help.ct_pptp_info.keymap_reply) {
144 DEBUGP("retransmission\n");
148 DEBUGP("trying to override keymap_reply for ct %p\n",
152 ct->help.ct_pptp_info.keymap_reply = km;
155 DEBUGP("adding new entry %p: ", km);
156 DUMP_TUPLE_GRE(&km->tuple);
158 WRITE_LOCK(&ip_ct_gre_lock);
159 list_append(&gre_keymap_list, km);
160 WRITE_UNLOCK(&ip_ct_gre_lock);
165 /* destroy the keymap entries associated with specified master ct */
166 void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct)
168 DEBUGP("entering for ct %p\n", ct);
170 if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
171 DEBUGP("refusing to destroy GRE keymap to non-pptp session\n");
175 WRITE_LOCK(&ip_ct_gre_lock);
176 if (ct->help.ct_pptp_info.keymap_orig) {
177 DEBUGP("removing %p from list\n",
178 ct->help.ct_pptp_info.keymap_orig);
179 list_del(&ct->help.ct_pptp_info.keymap_orig->list);
180 kfree(ct->help.ct_pptp_info.keymap_orig);
181 ct->help.ct_pptp_info.keymap_orig = NULL;
183 if (ct->help.ct_pptp_info.keymap_reply) {
184 DEBUGP("removing %p from list\n",
185 ct->help.ct_pptp_info.keymap_reply);
186 list_del(&ct->help.ct_pptp_info.keymap_reply->list);
187 kfree(ct->help.ct_pptp_info.keymap_reply);
188 ct->help.ct_pptp_info.keymap_reply = NULL;
190 WRITE_UNLOCK(&ip_ct_gre_lock);
194 /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
196 /* invert gre part of tuple */
197 static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
198 const struct ip_conntrack_tuple *orig)
200 tuple->dst.u.gre.key = orig->src.u.gre.key;
201 tuple->src.u.gre.key = orig->dst.u.gre.key;
206 /* gre hdr info to tuple */
207 static int gre_pkt_to_tuple(const struct sk_buff *skb,
208 unsigned int dataoff,
209 struct ip_conntrack_tuple *tuple)
211 struct gre_hdr _grehdr, *grehdr;
212 struct gre_hdr_pptp _pgrehdr, *pgrehdr;
215 grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
216 /* PPTP header is variable length, only need up to the call_id field */
217 pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);
219 if (!grehdr || !pgrehdr)
222 switch (grehdr->version) {
223 case GRE_VERSION_1701:
225 DEBUGP("Can't track GRE without key\n");
228 tuple->dst.u.gre.key = *(gre_key(grehdr));
231 case GRE_VERSION_PPTP:
232 if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
233 DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
236 tuple->dst.u.gre.key = pgrehdr->call_id;
240 printk(KERN_WARNING "unknown GRE version %hu\n",
245 srckey = gre_keymap_lookup(tuple);
247 tuple->src.u.gre.key = srckey;
249 DEBUGP("found src key %x for tuple ", ntohs(srckey));
250 DUMP_TUPLE_GRE(tuple);
256 /* print gre part of tuple */
257 static int gre_print_tuple(struct seq_file *s,
258 const struct ip_conntrack_tuple *tuple)
260 return seq_printf(s, "srckey=0x%x dstkey=0x%x ",
261 ntohs(tuple->src.u.gre.key),
262 ntohs(tuple->dst.u.gre.key));
265 /* print private data for conntrack */
266 static int gre_print_conntrack(struct seq_file *s,
267 const struct ip_conntrack *ct)
269 return seq_printf(s, "timeout=%u, stream_timeout=%u ",
270 (ct->proto.gre.timeout / HZ),
271 (ct->proto.gre.stream_timeout / HZ));
274 /* Returns verdict for packet, and may modify conntrack */
275 static int gre_packet(struct ip_conntrack *ct,
276 const struct sk_buff *skb,
277 enum ip_conntrack_info conntrackinfo)
279 /* If we've seen traffic both ways, this is a GRE connection.
281 if (ct->status & IPS_SEEN_REPLY) {
282 ip_ct_refresh_acct(ct, conntrackinfo, skb,
283 ct->proto.gre.stream_timeout);
284 /* Also, more likely to be important, and not a probe. */
285 set_bit(IPS_ASSURED_BIT, &ct->status);
287 ip_ct_refresh_acct(ct, conntrackinfo, skb,
288 ct->proto.gre.timeout);
293 /* Called when a new connection for this protocol found. */
294 static int gre_new(struct ip_conntrack *ct,
295 const struct sk_buff *skb)
298 DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
300 /* initialize to sane value. Ideally a conntrack helper
301 * (e.g. in case of pptp) is increasing them */
302 ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
303 ct->proto.gre.timeout = GRE_TIMEOUT;
308 /* Called when a conntrack entry has already been removed from the hashes
309 * and is about to be deleted from memory */
310 static void gre_destroy(struct ip_conntrack *ct)
312 struct ip_conntrack *master = ct->master;
313 DEBUGP(" entering\n");
316 DEBUGP("no master !?!\n");
318 ip_ct_gre_keymap_destroy(master);
321 /* protocol helper struct */
322 static struct ip_conntrack_protocol gre = {
323 .proto = IPPROTO_GRE,
325 .pkt_to_tuple = gre_pkt_to_tuple,
326 .invert_tuple = gre_invert_tuple,
327 .print_tuple = gre_print_tuple,
328 .print_conntrack = gre_print_conntrack,
329 .packet = gre_packet,
331 .destroy = gre_destroy,
335 /* ip_conntrack_proto_gre initialization */
336 static int __init init(void)
340 if ((retcode = ip_conntrack_protocol_register(&gre))) {
341 printk(KERN_ERR "Unable to register conntrack protocol "
342 "helper for gre: %d\n", retcode);
349 static void __exit fini(void)
351 struct list_head *pos, *n;
353 /* delete all keymap entries */
354 WRITE_LOCK(&ip_ct_gre_lock);
355 list_for_each_safe(pos, n, &gre_keymap_list) {
356 DEBUGP("deleting keymap %p at module unload time\n", pos);
360 WRITE_UNLOCK(&ip_ct_gre_lock);
362 ip_conntrack_protocol_unregister(&gre);
365 EXPORT_SYMBOL(ip_ct_gre_keymap_add);
366 EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);