static inline int pptp_inbound_pkt(struct sk_buff *skb, struct PptpControlHeader *ctlh, union pptp_ctrl_union *pptpReq, unsigned int reqlen, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info; u_int16_t msg; __be16 cid = 0, pcid = 0; typeof(nf_nat_pptp_hook_inbound) nf_nat_pptp_inbound; msg = ntohs(ctlh->messageType); pr_debug("inbound control message %s\n", pptp_msg_name[msg]); switch (msg) { case PPTP_START_SESSION_REPLY: /* server confirms new control session */ if (info->sstate < PPTP_SESSION_REQUESTED) goto invalid; if (pptpReq->srep.resultCode == PPTP_START_OK) info->sstate = PPTP_SESSION_CONFIRMED; else info->sstate = PPTP_SESSION_ERROR; break; case PPTP_STOP_SESSION_REPLY: /* server confirms end of control session */ if (info->sstate > PPTP_SESSION_STOPREQ) goto invalid; if (pptpReq->strep.resultCode == PPTP_STOP_OK) info->sstate = PPTP_SESSION_NONE; else info->sstate = PPTP_SESSION_ERROR; break; case PPTP_OUT_CALL_REPLY: /* server accepted call, we now expect GRE frames */ if (info->sstate != PPTP_SESSION_CONFIRMED) goto invalid; if (info->cstate != PPTP_CALL_OUT_REQ && info->cstate != PPTP_CALL_OUT_CONF) goto invalid; cid = pptpReq->ocack.callID; pcid = pptpReq->ocack.peersCallID; if (info->pns_call_id != pcid) goto invalid; pr_debug("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], ntohs(cid), ntohs(pcid)); if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) { info->cstate = PPTP_CALL_OUT_CONF; info->pac_call_id = cid; exp_gre(ct, cid, pcid); } else info->cstate = PPTP_CALL_NONE; break; case PPTP_IN_CALL_REQUEST: /* server tells us about incoming call request */ if (info->sstate != PPTP_SESSION_CONFIRMED) goto invalid; cid = pptpReq->icreq.callID; pr_debug("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); info->cstate = PPTP_CALL_IN_REQ; info->pac_call_id = cid; break; case PPTP_IN_CALL_CONNECT: /* server tells us about incoming call established */ if (info->sstate != PPTP_SESSION_CONFIRMED) goto invalid; if (info->cstate != PPTP_CALL_IN_REP && info->cstate != PPTP_CALL_IN_CONF) goto invalid; pcid = pptpReq->iccon.peersCallID; cid = info->pac_call_id; if (info->pns_call_id != pcid) goto invalid; pr_debug("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid)); info->cstate = PPTP_CALL_IN_CONF; /* we expect a GRE connection from PAC to PNS */ exp_gre(ct, cid, pcid); break; case PPTP_CALL_DISCONNECT_NOTIFY: /* server confirms disconnect */ cid = pptpReq->disc.callID; pr_debug("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); info->cstate = PPTP_CALL_NONE; /* untrack this call id, unexpect GRE packets */ pptp_destroy_siblings(ct); break; case PPTP_WAN_ERROR_NOTIFY: case PPTP_ECHO_REQUEST: case PPTP_ECHO_REPLY: /* I don't have to explain these ;) */ break; default: goto invalid; } nf_nat_pptp_inbound = rcu_dereference(nf_nat_pptp_hook_inbound); if (nf_nat_pptp_inbound && ct->status & IPS_NAT_MASK) return nf_nat_pptp_inbound(skb, ct, ctinfo, ctlh, pptpReq); return NF_ACCEPT; invalid: pr_debug("invalid %s: type=%d cid=%u pcid=%u " "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, ntohs(info->pns_call_id), ntohs(info->pac_call_id)); return NF_ACCEPT; }
static inline int pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, size_t datalen, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct PptpControlHeader *ctlh; union pptp_ctrl_union pptpReq; struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; u_int16_t msg, *cid, *pcid; u_int32_t seq; ctlh = (struct PptpControlHeader *) ((char *) pptph + sizeof(struct pptp_pkt_hdr)); pptpReq.rawreq = (void *) ((char *) ctlh + sizeof(struct PptpControlHeader)); msg = ntohs(ctlh->messageType); DEBUGP("inbound control message %s\n", strMName[msg]); switch (msg) { case PPTP_START_SESSION_REPLY: /* server confirms new control session */ if (info->sstate < PPTP_SESSION_REQUESTED) { DEBUGP("%s without START_SESS_REQUEST\n", strMName[msg]); break; } if (pptpReq.srep->resultCode == PPTP_START_OK) info->sstate = PPTP_SESSION_CONFIRMED; else info->sstate = PPTP_SESSION_ERROR; break; case PPTP_STOP_SESSION_REPLY: /* server confirms end of control session */ if (info->sstate > PPTP_SESSION_STOPREQ) { DEBUGP("%s without STOP_SESS_REQUEST\n", strMName[msg]); break; } if (pptpReq.strep->resultCode == PPTP_STOP_OK) info->sstate = PPTP_SESSION_NONE; else info->sstate = PPTP_SESSION_ERROR; break; case PPTP_OUT_CALL_REPLY: /* server accepted call, we now expect GRE frames */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", strMName[msg]); break; } if (info->cstate != PPTP_CALL_OUT_REQ && info->cstate != PPTP_CALL_OUT_CONF) { DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]); break; } if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) { info->cstate = PPTP_CALL_NONE; break; } cid = &pptpReq.ocack->callID; pcid = &pptpReq.ocack->peersCallID; info->pac_call_id = ntohs(*cid); if (htons(info->pns_call_id) != *pcid) { DEBUGP("%s for unknown callid %u\n", strMName[msg], ntohs(*pcid)); break; } DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], ntohs(*cid), ntohs(*pcid)); info->cstate = PPTP_CALL_OUT_CONF; seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); if (exp_gre(ct, seq, *cid, *pcid) != 0) printk("ip_conntrack_pptp: error during exp_gre\n"); break; case PPTP_IN_CALL_REQUEST: /* server tells us about incoming call request */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", strMName[msg]); break; } pcid = &pptpReq.icack->peersCallID; DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); info->cstate = PPTP_CALL_IN_REQ; info->pac_call_id= ntohs(*pcid); break; case PPTP_IN_CALL_CONNECT: /* server tells us about incoming call established */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", strMName[msg]); break; } if (info->sstate != PPTP_CALL_IN_REP && info->sstate != PPTP_CALL_IN_CONF) { DEBUGP("%s but never sent IN_CALL_REPLY\n", strMName[msg]); break; } pcid = &pptpReq.iccon->peersCallID; cid = &info->pac_call_id; if (info->pns_call_id != ntohs(*pcid)) { DEBUGP("%s for unknown CallID %u\n", strMName[msg], ntohs(*cid)); break; } DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); info->cstate = PPTP_CALL_IN_CONF; /* we expect a GRE connection from PAC to PNS */ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); if (exp_gre(ct, seq, *cid, *pcid) != 0) printk("ip_conntrack_pptp: error during exp_gre\n"); break; case PPTP_CALL_DISCONNECT_NOTIFY: /* server confirms disconnect */ cid = &pptpReq.disc->callID; DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); info->cstate = PPTP_CALL_NONE; /* untrack this call id, unexpect GRE packets */ pptp_timeout_related(ct); break; case PPTP_WAN_ERROR_NOTIFY: break; case PPTP_ECHO_REQUEST: case PPTP_ECHO_REPLY: /* I don't have to explain these ;) */ break; default: DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) ? strMName[msg]:strMName[0], msg); break; } return NF_ACCEPT; }