1/* 2 * ip_conntrack_proto_gre.c - Version 3.0 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-2005 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/module.h> 27#include <linux/types.h> 28#include <linux/timer.h> 29#include <linux/list.h> 30#include <linux/seq_file.h> 31#include <linux/in.h> 32#include <linux/netdevice.h> 33#include <linux/skbuff.h> 34#include <linux/slab.h> 35#include <net/dst.h> 36#include <net/net_namespace.h> 37#include <net/netns/generic.h> 38#include <net/netfilter/nf_conntrack_l4proto.h> 39#include <net/netfilter/nf_conntrack_helper.h> 40#include <net/netfilter/nf_conntrack_core.h> 41#include <linux/netfilter/nf_conntrack_proto_gre.h> 42#include <linux/netfilter/nf_conntrack_pptp.h> 43 44#define GRE_TIMEOUT (30 * HZ) 45#define GRE_STREAM_TIMEOUT (180 * HZ) 46 47static int proto_gre_net_id __read_mostly; 48struct netns_proto_gre { 49 rwlock_t keymap_lock; 50 struct list_head keymap_list; 51}; 52 53void nf_ct_gre_keymap_flush(struct net *net) 54{ 55 struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); 56 struct nf_ct_gre_keymap *km, *tmp; 57 58 write_lock_bh(&net_gre->keymap_lock); 59 list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) { 60 list_del(&km->list); 61 kfree(km); 62 } 63 write_unlock_bh(&net_gre->keymap_lock); 64} 65EXPORT_SYMBOL(nf_ct_gre_keymap_flush); 66 67static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, 68 const struct nf_conntrack_tuple *t) 69{ 70 return km->tuple.src.l3num == t->src.l3num && 71 !memcmp(&km->tuple.src.u3, &t->src.u3, sizeof(t->src.u3)) && 72 !memcmp(&km->tuple.dst.u3, &t->dst.u3, sizeof(t->dst.u3)) && 73 km->tuple.dst.protonum == t->dst.protonum && 74 km->tuple.dst.u.all == t->dst.u.all; 75} 76 77/* look up the source key for a given tuple */ 78static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t) 79{ 80 struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); 81 struct nf_ct_gre_keymap *km; 82 __be16 key = 0; 83 84 read_lock_bh(&net_gre->keymap_lock); 85 list_for_each_entry(km, &net_gre->keymap_list, list) { 86 if (gre_key_cmpfn(km, t)) { 87 key = km->tuple.src.u.gre.key; 88 break; 89 } 90 } 91 read_unlock_bh(&net_gre->keymap_lock); 92 93 pr_debug("lookup src key 0x%x for ", key); 94 nf_ct_dump_tuple(t); 95 96 return key; 97} 98 99/* add a single keymap entry, associate with specified master ct */ 100int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, 101 struct nf_conntrack_tuple *t) 102{ 103 struct net *net = nf_ct_net(ct); 104 struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); 105 struct nf_conn_help *help = nfct_help(ct); 106 struct nf_ct_gre_keymap **kmp, *km; 107 108 kmp = &help->help.ct_pptp_info.keymap[dir]; 109 if (*kmp) { 110 /* check whether it's a retransmission */ 111 read_lock_bh(&net_gre->keymap_lock); 112 list_for_each_entry(km, &net_gre->keymap_list, list) { 113 if (gre_key_cmpfn(km, t) && km == *kmp) { 114 read_unlock_bh(&net_gre->keymap_lock); 115 return 0; 116 } 117 } 118 read_unlock_bh(&net_gre->keymap_lock); 119 pr_debug("trying to override keymap_%s for ct %p\n", 120 dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); 121 return -EEXIST; 122 } 123 124 km = kmalloc(sizeof(*km), GFP_ATOMIC); 125 if (!km) 126 return -ENOMEM; 127 memcpy(&km->tuple, t, sizeof(*t)); 128 *kmp = km; 129 130 pr_debug("adding new entry %p: ", km); 131 nf_ct_dump_tuple(&km->tuple); 132 133 write_lock_bh(&net_gre->keymap_lock); 134 list_add_tail(&km->list, &net_gre->keymap_list); 135 write_unlock_bh(&net_gre->keymap_lock); 136 137 return 0; 138} 139EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add); 140 141/* destroy the keymap entries associated with specified master ct */ 142void nf_ct_gre_keymap_destroy(struct nf_conn *ct) 143{ 144 struct net *net = nf_ct_net(ct); 145 struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); 146 struct nf_conn_help *help = nfct_help(ct); 147 enum ip_conntrack_dir dir; 148 149 pr_debug("entering for ct %p\n", ct); 150 151 write_lock_bh(&net_gre->keymap_lock); 152 for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { 153 if (help->help.ct_pptp_info.keymap[dir]) { 154 pr_debug("removing %p from list\n", 155 help->help.ct_pptp_info.keymap[dir]); 156 list_del(&help->help.ct_pptp_info.keymap[dir]->list); 157 kfree(help->help.ct_pptp_info.keymap[dir]); 158 help->help.ct_pptp_info.keymap[dir] = NULL; 159 } 160 } 161 write_unlock_bh(&net_gre->keymap_lock); 162} 163EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); 164 165/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ 166 167/* invert gre part of tuple */ 168static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple, 169 const struct nf_conntrack_tuple *orig) 170{ 171 tuple->dst.u.gre.key = orig->src.u.gre.key; 172 tuple->src.u.gre.key = orig->dst.u.gre.key; 173 return true; 174} 175 176/* gre hdr info to tuple */ 177static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, 178 struct nf_conntrack_tuple *tuple) 179{ 180 struct net *net = dev_net(skb->dev ? skb->dev : skb_dst(skb)->dev); 181 const struct gre_hdr_pptp *pgrehdr; 182 struct gre_hdr_pptp _pgrehdr; 183 __be16 srckey; 184 const struct gre_hdr *grehdr; 185 struct gre_hdr _grehdr; 186 187 /* first only delinearize old RFC1701 GRE header */ 188 grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); 189 if (!grehdr || grehdr->version != GRE_VERSION_PPTP) { 190 /* try to behave like "nf_conntrack_proto_generic" */ 191 tuple->src.u.all = 0; 192 tuple->dst.u.all = 0; 193 return true; 194 } 195 196 /* PPTP header is variable length, only need up to the call_id field */ 197 pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); 198 if (!pgrehdr) 199 return true; 200 201 if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { 202 pr_debug("GRE_VERSION_PPTP but unknown proto\n"); 203 return false; 204 } 205 206 tuple->dst.u.gre.key = pgrehdr->call_id; 207 srckey = gre_keymap_lookup(net, tuple); 208 tuple->src.u.gre.key = srckey; 209 210 return true; 211} 212 213/* print gre part of tuple */ 214static int gre_print_tuple(struct seq_file *s, 215 const struct nf_conntrack_tuple *tuple) 216{ 217 return seq_printf(s, "srckey=0x%x dstkey=0x%x ", 218 ntohs(tuple->src.u.gre.key), 219 ntohs(tuple->dst.u.gre.key)); 220} 221 222/* print private data for conntrack */ 223static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) 224{ 225 return seq_printf(s, "timeout=%u, stream_timeout=%u ", 226 (ct->proto.gre.timeout / HZ), 227 (ct->proto.gre.stream_timeout / HZ)); 228} 229 230/* Returns verdict for packet, and may modify conntrack */ 231static int gre_packet(struct nf_conn *ct, 232 const struct sk_buff *skb, 233 unsigned int dataoff, 234 enum ip_conntrack_info ctinfo, 235 u_int8_t pf, 236 unsigned int hooknum) 237{ 238 /* If we've seen traffic both ways, this is a GRE connection. 239 * Extend timeout. */ 240 if (ct->status & IPS_SEEN_REPLY) { 241 nf_ct_refresh_acct(ct, ctinfo, skb, 242 ct->proto.gre.stream_timeout); 243 /* Also, more likely to be important, and not a probe. */ 244 set_bit(IPS_ASSURED_BIT, &ct->status); 245 nf_conntrack_event_cache(IPCT_ASSURED, ct); 246 } else 247 nf_ct_refresh_acct(ct, ctinfo, skb, 248 ct->proto.gre.timeout); 249 250 return NF_ACCEPT; 251} 252 253/* Called when a new connection for this protocol found. */ 254static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, 255 unsigned int dataoff) 256{ 257 pr_debug(": "); 258 nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 259 260 /* initialize to sane value. Ideally a conntrack helper 261 * (e.g. in case of pptp) is increasing them */ 262 ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; 263 ct->proto.gre.timeout = GRE_TIMEOUT; 264 265 return true; 266} 267 268/* Called when a conntrack entry has already been removed from the hashes 269 * and is about to be deleted from memory */ 270static void gre_destroy(struct nf_conn *ct) 271{ 272 struct nf_conn *master = ct->master; 273 pr_debug(" entering\n"); 274 275 if (!master) 276 pr_debug("no master !?!\n"); 277 else 278 nf_ct_gre_keymap_destroy(master); 279} 280 281/* protocol helper struct */ 282static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { 283 .l3proto = AF_INET, 284 .l4proto = IPPROTO_GRE, 285 .name = "gre", 286 .pkt_to_tuple = gre_pkt_to_tuple, 287 .invert_tuple = gre_invert_tuple, 288 .print_tuple = gre_print_tuple, 289 .print_conntrack = gre_print_conntrack, 290 .packet = gre_packet, 291 .new = gre_new, 292 .destroy = gre_destroy, 293 .me = THIS_MODULE, 294#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 295 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 296 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 297 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 298 .nla_policy = nf_ct_port_nla_policy, 299#endif 300}; 301 302static int proto_gre_net_init(struct net *net) 303{ 304 struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); 305 306 rwlock_init(&net_gre->keymap_lock); 307 INIT_LIST_HEAD(&net_gre->keymap_list); 308 309 return 0; 310} 311 312static void proto_gre_net_exit(struct net *net) 313{ 314 nf_ct_gre_keymap_flush(net); 315} 316 317static struct pernet_operations proto_gre_net_ops = { 318 .init = proto_gre_net_init, 319 .exit = proto_gre_net_exit, 320 .id = &proto_gre_net_id, 321 .size = sizeof(struct netns_proto_gre), 322}; 323 324static int __init nf_ct_proto_gre_init(void) 325{ 326 int rv; 327 328 rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4); 329 if (rv < 0) 330 return rv; 331 rv = register_pernet_subsys(&proto_gre_net_ops); 332 if (rv < 0) 333 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); 334 return rv; 335} 336 337static void __exit nf_ct_proto_gre_fini(void) 338{ 339 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); 340 unregister_pernet_subsys(&proto_gre_net_ops); 341} 342 343module_init(nf_ct_proto_gre_init); 344module_exit(nf_ct_proto_gre_fini); 345 346MODULE_LICENSE("GPL"); 347