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