NF_IP_PRI_FILTER = 0,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_SELINUX_LAST = 225,
+       NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2,
+       NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1,
+       NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
        NF_IP_PRI_LAST = INT_MAX,
 };
 
 
                               const struct net_device *in,
                               const struct net_device *out,
                               int (*okfn)(struct sk_buff *))
+{
+       /* We've seen it coming out the other side: confirm it */
+       return ip_conntrack_confirm(pskb);
+}
+
+static unsigned int ip_conntrack_help(unsigned int hooknum,
+                                     struct sk_buff **pskb,
+                                     const struct net_device *in,
+                                     const struct net_device *out,
+                                     int (*okfn)(struct sk_buff *))
 {
        struct ip_conntrack *ct;
        enum ip_conntrack_info ctinfo;
                if (ret != NF_ACCEPT)
                        return ret;
        }
-
-       /* We've seen it coming out the other side: confirm it */
-       return ip_conntrack_confirm(pskb);
+       return NF_ACCEPT;
 }
 
 static unsigned int ip_conntrack_defrag(unsigned int hooknum,
        .priority       = NF_IP_PRI_CONNTRACK,
 };
 
+/* helpers */
+static struct nf_hook_ops ip_conntrack_helper_out_ops = {
+       .hook           = ip_conntrack_help,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_POST_ROUTING,
+       .priority       = NF_IP_PRI_CONNTRACK_HELPER,
+};
+
+static struct nf_hook_ops ip_conntrack_helper_in_ops = {
+       .hook           = ip_conntrack_help,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_LOCAL_IN,
+       .priority       = NF_IP_PRI_CONNTRACK_HELPER,
+};
+
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops = {
        .hook           = ip_refrag,
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_POST_ROUTING,
-       .priority       = NF_IP_PRI_LAST,
+       .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
 };
 
 static struct nf_hook_ops ip_conntrack_local_in_ops = {
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_LOCAL_IN,
-       .priority       = NF_IP_PRI_LAST-1,
+       .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
 };
 
 /* Sysctl support */
                printk("ip_conntrack: can't register local out hook.\n");
                goto cleanup_inops;
        }
+       ret = nf_register_hook(&ip_conntrack_helper_in_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register local in helper hook.\n");
+               goto cleanup_inandlocalops;
+       }
+       ret = nf_register_hook(&ip_conntrack_helper_out_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register postrouting helper hook.\n");
+               goto cleanup_helperinops;
+       }
        ret = nf_register_hook(&ip_conntrack_out_ops);
        if (ret < 0) {
                printk("ip_conntrack: can't register post-routing hook.\n");
-               goto cleanup_inandlocalops;
+               goto cleanup_helperoutops;
        }
        ret = nf_register_hook(&ip_conntrack_local_in_ops);
        if (ret < 0) {
        nf_unregister_hook(&ip_conntrack_local_in_ops);
  cleanup_inoutandlocalops:
        nf_unregister_hook(&ip_conntrack_out_ops);
+ cleanup_helperoutops:
+       nf_unregister_hook(&ip_conntrack_helper_out_ops);
+ cleanup_helperinops:
+       nf_unregister_hook(&ip_conntrack_helper_in_ops);
  cleanup_inandlocalops:
        nf_unregister_hook(&ip_conntrack_local_out_ops);
  cleanup_inops:
 
        unsigned long statusbit;
        enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum);
 
-       if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)
-           && (hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_IN)) {
-               DEBUGP("ip_nat_core: adjusting sequence number\n");
-               /* future: put this in a l4-proto specific function,
-                * and call this function here. */
-               if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
-                       return NF_DROP;
-       }
-
        if (mtype == IP_NAT_MANIP_SRC)
                statusbit = IPS_SRC_NAT;
        else
 
        return ret;
 }
 
+static unsigned int
+ip_nat_adjust(unsigned int hooknum,
+             struct sk_buff **pskb,
+             const struct net_device *in,
+             const struct net_device *out,
+             int (*okfn)(struct sk_buff *))
+{
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+
+       ct = ip_conntrack_get(*pskb, &ctinfo);
+       if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
+               DEBUGP("ip_nat_standalone: adjusting sequence number\n");
+               if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
+                       return NF_DROP;
+       }
+       return NF_ACCEPT;
+}
+
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
        .priority       = NF_IP_PRI_NAT_SRC,
 };
 
+/* After conntrack, adjust sequence number */
+static struct nf_hook_ops ip_nat_adjust_out_ops = {
+       .hook           = ip_nat_adjust,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_POST_ROUTING,
+       .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
+};
+
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops = {
        .hook           = ip_nat_local_fn,
        .priority       = NF_IP_PRI_NAT_SRC,
 };
 
+/* After conntrack, adjust sequence number */
+static struct nf_hook_ops ip_nat_adjust_in_ops = {
+       .hook           = ip_nat_adjust,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_LOCAL_IN,
+       .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
+};
+
+
 static int init_or_cleanup(int init)
 {
        int ret = 0;
                printk("ip_nat_init: can't register out hook.\n");
                goto cleanup_inops;
        }
+       ret = nf_register_hook(&ip_nat_adjust_in_ops);
+       if (ret < 0) {
+               printk("ip_nat_init: can't register adjust in hook.\n");
+               goto cleanup_outops;
+       }
+       ret = nf_register_hook(&ip_nat_adjust_out_ops);
+       if (ret < 0) {
+               printk("ip_nat_init: can't register adjust out hook.\n");
+               goto cleanup_adjustin_ops;
+       }
        ret = nf_register_hook(&ip_nat_local_out_ops);
        if (ret < 0) {
                printk("ip_nat_init: can't register local out hook.\n");
-               goto cleanup_outops;
+               goto cleanup_adjustout_ops;;
        }
        ret = nf_register_hook(&ip_nat_local_in_ops);
        if (ret < 0) {
        nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
        nf_unregister_hook(&ip_nat_local_out_ops);
+ cleanup_adjustout_ops:
+       nf_unregister_hook(&ip_nat_adjust_out_ops);
+ cleanup_adjustin_ops:
+       nf_unregister_hook(&ip_nat_adjust_in_ops);
  cleanup_outops:
        nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops: