···4242struct vlan_ethhdr {4343 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */4444 unsigned char h_source[ETH_ALEN]; /* source ether addr */4545- unsigned short h_vlan_proto; /* Should always be 0x8100 */4646- unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */4545+ __be16 h_vlan_proto; /* Should always be 0x8100 */4646+ __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */4747 unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */4848};4949···5555}56565757struct vlan_hdr {5858- unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */5959- unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */5858+ __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */5959+ __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */6060};61616262#define VLAN_VID_MASK 0xfff
+13-1
include/linux/netfilter_ipv4/ip_conntrack.h
···133133134134#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>135135#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>136136+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>136137#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>137138138139/* per conntrack: protocol private data */139140union ip_conntrack_proto {140141 /* insert conntrack proto private data here */142142+ struct ip_ct_gre gre;141143 struct ip_ct_sctp sctp;142144 struct ip_ct_tcp tcp;143145 struct ip_ct_icmp icmp;···150148};151149152150/* Add protocol helper include file here */151151+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>153152#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>154153#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>155154#include <linux/netfilter_ipv4/ip_conntrack_irc.h>···158155/* per conntrack: application helper private data */159156union ip_conntrack_help {160157 /* insert conntrack helper private data (master) here */158158+ struct ip_ct_pptp_master ct_pptp_info;161159 struct ip_ct_ftp_master ct_ftp_info;162160 struct ip_ct_irc_master ct_irc_info;163161};164162165163#ifdef CONFIG_IP_NF_NAT_NEEDED166164#include <linux/netfilter_ipv4/ip_nat.h>165165+#include <linux/netfilter_ipv4/ip_nat_pptp.h>166166+167167+/* per conntrack: nat application helper private data */168168+union ip_conntrack_nat_help {169169+ /* insert nat helper private data here */170170+ struct ip_nat_pptp nat_pptp_info;171171+};167172#endif168173169174#include <linux/types.h>···234223#ifdef CONFIG_IP_NF_NAT_NEEDED235224 struct {236225 struct ip_nat_info info;226226+ union ip_conntrack_nat_help help;237227#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \238228 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)239229 int masq_index;···384372__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);385373386374extern struct ip_conntrack_expect *387387-ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);375375+ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);388376389377extern struct ip_conntrack_tuple_hash *390378__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
···11+#ifndef _CONNTRACK_PROTO_GRE_H22+#define _CONNTRACK_PROTO_GRE_H33+#include <asm/byteorder.h>44+55+/* GRE PROTOCOL HEADER */66+77+/* GRE Version field */88+#define GRE_VERSION_1701 0x099+#define GRE_VERSION_PPTP 0x11010+1111+/* GRE Protocol field */1212+#define GRE_PROTOCOL_PPTP 0x880B1313+1414+/* GRE Flags */1515+#define GRE_FLAG_C 0x801616+#define GRE_FLAG_R 0x401717+#define GRE_FLAG_K 0x201818+#define GRE_FLAG_S 0x101919+#define GRE_FLAG_A 0x802020+2121+#define GRE_IS_C(f) ((f)&GRE_FLAG_C)2222+#define GRE_IS_R(f) ((f)&GRE_FLAG_R)2323+#define GRE_IS_K(f) ((f)&GRE_FLAG_K)2424+#define GRE_IS_S(f) ((f)&GRE_FLAG_S)2525+#define GRE_IS_A(f) ((f)&GRE_FLAG_A)2626+2727+/* GRE is a mess: Four different standards */2828+struct gre_hdr {2929+#if defined(__LITTLE_ENDIAN_BITFIELD)3030+ __u16 rec:3,3131+ srr:1,3232+ seq:1,3333+ key:1,3434+ routing:1,3535+ csum:1,3636+ version:3,3737+ reserved:4,3838+ ack:1;3939+#elif defined(__BIG_ENDIAN_BITFIELD)4040+ __u16 csum:1,4141+ routing:1,4242+ key:1,4343+ seq:1,4444+ srr:1,4545+ rec:3,4646+ ack:1,4747+ reserved:4,4848+ version:3;4949+#else5050+#error "Adjust your <asm/byteorder.h> defines"5151+#endif5252+ __u16 protocol;5353+};5454+5555+/* modified GRE header for PPTP */5656+struct gre_hdr_pptp {5757+ __u8 flags; /* bitfield */5858+ __u8 version; /* should be GRE_VERSION_PPTP */5959+ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */6060+ __u16 payload_len; /* size of ppp payload, not inc. gre header */6161+ __u16 call_id; /* peer's call_id for this session */6262+ __u32 seq; /* sequence number. Present if S==1 */6363+ __u32 ack; /* seq number of highest packet recieved by */6464+ /* sender in this session */6565+};6666+6767+6868+/* this is part of ip_conntrack */6969+struct ip_ct_gre {7070+ unsigned int stream_timeout;7171+ unsigned int timeout;7272+};7373+7474+#ifdef __KERNEL__7575+struct ip_conntrack_expect;7676+struct ip_conntrack;7777+7878+/* structure for original <-> reply keymap */7979+struct ip_ct_gre_keymap {8080+ struct list_head list;8181+8282+ struct ip_conntrack_tuple tuple;8383+};8484+8585+/* add new tuple->key_reply pair to keymap */8686+int ip_ct_gre_keymap_add(struct ip_conntrack *ct,8787+ struct ip_conntrack_tuple *t,8888+ int reply);8989+9090+/* delete keymap entries */9191+void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct);9292+9393+9494+/* get pointer to gre key, if present */9595+static inline u_int32_t *gre_key(struct gre_hdr *greh)9696+{9797+ if (!greh->key)9898+ return NULL;9999+ if (greh->csum || greh->routing)100100+ return (u_int32_t *) (greh+sizeof(*greh)+4);101101+ return (u_int32_t *) (greh+sizeof(*greh));102102+}103103+104104+/* get pointer ot gre csum, if present */105105+static inline u_int16_t *gre_csum(struct gre_hdr *greh)106106+{107107+ if (!greh->csum)108108+ return NULL;109109+ return (u_int16_t *) (greh+sizeof(*greh));110110+}111111+112112+#endif /* __KERNEL__ */113113+114114+#endif /* _CONNTRACK_PROTO_GRE_H */
+7
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
···2828 struct {2929 u_int16_t port;3030 } sctp;3131+ struct {3232+ u_int16_t key; /* key is 32bit, pptp only uses 16 */3333+ } gre;3134};32353336/* The manipulable part of the tuple. */···6461 struct {6562 u_int16_t port;6663 } sctp;6464+ struct {6565+ u_int16_t key; /* key is 32bit, 6666+ * pptp only uses 16 */6767+ } gre;6768 } u;68696970 /* The protocol. */
+11
include/linux/netfilter_ipv4/ip_nat_pptp.h
···11+/* PPTP constants and structs */22+#ifndef _NAT_PPTP_H33+#define _NAT_PPTP_H44+55+/* conntrack private data */66+struct ip_nat_pptp {77+ u_int16_t pns_call_id; /* NAT'ed PNS call id */88+ u_int16_t pac_call_id; /* NAT'ed PAC call id */99+};1010+1111+#endif /* _NAT_PPTP_H */
+3
include/linux/netfilter_ipv6/ip6_tables.h
···455455456456/* Check for an extension */457457extern int ip6t_ext_hdr(u8 nexthdr);458458+/* find specified header and get offset to it */459459+extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,460460+ u8 target);458461459462#define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))460463
+1-1
net/8021q/vlan_dev.c
···120120 unsigned short vid;121121 struct net_device_stats *stats;122122 unsigned short vlan_TCI;123123- unsigned short proto;123123+ __be16 proto;124124125125 /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */126126 vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+17-17
net/ipv4/fib_trie.c
···4343 * 2 of the License, or (at your option) any later version.4444 */45454646-#define VERSION "0.403"4646+#define VERSION "0.404"47474848#include <linux/config.h>4949#include <asm/uaccess.h>···224224 Consider a node 'n' and its parent 'tp'.225225226226 If n is a leaf, every bit in its key is significant. Its presence is 227227- necessitaded by path compression, since during a tree traversal (when 227227+ necessitated by path compression, since during a tree traversal (when 228228 searching for a leaf - unless we are doing an insertion) we will completely 229229 ignore all skipped bits we encounter. Thus we need to verify, at the end of 230230 a potentially successful search, that we have indeed been walking the ···836836#endif837837}838838839839-/* readside most use rcu_read_lock currently dump routines839839+/* readside must use rcu_read_lock currently dump routines840840 via get_fa_head and dump */841841842842-static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen)842842+static struct leaf_info *find_leaf_info(struct leaf *l, int plen)843843{844844+ struct hlist_head *head = &l->list;844845 struct hlist_node *node;845846 struct leaf_info *li;846847···854853855854static inline struct list_head * get_fa_head(struct leaf *l, int plen)856855{857857- struct leaf_info *li = find_leaf_info(&l->list, plen);856856+ struct leaf_info *li = find_leaf_info(l, plen);858857859858 if (!li)860859 return NULL;···12491248}125012491251125012521252-/* should be clalled with rcu_read_lock */12511251+/* should be called with rcu_read_lock */12531252static inline int check_leaf(struct trie *t, struct leaf *l,12541253 t_key key, int *plen, const struct flowi *flp,12551254 struct fib_result *res)···15911590 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);1592159115931592 l = fib_find_node(t, key);15941594- li = find_leaf_info(&l->list, plen);15931593+ li = find_leaf_info(l, plen);1595159415961595 list_del_rcu(&fa->fa_list);15971596···1715171417161715 t->revision++;1717171617181718- rcu_read_lock();17191717 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {17201718 found += trie_flush_leaf(t, l);17211719···17221722 trie_leaf_remove(t, ll->key);17231723 ll = l;17241724 }17251725- rcu_read_unlock(); 1726172517271726 if (ll && hlist_empty(&ll->list))17281727 trie_leaf_remove(t, ll->key);···20282029 iter->tnode = (struct tnode *) n;20292030 iter->trie = t;20302031 iter->index = 0;20312031- iter->depth = 0;20322032+ iter->depth = 1;20322033 return n;20332034 }20342035 return NULL;···22732274 seq_puts(seq, "<local>:\n");22742275 else22752276 seq_puts(seq, "<main>:\n");22762276- } else {22772277- seq_indent(seq, iter->depth-1);22782278- seq_printf(seq, " +-- %d.%d.%d.%d/%d\n",22792279- NIPQUAD(prf), tn->pos);22802280- }22772277+ } 22782278+ seq_indent(seq, iter->depth-1);22792279+ seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n",22802280+ NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, 22812281+ tn->empty_children);22822282+22812283 } else {22822284 struct leaf *l = (struct leaf *) n;22832285 int i;···22872287 seq_indent(seq, iter->depth);22882288 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));22892289 for (i = 32; i >= 0; i--) {22902290- struct leaf_info *li = find_leaf_info(&l->list, i);22902290+ struct leaf_info *li = find_leaf_info(l, i);22912291 if (li) {22922292 struct fib_alias *fa;22932293 list_for_each_entry_rcu(fa, &li->falh, fa_list) {···23832383 return 0;2384238423852385 for (i=32; i>=0; i--) {23862386- struct leaf_info *li = find_leaf_info(&l->list, i);23862386+ struct leaf_info *li = find_leaf_info(l, i);23872387 struct fib_alias *fa;23882388 u32 mask, prefix;23892389
+22
net/ipv4/netfilter/Kconfig
···137137138138 To compile it as a module, choose M here. If unsure, say Y.139139140140+config IP_NF_PPTP141141+ tristate 'PPTP protocol support'142142+ help143143+ This module adds support for PPTP (Point to Point Tunnelling144144+ Protocol, RFC2637) conncection tracking and NAT. 145145+146146+ If you are running PPTP sessions over a stateful firewall or NAT147147+ box, you may want to enable this feature. 148148+149149+ Please note that not all PPTP modes of operation are supported yet.150150+ For more info, read top of the file151151+ net/ipv4/netfilter/ip_conntrack_pptp.c152152+153153+ If you want to compile it as a module, say M here and read154154+ Documentation/modules.txt. If unsure, say `N'.155155+140156config IP_NF_QUEUE141157 tristate "IP Userspace queueing via NETLINK (OBSOLETE)"142158 help···636620 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n637621 default IP_NF_NAT if IP_NF_AMANDA=y638622 default m if IP_NF_AMANDA=m623623+624624+config IP_NF_NAT_PPTP625625+ tristate626626+ depends on IP_NF_NAT!=n && IP_NF_PPTP!=n627627+ default IP_NF_NAT if IP_NF_PPTP=y628628+ default m if IP_NF_PPTP=m639629640630# mangle + specific targets641631config IP_NF_MANGLE
···11+/*22+ * ip_conntrack_proto_gre.c - Version 3.0 33+ *44+ * Connection tracking protocol helper module for GRE.55+ *66+ * GRE is a generic encapsulation protocol, which is generally not very77+ * suited for NAT, as it has no protocol-specific part as port numbers.88+ *99+ * It has an optional key field, which may help us distinguishing two 1010+ * connections between the same two hosts.1111+ *1212+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 1313+ *1414+ * PPTP is built on top of a modified version of GRE, and has a mandatory1515+ * field called "CallID", which serves us for the same purpose as the key1616+ * field in plain GRE.1717+ *1818+ * Documentation about PPTP can be found in RFC 26371919+ *2020+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>2121+ *2222+ * Development of this code funded by Astaro AG (http://www.astaro.com/)2323+ *2424+ */2525+2626+#include <linux/config.h>2727+#include <linux/module.h>2828+#include <linux/types.h>2929+#include <linux/timer.h>3030+#include <linux/netfilter.h>3131+#include <linux/ip.h>3232+#include <linux/in.h>3333+#include <linux/list.h>3434+3535+static DEFINE_RWLOCK(ip_ct_gre_lock);3636+#define ASSERT_READ_LOCK(x)3737+#define ASSERT_WRITE_LOCK(x)3838+3939+#include <linux/netfilter_ipv4/listhelp.h>4040+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>4141+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>4242+#include <linux/netfilter_ipv4/ip_conntrack_core.h>4343+4444+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>4545+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>4646+4747+MODULE_LICENSE("GPL");4848+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");4949+MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");5050+5151+/* shamelessly stolen from ip_conntrack_proto_udp.c */5252+#define GRE_TIMEOUT (30*HZ)5353+#define GRE_STREAM_TIMEOUT (180*HZ)5454+5555+#if 05656+#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)5757+#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \5858+ NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \5959+ NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key))6060+#else6161+#define DEBUGP(x, args...)6262+#define DUMP_TUPLE_GRE(x)6363+#endif6464+6565+/* GRE KEYMAP HANDLING FUNCTIONS */6666+static LIST_HEAD(gre_keymap_list);6767+6868+static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,6969+ const struct ip_conntrack_tuple *t)7070+{7171+ return ((km->tuple.src.ip == t->src.ip) &&7272+ (km->tuple.dst.ip == t->dst.ip) &&7373+ (km->tuple.dst.protonum == t->dst.protonum) &&7474+ (km->tuple.dst.u.all == t->dst.u.all));7575+}7676+7777+/* look up the source key for a given tuple */7878+static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)7979+{8080+ struct ip_ct_gre_keymap *km;8181+ u_int32_t key = 0;8282+8383+ read_lock_bh(&ip_ct_gre_lock);8484+ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,8585+ struct ip_ct_gre_keymap *, t);8686+ if (km)8787+ key = km->tuple.src.u.gre.key;8888+ read_unlock_bh(&ip_ct_gre_lock);8989+9090+ DEBUGP("lookup src key 0x%x up key for ", key);9191+ DUMP_TUPLE_GRE(t);9292+9393+ return key;9494+}9595+9696+/* add a single keymap entry, associate with specified master ct */9797+int9898+ip_ct_gre_keymap_add(struct ip_conntrack *ct,9999+ struct ip_conntrack_tuple *t, int reply)100100+{101101+ struct ip_ct_gre_keymap **exist_km, *km, *old;102102+103103+ if (!ct->helper || strcmp(ct->helper->name, "pptp")) {104104+ DEBUGP("refusing to add GRE keymap to non-pptp session\n");105105+ return -1;106106+ }107107+108108+ if (!reply) 109109+ exist_km = &ct->help.ct_pptp_info.keymap_orig;110110+ else111111+ exist_km = &ct->help.ct_pptp_info.keymap_reply;112112+113113+ if (*exist_km) {114114+ /* check whether it's a retransmission */115115+ old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,116116+ struct ip_ct_gre_keymap *, t);117117+ if (old == *exist_km) {118118+ DEBUGP("retransmission\n");119119+ return 0;120120+ }121121+122122+ DEBUGP("trying to override keymap_%s for ct %p\n", 123123+ reply? "reply":"orig", ct);124124+ return -EEXIST;125125+ }126126+127127+ km = kmalloc(sizeof(*km), GFP_ATOMIC);128128+ if (!km)129129+ return -ENOMEM;130130+131131+ memcpy(&km->tuple, t, sizeof(*t));132132+ *exist_km = km;133133+134134+ DEBUGP("adding new entry %p: ", km);135135+ DUMP_TUPLE_GRE(&km->tuple);136136+137137+ write_lock_bh(&ip_ct_gre_lock);138138+ list_append(&gre_keymap_list, km);139139+ write_unlock_bh(&ip_ct_gre_lock);140140+141141+ return 0;142142+}143143+144144+/* destroy the keymap entries associated with specified master ct */145145+void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct)146146+{147147+ DEBUGP("entering for ct %p\n", ct);148148+149149+ if (!ct->helper || strcmp(ct->helper->name, "pptp")) {150150+ DEBUGP("refusing to destroy GRE keymap to non-pptp session\n");151151+ return;152152+ }153153+154154+ write_lock_bh(&ip_ct_gre_lock);155155+ if (ct->help.ct_pptp_info.keymap_orig) {156156+ DEBUGP("removing %p from list\n", 157157+ ct->help.ct_pptp_info.keymap_orig);158158+ list_del(&ct->help.ct_pptp_info.keymap_orig->list);159159+ kfree(ct->help.ct_pptp_info.keymap_orig);160160+ ct->help.ct_pptp_info.keymap_orig = NULL;161161+ }162162+ if (ct->help.ct_pptp_info.keymap_reply) {163163+ DEBUGP("removing %p from list\n",164164+ ct->help.ct_pptp_info.keymap_reply);165165+ list_del(&ct->help.ct_pptp_info.keymap_reply->list);166166+ kfree(ct->help.ct_pptp_info.keymap_reply);167167+ ct->help.ct_pptp_info.keymap_reply = NULL;168168+ }169169+ write_unlock_bh(&ip_ct_gre_lock);170170+}171171+172172+173173+/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */174174+175175+/* invert gre part of tuple */176176+static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,177177+ const struct ip_conntrack_tuple *orig)178178+{179179+ tuple->dst.u.gre.key = orig->src.u.gre.key;180180+ tuple->src.u.gre.key = orig->dst.u.gre.key;181181+182182+ return 1;183183+}184184+185185+/* gre hdr info to tuple */186186+static int gre_pkt_to_tuple(const struct sk_buff *skb,187187+ unsigned int dataoff,188188+ struct ip_conntrack_tuple *tuple)189189+{190190+ struct gre_hdr_pptp _pgrehdr, *pgrehdr;191191+ u_int32_t srckey;192192+ struct gre_hdr _grehdr, *grehdr;193193+194194+ /* first only delinearize old RFC1701 GRE header */195195+ grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);196196+ if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {197197+ /* try to behave like "ip_conntrack_proto_generic" */198198+ tuple->src.u.all = 0;199199+ tuple->dst.u.all = 0;200200+ return 1;201201+ }202202+203203+ /* PPTP header is variable length, only need up to the call_id field */204204+ pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);205205+ if (!pgrehdr)206206+ return 1;207207+208208+ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {209209+ DEBUGP("GRE_VERSION_PPTP but unknown proto\n");210210+ return 0;211211+ }212212+213213+ tuple->dst.u.gre.key = pgrehdr->call_id;214214+ srckey = gre_keymap_lookup(tuple);215215+ tuple->src.u.gre.key = srckey;216216+217217+ return 1;218218+}219219+220220+/* print gre part of tuple */221221+static int gre_print_tuple(struct seq_file *s,222222+ const struct ip_conntrack_tuple *tuple)223223+{224224+ return seq_printf(s, "srckey=0x%x dstkey=0x%x ", 225225+ ntohs(tuple->src.u.gre.key),226226+ ntohs(tuple->dst.u.gre.key));227227+}228228+229229+/* print private data for conntrack */230230+static int gre_print_conntrack(struct seq_file *s,231231+ const struct ip_conntrack *ct)232232+{233233+ return seq_printf(s, "timeout=%u, stream_timeout=%u ",234234+ (ct->proto.gre.timeout / HZ),235235+ (ct->proto.gre.stream_timeout / HZ));236236+}237237+238238+/* Returns verdict for packet, and may modify conntrack */239239+static int gre_packet(struct ip_conntrack *ct,240240+ const struct sk_buff *skb,241241+ enum ip_conntrack_info conntrackinfo)242242+{243243+ /* If we've seen traffic both ways, this is a GRE connection.244244+ * Extend timeout. */245245+ if (ct->status & IPS_SEEN_REPLY) {246246+ ip_ct_refresh_acct(ct, conntrackinfo, skb,247247+ ct->proto.gre.stream_timeout);248248+ /* Also, more likely to be important, and not a probe. */249249+ set_bit(IPS_ASSURED_BIT, &ct->status);250250+ } else251251+ ip_ct_refresh_acct(ct, conntrackinfo, skb,252252+ ct->proto.gre.timeout);253253+254254+ return NF_ACCEPT;255255+}256256+257257+/* Called when a new connection for this protocol found. */258258+static int gre_new(struct ip_conntrack *ct,259259+ const struct sk_buff *skb)260260+{ 261261+ DEBUGP(": ");262262+ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);263263+264264+ /* initialize to sane value. Ideally a conntrack helper265265+ * (e.g. in case of pptp) is increasing them */266266+ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;267267+ ct->proto.gre.timeout = GRE_TIMEOUT;268268+269269+ return 1;270270+}271271+272272+/* Called when a conntrack entry has already been removed from the hashes273273+ * and is about to be deleted from memory */274274+static void gre_destroy(struct ip_conntrack *ct)275275+{276276+ struct ip_conntrack *master = ct->master;277277+ DEBUGP(" entering\n");278278+279279+ if (!master)280280+ DEBUGP("no master !?!\n");281281+ else282282+ ip_ct_gre_keymap_destroy(master);283283+}284284+285285+/* protocol helper struct */286286+static struct ip_conntrack_protocol gre = { 287287+ .proto = IPPROTO_GRE,288288+ .name = "gre", 289289+ .pkt_to_tuple = gre_pkt_to_tuple,290290+ .invert_tuple = gre_invert_tuple,291291+ .print_tuple = gre_print_tuple,292292+ .print_conntrack = gre_print_conntrack,293293+ .packet = gre_packet,294294+ .new = gre_new,295295+ .destroy = gre_destroy,296296+ .me = THIS_MODULE,297297+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \298298+ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)299299+ .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,300300+ .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,301301+#endif302302+};303303+304304+/* ip_conntrack_proto_gre initialization */305305+int __init ip_ct_proto_gre_init(void)306306+{307307+ return ip_conntrack_protocol_register(&gre);308308+}309309+310310+void __exit ip_ct_proto_gre_fini(void)311311+{312312+ struct list_head *pos, *n;313313+314314+ /* delete all keymap entries */315315+ write_lock_bh(&ip_ct_gre_lock);316316+ list_for_each_safe(pos, n, &gre_keymap_list) {317317+ DEBUGP("deleting keymap %p at module unload time\n", pos);318318+ list_del(pos);319319+ kfree(pos);320320+ }321321+ write_unlock_bh(&ip_ct_gre_lock);322322+323323+ ip_conntrack_protocol_unregister(&gre); 324324+}325325+326326+EXPORT_SYMBOL(ip_ct_gre_keymap_add);327327+EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
···11+/*22+ * ip_nat_pptp.c - Version 3.033+ *44+ * NAT support for PPTP (Point to Point Tunneling Protocol).55+ * PPTP is a a protocol for creating virtual private networks.66+ * It is a specification defined by Microsoft and some vendors77+ * working with Microsoft. PPTP is built on top of a modified88+ * version of the Internet Generic Routing Encapsulation Protocol.99+ * GRE is defined in RFC 1701 and RFC 1702. Documentation of1010+ * PPTP can be found in RFC 26371111+ *1212+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>1313+ *1414+ * Development of this code funded by Astaro AG (http://www.astaro.com/)1515+ *1616+ * TODO: - NAT to a unique tuple, not to TCP source port1717+ * (needs netfilter tuple reservation)1818+ *1919+ * Changes:2020+ * 2002-02-10 - Version 1.32121+ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's2222+ * in local connections (Philip Craig <philipc@snapgear.com>)2323+ * - add checks for magicCookie and pptp version2424+ * - make argument list of pptp_{out,in}bound_packet() shorter2525+ * - move to C99 style initializers2626+ * - print version number at module loadtime2727+ * 2003-09-22 - Version 1.52828+ * - use SNATed tcp sourceport as callid, since we get called before2929+ * TCP header is mangled (Philip Craig <philipc@snapgear.com>)3030+ * 2004-10-22 - Version 2.03131+ * - kernel 2.6.x version3232+ * 2005-06-10 - Version 3.03333+ * - kernel >= 2.6.11 version,3434+ * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)3535+ * 3636+ */3737+3838+#include <linux/config.h>3939+#include <linux/module.h>4040+#include <linux/ip.h>4141+#include <linux/tcp.h>4242+#include <net/tcp.h>4343+4444+#include <linux/netfilter_ipv4/ip_nat.h>4545+#include <linux/netfilter_ipv4/ip_nat_rule.h>4646+#include <linux/netfilter_ipv4/ip_nat_helper.h>4747+#include <linux/netfilter_ipv4/ip_nat_pptp.h>4848+#include <linux/netfilter_ipv4/ip_conntrack_core.h>4949+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>5050+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>5151+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>5252+5353+#define IP_NAT_PPTP_VERSION "3.0"5454+5555+MODULE_LICENSE("GPL");5656+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");5757+MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");5858+5959+6060+#if 06161+extern const char *pptp_msg_name[];6262+#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \6363+ __FUNCTION__, ## args)6464+#else6565+#define DEBUGP(format, args...)6666+#endif6767+6868+static void pptp_nat_expected(struct ip_conntrack *ct,6969+ struct ip_conntrack_expect *exp)7070+{7171+ struct ip_conntrack *master = ct->master;7272+ struct ip_conntrack_expect *other_exp;7373+ struct ip_conntrack_tuple t;7474+ struct ip_ct_pptp_master *ct_pptp_info;7575+ struct ip_nat_pptp *nat_pptp_info;7676+7777+ ct_pptp_info = &master->help.ct_pptp_info;7878+ nat_pptp_info = &master->nat.help.nat_pptp_info;7979+8080+ /* And here goes the grand finale of corrosion... */8181+8282+ if (exp->dir == IP_CT_DIR_ORIGINAL) {8383+ DEBUGP("we are PNS->PAC\n");8484+ /* therefore, build tuple for PAC->PNS */8585+ t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;8686+ t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id);8787+ t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;8888+ t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id);8989+ t.dst.protonum = IPPROTO_GRE;9090+ } else {9191+ DEBUGP("we are PAC->PNS\n");9292+ /* build tuple for PNS->PAC */9393+ t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;9494+ t.src.u.gre.key = 9595+ htons(master->nat.help.nat_pptp_info.pns_call_id);9696+ t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;9797+ t.dst.u.gre.key = 9898+ htons(master->nat.help.nat_pptp_info.pac_call_id);9999+ t.dst.protonum = IPPROTO_GRE;100100+ }101101+102102+ DEBUGP("trying to unexpect other dir: ");103103+ DUMP_TUPLE(&t);104104+ other_exp = ip_conntrack_expect_find(&t);105105+ if (other_exp) {106106+ ip_conntrack_unexpect_related(other_exp);107107+ ip_conntrack_expect_put(other_exp);108108+ DEBUGP("success\n");109109+ } else {110110+ DEBUGP("not found!\n");111111+ }112112+113113+ ip_nat_follow_master(ct, exp);114114+}115115+116116+/* outbound packets == from PNS to PAC */117117+static int118118+pptp_outbound_pkt(struct sk_buff **pskb,119119+ struct ip_conntrack *ct,120120+ enum ip_conntrack_info ctinfo,121121+ struct PptpControlHeader *ctlh,122122+ union pptp_ctrl_union *pptpReq)123123+124124+{125125+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;126126+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;127127+128128+ u_int16_t msg, *cid = NULL, new_callid;129129+130130+ new_callid = htons(ct_pptp_info->pns_call_id);131131+132132+ switch (msg = ntohs(ctlh->messageType)) {133133+ case PPTP_OUT_CALL_REQUEST:134134+ cid = &pptpReq->ocreq.callID;135135+ /* FIXME: ideally we would want to reserve a call ID136136+ * here. current netfilter NAT core is not able to do137137+ * this :( For now we use TCP source port. This breaks138138+ * multiple calls within one control session */139139+140140+ /* save original call ID in nat_info */141141+ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;142142+143143+ /* don't use tcph->source since we are at a DSTmanip144144+ * hook (e.g. PREROUTING) and pkt is not mangled yet */145145+ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;146146+147147+ /* save new call ID in ct info */148148+ ct_pptp_info->pns_call_id = ntohs(new_callid);149149+ break;150150+ case PPTP_IN_CALL_REPLY:151151+ cid = &pptpReq->icreq.callID;152152+ break;153153+ case PPTP_CALL_CLEAR_REQUEST:154154+ cid = &pptpReq->clrreq.callID;155155+ break;156156+ default:157157+ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,158158+ (msg <= PPTP_MSG_MAX)? 159159+ pptp_msg_name[msg]:pptp_msg_name[0]);160160+ /* fall through */161161+162162+ case PPTP_SET_LINK_INFO:163163+ /* only need to NAT in case PAC is behind NAT box */164164+ case PPTP_START_SESSION_REQUEST:165165+ case PPTP_START_SESSION_REPLY:166166+ case PPTP_STOP_SESSION_REQUEST:167167+ case PPTP_STOP_SESSION_REPLY:168168+ case PPTP_ECHO_REQUEST:169169+ case PPTP_ECHO_REPLY:170170+ /* no need to alter packet */171171+ return NF_ACCEPT;172172+ }173173+174174+ /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass175175+ * down to here */176176+177177+ IP_NF_ASSERT(cid);178178+179179+ DEBUGP("altering call id from 0x%04x to 0x%04x\n",180180+ ntohs(*cid), ntohs(new_callid));181181+182182+ /* mangle packet */183183+ if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,184184+ (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)),185185+ sizeof(new_callid), 186186+ (char *)&new_callid,187187+ sizeof(new_callid)) == 0)188188+ return NF_DROP;189189+190190+ return NF_ACCEPT;191191+}192192+193193+static int194194+pptp_exp_gre(struct ip_conntrack_expect *expect_orig,195195+ struct ip_conntrack_expect *expect_reply)196196+{197197+ struct ip_ct_pptp_master *ct_pptp_info = 198198+ &expect_orig->master->help.ct_pptp_info;199199+ struct ip_nat_pptp *nat_pptp_info = 200200+ &expect_orig->master->nat.help.nat_pptp_info;201201+202202+ struct ip_conntrack *ct = expect_orig->master;203203+204204+ struct ip_conntrack_tuple inv_t;205205+ struct ip_conntrack_tuple *orig_t, *reply_t;206206+207207+ /* save original PAC call ID in nat_info */208208+ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;209209+210210+ /* alter expectation */211211+ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;212212+ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;213213+214214+ /* alter expectation for PNS->PAC direction */215215+ invert_tuplepr(&inv_t, &expect_orig->tuple);216216+ expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id);217217+ expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id);218218+ expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);219219+ inv_t.src.ip = reply_t->src.ip;220220+ inv_t.dst.ip = reply_t->dst.ip;221221+ inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id);222222+ inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);223223+224224+ if (!ip_conntrack_expect_related(expect_orig)) {225225+ DEBUGP("successfully registered expect\n");226226+ } else {227227+ DEBUGP("can't expect_related(expect_orig)\n");228228+ return 1;229229+ }230230+231231+ /* alter expectation for PAC->PNS direction */232232+ invert_tuplepr(&inv_t, &expect_reply->tuple);233233+ expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id);234234+ expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id);235235+ expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);236236+ inv_t.src.ip = orig_t->src.ip;237237+ inv_t.dst.ip = orig_t->dst.ip;238238+ inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id);239239+ inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);240240+241241+ if (!ip_conntrack_expect_related(expect_reply)) {242242+ DEBUGP("successfully registered expect\n");243243+ } else {244244+ DEBUGP("can't expect_related(expect_reply)\n");245245+ ip_conntrack_unexpect_related(expect_orig);246246+ return 1;247247+ }248248+249249+ if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) {250250+ DEBUGP("can't register original keymap\n");251251+ ip_conntrack_unexpect_related(expect_orig);252252+ ip_conntrack_unexpect_related(expect_reply);253253+ return 1;254254+ }255255+256256+ if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) {257257+ DEBUGP("can't register reply keymap\n");258258+ ip_conntrack_unexpect_related(expect_orig);259259+ ip_conntrack_unexpect_related(expect_reply);260260+ ip_ct_gre_keymap_destroy(ct);261261+ return 1;262262+ }263263+264264+ return 0;265265+}266266+267267+/* inbound packets == from PAC to PNS */268268+static int269269+pptp_inbound_pkt(struct sk_buff **pskb,270270+ struct ip_conntrack *ct,271271+ enum ip_conntrack_info ctinfo,272272+ struct PptpControlHeader *ctlh,273273+ union pptp_ctrl_union *pptpReq)274274+{275275+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;276276+ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;277277+278278+ int ret = NF_ACCEPT, rv;279279+280280+ new_pcid = htons(nat_pptp_info->pns_call_id);281281+282282+ switch (msg = ntohs(ctlh->messageType)) {283283+ case PPTP_OUT_CALL_REPLY:284284+ pcid = &pptpReq->ocack.peersCallID; 285285+ cid = &pptpReq->ocack.callID;286286+ break;287287+ case PPTP_IN_CALL_CONNECT:288288+ pcid = &pptpReq->iccon.peersCallID;289289+ break;290290+ case PPTP_IN_CALL_REQUEST:291291+ /* only need to nat in case PAC is behind NAT box */292292+ break;293293+ case PPTP_WAN_ERROR_NOTIFY:294294+ pcid = &pptpReq->wanerr.peersCallID;295295+ break;296296+ case PPTP_CALL_DISCONNECT_NOTIFY:297297+ pcid = &pptpReq->disc.callID;298298+ break;299299+ case PPTP_SET_LINK_INFO:300300+ pcid = &pptpReq->setlink.peersCallID;301301+ break;302302+303303+ default:304304+ DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? 305305+ pptp_msg_name[msg]:pptp_msg_name[0]);306306+ /* fall through */307307+308308+ case PPTP_START_SESSION_REQUEST:309309+ case PPTP_START_SESSION_REPLY:310310+ case PPTP_STOP_SESSION_REQUEST:311311+ case PPTP_STOP_SESSION_REPLY:312312+ case PPTP_ECHO_REQUEST:313313+ case PPTP_ECHO_REPLY:314314+ /* no need to alter packet */315315+ return NF_ACCEPT;316316+ }317317+318318+ /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST,319319+ * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */320320+321321+ /* mangle packet */322322+ IP_NF_ASSERT(pcid);323323+ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",324324+ ntohs(*pcid), ntohs(new_pcid));325325+326326+ rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 327327+ (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)),328328+ sizeof(new_pcid), (char *)&new_pcid, 329329+ sizeof(new_pcid));330330+ if (rv != NF_ACCEPT) 331331+ return rv;332332+333333+ if (new_cid) {334334+ IP_NF_ASSERT(cid);335335+ DEBUGP("altering call id from 0x%04x to 0x%04x\n",336336+ ntohs(*cid), ntohs(new_cid));337337+ rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 338338+ (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 339339+ sizeof(new_cid),340340+ (char *)&new_cid, 341341+ sizeof(new_cid));342342+ if (rv != NF_ACCEPT)343343+ return rv;344344+ }345345+346346+ /* check for earlier return value of 'switch' above */347347+ if (ret != NF_ACCEPT)348348+ return ret;349349+350350+ /* great, at least we don't need to resize packets */351351+ return NF_ACCEPT;352352+}353353+354354+355355+extern int __init ip_nat_proto_gre_init(void);356356+extern void __exit ip_nat_proto_gre_fini(void);357357+358358+static int __init init(void)359359+{360360+ int ret;361361+362362+ DEBUGP("%s: registering NAT helper\n", __FILE__);363363+364364+ ret = ip_nat_proto_gre_init();365365+ if (ret < 0)366366+ return ret;367367+368368+ BUG_ON(ip_nat_pptp_hook_outbound);369369+ ip_nat_pptp_hook_outbound = &pptp_outbound_pkt;370370+371371+ BUG_ON(ip_nat_pptp_hook_inbound);372372+ ip_nat_pptp_hook_inbound = &pptp_inbound_pkt;373373+374374+ BUG_ON(ip_nat_pptp_hook_exp_gre);375375+ ip_nat_pptp_hook_exp_gre = &pptp_exp_gre;376376+377377+ BUG_ON(ip_nat_pptp_hook_expectfn);378378+ ip_nat_pptp_hook_expectfn = &pptp_nat_expected;379379+380380+ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);381381+ return 0;382382+}383383+384384+static void __exit fini(void)385385+{386386+ DEBUGP("cleanup_module\n" );387387+388388+ ip_nat_pptp_hook_expectfn = NULL;389389+ ip_nat_pptp_hook_exp_gre = NULL;390390+ ip_nat_pptp_hook_inbound = NULL;391391+ ip_nat_pptp_hook_outbound = NULL;392392+393393+ ip_nat_proto_gre_fini();394394+ /* Make sure noone calls it, meanwhile */395395+ synchronize_net();396396+397397+ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);398398+}399399+400400+module_init(init);401401+module_exit(fini);
+214
net/ipv4/netfilter/ip_nat_proto_gre.c
···11+/*22+ * ip_nat_proto_gre.c - Version 2.033+ *44+ * NAT protocol helper module for GRE.55+ *66+ * GRE is a generic encapsulation protocol, which is generally not very77+ * suited for NAT, as it has no protocol-specific part as port numbers.88+ *99+ * It has an optional key field, which may help us distinguishing two 1010+ * connections between the same two hosts.1111+ *1212+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 1313+ *1414+ * PPTP is built on top of a modified version of GRE, and has a mandatory1515+ * field called "CallID", which serves us for the same purpose as the key1616+ * field in plain GRE.1717+ *1818+ * Documentation about PPTP can be found in RFC 26371919+ *2020+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>2121+ *2222+ * Development of this code funded by Astaro AG (http://www.astaro.com/)2323+ *2424+ */2525+2626+#include <linux/config.h>2727+#include <linux/module.h>2828+#include <linux/ip.h>2929+#include <linux/netfilter_ipv4/ip_nat.h>3030+#include <linux/netfilter_ipv4/ip_nat_rule.h>3131+#include <linux/netfilter_ipv4/ip_nat_protocol.h>3232+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>3333+3434+MODULE_LICENSE("GPL");3535+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");3636+MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");3737+3838+#if 03939+#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \4040+ __FUNCTION__, ## args)4141+#else4242+#define DEBUGP(x, args...)4343+#endif4444+4545+/* is key in given range between min and max */4646+static int4747+gre_in_range(const struct ip_conntrack_tuple *tuple,4848+ enum ip_nat_manip_type maniptype,4949+ const union ip_conntrack_manip_proto *min,5050+ const union ip_conntrack_manip_proto *max)5151+{5252+ u_int32_t key;5353+5454+ if (maniptype == IP_NAT_MANIP_SRC)5555+ key = tuple->src.u.gre.key;5656+ else5757+ key = tuple->dst.u.gre.key;5858+5959+ return ntohl(key) >= ntohl(min->gre.key)6060+ && ntohl(key) <= ntohl(max->gre.key);6161+}6262+6363+/* generate unique tuple ... */6464+static int 6565+gre_unique_tuple(struct ip_conntrack_tuple *tuple,6666+ const struct ip_nat_range *range,6767+ enum ip_nat_manip_type maniptype,6868+ const struct ip_conntrack *conntrack)6969+{7070+ static u_int16_t key;7171+ u_int16_t *keyptr;7272+ unsigned int min, i, range_size;7373+7474+ if (maniptype == IP_NAT_MANIP_SRC)7575+ keyptr = &tuple->src.u.gre.key;7676+ else7777+ keyptr = &tuple->dst.u.gre.key;7878+7979+ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {8080+ DEBUGP("%p: NATing GRE PPTP\n", conntrack);8181+ min = 1;8282+ range_size = 0xffff;8383+ } else {8484+ min = ntohl(range->min.gre.key);8585+ range_size = ntohl(range->max.gre.key) - min + 1;8686+ }8787+8888+ DEBUGP("min = %u, range_size = %u\n", min, range_size); 8989+9090+ for (i = 0; i < range_size; i++, key++) {9191+ *keyptr = htonl(min + key % range_size);9292+ if (!ip_nat_used_tuple(tuple, conntrack))9393+ return 1;9494+ }9595+9696+ DEBUGP("%p: no NAT mapping\n", conntrack);9797+9898+ return 0;9999+}100100+101101+/* manipulate a GRE packet according to maniptype */102102+static int103103+gre_manip_pkt(struct sk_buff **pskb,104104+ unsigned int iphdroff,105105+ const struct ip_conntrack_tuple *tuple,106106+ enum ip_nat_manip_type maniptype)107107+{108108+ struct gre_hdr *greh;109109+ struct gre_hdr_pptp *pgreh;110110+ struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);111111+ unsigned int hdroff = iphdroff + iph->ihl*4;112112+113113+ /* pgreh includes two optional 32bit fields which are not required114114+ * to be there. That's where the magic '8' comes from */115115+ if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8))116116+ return 0;117117+118118+ greh = (void *)(*pskb)->data + hdroff;119119+ pgreh = (struct gre_hdr_pptp *) greh;120120+121121+ /* we only have destination manip of a packet, since 'source key' 122122+ * is not present in the packet itself */123123+ if (maniptype == IP_NAT_MANIP_DST) {124124+ /* key manipulation is always dest */125125+ switch (greh->version) {126126+ case 0:127127+ if (!greh->key) {128128+ DEBUGP("can't nat GRE w/o key\n");129129+ break;130130+ }131131+ if (greh->csum) {132132+ /* FIXME: Never tested this code... */133133+ *(gre_csum(greh)) = 134134+ ip_nat_cheat_check(~*(gre_key(greh)),135135+ tuple->dst.u.gre.key,136136+ *(gre_csum(greh)));137137+ }138138+ *(gre_key(greh)) = tuple->dst.u.gre.key;139139+ break;140140+ case GRE_VERSION_PPTP:141141+ DEBUGP("call_id -> 0x%04x\n", 142142+ ntohl(tuple->dst.u.gre.key));143143+ pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key));144144+ break;145145+ default:146146+ DEBUGP("can't nat unknown GRE version\n");147147+ return 0;148148+ break;149149+ }150150+ }151151+ return 1;152152+}153153+154154+/* print out a nat tuple */155155+static unsigned int 156156+gre_print(char *buffer, 157157+ const struct ip_conntrack_tuple *match,158158+ const struct ip_conntrack_tuple *mask)159159+{160160+ unsigned int len = 0;161161+162162+ if (mask->src.u.gre.key)163163+ len += sprintf(buffer + len, "srckey=0x%x ", 164164+ ntohl(match->src.u.gre.key));165165+166166+ if (mask->dst.u.gre.key)167167+ len += sprintf(buffer + len, "dstkey=0x%x ",168168+ ntohl(match->src.u.gre.key));169169+170170+ return len;171171+}172172+173173+/* print a range of keys */174174+static unsigned int 175175+gre_print_range(char *buffer, const struct ip_nat_range *range)176176+{177177+ if (range->min.gre.key != 0 178178+ || range->max.gre.key != 0xFFFF) {179179+ if (range->min.gre.key == range->max.gre.key)180180+ return sprintf(buffer, "key 0x%x ",181181+ ntohl(range->min.gre.key));182182+ else183183+ return sprintf(buffer, "keys 0x%u-0x%u ",184184+ ntohl(range->min.gre.key),185185+ ntohl(range->max.gre.key));186186+ } else187187+ return 0;188188+}189189+190190+/* nat helper struct */191191+static struct ip_nat_protocol gre = { 192192+ .name = "GRE", 193193+ .protonum = IPPROTO_GRE,194194+ .manip_pkt = gre_manip_pkt,195195+ .in_range = gre_in_range,196196+ .unique_tuple = gre_unique_tuple,197197+ .print = gre_print,198198+ .print_range = gre_print_range,199199+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \200200+ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)201201+ .range_to_nfattr = ip_nat_port_range_to_nfattr,202202+ .nfattr_to_range = ip_nat_port_nfattr_to_range,203203+#endif204204+};205205+206206+int __init ip_nat_proto_gre_init(void)207207+{208208+ return ip_nat_protocol_register(&gre);209209+}210210+211211+void __exit ip_nat_proto_gre_fini(void)212212+{213213+ ip_nat_protocol_unregister(&gre);214214+}