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