diff options
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_amanda.h | 8 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_core.h | 6 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_helper.h | 2 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_irc.h | 5 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_protocol.h | 15 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_amanda.c | 238 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_core.c | 81 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_ftp.c | 75 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_irc.c | 74 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_proto_generic.c | 14 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 18 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 61 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_proto_udp.c | 20 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_standalone.c | 8 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_tftp.c | 17 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_fw_compat_masq.c | 8 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_nat_core.c | 8 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_nat_tftp.c | 2 |
18 files changed, 301 insertions, 359 deletions
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h b/include/linux/netfilter_ipv4/ip_conntrack_amanda.h index 98f8e0df3467..50726ea6b641 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_amanda.h @@ -11,14 +11,6 @@ DECLARE_LOCK_EXTERN(ip_amanda_lock); #endif -struct conn { - char* match; - int matchlen; -}; - -#define NUM_MSGS 3 - - struct ip_ct_amanda_expect { u_int16_t port; /* port number of this expectation */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h index c46f0e86fe60..2a180c944193 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_core.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h @@ -24,9 +24,11 @@ extern struct list_head protocol_list; extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, unsigned int hooknum); -extern int get_tuple(const struct iphdr *iph, size_t len, +extern int get_tuple(const struct iphdr *iph, + const struct sk_buff *skb, + unsigned int dataoff, struct ip_conntrack_tuple *tuple, - struct ip_conntrack_protocol *protocol); + const struct ip_conntrack_protocol *protocol); /* Find a connection corresponding to a tuple. */ struct ip_conntrack_tuple_hash * diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h index d092a4fcb33b..997f09d81a92 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper.h @@ -25,7 +25,7 @@ struct ip_conntrack_helper /* Function to call when data passes; return verdict, or -1 to invalidate. */ - int (*help)(const struct iphdr *, size_t len, + int (*help)(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info conntrackinfo); }; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_irc.h b/include/linux/netfilter_ipv4/ip_conntrack_irc.h index 55571becc756..170248fa87bd 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_irc.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_irc.h @@ -37,11 +37,6 @@ struct ip_ct_irc_master { #define IRC_PORT 6667 -struct dccproto { - char* match; - int matchlen; -}; - /* Protects irc part of conntracks */ DECLARE_LOCK_EXTERN(ip_irc_lock); diff --git a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h index e99cd7ded26f..56e37ef255b7 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h @@ -14,9 +14,11 @@ struct ip_conntrack_protocol /* Protocol name */ const char *name; - /* Try to fill in the third arg; return true if possible. */ - int (*pkt_to_tuple)(const void *datah, size_t datalen, - struct ip_conntrack_tuple *tuple); + /* Try to fill in the third arg: dataoff is offset past IP + hdr. Return true if possible. */ + int (*pkt_to_tuple)(const struct sk_buff *skb, + unsigned int dataoff, + struct ip_conntrack_tuple *tuple); /* Invert the per-proto part of the tuple: ie. turn xmit into reply. * Some packets can't be inverted: return 0 in that case. @@ -34,20 +36,19 @@ struct ip_conntrack_protocol /* Returns verdict for packet, or -1 for invalid. */ int (*packet)(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len, + const struct sk_buff *skb, enum ip_conntrack_info ctinfo); /* Called when a new connection for this protocol found; * returns TRUE if it's OK. If so, packet() called next. */ - int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph, - size_t len); + int (*new)(struct ip_conntrack *conntrack, const struct sk_buff *skb); /* Called when a conntrack entry is destroyed */ void (*destroy)(struct ip_conntrack *conntrack); /* Has to decide if a expectation matches one packet or not */ int (*exp_matches_pkt)(struct ip_conntrack_expect *exp, - struct sk_buff **pskb); + const struct sk_buff *skb); /* Module (if any) which this is connected to. */ struct module *me; diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 453c1fb5b88b..1dbd17c6dc12 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -37,14 +37,8 @@ MODULE_PARM(master_timeout, "i"); MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); DECLARE_LOCK(ip_amanda_lock); -struct module *ip_conntrack_amanda = THIS_MODULE; -#define MAXMATCHLEN 6 -struct conn conns[NUM_MSGS] = { - {"DATA ", 5}, - {"MESG ", 5}, - {"INDEX ", 6}, -}; +char *conns[] = { "DATA ", "MESG ", "INDEX " }; #if 0 #define DEBUGP printk @@ -52,18 +46,15 @@ struct conn conns[NUM_MSGS] = { #define DEBUGP(format, args...) #endif +/* This is slow, but it's simple. --RR */ +static char amanda_buffer[65536]; -/* FIXME: This should be in userspace. Later. */ -static int help(const struct iphdr *iph, size_t len, +static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { - struct udphdr *udph = (void *)iph + iph->ihl * 4; - u_int32_t udplen = len - iph->ihl * 4; - u_int32_t datalen = udplen - sizeof(struct udphdr); - char *data = (char *)udph + sizeof(struct udphdr); - char *datap = data; - char *data_limit = (char *) data + datalen; + char *data, *data_limit; int dir = CTINFO2DIR(ctinfo); + unsigned int dataoff, i; struct ip_ct_amanda *info = (struct ip_ct_amanda *)&ct->help.ct_ftp_info; @@ -79,121 +70,121 @@ static int help(const struct iphdr *iph, size_t len, if (dir == IP_CT_DIR_ORIGINAL) return NF_ACCEPT; - /* Not whole UDP header? */ - if (udplen < sizeof(struct udphdr)) { - printk("ip_conntrack_amanda_help: udplen = %u\n", - (unsigned)udplen); + /* No data? */ + dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr); + if (dataoff >= skb->len) { + if (net_ratelimit()) + printk("ip_conntrack_amanda_help: skblen = %u\n", + (unsigned)skb->len); return NF_ACCEPT; } - /* Checksum invalid? Ignore. */ - if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, - csum_partial((char *)udph, udplen, 0))) { - DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u " - "%u.%u.%u.%u\n", - udph, udplen, NIPQUAD(iph->saddr), - NIPQUAD(iph->daddr)); - return NF_ACCEPT; - } - + LOCK_BH(&ip_amanda_lock); + skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff); + data = amanda_buffer; + data_limit = amanda_buffer + skb->len - dataoff; + *data_limit = '\0'; + /* Search for the CONNECT string */ - while (data < data_limit) { - if (!memcmp(data, "CONNECT ", 8)) { - break; - } - data++; - } - if (memcmp(data, "CONNECT ", 8)) - return NF_ACCEPT; + data = strstr(data, "CONNECT "); + if (!data) + goto out; DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection " "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n", NIPQUAD(iph->saddr), htons(udph->source), NIPQUAD(iph->daddr), htons(udph->dest)); - data += 8; - while (*data != 0x0a && data < data_limit) { - - int i; - - for (i = 0; i < NUM_MSGS; i++) { - if (!memcmp(data, conns[i].match, - conns[i].matchlen)) { - - char *portchr; - struct ip_conntrack_expect expect; - struct ip_ct_amanda_expect - *exp_amanda_info = - &expect.help.exp_amanda_info; - - memset(&expect, 0, sizeof(expect)); - - data += conns[i].matchlen; - /* this is not really tcp, but let's steal an - * idea from a tcp stream helper :-) + data += strlen("CONNECT "); + + /* Only search first line. */ + if (strchr(data, '\n')) + *strchr(data, '\n') = '\0'; + + for (i = 0; i < ARRAY_SIZE(conns); i++) { + char *match = strstr(data, conns[i]); + if (match) { + char *portchr; + struct ip_conntrack_expect expect; + struct ip_ct_amanda_expect *exp_amanda_info = + &expect.help.exp_amanda_info; + + memset(&expect, 0, sizeof(expect)); + + data += strlen(conns[i]); + /* this is not really tcp, but let's steal an + * idea from a tcp stream helper :-) */ + // XXX expect.seq = data - amanda_buffer; + exp_amanda_info->offset = data - amanda_buffer; +// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, amanda_buffer, expect.seq); +DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, amanda_buffer, exp_amanda_info->offset); + portchr = data; + exp_amanda_info->port = simple_strtoul(data, &data,10); + exp_amanda_info->len = data - portchr; + + /* eat whitespace */ + while (*data == ' ') + data++; + DEBUGP("ip_conntrack_amanda_help: " + "CONNECT %s request with port " + "%u found\n", conns[i], + exp_amanda_info->port); + + expect.tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, + { 0 } }, + { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, + { htons(exp_amanda_info->port) }, + IPPROTO_TCP }}); + expect.mask = ((struct ip_conntrack_tuple) + { { 0, { 0 } }, + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + + expect.expectfn = NULL; + + DEBUGP ("ip_conntrack_amanda_help: " + "expect_related: %u.%u.%u.%u:%u - " + "%u.%u.%u.%u:%u\n", + NIPQUAD(expect.tuple.src.ip), + ntohs(expect.tuple.src.u.tcp.port), + NIPQUAD(expect.tuple.dst.ip), + ntohs(expect.tuple.dst.u.tcp.port)); + if (ip_conntrack_expect_related(ct, &expect) + == -EEXIST) { + ; + /* this must be a packet being resent */ + /* XXX - how do I get the + * ip_conntrack_expect that + * already exists so that I can + * update the .seq so that the + * nat module rewrites the port + * numbers? + * Perhaps I should use the + * exp_amanda_info instead of + * .seq. */ - // XXX expect.seq = data - datap; - exp_amanda_info->offset = data - datap; -// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, datap, expect.seq); -DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, datap, exp_amanda_info->offset); - portchr = data; - exp_amanda_info->port = - simple_strtoul(data, &data, 10); - exp_amanda_info->len = data - portchr; - - /* eat whitespace */ - while (*data == ' ') - data++; - DEBUGP ("ip_conntrack_amanda_help: " - "CONNECT %s request with port " - "%u found\n", conns[i].match, - exp_amanda_info->port); - - LOCK_BH(&ip_amanda_lock); - - expect.tuple = ((struct ip_conntrack_tuple) - { { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, - { 0 } }, - { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, - { htons(exp_amanda_info->port) }, - IPPROTO_TCP }}); - expect.mask = ((struct ip_conntrack_tuple) - { { 0, { 0 } }, - { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); - - expect.expectfn = NULL; - - DEBUGP ("ip_conntrack_amanda_help: " - "expect_related: %u.%u.%u.%u:%u - " - "%u.%u.%u.%u:%u\n", - NIPQUAD(expect.tuple.src.ip), - ntohs(expect.tuple.src.u.tcp.port), - NIPQUAD(expect.tuple.dst.ip), - ntohs(expect.tuple.dst.u.tcp.port)); - if (ip_conntrack_expect_related(ct, &expect) == - -EEXIST) { - ; - /* this must be a packet being resent */ - /* XXX - how do I get the - * ip_conntrack_expect that - * already exists so that I can - * update the .seq so that the - * nat module rewrites the port - * numbers? - * Perhaps I should use the - * exp_amanda_info instead of - * .seq. - */ - } - UNLOCK_BH(&ip_amanda_lock); - } /* if memcmp(conns) */ - } /* for .. NUM_MSGS */ - data++; - } /* while (*data != 0x0a && data < data_limit) */ - + } + } + } + out: + UNLOCK_BH(&ip_amanda_lock); return NF_ACCEPT; } -static struct ip_conntrack_helper amanda_helper; +static struct ip_conntrack_helper amanda_helper = { + .max_expected = ARRAY_SIZE(conns), + .timeout = 180, + .flags = IP_CT_HELPER_F_REUSE_EXPECT, + .me = THIS_MODULE, + .help = help, + .name = "amanda", + + .tuple = { .src = { .u = { __constant_htons(10080) } }, + .dst = { .protonum = IPPROTO_UDP }, + }, + .mask = { .src = { .u = { 0xFFFF } }, + .dst = { .protonum = 0xFFFF }, + }, +}; static void fini(void) { @@ -205,20 +196,7 @@ static int __init init(void) { int ret; - memset(&amanda_helper, 0, sizeof(struct ip_conntrack_helper)); - amanda_helper.tuple.src.u.udp.port = htons(10080); - amanda_helper.tuple.dst.protonum = IPPROTO_UDP; - amanda_helper.mask.src.u.udp.port = 0xFFFF; - amanda_helper.mask.dst.protonum = 0xFFFF; - amanda_helper.max_expected = NUM_MSGS; - amanda_helper.timeout = 180; - amanda_helper.flags = IP_CT_HELPER_F_REUSE_EXPECT; - amanda_helper.me = ip_conntrack_amanda; - amanda_helper.help = help; - amanda_helper.name = "amanda"; - DEBUGP("ip_ct_amanda: registering helper for port 10080\n"); - ret = ip_conntrack_helper_register(&amanda_helper); if (ret) { diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 0996e894754f..f9eaf839d263 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -120,31 +120,25 @@ hash_conntrack(const struct ip_conntrack_tuple *tuple) % ip_conntrack_htable_size; } -inline int -get_tuple(const struct iphdr *iph, size_t len, +int +get_tuple(const struct iphdr *iph, + const struct sk_buff *skb, + unsigned int dataoff, struct ip_conntrack_tuple *tuple, - struct ip_conntrack_protocol *protocol) + const struct ip_conntrack_protocol *protocol) { - int ret; - /* Never happen */ if (iph->frag_off & htons(IP_OFFSET)) { printk("ip_conntrack_core: Frag of proto %u.\n", iph->protocol); return 0; } - /* Guarantee 8 protocol bytes: if more wanted, use len param */ - else if (iph->ihl * 4 + 8 > len) - return 0; tuple->src.ip = iph->saddr; tuple->dst.ip = iph->daddr; tuple->dst.protonum = iph->protocol; - ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl, - len - 4*iph->ihl, - tuple); - return ret; + return protocol->pkt_to_tuple(skb, dataoff, tuple); } static int @@ -496,54 +490,40 @@ icmp_error_track(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, unsigned int hooknum) { - const struct iphdr *iph; - struct icmphdr *hdr; struct ip_conntrack_tuple innertuple, origtuple; - struct iphdr *inner; - size_t datalen; + struct { + struct icmphdr icmp; + struct iphdr ip; + } inside; struct ip_conntrack_protocol *innerproto; struct ip_conntrack_tuple_hash *h; + int dataoff; - IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP); IP_NF_ASSERT(skb->nfct == NULL); - iph = skb->nh.iph; - hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl); - inner = (struct iphdr *)(hdr + 1); - datalen = skb->len - iph->ihl*4 - sizeof(*hdr); - - if (skb->len < iph->ihl * 4 + sizeof(*hdr) + sizeof(*iph)) { - DEBUGP("icmp_error_track: too short\n"); + /* Not enough header? */ + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0) return NULL; - } - if (hdr->type != ICMP_DEST_UNREACH - && hdr->type != ICMP_SOURCE_QUENCH - && hdr->type != ICMP_TIME_EXCEEDED - && hdr->type != ICMP_PARAMETERPROB - && hdr->type != ICMP_REDIRECT) + if (inside.icmp.type != ICMP_DEST_UNREACH + && inside.icmp.type != ICMP_SOURCE_QUENCH + && inside.icmp.type != ICMP_TIME_EXCEEDED + && inside.icmp.type != ICMP_PARAMETERPROB + && inside.icmp.type != ICMP_REDIRECT) return NULL; /* Ignore ICMP's containing fragments (shouldn't happen) */ - if (inner->frag_off & htons(IP_OFFSET)) { + if (inside.ip.frag_off & htons(IP_OFFSET)) { DEBUGP("icmp_error_track: fragment of proto %u\n", - inner->protocol); - return NULL; - } - - /* Ignore it if the checksum's bogus. */ - if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) { - DEBUGP("icmp_error_track: bad csum\n"); + inside.ip.protocol); return NULL; } - innerproto = ip_ct_find_proto(inner->protocol); + innerproto = ip_ct_find_proto(inside.ip.protocol); + dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4; /* Are they talking about one of our connections? */ - if (inner->ihl * 4 + 8 > datalen - || !get_tuple(inner, datalen, &origtuple, innerproto)) { - DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n", - inner->protocol, inner->ihl, 8, - datalen); + if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) { + DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol); return NULL; } @@ -679,7 +659,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, for (i=0; i < IP_CT_NUMBER; i++) conntrack->infos[i].master = &conntrack->ct_general; - if (!protocol->new(conntrack, skb->nh.iph, skb->len)) { + if (!protocol->new(conntrack, skb)) { kmem_cache_free(ip_conntrack_cachep, conntrack); return NULL; } @@ -748,7 +728,7 @@ resolve_normal_ct(struct sk_buff *skb, IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0); - if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto)) + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto)) return NULL; /* look for tuple match */ @@ -823,10 +803,6 @@ unsigned int ip_conntrack_in(unsigned int hooknum, if ((*pskb)->nfct) return NF_ACCEPT; - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - /* Gather fragments. */ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { *pskb = ip_ct_gather_frags(*pskb); @@ -851,7 +827,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum, IP_NF_ASSERT((*pskb)->nfct); - ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo); + ret = proto->packet(ct, *pskb, ctinfo); if (ret == -1) { /* Invalid */ nf_conntrack_put((*pskb)->nfct); @@ -860,8 +836,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum, } if (ret != NF_DROP && ct->helper) { - ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len, - ct, ctinfo); + ret = ct->helper->help(*pskb, ct, ctinfo); if (ret == -1) { /* Invalid */ nf_conntrack_put((*pskb)->nfct); diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index c9f148ac4e92..598b0a7e7c40 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -11,6 +11,9 @@ #include <linux/netfilter_ipv4/ip_conntrack_helper.h> #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> +/* This is slow, but it's simple. --RR */ +static char ftp_buffer[65536]; + DECLARE_LOCK(ip_ftp_lock); struct module *ip_conntrack_ftp = THIS_MODULE; @@ -228,18 +231,14 @@ static int find_pattern(const char *data, size_t dlen, return 1; } -/* FIXME: This should be in userspace. Later. */ -static int help(const struct iphdr *iph, size_t len, +static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { - /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ - struct tcphdr *tcph = (void *)iph + iph->ihl * 4; - const char *data = (const char *)tcph + tcph->doff * 4; - unsigned int tcplen = len - iph->ihl * 4; - unsigned int datalen = tcplen - tcph->doff * 4; + unsigned int dataoff, datalen; + struct tcphdr tcph; u_int32_t old_seq_aft_nl; - int old_seq_aft_nl_set; + int old_seq_aft_nl_set, ret; u_int32_t array[6] = { 0 }; int dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff; @@ -257,45 +256,42 @@ static int help(const struct iphdr *iph, size_t len, return NF_ACCEPT; } - /* Not whole TCP header? */ - if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) { - DEBUGP("ftp: tcplen = %u\n", (unsigned)tcplen); + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0) return NF_ACCEPT; - } - /* Checksum invalid? Ignore. */ - /* FIXME: Source route IP option packets --RR */ - if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, - csum_partial((char *)tcph, tcplen, 0))) { - DEBUGP("ftp_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", - tcph, tcplen, NIPQUAD(iph->saddr), - NIPQUAD(iph->daddr)); + dataoff = skb->nh.iph->ihl*4 + tcph.doff*4; + /* No data? */ + if (dataoff >= skb->len) { + DEBUGP("ftp: skblen = %u\n", skb->len); return NF_ACCEPT; } + datalen = skb->len - dataoff; LOCK_BH(&ip_ftp_lock); + skb_copy_bits(skb, dataoff, ftp_buffer, skb->len - dataoff); + old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir]; old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir]; DEBUGP("conntrack_ftp: datalen %u\n", datalen); - if ((datalen > 0) && (data[datalen-1] == '\n')) { + if (ftp_buffer[datalen - 1] == '\n') { DEBUGP("conntrack_ftp: datalen %u ends in \\n\n", datalen); if (!old_seq_aft_nl_set - || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) { + || after(ntohl(tcph.seq) + datalen, old_seq_aft_nl)) { DEBUGP("conntrack_ftp: updating nl to %u\n", - ntohl(tcph->seq) + datalen); + ntohl(tcph.seq) + datalen); ct_ftp_info->seq_aft_nl[dir] = - ntohl(tcph->seq) + datalen; + ntohl(tcph.seq) + datalen; ct_ftp_info->seq_aft_nl_set[dir] = 1; } } - UNLOCK_BH(&ip_ftp_lock); if(!old_seq_aft_nl_set || - (ntohl(tcph->seq) != old_seq_aft_nl)) { + (ntohl(tcph.seq) != old_seq_aft_nl)) { DEBUGP("ip_conntrack_ftp_help: wrong seq pos %s(%u)\n", old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl); - return NF_ACCEPT; + ret = NF_ACCEPT; + goto out; } /* Initialize IP array to expected address (it's not mentioned @@ -308,7 +304,7 @@ static int help(const struct iphdr *iph, size_t len, for (i = 0; i < sizeof(search) / sizeof(search[0]); i++) { if (search[i].dir != dir) continue; - found = find_pattern(data, datalen, + found = find_pattern(ftp_buffer, skb->len - dataoff, search[i].pattern, search[i].plen, search[i].skip, @@ -326,22 +322,24 @@ static int help(const struct iphdr *iph, size_t len, if (net_ratelimit()) printk("conntrack_ftp: partial %s %u+%u\n", search[i].pattern, - ntohl(tcph->seq), datalen); - return NF_DROP; - } else if (found == 0) /* No match */ - return NF_ACCEPT; + ntohl(tcph.seq), datalen); + ret = NF_DROP; + goto out; + } else if (found == 0) { /* No match */ + ret = NF_ACCEPT; + goto out; + } DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n", (int)matchlen, data + matchoff, - matchlen, ntohl(tcph->seq) + matchoff); + matchlen, ntohl(tcph.seq) + matchoff); memset(&expect, 0, sizeof(expect)); /* Update the ftp info */ - LOCK_BH(&ip_ftp_lock); if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) == ct->tuplehash[dir].tuple.src.ip) { - exp->seq = ntohl(tcph->seq) + matchoff; + exp->seq = ntohl(tcph.seq) + matchoff; exp_ftp_info->len = matchlen; exp_ftp_info->ftptype = search[i].ftptype; exp_ftp_info->port = array[4] << 8 | array[5]; @@ -358,7 +356,10 @@ static int help(const struct iphdr *iph, size_t len, <lincoln@cesar.org.br> for reporting this potential problem (DMZ machines opening holes to internal networks, or the packet filter itself). */ - if (!loose) goto out; + if (!loose) { + ret = NF_ACCEPT; + goto out; + } } exp->tuple = ((struct ip_conntrack_tuple) @@ -376,10 +377,10 @@ static int help(const struct iphdr *iph, size_t len, /* Ignore failure; should only happen with NAT */ ip_conntrack_expect_related(ct, &expect); + ret = NF_ACCEPT; out: UNLOCK_BH(&ip_ftp_lock); - - return NF_ACCEPT; + return ret; } static struct ip_conntrack_helper ftp[MAX_PORTS]; diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index ab4f6c0d8420..bedbf1ba60da 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -38,6 +38,8 @@ static int ports[MAX_PORTS]; static int ports_c = 0; static int max_dcc_channels = 8; static unsigned int dcc_timeout = 300; +/* This is slow, but it's simple. --RR */ +static char irc_buffer[65536]; MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); MODULE_DESCRIPTION("IRC (DCC) connection tracking module"); @@ -51,14 +53,7 @@ MODULE_PARM(dcc_timeout, "i"); MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); #endif -#define NUM_DCCPROTO 5 -struct dccproto dccprotos[NUM_DCCPROTO] = { - {"SEND ", 5}, - {"CHAT ", 5}, - {"MOVE ", 5}, - {"TSEND ", 6}, - {"SCHAT ", 6} -}; +static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; #define MAXMATCHLEN 6 DECLARE_LOCK(ip_irc_lock); @@ -102,18 +97,12 @@ int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port, return 0; } - -/* FIXME: This should be in userspace. Later. */ -static int help(const struct iphdr *iph, size_t len, +static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { - /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ - struct tcphdr *tcph = (void *) iph + iph->ihl * 4; - const char *data = (const char *) tcph + tcph->doff * 4; - const char *_data = data; - char *data_limit; - u_int32_t tcplen = len - iph->ihl * 4; - u_int32_t datalen = tcplen - tcph->doff * 4; + unsigned int dataoff; + struct tcphdr tcph; + char *data, *data_limit; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info; @@ -136,23 +125,20 @@ static int help(const struct iphdr *iph, size_t len, return NF_ACCEPT; } - /* Not whole TCP header? */ - if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { - DEBUGP("tcplen = %u\n", (unsigned) tcplen); + /* Not a full tcp header? */ + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0) return NF_ACCEPT; - } - /* Checksum invalid? Ignore. */ - /* FIXME: Source route IP option packets --RR */ - if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, - csum_partial((char *) tcph, tcplen, 0))) { - DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", - tcph, tcplen, NIPQUAD(iph->saddr), - NIPQUAD(iph->daddr)); + /* No data? */ + dataoff = skb->nh.iph->ihl*4 + tcph.doff*4; + if (dataoff >= skb->len) return NF_ACCEPT; - } - data_limit = (char *) data + datalen; + LOCK_BH(&ip_irc_lock); + skb_copy_bits(skb, dataoff, irc_buffer, skb->len - dataoff); + + data = irc_buffer; + data_limit = irc_buffer + skb->len - dataoff; while (data < (data_limit - (22 + MAXMATCHLEN))) { if (memcmp(data, "\1DCC ", 5)) { data++; @@ -162,19 +148,18 @@ static int help(const struct iphdr *iph, size_t len, data += 5; DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", - NIPQUAD(iph->saddr), ntohs(tcph->source), - NIPQUAD(iph->daddr), ntohs(tcph->dest)); + NIPQUAD(iph->saddr), ntohs(tcph.source), + NIPQUAD(iph->daddr), ntohs(tcph.dest)); - for (i = 0; i < NUM_DCCPROTO; i++) { - if (memcmp(data, dccprotos[i].match, - dccprotos[i].matchlen)) { + for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { + if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { /* no match */ continue; } - DEBUGP("DCC %s detected\n", dccprotos[i].match); - data += dccprotos[i].matchlen; - if (parse_dcc((char *) data, data_limit, &dcc_ip, + DEBUGP("DCC %s detected\n", dccprotos[i]); + data += strlen(dccprotos[i]); + if (parse_dcc((char *)data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { /* unable to parse */ DEBUGP("unable to parse dcc command\n"); @@ -196,12 +181,10 @@ static int help(const struct iphdr *iph, size_t len, memset(&expect, 0, sizeof(expect)); - LOCK_BH(&ip_irc_lock); - /* save position of address in dcc string, * necessary for NAT */ - DEBUGP("tcph->seq = %u\n", tcph->seq); - exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data); + DEBUGP("tcph->seq = %u\n", tcph.seq); + exp->seq = ntohl(tcph.seq) + (addr_beg_p - irc_buffer); exp_irc_info->len = (addr_end_p - addr_beg_p); exp_irc_info->port = dcc_port; DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n", @@ -224,12 +207,13 @@ static int help(const struct iphdr *iph, size_t len, ntohs(exp->tuple.dst.u.tcp.port)); ip_conntrack_expect_related(ct, &expect); - UNLOCK_BH(&ip_irc_lock); - return NF_ACCEPT; + goto out; } /* for .. NUM_DCCPROTO */ } /* while data < ... */ + out: + UNLOCK_BH(&ip_irc_lock); return NF_ACCEPT; } diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c index e5b399b26eba..74768998bd10 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c @@ -6,7 +6,8 @@ #define GENERIC_TIMEOUT (600*HZ) -static int generic_pkt_to_tuple(const void *datah, size_t datalen, +static int generic_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, struct ip_conntrack_tuple *tuple) { tuple->src.u.all = 0; @@ -39,17 +40,16 @@ static unsigned int generic_print_conntrack(char *buffer, } /* Returns verdict for packet, or -1 for invalid. */ -static int established(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len, - enum ip_conntrack_info conntrackinfo) +static int packet(struct ip_conntrack *conntrack, + const struct sk_buff *skb, + enum ip_conntrack_info conntrackinfo) { ip_ct_refresh(conntrack, GENERIC_TIMEOUT); return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ -static int -new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len) +static int new(struct ip_conntrack *conntrack, const struct sk_buff *skb) { return 1; } @@ -57,5 +57,5 @@ new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len) struct ip_conntrack_protocol ip_conntrack_generic_protocol = { { NULL, NULL }, 0, "unknown", generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple, - generic_print_conntrack, established, new, NULL, NULL, NULL }; + generic_print_conntrack, packet, new, NULL, NULL, NULL }; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index b72e1a8eeea6..e280eeba49a8 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c @@ -14,14 +14,18 @@ #define DEBUGP(format, args...) #endif -static int icmp_pkt_to_tuple(const void *datah, size_t datalen, +static int icmp_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, struct ip_conntrack_tuple *tuple) { - const struct icmphdr *hdr = datah; + struct icmphdr hdr; - tuple->dst.u.icmp.type = hdr->type; - tuple->src.u.icmp.id = hdr->un.echo.id; - tuple->dst.u.icmp.code = hdr->code; + if (skb_copy_bits(skb, dataoff, &hdr, sizeof(hdr)) != 0) + return 0; + + tuple->dst.u.icmp.type = hdr.type; + tuple->src.u.icmp.id = hdr.un.echo.id; + tuple->dst.u.icmp.code = hdr.code; return 1; } @@ -69,7 +73,7 @@ static unsigned int icmp_print_conntrack(char *buffer, /* Returns verdict for packet, or -1 for invalid. */ static int icmp_packet(struct ip_conntrack *ct, - struct iphdr *iph, size_t len, + const struct sk_buff *skb, enum ip_conntrack_info ctinfo) { /* Try to delete connection immediately after all replies: @@ -90,7 +94,7 @@ static int icmp_packet(struct ip_conntrack *ct, /* Called when a new connection for this protocol found. */ static int icmp_new(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len) + const struct sk_buff *skb) { static u_int8_t valid_new[] = { [ICMP_ECHO] = 1, diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 585806b4b11b..37e478dfb81f 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -96,13 +96,18 @@ static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] = { } }; -static int tcp_pkt_to_tuple(const void *datah, size_t datalen, - struct ip_conntrack_tuple *tuple) +static int tcp_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct ip_conntrack_tuple *tuple) { - const struct tcphdr *hdr = datah; + struct tcphdr hdr; - tuple->src.u.tcp.port = hdr->source; - tuple->dst.u.tcp.port = hdr->dest; + /* Actually only need first 8 bytes. */ + if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0) + return 0; + + tuple->src.u.tcp.port = hdr.source; + tuple->dst.u.tcp.port = hdr.dest; return 1; } @@ -148,30 +153,26 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph) /* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len, + const struct sk_buff *skb, enum ip_conntrack_info ctinfo) { enum tcp_conntrack newconntrack, oldtcpstate; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); + struct tcphdr tcph; - /* We're guaranteed to have the base header, but maybe not the - options. */ - if (len < (iph->ihl + tcph->doff) * 4) { - DEBUGP("ip_conntrack_tcp: Truncated packet.\n"); + if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0) return -1; - } WRITE_LOCK(&tcp_lock); oldtcpstate = conntrack->proto.tcp.state; newconntrack = tcp_conntracks [CTINFO2DIR(ctinfo)] - [get_conntrack_index(tcph)][oldtcpstate]; + [get_conntrack_index(&tcph)][oldtcpstate]; /* Invalid */ if (newconntrack == TCP_CONNTRACK_MAX) { DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n", - CTINFO2DIR(ctinfo), get_conntrack_index(tcph), + CTINFO2DIR(ctinfo), get_conntrack_index(&tcph), conntrack->proto.tcp.state); WRITE_UNLOCK(&tcp_lock); return -1; @@ -182,15 +183,15 @@ static int tcp_packet(struct ip_conntrack *conntrack, /* Poor man's window tracking: record SYN/ACK for handshake check */ if (oldtcpstate == TCP_CONNTRACK_SYN_SENT && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY - && tcph->syn && tcph->ack) + && tcph.syn && tcph.ack) conntrack->proto.tcp.handshake_ack - = htonl(ntohl(tcph->seq) + 1); + = htonl(ntohl(tcph.seq) + 1); /* If only reply is a RST, we can consider ourselves not to have an established connection: this is a fairly common problem case, so we can delete the conntrack immediately. --RR */ - if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) { + if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) { WRITE_UNLOCK(&tcp_lock); if (del_timer(&conntrack->timeout)) conntrack->timeout.function((unsigned long)conntrack); @@ -198,8 +199,8 @@ static int tcp_packet(struct ip_conntrack *conntrack, /* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */ if (oldtcpstate == TCP_CONNTRACK_SYN_RECV && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL - && tcph->ack && !tcph->syn - && tcph->ack_seq == conntrack->proto.tcp.handshake_ack) + && tcph.ack && !tcph.syn + && tcph.ack_seq == conntrack->proto.tcp.handshake_ack) set_bit(IPS_ASSURED_BIT, &conntrack->status); WRITE_UNLOCK(&tcp_lock); @@ -210,15 +211,17 @@ static int tcp_packet(struct ip_conntrack *conntrack, } /* Called when a new connection for this protocol found. */ -static int tcp_new(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len) +static int tcp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb) { enum tcp_conntrack newconntrack; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); + struct tcphdr tcph; + + if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0) + return -1; /* Don't need lock here: this conntrack not in circulation yet */ newconntrack - = tcp_conntracks[0][get_conntrack_index(tcph)] + = tcp_conntracks[0][get_conntrack_index(&tcph)] [TCP_CONNTRACK_NONE]; /* Invalid: delete conntrack */ @@ -232,15 +235,17 @@ static int tcp_new(struct ip_conntrack *conntrack, } static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp, - struct sk_buff **pskb) + const struct sk_buff *skb) { - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); + const struct iphdr *iph = skb->nh.iph; + struct tcphdr tcph; unsigned int datalen; - datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; + if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0) + return 0; + datalen = skb->len - iph->ihl*4 - tcph.doff*4; - return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); + return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen); } struct ip_conntrack_protocol ip_conntrack_protocol_tcp diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index bb4b8787d546..120f2c38e1a1 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -9,13 +9,18 @@ #define UDP_TIMEOUT (30*HZ) #define UDP_STREAM_TIMEOUT (180*HZ) -static int udp_pkt_to_tuple(const void *datah, size_t datalen, - struct ip_conntrack_tuple *tuple) +static int udp_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct ip_conntrack_tuple *tuple) { - const struct udphdr *hdr = datah; + struct udphdr hdr; - tuple->src.u.udp.port = hdr->source; - tuple->dst.u.udp.port = hdr->dest; + /* Actually only need first 8 bytes. */ + if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0) + return 0; + + tuple->src.u.udp.port = hdr.source; + tuple->dst.u.udp.port = hdr.dest; return 1; } @@ -46,7 +51,7 @@ static unsigned int udp_print_conntrack(char *buffer, /* Returns verdict for packet, and may modify conntracktype */ static int udp_packet(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len, + const struct sk_buff *skb, enum ip_conntrack_info conntrackinfo) { /* If we've seen traffic both ways, this is some kind of UDP @@ -62,8 +67,7 @@ static int udp_packet(struct ip_conntrack *conntrack, } /* Called when a new connection for this protocol found. */ -static int udp_new(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len) +static int udp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb) { return 1; } diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 62ff76044b01..c939c329ecf1 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -192,10 +192,6 @@ static unsigned int ip_refrag(unsigned int hooknum, { struct rtable *rt = (struct rtable *)(*pskb)->dst; - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - /* We've seen it coming out the other side: confirm */ if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT) return NF_DROP; @@ -217,10 +213,6 @@ static unsigned int ip_conntrack_local(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) { diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index f75910aa0652..2bd9c4b1dea3 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c @@ -35,15 +35,18 @@ MODULE_PARM_DESC(ports, "port numbers of tftp servers"); #define DEBUGP(format, args...) #endif -static int tftp_help(const struct iphdr *iph, size_t len, - struct ip_conntrack *ct, - enum ip_conntrack_info ctinfo) +static int tftp_help(struct sk_buff *skb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) { - struct udphdr *udph = (void *)iph + iph->ihl * 4; - struct tftphdr *tftph = (void *)udph + 8; + struct tftphdr tftph; struct ip_conntrack_expect exp; - - switch (ntohs(tftph->opcode)) { + + if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr), + &tftph, sizeof(tftph)) != 0) + return -1; + + switch (ntohs(tftph.opcode)) { /* RRQ and WRQ works the same way */ case TFTP_OPCODE_READ: case TFTP_OPCODE_WRITE: diff --git a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c index f522eab4038b..d65adf334696 100644 --- a/net/ipv4/netfilter/ip_fw_compat_masq.c +++ b/net/ipv4/netfilter/ip_fw_compat_masq.c @@ -146,6 +146,12 @@ check_for_demasq(struct sk_buff **pskb) server here (== DNAT). Do SNAT icmp manips in POST_ROUTING handling. */ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { + /* FIXME: Remove once NAT handled non-linear. + */ + if (skb_is_nonlinear(*pskb) + && skb_linearize(*pskb, GFP_ATOMIC) != 0) + return NF_DROP; + icmp_reply_translation(*pskb, ct, NF_IP_PRE_ROUTING, CTINFO2DIR(ctinfo)); @@ -160,7 +166,7 @@ check_for_demasq(struct sk_buff **pskb) case IPPROTO_UDP: IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0); - if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) { + if (!get_tuple(iph, *pskb, iph->ihl*4, &tuple, protocol)) { if (net_ratelimit()) printk("ip_fw_compat_masq: Can't get tuple\n"); return NF_ACCEPT; diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 08e0b66b6541..5065e4349dd3 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -730,15 +730,15 @@ manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len, } static inline int exp_for_packet(struct ip_conntrack_expect *exp, - struct sk_buff **pskb) + struct sk_buff *skb) { struct ip_conntrack_protocol *proto; int ret = 1; MUST_BE_READ_LOCKED(&ip_conntrack_lock); - proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol); + proto = __ip_ct_find_proto(skb->nh.iph->protocol); if (proto->exp_matches_pkt) - ret = proto->exp_matches_pkt(exp, pskb); + ret = proto->exp_matches_pkt(exp, skb); return ret; } @@ -813,7 +813,7 @@ do_bindings(struct ip_conntrack *ct, if (exp->sibling) continue; - if (exp_for_packet(exp, pskb)) { + if (exp_for_packet(exp, *pskb)) { /* FIXME: May be true multiple times in the case of UDP!! */ DEBUGP("calling nat helper (exp=%p) for packet\n", exp); diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c index 70a6fb4d346a..bce0f40fd974 100644 --- a/net/ipv4/netfilter/ip_nat_tftp.c +++ b/net/ipv4/netfilter/ip_nat_tftp.c @@ -153,7 +153,7 @@ static void fini(void) static int __init init(void) { - int i, ret; + int i, ret = 0; char *tmpname; if (!ports[0]) |
