1145516Sdarrenr/* 2255332Scy * Copyright (C) 2012 by Darren Reed. 3145516Sdarrenr * 4145516Sdarrenr * Simple PPTP transparent proxy for in-kernel use. For use with the NAT 5145516Sdarrenr * code. 6145516Sdarrenr * 7255332Scy * $Id$ 8145516Sdarrenr * 9145516Sdarrenr */ 10145516Sdarrenr#define IPF_PPTP_PROXY 11145516Sdarrenr 12255332Scy 13255332Scy 14255332Scy/* 15255332Scy * PPTP proxy 16255332Scy */ 17255332Scytypedef struct pptp_side { 18255332Scy u_32_t pptps_nexthdr; 19255332Scy u_32_t pptps_next; 20255332Scy int pptps_state; 21255332Scy int pptps_gothdr; 22255332Scy int pptps_len; 23255332Scy int pptps_bytes; 24255332Scy char *pptps_wptr; 25255332Scy char pptps_buffer[512]; 26255332Scy} pptp_side_t; 27255332Scy 28255332Scytypedef struct pptp_pxy { 29255332Scy nat_t *pptp_nat; 30255332Scy struct ipstate *pptp_state; 31255332Scy u_short pptp_call[2]; 32255332Scy pptp_side_t pptp_side[2]; 33255332Scy ipnat_t *pptp_rule; 34255332Scy} pptp_pxy_t; 35255332Scy 36145516Sdarrenrtypedef struct pptp_hdr { 37255332Scy u_short pptph_len; 38255332Scy u_short pptph_type; 39255332Scy u_32_t pptph_cookie; 40145516Sdarrenr} pptp_hdr_t; 41145516Sdarrenr 42145516Sdarrenr#define PPTP_MSGTYPE_CTL 1 43145516Sdarrenr#define PPTP_MTCTL_STARTREQ 1 44145516Sdarrenr#define PPTP_MTCTL_STARTREP 2 45145516Sdarrenr#define PPTP_MTCTL_STOPREQ 3 46145516Sdarrenr#define PPTP_MTCTL_STOPREP 4 47145516Sdarrenr#define PPTP_MTCTL_ECHOREQ 5 48145516Sdarrenr#define PPTP_MTCTL_ECHOREP 6 49145516Sdarrenr#define PPTP_MTCTL_OUTREQ 7 50145516Sdarrenr#define PPTP_MTCTL_OUTREP 8 51145516Sdarrenr#define PPTP_MTCTL_INREQ 9 52145516Sdarrenr#define PPTP_MTCTL_INREP 10 53145516Sdarrenr#define PPTP_MTCTL_INCONNECT 11 54145516Sdarrenr#define PPTP_MTCTL_CLEAR 12 55145516Sdarrenr#define PPTP_MTCTL_DISCONNECT 13 56145516Sdarrenr#define PPTP_MTCTL_WANERROR 14 57145516Sdarrenr#define PPTP_MTCTL_LINKINFO 15 58145516Sdarrenr 59145516Sdarrenr 60255332Scyvoid ipf_p_pptp_main_load __P((void)); 61255332Scyvoid ipf_p_pptp_main_unload __P((void)); 62255332Scyint ipf_p_pptp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 63255332Scyvoid ipf_p_pptp_del __P((ipf_main_softc_t *, ap_session_t *)); 64255332Scyint ipf_p_pptp_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *)); 65255332Scyvoid ipf_p_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *)); 66255332Scyint ipf_p_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); 67255332Scyint ipf_p_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int)); 68255332Scyint ipf_p_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); 69145516Sdarrenr 70145516Sdarrenrstatic frentry_t pptpfr; 71145516Sdarrenr 72255332Scystatic int pptp_proxy_init = 0; 73255332Scystatic int ipf_p_pptp_debug = 0; 74255332Scystatic int ipf_p_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */ 75145516Sdarrenr 76145516Sdarrenr 77145516Sdarrenr/* 78145516Sdarrenr * PPTP application proxy initialization. 79145516Sdarrenr */ 80255332Scyvoid 81255332Scyipf_p_pptp_main_load() 82145516Sdarrenr{ 83145516Sdarrenr bzero((char *)&pptpfr, sizeof(pptpfr)); 84145516Sdarrenr pptpfr.fr_ref = 1; 85255332Scy pptpfr.fr_age[0] = ipf_p_pptp_gretimeout; 86255332Scy pptpfr.fr_age[1] = ipf_p_pptp_gretimeout; 87145516Sdarrenr pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 88145516Sdarrenr MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock"); 89145516Sdarrenr pptp_proxy_init = 1; 90145516Sdarrenr} 91145516Sdarrenr 92145516Sdarrenr 93255332Scyvoid 94255332Scyipf_p_pptp_main_unload() 95145516Sdarrenr{ 96145516Sdarrenr if (pptp_proxy_init == 1) { 97145516Sdarrenr MUTEX_DESTROY(&pptpfr.fr_lock); 98145516Sdarrenr pptp_proxy_init = 0; 99145516Sdarrenr } 100145516Sdarrenr} 101145516Sdarrenr 102145516Sdarrenr 103145516Sdarrenr/* 104145516Sdarrenr * Setup for a new PPTP proxy. 105170263Sdarrenr * 106170263Sdarrenr * NOTE: The printf's are broken up with %s in them to prevent them being 107170263Sdarrenr * optimised into puts statements on FreeBSD (this doesn't exist in the kernel) 108145516Sdarrenr */ 109255332Scyint 110255332Scyipf_p_pptp_new(arg, fin, aps, nat) 111255332Scy void *arg; 112255332Scy fr_info_t *fin; 113255332Scy ap_session_t *aps; 114255332Scy nat_t *nat; 115145516Sdarrenr{ 116145516Sdarrenr pptp_pxy_t *pptp; 117145516Sdarrenr ipnat_t *ipn; 118255332Scy ipnat_t *np; 119255332Scy int size; 120145516Sdarrenr ip_t *ip; 121145516Sdarrenr 122255332Scy if (fin->fin_v != 4) 123255332Scy return -1; 124255332Scy 125145516Sdarrenr ip = fin->fin_ip; 126255332Scy np = nat->nat_ptr; 127255332Scy size = np->in_size; 128145516Sdarrenr 129255332Scy if (ipf_nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_osrcip, 130145516Sdarrenr ip->ip_dst) != NULL) { 131255332Scy if (ipf_p_pptp_debug > 0) 132255332Scy printf("ipf_p_pptp_new: GRE session already exists\n"); 133145516Sdarrenr return -1; 134145516Sdarrenr } 135145516Sdarrenr 136255332Scy KMALLOC(pptp, pptp_pxy_t *); 137255332Scy if (pptp == NULL) { 138255332Scy if (ipf_p_pptp_debug > 0) 139255332Scy printf("ipf_p_pptp_new: malloc for aps_data failed\n"); 140145516Sdarrenr return -1; 141145516Sdarrenr } 142255332Scy KMALLOCS(ipn, ipnat_t *, size); 143255332Scy if (ipn == NULL) { 144255332Scy KFREE(pptp); 145255332Scy return -1; 146255332Scy } 147145516Sdarrenr 148255332Scy aps->aps_data = pptp; 149255332Scy aps->aps_psiz = sizeof(*pptp); 150255332Scy bzero((char *)pptp, sizeof(*pptp)); 151255332Scy bzero((char *)ipn, size); 152255332Scy pptp->pptp_rule = ipn; 153255332Scy 154145516Sdarrenr /* 155145516Sdarrenr * Create NAT rule against which the tunnel/transport mapping is 156145516Sdarrenr * created. This is required because the current NAT rule does not 157145516Sdarrenr * describe GRE but TCP instead. 158145516Sdarrenr */ 159255332Scy ipn->in_size = size; 160145516Sdarrenr ipn->in_ifps[0] = fin->fin_ifp; 161145516Sdarrenr ipn->in_apr = NULL; 162145516Sdarrenr ipn->in_use = 1; 163145516Sdarrenr ipn->in_hits = 1; 164145516Sdarrenr ipn->in_ippip = 1; 165255332Scy ipn->in_snip = ntohl(nat->nat_nsrcaddr); 166255332Scy ipn->in_nsrcaddr = fin->fin_saddr; 167255332Scy ipn->in_dnip = ntohl(nat->nat_ndstaddr); 168255332Scy ipn->in_ndstaddr = nat->nat_ndstaddr; 169255332Scy ipn->in_redir = np->in_redir; 170255332Scy ipn->in_osrcaddr = nat->nat_osrcaddr; 171255332Scy ipn->in_odstaddr = nat->nat_odstaddr; 172255332Scy ipn->in_osrcmsk = 0xffffffff; 173255332Scy ipn->in_nsrcmsk = 0xffffffff; 174255332Scy ipn->in_odstmsk = 0xffffffff; 175255332Scy ipn->in_ndstmsk = 0xffffffff; 176255332Scy ipn->in_flags = (np->in_flags | IPN_PROXYRULE); 177255332Scy MUTEX_INIT(&ipn->in_lock, "pptp proxy NAT rule"); 178145516Sdarrenr 179255332Scy ipn->in_namelen = np->in_namelen; 180255332Scy bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen); 181255332Scy ipn->in_ifnames[0] = np->in_ifnames[0]; 182255332Scy ipn->in_ifnames[1] = np->in_ifnames[1]; 183255332Scy 184255332Scy ipn->in_pr[0] = IPPROTO_GRE; 185255332Scy ipn->in_pr[1] = IPPROTO_GRE; 186255332Scy 187145516Sdarrenr pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer; 188145516Sdarrenr pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer; 189145516Sdarrenr return 0; 190145516Sdarrenr} 191145516Sdarrenr 192145516Sdarrenr 193255332Scyvoid 194255332Scyipf_p_pptp_donatstate(fin, nat, pptp) 195255332Scy fr_info_t *fin; 196255332Scy nat_t *nat; 197255332Scy pptp_pxy_t *pptp; 198145516Sdarrenr{ 199255332Scy ipf_main_softc_t *softc = fin->fin_main_soft; 200145516Sdarrenr fr_info_t fi; 201145516Sdarrenr grehdr_t gre; 202145516Sdarrenr nat_t *nat2; 203145516Sdarrenr u_char p; 204145516Sdarrenr ip_t *ip; 205145516Sdarrenr 206145516Sdarrenr ip = fin->fin_ip; 207145516Sdarrenr p = ip->ip_p; 208145516Sdarrenr 209145516Sdarrenr nat2 = pptp->pptp_nat; 210145516Sdarrenr if ((nat2 == NULL) || (pptp->pptp_state == NULL)) { 211145516Sdarrenr bcopy((char *)fin, (char *)&fi, sizeof(fi)); 212145516Sdarrenr bzero((char *)&gre, sizeof(gre)); 213145516Sdarrenr fi.fin_fi.fi_p = IPPROTO_GRE; 214145516Sdarrenr fi.fin_fr = &pptpfr; 215145516Sdarrenr if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) || 216145516Sdarrenr (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) { 217145516Sdarrenr fi.fin_data[0] = pptp->pptp_call[0]; 218145516Sdarrenr fi.fin_data[1] = pptp->pptp_call[1]; 219145516Sdarrenr } else { 220145516Sdarrenr fi.fin_data[0] = pptp->pptp_call[1]; 221145516Sdarrenr fi.fin_data[1] = pptp->pptp_call[0]; 222145516Sdarrenr } 223145516Sdarrenr ip = fin->fin_ip; 224145516Sdarrenr ip->ip_p = IPPROTO_GRE; 225145516Sdarrenr fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); 226145516Sdarrenr fi.fin_flx |= FI_IGNORE; 227145516Sdarrenr fi.fin_dp = &gre; 228145516Sdarrenr gre.gr_flags = htons(1 << 13); 229255332Scy 230255332Scy fi.fin_fi.fi_saddr = nat->nat_osrcaddr; 231255332Scy fi.fin_fi.fi_daddr = nat->nat_odstaddr; 232145516Sdarrenr } 233145516Sdarrenr 234145516Sdarrenr /* 235145516Sdarrenr * Update NAT timeout/create NAT if missing. 236145516Sdarrenr */ 237145516Sdarrenr if (nat2 != NULL) 238255332Scy ipf_queueback(softc->ipf_ticks, &nat2->nat_tqe); 239145516Sdarrenr else { 240255332Scy#ifdef USE_MUTEXES 241255332Scy ipf_nat_softc_t *softn = softc->ipf_nat_soft; 242255332Scy#endif 243255332Scy 244255332Scy MUTEX_ENTER(&softn->ipf_nat_new); 245255332Scy nat2 = ipf_nat_add(&fi, pptp->pptp_rule, &pptp->pptp_nat, 246255332Scy NAT_SLAVE, nat->nat_dir); 247255332Scy MUTEX_EXIT(&softn->ipf_nat_new); 248145516Sdarrenr if (nat2 != NULL) { 249255332Scy (void) ipf_nat_proto(&fi, nat2, 0); 250255332Scy MUTEX_ENTER(&nat2->nat_lock); 251255332Scy ipf_nat_update(&fi, nat2); 252255332Scy MUTEX_EXIT(&nat2->nat_lock); 253145516Sdarrenr } 254145516Sdarrenr } 255145516Sdarrenr 256255332Scy READ_ENTER(&softc->ipf_state); 257145516Sdarrenr if (pptp->pptp_state != NULL) { 258255332Scy ipf_queueback(softc->ipf_ticks, &pptp->pptp_state->is_sti); 259255332Scy RWLOCK_EXIT(&softc->ipf_state); 260145516Sdarrenr } else { 261255332Scy RWLOCK_EXIT(&softc->ipf_state); 262161351Sguido if (nat2 != NULL) { 263161351Sguido if (nat->nat_dir == NAT_INBOUND) 264255332Scy fi.fin_fi.fi_daddr = nat2->nat_ndstaddr; 265161351Sguido else 266255332Scy fi.fin_fi.fi_saddr = nat2->nat_osrcaddr; 267161351Sguido } 268145516Sdarrenr fi.fin_ifp = NULL; 269255332Scy (void) ipf_state_add(softc, &fi, &pptp->pptp_state, 0); 270145516Sdarrenr } 271145516Sdarrenr ip->ip_p = p; 272145516Sdarrenr return; 273145516Sdarrenr} 274145516Sdarrenr 275145516Sdarrenr 276145516Sdarrenr/* 277145516Sdarrenr * Try and build up the next PPTP message in the TCP stream and if we can 278145516Sdarrenr * build it up completely (fits in our buffer) then pass it off to the message 279145516Sdarrenr * parsing function. 280145516Sdarrenr */ 281255332Scyint 282255332Scyipf_p_pptp_nextmessage(fin, nat, pptp, rev) 283255332Scy fr_info_t *fin; 284255332Scy nat_t *nat; 285255332Scy pptp_pxy_t *pptp; 286255332Scy int rev; 287145516Sdarrenr{ 288255332Scy static const char *funcname = "ipf_p_pptp_nextmessage"; 289145516Sdarrenr pptp_side_t *pptps; 290145516Sdarrenr u_32_t start, end; 291145516Sdarrenr pptp_hdr_t *hdr; 292145516Sdarrenr tcphdr_t *tcp; 293145516Sdarrenr int dlen, off; 294145516Sdarrenr u_short len; 295145516Sdarrenr char *msg; 296145516Sdarrenr 297145516Sdarrenr tcp = fin->fin_dp; 298145516Sdarrenr dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); 299145516Sdarrenr start = ntohl(tcp->th_seq); 300145516Sdarrenr pptps = &pptp->pptp_side[rev]; 301145516Sdarrenr off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) + 302145516Sdarrenr fin->fin_ipoff; 303145516Sdarrenr 304145516Sdarrenr if (dlen <= 0) 305145516Sdarrenr return 0; 306145516Sdarrenr /* 307145516Sdarrenr * If the complete data packet is before what we expect to see 308145516Sdarrenr * "next", just ignore it as the chances are we've already seen it. 309145516Sdarrenr * The next if statement following this one really just causes packets 310145516Sdarrenr * ahead of what we've seen to be dropped, implying that something in 311145516Sdarrenr * the middle went missing and we want to see that first. 312145516Sdarrenr */ 313145516Sdarrenr end = start + dlen; 314145516Sdarrenr if (pptps->pptps_next > end && pptps->pptps_next > start) 315145516Sdarrenr return 0; 316145516Sdarrenr 317145516Sdarrenr if (pptps->pptps_next != start) { 318255332Scy if (ipf_p_pptp_debug > 5) 319145516Sdarrenr printf("%s: next (%x) != start (%x)\n", funcname, 320145516Sdarrenr pptps->pptps_next, start); 321145516Sdarrenr return -1; 322145516Sdarrenr } 323145516Sdarrenr 324145516Sdarrenr msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2); 325145516Sdarrenr 326145516Sdarrenr while (dlen > 0) { 327145516Sdarrenr off += pptps->pptps_bytes; 328145516Sdarrenr if (pptps->pptps_gothdr == 0) { 329145516Sdarrenr /* 330145516Sdarrenr * PPTP has an 8 byte header that inclues the cookie. 331145516Sdarrenr * The start of every message should include one and 332145516Sdarrenr * it should match 1a2b3c4d. Byte order is ignored, 333145516Sdarrenr * deliberately, when printing out the error. 334145516Sdarrenr */ 335145516Sdarrenr len = MIN(8 - 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 hdr = (pptp_hdr_t *)pptps->pptps_buffer; 340145516Sdarrenr if (pptps->pptps_bytes == 8) { 341145516Sdarrenr pptps->pptps_next += 8; 342145516Sdarrenr if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) { 343255332Scy if (ipf_p_pptp_debug > 1) 344145516Sdarrenr printf("%s: bad cookie (%x)\n", 345145516Sdarrenr funcname, 346145516Sdarrenr hdr->pptph_cookie); 347145516Sdarrenr return -1; 348145516Sdarrenr } 349145516Sdarrenr } 350145516Sdarrenr dlen -= len; 351145516Sdarrenr msg += len; 352145516Sdarrenr off += len; 353145516Sdarrenr 354145516Sdarrenr pptps->pptps_gothdr = 1; 355145516Sdarrenr len = ntohs(hdr->pptph_len); 356145516Sdarrenr pptps->pptps_len = len; 357145516Sdarrenr pptps->pptps_nexthdr += len; 358145516Sdarrenr 359145516Sdarrenr /* 360145516Sdarrenr * If a message is too big for the buffer, just set 361145516Sdarrenr * the fields for the next message to come along. 362145516Sdarrenr * The messages defined in RFC 2637 will not exceed 363145516Sdarrenr * 512 bytes (in total length) so this is likely a 364145516Sdarrenr * bad data packet, anyway. 365145516Sdarrenr */ 366145516Sdarrenr if (len > sizeof(pptps->pptps_buffer)) { 367255332Scy if (ipf_p_pptp_debug > 3) 368145516Sdarrenr printf("%s: message too big (%d)\n", 369145516Sdarrenr funcname, len); 370145516Sdarrenr pptps->pptps_next = pptps->pptps_nexthdr; 371145516Sdarrenr pptps->pptps_wptr = pptps->pptps_buffer; 372145516Sdarrenr pptps->pptps_gothdr = 0; 373145516Sdarrenr pptps->pptps_bytes = 0; 374145516Sdarrenr pptps->pptps_len = 0; 375145516Sdarrenr break; 376145516Sdarrenr } 377145516Sdarrenr } 378145516Sdarrenr 379145516Sdarrenr len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen); 380145516Sdarrenr COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); 381145516Sdarrenr pptps->pptps_bytes += len; 382145516Sdarrenr pptps->pptps_wptr += len; 383145516Sdarrenr pptps->pptps_next += len; 384145516Sdarrenr 385145516Sdarrenr if (pptps->pptps_len > pptps->pptps_bytes) 386145516Sdarrenr break; 387145516Sdarrenr 388255332Scy ipf_p_pptp_message(fin, nat, pptp, pptps); 389145516Sdarrenr pptps->pptps_wptr = pptps->pptps_buffer; 390145516Sdarrenr pptps->pptps_gothdr = 0; 391145516Sdarrenr pptps->pptps_bytes = 0; 392145516Sdarrenr pptps->pptps_len = 0; 393145516Sdarrenr 394145516Sdarrenr start += len; 395145516Sdarrenr msg += len; 396145516Sdarrenr dlen -= len; 397145516Sdarrenr } 398145516Sdarrenr 399145516Sdarrenr return 0; 400145516Sdarrenr} 401145516Sdarrenr 402145516Sdarrenr 403145516Sdarrenr/* 404145516Sdarrenr * handle a complete PPTP message 405145516Sdarrenr */ 406255332Scyint 407255332Scyipf_p_pptp_message(fin, nat, pptp, pptps) 408255332Scy fr_info_t *fin; 409255332Scy nat_t *nat; 410255332Scy pptp_pxy_t *pptp; 411255332Scy pptp_side_t *pptps; 412145516Sdarrenr{ 413145516Sdarrenr pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer; 414145516Sdarrenr 415145516Sdarrenr switch (ntohs(hdr->pptph_type)) 416145516Sdarrenr { 417145516Sdarrenr case PPTP_MSGTYPE_CTL : 418255332Scy ipf_p_pptp_mctl(fin, nat, pptp, pptps); 419145516Sdarrenr break; 420145516Sdarrenr 421145516Sdarrenr default : 422145516Sdarrenr break; 423145516Sdarrenr } 424145516Sdarrenr return 0; 425145516Sdarrenr} 426145516Sdarrenr 427145516Sdarrenr 428145516Sdarrenr/* 429145516Sdarrenr * handle a complete PPTP control message 430145516Sdarrenr */ 431255332Scyint 432255332Scyipf_p_pptp_mctl(fin, nat, pptp, pptps) 433255332Scy fr_info_t *fin; 434255332Scy nat_t *nat; 435255332Scy pptp_pxy_t *pptp; 436255332Scy pptp_side_t *pptps; 437145516Sdarrenr{ 438145516Sdarrenr u_short *buffer = (u_short *)(pptps->pptps_buffer); 439145516Sdarrenr pptp_side_t *pptpo; 440145516Sdarrenr 441145516Sdarrenr if (pptps == &pptp->pptp_side[0]) 442145516Sdarrenr pptpo = &pptp->pptp_side[1]; 443145516Sdarrenr else 444145516Sdarrenr pptpo = &pptp->pptp_side[0]; 445145516Sdarrenr 446145516Sdarrenr /* 447145516Sdarrenr * Breakout to handle all the various messages. Most are just state 448145516Sdarrenr * transition. 449145516Sdarrenr */ 450145516Sdarrenr switch (ntohs(buffer[4])) 451145516Sdarrenr { 452145516Sdarrenr case PPTP_MTCTL_STARTREQ : 453145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STARTREQ; 454145516Sdarrenr break; 455145516Sdarrenr case PPTP_MTCTL_STARTREP : 456145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ) 457145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STARTREP; 458145516Sdarrenr break; 459145516Sdarrenr case PPTP_MTCTL_STOPREQ : 460145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STOPREQ; 461145516Sdarrenr break; 462145516Sdarrenr case PPTP_MTCTL_STOPREP : 463145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ) 464145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_STOPREP; 465145516Sdarrenr break; 466145516Sdarrenr case PPTP_MTCTL_ECHOREQ : 467145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_ECHOREQ; 468145516Sdarrenr break; 469145516Sdarrenr case PPTP_MTCTL_ECHOREP : 470145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ) 471145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_ECHOREP; 472145516Sdarrenr break; 473145516Sdarrenr case PPTP_MTCTL_OUTREQ : 474145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_OUTREQ; 475145516Sdarrenr break; 476145516Sdarrenr case PPTP_MTCTL_OUTREP : 477145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) { 478145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_OUTREP; 479145516Sdarrenr pptp->pptp_call[0] = buffer[7]; 480145516Sdarrenr pptp->pptp_call[1] = buffer[6]; 481255332Scy ipf_p_pptp_donatstate(fin, nat, pptp); 482145516Sdarrenr } 483145516Sdarrenr break; 484145516Sdarrenr case PPTP_MTCTL_INREQ : 485145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_INREQ; 486145516Sdarrenr break; 487145516Sdarrenr case PPTP_MTCTL_INREP : 488145516Sdarrenr if (pptpo->pptps_state == PPTP_MTCTL_INREQ) { 489145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_INREP; 490145516Sdarrenr pptp->pptp_call[0] = buffer[7]; 491145516Sdarrenr pptp->pptp_call[1] = buffer[6]; 492255332Scy ipf_p_pptp_donatstate(fin, nat, pptp); 493145516Sdarrenr } 494145516Sdarrenr break; 495145516Sdarrenr case PPTP_MTCTL_INCONNECT : 496145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_INCONNECT; 497145516Sdarrenr break; 498145516Sdarrenr case PPTP_MTCTL_CLEAR : 499145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_CLEAR; 500145516Sdarrenr break; 501145516Sdarrenr case PPTP_MTCTL_DISCONNECT : 502145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_DISCONNECT; 503145516Sdarrenr break; 504145516Sdarrenr case PPTP_MTCTL_WANERROR : 505145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_WANERROR; 506145516Sdarrenr break; 507145516Sdarrenr case PPTP_MTCTL_LINKINFO : 508145516Sdarrenr pptps->pptps_state = PPTP_MTCTL_LINKINFO; 509145516Sdarrenr break; 510145516Sdarrenr } 511145516Sdarrenr 512145516Sdarrenr return 0; 513145516Sdarrenr} 514145516Sdarrenr 515145516Sdarrenr 516145516Sdarrenr/* 517145516Sdarrenr * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if 518145516Sdarrenr * we can. If they have disappeared, recreate them. 519145516Sdarrenr */ 520255332Scyint 521255332Scyipf_p_pptp_inout(arg, fin, aps, nat) 522255332Scy void *arg; 523255332Scy fr_info_t *fin; 524255332Scy ap_session_t *aps; 525255332Scy nat_t *nat; 526145516Sdarrenr{ 527145516Sdarrenr pptp_pxy_t *pptp; 528145516Sdarrenr tcphdr_t *tcp; 529145516Sdarrenr int rev; 530145516Sdarrenr 531145516Sdarrenr if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) 532145516Sdarrenr rev = 1; 533145516Sdarrenr else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) 534145516Sdarrenr rev = 1; 535145516Sdarrenr else 536145516Sdarrenr rev = 0; 537145516Sdarrenr 538145516Sdarrenr tcp = (tcphdr_t *)fin->fin_dp; 539145516Sdarrenr if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 540145516Sdarrenr pptp = (pptp_pxy_t *)aps->aps_data; 541145516Sdarrenr pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack); 542145516Sdarrenr pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack); 543145516Sdarrenr pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1; 544145516Sdarrenr pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1; 545145516Sdarrenr } 546255332Scy return ipf_p_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data, 547145516Sdarrenr rev); 548145516Sdarrenr} 549145516Sdarrenr 550145516Sdarrenr 551145516Sdarrenr/* 552145516Sdarrenr * clean up after ourselves. 553145516Sdarrenr */ 554255332Scyvoid 555255332Scyipf_p_pptp_del(softc, aps) 556255332Scy ipf_main_softc_t *softc; 557255332Scy ap_session_t *aps; 558145516Sdarrenr{ 559145516Sdarrenr pptp_pxy_t *pptp; 560145516Sdarrenr 561145516Sdarrenr pptp = aps->aps_data; 562145516Sdarrenr 563145516Sdarrenr if (pptp != NULL) { 564145516Sdarrenr /* 565145516Sdarrenr * Don't bother changing any of the NAT structure details, 566145516Sdarrenr * *_del() is on a callback from aps_free(), from nat_delete() 567145516Sdarrenr */ 568145516Sdarrenr 569255332Scy READ_ENTER(&softc->ipf_state); 570145516Sdarrenr if (pptp->pptp_state != NULL) { 571255332Scy ipf_state_setpending(softc, pptp->pptp_state); 572145516Sdarrenr } 573255332Scy RWLOCK_EXIT(&softc->ipf_state); 574145516Sdarrenr 575255332Scy if (pptp->pptp_nat != NULL) 576255332Scy ipf_nat_setpending(softc, pptp->pptp_nat); 577255332Scy pptp->pptp_rule->in_flags |= IPN_DELETE; 578255332Scy ipf_nat_rule_deref(softc, &pptp->pptp_rule); 579145516Sdarrenr } 580145516Sdarrenr} 581