2 * ip_conntrack_pptp.c - Version 2.0
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
12 * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
14 * Development of this code funded by Astaro AG (http://www.astaro.com/)
17 * - We blindly assume that control connections are always
18 * established in PNS->PAC direction. This is a violation
21 * TODO: - finish support for multiple calls within one session
22 * (needs expect reservations in newnat)
23 * - testing of incoming PPTP calls
26 * 2002-02-05 - Version 1.3
27 * - Call ip_conntrack_unexpect_related() from
28 * pptp_timeout_related() to destroy expectations in case
29 * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
30 * (Philip Craig <philipc@snapgear.com>)
31 * - Add Version information at module loadtime
32 * 2002-02-10 - Version 1.6
33 * - move to C99 style initializers
34 * - remove second expectation if first arrives
35 * 2004-10-22 - Version 2.0
36 * - merge Mandrake's 2.6.x port with recent 2.6.x API changes
37 * - fix lots of linear skb assumptions from Mandrake's port
41 #include <linux/config.h>
42 #include <linux/module.h>
43 #include <linux/netfilter.h>
45 #include <net/checksum.h>
48 #include <linux/netfilter_ipv4/lockhelp.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>
53 #define IP_CT_PPTP_VERSION "2.0"
55 MODULE_LICENSE("GPL");
56 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
57 MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
59 DECLARE_LOCK(ip_pptp_lock);
62 #include "ip_conntrack_pptp_priv.h"
63 #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
65 #define DEBUGP(format, args...)
69 #define MINS * 60 SECS
70 #define HOURS * 60 MINS
71 #define DAYS * 24 HOURS
73 #define PPTP_GRE_TIMEOUT (10 MINS)
74 #define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
76 static int pptp_expectfn(struct ip_conntrack *ct)
78 struct ip_conntrack *master;
79 struct ip_conntrack_expect *exp;
81 DEBUGP("increasing timeouts\n");
82 /* increase timeout of GRE data channel conntrack entry */
83 ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
84 ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
86 master = master_ct(ct);
88 DEBUGP(" no master!!!\n");
94 DEBUGP("no expectation!!\n");
98 DEBUGP("completing tuples with ct info\n");
99 /* we can do this, since we're unconfirmed */
100 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
101 htonl(master->help.ct_pptp_info.pac_call_id)) {
102 /* assume PNS->PAC */
103 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
104 htonl(master->help.ct_pptp_info.pns_call_id);
105 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
106 htonl(master->help.ct_pptp_info.pns_call_id);
108 /* assume PAC->PNS */
109 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
110 htonl(master->help.ct_pptp_info.pac_call_id);
111 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
112 htonl(master->help.ct_pptp_info.pac_call_id);
115 /* delete other expectation */
116 if (exp->expected_list.next != &exp->expected_list) {
117 struct ip_conntrack_expect *other_exp;
118 struct list_head *cur_item, *next;
120 for (cur_item = master->sibling_list.next;
121 cur_item != &master->sibling_list; cur_item = next) {
122 next = cur_item->next;
123 other_exp = list_entry(cur_item,
124 struct ip_conntrack_expect,
126 /* remove only if occurred at same sequence number */
127 if (other_exp != exp && other_exp->seq == exp->seq) {
128 DEBUGP("unexpecting other direction\n");
129 ip_ct_gre_keymap_destroy(other_exp);
130 ip_conntrack_unexpect_related(other_exp);
138 /* timeout GRE data connections */
139 static int pptp_timeout_related(struct ip_conntrack *ct)
141 struct list_head *cur_item, *next;
142 struct ip_conntrack_expect *exp;
144 /* FIXME: do we have to lock something ? */
145 for (cur_item = ct->sibling_list.next;
146 cur_item != &ct->sibling_list; cur_item = next) {
147 next = cur_item->next;
148 exp = list_entry(cur_item, struct ip_conntrack_expect,
151 ip_ct_gre_keymap_destroy(exp);
153 ip_conntrack_unexpect_related(exp);
157 DEBUGP("setting timeout of conntrack %p to 0\n",
159 exp->sibling->proto.gre.timeout = 0;
160 exp->sibling->proto.gre.stream_timeout = 0;
161 /* refresh_acct will not modify counters if skb == NULL */
162 ip_ct_refresh_acct(exp->sibling, 0, NULL, 0);
168 /* expect GRE connections (PNS->PAC and PAC->PNS direction) */
170 exp_gre(struct ip_conntrack *master,
173 u_int16_t peer_callid)
175 struct ip_conntrack_tuple inv_tuple;
176 struct ip_conntrack_tuple exp_tuples[] = {
177 /* tuple in original direction, PNS->PAC */
178 { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
179 .u = { .gre = { .key = htonl(ntohs(peer_callid)) } }
181 .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
182 .u = { .gre = { .key = htonl(ntohs(callid)) } },
183 .protonum = IPPROTO_GRE
186 /* tuple in reply direction, PAC->PNS */
187 { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
188 .u = { .gre = { .key = htonl(ntohs(callid)) } }
190 .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
191 .u = { .gre = { .key = htonl(ntohs(peer_callid)) } },
192 .protonum = IPPROTO_GRE
197 for (exp_tuple = exp_tuples; exp_tuple < &exp_tuples[2]; exp_tuple++) {
198 struct ip_conntrack_expect *exp;
200 exp = ip_conntrack_expect_alloc();
204 memcpy(&exp->tuple, exp_tuple, sizeof(exp->tuple));
206 exp->mask.src.ip = 0xffffffff;
207 exp->mask.src.u.all = 0;
208 exp->mask.dst.u.all = 0;
209 exp->mask.dst.u.gre.key = 0xffffffff;
210 exp->mask.dst.ip = 0xffffffff;
211 exp->mask.dst.protonum = 0xffff;
214 exp->expectfn = pptp_expectfn;
216 exp->help.exp_pptp_info.pac_call_id = ntohs(callid);
217 exp->help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
219 DEBUGP("calling expect_related ");
220 DUMP_TUPLE_RAW(&exp->tuple);
222 /* Add GRE keymap entries */
223 if (ip_ct_gre_keymap_add(exp, &exp->tuple, 0) != 0) {
228 invert_tuplepr(&inv_tuple, &exp->tuple);
229 if (ip_ct_gre_keymap_add(exp, &inv_tuple, 1) != 0) {
230 ip_ct_gre_keymap_destroy(exp);
235 if (ip_conntrack_expect_related(exp, master) != 0) {
236 ip_ct_gre_keymap_destroy(exp);
238 DEBUGP("cannot expect_related()\n");
247 pptp_inbound_pkt(struct sk_buff *skb,
249 unsigned int ctlhoff,
251 struct ip_conntrack *ct)
253 struct PptpControlHeader _ctlh, *ctlh;
255 union pptp_ctrl_union _pptpReq, *pptpReq;
256 struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
257 u_int16_t msg, *cid, *pcid;
260 ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh);
261 if (unlikely(!ctlh)) {
262 DEBUGP("error during skb_header_pointer\n");
266 reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh);
267 pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(struct pptp_pkt_hdr),
269 if (unlikely(!pptpReq)) {
270 DEBUGP("error during skb_header_pointer\n");
274 msg = ntohs(ctlh->messageType);
275 DEBUGP("inbound control message %s\n", strMName[msg]);
278 case PPTP_START_SESSION_REPLY:
279 if (reqlen < sizeof(_pptpReq.srep)) {
280 DEBUGP("%s: short packet\n", strMName[msg]);
284 /* server confirms new control session */
285 if (info->sstate < PPTP_SESSION_REQUESTED) {
286 DEBUGP("%s without START_SESS_REQUEST\n",
290 if (pptpReq->srep.resultCode == PPTP_START_OK)
291 info->sstate = PPTP_SESSION_CONFIRMED;
293 info->sstate = PPTP_SESSION_ERROR;
296 case PPTP_STOP_SESSION_REPLY:
297 if (reqlen < sizeof(_pptpReq.strep)) {
298 DEBUGP("%s: short packet\n", strMName[msg]);
302 /* server confirms end of control session */
303 if (info->sstate > PPTP_SESSION_STOPREQ) {
304 DEBUGP("%s without STOP_SESS_REQUEST\n",
308 if (pptpReq->strep.resultCode == PPTP_STOP_OK)
309 info->sstate = PPTP_SESSION_NONE;
311 info->sstate = PPTP_SESSION_ERROR;
314 case PPTP_OUT_CALL_REPLY:
315 if (reqlen < sizeof(_pptpReq.ocack)) {
316 DEBUGP("%s: short packet\n", strMName[msg]);
320 /* server accepted call, we now expect GRE frames */
321 if (info->sstate != PPTP_SESSION_CONFIRMED) {
322 DEBUGP("%s but no session\n", strMName[msg]);
325 if (info->cstate != PPTP_CALL_OUT_REQ &&
326 info->cstate != PPTP_CALL_OUT_CONF) {
327 DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
330 if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) {
331 info->cstate = PPTP_CALL_NONE;
335 cid = &pptpReq->ocack.callID;
336 pcid = &pptpReq->ocack.peersCallID;
338 info->pac_call_id = ntohs(*cid);
340 if (htons(info->pns_call_id) != *pcid) {
341 DEBUGP("%s for unknown callid %u\n",
342 strMName[msg], ntohs(*pcid));
346 DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
347 ntohs(*cid), ntohs(*pcid));
349 info->cstate = PPTP_CALL_OUT_CONF;
351 seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
352 + sizeof(struct PptpControlHeader)
353 + ((void *)pcid - (void *)pptpReq);
355 if (exp_gre(ct, seq, *cid, *pcid) != 0)
356 printk("ip_conntrack_pptp: error during exp_gre\n");
359 case PPTP_IN_CALL_REQUEST:
360 if (reqlen < sizeof(_pptpReq.icack)) {
361 DEBUGP("%s: short packet\n", strMName[msg]);
365 /* server tells us about incoming call request */
366 if (info->sstate != PPTP_SESSION_CONFIRMED) {
367 DEBUGP("%s but no session\n", strMName[msg]);
370 pcid = &pptpReq->icack.peersCallID;
371 DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
372 info->cstate = PPTP_CALL_IN_REQ;
373 info->pac_call_id = ntohs(*pcid);
376 case PPTP_IN_CALL_CONNECT:
377 if (reqlen < sizeof(_pptpReq.iccon)) {
378 DEBUGP("%s: short packet\n", strMName[msg]);
382 /* server tells us about incoming call established */
383 if (info->sstate != PPTP_SESSION_CONFIRMED) {
384 DEBUGP("%s but no session\n", strMName[msg]);
387 if (info->sstate != PPTP_CALL_IN_REP
388 && info->sstate != PPTP_CALL_IN_CONF) {
389 DEBUGP("%s but never sent IN_CALL_REPLY\n",
394 pcid = &pptpReq->iccon.peersCallID;
395 cid = &info->pac_call_id;
397 if (info->pns_call_id != ntohs(*pcid)) {
398 DEBUGP("%s for unknown CallID %u\n",
399 strMName[msg], ntohs(*cid));
403 DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
404 info->cstate = PPTP_CALL_IN_CONF;
406 /* we expect a GRE connection from PAC to PNS */
407 seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr)
408 + sizeof(struct PptpControlHeader)
409 + ((void *)pcid - (void *)pptpReq);
411 if (exp_gre(ct, seq, *cid, *pcid) != 0)
412 printk("ip_conntrack_pptp: error during exp_gre\n");
416 case PPTP_CALL_DISCONNECT_NOTIFY:
417 if (reqlen < sizeof(_pptpReq.disc)) {
418 DEBUGP("%s: short packet\n", strMName[msg]);
422 /* server confirms disconnect */
423 cid = &pptpReq->disc.callID;
424 DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
425 info->cstate = PPTP_CALL_NONE;
427 /* untrack this call id, unexpect GRE packets */
428 pptp_timeout_related(ct);
431 case PPTP_WAN_ERROR_NOTIFY:
434 case PPTP_ECHO_REQUEST:
435 case PPTP_ECHO_REPLY:
436 /* I don't have to explain these ;) */
439 DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
440 ? strMName[msg]:strMName[0], msg);
449 pptp_outbound_pkt(struct sk_buff *skb,
451 unsigned int ctlhoff,
453 struct ip_conntrack *ct)
455 struct PptpControlHeader _ctlh, *ctlh;
457 union pptp_ctrl_union _pptpReq, *pptpReq;
458 struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
459 u_int16_t msg, *cid, *pcid;
461 ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh);
465 reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh);
466 pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(_ctlh), reqlen,
471 msg = ntohs(ctlh->messageType);
472 DEBUGP("outbound control message %s\n", strMName[msg]);
475 case PPTP_START_SESSION_REQUEST:
476 /* client requests for new control session */
477 if (info->sstate != PPTP_SESSION_NONE) {
478 DEBUGP("%s but we already have one",
481 info->sstate = PPTP_SESSION_REQUESTED;
483 case PPTP_STOP_SESSION_REQUEST:
484 /* client requests end of control session */
485 info->sstate = PPTP_SESSION_STOPREQ;
488 case PPTP_OUT_CALL_REQUEST:
489 if (reqlen < sizeof(_pptpReq.ocreq)) {
490 DEBUGP("%s: short packet\n", strMName[msg]);
494 /* client initiating connection to server */
495 if (info->sstate != PPTP_SESSION_CONFIRMED) {
496 DEBUGP("%s but no session\n",
500 info->cstate = PPTP_CALL_OUT_REQ;
501 /* track PNS call id */
502 cid = &pptpReq->ocreq.callID;
503 DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
504 info->pns_call_id = ntohs(*cid);
506 case PPTP_IN_CALL_REPLY:
507 if (reqlen < sizeof(_pptpReq.icack)) {
508 DEBUGP("%s: short packet\n", strMName[msg]);
512 /* client answers incoming call */
513 if (info->cstate != PPTP_CALL_IN_REQ
514 && info->cstate != PPTP_CALL_IN_REP) {
515 DEBUGP("%s without incall_req\n",
519 if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) {
520 info->cstate = PPTP_CALL_NONE;
523 pcid = &pptpReq->icack.peersCallID;
524 if (info->pac_call_id != ntohs(*pcid)) {
525 DEBUGP("%s for unknown call %u\n",
526 strMName[msg], ntohs(*pcid));
529 DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
530 /* part two of the three-way handshake */
531 info->cstate = PPTP_CALL_IN_REP;
532 info->pns_call_id = ntohs(pptpReq->icack.callID);
535 case PPTP_CALL_CLEAR_REQUEST:
536 /* client requests hangup of call */
537 if (info->sstate != PPTP_SESSION_CONFIRMED) {
538 DEBUGP("CLEAR_CALL but no session\n");
541 /* FUTURE: iterate over all calls and check if
542 * call ID is valid. We don't do this without newnat,
543 * because we only know about last call */
544 info->cstate = PPTP_CALL_CLEAR_REQ;
546 case PPTP_SET_LINK_INFO:
548 case PPTP_ECHO_REQUEST:
549 case PPTP_ECHO_REPLY:
550 /* I don't have to explain these ;) */
553 DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
554 strMName[msg]:strMName[0], msg);
555 /* unknown: no need to create GRE masq table entry */
563 /* track caller id inside control connection, call expect_related */
565 conntrack_pptp_help(struct sk_buff *skb,
566 struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
569 struct pptp_pkt_hdr _pptph, *pptph;
571 struct tcphdr _tcph, *tcph;
572 u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
575 int dir = CTINFO2DIR(ctinfo);
576 struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
577 unsigned int nexthdr_off;
579 int oldsstate, oldcstate;
582 /* don't do any tracking before tcp handshake complete */
583 if (ctinfo != IP_CT_ESTABLISHED
584 && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
585 DEBUGP("ctinfo = %u, skipping\n", ctinfo);
589 nexthdr_off = skb->nh.iph->ihl*4;
590 tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_tcph),
595 /* not a complete TCP header? */
596 if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
597 DEBUGP("tcplen = %u\n", tcplen);
602 datalen = tcplen - tcph->doff * 4;
604 /* checksum invalid? */
605 if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.iph->daddr,
606 csum_partial((char *) tcph, tcplen, 0))) {
607 printk(KERN_NOTICE __FILE__ ": bad csum\n");
608 /* W2K PPTP server sends TCP packets with wrong checksum :(( */
612 if (tcph->fin || tcph->rst) {
613 DEBUGP("RST/FIN received, timeouting GRE\n");
614 /* can't do this after real newnat */
615 info->cstate = PPTP_CALL_NONE;
617 /* untrack this call id, unexpect GRE packets */
618 pptp_timeout_related(ct);
621 nexthdr_off += tcph->doff*4;
622 pptph = skb_header_pointer(skb, skb->nh.iph->ihl*4 + tcph->doff*4,
623 sizeof(_pptph), &_pptph);
625 DEBUGP("no full PPTP header, can't track\n");
629 datalimit = (void *) pptph + datalen;
631 /* if it's not a control message we can't do anything with it */
632 if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
633 ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
634 DEBUGP("not a control packet\n");
638 oldsstate = info->sstate;
639 oldcstate = info->cstate;
641 LOCK_BH(&ip_pptp_lock);
643 nexthdr_off += sizeof(_pptph);
644 /* FIXME: We just blindly assume that the control connection is always
645 * established from PNS->PAC. However, RFC makes no guarantee */
646 if (dir == IP_CT_DIR_ORIGINAL)
647 /* client -> server (PNS -> PAC) */
648 ret = pptp_outbound_pkt(skb, tcph, nexthdr_off, datalen, ct);
650 /* server -> client (PAC -> PNS) */
651 ret = pptp_inbound_pkt(skb, tcph, nexthdr_off, datalen, ct);
652 DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
653 oldsstate, info->sstate, oldcstate, info->cstate);
654 UNLOCK_BH(&ip_pptp_lock);
659 /* control protocol helper */
660 static struct ip_conntrack_helper pptp = {
661 .list = { NULL, NULL },
663 .flags = IP_CT_HELPER_F_REUSE_EXPECT,
667 .tuple = { .src = { .ip = 0,
668 .u = { .tcp = { .port =
669 __constant_htons(PPTP_CONTROL_PORT) } }
673 .protonum = IPPROTO_TCP
676 .mask = { .src = { .ip = 0,
677 .u = { .tcp = { .port = 0xffff } }
684 .help = conntrack_pptp_help
687 /* ip_conntrack_pptp initialization */
688 static int __init init(void)
692 DEBUGP(__FILE__ ": registering helper\n");
693 if ((retcode = ip_conntrack_helper_register(&pptp))) {
694 printk(KERN_ERR "Unable to register conntrack application "
695 "helper for pptp: %d\n", retcode);
699 printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
703 static void __exit fini(void)
705 ip_conntrack_helper_unregister(&pptp);
706 printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
712 EXPORT_SYMBOL(ip_pptp_lock);