📄 ip_conntrack_helper_pptp.c
字号:
} /* server accepted call, we now expect GRE frames */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", pptp_msg_name[msg]); break; } if (info->cstate != PPTP_CALL_OUT_REQ && info->cstate != PPTP_CALL_OUT_CONF) { DEBUGP("%s without OUTCALL_REQ\n", pptp_msg_name[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", pptp_msg_name[msg], ntohs(*pcid)); break; } DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], ntohs(*cid), ntohs(*pcid)); info->cstate = PPTP_CALL_OUT_CONF; seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) + sizeof(struct PptpControlHeader) + ((void *)pcid - (void *)pptpReq); if (exp_gre(ct, seq, *cid, *pcid) != 0) printk("ip_conntrack_pptp: error during exp_gre\n"); break; case PPTP_IN_CALL_REQUEST: if (reqlen < sizeof(_pptpReq.icack)) { DEBUGP("%s: short packet\n", pptp_msg_name[msg]); break; } /* server tells us about incoming call request */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", pptp_msg_name[msg]); break; } pcid = &pptpReq->icack.peersCallID; DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); info->cstate = PPTP_CALL_IN_REQ; info->pac_call_id = ntohs(*pcid); break; case PPTP_IN_CALL_CONNECT: if (reqlen < sizeof(_pptpReq.iccon)) { DEBUGP("%s: short packet\n", pptp_msg_name[msg]); break; } /* server tells us about incoming call established */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", pptp_msg_name[msg]); break; } if (info->sstate != PPTP_CALL_IN_REP && info->sstate != PPTP_CALL_IN_CONF) { DEBUGP("%s but never sent IN_CALL_REPLY\n", pptp_msg_name[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", pptp_msg_name[msg], ntohs(*pcid)); break; } DEBUGP("%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 */ seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) + sizeof(struct PptpControlHeader) + ((void *)pcid - (void *)pptpReq); if (exp_gre(ct, seq, *cid, *pcid) != 0) printk("ip_conntrack_pptp: error during exp_gre\n"); break; case PPTP_CALL_DISCONNECT_NOTIFY: if (reqlen < sizeof(_pptpReq.disc)) { DEBUGP("%s: short packet\n", pptp_msg_name[msg]); break; } /* server confirms disconnect */ cid = &pptpReq->disc.callID; DEBUGP("%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: 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) ? pptp_msg_name[msg]:pptp_msg_name[0], msg); break; } if (ip_nat_pptp_hook_inbound) return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, pptpReq); return NF_ACCEPT;}static inline intpptp_outbound_pkt(struct sk_buff **pskb, struct tcphdr *tcph, unsigned int nexthdr_off, unsigned int datalen, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo){ struct PptpControlHeader _ctlh, *ctlh; unsigned int reqlen; union pptp_ctrl_union _pptpReq, *pptpReq; struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; u_int16_t msg; __be16 *cid, *pcid; ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); if (!ctlh) return NF_ACCEPT; nexthdr_off += sizeof(_ctlh); datalen -= sizeof(_ctlh); reqlen = datalen; if (reqlen > sizeof(*pptpReq)) reqlen = sizeof(*pptpReq); pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); if (!pptpReq) return NF_ACCEPT; msg = ntohs(ctlh->messageType); DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); switch (msg) { case PPTP_START_SESSION_REQUEST: /* client requests for new control session */ if (info->sstate != PPTP_SESSION_NONE) { DEBUGP("%s but we already have one", pptp_msg_name[msg]); } info->sstate = PPTP_SESSION_REQUESTED; break; case PPTP_STOP_SESSION_REQUEST: /* client requests end of control session */ info->sstate = PPTP_SESSION_STOPREQ; break; case PPTP_OUT_CALL_REQUEST: if (reqlen < sizeof(_pptpReq.ocreq)) { DEBUGP("%s: short packet\n", pptp_msg_name[msg]); /* FIXME: break; */ } /* client initiating connection to server */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("%s but no session\n", pptp_msg_name[msg]); break; } info->cstate = PPTP_CALL_OUT_REQ; /* track PNS call id */ cid = &pptpReq->ocreq.callID; DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); info->pns_call_id = ntohs(*cid); break; case PPTP_IN_CALL_REPLY: if (reqlen < sizeof(_pptpReq.icack)) { DEBUGP("%s: short packet\n", pptp_msg_name[msg]); break; } /* client answers incoming call */ if (info->cstate != PPTP_CALL_IN_REQ && info->cstate != PPTP_CALL_IN_REP) { DEBUGP("%s without incall_req\n", pptp_msg_name[msg]); break; } if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) { info->cstate = PPTP_CALL_NONE; break; } pcid = &pptpReq->icack.peersCallID; if (info->pac_call_id != ntohs(*pcid)) { DEBUGP("%s for unknown call %u\n", pptp_msg_name[msg], ntohs(*pcid)); break; } DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); /* part two of the three-way handshake */ info->cstate = PPTP_CALL_IN_REP; info->pns_call_id = ntohs(pptpReq->icack.callID); break; case PPTP_CALL_CLEAR_REQUEST: /* client requests hangup of call */ if (info->sstate != PPTP_SESSION_CONFIRMED) { DEBUGP("CLEAR_CALL but no session\n"); break; } /* FUTURE: iterate over all calls and check if * call ID is valid. We don't do this without newnat, * because we only know about last call */ info->cstate = PPTP_CALL_CLEAR_REQ; break; case PPTP_SET_LINK_INFO: 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)? pptp_msg_name[msg]:pptp_msg_name[0], msg); /* unknown: no need to create GRE masq table entry */ break; } if (ip_nat_pptp_hook_outbound) return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, pptpReq); return NF_ACCEPT;}/* track caller id inside control connection, call expect_related */static int conntrack_pptp_help(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo){ struct pptp_pkt_hdr _pptph, *pptph; struct tcphdr _tcph, *tcph; u_int32_t tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; u_int32_t datalen; int dir = CTINFO2DIR(ctinfo); struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; unsigned int nexthdr_off; int oldsstate, oldcstate; int ret; /* 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; } nexthdr_off = (*pskb)->nh.iph->ihl*4; tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); BUG_ON(!tcph); nexthdr_off += tcph->doff * 4; datalen = tcplen - tcph->doff * 4; 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_destroy_siblings(ct); } pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); if (!pptph) { DEBUGP("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) { DEBUGP("not a control packet\n"); return NF_ACCEPT; } oldsstate = info->sstate; oldcstate = info->cstate; spin_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(pskb, tcph, nexthdr_off, datalen, ct, ctinfo); else /* server -> client (PAC -> PNS) */ ret = pptp_inbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, ctinfo); DEBUGP("sstate: %d->%d, cstate: %d->%d\n", oldsstate, info->sstate, oldcstate, info->cstate); spin_unlock_bh(&ip_pptp_lock); return ret;}/* control protocol helper */static struct ip_conntrack_helper pptp = { .list = { NULL, NULL }, .name = "pptp", .me = THIS_MODULE, .max_expected = 2, .timeout = 5 * 60, .tuple = { .src = { .ip = 0, .u = { .tcp = { .port = __constant_htons(PPTP_CONTROL_PORT) } } }, .dst = { .ip = 0, .u = { .all = 0 }, .protonum = IPPROTO_TCP } }, .mask = { .src = { .ip = 0, .u = { .tcp = { .port = __constant_htons(0xffff) } } }, .dst = { .ip = 0, .u = { .all = 0 }, .protonum = 0xff } }, .help = conntrack_pptp_help};extern void __exit ip_ct_proto_gre_fini(void);extern int __init ip_ct_proto_gre_init(void);/* ip_conntrack_pptp initialization */static int __init init(void){ int retcode; retcode = ip_ct_proto_gre_init(); if (retcode < 0) return retcode; DEBUGP(" registering helper\n"); if ((retcode = ip_conntrack_helper_register(&pptp))) { printk(KERN_ERR "Unable to register conntrack application " "helper for pptp: %d\n", retcode); ip_ct_proto_gre_fini(); return retcode; } printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); return 0;}static void __exit fini(void){ ip_conntrack_helper_unregister(&pptp); ip_ct_proto_gre_fini(); printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);}module_init(init);module_exit(fini);EXPORT_SYMBOL(ip_nat_pptp_hook_outbound);EXPORT_SYMBOL(ip_nat_pptp_hook_inbound);EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre);EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -