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