···42struct vlan_ethhdr {43 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */44 unsigned char h_source[ETH_ALEN]; /* source ether addr */45- unsigned short h_vlan_proto; /* Should always be 0x8100 */46- unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */47 unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */48};49···55}5657struct vlan_hdr {58- unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */59- unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */60};6162#define VLAN_VID_MASK 0xfff
···42struct vlan_ethhdr {43 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */44 unsigned char h_source[ETH_ALEN]; /* source ether addr */45+ __be16 h_vlan_proto; /* Should always be 0x8100 */46+ __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */47 unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */48};49···55}5657struct vlan_hdr {58+ __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */59+ __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */60};6162#define VLAN_VID_MASK 0xfff
+13-1
include/linux/netfilter_ipv4/ip_conntrack.h
···133134#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>135#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>0136#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>137138/* per conntrack: protocol private data */139union ip_conntrack_proto {140 /* insert conntrack proto private data here */0141 struct ip_ct_sctp sctp;142 struct ip_ct_tcp tcp;143 struct ip_ct_icmp icmp;···150};151152/* Add protocol helper include file here */0153#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>154#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>155#include <linux/netfilter_ipv4/ip_conntrack_irc.h>···158/* per conntrack: application helper private data */159union ip_conntrack_help {160 /* insert conntrack helper private data (master) here */0161 struct ip_ct_ftp_master ct_ftp_info;162 struct ip_ct_irc_master ct_irc_info;163};164165#ifdef CONFIG_IP_NF_NAT_NEEDED166#include <linux/netfilter_ipv4/ip_nat.h>0000000167#endif168169#include <linux/types.h>···234#ifdef CONFIG_IP_NF_NAT_NEEDED235 struct {236 struct ip_nat_info info;0237#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \238 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)239 int masq_index;···384__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);385386extern struct ip_conntrack_expect *387-ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);388389extern struct ip_conntrack_tuple_hash *390__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
···133134#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>135#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>136+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>137#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>138139/* per conntrack: protocol private data */140union ip_conntrack_proto {141 /* insert conntrack proto private data here */142+ struct ip_ct_gre gre;143 struct ip_ct_sctp sctp;144 struct ip_ct_tcp tcp;145 struct ip_ct_icmp icmp;···148};149150/* Add protocol helper include file here */151+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>152#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>153#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>154#include <linux/netfilter_ipv4/ip_conntrack_irc.h>···155/* per conntrack: application helper private data */156union ip_conntrack_help {157 /* insert conntrack helper private data (master) here */158+ struct ip_ct_pptp_master ct_pptp_info;159 struct ip_ct_ftp_master ct_ftp_info;160 struct ip_ct_irc_master ct_irc_info;161};162163#ifdef CONFIG_IP_NF_NAT_NEEDED164#include <linux/netfilter_ipv4/ip_nat.h>165+#include <linux/netfilter_ipv4/ip_nat_pptp.h>166+167+/* per conntrack: nat application helper private data */168+union ip_conntrack_nat_help {169+ /* insert nat helper private data here */170+ struct ip_nat_pptp nat_pptp_info;171+};172#endif173174#include <linux/types.h>···223#ifdef CONFIG_IP_NF_NAT_NEEDED224 struct {225 struct ip_nat_info info;226+ union ip_conntrack_nat_help help;227#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \228 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)229 int masq_index;···372__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);373374extern struct ip_conntrack_expect *375+ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);376377extern struct ip_conntrack_tuple_hash *378__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
···1+#ifndef _CONNTRACK_PROTO_GRE_H2+#define _CONNTRACK_PROTO_GRE_H3+#include <asm/byteorder.h>4+5+/* GRE PROTOCOL HEADER */6+7+/* GRE Version field */8+#define GRE_VERSION_1701 0x09+#define GRE_VERSION_PPTP 0x110+11+/* GRE Protocol field */12+#define GRE_PROTOCOL_PPTP 0x880B13+14+/* GRE Flags */15+#define GRE_FLAG_C 0x8016+#define GRE_FLAG_R 0x4017+#define GRE_FLAG_K 0x2018+#define GRE_FLAG_S 0x1019+#define GRE_FLAG_A 0x8020+21+#define GRE_IS_C(f) ((f)&GRE_FLAG_C)22+#define GRE_IS_R(f) ((f)&GRE_FLAG_R)23+#define GRE_IS_K(f) ((f)&GRE_FLAG_K)24+#define GRE_IS_S(f) ((f)&GRE_FLAG_S)25+#define GRE_IS_A(f) ((f)&GRE_FLAG_A)26+27+/* GRE is a mess: Four different standards */28+struct gre_hdr {29+#if defined(__LITTLE_ENDIAN_BITFIELD)30+ __u16 rec:3,31+ srr:1,32+ seq:1,33+ key:1,34+ routing:1,35+ csum:1,36+ version:3,37+ reserved:4,38+ ack:1;39+#elif defined(__BIG_ENDIAN_BITFIELD)40+ __u16 csum:1,41+ routing:1,42+ key:1,43+ seq:1,44+ srr:1,45+ rec:3,46+ ack:1,47+ reserved:4,48+ version:3;49+#else50+#error "Adjust your <asm/byteorder.h> defines"51+#endif52+ __u16 protocol;53+};54+55+/* modified GRE header for PPTP */56+struct gre_hdr_pptp {57+ __u8 flags; /* bitfield */58+ __u8 version; /* should be GRE_VERSION_PPTP */59+ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */60+ __u16 payload_len; /* size of ppp payload, not inc. gre header */61+ __u16 call_id; /* peer's call_id for this session */62+ __u32 seq; /* sequence number. Present if S==1 */63+ __u32 ack; /* seq number of highest packet recieved by */64+ /* sender in this session */65+};66+67+68+/* this is part of ip_conntrack */69+struct ip_ct_gre {70+ unsigned int stream_timeout;71+ unsigned int timeout;72+};73+74+#ifdef __KERNEL__75+struct ip_conntrack_expect;76+struct ip_conntrack;77+78+/* structure for original <-> reply keymap */79+struct ip_ct_gre_keymap {80+ struct list_head list;81+82+ struct ip_conntrack_tuple tuple;83+};84+85+/* add new tuple->key_reply pair to keymap */86+int ip_ct_gre_keymap_add(struct ip_conntrack *ct,87+ struct ip_conntrack_tuple *t,88+ int reply);89+90+/* delete keymap entries */91+void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct);92+93+94+/* get pointer to gre key, if present */95+static inline u_int32_t *gre_key(struct gre_hdr *greh)96+{97+ if (!greh->key)98+ return NULL;99+ if (greh->csum || greh->routing)100+ return (u_int32_t *) (greh+sizeof(*greh)+4);101+ return (u_int32_t *) (greh+sizeof(*greh));102+}103+104+/* get pointer ot gre csum, if present */105+static inline u_int16_t *gre_csum(struct gre_hdr *greh)106+{107+ if (!greh->csum)108+ return NULL;109+ return (u_int16_t *) (greh+sizeof(*greh));110+}111+112+#endif /* __KERNEL__ */113+114+#endif /* _CONNTRACK_PROTO_GRE_H */
+7
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
···28 struct {29 u_int16_t port;30 } sctp;00031};3233/* The manipulable part of the tuple. */···64 struct {65 u_int16_t port;66 } sctp;000067 } u;6869 /* The protocol. */
···28 struct {29 u_int16_t port;30 } sctp;31+ struct {32+ u_int16_t key; /* key is 32bit, pptp only uses 16 */33+ } gre;34};3536/* The manipulable part of the tuple. */···61 struct {62 u_int16_t port;63 } sctp;64+ struct {65+ u_int16_t key; /* key is 32bit, 66+ * pptp only uses 16 */67+ } gre;68 } u;6970 /* The protocol. */
+11
include/linux/netfilter_ipv4/ip_nat_pptp.h
···00000000000
···1+/* PPTP constants and structs */2+#ifndef _NAT_PPTP_H3+#define _NAT_PPTP_H4+5+/* conntrack private data */6+struct ip_nat_pptp {7+ u_int16_t pns_call_id; /* NAT'ed PNS call id */8+ u_int16_t pac_call_id; /* NAT'ed PAC call id */9+};10+11+#endif /* _NAT_PPTP_H */
+3
include/linux/netfilter_ipv6/ip6_tables.h
···455456/* Check for an extension */457extern int ip6t_ext_hdr(u8 nexthdr);000458459#define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))460
···455456/* Check for an extension */457extern int ip6t_ext_hdr(u8 nexthdr);458+/* find specified header and get offset to it */459+extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,460+ u8 target);461462#define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))463
+1-1
net/8021q/vlan_dev.c
···120 unsigned short vid;121 struct net_device_stats *stats;122 unsigned short vlan_TCI;123- unsigned short proto;124125 /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */126 vlan_TCI = ntohs(vhdr->h_vlan_TCI);
···120 unsigned short vid;121 struct net_device_stats *stats;122 unsigned short vlan_TCI;123+ __be16 proto;124125 /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */126 vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+17-17
net/ipv4/fib_trie.c
···43 * 2 of the License, or (at your option) any later version.44 */4546-#define VERSION "0.403"4748#include <linux/config.h>49#include <asm/uaccess.h>···224 Consider a node 'n' and its parent 'tp'.225226 If n is a leaf, every bit in its key is significant. Its presence is 227- necessitaded by path compression, since during a tree traversal (when 228 searching for a leaf - unless we are doing an insertion) we will completely 229 ignore all skipped bits we encounter. Thus we need to verify, at the end of 230 a potentially successful search, that we have indeed been walking the ···836#endif837}838839-/* readside most use rcu_read_lock currently dump routines840 via get_fa_head and dump */841842-static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen)843{0844 struct hlist_node *node;845 struct leaf_info *li;846···854855static inline struct list_head * get_fa_head(struct leaf *l, int plen)856{857- struct leaf_info *li = find_leaf_info(&l->list, plen);858859 if (!li)860 return NULL;···1249}125012511252-/* should be clalled with rcu_read_lock */1253static inline int check_leaf(struct trie *t, struct leaf *l,1254 t_key key, int *plen, const struct flowi *flp,1255 struct fib_result *res)···1591 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);15921593 l = fib_find_node(t, key);1594- li = find_leaf_info(&l->list, plen);15951596 list_del_rcu(&fa->fa_list);1597···17151716 t->revision++;17171718- rcu_read_lock();1719 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {1720 found += trie_flush_leaf(t, l);1721···1722 trie_leaf_remove(t, ll->key);1723 ll = l;1724 }1725- rcu_read_unlock(); 17261727 if (ll && hlist_empty(&ll->list))1728 trie_leaf_remove(t, ll->key);···2028 iter->tnode = (struct tnode *) n;2029 iter->trie = t;2030 iter->index = 0;2031- iter->depth = 0;2032 return n;2033 }2034 return NULL;···2273 seq_puts(seq, "<local>:\n");2274 else2275 seq_puts(seq, "<main>:\n");2276- } else {2277- seq_indent(seq, iter->depth-1);2278- seq_printf(seq, " +-- %d.%d.%d.%d/%d\n",2279- NIPQUAD(prf), tn->pos);2280- }02281 } else {2282 struct leaf *l = (struct leaf *) n;2283 int i;···2287 seq_indent(seq, iter->depth);2288 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));2289 for (i = 32; i >= 0; i--) {2290- struct leaf_info *li = find_leaf_info(&l->list, i);2291 if (li) {2292 struct fib_alias *fa;2293 list_for_each_entry_rcu(fa, &li->falh, fa_list) {···2383 return 0;23842385 for (i=32; i>=0; i--) {2386- struct leaf_info *li = find_leaf_info(&l->list, i);2387 struct fib_alias *fa;2388 u32 mask, prefix;2389
···43 * 2 of the License, or (at your option) any later version.44 */4546+#define VERSION "0.404"4748#include <linux/config.h>49#include <asm/uaccess.h>···224 Consider a node 'n' and its parent 'tp'.225226 If n is a leaf, every bit in its key is significant. Its presence is 227+ necessitated by path compression, since during a tree traversal (when 228 searching for a leaf - unless we are doing an insertion) we will completely 229 ignore all skipped bits we encounter. Thus we need to verify, at the end of 230 a potentially successful search, that we have indeed been walking the ···836#endif837}838839+/* readside must use rcu_read_lock currently dump routines840 via get_fa_head and dump */841842+static struct leaf_info *find_leaf_info(struct leaf *l, int plen)843{844+ struct hlist_head *head = &l->list;845 struct hlist_node *node;846 struct leaf_info *li;847···853854static inline struct list_head * get_fa_head(struct leaf *l, int plen)855{856+ struct leaf_info *li = find_leaf_info(l, plen);857858 if (!li)859 return NULL;···1248}124912501251+/* should be called with rcu_read_lock */1252static inline int check_leaf(struct trie *t, struct leaf *l,1253 t_key key, int *plen, const struct flowi *flp,1254 struct fib_result *res)···1590 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);15911592 l = fib_find_node(t, key);1593+ li = find_leaf_info(l, plen);15941595 list_del_rcu(&fa->fa_list);1596···17141715 t->revision++;171601717 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {1718 found += trie_flush_leaf(t, l);1719···1722 trie_leaf_remove(t, ll->key);1723 ll = l;1724 }017251726 if (ll && hlist_empty(&ll->list))1727 trie_leaf_remove(t, ll->key);···2029 iter->tnode = (struct tnode *) n;2030 iter->trie = t;2031 iter->index = 0;2032+ iter->depth = 1;2033 return n;2034 }2035 return NULL;···2274 seq_puts(seq, "<local>:\n");2275 else2276 seq_puts(seq, "<main>:\n");2277+ } 2278+ seq_indent(seq, iter->depth-1);2279+ seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n",2280+ NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, 2281+ tn->empty_children);2282+2283 } else {2284 struct leaf *l = (struct leaf *) n;2285 int i;···2287 seq_indent(seq, iter->depth);2288 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));2289 for (i = 32; i >= 0; i--) {2290+ struct leaf_info *li = find_leaf_info(l, i);2291 if (li) {2292 struct fib_alias *fa;2293 list_for_each_entry_rcu(fa, &li->falh, fa_list) {···2383 return 0;23842385 for (i=32; i>=0; i--) {2386+ struct leaf_info *li = find_leaf_info(l, i);2387 struct fib_alias *fa;2388 u32 mask, prefix;2389
+22
net/ipv4/netfilter/Kconfig
···137138 To compile it as a module, choose M here. If unsure, say Y.1390000000000000000140config IP_NF_QUEUE141 tristate "IP Userspace queueing via NETLINK (OBSOLETE)"142 help···636 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n637 default IP_NF_NAT if IP_NF_AMANDA=y638 default m if IP_NF_AMANDA=m000000639640# mangle + specific targets641config IP_NF_MANGLE
···137138 To compile it as a module, choose M here. If unsure, say Y.139140+config IP_NF_PPTP141+ tristate 'PPTP protocol support'142+ help143+ This module adds support for PPTP (Point to Point Tunnelling144+ Protocol, RFC2637) conncection tracking and NAT. 145+146+ If you are running PPTP sessions over a stateful firewall or NAT147+ box, you may want to enable this feature. 148+149+ Please note that not all PPTP modes of operation are supported yet.150+ For more info, read top of the file151+ net/ipv4/netfilter/ip_conntrack_pptp.c152+153+ If you want to compile it as a module, say M here and read154+ Documentation/modules.txt. If unsure, say `N'.155+156config IP_NF_QUEUE157 tristate "IP Userspace queueing via NETLINK (OBSOLETE)"158 help···620 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n621 default IP_NF_NAT if IP_NF_AMANDA=y622 default m if IP_NF_AMANDA=m623+624+config IP_NF_NAT_PPTP625+ tristate626+ depends on IP_NF_NAT!=n && IP_NF_PPTP!=n627+ default IP_NF_NAT if IP_NF_PPTP=y628+ default m if IP_NF_PPTP=m629630# mangle + specific targets631config IP_NF_MANGLE
···233234/* Just find a expectation corresponding to a tuple. */235struct ip_conntrack_expect *236-ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)237{238 struct ip_conntrack_expect *i;239
···233234/* Just find a expectation corresponding to a tuple. */235struct ip_conntrack_expect *236+ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple)237{238 struct ip_conntrack_expect *i;239
···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 very7+ * 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 mandatory15+ * field called "CallID", which serves us for the same purpose as the key16+ * field in plain GRE.17+ *18+ * Documentation about PPTP can be found in RFC 263719+ *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/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+static DEFINE_RWLOCK(ip_ct_gre_lock);36+#define ASSERT_READ_LOCK(x)37+#define ASSERT_WRITE_LOCK(x)38+39+#include <linux/netfilter_ipv4/listhelp.h>40+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>41+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>42+#include <linux/netfilter_ipv4/ip_conntrack_core.h>43+44+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>45+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>46+47+MODULE_LICENSE("GPL");48+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");49+MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");50+51+/* shamelessly stolen from ip_conntrack_proto_udp.c */52+#define GRE_TIMEOUT (30*HZ)53+#define GRE_STREAM_TIMEOUT (180*HZ)54+55+#if 056+#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)57+#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \58+ NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \59+ NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key))60+#else61+#define DEBUGP(x, args...)62+#define DUMP_TUPLE_GRE(x)63+#endif64+65+/* GRE KEYMAP HANDLING FUNCTIONS */66+static LIST_HEAD(gre_keymap_list);67+68+static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,69+ const struct ip_conntrack_tuple *t)70+{71+ return ((km->tuple.src.ip == t->src.ip) &&72+ (km->tuple.dst.ip == t->dst.ip) &&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 */78+static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)79+{80+ struct ip_ct_gre_keymap *km;81+ u_int32_t key = 0;82+83+ read_lock_bh(&ip_ct_gre_lock);84+ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,85+ struct ip_ct_gre_keymap *, t);86+ if (km)87+ key = km->tuple.src.u.gre.key;88+ read_unlock_bh(&ip_ct_gre_lock);89+90+ DEBUGP("lookup src key 0x%x up key for ", key);91+ DUMP_TUPLE_GRE(t);92+93+ return key;94+}95+96+/* add a single keymap entry, associate with specified master ct */97+int98+ip_ct_gre_keymap_add(struct ip_conntrack *ct,99+ struct ip_conntrack_tuple *t, int reply)100+{101+ struct ip_ct_gre_keymap **exist_km, *km, *old;102+103+ if (!ct->helper || strcmp(ct->helper->name, "pptp")) {104+ DEBUGP("refusing to add GRE keymap to non-pptp session\n");105+ return -1;106+ }107+108+ if (!reply) 109+ exist_km = &ct->help.ct_pptp_info.keymap_orig;110+ else111+ exist_km = &ct->help.ct_pptp_info.keymap_reply;112+113+ if (*exist_km) {114+ /* check whether it's a retransmission */115+ old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,116+ struct ip_ct_gre_keymap *, t);117+ if (old == *exist_km) {118+ DEBUGP("retransmission\n");119+ return 0;120+ }121+122+ DEBUGP("trying to override keymap_%s for ct %p\n", 123+ reply? "reply":"orig", ct);124+ return -EEXIST;125+ }126+127+ km = kmalloc(sizeof(*km), GFP_ATOMIC);128+ if (!km)129+ return -ENOMEM;130+131+ memcpy(&km->tuple, t, sizeof(*t));132+ *exist_km = km;133+134+ DEBUGP("adding new entry %p: ", km);135+ DUMP_TUPLE_GRE(&km->tuple);136+137+ write_lock_bh(&ip_ct_gre_lock);138+ list_append(&gre_keymap_list, km);139+ write_unlock_bh(&ip_ct_gre_lock);140+141+ return 0;142+}143+144+/* destroy the keymap entries associated with specified master ct */145+void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct)146+{147+ DEBUGP("entering for ct %p\n", ct);148+149+ if (!ct->helper || strcmp(ct->helper->name, "pptp")) {150+ DEBUGP("refusing to destroy GRE keymap to non-pptp session\n");151+ return;152+ }153+154+ write_lock_bh(&ip_ct_gre_lock);155+ if (ct->help.ct_pptp_info.keymap_orig) {156+ DEBUGP("removing %p from list\n", 157+ ct->help.ct_pptp_info.keymap_orig);158+ list_del(&ct->help.ct_pptp_info.keymap_orig->list);159+ kfree(ct->help.ct_pptp_info.keymap_orig);160+ ct->help.ct_pptp_info.keymap_orig = NULL;161+ }162+ if (ct->help.ct_pptp_info.keymap_reply) {163+ DEBUGP("removing %p from list\n",164+ ct->help.ct_pptp_info.keymap_reply);165+ list_del(&ct->help.ct_pptp_info.keymap_reply->list);166+ kfree(ct->help.ct_pptp_info.keymap_reply);167+ ct->help.ct_pptp_info.keymap_reply = NULL;168+ }169+ write_unlock_bh(&ip_ct_gre_lock);170+}171+172+173+/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */174+175+/* invert gre part of tuple */176+static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,177+ const struct ip_conntrack_tuple *orig)178+{179+ tuple->dst.u.gre.key = orig->src.u.gre.key;180+ tuple->src.u.gre.key = orig->dst.u.gre.key;181+182+ return 1;183+}184+185+/* gre hdr info to tuple */186+static int gre_pkt_to_tuple(const struct sk_buff *skb,187+ unsigned int dataoff,188+ struct ip_conntrack_tuple *tuple)189+{190+ struct gre_hdr_pptp _pgrehdr, *pgrehdr;191+ u_int32_t srckey;192+ struct gre_hdr _grehdr, *grehdr;193+194+ /* first only delinearize old RFC1701 GRE header */195+ grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);196+ if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {197+ /* try to behave like "ip_conntrack_proto_generic" */198+ tuple->src.u.all = 0;199+ tuple->dst.u.all = 0;200+ return 1;201+ }202+203+ /* PPTP header is variable length, only need up to the call_id field */204+ pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);205+ if (!pgrehdr)206+ return 1;207+208+ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {209+ DEBUGP("GRE_VERSION_PPTP but unknown proto\n");210+ return 0;211+ }212+213+ tuple->dst.u.gre.key = pgrehdr->call_id;214+ srckey = gre_keymap_lookup(tuple);215+ tuple->src.u.gre.key = srckey;216+217+ return 1;218+}219+220+/* print gre part of tuple */221+static int gre_print_tuple(struct seq_file *s,222+ const struct ip_conntrack_tuple *tuple)223+{224+ return seq_printf(s, "srckey=0x%x dstkey=0x%x ", 225+ ntohs(tuple->src.u.gre.key),226+ ntohs(tuple->dst.u.gre.key));227+}228+229+/* print private data for conntrack */230+static int gre_print_conntrack(struct seq_file *s,231+ const struct ip_conntrack *ct)232+{233+ return seq_printf(s, "timeout=%u, stream_timeout=%u ",234+ (ct->proto.gre.timeout / HZ),235+ (ct->proto.gre.stream_timeout / HZ));236+}237+238+/* Returns verdict for packet, and may modify conntrack */239+static int gre_packet(struct ip_conntrack *ct,240+ const struct sk_buff *skb,241+ enum ip_conntrack_info conntrackinfo)242+{243+ /* If we've seen traffic both ways, this is a GRE connection.244+ * Extend timeout. */245+ if (ct->status & IPS_SEEN_REPLY) {246+ ip_ct_refresh_acct(ct, conntrackinfo, skb,247+ ct->proto.gre.stream_timeout);248+ /* Also, more likely to be important, and not a probe. */249+ set_bit(IPS_ASSURED_BIT, &ct->status);250+ } else251+ ip_ct_refresh_acct(ct, conntrackinfo, skb,252+ ct->proto.gre.timeout);253+254+ return NF_ACCEPT;255+}256+257+/* Called when a new connection for this protocol found. */258+static int gre_new(struct ip_conntrack *ct,259+ const struct sk_buff *skb)260+{ 261+ DEBUGP(": ");262+ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);263+264+ /* initialize to sane value. Ideally a conntrack helper265+ * (e.g. in case of pptp) is increasing them */266+ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;267+ ct->proto.gre.timeout = GRE_TIMEOUT;268+269+ return 1;270+}271+272+/* Called when a conntrack entry has already been removed from the hashes273+ * and is about to be deleted from memory */274+static void gre_destroy(struct ip_conntrack *ct)275+{276+ struct ip_conntrack *master = ct->master;277+ DEBUGP(" entering\n");278+279+ if (!master)280+ DEBUGP("no master !?!\n");281+ else282+ ip_ct_gre_keymap_destroy(master);283+}284+285+/* protocol helper struct */286+static struct ip_conntrack_protocol gre = { 287+ .proto = IPPROTO_GRE,288+ .name = "gre", 289+ .pkt_to_tuple = gre_pkt_to_tuple,290+ .invert_tuple = gre_invert_tuple,291+ .print_tuple = gre_print_tuple,292+ .print_conntrack = gre_print_conntrack,293+ .packet = gre_packet,294+ .new = gre_new,295+ .destroy = gre_destroy,296+ .me = THIS_MODULE,297+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \298+ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)299+ .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,300+ .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,301+#endif302+};303+304+/* ip_conntrack_proto_gre initialization */305+int __init ip_ct_proto_gre_init(void)306+{307+ return ip_conntrack_protocol_register(&gre);308+}309+310+void __exit ip_ct_proto_gre_fini(void)311+{312+ struct list_head *pos, *n;313+314+ /* delete all keymap entries */315+ write_lock_bh(&ip_ct_gre_lock);316+ list_for_each_safe(pos, n, &gre_keymap_list) {317+ DEBUGP("deleting keymap %p at module unload time\n", pos);318+ list_del(pos);319+ kfree(pos);320+ }321+ write_unlock_bh(&ip_ct_gre_lock);322+323+ ip_conntrack_protocol_unregister(&gre); 324+}325+326+EXPORT_SYMBOL(ip_ct_gre_keymap_add);327+EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
···1+/*2+ * ip_nat_pptp.c - Version 3.03+ *4+ * NAT support for PPTP (Point to Point Tunneling Protocol).5+ * PPTP is a a protocol for creating virtual private networks.6+ * It is a specification defined by Microsoft and some vendors7+ * working with Microsoft. PPTP is built on top of a modified8+ * version of the Internet Generic Routing Encapsulation Protocol.9+ * GRE is defined in RFC 1701 and RFC 1702. Documentation of10+ * PPTP can be found in RFC 263711+ *12+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>13+ *14+ * Development of this code funded by Astaro AG (http://www.astaro.com/)15+ *16+ * TODO: - NAT to a unique tuple, not to TCP source port17+ * (needs netfilter tuple reservation)18+ *19+ * Changes:20+ * 2002-02-10 - Version 1.321+ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's22+ * in local connections (Philip Craig <philipc@snapgear.com>)23+ * - add checks for magicCookie and pptp version24+ * - make argument list of pptp_{out,in}bound_packet() shorter25+ * - move to C99 style initializers26+ * - print version number at module loadtime27+ * 2003-09-22 - Version 1.528+ * - use SNATed tcp sourceport as callid, since we get called before29+ * TCP header is mangled (Philip Craig <philipc@snapgear.com>)30+ * 2004-10-22 - Version 2.031+ * - kernel 2.6.x version32+ * 2005-06-10 - Version 3.033+ * - kernel >= 2.6.11 version,34+ * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)35+ * 36+ */37+38+#include <linux/config.h>39+#include <linux/module.h>40+#include <linux/ip.h>41+#include <linux/tcp.h>42+#include <net/tcp.h>43+44+#include <linux/netfilter_ipv4/ip_nat.h>45+#include <linux/netfilter_ipv4/ip_nat_rule.h>46+#include <linux/netfilter_ipv4/ip_nat_helper.h>47+#include <linux/netfilter_ipv4/ip_nat_pptp.h>48+#include <linux/netfilter_ipv4/ip_conntrack_core.h>49+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>50+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>51+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>52+53+#define IP_NAT_PPTP_VERSION "3.0"54+55+MODULE_LICENSE("GPL");56+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");57+MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");58+59+60+#if 061+extern const char *pptp_msg_name[];62+#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \63+ __FUNCTION__, ## args)64+#else65+#define DEBUGP(format, args...)66+#endif67+68+static void pptp_nat_expected(struct ip_conntrack *ct,69+ struct ip_conntrack_expect *exp)70+{71+ struct ip_conntrack *master = ct->master;72+ struct ip_conntrack_expect *other_exp;73+ struct ip_conntrack_tuple t;74+ struct ip_ct_pptp_master *ct_pptp_info;75+ struct ip_nat_pptp *nat_pptp_info;76+77+ ct_pptp_info = &master->help.ct_pptp_info;78+ nat_pptp_info = &master->nat.help.nat_pptp_info;79+80+ /* And here goes the grand finale of corrosion... */81+82+ if (exp->dir == IP_CT_DIR_ORIGINAL) {83+ DEBUGP("we are PNS->PAC\n");84+ /* therefore, build tuple for PAC->PNS */85+ t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;86+ t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id);87+ t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;88+ t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id);89+ t.dst.protonum = IPPROTO_GRE;90+ } else {91+ DEBUGP("we are PAC->PNS\n");92+ /* build tuple for PNS->PAC */93+ t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;94+ t.src.u.gre.key = 95+ htons(master->nat.help.nat_pptp_info.pns_call_id);96+ t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;97+ t.dst.u.gre.key = 98+ htons(master->nat.help.nat_pptp_info.pac_call_id);99+ t.dst.protonum = IPPROTO_GRE;100+ }101+102+ DEBUGP("trying to unexpect other dir: ");103+ DUMP_TUPLE(&t);104+ other_exp = ip_conntrack_expect_find(&t);105+ if (other_exp) {106+ ip_conntrack_unexpect_related(other_exp);107+ ip_conntrack_expect_put(other_exp);108+ DEBUGP("success\n");109+ } else {110+ DEBUGP("not found!\n");111+ }112+113+ ip_nat_follow_master(ct, exp);114+}115+116+/* outbound packets == from PNS to PAC */117+static int118+pptp_outbound_pkt(struct sk_buff **pskb,119+ struct ip_conntrack *ct,120+ enum ip_conntrack_info ctinfo,121+ struct PptpControlHeader *ctlh,122+ union pptp_ctrl_union *pptpReq)123+124+{125+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;126+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;127+128+ u_int16_t msg, *cid = NULL, new_callid;129+130+ new_callid = htons(ct_pptp_info->pns_call_id);131+132+ switch (msg = ntohs(ctlh->messageType)) {133+ case PPTP_OUT_CALL_REQUEST:134+ cid = &pptpReq->ocreq.callID;135+ /* FIXME: ideally we would want to reserve a call ID136+ * here. current netfilter NAT core is not able to do137+ * this :( For now we use TCP source port. This breaks138+ * multiple calls within one control session */139+140+ /* save original call ID in nat_info */141+ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;142+143+ /* don't use tcph->source since we are at a DSTmanip144+ * hook (e.g. PREROUTING) and pkt is not mangled yet */145+ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;146+147+ /* save new call ID in ct info */148+ ct_pptp_info->pns_call_id = ntohs(new_callid);149+ break;150+ case PPTP_IN_CALL_REPLY:151+ cid = &pptpReq->icreq.callID;152+ break;153+ case PPTP_CALL_CLEAR_REQUEST:154+ cid = &pptpReq->clrreq.callID;155+ break;156+ default:157+ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,158+ (msg <= PPTP_MSG_MAX)? 159+ pptp_msg_name[msg]:pptp_msg_name[0]);160+ /* fall through */161+162+ case PPTP_SET_LINK_INFO:163+ /* only need to NAT in case PAC is behind NAT box */164+ case PPTP_START_SESSION_REQUEST:165+ case PPTP_START_SESSION_REPLY:166+ case PPTP_STOP_SESSION_REQUEST:167+ case PPTP_STOP_SESSION_REPLY:168+ case PPTP_ECHO_REQUEST:169+ case PPTP_ECHO_REPLY:170+ /* no need to alter packet */171+ return NF_ACCEPT;172+ }173+174+ /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass175+ * down to here */176+177+ IP_NF_ASSERT(cid);178+179+ DEBUGP("altering call id from 0x%04x to 0x%04x\n",180+ ntohs(*cid), ntohs(new_callid));181+182+ /* mangle packet */183+ if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,184+ (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)),185+ sizeof(new_callid), 186+ (char *)&new_callid,187+ sizeof(new_callid)) == 0)188+ return NF_DROP;189+190+ return NF_ACCEPT;191+}192+193+static int194+pptp_exp_gre(struct ip_conntrack_expect *expect_orig,195+ struct ip_conntrack_expect *expect_reply)196+{197+ struct ip_ct_pptp_master *ct_pptp_info = 198+ &expect_orig->master->help.ct_pptp_info;199+ struct ip_nat_pptp *nat_pptp_info = 200+ &expect_orig->master->nat.help.nat_pptp_info;201+202+ struct ip_conntrack *ct = expect_orig->master;203+204+ struct ip_conntrack_tuple inv_t;205+ struct ip_conntrack_tuple *orig_t, *reply_t;206+207+ /* save original PAC call ID in nat_info */208+ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;209+210+ /* alter expectation */211+ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;212+ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;213+214+ /* alter expectation for PNS->PAC direction */215+ invert_tuplepr(&inv_t, &expect_orig->tuple);216+ expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id);217+ expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id);218+ expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);219+ inv_t.src.ip = reply_t->src.ip;220+ inv_t.dst.ip = reply_t->dst.ip;221+ inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id);222+ inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);223+224+ if (!ip_conntrack_expect_related(expect_orig)) {225+ DEBUGP("successfully registered expect\n");226+ } else {227+ DEBUGP("can't expect_related(expect_orig)\n");228+ return 1;229+ }230+231+ /* alter expectation for PAC->PNS direction */232+ invert_tuplepr(&inv_t, &expect_reply->tuple);233+ expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id);234+ expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id);235+ expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);236+ inv_t.src.ip = orig_t->src.ip;237+ inv_t.dst.ip = orig_t->dst.ip;238+ inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id);239+ inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);240+241+ if (!ip_conntrack_expect_related(expect_reply)) {242+ DEBUGP("successfully registered expect\n");243+ } else {244+ DEBUGP("can't expect_related(expect_reply)\n");245+ ip_conntrack_unexpect_related(expect_orig);246+ return 1;247+ }248+249+ if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) {250+ DEBUGP("can't register original keymap\n");251+ ip_conntrack_unexpect_related(expect_orig);252+ ip_conntrack_unexpect_related(expect_reply);253+ return 1;254+ }255+256+ if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) {257+ DEBUGP("can't register reply keymap\n");258+ ip_conntrack_unexpect_related(expect_orig);259+ ip_conntrack_unexpect_related(expect_reply);260+ ip_ct_gre_keymap_destroy(ct);261+ return 1;262+ }263+264+ return 0;265+}266+267+/* inbound packets == from PAC to PNS */268+static int269+pptp_inbound_pkt(struct sk_buff **pskb,270+ struct ip_conntrack *ct,271+ enum ip_conntrack_info ctinfo,272+ struct PptpControlHeader *ctlh,273+ union pptp_ctrl_union *pptpReq)274+{275+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;276+ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;277+278+ int ret = NF_ACCEPT, rv;279+280+ new_pcid = htons(nat_pptp_info->pns_call_id);281+282+ switch (msg = ntohs(ctlh->messageType)) {283+ case PPTP_OUT_CALL_REPLY:284+ pcid = &pptpReq->ocack.peersCallID; 285+ cid = &pptpReq->ocack.callID;286+ break;287+ case PPTP_IN_CALL_CONNECT:288+ pcid = &pptpReq->iccon.peersCallID;289+ break;290+ case PPTP_IN_CALL_REQUEST:291+ /* only need to nat in case PAC is behind NAT box */292+ break;293+ case PPTP_WAN_ERROR_NOTIFY:294+ pcid = &pptpReq->wanerr.peersCallID;295+ break;296+ case PPTP_CALL_DISCONNECT_NOTIFY:297+ pcid = &pptpReq->disc.callID;298+ break;299+ case PPTP_SET_LINK_INFO:300+ pcid = &pptpReq->setlink.peersCallID;301+ break;302+303+ default:304+ DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? 305+ pptp_msg_name[msg]:pptp_msg_name[0]);306+ /* fall through */307+308+ case PPTP_START_SESSION_REQUEST:309+ case PPTP_START_SESSION_REPLY:310+ case PPTP_STOP_SESSION_REQUEST:311+ case PPTP_STOP_SESSION_REPLY:312+ case PPTP_ECHO_REQUEST:313+ case PPTP_ECHO_REPLY:314+ /* no need to alter packet */315+ return NF_ACCEPT;316+ }317+318+ /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST,319+ * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */320+321+ /* mangle packet */322+ IP_NF_ASSERT(pcid);323+ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",324+ ntohs(*pcid), ntohs(new_pcid));325+326+ rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 327+ (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)),328+ sizeof(new_pcid), (char *)&new_pcid, 329+ sizeof(new_pcid));330+ if (rv != NF_ACCEPT) 331+ return rv;332+333+ if (new_cid) {334+ IP_NF_ASSERT(cid);335+ DEBUGP("altering call id from 0x%04x to 0x%04x\n",336+ ntohs(*cid), ntohs(new_cid));337+ rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 338+ (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 339+ sizeof(new_cid),340+ (char *)&new_cid, 341+ sizeof(new_cid));342+ if (rv != NF_ACCEPT)343+ return rv;344+ }345+346+ /* check for earlier return value of 'switch' above */347+ if (ret != NF_ACCEPT)348+ return ret;349+350+ /* great, at least we don't need to resize packets */351+ return NF_ACCEPT;352+}353+354+355+extern int __init ip_nat_proto_gre_init(void);356+extern void __exit ip_nat_proto_gre_fini(void);357+358+static int __init init(void)359+{360+ int ret;361+362+ DEBUGP("%s: registering NAT helper\n", __FILE__);363+364+ ret = ip_nat_proto_gre_init();365+ if (ret < 0)366+ return ret;367+368+ BUG_ON(ip_nat_pptp_hook_outbound);369+ ip_nat_pptp_hook_outbound = &pptp_outbound_pkt;370+371+ BUG_ON(ip_nat_pptp_hook_inbound);372+ ip_nat_pptp_hook_inbound = &pptp_inbound_pkt;373+374+ BUG_ON(ip_nat_pptp_hook_exp_gre);375+ ip_nat_pptp_hook_exp_gre = &pptp_exp_gre;376+377+ BUG_ON(ip_nat_pptp_hook_expectfn);378+ ip_nat_pptp_hook_expectfn = &pptp_nat_expected;379+380+ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);381+ return 0;382+}383+384+static void __exit fini(void)385+{386+ DEBUGP("cleanup_module\n" );387+388+ ip_nat_pptp_hook_expectfn = NULL;389+ ip_nat_pptp_hook_exp_gre = NULL;390+ ip_nat_pptp_hook_inbound = NULL;391+ ip_nat_pptp_hook_outbound = NULL;392+393+ ip_nat_proto_gre_fini();394+ /* Make sure noone calls it, meanwhile */395+ synchronize_net();396+397+ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);398+}399+400+module_init(init);401+module_exit(fini);
···1+/*2+ * ip_nat_proto_gre.c - Version 2.03+ *4+ * NAT protocol helper module for GRE.5+ *6+ * GRE is a generic encapsulation protocol, which is generally not very7+ * 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 mandatory15+ * field called "CallID", which serves us for the same purpose as the key16+ * field in plain GRE.17+ *18+ * Documentation about PPTP can be found in RFC 263719+ *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/config.h>27+#include <linux/module.h>28+#include <linux/ip.h>29+#include <linux/netfilter_ipv4/ip_nat.h>30+#include <linux/netfilter_ipv4/ip_nat_rule.h>31+#include <linux/netfilter_ipv4/ip_nat_protocol.h>32+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>33+34+MODULE_LICENSE("GPL");35+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");36+MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");37+38+#if 039+#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \40+ __FUNCTION__, ## args)41+#else42+#define DEBUGP(x, args...)43+#endif44+45+/* is key in given range between min and max */46+static int47+gre_in_range(const struct ip_conntrack_tuple *tuple,48+ enum ip_nat_manip_type maniptype,49+ const union ip_conntrack_manip_proto *min,50+ const union ip_conntrack_manip_proto *max)51+{52+ u_int32_t key;53+54+ if (maniptype == IP_NAT_MANIP_SRC)55+ key = tuple->src.u.gre.key;56+ else57+ key = tuple->dst.u.gre.key;58+59+ return ntohl(key) >= ntohl(min->gre.key)60+ && ntohl(key) <= ntohl(max->gre.key);61+}62+63+/* generate unique tuple ... */64+static int 65+gre_unique_tuple(struct ip_conntrack_tuple *tuple,66+ const struct ip_nat_range *range,67+ enum ip_nat_manip_type maniptype,68+ const struct ip_conntrack *conntrack)69+{70+ static u_int16_t key;71+ u_int16_t *keyptr;72+ unsigned int min, i, range_size;73+74+ if (maniptype == IP_NAT_MANIP_SRC)75+ keyptr = &tuple->src.u.gre.key;76+ else77+ keyptr = &tuple->dst.u.gre.key;78+79+ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {80+ DEBUGP("%p: NATing GRE PPTP\n", conntrack);81+ min = 1;82+ range_size = 0xffff;83+ } else {84+ min = ntohl(range->min.gre.key);85+ range_size = ntohl(range->max.gre.key) - min + 1;86+ }87+88+ DEBUGP("min = %u, range_size = %u\n", min, range_size); 89+90+ for (i = 0; i < range_size; i++, key++) {91+ *keyptr = htonl(min + key % range_size);92+ if (!ip_nat_used_tuple(tuple, conntrack))93+ return 1;94+ }95+96+ DEBUGP("%p: no NAT mapping\n", conntrack);97+98+ return 0;99+}100+101+/* manipulate a GRE packet according to maniptype */102+static int103+gre_manip_pkt(struct sk_buff **pskb,104+ unsigned int iphdroff,105+ const struct ip_conntrack_tuple *tuple,106+ enum ip_nat_manip_type maniptype)107+{108+ struct gre_hdr *greh;109+ struct gre_hdr_pptp *pgreh;110+ struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);111+ unsigned int hdroff = iphdroff + iph->ihl*4;112+113+ /* pgreh includes two optional 32bit fields which are not required114+ * to be there. That's where the magic '8' comes from */115+ if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8))116+ return 0;117+118+ greh = (void *)(*pskb)->data + hdroff;119+ pgreh = (struct gre_hdr_pptp *) greh;120+121+ /* we only have destination manip of a packet, since 'source key' 122+ * is not present in the packet itself */123+ if (maniptype == IP_NAT_MANIP_DST) {124+ /* key manipulation is always dest */125+ switch (greh->version) {126+ case 0:127+ if (!greh->key) {128+ DEBUGP("can't nat GRE w/o key\n");129+ break;130+ }131+ if (greh->csum) {132+ /* FIXME: Never tested this code... */133+ *(gre_csum(greh)) = 134+ ip_nat_cheat_check(~*(gre_key(greh)),135+ tuple->dst.u.gre.key,136+ *(gre_csum(greh)));137+ }138+ *(gre_key(greh)) = tuple->dst.u.gre.key;139+ break;140+ case GRE_VERSION_PPTP:141+ DEBUGP("call_id -> 0x%04x\n", 142+ ntohl(tuple->dst.u.gre.key));143+ pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key));144+ break;145+ default:146+ DEBUGP("can't nat unknown GRE version\n");147+ return 0;148+ break;149+ }150+ }151+ return 1;152+}153+154+/* print out a nat tuple */155+static unsigned int 156+gre_print(char *buffer, 157+ const struct ip_conntrack_tuple *match,158+ const struct ip_conntrack_tuple *mask)159+{160+ unsigned int len = 0;161+162+ if (mask->src.u.gre.key)163+ len += sprintf(buffer + len, "srckey=0x%x ", 164+ ntohl(match->src.u.gre.key));165+166+ if (mask->dst.u.gre.key)167+ len += sprintf(buffer + len, "dstkey=0x%x ",168+ ntohl(match->src.u.gre.key));169+170+ return len;171+}172+173+/* print a range of keys */174+static unsigned int 175+gre_print_range(char *buffer, const struct ip_nat_range *range)176+{177+ if (range->min.gre.key != 0 178+ || range->max.gre.key != 0xFFFF) {179+ if (range->min.gre.key == range->max.gre.key)180+ return sprintf(buffer, "key 0x%x ",181+ ntohl(range->min.gre.key));182+ else183+ return sprintf(buffer, "keys 0x%u-0x%u ",184+ ntohl(range->min.gre.key),185+ ntohl(range->max.gre.key));186+ } else187+ return 0;188+}189+190+/* nat helper struct */191+static struct ip_nat_protocol gre = { 192+ .name = "GRE", 193+ .protonum = IPPROTO_GRE,194+ .manip_pkt = gre_manip_pkt,195+ .in_range = gre_in_range,196+ .unique_tuple = gre_unique_tuple,197+ .print = gre_print,198+ .print_range = gre_print_range,199+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \200+ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)201+ .range_to_nfattr = ip_nat_port_range_to_nfattr,202+ .nfattr_to_range = ip_nat_port_nfattr_to_range,203+#endif204+};205+206+int __init ip_nat_proto_gre_init(void)207+{208+ return ip_nat_protocol_register(&gre);209+}210+211+void __exit ip_nat_proto_gre_fini(void)212+{213+ ip_nat_protocol_unregister(&gre);214+}