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