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