ip_pptp_pxy.c revision 153872
1145516Sdarrenr/* 2145516Sdarrenr * Copyright (C) 2002-2003 by Darren Reed 3145516Sdarrenr * 4145516Sdarrenr * Simple PPTP transparent proxy for in-kernel use. For use with the NAT 5145516Sdarrenr * code. 6145516Sdarrenr * 7153872Sguido * $Id: ip_pptp_pxy.c,v 2.10.2.11 2005/12/04 23:39:27 darrenr Exp $ 8145516Sdarrenr * 9145516Sdarrenr */ 10145516Sdarrenr#define IPF_PPTP_PROXY 11145516Sdarrenr 12145516Sdarrenrtypedef struct pptp_hdr { 13145516Sdarrenr u_short pptph_len; 14145516Sdarrenr u_short pptph_type; 15145516Sdarrenr u_32_t pptph_cookie; 16145516Sdarrenr} pptp_hdr_t; 17145516Sdarrenr 18145516Sdarrenr#define PPTP_MSGTYPE_CTL 1 19145516Sdarrenr#define PPTP_MTCTL_STARTREQ 1 20145516Sdarrenr#define PPTP_MTCTL_STARTREP 2 21145516Sdarrenr#define PPTP_MTCTL_STOPREQ 3 22145516Sdarrenr#define PPTP_MTCTL_STOPREP 4 23145516Sdarrenr#define PPTP_MTCTL_ECHOREQ 5 24145516Sdarrenr#define PPTP_MTCTL_ECHOREP 6 25145516Sdarrenr#define PPTP_MTCTL_OUTREQ 7 26145516Sdarrenr#define PPTP_MTCTL_OUTREP 8 27145516Sdarrenr#define PPTP_MTCTL_INREQ 9 28145516Sdarrenr#define PPTP_MTCTL_INREP 10 29145516Sdarrenr#define PPTP_MTCTL_INCONNECT 11 30145516Sdarrenr#define PPTP_MTCTL_CLEAR 12 31145516Sdarrenr#define PPTP_MTCTL_DISCONNECT 13 32145516Sdarrenr#define PPTP_MTCTL_WANERROR 14 33145516Sdarrenr#define PPTP_MTCTL_LINKINFO 15 34145516Sdarrenr 35145516Sdarrenr 36145516Sdarrenrint ippr_pptp_init __P((void)); 37145516Sdarrenrvoid ippr_pptp_fini __P((void)); 38145516Sdarrenrint ippr_pptp_new __P((fr_info_t *, ap_session_t *, nat_t *)); 39145516Sdarrenrvoid ippr_pptp_del __P((ap_session_t *)); 40145516Sdarrenrint ippr_pptp_inout __P((fr_info_t *, ap_session_t *, nat_t *)); 41145516Sdarrenrvoid ippr_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *)); 42145516Sdarrenrint ippr_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); 43145516Sdarrenrint ippr_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int)); 44145516Sdarrenrint ippr_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); 45145516Sdarrenr 46145516Sdarrenrstatic frentry_t pptpfr; 47145516Sdarrenr 48145516Sdarrenrint pptp_proxy_init = 0; 49145516Sdarrenrint ippr_pptp_debug = 0; 50145516Sdarrenrint ippr_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */ 51145516Sdarrenr 52145516Sdarrenr 53145516Sdarrenr/* 54145516Sdarrenr * PPTP application proxy initialization. 55145516Sdarrenr */ 56145516Sdarrenrint ippr_pptp_init() 57145516Sdarrenr{ 58145516Sdarrenr bzero((char *)&pptpfr, sizeof(pptpfr)); 59145516Sdarrenr pptpfr.fr_ref = 1; 60145516Sdarrenr pptpfr.fr_age[0] = ippr_pptp_gretimeout; 61145516Sdarrenr pptpfr.fr_age[1] = ippr_pptp_gretimeout; 62145516Sdarrenr pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 63145516Sdarrenr MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock"); 64145516Sdarrenr pptp_proxy_init = 1; 65145516Sdarrenr 66145516Sdarrenr return 0; 67145516Sdarrenr} 68145516Sdarrenr 69145516Sdarrenr 70145516Sdarrenrvoid ippr_pptp_fini() 71145516Sdarrenr{ 72145516Sdarrenr if (pptp_proxy_init == 1) { 73145516Sdarrenr MUTEX_DESTROY(&pptpfr.fr_lock); 74145516Sdarrenr pptp_proxy_init = 0; 75145516Sdarrenr } 76145516Sdarrenr} 77145516Sdarrenr 78145516Sdarrenr 79145516Sdarrenr/* 80145516Sdarrenr * Setup for a new PPTP proxy. 81145516Sdarrenr */ 82145516Sdarrenrint ippr_pptp_new(fin, aps, nat) 83145516Sdarrenrfr_info_t *fin; 84145516Sdarrenrap_session_t *aps; 85145516Sdarrenrnat_t *nat; 86145516Sdarrenr{ 87145516Sdarrenr pptp_pxy_t *pptp; 88145516Sdarrenr ipnat_t *ipn; 89145516Sdarrenr ip_t *ip; 90145516Sdarrenr 91145516Sdarrenr ip = fin->fin_ip; 92145516Sdarrenr 93145516Sdarrenr if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip, 94145516Sdarrenr ip->ip_dst) != NULL) { 95145516Sdarrenr if (ippr_pptp_debug > 0) 96145516Sdarrenr printf("ippr_pptp_new: GRE session already exists\n"); 97145516Sdarrenr return -1; 98145516Sdarrenr } 99145516Sdarrenr 100145516Sdarrenr aps->aps_psiz = sizeof(*pptp); 101145516Sdarrenr KMALLOCS(aps->aps_data, pptp_pxy_t *, sizeof(*pptp)); 102145516Sdarrenr if (aps->aps_data == NULL) { 103145516Sdarrenr if (ippr_pptp_debug > 0) 104145516Sdarrenr printf("ippr_pptp_new: malloc for aps_data failed\n"); 105145516Sdarrenr return -1; 106145516Sdarrenr } 107145516Sdarrenr 108145516Sdarrenr /* 109145516Sdarrenr * Create NAT rule against which the tunnel/transport mapping is 110145516Sdarrenr * created. This is required because the current NAT rule does not 111145516Sdarrenr * describe GRE but TCP instead. 112145516Sdarrenr */ 113145516Sdarrenr pptp = aps->aps_data; 114145516Sdarrenr bzero((char *)pptp, sizeof(*pptp)); 115145516Sdarrenr ipn = &pptp->pptp_rule; 116145516Sdarrenr ipn->in_ifps[0] = fin->fin_ifp; 117145516Sdarrenr ipn->in_apr = NULL; 118145516Sdarrenr ipn->in_use = 1; 119145516Sdarrenr ipn->in_hits = 1; 120145516Sdarrenr ipn->in_ippip = 1; 121145516Sdarrenr if (nat->nat_dir == NAT_OUTBOUND) { 122145516Sdarrenr ipn->in_nip = ntohl(nat->nat_outip.s_addr); 123145516Sdarrenr ipn->in_outip = fin->fin_saddr; 124145516Sdarrenr ipn->in_redir = NAT_MAP; 125145516Sdarrenr } else if (nat->nat_dir == NAT_INBOUND) { 126145516Sdarrenr ipn->in_nip = 0; 127145516Sdarrenr ipn->in_outip = nat->nat_outip.s_addr; 128145516Sdarrenr ipn->in_redir = NAT_REDIRECT; 129145516Sdarrenr } 130145516Sdarrenr ipn->in_inip = nat->nat_inip.s_addr; 131145516Sdarrenr ipn->in_inmsk = 0xffffffff; 132145516Sdarrenr ipn->in_outmsk = 0xffffffff; 133145516Sdarrenr ipn->in_srcip = fin->fin_saddr; 134145516Sdarrenr ipn->in_srcmsk = 0xffffffff; 135145516Sdarrenr bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0], 136145516Sdarrenr sizeof(ipn->in_ifnames[0])); 137145516Sdarrenr ipn->in_p = IPPROTO_GRE; 138145516Sdarrenr 139145516Sdarrenr pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer; 140145516Sdarrenr pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer; 141145516Sdarrenr return 0; 142145516Sdarrenr} 143145516Sdarrenr 144145516Sdarrenr 145145516Sdarrenrvoid ippr_pptp_donatstate(fin, nat, pptp) 146145516Sdarrenrfr_info_t *fin; 147145516Sdarrenrnat_t *nat; 148145516Sdarrenrpptp_pxy_t *pptp; 149145516Sdarrenr{ 150145516Sdarrenr fr_info_t fi; 151145516Sdarrenr grehdr_t gre; 152145516Sdarrenr nat_t *nat2; 153145516Sdarrenr u_char p; 154145516Sdarrenr ip_t *ip; 155145516Sdarrenr 156145516Sdarrenr ip = fin->fin_ip; 157145516Sdarrenr p = ip->ip_p; 158145516Sdarrenr 159145516Sdarrenr nat2 = pptp->pptp_nat; 160145516Sdarrenr if ((nat2 == NULL) || (pptp->pptp_state == NULL)) { 161145516Sdarrenr bcopy((char *)fin, (char *)&fi, sizeof(fi)); 162145516Sdarrenr bzero((char *)&gre, sizeof(gre)); 163145516Sdarrenr fi.fin_state = NULL; 164145516Sdarrenr fi.fin_nat = NULL; 165145516Sdarrenr fi.fin_fi.fi_p = IPPROTO_GRE; 166145516Sdarrenr fi.fin_fr = &pptpfr; 167145516Sdarrenr if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) || 168145516Sdarrenr (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) { 169145516Sdarrenr fi.fin_data[0] = pptp->pptp_call[0]; 170145516Sdarrenr fi.fin_data[1] = pptp->pptp_call[1]; 171145516Sdarrenr } else { 172145516Sdarrenr fi.fin_data[0] = pptp->pptp_call[1]; 173145516Sdarrenr fi.fin_data[1] = pptp->pptp_call[0]; 174145516Sdarrenr } 175145516Sdarrenr ip = fin->fin_ip; 176145516Sdarrenr ip->ip_p = IPPROTO_GRE; 177145516Sdarrenr fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); 178145516Sdarrenr fi.fin_flx |= FI_IGNORE; 179145516Sdarrenr fi.fin_dp = &gre; 180145516Sdarrenr gre.gr_flags = htons(1 << 13); 181145516Sdarrenr if (fin->fin_out && nat->nat_dir == NAT_INBOUND) { 182145516Sdarrenr fi.fin_fi.fi_saddr = fin->fin_fi.fi_daddr; 183145516Sdarrenr fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; 184145516Sdarrenr } else if (!fin->fin_out && nat->nat_dir == NAT_OUTBOUND) { 185145516Sdarrenr fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 186145516Sdarrenr fi.fin_fi.fi_daddr = fin->fin_fi.fi_saddr; 187145516Sdarrenr } 188145516Sdarrenr } 189145516Sdarrenr 190145516Sdarrenr /* 191145516Sdarrenr * Update NAT timeout/create NAT if missing. 192145516Sdarrenr */ 193145516Sdarrenr if (nat2 != NULL) 194145516Sdarrenr fr_queueback(&nat2->nat_tqe); 195145516Sdarrenr else { 196145516Sdarrenr nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat, 197145516Sdarrenr NAT_SLAVE, nat->nat_dir); 198145516Sdarrenr pptp->pptp_nat = nat2; 199145516Sdarrenr if (nat2 != NULL) { 200145516Sdarrenr (void) nat_proto(&fi, nat2, 0); 201145516Sdarrenr nat_update(&fi, nat2, nat2->nat_ptr); 202145516Sdarrenr } 203145516Sdarrenr } 204145516Sdarrenr 205145516Sdarrenr READ_ENTER(&ipf_state); 206145516Sdarrenr if (pptp->pptp_state != NULL) { 207145516Sdarrenr fr_queueback(&pptp->pptp_state->is_sti); 208145516Sdarrenr RWLOCK_EXIT(&ipf_state); 209145516Sdarrenr } else { 210145516Sdarrenr RWLOCK_EXIT(&ipf_state); 211145516Sdarrenr if (nat->nat_dir == NAT_INBOUND) 212145516Sdarrenr fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr; 213145516Sdarrenr else 214145516Sdarrenr fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr; 215145516Sdarrenr fi.fin_ifp = NULL; 216145516Sdarrenr pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state, 217145516Sdarrenr 0); 218145516Sdarrenr if (fi.fin_state != NULL) 219145516Sdarrenr fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 220145516Sdarrenr } 221145516Sdarrenr ip->ip_p = p; 222145516Sdarrenr return; 223145516Sdarrenr} 224145516Sdarrenr 225145516Sdarrenr 226145516Sdarrenr/* 227145516Sdarrenr * Try and build up the next PPTP message in the TCP stream and if we can 228145516Sdarrenr * build it up completely (fits in our buffer) then pass it off to the message 229145516Sdarrenr * parsing function. 230145516Sdarrenr */ 231145516Sdarrenrint ippr_pptp_nextmessage(fin, nat, pptp, rev) 232145516Sdarrenrfr_info_t *fin; 233145516Sdarrenrnat_t *nat; 234145516Sdarrenrpptp_pxy_t *pptp; 235145516Sdarrenrint rev; 236145516Sdarrenr{ 237153872Sguido static const char *funcname = "ippr_pptp_nextmessage"; 238145516Sdarrenr pptp_side_t *pptps; 239145516Sdarrenr u_32_t start, end; 240145516Sdarrenr pptp_hdr_t *hdr; 241145516Sdarrenr tcphdr_t *tcp; 242145516Sdarrenr int dlen, off; 243145516Sdarrenr u_short len; 244145516Sdarrenr char *msg; 245145516Sdarrenr 246145516Sdarrenr tcp = fin->fin_dp; 247145516Sdarrenr dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 248145516Sdarrenr start = ntohl(tcp->th_seq); 249145516Sdarrenr pptps = &pptp->pptp_side[rev]; 250145516Sdarrenr off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) + 251145516Sdarrenr fin->fin_ipoff; 252145516Sdarrenr 253145516Sdarrenr if (dlen <= 0) 254145516Sdarrenr return 0; 255145516Sdarrenr /* 256145516Sdarrenr * If the complete data packet is before what we expect to see 257145516Sdarrenr * "next", just ignore it as the chances are we've already seen it. 258145516Sdarrenr * The next if statement following this one really just causes packets 259145516Sdarrenr * ahead of what we've seen to be dropped, implying that something in 260145516Sdarrenr * the middle went missing and we want to see that first. 261145516Sdarrenr */ 262145516Sdarrenr end = start + dlen; 263145516Sdarrenr if (pptps->pptps_next > end && pptps->pptps_next > start) 264145516Sdarrenr return 0; 265145516Sdarrenr 266145516Sdarrenr if (pptps->pptps_next != start) { 267145516Sdarrenr if (ippr_pptp_debug > 5) 268145516Sdarrenr printf("%s: next (%x) != start (%x)\n", funcname, 269145516Sdarrenr pptps->pptps_next, start); 270145516Sdarrenr return -1; 271145516Sdarrenr } 272145516Sdarrenr 273145516Sdarrenr msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2); 274145516Sdarrenr 275145516Sdarrenr while (dlen > 0) { 276145516Sdarrenr off += pptps->pptps_bytes; 277145516Sdarrenr if (pptps->pptps_gothdr == 0) { 278145516Sdarrenr /* 279145516Sdarrenr * PPTP has an 8 byte header that inclues the cookie. 280145516Sdarrenr * The start of every message should include one and 281145516Sdarrenr * it should match 1a2b3c4d. Byte order is ignored, 282145516Sdarrenr * deliberately, when printing out the error. 283145516Sdarrenr */ 284145516Sdarrenr len = MIN(8 - pptps->pptps_bytes, dlen); 285145516Sdarrenr COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); 286145516Sdarrenr pptps->pptps_bytes += len; 287145516Sdarrenr pptps->pptps_wptr += len; 288145516Sdarrenr hdr = (pptp_hdr_t *)pptps->pptps_buffer; 289145516Sdarrenr if (pptps->pptps_bytes == 8) { 290145516Sdarrenr pptps->pptps_next += 8; 291145516Sdarrenr if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) { 292145516Sdarrenr if (ippr_pptp_debug > 1) 293145516Sdarrenr printf("%s: bad cookie (%x)\n", 294145516Sdarrenr funcname, 295145516Sdarrenr hdr->pptph_cookie); 296145516Sdarrenr return -1; 297145516Sdarrenr } 298145516Sdarrenr } 299145516Sdarrenr dlen -= len; 300145516Sdarrenr msg += len; 301145516Sdarrenr off += len; 302145516Sdarrenr 303145516Sdarrenr pptps->pptps_gothdr = 1; 304145516Sdarrenr len = ntohs(hdr->pptph_len); 305145516Sdarrenr pptps->pptps_len = len; 306145516Sdarrenr pptps->pptps_nexthdr += len; 307145516Sdarrenr 308145516Sdarrenr /* 309145516Sdarrenr * If a message is too big for the buffer, just set 310145516Sdarrenr * the fields for the next message to come along. 311145516Sdarrenr * The messages defined in RFC 2637 will not exceed 312145516Sdarrenr * 512 bytes (in total length) so this is likely a 313145516Sdarrenr * bad data packet, anyway. 314145516Sdarrenr */ 315145516Sdarrenr if (len > sizeof(pptps->pptps_buffer)) { 316145516Sdarrenr if (ippr_pptp_debug > 3) 317145516Sdarrenr printf("%s: message too big (%d)\n", 318145516Sdarrenr funcname, len); 319145516Sdarrenr pptps->pptps_next = pptps->pptps_nexthdr; 320145516Sdarrenr pptps->pptps_wptr = pptps->pptps_buffer; 321145516Sdarrenr pptps->pptps_gothdr = 0; 322145516Sdarrenr pptps->pptps_bytes = 0; 323145516Sdarrenr pptps->pptps_len = 0; 324145516Sdarrenr break; 325145516Sdarrenr } 326145516Sdarrenr } 327145516Sdarrenr 328145516Sdarrenr len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen); 329145516Sdarrenr COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); 330145516Sdarrenr pptps->pptps_bytes += len; 331145516Sdarrenr pptps->pptps_wptr += len; 332145516Sdarrenr pptps->pptps_next += len; 333145516Sdarrenr 334145516Sdarrenr if (pptps->pptps_len > pptps->pptps_bytes) 335145516Sdarrenr break; 336145516Sdarrenr 337145516Sdarrenr ippr_pptp_message(fin, nat, pptp, pptps); 338145516Sdarrenr pptps->pptps_wptr = pptps->pptps_buffer; 339145516Sdarrenr pptps->pptps_gothdr = 0; 340145516Sdarrenr pptps->pptps_bytes = 0; 341145516Sdarrenr pptps->pptps_len = 0; 342145516Sdarrenr 343145516Sdarrenr start += len; 344145516Sdarrenr msg += len; 345145516Sdarrenr dlen -= len; 346145516Sdarrenr } 347145516Sdarrenr 348145516Sdarrenr return 0; 349145516Sdarrenr} 350145516Sdarrenr 351145516Sdarrenr 352145516Sdarrenr/* 353145516Sdarrenr * handle a complete PPTP message 354145516Sdarrenr */ 355145516Sdarrenrint ippr_pptp_message(fin, nat, pptp, pptps) 356145516Sdarrenrfr_info_t *fin; 357145516Sdarrenrnat_t *nat; 358145516Sdarrenrpptp_pxy_t *pptp; 359145516Sdarrenrpptp_side_t *pptps; 360145516Sdarrenr{ 361145516Sdarrenr pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer; 362145516Sdarrenr 363145516Sdarrenr switch (ntohs(hdr->pptph_type)) 364145516Sdarrenr { 365145516Sdarrenr case PPTP_MSGTYPE_CTL : 366145516Sdarrenr ippr_pptp_mctl(fin, nat, pptp, pptps); 367145516Sdarrenr break; 368145516Sdarrenr 369145516Sdarrenr default : 370145516Sdarrenr break; 371145516Sdarrenr } 372145516Sdarrenr return 0; 373145516Sdarrenr} 374145516Sdarrenr 375145516Sdarrenr 376145516Sdarrenr/* 377145516Sdarrenr * handle a complete PPTP control message 378145516Sdarrenr */ 379145516Sdarrenrint ippr_pptp_mctl(fin, nat, pptp, pptps) 380145516Sdarrenrfr_info_t *fin; 381145516Sdarrenrnat_t *nat; 382145516Sdarrenrpptp_pxy_t *pptp; 383145516Sdarrenrpptp_side_t *pptps; 384145516Sdarrenr{ 385145516Sdarrenr u_short *buffer = (u_short *)(pptps->pptps_buffer); 386145516Sdarrenr pptp_side_t *pptpo; 387145516Sdarrenr 388145516Sdarrenr if (pptps == &pptp->pptp_side[0]) 389145516Sdarrenr pptpo = &pptp->pptp_side[1]; 390145516Sdarrenr else 391145516Sdarrenr pptpo = &pptp->pptp_side[0]; 392145516Sdarrenr 393145516Sdarrenr /* 394145516Sdarrenr * Breakout to handle all the various messages. Most are just state 395145516Sdarrenr * transition. 396145516Sdarrenr */ 397145516Sdarrenr switch (ntohs(buffer[4])) 398145516Sdarrenr { 399145516Sdarrenr case PPTP_MTCTL_STARTREQ : 400145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STARTREQ; 401145516Sdarrenr break; 402145516Sdarrenr case PPTP_MTCTL_STARTREP : 403145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ) 404145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STARTREP; 405145516Sdarrenr break; 406145516Sdarrenr case PPTP_MTCTL_STOPREQ : 407145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STOPREQ; 408145516Sdarrenr break; 409145516Sdarrenr case PPTP_MTCTL_STOPREP : 410145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ) 411145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STOPREP; 412145516Sdarrenr break; 413145516Sdarrenr case PPTP_MTCTL_ECHOREQ : 414145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_ECHOREQ; 415145516Sdarrenr break; 416145516Sdarrenr case PPTP_MTCTL_ECHOREP : 417145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ) 418145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_ECHOREP; 419145516Sdarrenr break; 420145516Sdarrenr case PPTP_MTCTL_OUTREQ : 421145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_OUTREQ; 422145516Sdarrenr break; 423145516Sdarrenr case PPTP_MTCTL_OUTREP : 424145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) { 425145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_OUTREP; 426145516Sdarrenr pptp->pptp_call[0] = buffer[7]; 427145516Sdarrenr pptp->pptp_call[1] = buffer[6]; 428145516Sdarrenr ippr_pptp_donatstate(fin, nat, pptp); 429145516Sdarrenr } 430145516Sdarrenr break; 431145516Sdarrenr case PPTP_MTCTL_INREQ : 432145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_INREQ; 433145516Sdarrenr break; 434145516Sdarrenr case PPTP_MTCTL_INREP : 435145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_INREQ) { 436145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_INREP; 437145516Sdarrenr pptp->pptp_call[0] = buffer[7]; 438145516Sdarrenr pptp->pptp_call[1] = buffer[6]; 439145516Sdarrenr ippr_pptp_donatstate(fin, nat, pptp); 440145516Sdarrenr } 441145516Sdarrenr break; 442145516Sdarrenr case PPTP_MTCTL_INCONNECT : 443145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_INCONNECT; 444145516Sdarrenr break; 445145516Sdarrenr case PPTP_MTCTL_CLEAR : 446145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_CLEAR; 447145516Sdarrenr break; 448145516Sdarrenr case PPTP_MTCTL_DISCONNECT : 449145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_DISCONNECT; 450145516Sdarrenr break; 451145516Sdarrenr case PPTP_MTCTL_WANERROR : 452145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_WANERROR; 453145516Sdarrenr break; 454145516Sdarrenr case PPTP_MTCTL_LINKINFO : 455145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_LINKINFO; 456145516Sdarrenr break; 457145516Sdarrenr } 458145516Sdarrenr 459145516Sdarrenr return 0; 460145516Sdarrenr} 461145516Sdarrenr 462145516Sdarrenr 463145516Sdarrenr/* 464145516Sdarrenr * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if 465145516Sdarrenr * we can. If they have disappeared, recreate them. 466145516Sdarrenr */ 467145516Sdarrenrint ippr_pptp_inout(fin, aps, nat) 468145516Sdarrenrfr_info_t *fin; 469145516Sdarrenrap_session_t *aps; 470145516Sdarrenrnat_t *nat; 471145516Sdarrenr{ 472145516Sdarrenr pptp_pxy_t *pptp; 473145516Sdarrenr tcphdr_t *tcp; 474145516Sdarrenr int rev; 475145516Sdarrenr 476145516Sdarrenr if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) 477145516Sdarrenr rev = 1; 478145516Sdarrenr else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) 479145516Sdarrenr rev = 1; 480145516Sdarrenr else 481145516Sdarrenr rev = 0; 482145516Sdarrenr 483145516Sdarrenr tcp = (tcphdr_t *)fin->fin_dp; 484145516Sdarrenr if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 485145516Sdarrenr pptp = (pptp_pxy_t *)aps->aps_data; 486145516Sdarrenr pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack); 487145516Sdarrenr pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack); 488145516Sdarrenr pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1; 489145516Sdarrenr pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1; 490145516Sdarrenr } 491145516Sdarrenr return ippr_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data, 492145516Sdarrenr rev); 493145516Sdarrenr} 494145516Sdarrenr 495145516Sdarrenr 496145516Sdarrenr/* 497145516Sdarrenr * clean up after ourselves. 498145516Sdarrenr */ 499145516Sdarrenrvoid ippr_pptp_del(aps) 500145516Sdarrenrap_session_t *aps; 501145516Sdarrenr{ 502145516Sdarrenr pptp_pxy_t *pptp; 503145516Sdarrenr 504145516Sdarrenr pptp = aps->aps_data; 505145516Sdarrenr 506145516Sdarrenr if (pptp != NULL) { 507145516Sdarrenr /* 508145516Sdarrenr * Don't bother changing any of the NAT structure details, 509145516Sdarrenr * *_del() is on a callback from aps_free(), from nat_delete() 510145516Sdarrenr */ 511145516Sdarrenr 512145516Sdarrenr READ_ENTER(&ipf_state); 513145516Sdarrenr if (pptp->pptp_state != NULL) { 514145516Sdarrenr pptp->pptp_state->is_die = fr_ticks + 1; 515145516Sdarrenr pptp->pptp_state->is_me = NULL; 516145516Sdarrenr fr_queuefront(&pptp->pptp_state->is_sti); 517145516Sdarrenr } 518145516Sdarrenr RWLOCK_EXIT(&ipf_state); 519145516Sdarrenr 520145516Sdarrenr pptp->pptp_state = NULL; 521145516Sdarrenr pptp->pptp_nat = NULL; 522145516Sdarrenr } 523145516Sdarrenr} 524