0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include <linux/module.h>
0027 #include <linux/skbuff.h>
0028 #include <linux/in.h>
0029 #include <linux/tcp.h>
0030
0031 #include <net/netfilter/nf_conntrack.h>
0032 #include <net/netfilter/nf_conntrack_core.h>
0033 #include <net/netfilter/nf_conntrack_helper.h>
0034 #include <net/netfilter/nf_conntrack_zones.h>
0035 #include <linux/netfilter/nf_conntrack_proto_gre.h>
0036 #include <linux/netfilter/nf_conntrack_pptp.h>
0037
0038 #define NF_CT_PPTP_VERSION "3.1"
0039
0040 MODULE_LICENSE("GPL");
0041 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
0042 MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
0043 MODULE_ALIAS("ip_conntrack_pptp");
0044 MODULE_ALIAS_NFCT_HELPER("pptp");
0045
0046 static DEFINE_SPINLOCK(nf_pptp_lock);
0047
0048 const struct nf_nat_pptp_hook __rcu *nf_nat_pptp_hook;
0049 EXPORT_SYMBOL_GPL(nf_nat_pptp_hook);
0050
0051 #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
0052
0053 static const char *const pptp_msg_name_array[PPTP_MSG_MAX + 1] = {
0054 [0] = "UNKNOWN_MESSAGE",
0055 [PPTP_START_SESSION_REQUEST] = "START_SESSION_REQUEST",
0056 [PPTP_START_SESSION_REPLY] = "START_SESSION_REPLY",
0057 [PPTP_STOP_SESSION_REQUEST] = "STOP_SESSION_REQUEST",
0058 [PPTP_STOP_SESSION_REPLY] = "STOP_SESSION_REPLY",
0059 [PPTP_ECHO_REQUEST] = "ECHO_REQUEST",
0060 [PPTP_ECHO_REPLY] = "ECHO_REPLY",
0061 [PPTP_OUT_CALL_REQUEST] = "OUT_CALL_REQUEST",
0062 [PPTP_OUT_CALL_REPLY] = "OUT_CALL_REPLY",
0063 [PPTP_IN_CALL_REQUEST] = "IN_CALL_REQUEST",
0064 [PPTP_IN_CALL_REPLY] = "IN_CALL_REPLY",
0065 [PPTP_IN_CALL_CONNECT] = "IN_CALL_CONNECT",
0066 [PPTP_CALL_CLEAR_REQUEST] = "CALL_CLEAR_REQUEST",
0067 [PPTP_CALL_DISCONNECT_NOTIFY] = "CALL_DISCONNECT_NOTIFY",
0068 [PPTP_WAN_ERROR_NOTIFY] = "WAN_ERROR_NOTIFY",
0069 [PPTP_SET_LINK_INFO] = "SET_LINK_INFO"
0070 };
0071
0072 const char *pptp_msg_name(u_int16_t msg)
0073 {
0074 if (msg > PPTP_MSG_MAX)
0075 return pptp_msg_name_array[0];
0076
0077 return pptp_msg_name_array[msg];
0078 }
0079 EXPORT_SYMBOL(pptp_msg_name);
0080 #endif
0081
0082 #define SECS *HZ
0083 #define MINS * 60 SECS
0084 #define HOURS * 60 MINS
0085
0086 #define PPTP_GRE_TIMEOUT (10 MINS)
0087 #define PPTP_GRE_STREAM_TIMEOUT (5 HOURS)
0088
0089 static void pptp_expectfn(struct nf_conn *ct,
0090 struct nf_conntrack_expect *exp)
0091 {
0092 const struct nf_nat_pptp_hook *hook;
0093 struct net *net = nf_ct_net(ct);
0094 pr_debug("increasing timeouts\n");
0095
0096
0097 ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
0098 ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
0099
0100
0101
0102
0103 hook = rcu_dereference(nf_nat_pptp_hook);
0104 if (hook && ct->master->status & IPS_NAT_MASK)
0105 hook->expectfn(ct, exp);
0106 else {
0107 struct nf_conntrack_tuple inv_t;
0108 struct nf_conntrack_expect *exp_other;
0109
0110
0111 nf_ct_invert_tuple(&inv_t, &exp->tuple);
0112 pr_debug("trying to unexpect other dir: ");
0113 nf_ct_dump_tuple(&inv_t);
0114
0115 exp_other = nf_ct_expect_find_get(net, nf_ct_zone(ct), &inv_t);
0116 if (exp_other) {
0117
0118 pr_debug("found\n");
0119 nf_ct_unexpect_related(exp_other);
0120 nf_ct_expect_put(exp_other);
0121 } else {
0122 pr_debug("not found\n");
0123 }
0124 }
0125 }
0126
0127 static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct,
0128 const struct nf_conntrack_tuple *t)
0129 {
0130 const struct nf_conntrack_tuple_hash *h;
0131 const struct nf_conntrack_zone *zone;
0132 struct nf_conntrack_expect *exp;
0133 struct nf_conn *sibling;
0134
0135 pr_debug("trying to timeout ct or exp for tuple ");
0136 nf_ct_dump_tuple(t);
0137
0138 zone = nf_ct_zone(ct);
0139 h = nf_conntrack_find_get(net, zone, t);
0140 if (h) {
0141 sibling = nf_ct_tuplehash_to_ctrack(h);
0142 pr_debug("setting timeout of conntrack %p to 0\n", sibling);
0143 sibling->proto.gre.timeout = 0;
0144 sibling->proto.gre.stream_timeout = 0;
0145 nf_ct_kill(sibling);
0146 nf_ct_put(sibling);
0147 return 1;
0148 } else {
0149 exp = nf_ct_expect_find_get(net, zone, t);
0150 if (exp) {
0151 pr_debug("unexpect_related of expect %p\n", exp);
0152 nf_ct_unexpect_related(exp);
0153 nf_ct_expect_put(exp);
0154 return 1;
0155 }
0156 }
0157 return 0;
0158 }
0159
0160
0161 static void pptp_destroy_siblings(struct nf_conn *ct)
0162 {
0163 struct net *net = nf_ct_net(ct);
0164 const struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
0165 struct nf_conntrack_tuple t;
0166
0167 nf_ct_gre_keymap_destroy(ct);
0168
0169
0170 memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t));
0171 t.dst.protonum = IPPROTO_GRE;
0172 t.src.u.gre.key = ct_pptp_info->pns_call_id;
0173 t.dst.u.gre.key = ct_pptp_info->pac_call_id;
0174 if (!destroy_sibling_or_exp(net, ct, &t))
0175 pr_debug("failed to timeout original pns->pac ct/exp\n");
0176
0177
0178 memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
0179 t.dst.protonum = IPPROTO_GRE;
0180 t.src.u.gre.key = ct_pptp_info->pac_call_id;
0181 t.dst.u.gre.key = ct_pptp_info->pns_call_id;
0182 if (!destroy_sibling_or_exp(net, ct, &t))
0183 pr_debug("failed to timeout reply pac->pns ct/exp\n");
0184 }
0185
0186
0187 static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
0188 {
0189 struct nf_conntrack_expect *exp_orig, *exp_reply;
0190 const struct nf_nat_pptp_hook *hook;
0191 enum ip_conntrack_dir dir;
0192 int ret = 1;
0193
0194 exp_orig = nf_ct_expect_alloc(ct);
0195 if (exp_orig == NULL)
0196 goto out;
0197
0198 exp_reply = nf_ct_expect_alloc(ct);
0199 if (exp_reply == NULL)
0200 goto out_put_orig;
0201
0202
0203 dir = IP_CT_DIR_ORIGINAL;
0204 nf_ct_expect_init(exp_orig, NF_CT_EXPECT_CLASS_DEFAULT,
0205 nf_ct_l3num(ct),
0206 &ct->tuplehash[dir].tuple.src.u3,
0207 &ct->tuplehash[dir].tuple.dst.u3,
0208 IPPROTO_GRE, &peer_callid, &callid);
0209 exp_orig->expectfn = pptp_expectfn;
0210
0211
0212 dir = IP_CT_DIR_REPLY;
0213 nf_ct_expect_init(exp_reply, NF_CT_EXPECT_CLASS_DEFAULT,
0214 nf_ct_l3num(ct),
0215 &ct->tuplehash[dir].tuple.src.u3,
0216 &ct->tuplehash[dir].tuple.dst.u3,
0217 IPPROTO_GRE, &callid, &peer_callid);
0218 exp_reply->expectfn = pptp_expectfn;
0219
0220 hook = rcu_dereference(nf_nat_pptp_hook);
0221 if (hook && ct->status & IPS_NAT_MASK)
0222 hook->exp_gre(exp_orig, exp_reply);
0223 if (nf_ct_expect_related(exp_orig, 0) != 0)
0224 goto out_put_both;
0225 if (nf_ct_expect_related(exp_reply, 0) != 0)
0226 goto out_unexpect_orig;
0227
0228
0229 if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_ORIGINAL, &exp_orig->tuple) != 0)
0230 goto out_unexpect_both;
0231 if (nf_ct_gre_keymap_add(ct, IP_CT_DIR_REPLY, &exp_reply->tuple) != 0) {
0232 nf_ct_gre_keymap_destroy(ct);
0233 goto out_unexpect_both;
0234 }
0235 ret = 0;
0236
0237 out_put_both:
0238 nf_ct_expect_put(exp_reply);
0239 out_put_orig:
0240 nf_ct_expect_put(exp_orig);
0241 out:
0242 return ret;
0243
0244 out_unexpect_both:
0245 nf_ct_unexpect_related(exp_reply);
0246 out_unexpect_orig:
0247 nf_ct_unexpect_related(exp_orig);
0248 goto out_put_both;
0249 }
0250
0251 static int
0252 pptp_inbound_pkt(struct sk_buff *skb, unsigned int protoff,
0253 struct PptpControlHeader *ctlh,
0254 union pptp_ctrl_union *pptpReq,
0255 unsigned int reqlen,
0256 struct nf_conn *ct,
0257 enum ip_conntrack_info ctinfo)
0258 {
0259 struct nf_ct_pptp_master *info = nfct_help_data(ct);
0260 const struct nf_nat_pptp_hook *hook;
0261 u_int16_t msg;
0262 __be16 cid = 0, pcid = 0;
0263
0264 msg = ntohs(ctlh->messageType);
0265 pr_debug("inbound control message %s\n", pptp_msg_name(msg));
0266
0267 switch (msg) {
0268 case PPTP_START_SESSION_REPLY:
0269
0270 if (info->sstate < PPTP_SESSION_REQUESTED)
0271 goto invalid;
0272 if (pptpReq->srep.resultCode == PPTP_START_OK)
0273 info->sstate = PPTP_SESSION_CONFIRMED;
0274 else
0275 info->sstate = PPTP_SESSION_ERROR;
0276 break;
0277
0278 case PPTP_STOP_SESSION_REPLY:
0279
0280 if (info->sstate > PPTP_SESSION_STOPREQ)
0281 goto invalid;
0282 if (pptpReq->strep.resultCode == PPTP_STOP_OK)
0283 info->sstate = PPTP_SESSION_NONE;
0284 else
0285 info->sstate = PPTP_SESSION_ERROR;
0286 break;
0287
0288 case PPTP_OUT_CALL_REPLY:
0289
0290 if (info->sstate != PPTP_SESSION_CONFIRMED)
0291 goto invalid;
0292 if (info->cstate != PPTP_CALL_OUT_REQ &&
0293 info->cstate != PPTP_CALL_OUT_CONF)
0294 goto invalid;
0295
0296 cid = pptpReq->ocack.callID;
0297 pcid = pptpReq->ocack.peersCallID;
0298 if (info->pns_call_id != pcid)
0299 goto invalid;
0300 pr_debug("%s, CID=%X, PCID=%X\n", pptp_msg_name(msg),
0301 ntohs(cid), ntohs(pcid));
0302
0303 if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) {
0304 info->cstate = PPTP_CALL_OUT_CONF;
0305 info->pac_call_id = cid;
0306 exp_gre(ct, cid, pcid);
0307 } else
0308 info->cstate = PPTP_CALL_NONE;
0309 break;
0310
0311 case PPTP_IN_CALL_REQUEST:
0312
0313 if (info->sstate != PPTP_SESSION_CONFIRMED)
0314 goto invalid;
0315
0316 cid = pptpReq->icreq.callID;
0317 pr_debug("%s, CID=%X\n", pptp_msg_name(msg), ntohs(cid));
0318 info->cstate = PPTP_CALL_IN_REQ;
0319 info->pac_call_id = cid;
0320 break;
0321
0322 case PPTP_IN_CALL_CONNECT:
0323
0324 if (info->sstate != PPTP_SESSION_CONFIRMED)
0325 goto invalid;
0326 if (info->cstate != PPTP_CALL_IN_REP &&
0327 info->cstate != PPTP_CALL_IN_CONF)
0328 goto invalid;
0329
0330 pcid = pptpReq->iccon.peersCallID;
0331 cid = info->pac_call_id;
0332
0333 if (info->pns_call_id != pcid)
0334 goto invalid;
0335
0336 pr_debug("%s, PCID=%X\n", pptp_msg_name(msg), ntohs(pcid));
0337 info->cstate = PPTP_CALL_IN_CONF;
0338
0339
0340 exp_gre(ct, cid, pcid);
0341 break;
0342
0343 case PPTP_CALL_DISCONNECT_NOTIFY:
0344
0345 cid = pptpReq->disc.callID;
0346 pr_debug("%s, CID=%X\n", pptp_msg_name(msg), ntohs(cid));
0347 info->cstate = PPTP_CALL_NONE;
0348
0349
0350 pptp_destroy_siblings(ct);
0351 break;
0352
0353 case PPTP_WAN_ERROR_NOTIFY:
0354 case PPTP_SET_LINK_INFO:
0355 case PPTP_ECHO_REQUEST:
0356 case PPTP_ECHO_REPLY:
0357
0358 break;
0359
0360 default:
0361 goto invalid;
0362 }
0363
0364 hook = rcu_dereference(nf_nat_pptp_hook);
0365 if (hook && ct->status & IPS_NAT_MASK)
0366 return hook->inbound(skb, ct, ctinfo, protoff, ctlh, pptpReq);
0367 return NF_ACCEPT;
0368
0369 invalid:
0370 pr_debug("invalid %s: type=%d cid=%u pcid=%u "
0371 "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
0372 pptp_msg_name(msg),
0373 msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
0374 ntohs(info->pns_call_id), ntohs(info->pac_call_id));
0375 return NF_ACCEPT;
0376 }
0377
0378 static int
0379 pptp_outbound_pkt(struct sk_buff *skb, unsigned int protoff,
0380 struct PptpControlHeader *ctlh,
0381 union pptp_ctrl_union *pptpReq,
0382 unsigned int reqlen,
0383 struct nf_conn *ct,
0384 enum ip_conntrack_info ctinfo)
0385 {
0386 struct nf_ct_pptp_master *info = nfct_help_data(ct);
0387 const struct nf_nat_pptp_hook *hook;
0388 u_int16_t msg;
0389 __be16 cid = 0, pcid = 0;
0390
0391 msg = ntohs(ctlh->messageType);
0392 pr_debug("outbound control message %s\n", pptp_msg_name(msg));
0393
0394 switch (msg) {
0395 case PPTP_START_SESSION_REQUEST:
0396
0397 if (info->sstate != PPTP_SESSION_NONE)
0398 goto invalid;
0399 info->sstate = PPTP_SESSION_REQUESTED;
0400 break;
0401
0402 case PPTP_STOP_SESSION_REQUEST:
0403
0404 info->sstate = PPTP_SESSION_STOPREQ;
0405 break;
0406
0407 case PPTP_OUT_CALL_REQUEST:
0408
0409 if (info->sstate != PPTP_SESSION_CONFIRMED)
0410 goto invalid;
0411 info->cstate = PPTP_CALL_OUT_REQ;
0412
0413 cid = pptpReq->ocreq.callID;
0414 pr_debug("%s, CID=%X\n", pptp_msg_name(msg), ntohs(cid));
0415 info->pns_call_id = cid;
0416 break;
0417
0418 case PPTP_IN_CALL_REPLY:
0419
0420 if (info->cstate != PPTP_CALL_IN_REQ &&
0421 info->cstate != PPTP_CALL_IN_REP)
0422 goto invalid;
0423
0424 cid = pptpReq->icack.callID;
0425 pcid = pptpReq->icack.peersCallID;
0426 if (info->pac_call_id != pcid)
0427 goto invalid;
0428 pr_debug("%s, CID=%X PCID=%X\n", pptp_msg_name(msg),
0429 ntohs(cid), ntohs(pcid));
0430
0431 if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) {
0432
0433 info->cstate = PPTP_CALL_IN_REP;
0434 info->pns_call_id = cid;
0435 } else
0436 info->cstate = PPTP_CALL_NONE;
0437 break;
0438
0439 case PPTP_CALL_CLEAR_REQUEST:
0440
0441 if (info->sstate != PPTP_SESSION_CONFIRMED)
0442 goto invalid;
0443
0444
0445
0446 info->cstate = PPTP_CALL_CLEAR_REQ;
0447 break;
0448
0449 case PPTP_SET_LINK_INFO:
0450 case PPTP_ECHO_REQUEST:
0451 case PPTP_ECHO_REPLY:
0452
0453 break;
0454
0455 default:
0456 goto invalid;
0457 }
0458
0459 hook = rcu_dereference(nf_nat_pptp_hook);
0460 if (hook && ct->status & IPS_NAT_MASK)
0461 return hook->outbound(skb, ct, ctinfo, protoff, ctlh, pptpReq);
0462 return NF_ACCEPT;
0463
0464 invalid:
0465 pr_debug("invalid %s: type=%d cid=%u pcid=%u "
0466 "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
0467 pptp_msg_name(msg),
0468 msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
0469 ntohs(info->pns_call_id), ntohs(info->pac_call_id));
0470 return NF_ACCEPT;
0471 }
0472
0473 static const unsigned int pptp_msg_size[] = {
0474 [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest),
0475 [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply),
0476 [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest),
0477 [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply),
0478 [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest),
0479 [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply),
0480 [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest),
0481 [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply),
0482 [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected),
0483 [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest),
0484 [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify),
0485 [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify),
0486 [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo),
0487 };
0488
0489
0490 static int
0491 conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
0492 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
0493
0494 {
0495 int dir = CTINFO2DIR(ctinfo);
0496 const struct nf_ct_pptp_master *info = nfct_help_data(ct);
0497 const struct tcphdr *tcph;
0498 struct tcphdr _tcph;
0499 const struct pptp_pkt_hdr *pptph;
0500 struct pptp_pkt_hdr _pptph;
0501 struct PptpControlHeader _ctlh, *ctlh;
0502 union pptp_ctrl_union _pptpReq, *pptpReq;
0503 unsigned int tcplen = skb->len - protoff;
0504 unsigned int datalen, reqlen, nexthdr_off;
0505 int oldsstate, oldcstate;
0506 int ret;
0507 u_int16_t msg;
0508
0509 #if IS_ENABLED(CONFIG_NF_NAT)
0510 if (!nf_ct_is_confirmed(ct) && (ct->status & IPS_NAT_MASK)) {
0511 struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
0512
0513 if (!nat && !nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC))
0514 return NF_DROP;
0515 }
0516 #endif
0517
0518 if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
0519 return NF_ACCEPT;
0520
0521 nexthdr_off = protoff;
0522 tcph = skb_header_pointer(skb, nexthdr_off, sizeof(_tcph), &_tcph);
0523 if (!tcph)
0524 return NF_ACCEPT;
0525
0526 nexthdr_off += tcph->doff * 4;
0527 datalen = tcplen - tcph->doff * 4;
0528
0529 pptph = skb_header_pointer(skb, nexthdr_off, sizeof(_pptph), &_pptph);
0530 if (!pptph) {
0531 pr_debug("no full PPTP header, can't track\n");
0532 return NF_ACCEPT;
0533 }
0534 nexthdr_off += sizeof(_pptph);
0535 datalen -= sizeof(_pptph);
0536
0537
0538 if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
0539 ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
0540 pr_debug("not a control packet\n");
0541 return NF_ACCEPT;
0542 }
0543
0544 ctlh = skb_header_pointer(skb, nexthdr_off, sizeof(_ctlh), &_ctlh);
0545 if (!ctlh)
0546 return NF_ACCEPT;
0547 nexthdr_off += sizeof(_ctlh);
0548 datalen -= sizeof(_ctlh);
0549
0550 reqlen = datalen;
0551 msg = ntohs(ctlh->messageType);
0552 if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])
0553 return NF_ACCEPT;
0554 if (reqlen > sizeof(*pptpReq))
0555 reqlen = sizeof(*pptpReq);
0556
0557 pptpReq = skb_header_pointer(skb, nexthdr_off, reqlen, &_pptpReq);
0558 if (!pptpReq)
0559 return NF_ACCEPT;
0560
0561 oldsstate = info->sstate;
0562 oldcstate = info->cstate;
0563
0564 spin_lock_bh(&nf_pptp_lock);
0565
0566
0567
0568 if (dir == IP_CT_DIR_ORIGINAL)
0569
0570 ret = pptp_outbound_pkt(skb, protoff, ctlh, pptpReq, reqlen, ct,
0571 ctinfo);
0572 else
0573
0574 ret = pptp_inbound_pkt(skb, protoff, ctlh, pptpReq, reqlen, ct,
0575 ctinfo);
0576 pr_debug("sstate: %d->%d, cstate: %d->%d\n",
0577 oldsstate, info->sstate, oldcstate, info->cstate);
0578 spin_unlock_bh(&nf_pptp_lock);
0579
0580 return ret;
0581 }
0582
0583 static const struct nf_conntrack_expect_policy pptp_exp_policy = {
0584 .max_expected = 2,
0585 .timeout = 5 * 60,
0586 };
0587
0588
0589 static struct nf_conntrack_helper pptp __read_mostly = {
0590 .name = "pptp",
0591 .me = THIS_MODULE,
0592 .tuple.src.l3num = AF_INET,
0593 .tuple.src.u.tcp.port = cpu_to_be16(PPTP_CONTROL_PORT),
0594 .tuple.dst.protonum = IPPROTO_TCP,
0595 .help = conntrack_pptp_help,
0596 .destroy = pptp_destroy_siblings,
0597 .expect_policy = &pptp_exp_policy,
0598 };
0599
0600 static int __init nf_conntrack_pptp_init(void)
0601 {
0602 NF_CT_HELPER_BUILD_BUG_ON(sizeof(struct nf_ct_pptp_master));
0603
0604 return nf_conntrack_helper_register(&pptp);
0605 }
0606
0607 static void __exit nf_conntrack_pptp_fini(void)
0608 {
0609 nf_conntrack_helper_unregister(&pptp);
0610 }
0611
0612 module_init(nf_conntrack_pptp_init);
0613 module_exit(nf_conntrack_pptp_fini);