1/*
2 * ip_conntrack_pptp.c	- Version 1.11
3 *
4 * Connection tracking 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 vendors
7 * working with Microsoft.  PPTP is built on top of a modified
8 * version of the Internet Generic Routing Encapsulation Protocol.
9 * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
10 * PPTP can be found in RFC 2637
11 *
12 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>,
13 *
14 * Development of this code funded by Astaro AG (http://www.astaro.com/)
15 *
16 * Limitations:
17 * 	 - We blindly assume that control connections are always
18 * 	   established in PNS->PAC direction.  This is a violation
19 * 	   of RFFC2673
20 *
21 * TODO: - finish support for multiple calls within one session
22 * 	   (needs expect reservations in newnat)
23 *	 - testing of incoming PPTP calls
24 */
25
26#include <linux/config.h>
27#include <linux/module.h>
28#include <linux/netfilter.h>
29#include <linux/ip.h>
30#include <net/checksum.h>
31#include <net/tcp.h>
32
33#include <linux/netfilter_ipv4/lockhelp.h>
34#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
35#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
36#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
37
38MODULE_LICENSE("GPL");
39MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
40MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
41
42DECLARE_LOCK(ip_pptp_lock);
43
44#define DEBUGP(format, args...)
45
46#define SECS *HZ
47#define MINS * 60 SECS
48#define HOURS * 60 MINS
49#define DAYS * 24 HOURS
50
51#define PPTP_GRE_TIMEOUT 		(10 MINS)
52#define PPTP_GRE_STREAM_TIMEOUT 	(5 DAYS)
53
54static int pptp_expectfn(struct ip_conntrack *ct)
55{
56	struct ip_conntrack_expect *exp, *other_exp;
57	struct ip_conntrack *master;
58
59	DEBUGP("increasing timeouts\n");
60	/* increase timeout of GRE data channel conntrack entry */
61	ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
62	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
63
64	master = master_ct(ct);
65	if (!master) {
66		DEBUGP(" no master!!!\n");
67		return 0;
68	}
69
70	DEBUGP("completing tuples with ct info\n");
71	/* we can do this, since we're unconfirmed */
72	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
73		htonl(master->help.ct_pptp_info.pac_call_id)) {
74		/* assume PNS->PAC */
75		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
76			htonl(master->help.ct_pptp_info.pns_call_id);
77		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
78			htonl(master->help.ct_pptp_info.pns_call_id);
79	} else {
80		/* assume PAC->PNS */
81		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
82			htonl(master->help.ct_pptp_info.pac_call_id);
83		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
84			htonl(master->help.ct_pptp_info.pns_call_id);
85	}
86
87	return 0;
88}
89
90/* timeout GRE data connections */
91static int pptp_timeout_related(struct ip_conntrack *ct)
92{
93	struct list_head *cur_item;
94	struct ip_conntrack_expect *exp;
95
96	list_for_each(cur_item, &ct->sibling_list) {
97		exp = list_entry(cur_item, struct ip_conntrack_expect,
98				 expected_list);
99
100		if (!exp->sibling)
101			continue;
102
103		DEBUGP("setting timeout of conntrack %p to 0\n",
104			exp->sibling);
105		exp->sibling->proto.gre.timeout = 0;
106		exp->sibling->proto.gre.stream_timeout = 0;
107		ip_ct_refresh(exp->sibling, 0);
108	}
109
110	return 0;
111}
112
113/* expect GRE connection in PNS->PAC direction */
114static inline int
115exp_gre(struct ip_conntrack *master,
116	u_int32_t seq,
117	u_int16_t callid,
118	u_int16_t peer_callid)
119{
120	struct ip_conntrack_expect exp;
121	struct ip_conntrack_tuple inv_tuple;
122
123	memset(&exp, 0, sizeof(exp));
124	/* tuple in original direction, PAC->PNS */
125	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
126	exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
127	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
128	exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
129	exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
130	exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
131	exp.tuple.dst.protonum = IPPROTO_GRE;
132
133	exp.mask.src.ip = 0xffffffff;
134	exp.mask.src.u.all = 0;
135	exp.mask.dst.u.all = 0;
136	exp.mask.dst.u.gre.key = 0xffffffff;
137	exp.mask.dst.u.gre.version = 0xff;
138	exp.mask.dst.u.gre.protocol = 0xffff;
139	exp.mask.dst.ip = 0xffffffff;
140	exp.mask.dst.protonum = 0xffff;
141
142	exp.seq = seq;
143	exp.expectfn = pptp_expectfn;
144
145	exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
146	exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
147
148	DEBUGP("calling expect_related ");
149	DUMP_TUPLE_RAW(&exp.tuple);
150
151	/* Add GRE keymap entries */
152	ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
153	invert_tuplepr(&inv_tuple, &exp.tuple);
154	ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
155
156	ip_conntrack_expect_related(master, &exp);
157
158	return 0;
159}
160
161static inline int
162pptp_inbound_pkt(struct tcphdr *tcph,
163		 struct pptp_pkt_hdr *pptph,
164		 size_t datalen,
165		 struct ip_conntrack *ct,
166		 enum ip_conntrack_info ctinfo)
167{
168	struct PptpControlHeader *ctlh;
169        union pptp_ctrl_union pptpReq;
170
171	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
172	u_int16_t msg, *cid, *pcid;
173	u_int32_t seq;
174
175	ctlh = (struct PptpControlHeader *)
176		((char *) pptph + sizeof(struct pptp_pkt_hdr));
177	pptpReq.rawreq = (void *)
178		((char *) ctlh + sizeof(struct PptpControlHeader));
179
180	msg = ntohs(ctlh->messageType);
181	DEBUGP("inbound control message %s\n", strMName[msg]);
182
183	switch (msg) {
184	case PPTP_START_SESSION_REPLY:
185		/* server confirms new control session */
186		if (info->sstate < PPTP_SESSION_REQUESTED) {
187			DEBUGP("%s without START_SESS_REQUEST\n",
188				strMName[msg]);
189			break;
190		}
191		if (pptpReq.srep->resultCode == PPTP_START_OK)
192			info->sstate = PPTP_SESSION_CONFIRMED;
193		else
194			info->sstate = PPTP_SESSION_ERROR;
195		break;
196
197	case PPTP_STOP_SESSION_REPLY:
198		/* server confirms end of control session */
199		if (info->sstate > PPTP_SESSION_STOPREQ) {
200			DEBUGP("%s without STOP_SESS_REQUEST\n",
201				strMName[msg]);
202			break;
203		}
204		if (pptpReq.strep->resultCode == PPTP_STOP_OK)
205			info->sstate = PPTP_SESSION_NONE;
206		else
207			info->sstate = PPTP_SESSION_ERROR;
208		break;
209
210	case PPTP_OUT_CALL_REPLY:
211		/* server accepted call, we now expect GRE frames */
212		if (info->sstate != PPTP_SESSION_CONFIRMED) {
213			DEBUGP("%s but no session\n", strMName[msg]);
214			break;
215		}
216		if (info->cstate != PPTP_CALL_OUT_REQ &&
217		    info->cstate != PPTP_CALL_OUT_CONF) {
218			DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
219			break;
220		}
221		if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
222			info->cstate = PPTP_CALL_NONE;
223			break;
224		}
225
226		cid = &pptpReq.ocack->callID;
227		pcid = &pptpReq.ocack->peersCallID;
228
229		info->pac_call_id = ntohs(*cid);
230
231		if (htons(info->pns_call_id) != *pcid) {
232			DEBUGP("%s for unknown callid %u\n",
233				strMName[msg], ntohs(*pcid));
234			break;
235		}
236
237		DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
238			ntohs(*cid), ntohs(*pcid));
239
240		info->cstate = PPTP_CALL_OUT_CONF;
241
242		seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
243		exp_gre(ct, seq, *cid, *pcid);
244		break;
245
246	case PPTP_IN_CALL_REQUEST:
247		/* server tells us about incoming call request */
248		if (info->sstate != PPTP_SESSION_CONFIRMED) {
249			DEBUGP("%s but no session\n", strMName[msg]);
250			break;
251		}
252		pcid = &pptpReq.icack->peersCallID;
253		DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
254		info->cstate = PPTP_CALL_IN_REQ;
255		info->pac_call_id= ntohs(*pcid);
256		break;
257
258	case PPTP_IN_CALL_CONNECT:
259		/* server tells us about incoming call established */
260		if (info->sstate != PPTP_SESSION_CONFIRMED) {
261			DEBUGP("%s but no session\n", strMName[msg]);
262			break;
263		}
264		if (info->sstate != PPTP_CALL_IN_REP
265		    && info->sstate != PPTP_CALL_IN_CONF) {
266			DEBUGP("%s but never sent IN_CALL_REPLY\n",
267				strMName[msg]);
268			break;
269		}
270
271		pcid = &pptpReq.iccon->peersCallID;
272		cid = &info->pac_call_id;
273
274		if (info->pns_call_id != ntohs(*pcid)) {
275			DEBUGP("%s for unknown CallID %u\n",
276				strMName[msg], ntohs(*cid));
277			break;
278		}
279
280		DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
281		info->cstate = PPTP_CALL_IN_CONF;
282
283		/* we expect a GRE connection from PAC to PNS */
284		seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
285		exp_gre(ct, seq, *cid, *pcid);
286
287		break;
288
289	case PPTP_CALL_DISCONNECT_NOTIFY:
290		/* server confirms disconnect */
291		cid = &pptpReq.disc->callID;
292		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
293		info->cstate = PPTP_CALL_NONE;
294
295		/* untrack this call id, unexpect GRE packets */
296		pptp_timeout_related(ct);
297		/* NEWNAT: look up exp for call id and unexpct_related */
298		break;
299
300	case PPTP_WAN_ERROR_NOTIFY:
301		break;
302
303	case PPTP_ECHO_REQUEST:
304	case PPTP_ECHO_REPLY:
305		/* I don't have to explain these ;) */
306		break;
307	default:
308		DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
309			? strMName[msg]:strMName[0], msg);
310		break;
311	}
312
313	return NF_ACCEPT;
314
315}
316
317static inline int
318pptp_outbound_pkt(struct tcphdr *tcph,
319		  struct pptp_pkt_hdr *pptph,
320		  size_t datalen,
321		  struct ip_conntrack *ct,
322		  enum ip_conntrack_info ctinfo)
323{
324	struct PptpControlHeader *ctlh;
325        union pptp_ctrl_union pptpReq;
326	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
327	u_int16_t msg, *cid, *pcid;
328
329	ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
330	pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
331
332	msg = ntohs(ctlh->messageType);
333	DEBUGP("outbound control message %s\n", strMName[msg]);
334
335	switch (msg) {
336	case PPTP_START_SESSION_REQUEST:
337		/* client requests for new control session */
338		if (info->sstate != PPTP_SESSION_NONE) {
339			DEBUGP("%s but we already have one",
340				strMName[msg]);
341		}
342		info->sstate = PPTP_SESSION_REQUESTED;
343		break;
344	case PPTP_STOP_SESSION_REQUEST:
345		/* client requests end of control session */
346		info->sstate = PPTP_SESSION_STOPREQ;
347		break;
348
349	case PPTP_OUT_CALL_REQUEST:
350		/* client initiating connection to server */
351		if (info->sstate != PPTP_SESSION_CONFIRMED) {
352			DEBUGP("%s but no session\n",
353				strMName[msg]);
354			break;
355		}
356		info->cstate = PPTP_CALL_OUT_REQ;
357		/* track PNS call id */
358		cid = &pptpReq.ocreq->callID;
359		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
360		info->pns_call_id = ntohs(*cid);
361		break;
362	case PPTP_IN_CALL_REPLY:
363		/* client answers incoming call */
364		if (info->cstate != PPTP_CALL_IN_REQ
365		    && info->cstate != PPTP_CALL_IN_REP) {
366			DEBUGP("%s without incall_req\n",
367				strMName[msg]);
368			break;
369		}
370		if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
371			info->cstate = PPTP_CALL_NONE;
372			break;
373		}
374		pcid = &pptpReq.icack->peersCallID;
375		if (info->pac_call_id != ntohs(*pcid)) {
376			DEBUGP("%s for unknown call %u\n",
377				strMName[msg], ntohs(*pcid));
378			break;
379		}
380		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
381		/* part two of the three-way handshake */
382		info->cstate = PPTP_CALL_IN_REP;
383		info->pns_call_id = ntohs(pptpReq.icack->callID);
384		break;
385
386	case PPTP_CALL_CLEAR_REQUEST:
387		/* client requests hangup of call */
388		if (info->sstate != PPTP_SESSION_CONFIRMED) {
389			DEBUGP("CLEAR_CALL but no session\n");
390			break;
391		}
392		/* FUTURE: iterate over all calls and check if
393		 * call ID is valid.  We don't do this without newnat,
394		 * because we only know about last call */
395		info->cstate = PPTP_CALL_CLEAR_REQ;
396		break;
397	case PPTP_SET_LINK_INFO:
398		break;
399	case PPTP_ECHO_REQUEST:
400	case PPTP_ECHO_REPLY:
401		/* I don't have to explain these ;) */
402		break;
403	default:
404		DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
405			strMName[msg]:strMName[0], msg);
406		/* unknown: no need to create GRE masq table entry */
407		break;
408	}
409
410	return NF_ACCEPT;
411}
412
413
414/* track caller id inside control connection, call expect_related */
415static int
416conntrack_pptp_help(const struct iphdr *iph, size_t len,
417		    struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
418
419{
420	struct pptp_pkt_hdr *pptph;
421
422	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
423	u_int32_t tcplen = len - iph->ihl * 4;
424	u_int32_t datalen = tcplen - tcph->doff * 4;
425	void *datalimit;
426	int dir = CTINFO2DIR(ctinfo);
427	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
428
429	int oldsstate, oldcstate;
430	int ret;
431
432	/* don't do any tracking before tcp handshake complete */
433	if (ctinfo != IP_CT_ESTABLISHED
434	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
435		DEBUGP("ctinfo = %u, skipping\n", ctinfo);
436		return NF_ACCEPT;
437	}
438
439	/* not a complete TCP header? */
440	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
441		DEBUGP("tcplen = %u\n", tcplen);
442		return NF_ACCEPT;
443	}
444
445	/* checksum invalid? */
446	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
447			csum_partial((char *) tcph, tcplen, 0))) {
448		printk(KERN_NOTICE __FILE__ ": bad csum\n");
449//		return NF_ACCEPT;
450	}
451
452	if (tcph->fin || tcph->rst) {
453		DEBUGP("RST/FIN received, timeouting GRE\n");
454		/* can't do this after real newnat */
455		info->cstate = PPTP_CALL_NONE;
456
457		/* untrack this call id, unexpect GRE packets */
458		pptp_timeout_related(ct);
459		/* no need to call unexpect_related since master conn
460		 * dies anyway */
461	}
462
463
464	pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
465	datalimit = (void *) pptph + datalen;
466
467	/* not a full pptp packet header? */
468	if ((void *) pptph+sizeof(*pptph) >= datalimit) {
469		DEBUGP("no full PPTP header, can't track\n");
470		return NF_ACCEPT;
471	}
472
473	/* if it's not a control message we can't do anything with it */
474        if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
475	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
476		DEBUGP("not a control packet\n");
477		return NF_ACCEPT;
478	}
479
480	oldsstate = info->sstate;
481	oldcstate = info->cstate;
482
483	LOCK_BH(&ip_pptp_lock);
484
485	if (dir == IP_CT_DIR_ORIGINAL)
486		/* client -> server (PNS -> PAC) */
487		ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
488	else
489		/* server -> client (PAC -> PNS) */
490		ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
491	DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
492		oldsstate, info->sstate, oldcstate, info->cstate);
493	UNLOCK_BH(&ip_pptp_lock);
494
495	return ret;
496}
497
498/* control protocol helper */
499static struct ip_conntrack_helper pptp = {
500	{ NULL, NULL },
501	"pptp", IP_CT_HELPER_F_REUSE_EXPECT, THIS_MODULE, 2, 0,
502	{ { 0, { tcp: { port: __constant_htons(PPTP_CONTROL_PORT) } } },
503	  { 0, { 0 }, IPPROTO_TCP } },
504	{ { 0, { tcp: { port: 0xffff } } },
505	  { 0, { 0 }, 0xffff } },
506	conntrack_pptp_help };
507
508/* ip_conntrack_pptp initialization */
509static int __init init(void)
510{
511	int retcode;
512
513	DEBUGP(__FILE__ ": registering helper\n");
514	if ((retcode = ip_conntrack_helper_register(&pptp))) {
515                printk(KERN_ERR "Unable to register conntrack application "
516				"helper for pptp: %d\n", retcode);
517		return -EIO;
518	}
519
520	return 0;
521}
522
523static void __exit fini(void)
524{
525	ip_conntrack_helper_unregister(&pptp);
526}
527
528module_init(init);
529module_exit(fini);
530
531EXPORT_SYMBOL(ip_pptp_lock);
532