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