On 13:34:22 Nov 22, Stuart Henderson wrote: > it must look at the control message on TCP/1723 and translate CallID;
Modulate, not translate. :) My terminology. I am using arc4random() to generate unique callIDs that do not clash. The callID is always set to zero by PPTP , hence this requirement. ( No more comments about M$ stuff :) > then it must look at the session packets (GRE/proto 47) and translate > CallID the same way. Yes and maintain a mapping. This is far more difficult than it first appears. You can see the diff for what all needs to be done. > > the parts handling control messages probably belong in userland and > they can add translation rules to an anchor like ftp-proxy does, but > that would need a change to PF so that you can tell it to translate > CallID for GRE packets (like you can tell it to translate port for > TCP/UDP). > > http://blogs.isaserver.org/pouseele/2007/06/17/multiple-pptp-vpn-clients-behind-a-nat-device/ I think though it takes a lot of clever programming and even smarter design, I have a problem with maintaining the table in kernel. I got it working perfectly a long time ago ( roughly a year ago) and I can send the working diff right away if you want. I am sure Henning is not going to like it. :) Whether it is small or not is a matter of taste but if I were to do it correctly I will do it the proxy rdr way. The problem however with that approach is that there is a huge overhead in passing packets between kernel to userland and back. Here is the diff attached. If you like it commit it. :) And bear in mind that I developed it against old code, so you might have to do some tweaks. If not I am more than willing to do it the right way. Let me know your choice. regards, Girish Index: pfvar.h =================================================================== RCS file: /cvs/src/sys/net/pfvar.h,v retrieving revision 1.242 diff -c -r1.242 pfvar.h *** pfvar.h 13 Dec 2006 05:10:15 -0000 1.242 --- pfvar.h 12 Mar 2007 09:18:49 -0000 *************** *** 2,7 **** --- 2,8 ---- /* * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2007 Girish Venkatachalam * All rights reserved. * * Redistribution and use in source and binary forms, with or without *************** *** 936,941 **** --- 937,943 ---- struct tcphdr *tcp; struct udphdr *udp; struct icmp *icmp; + struct gre_h *gre; #ifdef INET6 struct icmp6_hdr *icmp6; #endif /* INET6 */ *************** *** 958,963 **** --- 960,970 ---- sa_family_t af; u_int8_t proto; u_int8_t tos; + u_int16_t mycallid; /* PPTP lan call id */ + u_int16_t peercallid; /* PPTP remote call id */ + struct pfpptp_head *pptph; + + }; /* flags for RDR options */ *************** *** 1351,1356 **** --- 1358,1372 ---- int pfiio_size; int pfiio_nzero; int pfiio_flags; + }; + + + enum { PF_PPTP_MYID, PF_PPTP_PEERID }; + + struct pfpptp_call { + SLIST_ENTRY(pfpptp_call) next_call; + u_int16_t myid; + u_int16_t peerid; }; Index: pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.523 diff -c -r1.523 pf.c *** pf.c 22 Dec 2006 13:24:52 -0000 1.523 --- pf.c 12 Mar 2007 09:18:01 -0000 *************** *** 3,8 **** --- 3,9 ---- /* * Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2002,2003 Henning Brauer + * Copyright (c) 2007, Girish Venkatachalam * All rights reserved. * * Redistribution and use in source and binary forms, with or without *************** *** 72,77 **** --- 73,79 ---- #include <netinet/icmp_var.h> #include <netinet/if_ether.h> + #include <net/if_gre.h> #include <dev/rndvar.h> #include <net/pfvar.h> #include <net/if_pflog.h> *************** *** 105,110 **** --- 107,114 ---- int altqs_inactive_open; u_int32_t ticket_pabuf; + SLIST_HEAD(pfpptp_head,pfpptp_call) pf_pptph; + struct pf_anchor_stackframe { struct pf_ruleset *rs; struct pf_rule *r; *************** *** 163,168 **** --- 167,176 ---- int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **, struct ifqueue *); + int pf_test_gre_pptp(struct pf_rule **, struct pf_state **, + int , struct pfi_kif *, struct mbuf *, int, + void *, struct pf_pdesc *, struct pf_rule **, + struct pf_ruleset **, struct ifqueue *); int pf_test_other(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, *************** *** 180,185 **** --- 188,196 ---- int pf_test_state_icmp(struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, u_short *); + int pf_test_state_gre_pptp(struct pf_state **, + struct mbuf *,int, int, + struct pfi_kif *, struct pf_pdesc *pd); int pf_test_state_other(struct pf_state **, int, struct pfi_kif *, struct pf_pdesc *); int pf_match_tag(struct mbuf *, struct pf_rule *, *************** *** 219,224 **** --- 230,241 ---- struct pf_state_cmp *, u_int8_t); int pf_src_connlimit(struct pf_state **); int pf_check_congestion(struct ifqueue *); + int pf_test(int dir, struct ifnet *ifp, + struct mbuf **m0, struct ether_header *eh); + int pf_delete_pptp_node(struct pf_pdesc *,u_int16_t ,int) ; + u_int16_t pf_find_pptp_id(struct pf_pdesc *,u_int16_t,int ); + int pf_append_pptp_node(struct pf_pdesc *,u_int16_t,u_int16_t); + void pf_clear_pptp_state(struct pf_pdesc *) ; extern struct pool pfr_ktable_pl; extern struct pool pfr_kentry_pl; *************** *** 496,502 **** return (0); } - #ifdef INET6 void pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) { --- 513,518 ---- *************** *** 506,511 **** --- 522,528 ---- dst->addr32[0] = src->addr32[0]; break; #endif /* INET */ + #ifdef INET6 case AF_INET6: dst->addr32[0] = src->addr32[0]; dst->addr32[1] = src->addr32[1]; *************** *** 946,951 **** --- 963,969 ---- rw_exit_write(&pf_consistency_lock); } + void pf_src_tree_remove_state(struct pf_state *s) { *************** *** 1183,1188 **** --- 1201,1209 ---- case IPPROTO_ICMP: printf("ICMP "); break; + case IPPROTO_GRE: + printf("GRE "); + break; case IPPROTO_ICMPV6: printf("ICMPV6 "); break; *************** *** 2273,2280 **** int pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, ! struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, ! struct pf_src_node **sn) { struct pf_state_cmp key; struct pf_addr init_addr; --- 2294,2301 ---- int pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, ! struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, ! u_int16_t high, struct pf_src_node **sn) { struct pf_state_cmp key; struct pf_addr init_addr; *************** *** 2301,2307 **** * similar 2 portloop in in_pcbbind */ if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || ! proto == IPPROTO_ICMP)) { key.gwy.port = dport; if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) return (0); --- 2322,2328 ---- * similar 2 portloop in in_pcbbind */ if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || ! proto == IPPROTO_ICMP )) { key.gwy.port = dport; if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) return (0); *************** *** 2839,2850 **** --- 2860,2873 ---- struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; + int rewrite = 0; int tag = -1, rtableid = -1; u_int16_t mss = tcp_mssdflt; int asd = 0; int match = 0; + if (pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); *************** *** 3079,3084 **** --- 3102,3108 ---- PF_ACPY(&s->lan.addr, &s->gwy.addr, af); s->lan.port = s->gwy.port; } + } else { PF_ACPY(&s->lan.addr, daddr, af); s->lan.port = th->th_dport; *************** *** 3091,3096 **** --- 3115,3122 ---- PF_ACPY(&s->gwy.addr, &s->lan.addr, af); s->gwy.port = s->lan.port; } + + } s->src.seqlo = ntohl(th->th_seq); *************** *** 3800,3805 **** --- 3826,4089 ---- } int + pf_test_gre_pptp(struct pf_rule **rm, struct pf_state **sm, int direction, + struct pfi_kif *kif, struct mbuf *m, int off, void *h, + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct ifqueue *ifq) + { + struct pf_rule *nr = NULL; + struct pf_addr *saddr = pd->src, *daddr = pd->dst; + u_int16_t dport,sport, nport = 0; + sa_family_t af = pd->af; + struct pf_rule *r, *a = NULL; + struct pf_ruleset *ruleset = NULL; + struct pf_src_node *nsn = NULL; + u_short reason; + int rewrite = 0; + int tag = -1, rtableid = -1; + int asd = 0; + int match = 0; + + if (pf_check_congestion(ifq)) { + REASON_SET(&reason, PFRES_CONGEST); + return (PF_DROP); + } + + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); + + if (direction == PF_OUT) { + dport = pd->hdr.gre->callid; + nport = pd->mycallid; + /* check outgoing packet for BINAT/NAT */ + if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, + saddr, pd->mycallid, daddr, dport, + &pd->naddr, &nport)) != NULL) { + PF_ACPY(&pd->baddr, saddr, af); + + pf_change_a(&saddr->v4.s_addr, pd->ip_sum, + pd->naddr.v4.s_addr,0); + rewrite++; + if (nr->natpass) + r = NULL; + pd->nat_rule = nr; + } + } else { + sport = pd->peercallid; + nport = pd->hdr.gre->callid; + /* check incoming packet for BINAT/RDR */ + if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, + saddr, sport, daddr, pd->hdr.gre->callid, &pd->naddr, + &nport)) != NULL) { + PF_ACPY(&pd->baddr, daddr, af); + pf_change_a(&daddr->v4.s_addr, pd->ip_sum, + pd->naddr.v4.s_addr, 0); + rewrite++; + if (nr->natpass) + r = NULL; + pd->nat_rule = nr; + } + } + + while (r != NULL) { + r->evaluations++; + if (pfi_kif_match(r->kif, kif) == r->ifnot) + r = r->skip[PF_SKIP_IFP].ptr; + else if (r->direction && r->direction != direction) + r = r->skip[PF_SKIP_DIR].ptr; + else if (r->af && r->af != af) + r = r->skip[PF_SKIP_AF].ptr; + else if (r->proto && r->proto != pd->proto) + r = r->skip[PF_SKIP_PROTO].ptr; + else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, + r->src.neg, kif)) + r = r->skip[PF_SKIP_SRC_ADDR].ptr; + else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, + r->dst.neg, NULL)) + r = r->skip[PF_SKIP_DST_ADDR].ptr; + else if (r->tos && !(r->tos == pd->tos)) + r = TAILQ_NEXT(r, entries); + else if (r->rule_flag & PFRULE_FRAGMENT) + r = TAILQ_NEXT(r, entries); + else if (r->prob && r->prob <= arc4random()) + r = TAILQ_NEXT(r, entries); + else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) + r = TAILQ_NEXT(r, entries); + else if (r->os_fingerprint != PF_OSFP_ANY) + r = TAILQ_NEXT(r, entries); + else { + if (r->tag) + tag = r->tag; + if (r->rtableid >= 0) + rtableid = r->rtableid; + if (r->anchor == NULL) { + match = 1; + *rm = r; + *am = a; + *rsm = ruleset; + if ((*rm)->quick) + break; + r = TAILQ_NEXT(r, entries); + } else + pf_step_into_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a, &match); + } + if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, + PF_RULESET_FILTER, &r, &a, &match)) + break; + } + + r = *rm; + a = *am; + ruleset = *rsm; + + REASON_SET(&reason, PFRES_MATCH); + + + if ((r->action == PF_DROP) && + ((r->rule_flag & PFRULE_RETURNICMP) || + (r->rule_flag & PFRULE_RETURN))) { + /* undo NAT changes, if they have taken place */ + if (nr != NULL) { + if (direction == PF_OUT) { + pf_change_a(&saddr->v4.s_addr, pd->ip_sum, + pd->baddr.v4.s_addr, 0); + rewrite++; + } else { + pf_change_a(&daddr->v4.s_addr,pd->ip_sum, + pd->baddr.v4.s_addr,0); + rewrite++; + } + } + if ((af == AF_INET) && r->return_icmp) + pf_send_icmp(m, r->return_icmp >> 8, + r->return_icmp & 255, af, r); + else if ((af == AF_INET6) && r->return_icmp6) + pf_send_icmp(m, r->return_icmp6 >> 8, + r->return_icmp6 & 255, af, r); + } + + if (r->action == PF_DROP) + return (PF_DROP); + + if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { + REASON_SET(&reason, PFRES_MEMORY); + return (PF_DROP); + } + + if (r->keep_state || nr != NULL) { + /* create new state */ + struct pf_state *s = NULL; + struct pf_src_node *sn = NULL; + + /* check maximums */ + if (r->max_states && (r->states >= r->max_states)) { + pf_status.lcounters[LCNT_STATES]++; + REASON_SET(&reason, PFRES_MAXSTATES); + goto cleanup; + } + /* src node for filter rule */ + if ((r->rule_flag & PFRULE_SRCTRACK || + r->rpool.opts & PF_POOL_STICKYADDR) && + pf_insert_src_node(&sn, r, saddr, af) != 0) { + REASON_SET(&reason, PFRES_SRCLIMIT); + goto cleanup; + } + /* src node for translation rule */ + if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && + ((direction == PF_OUT && + pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || + (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) { + REASON_SET(&reason, PFRES_SRCLIMIT); + goto cleanup; + } + s = pool_get(&pf_state_pl, PR_NOWAIT); + if (s == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + cleanup: + if (sn != NULL && sn->states == 0 && sn->expire == 0) { + RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); + pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + pf_status.src_nodes--; + pool_put(&pf_src_tree_pl, sn); + } + if (nsn != sn && nsn != NULL && nsn->states == 0 && + nsn->expire == 0) { + RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); + pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + pf_status.src_nodes--; + pool_put(&pf_src_tree_pl, nsn); + } + return (PF_DROP); + } + bzero(s, sizeof(*s)); + s->rule.ptr = r; + s->nat_rule.ptr = nr; + s->anchor.ptr = a; + STATE_INC_COUNTERS(s); + s->allow_opts = r->allow_opts; + s->log = r->log & PF_LOG_ALL; + if (nr != NULL) + s->log |= nr->log & PF_LOG_ALL; + s->proto = IPPROTO_GRE; + s->direction = direction; + s->af = af; + if (direction == PF_OUT) { + PF_ACPY(&s->gwy.addr, saddr, af); + s->gwy.port = pd->mycallid; + PF_ACPY(&s->ext.addr, daddr, af); + s->ext.port = pd->hdr.gre->callid; + if (nr != NULL) { + PF_ACPY(&s->lan.addr, &pd->baddr, af); + } else { + PF_ACPY(&s->lan.addr, &s->gwy.addr, af); + } + s->lan.port = s->gwy.port; + } else { + PF_ACPY(&s->lan.addr, daddr, af); + s->lan.port = pd->hdr.gre->callid; + PF_ACPY(&s->ext.addr, saddr, af); + s->ext.port = pd->peercallid; + if (nr != NULL) { + PF_ACPY(&s->gwy.addr, &pd->baddr, af); + } else { + PF_ACPY(&s->gwy.addr, &s->lan.addr, af); + } + s->gwy.port = s->lan.port; + } + s->src.state = PFOTHERS_SINGLE; + s->dst.state = PFOTHERS_NO_TRAFFIC; + s->creation = time_second; + s->expire = time_second; + s->timeout = PFTM_OTHER_FIRST_PACKET; + pf_set_rt_ifp(s, saddr); + if (sn != NULL) { + s->src_node = sn; + s->src_node->states++; + } + if (nsn != NULL) { + PF_ACPY(&nsn->raddr, &pd->naddr, af); + s->nat_src_node = nsn; + s->nat_src_node->states++; + } + if (pf_insert_state(BOUND_IFACE(r, kif), s)) { + REASON_SET(&reason, PFRES_STATEINS); + pf_src_tree_remove_state(s); + STATE_DEC_COUNTERS(s); + pool_put(&pf_state_pl, s); + return (PF_DROP); + } else + *sm = s; + if (tag > 0) { + pf_tag_ref(tag); + s->tag = tag; + } + } + return (PF_PASS); + } + + + + int pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) *************** *** 4161,4167 **** --- 4445,4456 ---- u_int8_t sws, dws; int ackskew; int copyback = 0; + int pptp_offset; struct pf_state_peer *src, *dst; + struct gre_pptp_h *pptp; + struct ip *ip; + struct pf_addr gwydst; + u_int16_t ocallid; key.af = pd->af; key.proto = IPPROTO_TCP; *************** *** 4170,4180 **** --- 4459,4576 ---- PF_ACPY(&key.gwy.addr, pd->dst, key.af); key.ext.port = th->th_sport; key.gwy.port = th->th_dport; + /* code added by Girish for pptp callid + * modulation + */ + if(ntohs(th->th_sport) == 1723) { + + ip = h; + pptp_offset = (th->th_off + ip->ip_hl) * 4; + pptp = (struct gre_pptp_h *)(m->m_data + +pptp_offset); + + if (ntohs(pptp->msgtype) == 1) { + + switch (ntohs(pptp->ctrltype)) { + + case 8: + /* It is Outgoing call + * Reply message + */ + ocallid = pptp->peer_callid; + pf_append_pptp_node(pd, + pptp->peer_callid, + pptp->callid); + /* + pd->mycallid = pptp->peer_callid; + pd->peercallid = pptp->callid; + */ + pptp->peer_callid = 0; + th->th_sum = pf_cksum_fixup( + th->th_sum, ocallid, + pptp->peer_callid,0); + m_copyback(m, off, sizeof(*th),th); + /* Create state for translation + * in the IN direction + */ + PF_ACPY(&gwydst,pd->dst,pd->af); + break; + case 12: + /* Call Clear request + * Remove state + */ + pf_delete_pptp_node(pd, + pptp->callid,PF_PPTP_PEERID); + break; + case 13: + /* Call Disconnect Notify recd. + * Remove state + */ + pf_delete_pptp_node(pd, + pptp->callid,PF_PPTP_PEERID); + + break; + default: + break; + + + } + } + + + } + } else { PF_ACPY(&key.lan.addr, pd->src, key.af); PF_ACPY(&key.ext.addr, pd->dst, key.af); key.lan.port = th->th_sport; key.ext.port = th->th_dport; + /* code added by Girish for pptp callid + * modulation + */ + if(ntohs(th->th_dport) == 1723) { + + pptp_offset = th->th_off * 4 + 20; + pptp = (struct gre_pptp_h *)(m->m_data + +pptp_offset); + + if( (ntohs(pptp->msgtype) == 1) ) { + switch(ntohs(pptp->ctrltype) ) { + + case 7: + /* It is Outgoing Call + * Request msg + */ + ocallid = pptp->callid; + pptp->callid = htons(arc4random()); + th->th_sum = pf_cksum_fixup(th->th_sum, + ocallid,pptp->callid,0); + m_copyback(m, off, sizeof(*th), th); + break; + case 12: + /* Call Clear request + * Remove state + */ + pf_delete_pptp_node(pd, + pptp->callid,PF_PPTP_MYID); + break; + case 13: + /* Call Disconnect Notify recd. + * Remove state + */ + pf_delete_pptp_node(pd, + pptp->callid,PF_PPTP_MYID); + + break; + + default: + break; + } + } + + + } + } STATE_LOOKUP(); *************** *** 4604,4609 **** --- 5000,5006 ---- m_copyback(m, off, sizeof(*th), th); } + return (PF_PASS); } *************** *** 5246,5251 **** --- 5643,5756 ---- } } + + int + pf_test_state_gre_pptp(struct pf_state **state,struct mbuf *m,int off,int direction, struct pfi_kif *kif, struct pf_pdesc *pd) + { + struct pf_state_peer *src, *dst; + struct pf_state_cmp key; + static int num_trans; + /*struct tcphdr *th = NULL; */ + u_int16_t callid; + + key.af = pd->af; + key.proto = pd->proto; + + callid = pd->hdr.gre->callid; + if (direction == PF_IN) { + PF_ACPY(&key.ext.addr, pd->src, key.af); + PF_ACPY(&key.gwy.addr, pd->dst, key.af); + key.ext.port = pd->peercallid; + key.gwy.port = callid; + } else { + PF_ACPY(&key.lan.addr, pd->src, key.af); + PF_ACPY(&key.ext.addr, pd->dst, key.af); + key.lan.port = pd->mycallid; + key.ext.port = callid; + } + + STATE_LOOKUP(); + + if (direction == (*state)->direction) { + src = &(*state)->src; + dst = &(*state)->dst; + } else { + src = &(*state)->dst; + dst = &(*state)->src; + } + + /* update states */ + if (src->state < PFOTHERS_SINGLE) + src->state = PFOTHERS_SINGLE; + if (dst->state == PFOTHERS_SINGLE) + dst->state = PFOTHERS_MULTIPLE; + + /* update expire time */ + (*state)->expire = time_second; + if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE) + (*state)->timeout = PFTM_OTHER_MULTIPLE; + else + (*state)->timeout = PFTM_OTHER_SINGLE; + + /* translate source/destination address, if necessary */ + if (STATE_TRANSLATE(*state)) { + if (direction == PF_OUT) + switch (pd->af) { + #ifdef INET + case AF_INET: + pf_change_a(&pd->src->v4.s_addr, + pd->ip_sum, (*state)->gwy.addr.v4.s_addr, + 0); + break; + #endif /* INET */ + #ifdef INET6 + case AF_INET6: + PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af); + break; + #endif /* INET6 */ + } + else + switch (pd->af) { + #ifdef INET + case AF_INET: + pf_change_a(&pd->dst->v4.s_addr, + pd->ip_sum, (*state)->lan.addr.v4.s_addr, + 0); + /* Change the callid back to 0 + * since we rewrote it while + * the PPTP control protocol + * was going on... + pd->hdr.gre->callid = (*state)->lan.port; + th = pd->hdr.tcp; + th->th_sum = pf_cksum_fixup( + th->th_sum, callid, + pd->hdr.gre->callid,0); + m_copyback(m, off, sizeof(*th),th); + */ + break; + #endif /* INET */ + #ifdef INET6 + case AF_INET6: + PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af); + break; + #endif /* INET6 */ + } + } + + return (PF_PASS); + } + int pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, struct pf_pdesc *pd) *************** *** 5974,5979 **** --- 6479,6487 ---- log = action != PF_PASS; goto done; } + + pd.pptph = &pf_pptph; + if (dir == PF_IN && pf_check_proto_cksum(m, off, ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) { REASON_SET(&reason, PFRES_PROTCKSUM); *************** *** 6067,6072 **** --- 6575,6616 ---- break; } + case IPPROTO_GRE: { + struct gre_h gh; + + pd.hdr.gre = &gh; + if (!pf_pull_hdr(m, off, &gh, sizeof(gh), + &action, &reason, AF_INET)) { + log = action != PF_PASS; + goto done; + } + + pd.pptph = &pf_pptph; + + if(dir == PF_IN) { + pd.mycallid = pd.hdr.gre->callid; + pd.peercallid = pf_find_pptp_id(&pd, + pd.mycallid,PF_PPTP_PEERID); + } else { + pd.peercallid = pd.hdr.gre->callid; + pd.mycallid = pf_find_pptp_id(&pd, + pd.peercallid,PF_PPTP_MYID); + } + + + action = pf_test_state_gre_pptp(&s,m, off, dir, kif, &pd); + if (action == PF_PASS) { + #if NPFSYNC + pfsync_update_state(s); + #endif /* NPFSYNC */ + r = s->rule.ptr; + a = s->anchor.ptr; + log = s->log; + } else if (s == NULL) + action = pf_test_gre_pptp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, &ipintrq); + break; + } default: action = pf_test_state_other(&s, dir, kif, &pd); if (action == PF_PASS) { *************** *** 6556,6559 **** --- 7100,7168 ---- return (1); else return (0); + } + + int pf_delete_pptp_node(struct pf_pdesc *pd,u_int16_t id,int type) { + struct pfpptp_call *tmp; + + SLIST_FOREACH(tmp,pd->pptph,next_call) { + if(type == PF_PPTP_MYID) { + if(tmp->myid == id) { + if(tmp == SLIST_FIRST(pd->pptph)) + SLIST_REMOVE_HEAD(pd->pptph,next_call); + else + SLIST_REMOVE(pd->pptph,tmp,pfpptp_call,next_call); + } + + + } else { + if(tmp->peerid == id) { + if(tmp == SLIST_FIRST(pd->pptph)) + SLIST_REMOVE_HEAD(pd->pptph,next_call); + else + SLIST_REMOVE(pd->pptph,tmp,pfpptp_call,next_call); + + } + } + } + return 0; + } + + u_int16_t pf_find_pptp_id(struct pf_pdesc *pd,u_int16_t id,int type ) { + struct pfpptp_call *tmp; + + SLIST_FOREACH(tmp,pd->pptph,next_call) { + if(type == PF_PPTP_MYID) { + if(tmp->peerid == id) + return tmp->myid; + } else { + if(tmp->myid == id) + return tmp->peerid; + } + + } + return 0; + } + + int pf_append_pptp_node(struct pf_pdesc *pd,u_int16_t myid,u_int16_t peerid) { + struct pfpptp_call *n; + n = (struct pfpptp_call *)malloc(sizeof(struct pfpptp_call),M_TEMP,M_WAITOK); + n->myid = myid; + n->peerid = peerid; + + if(SLIST_EMPTY(pd->pptph)) { + SLIST_INIT(pd->pptph); + SLIST_INSERT_HEAD(pd->pptph,n,next_call); + } + else { + SLIST_INSERT_AFTER(SLIST_FIRST(pd->pptph),n,next_call ); + } + + return 0; + + } + + void pf_clear_pptp_state(struct pf_pdesc *pd) { + while(!SLIST_EMPTY(pd->pptph)) + SLIST_REMOVE_HEAD(pd->pptph,next_call); } Index: if_gre.h =================================================================== RCS file: /cvs/src/sys/net/if_gre.h,v retrieving revision 1.10 diff -c -r1.10 if_gre.h *** if_gre.h 14 May 2005 19:24:23 -0000 1.10 --- if_gre.h 12 Mar 2007 09:18:31 -0000 *************** *** 3,8 **** --- 3,9 ---- /* * Copyright (c) 1998 The NetBSD Foundation, Inc. + * Copyright (c) 2007 Girish Venkatachalam * All rights reserved * * This code is derived from software contributed to The NetBSD Foundation *************** *** 52,62 **** --- 53,76 ---- u_char g_proto; /* protocol of encapsulator */ }; + struct gre_pptp_h { + u_int16_t len; + u_int16_t msgtype; + u_int32_t magic; + u_int16_t ctrltype; + u_int16_t res; + u_int16_t callid; + u_int16_t peer_callid; + }; + struct gre_h { u_int16_t flags; /* GRE flags */ u_int16_t ptype; /* protocol type of payload typically Ether protocol type*/ + /* These two are the key field for PPTP */ + u_int16_t len; + u_int16_t callid; /* * from here on: fields are optional, presence indicated by flags *

