diff -upr linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h msyn-linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h
--- linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h 2007-04-09 15:06:47.000000000 +0800
@@ -36,6 +36,7 @@ struct ip_ct_tcp_state {
u_int8_t td_scale; /* window scale factor */
u_int8_t loose; /* used when connection picked up from the middle */
u_int8_t flags; /* per direction options */
+ u_int8_t dummy;
};
struct ip_ct_tcp
@@ -49,6 +50,8 @@ struct ip_ct_tcp
u_int32_t last_seq; /* Last sequence number seen in dir */
u_int32_t last_ack; /* Last sequence number seen in opposite dir */
u_int32_t last_end; /* Last seq + len */
+ u_int32_t aseq;
+ u_int32_t pseq;
};
#endif /* __KERNEL__ */
diff -upr linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h 2007-04-29 15:23:07.000000000 +0800
@@ -81,6 +81,10 @@ struct ip_conntrack
/* Have we seen traffic both ways yet? (bitset) */
unsigned long status;
+
+ unsigned long cookie;
+#define IPCT_COOKIE 0x00001000 /* cookie ct */
+#define IPCT_HOCONT 0x00000010 /* half-open-cnt ct */
/* Timer function; drops refcnt when it goes off. */
struct timer_list timeout;
@@ -287,6 +291,10 @@ static inline int is_confirmed(struct ip
return test_bit(IPS_CONFIRMED_BIT, &ct->status);
}
+extern int nr_ho;
+//extern int cfg_nic_ok(struct sk_buff *);
+extern int sysctl_nt_syn_cookie[4];
+
static inline int is_dying(struct ip_conntrack *ct)
{
return test_bit(IPS_DYING_BIT, &ct->status);
diff -upr linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2007-04-09 15:09:11.000000000 +0800
@@ -47,7 +47,7 @@ struct ip_conntrack_manip
struct ip_conntrack_tuple
{
struct ip_conntrack_manip src;
-
+
/* These are the parts of the tuple which are fixed. */
struct {
u_int32_t ip;
diff -upr linux-2.6.17.8/include/linux/skbuff.h msyn-linux-2.6.17.8/include/linux/skbuff.h
--- linux-2.6.17.8/include/linux/skbuff.h 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/skbuff.h 2007-04-03 11:51:08.000000000 +0800
@@ -89,6 +89,7 @@ struct net_device;
struct nf_conntrack {
atomic_t use;
void (*destroy)(struct nf_conntrack *);
+ unsigned long dummy, cook2;
};
#ifdef CONFIG_BRIDGE_NETFILTER
diff -upr linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c 2007-04-29 15:23:38.000000000 +0800
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/icmp.h>
#include <linux/ip.h>
+#include <linux/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/module.h>
@@ -69,6 +70,8 @@ struct ip_conntrack_protocol *ip_ct_prot
static LIST_HEAD(helpers);
unsigned int ip_conntrack_htable_size = 0;
int ip_conntrack_max;
+int sysctl_nt_syn_cookie[4] = { 8192, 128, 0, 0 };
+int nr_ho = 0;
struct list_head *ip_conntrack_hash;
static kmem_cache_t *ip_conntrack_cachep __read_mostly;
static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly;
@@ -352,6 +355,13 @@ destroy_conntrack(struct nf_conntrack *n
ip_conntrack_put(ct->master);
DEBUGP("destroy_conntrack: returning ct=%p to slab/n", ct);
+ if (nfct->cook2) {
+ struct sk_buff * tmp =
+ (struct sk_buff *) nfct->cook2;
+ nfct->cook2 = 0;
+ atomic_dec(&(tmp->users));
+ kfree_skb(tmp);
+ }
ip_conntrack_free(ct);
}
@@ -363,7 +373,13 @@ static void death_by_timeout(unsigned lo
/* Inside lock so preempt is disabled on module removal path.
* Otherwise we can get spurious warnings. */
CONNTRACK_STAT_INC(delete_list);
- clean_from_lists(ct);
+ clean_from_lists(ct);
+ if ((ct->cookie & IPCT_HOCONT)
+ && (ct->proto.tcp.state == TCP_CONNTRACK_SYN_SENT
+ || ct->proto.tcp.state == TCP_CONNTRACK_SYN_RECV))
+ --nr_ho;
+ if (nr_ho <0)
+ nr_ho = 0;
write_unlock_bh(&ip_conntrack_lock);
ip_conntrack_put(ct);
}
@@ -492,6 +508,9 @@ __ip_conntrack_confirm(struct sk_buff **
set_bit(IPS_CONFIRMED_BIT, &ct->status);
CONNTRACK_STAT_INC(insert);
write_unlock_bh(&ip_conntrack_lock);
+ if ((ct->cookie & IPCT_HOCONT)
+ && ct->proto.tcp.state == TCP_CONNTRACK_SYN_SENT)
+ ++nr_ho;
if (ct->helper)
ip_conntrack_event_cache(IPCT_HELPER, *pskb);
#ifdef CONFIG_IP_NF_NAT_NEEDED
@@ -503,8 +522,7 @@ __ip_conntrack_confirm(struct sk_buff **
IPCT_RELATED : IPCT_NEW, *pskb);
return NF_ACCEPT;
- }
-
+ }
CONNTRACK_STAT_INC(insert_failed);
write_unlock_bh(&ip_conntrack_lock);
@@ -745,7 +763,192 @@ init_conntrack(struct ip_conntrack_tuple
return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
}
+static struct sk_buff * make_new_syn(struct sk_buff *);
+static void give_cookie_toc(struct sk_buff *);
+static int skb_is_cookie_ok(struct sk_buff *);
+static u32 make_cookie(struct sk_buff * , int);
+static int skb_is_syn_ack(struct sk_buff * , int);
+
+static struct sk_buff * make_new_syn (struct sk_buff * skbo)
+{
+ struct sk_buff * skb ;
+ struct tcphdr *th, *oth;
+ struct iphdr *iph, *oiph;
+ struct ethhdr *eth, *oeth;
+ unsigned int size = 20 + 28;
+
+ size += (((skbo->nh.raw - skbo->mac.raw) +15) & ~15);
+ if ((skb = alloc_skb(size, GFP_ATOMIC)) == NULL)
+ return NULL;
+ skb_reserve(skb, size);
+
+ oeth = (struct ethhdr *)skbo->mac.raw;
+ oiph = skbo->nh.iph;
+ oth = (void *)oiph + (oiph->ihl<<2) ;
+
+ th = (struct tcphdr *) skb_push(skb, 28);
+ memset(th, 0, 28);
+
+ th->source = oth->source;
+ th->dest = oth->dest;
+
+ th->seq = htonl(ntohl(oth->seq) -1);
+
+ th->syn = 1;
+ th->doff = 28 >> 2;
+ th->window = oth->window ;
+ *(__be32 *)(th + 1) = htonl((2 << 24) | (4 << 16) | 1460);
+ th->check = csum_tcpudp_magic(oiph->saddr, oiph->daddr,
+ skb->len, IPPROTO_TCP,
+ csum_partial((char *)th, skb->len, 0));
+
+ skb->nh.iph = iph = (struct iphdr *)skb_push(skb, 20);
+ memset(iph, 0, 20);
+
+ iph->version = 4;
+ iph->ihl = 5;
+ iph->ttl = oiph->ttl;
+ iph->tos = oiph->tos;
+ iph->protocol = oiph->protocol;
+ iph->id = oiph->id ;
+
+ iph->daddr = oiph->daddr;
+ iph->saddr = oiph->saddr;
+
+ iph->tot_len = htons(skb->len);
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+ size = skbo->nh.raw - skbo->mac.raw;
+ eth = (struct ethhdr *)skb_push(skb, size);
+ skb_pull(skb, size);
+ skb->mac.raw = (void *)eth;
+ memcpy(skb->mac.raw, skbo->mac.raw, size);
+ skb->protocol = skbo->protocol;
+ skb->pkt_type = skbo->pkt_type;
+ skb->dev = skbo->dev;
+ return skb;
+}
+static void give_cookie_toc (struct sk_buff * skbo)
+{
+ struct sk_buff * skb ;
+ struct tcphdr *th, *oth;
+ struct iphdr *iph, *oiph;
+ struct ethhdr *eth, *oeth;
+ unsigned int size = 20 + 28;
+
+ size += (((skbo->nh.raw - skbo->mac.raw) +15) & ~15);
+ if ((skb = alloc_skb(size, GFP_ATOMIC)) == NULL)
+ return;
+ skb_reserve(skb, size);
+
+ oeth = (struct ethhdr *) skbo->mac.raw;
+ oiph = skbo->nh.iph;
+ oth = (struct tcphdr *)((char *)oiph + (oiph->ihl<<2));
+
+ skb->h.th = th = (struct tcphdr *) skb_push(skb, 28);
+ memset(th, 0, 28);
+
+ th->source = oth->dest;
+ th->dest = oth->source;
+
+ th->ack_seq = htonl(ntohl(oth->seq) + 1);
+ th->seq = htonl(make_cookie(skbo, 1));
+
+ th->syn = th->ack = 1;
+ th->doff = 28 >> 2;
+
+ th->window = htons(5840);
+ *(__be32 *)(th + 1) = htonl((2 << 24) | (4 << 16) | 1460);
+
+ th->check = csum_tcpudp_magic(oiph->daddr, oiph->saddr,
+ skb->len, IPPROTO_TCP,
+ csum_partial((char *)th, skb->len, 0));
+
+ skb->nh.iph = iph = (struct iphdr *)skb_push(skb, 20);
+ memset(iph, 0, 20);
+
+ iph->daddr = oiph->saddr;
+ iph->saddr = oiph->daddr;
+
+ iph->version = 4;
+ iph->ihl = 5;
+ iph->ttl = 64;
+ iph->tos = oiph->tos;
+ iph->protocol = oiph->protocol;
+ iph->id = oiph->id ;
+
+ iph->tot_len = htons(skb->len);
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+ size = skbo->nh.raw - skbo->mac.raw;
+ eth = (struct ethhdr *)skb_push(skb, size);
+ skb->mac.raw = (void *)eth;
+ memcpy(skb->mac.raw, skbo->mac.raw, size);
+ memcpy(eth->h_dest, oeth->h_source, ETH_ALEN);
+ memcpy(eth->h_source, oeth->h_dest, ETH_ALEN);
+
+ skb->protocol = skbo->protocol;
+ skb->dev = (skbo->dev->priv_flags & IFF_EBRIDGE) ?
+ skbo->nf_bridge->physindev :
+ skbo->input_dev;
+ dev_queue_xmit(skb);
+}
+static int skb_is_syn_ack (struct sk_buff * skb, int syn)
+{
+ struct iphdr * i = skb->nh.iph;
+ struct tcphdr * t =
+ (struct tcphdr *)((char *)i +(i->ihl<<2));
+
+ if ((syn ? (t->syn == 1 && t->ack == 0) :
+ (t->syn == 0 && t->ack == 1))
+ && t->fin == 0 && t->rst == 0
+ && skb->len == 4*(i->ihl + t->doff))
+ return 1;
+ return 0;
+}
+static u32 make_cookie (struct sk_buff * skb, int is_syn)
+{
+ /*
+ * code granted by other guys,
+ * though simple and effective,
+ * no need to appreciate.
+ *
+ * and linux has other nicee codes,
+ * isnt it?
+ *
+ *
+ *
+ *
+ *
+ */
+}
+static int skb_is_cookie_ok (struct sk_buff * skb)
+{
+ struct iphdr * i = skb->nh.iph;
+ struct tcphdr * t =
+ (struct tcphdr *)((char *)i +(i->ihl<<2));
+ if (skb/*xxuglyx*/)
+ return 1;
+ return 0;
+}
+static int cfg_nic_ok(struct sk_buff * skb)
+{
+ int j, k;
+
+ k = sizeof(sysctl_nt_syn_cookie) / sizeof(int);
+ for (j = 2; j < k; j++) {
+ if (sysctl_nt_syn_cookie[j] > 0 &&
+ sysctl_nt_syn_cookie[j] == (
+#ifdef CONFIG_BRIDGE_NETFILTER
+ skb->nf_bridge ?
+ skb->nf_bridge->physindev->ifindex :
+#endif
+ skb->input_dev->ifindex))
+ return 1;
+ }
+ return 0;
+}
/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
static inline struct ip_conntrack *
resolve_normal_ct(struct sk_buff *skb,
@@ -758,6 +961,9 @@ resolve_normal_ct(struct sk_buff *skb,
struct ip_conntrack_tuple_hash *h;
struct ip_conntrack *ct;
+ static unsigned long cnt_ho, tstamp = 0;
+ unsigned long now;
+
IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4,
@@ -767,6 +973,48 @@ resolve_normal_ct(struct sk_buff *skb,
/* look for tuple match */
h = ip_conntrack_find_get(&tuple, NULL);
if (!h) {
+#define cfg_anr sysctl_nt_syn_cookie[0]
+#define cfg_snr sysctl_nt_syn_cookie[1]
+
+ if (proto->proto == IPPROTO_TCP &&
+ hooknum == NF_IP_PRE_ROUTING &&
+ cfg_nic_ok(skb))
+ {
+ if (cfg_anr < 0 || cfg_snr < 0) {
+ mixi:
+ h = ERR_PTR(-601);
+ return (void *)h;
+ }
+ tuple.dst.dir = 0;
+ if (skb_is_syn_ack(skb, 1)) {
+ int buk = 0;
+
+ now = jiffies ;
+ cnt_ho += (now - tstamp);
+ tstamp = now;
+ if (cnt_ho > HZ * cfg_snr)
+ cnt_ho = HZ * cfg_snr;
+ if (cnt_ho >= HZ) {
+ cnt_ho -= HZ ;
+ buk = 1;
+ }
+ if (nr_ho < cfg_anr && buk) {
+ tuple.dst.dir = 4;
+ goto nook;
+ }
+ h = ERR_PTR(-600);
+ return (void *)h;
+ } else if (skb_is_syn_ack(skb, 0) &&
+ skb_is_cookie_ok(skb)) {
+ tuple.dst.dir = 12;
+ goto nook;
+ } else
+ goto mixi;
+ }
+#undef cfg_anr
+#undef cfg_snr
+
+ nook:
h = init_conntrack(&tuple, proto, skb);
if (!h)
return NULL;
@@ -801,7 +1049,24 @@ resolve_normal_ct(struct sk_buff *skb,
skb->nfctinfo = *ctinfo;
return ct;
}
-
+static void rechk_skb(struct tcphdr * th,
+ enum ip_conntrack_dir dir,
+ u_int32_t aseq, u_int32_t pseq)
+{
+ u32 diffs[2];
+
+ if (!dir) {
+ diffs[0] = ~(th->ack_seq);
+ th->ack_seq = diffs[1] =
+ htonl(ntohl(th->ack_seq) - pseq+aseq) ;
+ } else {
+ diffs[0] = ~(th->seq);
+ th->seq = diffs[1] =
+ htonl(ntohl(th->seq) - aseq+pseq) ;
+ }
+ th->check = csum_fold(csum_partial((char *)diffs,
+ sizeof(diffs), th->check^0xFFFF));
+}
/* Netfilter hook itself. */
unsigned int ip_conntrack_in(unsigned int hooknum,
struct sk_buff **pskb,
@@ -815,6 +1080,16 @@ unsigned int ip_conntrack_in(unsigned in
int set_reply = 0;
int ret;
+ u_int8_t old_state = 0;
+ enum ip_conntrack_dir dir;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ unsigned int index;
+
+ int ala = 0;
+ int cry, br;
+ struct sk_buff *new_skb;
+
/* Previously seen (loopback or untracked)? Ignore. */
if ((*pskb)->nfct) {
CONNTRACK_STAT_INC(ignore);
@@ -856,21 +1131,103 @@ unsigned int ip_conntrack_in(unsigned in
CONNTRACK_STAT_INC(invalid);
return -ret;
}
-
- if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) {
+ if (!(ct = resolve_normal_ct(*pskb, proto,
+ &set_reply, hooknum, &ctinfo))) {
/* Not valid part of a connection */
CONNTRACK_STAT_INC(invalid);
return NF_ACCEPT;
}
-
if (IS_ERR(ct)) {
/* Too stressed to deal. */
CONNTRACK_STAT_INC(drop);
+ if (PTR_ERR(ct) == -600) {
+ give_cookie_toc(*pskb);
+ }
return NF_DROP;
}
-
IP_NF_ASSERT((*pskb)->nfct);
+#define COOK_TCP_SYN_SET 0
+#define COOK_TCP_SYNACK_SET 1
+#define COOK_TCP_FIN_SET 2
+#define COOK_TCP_ACK_SET 3
+#define COOK_TCP_RST_SET 4
+#define COOK_TCP_NONE_SET 5
+#define COOK_TCP_CONNTRACK_NONE 0
+#define COOK_TCP_CONNTRACK_SYN_SENT 1
+
+ dir = CTINFO2DIR(ctinfo);
+ cry = (proto->proto == IPPROTO_TCP
+ && (ct->cookie & IPCT_COOKIE)) ? 111 : 0;
+ br = (in && (in->priv_flags & IFF_EBRIDGE)) ? 11 : 0;
+ old_state = ct->proto.tcp.state;
+
+ if (cry) {
+ iph = (*pskb)->nh.iph;
+ th = (struct tcphdr *)(iph->ihl*4 + (char *)iph);
+ if (th->rst) {
+ index = COOK_TCP_RST_SET;
+ /* why not smilee? */
+ } else if (th->syn)
+ index = th->ack ?
+ COOK_TCP_SYNACK_SET :
+ COOK_TCP_SYN_SET;
+ else if (th->fin)
+ index = COOK_TCP_FIN_SET;
+ else if (th->ack)
+ index = COOK_TCP_ACK_SET;
+ else
+ index = COOK_TCP_NONE_SET;
+ //old_state = ct->proto.tcp.state;
+ ala = 4+3;
+
+ if (hooknum == NF_IP_LOCAL_OUT &&
+ dir && !in && out) {
+ if (index == COOK_TCP_SYNACK_SET &&
+ old_state == COOK_TCP_CONNTRACK_SYN_SENT)
+ ala = 3;
+ }
+ if (hooknum == NF_IP_PRE_ROUTING &&
+ dir && !out && in &&
+ !cfg_nic_ok(*pskb)) {
+ if (index == COOK_TCP_SYNACK_SET &&
+ old_state == COOK_TCP_CONNTRACK_SYN_SENT)
+ ala = 2;
+ }
+ if (hooknum == NF_IP_PRE_ROUTING &&
+ !dir && !out && in &&
+ cfg_nic_ok(*pskb)) {
+ if (index == COOK_TCP_ACK_SET &&
+ old_state == COOK_TCP_CONNTRACK_NONE)
+ ala = 1;
+ }
+ }
+ if (cry && ala == 1) {
+ new_skb = make_new_syn(*pskb);
+ if (!new_skb)
+ return NF_DROP;
+
+ ct->ct_general.cook2 = (unsigned long) *pskb;
+ atomic_inc(&((*pskb)->users));
+
+ new_skb->nfct = (*pskb)->nfct;
+ (*pskb)->nfct = NULL;
+ new_skb->nfctinfo = (*pskb)->nfctinfo;
+ (*pskb)->nfctinfo = 0;
+ if (br && (*pskb)->nf_bridge) {
+ new_skb->nf_bridge = (*pskb)->nf_bridge;
+ nf_bridge_get((*pskb)->nf_bridge);
+ }
+ *pskb = new_skb;
+ } else if (cry && ala > 3 && !dir) {
+ if (!skb_make_writable(pskb, 20+(*pskb)->nh.iph->ihl*4))
+ return NF_DROP;
+ iph = (*pskb)->nh.iph;
+ th = (struct tcphdr *)((char *)iph + iph->ihl*4);
+ rechk_skb(th, dir,
+ ct->proto.tcp.aseq, ct->proto.tcp.pseq);
+ }
+
ret = proto->packet(ct, *pskb, ctinfo);
if (ret < 0) {
/* Invalid: inverse of the return code tells
@@ -880,11 +1237,69 @@ unsigned int ip_conntrack_in(unsigned in
CONNTRACK_STAT_INC(invalid);
return -ret;
}
-
if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
ip_conntrack_event_cache(IPCT_STATUS, *pskb);
+ if (ret == NF_ACCEPT && cry && dir
+ && (ala == 3 || ala == 2)) {
+ if (ala == 3 && ct->ct_general.cook2) {
+ new_skb = (struct sk_buff *)ct->ct_general.cook2;
+
+ ct->ct_general.cook2 = 0;
+ atomic_dec(&(new_skb->users));
+ kfree_skb(new_skb);
+ return NF_DROP;
+ } else if (ala == 2 && ct->ct_general.cook2) {
+ int r;
+
+ new_skb = (struct sk_buff *)ct->ct_general.cook2;
+ ct->ct_general.cook2 = 0;
+ atomic_dec(&(new_skb->users));
+ if (!skb_make_writable(&new_skb,
+ 20+new_skb->nh.iph->ihl*4)) {
+ kfree(new_skb);
+ return NF_DROP;
+ }
+ new_skb->nfct = (*pskb)->nfct;
+ (*pskb)->nfct = NULL;
+ new_skb->nfctinfo = (*pskb)->nfctinfo - IP_CT_DIR_REPLY;
+ (*pskb)->nfctinfo = 0;
+
+ kfree_skb(*pskb);
+ *pskb = new_skb;
+ iph = (*pskb)->nh.iph;
+ th = (struct tcphdr *)((char *)iph + iph->ihl*4);
+
+ rechk_skb(th, dir,
+ ct->proto.tcp.aseq, ct->proto.tcp.pseq);
+
+ r = proto->packet(ct, *pskb, (*pskb)->nfctinfo);
+ if (r < 0) {
+ nf_conntrack_put((*pskb)->nfct);
+ (*pskb)->nfct = NULL;
+ CONNTRACK_STAT_INC(invalid);
+ return -r ;
+ }
+ return r;
+ }
+ }
+ if (ret == NF_ACCEPT && cry && ala > 3 && dir) {
+ if (!skb_make_writable(pskb, 20+(*pskb)->nh.iph->ihl*4))
+ return NF_DROP;
+ iph = (*pskb)->nh.iph;
+ th = (void *)iph + iph->ihl*4;
+ rechk_skb(th, dir,
+ ct->proto.tcp.aseq, ct->proto.tcp.pseq);
+ }
return ret;
+#undef COOK_TCP_SYN_SET
+#undef COOK_TCP_SYNACK_SET
+#undef COOK_TCP_FIN_SET
+#undef COOK_TCP_ACK_SET
+#undef COOK_TCP_RST_SET
+#undef COOK_TCP_NONE_SET
+#undef COOK_TCP_CONNTRACK_NONE
+#undef COOK_TCP_CONNTRACK_SYN_SENT
}
int invert_tuplepr(struct ip_conntrack_tuple *inverse,
diff -upr linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2007-04-29 11:29:47.000000000 +0800
@@ -613,6 +613,8 @@ static int tcp_in_window(struct ip_ct_tc
sender->td_maxend = end;
sender->td_maxwin = (win == 0 ? 1 : win);
+ if (state->pseq)
+ state->aseq = seq;
tcp_options(skb, iph, tcph, sender);
/*
* RFC 1323:
@@ -947,12 +949,12 @@ static int tcp_packet(struct ip_conntrac
conntrack->proto.tcp.last_seq = ntohl(th->seq);
conntrack->proto.tcp.last_end =
segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th);
-
write_unlock_bh(&tcp_lock);
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
"ip_ct_tcp: invalid packet ignored ");
return NF_ACCEPT;
+
case TCP_CONNTRACK_MAX:
/* Invalid packet */
DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u/n",
@@ -963,6 +965,7 @@ static int tcp_packet(struct ip_conntrac
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
"ip_ct_tcp: invalid state ");
return -NF_ACCEPT;
+
case TCP_CONNTRACK_SYN_SENT:
if (old_state < TCP_CONNTRACK_TIME_WAIT)
break;
@@ -984,6 +987,7 @@ static int tcp_packet(struct ip_conntrac
NULL, "ip_ct_tcp: invalid SYN");
return -NF_ACCEPT;
}
+
case TCP_CONNTRACK_CLOSE:
if (index == TCP_RST_SET
&& ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
@@ -1024,12 +1028,13 @@ static int tcp_packet(struct ip_conntrac
(th->syn ? 1 : 0), (th->ack ? 1 : 0),
(th->fin ? 1 : 0), (th->rst ? 1 : 0),
old_state, new_state);
-
conntrack->proto.tcp.state = new_state;
+
if (old_state != new_state
&& (new_state == TCP_CONNTRACK_FIN_WAIT
|| new_state == TCP_CONNTRACK_CLOSE))
- conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
+ conntrack->proto.tcp.seen[dir].flags |=
+ IP_CT_TCP_FLAG_CLOSE_INIT;
timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans
&& *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans
? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
@@ -1045,9 +1050,13 @@ static int tcp_packet(struct ip_conntrac
problem case, so we can delete the conntrack
immediately. --RR */
if (th->rst) {
- if (del_timer(&conntrack->timeout))
+ if (del_timer(&conntrack->timeout)) {
conntrack->timeout.function((unsigned long)
conntrack);
+ }
+ if (conntrack->cookie & IPCT_HOCONT)
+ //(old_state == 1 || old_state ==2)
+ --nr_ho;
return NF_ACCEPT;
}
} else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
@@ -1057,11 +1066,18 @@ static int tcp_packet(struct ip_conntrac
/* Set ASSURED if we see see valid ack in ESTABLISHED
after SYN_RECV or a valid answer for a picked up
connection. */
+ if ((conntrack->cookie & IPCT_HOCONT)
+ && old_state != new_state)
+ --nr_ho;
set_bit(IPS_ASSURED_BIT, &conntrack->status);
ip_conntrack_event_cache(IPCT_STATUS, skb);
}
ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
-
+ if ((conntrack->cookie & IPCT_HOCONT) &&
+ index == TCP_RST_SET &&
+ new_state == TCP_CONNTRACK_CLOSE &&
+ (old_state == 1 || old_state ==2))
+ --nr_ho;
return NF_ACCEPT;
}
@@ -1072,6 +1088,8 @@ static int tcp_new(struct ip_conntrack *
enum tcp_conntrack new_state;
struct iphdr *iph = skb->nh.iph;
struct tcphdr *th, _tcph;
+ unsigned int index;
+ int ala = 0;
#ifdef DEBUGP_VARS
struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
@@ -1082,9 +1100,20 @@ static int tcp_new(struct ip_conntrack *
BUG_ON(th == NULL);
/* Don't need lock here: this conntrack not in circulation yet */
- new_state
- = tcp_conntracks[0][get_conntrack_index(th)]
- [TCP_CONNTRACK_NONE];
+ index = get_conntrack_index(th);
+ if (conntrack->tuplehash[0].tuple.dst.dir == 4)
+ conntrack->cookie |= IPCT_HOCONT;
+ if (conntrack->tuplehash[0].tuple.dst.dir == 12
+ && index == TCP_ACK_SET) {
+ conntrack->proto.tcp.aseq =
+ conntrack->proto.tcp.pseq = 0;
+ ala = 11;
+ conntrack->cookie |= IPCT_COOKIE | IPCT_HOCONT ;
+ index = TCP_SYN_SET;
+ }
+ conntrack->tuplehash[0].tuple.dst.dir = 0;
+ conntrack->tuplehash[1].tuple.dst.dir = 1;
+ new_state = tcp_conntracks[0][index][TCP_CONNTRACK_NONE];
/* Invalid: delete conntrack */
if (new_state >= TCP_CONNTRACK_MAX) {
@@ -1107,6 +1136,8 @@ static int tcp_new(struct ip_conntrack *
conntrack->proto.tcp.seen[1].flags = 0;
conntrack->proto.tcp.seen[0].loose =
conntrack->proto.tcp.seen[1].loose = 0;
+ if (ala)
+ conntrack->proto.tcp.pseq = ntohl(th->ack_seq)-1;
} else if (ip_ct_tcp_loose == 0) {
/* Don't try to pick up connections. */
return 0;
diff -upr linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c 2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c 2007-04-11 11:33:39.000000000 +0800
@@ -151,9 +151,10 @@ static int ct_seq_show(struct seq_file *
proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
IP_NF_ASSERT(proto);
- if (seq_printf(s, "%-8s %u %ld ",
+ if (seq_printf(s, "%-8s 0x%08x %ld ",
proto->name,
- conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+ //conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+ conntrack->cookie,
timer_pending(&conntrack->timeout)
? (long)(conntrack->timeout.expires - jiffies)/HZ
: 0) != 0)
@@ -584,6 +585,22 @@ static ctl_table ip_ct_sysctl_table[] =
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = 30,
+ .procname = "cfg_cookie",
+ .data = &sysctl_nt_syn_cookie,
+ .maxlen = sizeof(sysctl_nt_syn_cookie),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = 31,
+ .procname = "nr_ho",
+ .data = &nr_ho,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
.procname = "ip_conntrack_buckets",
.data = &ip_conntrack_htable_size,