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