linux/net/ipv4/netfilter/nf_nat_proto_gre.c
<<
>>
Prefs
   1/*
   2 * nf_nat_proto_gre.c
   3 *
   4 * NAT 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/skbuff.h>
  28#include <linux/ip.h>
  29
  30#include <net/netfilter/nf_nat.h>
  31#include <net/netfilter/nf_nat_rule.h>
  32#include <net/netfilter/nf_nat_protocol.h>
  33#include <linux/netfilter/nf_conntrack_proto_gre.h>
  34
  35MODULE_LICENSE("GPL");
  36MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
  37MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
  38
  39/* generate unique tuple ... */
  40static bool
  41gre_unique_tuple(struct nf_conntrack_tuple *tuple,
  42                 const struct nf_nat_range *range,
  43                 enum nf_nat_manip_type maniptype,
  44                 const struct nf_conn *ct)
  45{
  46        static u_int16_t key;
  47        __be16 *keyptr;
  48        unsigned int min, i, range_size;
  49
  50        /* If there is no master conntrack we are not PPTP,
  51           do not change tuples */
  52        if (!ct->master)
  53                return false;
  54
  55        if (maniptype == IP_NAT_MANIP_SRC)
  56                keyptr = &tuple->src.u.gre.key;
  57        else
  58                keyptr = &tuple->dst.u.gre.key;
  59
  60        if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
  61                pr_debug("%p: NATing GRE PPTP\n", ct);
  62                min = 1;
  63                range_size = 0xffff;
  64        } else {
  65                min = ntohs(range->min.gre.key);
  66                range_size = ntohs(range->max.gre.key) - min + 1;
  67        }
  68
  69        pr_debug("min = %u, range_size = %u\n", min, range_size);
  70
  71        for (i = 0; i < range_size; i++, key++) {
  72                *keyptr = htons(min + key % range_size);
  73                if (!nf_nat_used_tuple(tuple, ct))
  74                        return true;
  75        }
  76
  77        pr_debug("%p: no NAT mapping\n", ct);
  78        return false;
  79}
  80
  81/* manipulate a GRE packet according to maniptype */
  82static bool
  83gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
  84              const struct nf_conntrack_tuple *tuple,
  85              enum nf_nat_manip_type maniptype)
  86{
  87        const struct gre_hdr *greh;
  88        struct gre_hdr_pptp *pgreh;
  89        const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
  90        unsigned int hdroff = iphdroff + iph->ihl * 4;
  91
  92        /* pgreh includes two optional 32bit fields which are not required
  93         * to be there.  That's where the magic '8' comes from */
  94        if (!skb_make_writable(skb, hdroff + sizeof(*pgreh) - 8))
  95                return false;
  96
  97        greh = (void *)skb->data + hdroff;
  98        pgreh = (struct gre_hdr_pptp *)greh;
  99
 100        /* we only have destination manip of a packet, since 'source key'
 101         * is not present in the packet itself */
 102        if (maniptype != IP_NAT_MANIP_DST)
 103                return true;
 104        switch (greh->version) {
 105        case GRE_VERSION_1701:
 106                /* We do not currently NAT any GREv0 packets.
 107                 * Try to behave like "nf_nat_proto_unknown" */
 108                break;
 109        case GRE_VERSION_PPTP:
 110                pr_debug("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
 111                pgreh->call_id = tuple->dst.u.gre.key;
 112                break;
 113        default:
 114                pr_debug("can't nat unknown GRE version\n");
 115                return false;
 116        }
 117        return true;
 118}
 119
 120static const struct nf_nat_protocol gre = {
 121        .protonum               = IPPROTO_GRE,
 122        .me                     = THIS_MODULE,
 123        .manip_pkt              = gre_manip_pkt,
 124        .in_range               = nf_nat_proto_in_range,
 125        .unique_tuple           = gre_unique_tuple,
 126#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 127        .range_to_nlattr        = nf_nat_proto_range_to_nlattr,
 128        .nlattr_to_range        = nf_nat_proto_nlattr_to_range,
 129#endif
 130};
 131
 132static int __init nf_nat_proto_gre_init(void)
 133{
 134        return nf_nat_protocol_register(&gre);
 135}
 136
 137static void __exit nf_nat_proto_gre_fini(void)
 138{
 139        nf_nat_protocol_unregister(&gre);
 140}
 141
 142module_init(nf_nat_proto_gre_init);
 143module_exit(nf_nat_proto_gre_fini);
 144
 145void nf_nat_need_gre(void)
 146{
 147        return;
 148}
 149EXPORT_SYMBOL_GPL(nf_nat_need_gre);
 150