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