cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nf_conntrack_pptp.c (18274B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
      4 * PPTP is a protocol for creating virtual private networks.
      5 * It is a specification defined by Microsoft and some vendors
      6 * working with Microsoft.  PPTP is built on top of a modified
      7 * version of the Internet Generic Routing Encapsulation Protocol.
      8 * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
      9 * PPTP can be found in RFC 2637
     10 *
     11 * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
     12 *
     13 * Development of this code funded by Astaro AG (http://www.astaro.com/)
     14 *
     15 * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
     16 *
     17 * Limitations:
     18 * 	 - We blindly assume that control connections are always
     19 * 	   established in PNS->PAC direction.  This is a violation
     20 *	   of RFC 2637
     21 * 	 - We can only support one single call within each session
     22 * TODO:
     23 *	 - testing of incoming PPTP calls
     24 */
     25
     26#include <linux/module.h>
     27#include <linux/skbuff.h>
     28#include <linux/in.h>
     29#include <linux/tcp.h>
     30
     31#include <net/netfilter/nf_conntrack.h>
     32#include <net/netfilter/nf_conntrack_core.h>
     33#include <net/netfilter/nf_conntrack_helper.h>
     34#include <net/netfilter/nf_conntrack_zones.h>
     35#include <linux/netfilter/nf_conntrack_proto_gre.h>
     36#include <linux/netfilter/nf_conntrack_pptp.h>
     37
     38#define NF_CT_PPTP_VERSION "3.1"
     39
     40MODULE_LICENSE("GPL");
     41MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
     42MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
     43MODULE_ALIAS("ip_conntrack_pptp");
     44MODULE_ALIAS_NFCT_HELPER("pptp");
     45
     46static DEFINE_SPINLOCK(nf_pptp_lock);
     47
     48const struct nf_nat_pptp_hook *nf_nat_pptp_hook;
     49EXPORT_SYMBOL_GPL(nf_nat_pptp_hook);
     50
     51#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
     52/* PptpControlMessageType names */
     53static const char *const pptp_msg_name_array[PPTP_MSG_MAX + 1] = {
     54	[0]				= "UNKNOWN_MESSAGE",
     55	[PPTP_START_SESSION_REQUEST]	= "START_SESSION_REQUEST",
     56	[PPTP_START_SESSION_REPLY]	= "START_SESSION_REPLY",
     57	[PPTP_STOP_SESSION_REQUEST]	= "STOP_SESSION_REQUEST",
     58	[PPTP_STOP_SESSION_REPLY]	= "STOP_SESSION_REPLY",
     59	[PPTP_ECHO_REQUEST]		= "ECHO_REQUEST",
     60	[PPTP_ECHO_REPLY]		= "ECHO_REPLY",
     61	[PPTP_OUT_CALL_REQUEST]		= "OUT_CALL_REQUEST",
     62	[PPTP_OUT_CALL_REPLY]		= "OUT_CALL_REPLY",
     63	[PPTP_IN_CALL_REQUEST]		= "IN_CALL_REQUEST",
     64	[PPTP_IN_CALL_REPLY]		= "IN_CALL_REPLY",
     65	[PPTP_IN_CALL_CONNECT]		= "IN_CALL_CONNECT",
     66	[PPTP_CALL_CLEAR_REQUEST]	= "CALL_CLEAR_REQUEST",
     67	[PPTP_CALL_DISCONNECT_NOTIFY]	= "CALL_DISCONNECT_NOTIFY",
     68	[PPTP_WAN_ERROR_NOTIFY]		= "WAN_ERROR_NOTIFY",
     69	[PPTP_SET_LINK_INFO]		= "SET_LINK_INFO"
     70};
     71
     72const char *pptp_msg_name(u_int16_t msg)
     73{
     74	if (msg > PPTP_MSG_MAX)
     75		return pptp_msg_name_array[0];
     76
     77	return pptp_msg_name_array[msg];
     78}
     79EXPORT_SYMBOL(pptp_msg_name);
     80#endif
     81
     82#define SECS *HZ
     83#define MINS * 60 SECS
     84#define HOURS * 60 MINS
     85
     86#define PPTP_GRE_TIMEOUT 		(10 MINS)
     87#define PPTP_GRE_STREAM_TIMEOUT 	(5 HOURS)
     88
     89static void pptp_expectfn(struct nf_conn *ct,
     90			 struct nf_conntrack_expect *exp)
     91{
     92	const struct nf_nat_pptp_hook *hook;
     93	struct net *net = nf_ct_net(ct);
     94	pr_debug("increasing timeouts\n");
     95
     96	/* increase timeout of GRE data channel conntrack entry */
     97	ct->proto.gre.timeout	     = PPTP_GRE_TIMEOUT;
     98	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
     99
    100	/* Can you see how rusty this code is, compared with the pre-2.6.11
    101	 * one? That's what happened to my shiny newnat of 2002 ;( -HW */
    102
    103	hook = rcu_dereference(nf_nat_pptp_hook);
    104	if (hook && ct->master->status & IPS_NAT_MASK)
    105		hook->expectfn(ct, exp);
    106	else {
    107		struct nf_conntrack_tuple inv_t;
    108		struct nf_conntrack_expect *exp_other;
    109
    110		/* obviously this tuple inversion only works until you do NAT */
    111		nf_ct_invert_tuple(&inv_t, &exp->tuple);
    112		pr_debug("trying to unexpect other dir: ");
    113		nf_ct_dump_tuple(&inv_t);
    114
    115		exp_other = nf_ct_expect_find_get(net, nf_ct_zone(ct), &inv_t);
    116		if (exp_other) {
    117			/* delete other expectation.  */
    118			pr_debug("found\n");
    119			nf_ct_unexpect_related(exp_other);
    120			nf_ct_expect_put(exp_other);
    121		} else {
    122			pr_debug("not found\n");
    123		}
    124	}
    125}
    126
    127static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct,
    128				  const struct nf_conntrack_tuple *t)
    129{
    130	const struct nf_conntrack_tuple_hash *h;
    131	const struct nf_conntrack_zone *zone;
    132	struct nf_conntrack_expect *exp;
    133	struct nf_conn *sibling;
    134
    135	pr_debug("trying to timeout ct or exp for tuple ");
    136	nf_ct_dump_tuple(t);
    137
    138	zone = nf_ct_zone(ct);
    139	h = nf_conntrack_find_get(net, zone, t);
    140	if (h)  {
    141		sibling = nf_ct_tuplehash_to_ctrack(h);
    142		pr_debug("setting timeout of conntrack %p to 0\n", sibling);
    143		sibling->proto.gre.timeout	  = 0;
    144		sibling->proto.gre.stream_timeout = 0;
    145		nf_ct_kill(sibling);
    146		nf_ct_put(sibling);
    147		return 1;
    148	} else {
    149		exp = nf_ct_expect_find_get(net, zone, t);
    150		if (exp) {
    151			pr_debug("unexpect_related of expect %p\n", exp);
    152			nf_ct_unexpect_related(exp);
    153			nf_ct_expect_put(exp);
    154			return 1;
    155		}
    156	}
    157	return 0;
    158}
    159
    160/* timeout GRE data connections */
    161static void pptp_destroy_siblings(struct nf_conn *ct)
    162{
    163	struct net *net = nf_ct_net(ct);
    164	const struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
    165	struct nf_conntrack_tuple t;
    166
    167	nf_ct_gre_keymap_destroy(ct);
    168
    169	/* try original (pns->pac) tuple */
    170	memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t));
    171	t.dst.protonum = IPPROTO_GRE;
    172	t.src.u.gre.key = ct_pptp_info->pns_call_id;
    173	t.dst.u.gre.key = ct_pptp_info->pac_call_id;
    174	if (!destroy_sibling_or_exp(net, ct, &t))
    175		pr_debug("failed to timeout original pns->pac ct/exp\n");
    176
    177	/* try reply (pac->pns) tuple */
    178	memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
    179	t.dst.protonum = IPPROTO_GRE;
    180	t.src.u.gre.key = ct_pptp_info->pac_call_id;
    181	t.dst.u.gre.key = ct_pptp_info->pns_call_id;
    182	if (!destroy_sibling_or_exp(net, ct, &t))
    183		pr_debug("failed to timeout reply pac->pns ct/exp\n");
    184}
    185
    186/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
    187static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
    188{
    189	struct nf_conntrack_expect *exp_orig, *exp_reply;
    190	const struct nf_nat_pptp_hook *hook;
    191	enum ip_conntrack_dir dir;
    192	int ret = 1;
    193
    194	exp_orig = nf_ct_expect_alloc(ct);
    195	if (exp_orig == NULL)
    196		goto out;
    197
    198	exp_reply = nf_ct_expect_alloc(ct);
    199	if (exp_reply == NULL)
    200		goto out_put_orig;
    201
    202	/* original direction, PNS->PAC */
    203	dir = IP_CT_DIR_ORIGINAL;
    204	nf_ct_expect_init(exp_orig, NF_CT_EXPECT_CLASS_DEFAULT,
    205			  nf_ct_l3num(ct),
    206			  &ct->tuplehash[dir].tuple.src.u3,
    207			  &ct->tuplehash[dir].tuple.dst.u3,
    208			  IPPROTO_GRE, &peer_callid, &callid);
    209	exp_orig->expectfn = pptp_expectfn;
    210
    211	/* reply direction, PAC->PNS */
    212	dir = IP_CT_DIR_REPLY;
    213	nf_ct_expect_init(exp_reply, NF_CT_EXPECT_CLASS_DEFAULT,
    214			  nf_ct_l3num(ct),
    215			  &ct->tuplehash[dir].tuple.src.u3,
    216			  &ct->tuplehash[dir].tuple.dst.u3,
    217			  IPPROTO_GRE, &callid, &peer_callid);
    218	exp_reply->expectfn = pptp_expectfn;
    219
    220	hook = rcu_dereference(nf_nat_pptp_hook);
    221	if (hook && ct->status & IPS_NAT_MASK)
    222		hook->exp_gre(exp_orig, exp_reply);
    223	if (nf_ct_expect_related(exp_orig, 0) != 0)
    224		goto out_put_both;
    225	if (nf_ct_expect_related(exp_reply, 0) != 0)
    226		goto out_unexpect_orig;
    227
    228	/* Add GRE keymap entries */
    229	if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_ORIGINAL, &exp_orig->tuple) != 0)
    230		goto out_unexpect_both;
    231	if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_REPLY, &exp_reply->tuple) != 0) {
    232		nf_ct_gre_keymap_destroy(ct);
    233		goto out_unexpect_both;
    234	}
    235	ret = 0;
    236
    237out_put_both:
    238	nf_ct_expect_put(exp_reply);
    239out_put_orig:
    240	nf_ct_expect_put(exp_orig);
    241out:
    242	return ret;
    243
    244out_unexpect_both:
    245	nf_ct_unexpect_related(exp_reply);
    246out_unexpect_orig:
    247	nf_ct_unexpect_related(exp_orig);
    248	goto out_put_both;
    249}
    250
    251static int
    252pptp_inbound_pkt(struct sk_buff *skb, unsigned int protoff,
    253		 struct PptpControlHeader *ctlh,
    254		 union pptp_ctrl_union *pptpReq,
    255		 unsigned int reqlen,
    256		 struct nf_conn *ct,
    257		 enum ip_conntrack_info ctinfo)
    258{
    259	struct nf_ct_pptp_master *info = nfct_help_data(ct);
    260	const struct nf_nat_pptp_hook *hook;
    261	u_int16_t msg;
    262	__be16 cid = 0, pcid = 0;
    263
    264	msg = ntohs(ctlh->messageType);
    265	pr_debug("inbound control message %s\n", pptp_msg_name(msg));
    266
    267	switch (msg) {
    268	case PPTP_START_SESSION_REPLY:
    269		/* server confirms new control session */
    270		if (info->sstate < PPTP_SESSION_REQUESTED)
    271			goto invalid;
    272		if (pptpReq->srep.resultCode == PPTP_START_OK)
    273			info->sstate = PPTP_SESSION_CONFIRMED;
    274		else
    275			info->sstate = PPTP_SESSION_ERROR;
    276		break;
    277
    278	case PPTP_STOP_SESSION_REPLY:
    279		/* server confirms end of control session */
    280		if (info->sstate > PPTP_SESSION_STOPREQ)
    281			goto invalid;
    282		if (pptpReq->strep.resultCode == PPTP_STOP_OK)
    283			info->sstate = PPTP_SESSION_NONE;
    284		else
    285			info->sstate = PPTP_SESSION_ERROR;
    286		break;
    287
    288	case PPTP_OUT_CALL_REPLY:
    289		/* server accepted call, we now expect GRE frames */
    290		if (info->sstate != PPTP_SESSION_CONFIRMED)
    291			goto invalid;
    292		if (info->cstate != PPTP_CALL_OUT_REQ &&
    293		    info->cstate != PPTP_CALL_OUT_CONF)
    294			goto invalid;
    295
    296		cid = pptpReq->ocack.callID;
    297		pcid = pptpReq->ocack.peersCallID;
    298		if (info->pns_call_id != pcid)
    299			goto invalid;
    300		pr_debug("%s, CID=%X, PCID=%X\n", pptp_msg_name(msg),
    301			 ntohs(cid), ntohs(pcid));
    302
    303		if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) {
    304			info->cstate = PPTP_CALL_OUT_CONF;
    305			info->pac_call_id = cid;
    306			exp_gre(ct, cid, pcid);
    307		} else
    308			info->cstate = PPTP_CALL_NONE;
    309		break;
    310
    311	case PPTP_IN_CALL_REQUEST:
    312		/* server tells us about incoming call request */
    313		if (info->sstate != PPTP_SESSION_CONFIRMED)
    314			goto invalid;
    315
    316		cid = pptpReq->icreq.callID;
    317		pr_debug("%s, CID=%X\n", pptp_msg_name(msg), ntohs(cid));
    318		info->cstate = PPTP_CALL_IN_REQ;
    319		info->pac_call_id = cid;
    320		break;
    321
    322	case PPTP_IN_CALL_CONNECT:
    323		/* server tells us about incoming call established */
    324		if (info->sstate != PPTP_SESSION_CONFIRMED)
    325			goto invalid;
    326		if (info->cstate != PPTP_CALL_IN_REP &&
    327		    info->cstate != PPTP_CALL_IN_CONF)
    328			goto invalid;
    329
    330		pcid = pptpReq->iccon.peersCallID;
    331		cid = info->pac_call_id;
    332
    333		if (info->pns_call_id != pcid)
    334			goto invalid;
    335
    336		pr_debug("%s, PCID=%X\n", pptp_msg_name(msg), ntohs(pcid));
    337		info->cstate = PPTP_CALL_IN_CONF;
    338
    339		/* we expect a GRE connection from PAC to PNS */
    340		exp_gre(ct, cid, pcid);
    341		break;
    342
    343	case PPTP_CALL_DISCONNECT_NOTIFY:
    344		/* server confirms disconnect */
    345		cid = pptpReq->disc.callID;
    346		pr_debug("%s, CID=%X\n", pptp_msg_name(msg), ntohs(cid));
    347		info->cstate = PPTP_CALL_NONE;
    348
    349		/* untrack this call id, unexpect GRE packets */
    350		pptp_destroy_siblings(ct);
    351		break;
    352
    353	case PPTP_WAN_ERROR_NOTIFY:
    354	case PPTP_SET_LINK_INFO:
    355	case PPTP_ECHO_REQUEST:
    356	case PPTP_ECHO_REPLY:
    357		/* I don't have to explain these ;) */
    358		break;
    359
    360	default:
    361		goto invalid;
    362	}
    363
    364	hook = rcu_dereference(nf_nat_pptp_hook);
    365	if (hook && ct->status & IPS_NAT_MASK)
    366		return hook->inbound(skb, ct, ctinfo, protoff, ctlh, pptpReq);
    367	return NF_ACCEPT;
    368
    369invalid:
    370	pr_debug("invalid %s: type=%d cid=%u pcid=%u "
    371		 "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
    372		 pptp_msg_name(msg),
    373		 msg, ntohs(cid), ntohs(pcid),  info->cstate, info->sstate,
    374		 ntohs(info->pns_call_id), ntohs(info->pac_call_id));
    375	return NF_ACCEPT;
    376}
    377
    378static int
    379pptp_outbound_pkt(struct sk_buff *skb, unsigned int protoff,
    380		  struct PptpControlHeader *ctlh,
    381		  union pptp_ctrl_union *pptpReq,
    382		  unsigned int reqlen,
    383		  struct nf_conn *ct,
    384		  enum ip_conntrack_info ctinfo)
    385{
    386	struct nf_ct_pptp_master *info = nfct_help_data(ct);
    387	const struct nf_nat_pptp_hook *hook;
    388	u_int16_t msg;
    389	__be16 cid = 0, pcid = 0;
    390
    391	msg = ntohs(ctlh->messageType);
    392	pr_debug("outbound control message %s\n", pptp_msg_name(msg));
    393
    394	switch (msg) {
    395	case PPTP_START_SESSION_REQUEST:
    396		/* client requests for new control session */
    397		if (info->sstate != PPTP_SESSION_NONE)
    398			goto invalid;
    399		info->sstate = PPTP_SESSION_REQUESTED;
    400		break;
    401
    402	case PPTP_STOP_SESSION_REQUEST:
    403		/* client requests end of control session */
    404		info->sstate = PPTP_SESSION_STOPREQ;
    405		break;
    406
    407	case PPTP_OUT_CALL_REQUEST:
    408		/* client initiating connection to server */
    409		if (info->sstate != PPTP_SESSION_CONFIRMED)
    410			goto invalid;
    411		info->cstate = PPTP_CALL_OUT_REQ;
    412		/* track PNS call id */
    413		cid = pptpReq->ocreq.callID;
    414		pr_debug("%s, CID=%X\n", pptp_msg_name(msg), ntohs(cid));
    415		info->pns_call_id = cid;
    416		break;
    417
    418	case PPTP_IN_CALL_REPLY:
    419		/* client answers incoming call */
    420		if (info->cstate != PPTP_CALL_IN_REQ &&
    421		    info->cstate != PPTP_CALL_IN_REP)
    422			goto invalid;
    423
    424		cid = pptpReq->icack.callID;
    425		pcid = pptpReq->icack.peersCallID;
    426		if (info->pac_call_id != pcid)
    427			goto invalid;
    428		pr_debug("%s, CID=%X PCID=%X\n", pptp_msg_name(msg),
    429			 ntohs(cid), ntohs(pcid));
    430
    431		if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) {
    432			/* part two of the three-way handshake */
    433			info->cstate = PPTP_CALL_IN_REP;
    434			info->pns_call_id = cid;
    435		} else
    436			info->cstate = PPTP_CALL_NONE;
    437		break;
    438
    439	case PPTP_CALL_CLEAR_REQUEST:
    440		/* client requests hangup of call */
    441		if (info->sstate != PPTP_SESSION_CONFIRMED)
    442			goto invalid;
    443		/* FUTURE: iterate over all calls and check if
    444		 * call ID is valid.  We don't do this without newnat,
    445		 * because we only know about last call */
    446		info->cstate = PPTP_CALL_CLEAR_REQ;
    447		break;
    448
    449	case PPTP_SET_LINK_INFO:
    450	case PPTP_ECHO_REQUEST:
    451	case PPTP_ECHO_REPLY:
    452		/* I don't have to explain these ;) */
    453		break;
    454
    455	default:
    456		goto invalid;
    457	}
    458
    459	hook = rcu_dereference(nf_nat_pptp_hook);
    460	if (hook && ct->status & IPS_NAT_MASK)
    461		return hook->outbound(skb, ct, ctinfo, protoff, ctlh, pptpReq);
    462	return NF_ACCEPT;
    463
    464invalid:
    465	pr_debug("invalid %s: type=%d cid=%u pcid=%u "
    466		 "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
    467		 pptp_msg_name(msg),
    468		 msg, ntohs(cid), ntohs(pcid),  info->cstate, info->sstate,
    469		 ntohs(info->pns_call_id), ntohs(info->pac_call_id));
    470	return NF_ACCEPT;
    471}
    472
    473static const unsigned int pptp_msg_size[] = {
    474	[PPTP_START_SESSION_REQUEST]  = sizeof(struct PptpStartSessionRequest),
    475	[PPTP_START_SESSION_REPLY]    = sizeof(struct PptpStartSessionReply),
    476	[PPTP_STOP_SESSION_REQUEST]   = sizeof(struct PptpStopSessionRequest),
    477	[PPTP_STOP_SESSION_REPLY]     = sizeof(struct PptpStopSessionReply),
    478	[PPTP_OUT_CALL_REQUEST]       = sizeof(struct PptpOutCallRequest),
    479	[PPTP_OUT_CALL_REPLY]	      = sizeof(struct PptpOutCallReply),
    480	[PPTP_IN_CALL_REQUEST]	      = sizeof(struct PptpInCallRequest),
    481	[PPTP_IN_CALL_REPLY]	      = sizeof(struct PptpInCallReply),
    482	[PPTP_IN_CALL_CONNECT]	      = sizeof(struct PptpInCallConnected),
    483	[PPTP_CALL_CLEAR_REQUEST]     = sizeof(struct PptpClearCallRequest),
    484	[PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify),
    485	[PPTP_WAN_ERROR_NOTIFY]	      = sizeof(struct PptpWanErrorNotify),
    486	[PPTP_SET_LINK_INFO]	      = sizeof(struct PptpSetLinkInfo),
    487};
    488
    489/* track caller id inside control connection, call expect_related */
    490static int
    491conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
    492		    struct nf_conn *ct, enum ip_conntrack_info ctinfo)
    493
    494{
    495	int dir = CTINFO2DIR(ctinfo);
    496	const struct nf_ct_pptp_master *info = nfct_help_data(ct);
    497	const struct tcphdr *tcph;
    498	struct tcphdr _tcph;
    499	const struct pptp_pkt_hdr *pptph;
    500	struct pptp_pkt_hdr _pptph;
    501	struct PptpControlHeader _ctlh, *ctlh;
    502	union pptp_ctrl_union _pptpReq, *pptpReq;
    503	unsigned int tcplen = skb->len - protoff;
    504	unsigned int datalen, reqlen, nexthdr_off;
    505	int oldsstate, oldcstate;
    506	int ret;
    507	u_int16_t msg;
    508
    509#if IS_ENABLED(CONFIG_NF_NAT)
    510	if (!nf_ct_is_confirmed(ct) && (ct->status & IPS_NAT_MASK)) {
    511		struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
    512
    513		if (!nat && !nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC))
    514			return NF_DROP;
    515	}
    516#endif
    517	/* don't do any tracking before tcp handshake complete */
    518	if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
    519		return NF_ACCEPT;
    520
    521	nexthdr_off = protoff;
    522	tcph = skb_header_pointer(skb, nexthdr_off, sizeof(_tcph), &_tcph);
    523	if (!tcph)
    524		return NF_ACCEPT;
    525
    526	nexthdr_off += tcph->doff * 4;
    527	datalen = tcplen - tcph->doff * 4;
    528
    529	pptph = skb_header_pointer(skb, nexthdr_off, sizeof(_pptph), &_pptph);
    530	if (!pptph) {
    531		pr_debug("no full PPTP header, can't track\n");
    532		return NF_ACCEPT;
    533	}
    534	nexthdr_off += sizeof(_pptph);
    535	datalen -= sizeof(_pptph);
    536
    537	/* if it's not a control message we can't do anything with it */
    538	if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
    539	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
    540		pr_debug("not a control packet\n");
    541		return NF_ACCEPT;
    542	}
    543
    544	ctlh = skb_header_pointer(skb, nexthdr_off, sizeof(_ctlh), &_ctlh);
    545	if (!ctlh)
    546		return NF_ACCEPT;
    547	nexthdr_off += sizeof(_ctlh);
    548	datalen -= sizeof(_ctlh);
    549
    550	reqlen = datalen;
    551	msg = ntohs(ctlh->messageType);
    552	if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])
    553		return NF_ACCEPT;
    554	if (reqlen > sizeof(*pptpReq))
    555		reqlen = sizeof(*pptpReq);
    556
    557	pptpReq = skb_header_pointer(skb, nexthdr_off, reqlen, &_pptpReq);
    558	if (!pptpReq)
    559		return NF_ACCEPT;
    560
    561	oldsstate = info->sstate;
    562	oldcstate = info->cstate;
    563
    564	spin_lock_bh(&nf_pptp_lock);
    565
    566	/* FIXME: We just blindly assume that the control connection is always
    567	 * established from PNS->PAC.  However, RFC makes no guarantee */
    568	if (dir == IP_CT_DIR_ORIGINAL)
    569		/* client -> server (PNS -> PAC) */
    570		ret = pptp_outbound_pkt(skb, protoff, ctlh, pptpReq, reqlen, ct,
    571					ctinfo);
    572	else
    573		/* server -> client (PAC -> PNS) */
    574		ret = pptp_inbound_pkt(skb, protoff, ctlh, pptpReq, reqlen, ct,
    575				       ctinfo);
    576	pr_debug("sstate: %d->%d, cstate: %d->%d\n",
    577		 oldsstate, info->sstate, oldcstate, info->cstate);
    578	spin_unlock_bh(&nf_pptp_lock);
    579
    580	return ret;
    581}
    582
    583static const struct nf_conntrack_expect_policy pptp_exp_policy = {
    584	.max_expected	= 2,
    585	.timeout	= 5 * 60,
    586};
    587
    588/* control protocol helper */
    589static struct nf_conntrack_helper pptp __read_mostly = {
    590	.name			= "pptp",
    591	.me			= THIS_MODULE,
    592	.tuple.src.l3num	= AF_INET,
    593	.tuple.src.u.tcp.port	= cpu_to_be16(PPTP_CONTROL_PORT),
    594	.tuple.dst.protonum	= IPPROTO_TCP,
    595	.help			= conntrack_pptp_help,
    596	.destroy		= pptp_destroy_siblings,
    597	.expect_policy		= &pptp_exp_policy,
    598};
    599
    600static int __init nf_conntrack_pptp_init(void)
    601{
    602	NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_pptp_master));
    603
    604	return nf_conntrack_helper_register(&pptp);
    605}
    606
    607static void __exit nf_conntrack_pptp_fini(void)
    608{
    609	nf_conntrack_helper_unregister(&pptp);
    610}
    611
    612module_init(nf_conntrack_pptp_init);
    613module_exit(nf_conntrack_pptp_fini);