ip_conntrack_helper_pptp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * ip_conntrack_pptp.c - Version 3.0
  3. *
  4. * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
  5. * PPTP is a a protocol for creating virtual private networks.
  6. * It is a specification defined by Microsoft and some vendors
  7. * working with Microsoft. PPTP is built on top of a modified
  8. * version of the Internet Generic Routing Encapsulation Protocol.
  9. * GRE is defined in RFC 1701 and RFC 1702. Documentation of
  10. * PPTP can be found in RFC 2637
  11. *
  12. * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
  13. *
  14. * Development of this code funded by Astaro AG (http://www.astaro.com/)
  15. *
  16. * Limitations:
  17. * - We blindly assume that control connections are always
  18. * established in PNS->PAC direction. This is a violation
  19. * of RFFC2673
  20. * - We can only support one single call within each session
  21. *
  22. * TODO:
  23. * - testing of incoming PPTP calls
  24. *
  25. * Changes:
  26. * 2002-02-05 - Version 1.3
  27. * - Call ip_conntrack_unexpect_related() from
  28. * pptp_destroy_siblings() to destroy expectations in case
  29. * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
  30. * (Philip Craig <philipc@snapgear.com>)
  31. * - Add Version information at module loadtime
  32. * 2002-02-10 - Version 1.6
  33. * - move to C99 style initializers
  34. * - remove second expectation if first arrives
  35. * 2004-10-22 - Version 2.0
  36. * - merge Mandrake's 2.6.x port with recent 2.6.x API changes
  37. * - fix lots of linear skb assumptions from Mandrake's port
  38. * 2005-06-10 - Version 2.1
  39. * - use ip_conntrack_expect_free() instead of kfree() on the
  40. * expect's (which are from the slab for quite some time)
  41. * 2005-06-10 - Version 3.0
  42. * - port helper to post-2.6.11 API changes,
  43. * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)
  44. * 2005-07-30 - Version 3.1
  45. * - port helper to 2.6.13 API changes
  46. *
  47. */
  48. #include <linux/module.h>
  49. #include <linux/netfilter.h>
  50. #include <linux/ip.h>
  51. #include <net/checksum.h>
  52. #include <net/tcp.h>
  53. #include <linux/netfilter_ipv4/ip_conntrack.h>
  54. #include <linux/netfilter_ipv4/ip_conntrack_core.h>
  55. #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
  56. #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
  57. #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
  58. #define IP_CT_PPTP_VERSION "3.1"
  59. MODULE_LICENSE("GPL");
  60. MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
  61. MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
  62. static DEFINE_SPINLOCK(ip_pptp_lock);
  63. int
  64. (*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb,
  65. struct ip_conntrack *ct,
  66. enum ip_conntrack_info ctinfo,
  67. struct PptpControlHeader *ctlh,
  68. union pptp_ctrl_union *pptpReq);
  69. int
  70. (*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb,
  71. struct ip_conntrack *ct,
  72. enum ip_conntrack_info ctinfo,
  73. struct PptpControlHeader *ctlh,
  74. union pptp_ctrl_union *pptpReq);
  75. void
  76. (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig,
  77. struct ip_conntrack_expect *expect_reply);
  78. void
  79. (*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct,
  80. struct ip_conntrack_expect *exp);
  81. #if 0
  82. /* PptpControlMessageType names */
  83. const char *pptp_msg_name[] = {
  84. "UNKNOWN_MESSAGE",
  85. "START_SESSION_REQUEST",
  86. "START_SESSION_REPLY",
  87. "STOP_SESSION_REQUEST",
  88. "STOP_SESSION_REPLY",
  89. "ECHO_REQUEST",
  90. "ECHO_REPLY",
  91. "OUT_CALL_REQUEST",
  92. "OUT_CALL_REPLY",
  93. "IN_CALL_REQUEST",
  94. "IN_CALL_REPLY",
  95. "IN_CALL_CONNECT",
  96. "CALL_CLEAR_REQUEST",
  97. "CALL_DISCONNECT_NOTIFY",
  98. "WAN_ERROR_NOTIFY",
  99. "SET_LINK_INFO"
  100. };
  101. EXPORT_SYMBOL(pptp_msg_name);
  102. #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
  103. #else
  104. #define DEBUGP(format, args...)
  105. #endif
  106. #define SECS *HZ
  107. #define MINS * 60 SECS
  108. #define HOURS * 60 MINS
  109. #define PPTP_GRE_TIMEOUT (10 MINS)
  110. #define PPTP_GRE_STREAM_TIMEOUT (5 HOURS)
  111. static void pptp_expectfn(struct ip_conntrack *ct,
  112. struct ip_conntrack_expect *exp)
  113. {
  114. typeof(ip_nat_pptp_hook_expectfn) ip_nat_pptp_expectfn;
  115. DEBUGP("increasing timeouts\n");
  116. /* increase timeout of GRE data channel conntrack entry */
  117. ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
  118. ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
  119. /* Can you see how rusty this code is, compared with the pre-2.6.11
  120. * one? That's what happened to my shiny newnat of 2002 ;( -HW */
  121. rcu_read_lock();
  122. ip_nat_pptp_expectfn = rcu_dereference(ip_nat_pptp_hook_expectfn);
  123. if (!ip_nat_pptp_expectfn) {
  124. struct ip_conntrack_tuple inv_t;
  125. struct ip_conntrack_expect *exp_other;
  126. /* obviously this tuple inversion only works until you do NAT */
  127. invert_tuplepr(&inv_t, &exp->tuple);
  128. DEBUGP("trying to unexpect other dir: ");
  129. DUMP_TUPLE(&inv_t);
  130. exp_other = ip_conntrack_expect_find_get(&inv_t);
  131. if (exp_other) {
  132. /* delete other expectation. */
  133. DEBUGP("found\n");
  134. ip_conntrack_unexpect_related(exp_other);
  135. ip_conntrack_expect_put(exp_other);
  136. } else {
  137. DEBUGP("not found\n");
  138. }
  139. } else {
  140. /* we need more than simple inversion */
  141. ip_nat_pptp_expectfn(ct, exp);
  142. }
  143. rcu_read_unlock();
  144. }
  145. static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
  146. {
  147. struct ip_conntrack_tuple_hash *h;
  148. struct ip_conntrack_expect *exp;
  149. DEBUGP("trying to timeout ct or exp for tuple ");
  150. DUMP_TUPLE(t);
  151. h = ip_conntrack_find_get(t, NULL);
  152. if (h) {
  153. struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
  154. DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
  155. sibling->proto.gre.timeout = 0;
  156. sibling->proto.gre.stream_timeout = 0;
  157. if (del_timer(&sibling->timeout))
  158. sibling->timeout.function((unsigned long)sibling);
  159. ip_conntrack_put(sibling);
  160. return 1;
  161. } else {
  162. exp = ip_conntrack_expect_find_get(t);
  163. if (exp) {
  164. DEBUGP("unexpect_related of expect %p\n", exp);
  165. ip_conntrack_unexpect_related(exp);
  166. ip_conntrack_expect_put(exp);
  167. return 1;
  168. }
  169. }
  170. return 0;
  171. }
  172. /* timeout GRE data connections */
  173. static void pptp_destroy_siblings(struct ip_conntrack *ct)
  174. {
  175. struct ip_conntrack_tuple t;
  176. ip_ct_gre_keymap_destroy(ct);
  177. /* Since ct->sibling_list has literally rusted away in 2.6.11,
  178. * we now need another way to find out about our sibling
  179. * contrack and expects... -HW */
  180. /* try original (pns->pac) tuple */
  181. memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t));
  182. t.dst.protonum = IPPROTO_GRE;
  183. t.src.u.gre.key = ct->help.ct_pptp_info.pns_call_id;
  184. t.dst.u.gre.key = ct->help.ct_pptp_info.pac_call_id;
  185. if (!destroy_sibling_or_exp(&t))
  186. DEBUGP("failed to timeout original pns->pac ct/exp\n");
  187. /* try reply (pac->pns) tuple */
  188. memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
  189. t.dst.protonum = IPPROTO_GRE;
  190. t.src.u.gre.key = ct->help.ct_pptp_info.pac_call_id;
  191. t.dst.u.gre.key = ct->help.ct_pptp_info.pns_call_id;
  192. if (!destroy_sibling_or_exp(&t))
  193. DEBUGP("failed to timeout reply pac->pns ct/exp\n");
  194. }
  195. /* expect GRE connections (PNS->PAC and PAC->PNS direction) */
  196. static inline int
  197. exp_gre(struct ip_conntrack *ct,
  198. __be16 callid,
  199. __be16 peer_callid)
  200. {
  201. struct ip_conntrack_expect *exp_orig, *exp_reply;
  202. int ret = 1;
  203. typeof(ip_nat_pptp_hook_exp_gre) ip_nat_pptp_exp_gre;
  204. exp_orig = ip_conntrack_expect_alloc(ct);
  205. if (exp_orig == NULL)
  206. goto out;
  207. exp_reply = ip_conntrack_expect_alloc(ct);
  208. if (exp_reply == NULL)
  209. goto out_put_orig;
  210. /* original direction, PNS->PAC */
  211. exp_orig->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
  212. exp_orig->tuple.src.u.gre.key = peer_callid;
  213. exp_orig->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
  214. exp_orig->tuple.dst.u.gre.key = callid;
  215. exp_orig->tuple.dst.protonum = IPPROTO_GRE;
  216. exp_orig->mask.src.ip = htonl(0xffffffff);
  217. exp_orig->mask.src.u.all = 0;
  218. exp_orig->mask.dst.u.gre.key = htons(0xffff);
  219. exp_orig->mask.dst.ip = htonl(0xffffffff);
  220. exp_orig->mask.dst.protonum = 0xff;
  221. exp_orig->master = ct;
  222. exp_orig->expectfn = pptp_expectfn;
  223. exp_orig->flags = 0;
  224. /* both expectations are identical apart from tuple */
  225. memcpy(exp_reply, exp_orig, sizeof(*exp_reply));
  226. /* reply direction, PAC->PNS */
  227. exp_reply->tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
  228. exp_reply->tuple.src.u.gre.key = callid;
  229. exp_reply->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
  230. exp_reply->tuple.dst.u.gre.key = peer_callid;
  231. exp_reply->tuple.dst.protonum = IPPROTO_GRE;
  232. ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre);
  233. if (ip_nat_pptp_exp_gre)
  234. ip_nat_pptp_exp_gre(exp_orig, exp_reply);
  235. if (ip_conntrack_expect_related(exp_orig) != 0)
  236. goto out_put_both;
  237. if (ip_conntrack_expect_related(exp_reply) != 0)
  238. goto out_unexpect_orig;
  239. /* Add GRE keymap entries */
  240. if (ip_ct_gre_keymap_add(ct, &exp_orig->tuple, 0) != 0)
  241. goto out_unexpect_both;
  242. if (ip_ct_gre_keymap_add(ct, &exp_reply->tuple, 1) != 0) {
  243. ip_ct_gre_keymap_destroy(ct);
  244. goto out_unexpect_both;
  245. }
  246. ret = 0;
  247. out_put_both:
  248. ip_conntrack_expect_put(exp_reply);
  249. out_put_orig:
  250. ip_conntrack_expect_put(exp_orig);
  251. out:
  252. return ret;
  253. out_unexpect_both:
  254. ip_conntrack_unexpect_related(exp_reply);
  255. out_unexpect_orig:
  256. ip_conntrack_unexpect_related(exp_orig);
  257. goto out_put_both;
  258. }
  259. static inline int
  260. pptp_inbound_pkt(struct sk_buff **pskb,
  261. struct PptpControlHeader *ctlh,
  262. union pptp_ctrl_union *pptpReq,
  263. unsigned int reqlen,
  264. struct ip_conntrack *ct,
  265. enum ip_conntrack_info ctinfo)
  266. {
  267. struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
  268. u_int16_t msg;
  269. __be16 cid = 0, pcid = 0;
  270. typeof(ip_nat_pptp_hook_inbound) ip_nat_pptp_inbound;
  271. msg = ntohs(ctlh->messageType);
  272. DEBUGP("inbound control message %s\n", pptp_msg_name[msg]);
  273. switch (msg) {
  274. case PPTP_START_SESSION_REPLY:
  275. /* server confirms new control session */
  276. if (info->sstate < PPTP_SESSION_REQUESTED)
  277. goto invalid;
  278. if (pptpReq->srep.resultCode == PPTP_START_OK)
  279. info->sstate = PPTP_SESSION_CONFIRMED;
  280. else
  281. info->sstate = PPTP_SESSION_ERROR;
  282. break;
  283. case PPTP_STOP_SESSION_REPLY:
  284. /* server confirms end of control session */
  285. if (info->sstate > PPTP_SESSION_STOPREQ)
  286. goto invalid;
  287. if (pptpReq->strep.resultCode == PPTP_STOP_OK)
  288. info->sstate = PPTP_SESSION_NONE;
  289. else
  290. info->sstate = PPTP_SESSION_ERROR;
  291. break;
  292. case PPTP_OUT_CALL_REPLY:
  293. /* server accepted call, we now expect GRE frames */
  294. if (info->sstate != PPTP_SESSION_CONFIRMED)
  295. goto invalid;
  296. if (info->cstate != PPTP_CALL_OUT_REQ &&
  297. info->cstate != PPTP_CALL_OUT_CONF)
  298. goto invalid;
  299. cid = pptpReq->ocack.callID;
  300. pcid = pptpReq->ocack.peersCallID;
  301. if (info->pns_call_id != pcid)
  302. goto invalid;
  303. DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg],
  304. ntohs(cid), ntohs(pcid));
  305. if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) {
  306. info->cstate = PPTP_CALL_OUT_CONF;
  307. info->pac_call_id = cid;
  308. exp_gre(ct, cid, pcid);
  309. } else
  310. info->cstate = PPTP_CALL_NONE;
  311. break;
  312. case PPTP_IN_CALL_REQUEST:
  313. /* server tells us about incoming call request */
  314. if (info->sstate != PPTP_SESSION_CONFIRMED)
  315. goto invalid;
  316. cid = pptpReq->icreq.callID;
  317. DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
  318. info->cstate = PPTP_CALL_IN_REQ;
  319. info->pac_call_id = cid;
  320. break;
  321. case PPTP_IN_CALL_CONNECT:
  322. /* server tells us about incoming call established */
  323. if (info->sstate != PPTP_SESSION_CONFIRMED)
  324. goto invalid;
  325. if (info->cstate != PPTP_CALL_IN_REP &&
  326. info->cstate != PPTP_CALL_IN_CONF)
  327. goto invalid;
  328. pcid = pptpReq->iccon.peersCallID;
  329. cid = info->pac_call_id;
  330. if (info->pns_call_id != pcid)
  331. goto invalid;
  332. DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid));
  333. info->cstate = PPTP_CALL_IN_CONF;
  334. /* we expect a GRE connection from PAC to PNS */
  335. exp_gre(ct, cid, pcid);
  336. break;
  337. case PPTP_CALL_DISCONNECT_NOTIFY:
  338. /* server confirms disconnect */
  339. cid = pptpReq->disc.callID;
  340. DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
  341. info->cstate = PPTP_CALL_NONE;
  342. /* untrack this call id, unexpect GRE packets */
  343. pptp_destroy_siblings(ct);
  344. break;
  345. case PPTP_WAN_ERROR_NOTIFY:
  346. case PPTP_ECHO_REQUEST:
  347. case PPTP_ECHO_REPLY:
  348. /* I don't have to explain these ;) */
  349. break;
  350. default:
  351. goto invalid;
  352. }
  353. ip_nat_pptp_inbound = rcu_dereference(ip_nat_pptp_hook_inbound);
  354. if (ip_nat_pptp_inbound)
  355. return ip_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq);
  356. return NF_ACCEPT;
  357. invalid:
  358. DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
  359. "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
  360. msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
  361. msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
  362. ntohs(info->pns_call_id), ntohs(info->pac_call_id));
  363. return NF_ACCEPT;
  364. }
  365. static inline int
  366. pptp_outbound_pkt(struct sk_buff **pskb,
  367. struct PptpControlHeader *ctlh,
  368. union pptp_ctrl_union *pptpReq,
  369. unsigned int reqlen,
  370. struct ip_conntrack *ct,
  371. enum ip_conntrack_info ctinfo)
  372. {
  373. struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
  374. u_int16_t msg;
  375. __be16 cid = 0, pcid = 0;
  376. typeof(ip_nat_pptp_hook_outbound) ip_nat_pptp_outbound;
  377. msg = ntohs(ctlh->messageType);
  378. DEBUGP("outbound control message %s\n", pptp_msg_name[msg]);
  379. switch (msg) {
  380. case PPTP_START_SESSION_REQUEST:
  381. /* client requests for new control session */
  382. if (info->sstate != PPTP_SESSION_NONE)
  383. goto invalid;
  384. info->sstate = PPTP_SESSION_REQUESTED;
  385. break;
  386. case PPTP_STOP_SESSION_REQUEST:
  387. /* client requests end of control session */
  388. info->sstate = PPTP_SESSION_STOPREQ;
  389. break;
  390. case PPTP_OUT_CALL_REQUEST:
  391. /* client initiating connection to server */
  392. if (info->sstate != PPTP_SESSION_CONFIRMED)
  393. goto invalid;
  394. info->cstate = PPTP_CALL_OUT_REQ;
  395. /* track PNS call id */
  396. cid = pptpReq->ocreq.callID;
  397. DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
  398. info->pns_call_id = cid;
  399. break;
  400. case PPTP_IN_CALL_REPLY:
  401. /* client answers incoming call */
  402. if (info->cstate != PPTP_CALL_IN_REQ &&
  403. info->cstate != PPTP_CALL_IN_REP)
  404. goto invalid;
  405. cid = pptpReq->icack.callID;
  406. pcid = pptpReq->icack.peersCallID;
  407. if (info->pac_call_id != pcid)
  408. goto invalid;
  409. DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg],
  410. ntohs(cid), ntohs(pcid));
  411. if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) {
  412. /* part two of the three-way handshake */
  413. info->cstate = PPTP_CALL_IN_REP;
  414. info->pns_call_id = cid;
  415. } else
  416. info->cstate = PPTP_CALL_NONE;
  417. break;
  418. case PPTP_CALL_CLEAR_REQUEST:
  419. /* client requests hangup of call */
  420. if (info->sstate != PPTP_SESSION_CONFIRMED)
  421. goto invalid;
  422. /* FUTURE: iterate over all calls and check if
  423. * call ID is valid. We don't do this without newnat,
  424. * because we only know about last call */
  425. info->cstate = PPTP_CALL_CLEAR_REQ;
  426. break;
  427. case PPTP_SET_LINK_INFO:
  428. case PPTP_ECHO_REQUEST:
  429. case PPTP_ECHO_REPLY:
  430. /* I don't have to explain these ;) */
  431. break;
  432. default:
  433. goto invalid;
  434. }
  435. ip_nat_pptp_outbound = rcu_dereference(ip_nat_pptp_hook_outbound);
  436. if (ip_nat_pptp_outbound)
  437. return ip_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq);
  438. return NF_ACCEPT;
  439. invalid:
  440. DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
  441. "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
  442. msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
  443. msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
  444. ntohs(info->pns_call_id), ntohs(info->pac_call_id));
  445. return NF_ACCEPT;
  446. }
  447. static const unsigned int pptp_msg_size[] = {
  448. [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest),
  449. [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply),
  450. [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest),
  451. [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply),
  452. [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest),
  453. [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply),
  454. [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest),
  455. [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply),
  456. [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected),
  457. [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest),
  458. [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify),
  459. [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify),
  460. [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo),
  461. };
  462. /* track caller id inside control connection, call expect_related */
  463. static int
  464. conntrack_pptp_help(struct sk_buff **pskb,
  465. struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
  466. {
  467. int dir = CTINFO2DIR(ctinfo);
  468. struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
  469. struct tcphdr _tcph, *tcph;
  470. struct pptp_pkt_hdr _pptph, *pptph;
  471. struct PptpControlHeader _ctlh, *ctlh;
  472. union pptp_ctrl_union _pptpReq, *pptpReq;
  473. unsigned int tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
  474. unsigned int datalen, reqlen, nexthdr_off;
  475. int oldsstate, oldcstate;
  476. int ret;
  477. u_int16_t msg;
  478. /* don't do any tracking before tcp handshake complete */
  479. if (ctinfo != IP_CT_ESTABLISHED
  480. && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
  481. DEBUGP("ctinfo = %u, skipping\n", ctinfo);
  482. return NF_ACCEPT;
  483. }
  484. nexthdr_off = (*pskb)->nh.iph->ihl*4;
  485. tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph);
  486. BUG_ON(!tcph);
  487. nexthdr_off += tcph->doff * 4;
  488. datalen = tcplen - tcph->doff * 4;
  489. pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph);
  490. if (!pptph) {
  491. DEBUGP("no full PPTP header, can't track\n");
  492. return NF_ACCEPT;
  493. }
  494. nexthdr_off += sizeof(_pptph);
  495. datalen -= sizeof(_pptph);
  496. /* if it's not a control message we can't do anything with it */
  497. if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
  498. ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
  499. DEBUGP("not a control packet\n");
  500. return NF_ACCEPT;
  501. }
  502. ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh);
  503. if (!ctlh)
  504. return NF_ACCEPT;
  505. nexthdr_off += sizeof(_ctlh);
  506. datalen -= sizeof(_ctlh);
  507. reqlen = datalen;
  508. msg = ntohs(ctlh->messageType);
  509. if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])
  510. return NF_ACCEPT;
  511. if (reqlen > sizeof(*pptpReq))
  512. reqlen = sizeof(*pptpReq);
  513. pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq);
  514. if (!pptpReq)
  515. return NF_ACCEPT;
  516. oldsstate = info->sstate;
  517. oldcstate = info->cstate;
  518. spin_lock_bh(&ip_pptp_lock);
  519. /* FIXME: We just blindly assume that the control connection is always
  520. * established from PNS->PAC. However, RFC makes no guarantee */
  521. if (dir == IP_CT_DIR_ORIGINAL)
  522. /* client -> server (PNS -> PAC) */
  523. ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
  524. ctinfo);
  525. else
  526. /* server -> client (PAC -> PNS) */
  527. ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
  528. ctinfo);
  529. DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
  530. oldsstate, info->sstate, oldcstate, info->cstate);
  531. spin_unlock_bh(&ip_pptp_lock);
  532. return ret;
  533. }
  534. /* control protocol helper */
  535. static struct ip_conntrack_helper pptp = {
  536. .list = { NULL, NULL },
  537. .name = "pptp",
  538. .me = THIS_MODULE,
  539. .max_expected = 2,
  540. .timeout = 5 * 60,
  541. .tuple = { .src = { .ip = 0,
  542. .u = { .tcp = { .port =
  543. __constant_htons(PPTP_CONTROL_PORT) } }
  544. },
  545. .dst = { .ip = 0,
  546. .u = { .all = 0 },
  547. .protonum = IPPROTO_TCP
  548. }
  549. },
  550. .mask = { .src = { .ip = 0,
  551. .u = { .tcp = { .port = __constant_htons(0xffff) } }
  552. },
  553. .dst = { .ip = 0,
  554. .u = { .all = 0 },
  555. .protonum = 0xff
  556. }
  557. },
  558. .help = conntrack_pptp_help,
  559. .destroy = pptp_destroy_siblings,
  560. };
  561. extern void ip_ct_proto_gre_fini(void);
  562. extern int __init ip_ct_proto_gre_init(void);
  563. /* ip_conntrack_pptp initialization */
  564. static int __init ip_conntrack_helper_pptp_init(void)
  565. {
  566. int retcode;
  567. retcode = ip_ct_proto_gre_init();
  568. if (retcode < 0)
  569. return retcode;
  570. DEBUGP(" registering helper\n");
  571. if ((retcode = ip_conntrack_helper_register(&pptp))) {
  572. printk(KERN_ERR "Unable to register conntrack application "
  573. "helper for pptp: %d\n", retcode);
  574. ip_ct_proto_gre_fini();
  575. return retcode;
  576. }
  577. printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
  578. return 0;
  579. }
  580. static void __exit ip_conntrack_helper_pptp_fini(void)
  581. {
  582. ip_conntrack_helper_unregister(&pptp);
  583. ip_ct_proto_gre_fini();
  584. printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
  585. }
  586. module_init(ip_conntrack_helper_pptp_init);
  587. module_exit(ip_conntrack_helper_pptp_fini);
  588. EXPORT_SYMBOL(ip_nat_pptp_hook_outbound);
  589. EXPORT_SYMBOL(ip_nat_pptp_hook_inbound);
  590. EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre);
  591. EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn);