/* track caller id inside control connection, call expect_related */ static int conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { int dir = CTINFO2DIR(ctinfo); const struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; const struct tcphdr *tcph; struct tcphdr _tcph; const struct pptp_pkt_hdr *pptph; struct pptp_pkt_hdr _pptph; struct PptpControlHeader _ctlh, *ctlh; union pptp_ctrl_union _pptpReq, *pptpReq; unsigned int tcplen = skb->len - protoff; unsigned int datalen, reqlen, nexthdr_off; int oldsstate, oldcstate; int ret; u_int16_t msg; /* don't do any tracking before tcp handshake complete */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY) return NF_ACCEPT; nexthdr_off = protoff; tcph = skb_header_pointer(skb, nexthdr_off, sizeof(_tcph), &_tcph); BUG_ON(!tcph); nexthdr_off += tcph->doff * 4; datalen = tcplen - tcph->doff * 4; pptph = skb_header_pointer(skb, nexthdr_off, sizeof(_pptph), &_pptph); if (!pptph) { pr_debug("no full PPTP header, can't track\n"); return NF_ACCEPT; } nexthdr_off += sizeof(_pptph); datalen -= sizeof(_pptph); /* if it's not a control message we can't do anything with it */ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { pr_debug("not a control packet\n"); return NF_ACCEPT; } ctlh = skb_header_pointer(skb, nexthdr_off, sizeof(_ctlh), &_ctlh); if (!ctlh) return NF_ACCEPT; nexthdr_off += sizeof(_ctlh); datalen -= sizeof(_ctlh); reqlen = datalen; msg = ntohs(ctlh->messageType); if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg]) return NF_ACCEPT; if (reqlen > sizeof(*pptpReq)) reqlen = sizeof(*pptpReq); pptpReq = skb_header_pointer(skb, nexthdr_off, reqlen, &_pptpReq); if (!pptpReq) return NF_ACCEPT; oldsstate = info->sstate; oldcstate = info->cstate; spin_lock_bh(&nf_pptp_lock); /* FIXME: We just blindly assume that the control connection is always * established from PNS->PAC. However, RFC makes no guarantee */ if (dir == IP_CT_DIR_ORIGINAL) /* client -> server (PNS -> PAC) */ ret = pptp_outbound_pkt(skb, ctlh, pptpReq, reqlen, ct, ctinfo); else /* server -> client (PAC -> PNS) */ ret = pptp_inbound_pkt(skb, ctlh, pptpReq, reqlen, ct, ctinfo); pr_debug("sstate: %d->%d, cstate: %d->%d\n", oldsstate, info->sstate, oldcstate, info->cstate); spin_unlock_bh(&nf_pptp_lock); return ret; }
/* track caller id inside control connection, call expect_related */ static int conntrack_pptp_help(const struct iphdr *iph, size_t len, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct pptp_pkt_hdr *pptph; struct tcphdr *tcph = (void *) iph + iph->ihl * 4; u_int32_t tcplen = len - iph->ihl * 4; u_int32_t datalen = tcplen - tcph->doff * 4; void *datalimit; int dir = CTINFO2DIR(ctinfo); struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; int oldsstate, oldcstate; int ret; #ifdef CONFIG_IFX_ALG_QOS // chandrav /* * Mark the connection tracket with PPTP ALG Family type * ( IFX_ALG_APP_PPTP) for PPTP traffic. */ ct->ifx_alg_qos_mark = IFX_ALG_APP_PPTP; IFX_ALG_QOS_DBG("\nPPTP_ALG helper marked ct->ifx_alg_qos_mark to : %x ***\n",ct->ifx_alg_qos_mark ); #endif /* CONFIG_IFX_ALG_QOS */ /* don't do any tracking before tcp handshake complete */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { DEBUGP("ctinfo = %u, skipping\n", ctinfo); return NF_ACCEPT; } /* not a complete TCP header? */ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { DEBUGP("tcplen = %u\n", tcplen); return NF_ACCEPT; } /* checksum invalid? */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *) tcph, tcplen, 0))) { DEBUGP("TC Test0\n"); printk(KERN_NOTICE __FILE__ ": bad csum\n"); /* W2K PPTP server sends TCP packets with wrong checksum :(( */ //return NF_ACCEPT; } DEBUGP("TC Test1\n"); if (tcph->fin || tcph->rst) { DEBUGP("RST/FIN received, timeouting GRE\n"); /* can't do this after real newnat */ info->cstate = PPTP_CALL_NONE; /* untrack this call id, unexpect GRE packets */ pptp_timeout_related(ct); } DEBUGP("TC Test2\n"); pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); datalimit = (void *) pptph + datalen; /* not a full pptp packet header? */ if ((void *) pptph+sizeof(*pptph) >= datalimit) { DEBUGP("no full PPTP header, can't track\n"); return NF_ACCEPT; } /* if it's not a control message we can't do anything with it */ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { DEBUGP("not a control packet\n"); return NF_ACCEPT; } DEBUGP("TC Test3\n"); oldsstate = info->sstate; oldcstate = info->cstate; LOCK_BH(&ip_pptp_lock); /* FIXME: We just blindly assume that the control connection is always * established from PNS->PAC. However, RFC makes no guarantee */ if (dir == IP_CT_DIR_ORIGINAL) /* client -> server (PNS -> PAC) */ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); else /* server -> client (PAC -> PNS) */ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); DEBUGP("sstate: %d->%d, cstate: %d->%d\n", oldsstate, info->sstate, oldcstate, info->cstate); UNLOCK_BH(&ip_pptp_lock); return ret; }