1 /* $NetBSD: ip_pptp_pxy.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * Simple PPTP transparent proxy for in-kernel use. For use with the NAT 7 * code. 8 * 9 * Id: ip_pptp_pxy.c,v 1.1.1.2 2012/07/22 13:44:23 darrenr Exp $ 10 * 11 */ 12 #define IPF_PPTP_PROXY 13 14 15 16 /* 17 * PPTP proxy 18 */ 19 typedef struct pptp_side { 20 u_32_t pptps_nexthdr; 21 u_32_t pptps_next; 22 int pptps_state; 23 int pptps_gothdr; 24 int pptps_len; 25 int pptps_bytes; 26 char *pptps_wptr; 27 char pptps_buffer[512]; 28 } pptp_side_t; 29 30 typedef struct pptp_pxy { 31 nat_t *pptp_nat; 32 struct ipstate *pptp_state; 33 u_short pptp_call[2]; 34 pptp_side_t pptp_side[2]; 35 ipnat_t *pptp_rule; 36 } pptp_pxy_t; 37 38 typedef struct pptp_hdr { 39 u_short pptph_len; 40 u_short pptph_type; 41 u_32_t pptph_cookie; 42 } pptp_hdr_t; 43 44 #define PPTP_MSGTYPE_CTL 1 45 #define PPTP_MTCTL_STARTREQ 1 46 #define PPTP_MTCTL_STARTREP 2 47 #define PPTP_MTCTL_STOPREQ 3 48 #define PPTP_MTCTL_STOPREP 4 49 #define PPTP_MTCTL_ECHOREQ 5 50 #define PPTP_MTCTL_ECHOREP 6 51 #define PPTP_MTCTL_OUTREQ 7 52 #define PPTP_MTCTL_OUTREP 8 53 #define PPTP_MTCTL_INREQ 9 54 #define PPTP_MTCTL_INREP 10 55 #define PPTP_MTCTL_INCONNECT 11 56 #define PPTP_MTCTL_CLEAR 12 57 #define PPTP_MTCTL_DISCONNECT 13 58 #define PPTP_MTCTL_WANERROR 14 59 #define PPTP_MTCTL_LINKINFO 15 60 61 62 void ipf_p_pptp_main_load __P((void)); 63 void ipf_p_pptp_main_unload __P((void)); 64 int ipf_p_pptp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 65 void ipf_p_pptp_del __P((ipf_main_softc_t *, ap_session_t *)); 66 int ipf_p_pptp_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 67 void ipf_p_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *)); 68 int ipf_p_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); 69 int ipf_p_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int)); 70 int ipf_p_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); 71 72 static frentry_t pptpfr; 73 74 static int pptp_proxy_init = 0; 75 static int ipf_p_pptp_debug = 0; 76 static int ipf_p_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */ 77 78 79 /* 80 * PPTP application proxy initialization. 81 */ 82 void 83 ipf_p_pptp_main_load() 84 { 85 bzero((char *)&pptpfr, sizeof(pptpfr)); 86 pptpfr.fr_ref = 1; 87 pptpfr.fr_age[0] = ipf_p_pptp_gretimeout; 88 pptpfr.fr_age[1] = ipf_p_pptp_gretimeout; 89 pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 90 MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock"); 91 pptp_proxy_init = 1; 92 } 93 94 95 void 96 ipf_p_pptp_main_unload() 97 { 98 if (pptp_proxy_init == 1) { 99 MUTEX_DESTROY(&pptpfr.fr_lock); 100 pptp_proxy_init = 0; 101 } 102 } 103 104 105 /* 106 * Setup for a new PPTP proxy. 107 * 108 * NOTE: The printf's are broken up with %s in them to prevent them being 109 * optimised into puts statements on FreeBSD (this doesn't exist in the kernel) 110 */ 111 int 112 ipf_p_pptp_new(arg, fin, aps, nat) 113 void *arg; 114 fr_info_t *fin; 115 ap_session_t *aps; 116 nat_t *nat; 117 { 118 pptp_pxy_t *pptp; 119 ipnat_t *ipn; 120 ipnat_t *np; 121 int size; 122 ip_t *ip; 123 124 if (fin->fin_v != 4) 125 return -1; 126 127 ip = fin->fin_ip; 128 np = nat->nat_ptr; 129 size = np->in_size; 130 131 if (ipf_nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_osrcip, 132 ip->ip_dst) != NULL) { 133 if (ipf_p_pptp_debug > 0) 134 printf("ipf_p_pptp_new: GRE session already exists\n"); 135 return -1; 136 } 137 138 KMALLOC(pptp, pptp_pxy_t *); 139 if (pptp == NULL) { 140 if (ipf_p_pptp_debug > 0) 141 printf("ipf_p_pptp_new: malloc for aps_data failed\n"); 142 return -1; 143 } 144 KMALLOCS(ipn, ipnat_t *, size); 145 if (ipn == NULL) { 146 KFREE(pptp); 147 return -1; 148 } 149 150 aps->aps_data = pptp; 151 aps->aps_psiz = sizeof(*pptp); 152 bzero((char *)pptp, sizeof(*pptp)); 153 bzero((char *)ipn, size); 154 pptp->pptp_rule = ipn; 155 156 /* 157 * Create NAT rule against which the tunnel/transport mapping is 158 * created. This is required because the current NAT rule does not 159 * describe GRE but TCP instead. 160 */ 161 ipn->in_size = size; 162 ipn->in_ifps[0] = fin->fin_ifp; 163 ipn->in_apr = NULL; 164 ipn->in_use = 1; 165 ipn->in_hits = 1; 166 ipn->in_ippip = 1; 167 ipn->in_snip = ntohl(nat->nat_nsrcaddr); 168 ipn->in_nsrcaddr = fin->fin_saddr; 169 ipn->in_dnip = ntohl(nat->nat_ndstaddr); 170 ipn->in_ndstaddr = nat->nat_ndstaddr; 171 ipn->in_redir = np->in_redir; 172 ipn->in_osrcaddr = nat->nat_osrcaddr; 173 ipn->in_odstaddr = nat->nat_odstaddr; 174 ipn->in_osrcmsk = 0xffffffff; 175 ipn->in_nsrcmsk = 0xffffffff; 176 ipn->in_odstmsk = 0xffffffff; 177 ipn->in_ndstmsk = 0xffffffff; 178 ipn->in_flags = (np->in_flags | IPN_PROXYRULE); 179 MUTEX_INIT(&ipn->in_lock, "pptp proxy NAT rule"); 180 181 ipn->in_namelen = np->in_namelen; 182 bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen); 183 ipn->in_ifnames[0] = np->in_ifnames[0]; 184 ipn->in_ifnames[1] = np->in_ifnames[1]; 185 186 ipn->in_pr[0] = IPPROTO_GRE; 187 ipn->in_pr[1] = IPPROTO_GRE; 188 189 pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer; 190 pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer; 191 return 0; 192 } 193 194 195 void 196 ipf_p_pptp_donatstate(fin, nat, pptp) 197 fr_info_t *fin; 198 nat_t *nat; 199 pptp_pxy_t *pptp; 200 { 201 ipf_main_softc_t *softc = fin->fin_main_soft; 202 fr_info_t fi; 203 grehdr_t gre; 204 nat_t *nat2; 205 u_char p; 206 ip_t *ip; 207 208 ip = fin->fin_ip; 209 p = ip->ip_p; 210 211 nat2 = pptp->pptp_nat; 212 if ((nat2 == NULL) || (pptp->pptp_state == NULL)) { 213 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 214 bzero((char *)&gre, sizeof(gre)); 215 fi.fin_fi.fi_p = IPPROTO_GRE; 216 fi.fin_fr = &pptpfr; 217 if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) || 218 (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) { 219 fi.fin_data[0] = pptp->pptp_call[0]; 220 fi.fin_data[1] = pptp->pptp_call[1]; 221 } else { 222 fi.fin_data[0] = pptp->pptp_call[1]; 223 fi.fin_data[1] = pptp->pptp_call[0]; 224 } 225 ip = fin->fin_ip; 226 ip->ip_p = IPPROTO_GRE; 227 fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); 228 fi.fin_flx |= FI_IGNORE; 229 fi.fin_dp = &gre; 230 gre.gr_flags = htons(1 << 13); 231 232 fi.fin_fi.fi_saddr = nat->nat_osrcaddr; 233 fi.fin_fi.fi_daddr = nat->nat_odstaddr; 234 } 235 236 /* 237 * Update NAT timeout/create NAT if missing. 238 */ 239 if (nat2 != NULL) 240 ipf_queueback(softc->ipf_ticks, &nat2->nat_tqe); 241 else { 242 #ifdef USE_MUTEXES 243 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 244 #endif 245 246 MUTEX_ENTER(&softn->ipf_nat_new); 247 nat2 = ipf_nat_add(&fi, pptp->pptp_rule, &pptp->pptp_nat, 248 NAT_SLAVE, nat->nat_dir); 249 MUTEX_EXIT(&softn->ipf_nat_new); 250 if (nat2 != NULL) { 251 (void) ipf_nat_proto(&fi, nat2, 0); 252 MUTEX_ENTER(&nat2->nat_lock); 253 ipf_nat_update(&fi, nat2); 254 MUTEX_EXIT(&nat2->nat_lock); 255 } 256 } 257 258 READ_ENTER(&softc->ipf_state); 259 if (pptp->pptp_state != NULL) { 260 ipf_queueback(softc->ipf_ticks, &pptp->pptp_state->is_sti); 261 RWLOCK_EXIT(&softc->ipf_state); 262 } else { 263 RWLOCK_EXIT(&softc->ipf_state); 264 if (nat2 != NULL) { 265 if (nat->nat_dir == NAT_INBOUND) 266 fi.fin_fi.fi_daddr = nat2->nat_ndstaddr; 267 else 268 fi.fin_fi.fi_saddr = nat2->nat_osrcaddr; 269 } 270 fi.fin_ifp = NULL; 271 (void) ipf_state_add(softc, &fi, &pptp->pptp_state, 0); 272 } 273 ip->ip_p = p; 274 return; 275 } 276 277 278 /* 279 * Try and build up the next PPTP message in the TCP stream and if we can 280 * build it up completely (fits in our buffer) then pass it off to the message 281 * parsing function. 282 */ 283 int 284 ipf_p_pptp_nextmessage(fin, nat, pptp, rev) 285 fr_info_t *fin; 286 nat_t *nat; 287 pptp_pxy_t *pptp; 288 int rev; 289 { 290 static const char *funcname = "ipf_p_pptp_nextmessage"; 291 pptp_side_t *pptps; 292 u_32_t start, end; 293 pptp_hdr_t *hdr; 294 tcphdr_t *tcp; 295 int dlen, off; 296 u_short len; 297 char *msg; 298 299 tcp = fin->fin_dp; 300 dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 301 start = ntohl(tcp->th_seq); 302 pptps = &pptp->pptp_side[rev]; 303 off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) + 304 fin->fin_ipoff; 305 306 if (dlen <= 0) 307 return 0; 308 /* 309 * If the complete data packet is before what we expect to see 310 * "next", just ignore it as the chances are we've already seen it. 311 * The next if statement following this one really just causes packets 312 * ahead of what we've seen to be dropped, implying that something in 313 * the middle went missing and we want to see that first. 314 */ 315 end = start + dlen; 316 if (pptps->pptps_next > end && pptps->pptps_next > start) 317 return 0; 318 319 if (pptps->pptps_next != start) { 320 if (ipf_p_pptp_debug > 5) 321 printf("%s: next (%x) != start (%x)\n", funcname, 322 pptps->pptps_next, start); 323 return -1; 324 } 325 326 msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2); 327 328 while (dlen > 0) { 329 off += pptps->pptps_bytes; 330 if (pptps->pptps_gothdr == 0) { 331 /* 332 * PPTP has an 8 byte header that inclues the cookie. 333 * The start of every message should include one and 334 * it should match 1a2b3c4d. Byte order is ignored, 335 * deliberately, when printing out the error. 336 */ 337 len = MIN(8 - pptps->pptps_bytes, dlen); 338 COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); 339 pptps->pptps_bytes += len; 340 pptps->pptps_wptr += len; 341 hdr = (pptp_hdr_t *)pptps->pptps_buffer; 342 if (pptps->pptps_bytes == 8) { 343 pptps->pptps_next += 8; 344 if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) { 345 if (ipf_p_pptp_debug > 1) 346 printf("%s: bad cookie (%x)\n", 347 funcname, 348 hdr->pptph_cookie); 349 return -1; 350 } 351 } 352 dlen -= len; 353 msg += len; 354 off += len; 355 356 pptps->pptps_gothdr = 1; 357 len = ntohs(hdr->pptph_len); 358 pptps->pptps_len = len; 359 pptps->pptps_nexthdr += len; 360 361 /* 362 * If a message is too big for the buffer, just set 363 * the fields for the next message to come along. 364 * The messages defined in RFC 2637 will not exceed 365 * 512 bytes (in total length) so this is likely a 366 * bad data packet, anyway. 367 */ 368 if (len > sizeof(pptps->pptps_buffer)) { 369 if (ipf_p_pptp_debug > 3) 370 printf("%s: message too big (%d)\n", 371 funcname, len); 372 pptps->pptps_next = pptps->pptps_nexthdr; 373 pptps->pptps_wptr = pptps->pptps_buffer; 374 pptps->pptps_gothdr = 0; 375 pptps->pptps_bytes = 0; 376 pptps->pptps_len = 0; 377 break; 378 } 379 } 380 381 len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen); 382 COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); 383 pptps->pptps_bytes += len; 384 pptps->pptps_wptr += len; 385 pptps->pptps_next += len; 386 387 if (pptps->pptps_len > pptps->pptps_bytes) 388 break; 389 390 ipf_p_pptp_message(fin, nat, pptp, pptps); 391 pptps->pptps_wptr = pptps->pptps_buffer; 392 pptps->pptps_gothdr = 0; 393 pptps->pptps_bytes = 0; 394 pptps->pptps_len = 0; 395 396 start += len; 397 msg += len; 398 dlen -= len; 399 } 400 401 return 0; 402 } 403 404 405 /* 406 * handle a complete PPTP message 407 */ 408 int 409 ipf_p_pptp_message(fin, nat, pptp, pptps) 410 fr_info_t *fin; 411 nat_t *nat; 412 pptp_pxy_t *pptp; 413 pptp_side_t *pptps; 414 { 415 pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer; 416 417 switch (ntohs(hdr->pptph_type)) 418 { 419 case PPTP_MSGTYPE_CTL : 420 ipf_p_pptp_mctl(fin, nat, pptp, pptps); 421 break; 422 423 default : 424 break; 425 } 426 return 0; 427 } 428 429 430 /* 431 * handle a complete PPTP control message 432 */ 433 int 434 ipf_p_pptp_mctl(fin, nat, pptp, pptps) 435 fr_info_t *fin; 436 nat_t *nat; 437 pptp_pxy_t *pptp; 438 pptp_side_t *pptps; 439 { 440 u_short *buffer = (u_short *)(pptps->pptps_buffer); 441 pptp_side_t *pptpo; 442 443 if (pptps == &pptp->pptp_side[0]) 444 pptpo = &pptp->pptp_side[1]; 445 else 446 pptpo = &pptp->pptp_side[0]; 447 448 /* 449 * Breakout to handle all the various messages. Most are just state 450 * transition. 451 */ 452 switch (ntohs(buffer[4])) 453 { 454 case PPTP_MTCTL_STARTREQ : 455 pptps->pptps_state = PPTP_MTCTL_STARTREQ; 456 break; 457 case PPTP_MTCTL_STARTREP : 458 if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ) 459 pptps->pptps_state = PPTP_MTCTL_STARTREP; 460 break; 461 case PPTP_MTCTL_STOPREQ : 462 pptps->pptps_state = PPTP_MTCTL_STOPREQ; 463 break; 464 case PPTP_MTCTL_STOPREP : 465 if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ) 466 pptps->pptps_state = PPTP_MTCTL_STOPREP; 467 break; 468 case PPTP_MTCTL_ECHOREQ : 469 pptps->pptps_state = PPTP_MTCTL_ECHOREQ; 470 break; 471 case PPTP_MTCTL_ECHOREP : 472 if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ) 473 pptps->pptps_state = PPTP_MTCTL_ECHOREP; 474 break; 475 case PPTP_MTCTL_OUTREQ : 476 pptps->pptps_state = PPTP_MTCTL_OUTREQ; 477 break; 478 case PPTP_MTCTL_OUTREP : 479 if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) { 480 pptps->pptps_state = PPTP_MTCTL_OUTREP; 481 pptp->pptp_call[0] = buffer[7]; 482 pptp->pptp_call[1] = buffer[6]; 483 ipf_p_pptp_donatstate(fin, nat, pptp); 484 } 485 break; 486 case PPTP_MTCTL_INREQ : 487 pptps->pptps_state = PPTP_MTCTL_INREQ; 488 break; 489 case PPTP_MTCTL_INREP : 490 if (pptpo->pptps_state == PPTP_MTCTL_INREQ) { 491 pptps->pptps_state = PPTP_MTCTL_INREP; 492 pptp->pptp_call[0] = buffer[7]; 493 pptp->pptp_call[1] = buffer[6]; 494 ipf_p_pptp_donatstate(fin, nat, pptp); 495 } 496 break; 497 case PPTP_MTCTL_INCONNECT : 498 pptps->pptps_state = PPTP_MTCTL_INCONNECT; 499 break; 500 case PPTP_MTCTL_CLEAR : 501 pptps->pptps_state = PPTP_MTCTL_CLEAR; 502 break; 503 case PPTP_MTCTL_DISCONNECT : 504 pptps->pptps_state = PPTP_MTCTL_DISCONNECT; 505 break; 506 case PPTP_MTCTL_WANERROR : 507 pptps->pptps_state = PPTP_MTCTL_WANERROR; 508 break; 509 case PPTP_MTCTL_LINKINFO : 510 pptps->pptps_state = PPTP_MTCTL_LINKINFO; 511 break; 512 } 513 514 return 0; 515 } 516 517 518 /* 519 * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if 520 * we can. If they have disappeared, recreate them. 521 */ 522 int 523 ipf_p_pptp_inout(arg, fin, aps, nat) 524 void *arg; 525 fr_info_t *fin; 526 ap_session_t *aps; 527 nat_t *nat; 528 { 529 pptp_pxy_t *pptp; 530 tcphdr_t *tcp; 531 int rev; 532 533 if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) 534 rev = 1; 535 else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) 536 rev = 1; 537 else 538 rev = 0; 539 540 tcp = (tcphdr_t *)fin->fin_dp; 541 if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 542 pptp = (pptp_pxy_t *)aps->aps_data; 543 pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack); 544 pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack); 545 pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1; 546 pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1; 547 } 548 return ipf_p_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data, 549 rev); 550 } 551 552 553 /* 554 * clean up after ourselves. 555 */ 556 void 557 ipf_p_pptp_del(softc, aps) 558 ipf_main_softc_t *softc; 559 ap_session_t *aps; 560 { 561 pptp_pxy_t *pptp; 562 563 pptp = aps->aps_data; 564 565 if (pptp != NULL) { 566 /* 567 * Don't bother changing any of the NAT structure details, 568 * *_del() is on a callback from aps_free(), from nat_delete() 569 */ 570 571 READ_ENTER(&softc->ipf_state); 572 if (pptp->pptp_state != NULL) { 573 ipf_state_setpending(softc, pptp->pptp_state); 574 } 575 RWLOCK_EXIT(&softc->ipf_state); 576 577 if (pptp->pptp_nat != NULL) 578 ipf_nat_setpending(softc, pptp->pptp_nat); 579 pptp->pptp_rule->in_flags |= IPN_DELETE; 580 ipf_nat_rule_deref(softc, &pptp->pptp_rule); 581 } 582 } 583