Commit 11bde9b1 authored by David S. Miller's avatar David S. Miller

Merge bk://212.42.230.204/nf-2.6

into nuts.davemloft.net:/disk1/BK/net-2.6
parents c3efef68 d110bbcc
...@@ -355,13 +355,15 @@ struct ip6t_match ...@@ -355,13 +355,15 @@ struct ip6t_match
/* Return true or false: return FALSE and set *hotdrop = 1 to /* Return true or false: return FALSE and set *hotdrop = 1 to
force immediate packet drop. */ force immediate packet drop. */
/* Arguments changed since 2.6.9, as this must now handle
non-linear skb, using skb_header_pointer and
skb_ip_make_writable. */
int (*match)(const struct sk_buff *skb, int (*match)(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop); int *hotdrop);
/* Called when user tries to insert an entry of this type. */ /* Called when user tries to insert an entry of this type. */
...@@ -386,11 +388,13 @@ struct ip6t_target ...@@ -386,11 +388,13 @@ struct ip6t_target
const char name[IP6T_FUNCTION_MAXNAMELEN]; const char name[IP6T_FUNCTION_MAXNAMELEN];
/* Returns verdict. */ /* Returns verdict. Argument order changed since 2.6.9, as this
must now handle non-linear skbs, using skb_copy_bits and
skb_ip_make_writable. */
unsigned int (*target)(struct sk_buff **pskb, unsigned int (*target)(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userdata); void *userdata);
......
...@@ -352,16 +352,14 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, ...@@ -352,16 +352,14 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
{ {
struct ip_conntrack_tuple_hash *h; struct ip_conntrack_tuple_hash *h;
unsigned int hash = hash_conntrack(tuple); unsigned int hash = hash_conntrack(tuple);
/* use per_cpu() to avoid multiple calls to smp_processor_id() */
unsigned int cpu = smp_processor_id();
MUST_BE_READ_LOCKED(&ip_conntrack_lock); MUST_BE_READ_LOCKED(&ip_conntrack_lock);
list_for_each_entry(h, &ip_conntrack_hash[hash], list) { list_for_each_entry(h, &ip_conntrack_hash[hash], list) {
if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) {
per_cpu(ip_conntrack_stat, cpu).found++; CONNTRACK_STAT_INC(found);
return h; return h;
} }
per_cpu(ip_conntrack_stat, cpu).searched++; CONNTRACK_STAT_INC(searched);
} }
return NULL; return NULL;
...@@ -436,13 +434,14 @@ __ip_conntrack_confirm(struct sk_buff *skb) ...@@ -436,13 +434,14 @@ __ip_conntrack_confirm(struct sk_buff *skb)
add_timer(&ct->timeout); add_timer(&ct->timeout);
atomic_inc(&ct->ct_general.use); atomic_inc(&ct->ct_general.use);
set_bit(IPS_CONFIRMED_BIT, &ct->status); set_bit(IPS_CONFIRMED_BIT, &ct->status);
WRITE_UNLOCK(&ip_conntrack_lock);
CONNTRACK_STAT_INC(insert); CONNTRACK_STAT_INC(insert);
WRITE_UNLOCK(&ip_conntrack_lock);
return NF_ACCEPT; return NF_ACCEPT;
} }
WRITE_UNLOCK(&ip_conntrack_lock);
CONNTRACK_STAT_INC(insert_failed); CONNTRACK_STAT_INC(insert_failed);
WRITE_UNLOCK(&ip_conntrack_lock);
return NF_DROP; return NF_DROP;
} }
......
...@@ -60,7 +60,7 @@ target(struct sk_buff **pskb, ...@@ -60,7 +60,7 @@ target(struct sk_buff **pskb,
break; break;
case IPT_CONNMARK_RESTORE: case IPT_CONNMARK_RESTORE:
nfmark = (*pskb)->nfmark; nfmark = (*pskb)->nfmark;
diff = (ct->mark ^ nfmark & markinfo->mask); diff = (ct->mark ^ nfmark) & markinfo->mask;
if (diff != 0) { if (diff != 0) {
(*pskb)->nfmark = nfmark ^ diff; (*pskb)->nfmark = nfmark ^ diff;
(*pskb)->nfcache |= NFC_ALTERED; (*pskb)->nfcache |= NFC_ALTERED;
......
...@@ -81,8 +81,8 @@ masquerade_target(struct sk_buff **pskb, ...@@ -81,8 +81,8 @@ masquerade_target(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
const struct ip_nat_multi_range *mr; const struct ip_nat_multi_range *mr;
struct ip_nat_multi_range newrange; struct ip_nat_multi_range newrange;
u_int32_t newsrc;
struct rtable *rt; struct rtable *rt;
u_int32_t newsrc;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
...@@ -96,36 +96,13 @@ masquerade_target(struct sk_buff **pskb, ...@@ -96,36 +96,13 @@ masquerade_target(struct sk_buff **pskb,
|| ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
mr = targinfo; mr = targinfo;
rt = (struct rtable *)(*pskb)->dst;
{ newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
struct flowi fl = { .nl_u = { .ip4_u = if (!newsrc) {
{ .daddr = (*pskb)->nh.iph->daddr, printk("MASQUERADE: %s ate my IP address\n", out->name);
.tos = (RT_TOS((*pskb)->nh.iph->tos) | return NF_DROP;
RTO_CONN),
#ifdef CONFIG_IP_ROUTE_FWMARK
.fwmark = (*pskb)->nfmark
#endif
} } };
if (ip_route_output_key(&rt, &fl) != 0) {
/* Funky routing can do this. */
if (net_ratelimit())
printk("MASQUERADE:"
" No route: Rusty's brain broke!\n");
return NF_DROP;
}
if (rt->u.dst.dev != out) {
if (net_ratelimit())
printk("MASQUERADE:"
" Route sent us somewhere else.\n");
ip_rt_put(rt);
return NF_DROP;
}
} }
newsrc = rt->rt_src;
DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
ip_rt_put(rt);
WRITE_LOCK(&masq_lock); WRITE_LOCK(&masq_lock);
ct->nat.masq_index = out->ifindex; ct->nat.masq_index = out->ifindex;
WRITE_UNLOCK(&masq_lock); WRITE_UNLOCK(&masq_lock);
...@@ -157,6 +134,18 @@ device_cmp(const struct ip_conntrack *i, void *_ina) ...@@ -157,6 +134,18 @@ device_cmp(const struct ip_conntrack *i, void *_ina)
return ret; return ret;
} }
static inline int
connect_unassure(const struct ip_conntrack *i, void *_ina)
{
struct in_ifaddr *ina = _ina;
/* We reset the ASSURED bit on all connections, so they will
* get reaped under memory pressure. */
if (i->nat.masq_index == ina->ifa_dev->dev->ifindex)
clear_bit(IPS_ASSURED_BIT, (unsigned long *)&i->status);
return 0;
}
static int masq_inet_event(struct notifier_block *this, static int masq_inet_event(struct notifier_block *this,
unsigned long event, unsigned long event,
void *ptr) void *ptr)
...@@ -166,6 +155,8 @@ static int masq_inet_event(struct notifier_block *this, ...@@ -166,6 +155,8 @@ static int masq_inet_event(struct notifier_block *this,
* entries. */ * entries. */
if (event == NETDEV_UP) if (event == NETDEV_UP)
ip_ct_selective_cleanup(device_cmp, ptr); ip_ct_selective_cleanup(device_cmp, ptr);
else if (event == NETDEV_DOWN)
ip_ct_selective_cleanup(connect_unassure, ptr);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -20,9 +20,9 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); ...@@ -20,9 +20,9 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
static unsigned int static unsigned int
target(struct sk_buff **pskb, target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
......
...@@ -31,12 +31,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); ...@@ -31,12 +31,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
static inline int static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{ {
int r=0; int r=0;
DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max); min,spi,max);
r=(spi >= min && spi <= max) ^ invert; r = (spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r; return r;
} }
static int static int
...@@ -45,125 +45,124 @@ match(const struct sk_buff *skb, ...@@ -45,125 +45,124 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct ip_auth_hdr *ah = NULL; struct ip_auth_hdr *ah = NULL, _ah;
const struct ip6t_ah *ahinfo = matchinfo; const struct ip6t_ah *ahinfo = matchinfo;
unsigned int temp; unsigned int temp;
int len; int len;
u8 nexthdr; u8 nexthdr;
unsigned int ptr; unsigned int ptr;
unsigned int hdrlen = 0; unsigned int hdrlen = 0;
/*DEBUGP("IPv6 AH entered\n");*/ /*DEBUGP("IPv6 AH entered\n");*/
/* if (opt->auth == 0) return 0; /* if (opt->auth == 0) return 0;
* It does not filled on output */ * It does not filled on output */
/* type of the 1st exthdr */ /* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr; nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */ /* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr); ptr = sizeof(struct ipv6hdr);
/* available length */ /* available length */
len = skb->len - ptr; len = skb->len - ptr;
temp = 0; temp = 0;
while (ip6t_ext_hdr(nexthdr)) { while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr; struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_ah header iteration \n"); DEBUGP("ipv6_ah header iteration \n");
/* Is there enough space for the next ext header? */ /* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr)) if (len < sizeof(struct ipv6_opt_hdr))
return 0; return 0;
/* No more exthdr -> evaluate */ /* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) { if (nexthdr == NEXTHDR_NONE)
break; break;
} /* ESP -> evaluate */
/* ESP -> evaluate */ if (nexthdr == NEXTHDR_ESP)
if (nexthdr == NEXTHDR_ESP) { break;
break;
} hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
/* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT)
if (nexthdr == NEXTHDR_FRAGMENT) { hdrlen = 8;
hdrlen = 8; else if (nexthdr == NEXTHDR_AUTH)
} else if (nexthdr == NEXTHDR_AUTH) hdrlen = (hp->hdrlen+2)<<2;
hdrlen = (hdr->hdrlen+2)<<2; else
else hdrlen = ipv6_optlen(hp);
hdrlen = ipv6_optlen(hdr);
/* AH -> evaluate */
/* AH -> evaluate */ if (nexthdr == NEXTHDR_AUTH) {
if (nexthdr == NEXTHDR_AUTH) { temp |= MASK_AH;
temp |= MASK_AH; break;
break; }
}
/* set the flag */
/* set the flag */ switch (nexthdr) {
switch (nexthdr){ case NEXTHDR_HOP:
case NEXTHDR_HOP: case NEXTHDR_ROUTING:
case NEXTHDR_ROUTING: case NEXTHDR_FRAGMENT:
case NEXTHDR_FRAGMENT: case NEXTHDR_AUTH:
case NEXTHDR_AUTH: case NEXTHDR_DEST:
case NEXTHDR_DEST: break;
break; default:
default: DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr); return 0;
return 0; }
break;
} nexthdr = hp->nexthdr;
len -= hdrlen;
nexthdr = hdr->nexthdr; ptr += hdrlen;
len -= hdrlen; if (ptr > skb->len) {
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_ah: new pointer too large! \n"); DEBUGP("ipv6_ah: new pointer too large! \n");
break; break;
} }
} }
/* AH header not found */ /* AH header not found */
if ( temp != MASK_AH ) return 0; if (temp != MASK_AH)
return 0;
if (len < (int)sizeof(struct ip_auth_hdr)){
*hotdrop = 1; if (len < sizeof(struct ip_auth_hdr)){
return 0; *hotdrop = 1;
} return 0;
}
ah = (struct ip_auth_hdr *) (skb->data + ptr);
ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); BUG_ON(ah == NULL);
DEBUGP("RES %04X ", ah->reserved);
DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
DEBUGP("RES %04X ", ah->reserved);
DEBUGP("IPv6 AH spi %02X ", DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi), DEBUGP("IPv6 AH spi %02X ",
!!(ahinfo->invflags & IP6T_AH_INV_SPI)))); (spi_match(ahinfo->spis[0], ahinfo->spis[1],
DEBUGP("len %02X %04X %02X ", ntohl(ah->spi),
ahinfo->hdrlen, hdrlen, !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
(!ahinfo->hdrlen || DEBUGP("len %02X %04X %02X ",
(ahinfo->hdrlen == hdrlen) ^ ahinfo->hdrlen, hdrlen,
!!(ahinfo->invflags & IP6T_AH_INV_LEN))); (!ahinfo->hdrlen ||
DEBUGP("res %02X %04X %02X\n", (ahinfo->hdrlen == hdrlen) ^
ahinfo->hdrres, ah->reserved, !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
!(ahinfo->hdrres && ah->reserved)); DEBUGP("res %02X %04X %02X\n",
ahinfo->hdrres, ah->reserved,
return (ah != NULL) !(ahinfo->hdrres && ah->reserved));
&&
(spi_match(ahinfo->spis[0], ahinfo->spis[1], return (ah != NULL)
ntohl(ah->spi), &&
!!(ahinfo->invflags & IP6T_AH_INV_SPI))) (spi_match(ahinfo->spis[0], ahinfo->spis[1],
&& ntohl(ah->spi),
(!ahinfo->hdrlen || !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
(ahinfo->hdrlen == hdrlen) ^ &&
!!(ahinfo->invflags & IP6T_AH_INV_LEN)) (!ahinfo->hdrlen ||
&& (ahinfo->hdrlen == hdrlen) ^
!(ahinfo->hdrres && ah->reserved); !!(ahinfo->invflags & IP6T_AH_INV_LEN))
&&
!(ahinfo->hdrres && ah->reserved);
} }
/* Called when user tries to insert an entry of this type. */ /* Called when user tries to insert an entry of this type. */
...@@ -174,20 +173,18 @@ checkentry(const char *tablename, ...@@ -174,20 +173,18 @@ checkentry(const char *tablename,
unsigned int matchinfosize, unsigned int matchinfosize,
unsigned int hook_mask) unsigned int hook_mask)
{ {
const struct ip6t_ah *ahinfo = matchinfo; const struct ip6t_ah *ahinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) { if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
DEBUGP("ip6t_ah: matchsize %u != %u\n", DEBUGP("ip6t_ah: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah))); matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
return 0; return 0;
} }
if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
DEBUGP("ip6t_ah: unknown flags %X\n", DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
ahinfo->invflags); return 0;
return 0; }
} return 1;
return 1;
} }
static struct ip6t_match ah_match = { static struct ip6t_match ah_match = {
...@@ -199,12 +196,12 @@ static struct ip6t_match ah_match = { ...@@ -199,12 +196,12 @@ static struct ip6t_match ah_match = {
static int __init init(void) static int __init init(void)
{ {
return ip6t_register_match(&ah_match); return ip6t_register_match(&ah_match);
} }
static void __exit cleanup(void) static void __exit cleanup(void)
{ {
ip6t_unregister_match(&ah_match); ip6t_unregister_match(&ah_match);
} }
module_init(init); module_init(init);
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
...@@ -20,8 +19,6 @@ ...@@ -20,8 +19,6 @@
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h> #include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 0 #define HOPBYHOP 0
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -48,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); ...@@ -48,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
* 0 -> invariant * 0 -> invariant
* 1 -> can change the routing * 1 -> can change the routing
* (Type & 0x1F) Type * (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!) * 0 -> Pad1 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2) * 1 -> PadN LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x * 5 -> RTALERT 2 x x
*/ */
...@@ -60,11 +57,10 @@ match(const struct sk_buff *skb, ...@@ -60,11 +57,10 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct ipv6_opt_hdr *optsh = NULL; struct ipv6_opt_hdr _optsh, *oh;
const struct ip6t_opts *optinfo = matchinfo; const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp; unsigned int temp;
unsigned int len; unsigned int len;
...@@ -72,7 +68,9 @@ match(const struct sk_buff *skb, ...@@ -72,7 +68,9 @@ match(const struct sk_buff *skb,
unsigned int ptr; unsigned int ptr;
unsigned int hdrlen = 0; unsigned int hdrlen = 0;
unsigned int ret = 0; unsigned int ret = 0;
u_int16_t *optdesc = NULL; u8 _opttype, *tp = NULL;
u8 _optlen, *lp = NULL;
unsigned int optlen;
/* type of the 1st exthdr */ /* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr; nexthdr = skb->nh.ipv6h->nexthdr;
...@@ -83,7 +81,7 @@ match(const struct sk_buff *skb, ...@@ -83,7 +81,7 @@ match(const struct sk_buff *skb,
temp = 0; temp = 0;
while (ip6t_ext_hdr(nexthdr)) { while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr; struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_opts header iteration \n"); DEBUGP("ipv6_opts header iteration \n");
...@@ -99,15 +97,16 @@ match(const struct sk_buff *skb, ...@@ -99,15 +97,16 @@ match(const struct sk_buff *skb,
break; break;
} }
hdr=(void *)(skb->data)+ptr; hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */ /* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8; hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH) } else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2; hdrlen = (hp->hdrlen+2)<<2;
else else
hdrlen = ipv6_optlen(hdr); hdrlen = ipv6_optlen(hp);
/* OPTS -> evaluate */ /* OPTS -> evaluate */
#if HOPBYHOP #if HOPBYHOP
...@@ -135,7 +134,7 @@ match(const struct sk_buff *skb, ...@@ -135,7 +134,7 @@ match(const struct sk_buff *skb,
break; break;
} }
nexthdr = hdr->nexthdr; nexthdr = hp->nexthdr;
len -= hdrlen; len -= hdrlen;
ptr += hdrlen; ptr += hdrlen;
if ( ptr > skb->len ) { if ( ptr > skb->len ) {
...@@ -161,9 +160,10 @@ match(const struct sk_buff *skb, ...@@ -161,9 +160,10 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
optsh=(void *)(skb->data)+ptr; oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
BUG_ON(oh == NULL);
DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
DEBUGP("len %02X %04X %02X ", DEBUGP("len %02X %04X %02X ",
optinfo->hdrlen, hdrlen, optinfo->hdrlen, hdrlen,
...@@ -171,13 +171,12 @@ match(const struct sk_buff *skb, ...@@ -171,13 +171,12 @@ match(const struct sk_buff *skb,
((optinfo->hdrlen == hdrlen) ^ ((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (optsh != NULL) ret = (oh != NULL)
&& &&
(!(optinfo->flags & IP6T_OPTS_LEN) || (!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^ ((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))); !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2; ptr += 2;
hdrlen -= 2; hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
...@@ -188,48 +187,59 @@ match(const struct sk_buff *skb, ...@@ -188,48 +187,59 @@ match(const struct sk_buff *skb,
DEBUGP("Strict "); DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr); DEBUGP("#%d ",optinfo->optsnr);
for(temp=0; temp<optinfo->optsnr; temp++){ for(temp=0; temp<optinfo->optsnr; temp++){
optdesc = (void *)(skb->data)+ptr; /* type field exists ? */
if (hdrlen < 1)
break;
tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
&_opttype);
if (tp == NULL)
break;
/* Type check */ /* Type check */
if ( (unsigned char)*optdesc != if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){
(optinfo->opts[temp] & 0xFF00)>>8 ){
DEBUGP("Tbad %02X %02X\n", DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc, *tp,
(optinfo->opts[temp] & (optinfo->opts[temp] & 0xFF00)>>8);
0xFF00)>>8);
return 0; return 0;
} else { } else {
DEBUGP("Tok "); DEBUGP("Tok ");
} }
/* Length check */ /* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && if (*tp) {
(unsigned char)*optdesc != 0){ u16 spec_len;
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){ /* length field exists ? */
DEBUGP("Lbad %02X %04X %04X\n", if (hdrlen < 2)
(unsigned char)*optdesc, break;
ntohs((u16)*optdesc), lp = skb_header_pointer(skb, ptr + 1,
optinfo->opts[temp]); sizeof(_optlen),
&_optlen);
if (lp == NULL)
break;
spec_len = optinfo->opts[temp] & 0x00FF;
if (spec_len != 0x00FF && spec_len != *lp) {
DEBUGP("Lbad %02X %04X\n", *lp,
spec_len);
return 0; return 0;
} else {
DEBUGP("Lok ");
} }
} DEBUGP("Lok ");
/* Step to the next */ optlen = *lp + 2;
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
} else { } else {
ptr += LOW(ntohs(*optdesc)); DEBUGP("Pad1\n");
hdrlen -= LOW(ntohs(*optdesc)); optlen = 1;
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
} }
if (ptr > skb->len || ( !hdrlen &&
(temp != optinfo->optsnr - 1))) { /* Step to the next */
DEBUGP("len%04X \n", optlen);
if ((ptr > skb->len - optlen || hdrlen < optlen) &&
(temp < optinfo->optsnr - 1)) {
DEBUGP("new pointer is too large! \n"); DEBUGP("new pointer is too large! \n");
break; break;
} }
ptr += optlen;
hdrlen -= optlen;
} }
if (temp == optinfo->optsnr) if (temp == optinfo->optsnr)
return ret; return ret;
...@@ -271,6 +281,7 @@ static struct ip6t_match opts_match = { ...@@ -271,6 +281,7 @@ static struct ip6t_match opts_match = {
#endif #endif
.match = &match, .match = &match,
.checkentry = &checkentry, .checkentry = &checkentry,
.me = THIS_MODULE,
}; };
static int __init init(void) static int __init init(void)
......
...@@ -32,8 +32,8 @@ static inline int ...@@ -32,8 +32,8 @@ static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{ {
int r=0; int r=0;
DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max); min,spi,max);
r=(spi >= min && spi <= max) ^ invert; r=(spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n"); DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r; return r;
...@@ -45,11 +45,10 @@ match(const struct sk_buff *skb, ...@@ -45,11 +45,10 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct ip_esp_hdr *esp = NULL; struct ip_esp_hdr _esp, *eh = NULL;
const struct ip6t_esp *espinfo = matchinfo; const struct ip6t_esp *espinfo = matchinfo;
unsigned int temp; unsigned int temp;
int len; int len;
...@@ -67,73 +66,74 @@ match(const struct sk_buff *skb, ...@@ -67,73 +66,74 @@ match(const struct sk_buff *skb,
len = skb->len - ptr; len = skb->len - ptr;
temp = 0; temp = 0;
while (ip6t_ext_hdr(nexthdr)) { while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr; struct ipv6_opt_hdr _hdr, *hp;
int hdrlen; int hdrlen;
DEBUGP("ipv6_esp header iteration \n"); DEBUGP("ipv6_esp header iteration \n");
/* Is there enough space for the next ext header? */ /* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr)) if (len < sizeof(struct ipv6_opt_hdr))
return 0; return 0;
/* No more exthdr -> evaluate */ /* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) { if (nexthdr == NEXTHDR_NONE)
break; break;
}
/* ESP -> evaluate */ /* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) { if (nexthdr == NEXTHDR_ESP) {
temp |= MASK_ESP; temp |= MASK_ESP;
break; break;
} }
hdr=(struct ipv6_opt_hdr *)skb->data+ptr; hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */ /* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT)
hdrlen = 8; hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH) else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2; hdrlen = (hp->hdrlen+2)<<2;
else else
hdrlen = ipv6_optlen(hdr); hdrlen = ipv6_optlen(hp);
/* set the flag */ /* set the flag */
switch (nexthdr){ switch (nexthdr) {
case NEXTHDR_HOP: case NEXTHDR_HOP:
case NEXTHDR_ROUTING: case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT: case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH: case NEXTHDR_AUTH:
case NEXTHDR_DEST: case NEXTHDR_DEST:
break; break;
default: default:
DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr); DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
return 0; return 0;
break;
} }
nexthdr = hdr->nexthdr; nexthdr = hp->nexthdr;
len -= hdrlen; len -= hdrlen;
ptr += hdrlen; ptr += hdrlen;
if ( ptr > skb->len ) { if (ptr > skb->len) {
DEBUGP("ipv6_esp: new pointer too large! \n"); DEBUGP("ipv6_esp: new pointer too large! \n");
break; break;
} }
} }
/* ESP header not found */ /* ESP header not found */
if ( temp != MASK_ESP ) return 0; if (temp != MASK_ESP)
return 0;
if (len < (int)sizeof(struct ip_esp_hdr)){ if (len < sizeof(struct ip_esp_hdr)) {
*hotdrop = 1; *hotdrop = 1;
return 0; return 0;
} }
esp = (struct ip_esp_hdr *) (skb->data + ptr); eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp);
BUG_ON(eh == NULL);
DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi)); DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi));
return (esp != NULL) return (eh != NULL)
&& spi_match(espinfo->spis[0], espinfo->spis[1], && spi_match(espinfo->spis[0], espinfo->spis[1],
ntohl(esp->spi), ntohl(eh->spi),
!!(espinfo->invflags & IP6T_ESP_INV_SPI)); !!(espinfo->invflags & IP6T_ESP_INV_SPI));
} }
...@@ -157,7 +157,6 @@ checkentry(const char *tablename, ...@@ -157,7 +157,6 @@ checkentry(const char *tablename,
espinfo->invflags); espinfo->invflags);
return 0; return 0;
} }
return 1; return 1;
} }
......
...@@ -24,8 +24,7 @@ match(const struct sk_buff *skb, ...@@ -24,8 +24,7 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
......
...@@ -45,11 +45,10 @@ match(const struct sk_buff *skb, ...@@ -45,11 +45,10 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct frag_hdr *frag = NULL; struct frag_hdr _frag, *fh = NULL;
const struct ip6t_frag *fraginfo = matchinfo; const struct ip6t_frag *fraginfo = matchinfo;
unsigned int temp; unsigned int temp;
int len; int len;
...@@ -66,7 +65,7 @@ match(const struct sk_buff *skb, ...@@ -66,7 +65,7 @@ match(const struct sk_buff *skb,
temp = 0; temp = 0;
while (ip6t_ext_hdr(nexthdr)) { while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr; struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_frag header iteration \n"); DEBUGP("ipv6_frag header iteration \n");
...@@ -82,15 +81,16 @@ match(const struct sk_buff *skb, ...@@ -82,15 +81,16 @@ match(const struct sk_buff *skb,
break; break;
} }
hdr=(struct ipv6_opt_hdr *)(skb->data+ptr); hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */ /* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8; hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH) } else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2; hdrlen = (hp->hdrlen+2)<<2;
else else
hdrlen = ipv6_optlen(hdr); hdrlen = ipv6_optlen(hp);
/* FRAG -> evaluate */ /* FRAG -> evaluate */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT) {
...@@ -113,7 +113,7 @@ match(const struct sk_buff *skb, ...@@ -113,7 +113,7 @@ match(const struct sk_buff *skb,
break; break;
} }
nexthdr = hdr->nexthdr; nexthdr = hp->nexthdr;
len -= hdrlen; len -= hdrlen;
ptr += hdrlen; ptr += hdrlen;
if ( ptr > skb->len ) { if ( ptr > skb->len ) {
...@@ -130,57 +130,58 @@ match(const struct sk_buff *skb, ...@@ -130,57 +130,58 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
frag = (struct frag_hdr *) (skb->data + ptr); fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
BUG_ON(fh == NULL);
DEBUGP("INFO %04X ", frag->frag_off); DEBUGP("INFO %04X ", fh->frag_off);
DEBUGP("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7); DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6); DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF)); DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF));
DEBUGP("ID %u %08X\n", ntohl(frag->identification), DEBUGP("ID %u %08X\n", ntohl(fh->identification),
ntohl(frag->identification)); ntohl(fh->identification));
DEBUGP("IPv6 FRAG id %02X ", DEBUGP("IPv6 FRAG id %02X ",
(id_match(fraginfo->ids[0], fraginfo->ids[1], (id_match(fraginfo->ids[0], fraginfo->ids[1],
ntohl(frag->identification), ntohl(fh->identification),
!!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))); !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
DEBUGP("res %02X %02X%04X %02X ", DEBUGP("res %02X %02X%04X %02X ",
(fraginfo->flags & IP6T_FRAG_RES), frag->reserved, (fraginfo->flags & IP6T_FRAG_RES), fh->reserved,
ntohs(frag->frag_off) & 0x6, ntohs(fh->frag_off) & 0x6,
!((fraginfo->flags & IP6T_FRAG_RES) !((fraginfo->flags & IP6T_FRAG_RES)
&& (frag->reserved || (ntohs(frag->frag_off) & 0x6)))); && (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
DEBUGP("first %02X %02X %02X ", DEBUGP("first %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_FST), (fraginfo->flags & IP6T_FRAG_FST),
ntohs(frag->frag_off) & ~0x7, ntohs(fh->frag_off) & ~0x7,
!((fraginfo->flags & IP6T_FRAG_FST) !((fraginfo->flags & IP6T_FRAG_FST)
&& (ntohs(frag->frag_off) & ~0x7))); && (ntohs(fh->frag_off) & ~0x7)));
DEBUGP("mf %02X %02X %02X ", DEBUGP("mf %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_MF), (fraginfo->flags & IP6T_FRAG_MF),
ntohs(frag->frag_off) & IP6_MF, ntohs(fh->frag_off) & IP6_MF,
!((fraginfo->flags & IP6T_FRAG_MF) !((fraginfo->flags & IP6T_FRAG_MF)
&& !((ntohs(frag->frag_off) & IP6_MF)))); && !((ntohs(fh->frag_off) & IP6_MF))));
DEBUGP("last %02X %02X %02X\n", DEBUGP("last %02X %02X %02X\n",
(fraginfo->flags & IP6T_FRAG_NMF), (fraginfo->flags & IP6T_FRAG_NMF),
ntohs(frag->frag_off) & IP6_MF, ntohs(fh->frag_off) & IP6_MF,
!((fraginfo->flags & IP6T_FRAG_NMF) !((fraginfo->flags & IP6T_FRAG_NMF)
&& (ntohs(frag->frag_off) & IP6_MF))); && (ntohs(fh->frag_off) & IP6_MF)));
return (frag != NULL) return (fh != NULL)
&& &&
(id_match(fraginfo->ids[0], fraginfo->ids[1], (id_match(fraginfo->ids[0], fraginfo->ids[1],
ntohl(frag->identification), ntohl(fh->identification),
!!(fraginfo->invflags & IP6T_FRAG_INV_IDS))) !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
&& &&
!((fraginfo->flags & IP6T_FRAG_RES) !((fraginfo->flags & IP6T_FRAG_RES)
&& (frag->reserved || (ntohs(frag->frag_off) & 0x6))) && (fh->reserved || (ntohs(fh->frag_off) & 0x6)))
&& &&
!((fraginfo->flags & IP6T_FRAG_FST) !((fraginfo->flags & IP6T_FRAG_FST)
&& (ntohs(frag->frag_off) & ~0x7)) && (ntohs(fh->frag_off) & ~0x7))
&& &&
!((fraginfo->flags & IP6T_FRAG_MF) !((fraginfo->flags & IP6T_FRAG_MF)
&& !(ntohs(frag->frag_off) & IP6_MF)) && !(ntohs(fh->frag_off) & IP6_MF))
&& &&
!((fraginfo->flags & IP6T_FRAG_NMF) !((fraginfo->flags & IP6T_FRAG_NMF)
&& (ntohs(frag->frag_off) & IP6_MF)); && (ntohs(fh->frag_off) & IP6_MF));
} }
/* Called when user tries to insert an entry of this type. */ /* Called when user tries to insert an entry of this type. */
......
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h> #include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 1 #define HOPBYHOP 1
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); ...@@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
* 0 -> invariant * 0 -> invariant
* 1 -> can change the routing * 1 -> can change the routing
* (Type & 0x1F) Type * (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!) * 0 -> Pad1 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2) * 1 -> PadN LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x * 5 -> RTALERT 2 x x
*/ */
...@@ -59,11 +57,10 @@ match(const struct sk_buff *skb, ...@@ -59,11 +57,10 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct ipv6_opt_hdr *optsh = NULL; struct ipv6_opt_hdr _optsh, *oh;
const struct ip6t_opts *optinfo = matchinfo; const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp; unsigned int temp;
unsigned int len; unsigned int len;
...@@ -71,7 +68,9 @@ match(const struct sk_buff *skb, ...@@ -71,7 +68,9 @@ match(const struct sk_buff *skb,
unsigned int ptr; unsigned int ptr;
unsigned int hdrlen = 0; unsigned int hdrlen = 0;
unsigned int ret = 0; unsigned int ret = 0;
u_int16_t *optdesc = NULL; u8 _opttype, *tp = NULL;
u8 _optlen, *lp = NULL;
unsigned int optlen;
/* type of the 1st exthdr */ /* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr; nexthdr = skb->nh.ipv6h->nexthdr;
...@@ -82,7 +81,7 @@ match(const struct sk_buff *skb, ...@@ -82,7 +81,7 @@ match(const struct sk_buff *skb,
temp = 0; temp = 0;
while (ip6t_ext_hdr(nexthdr)) { while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr; struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_opts header iteration \n"); DEBUGP("ipv6_opts header iteration \n");
...@@ -98,15 +97,16 @@ match(const struct sk_buff *skb, ...@@ -98,15 +97,16 @@ match(const struct sk_buff *skb,
break; break;
} }
hdr=(void *)(skb->data)+ptr; hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */ /* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8; hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH) } else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2; hdrlen = (hp->hdrlen+2)<<2;
else else
hdrlen = ipv6_optlen(hdr); hdrlen = ipv6_optlen(hp);
/* OPTS -> evaluate */ /* OPTS -> evaluate */
#if HOPBYHOP #if HOPBYHOP
...@@ -134,7 +134,7 @@ match(const struct sk_buff *skb, ...@@ -134,7 +134,7 @@ match(const struct sk_buff *skb,
break; break;
} }
nexthdr = hdr->nexthdr; nexthdr = hp->nexthdr;
len -= hdrlen; len -= hdrlen;
ptr += hdrlen; ptr += hdrlen;
if ( ptr > skb->len ) { if ( ptr > skb->len ) {
...@@ -160,9 +160,10 @@ match(const struct sk_buff *skb, ...@@ -160,9 +160,10 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
optsh=(void *)(skb->data)+ptr; oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
BUG_ON(oh == NULL);
DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
DEBUGP("len %02X %04X %02X ", DEBUGP("len %02X %04X %02X ",
optinfo->hdrlen, hdrlen, optinfo->hdrlen, hdrlen,
...@@ -170,13 +171,12 @@ match(const struct sk_buff *skb, ...@@ -170,13 +171,12 @@ match(const struct sk_buff *skb,
((optinfo->hdrlen == hdrlen) ^ ((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (optsh != NULL) ret = (oh != NULL)
&& &&
(!(optinfo->flags & IP6T_OPTS_LEN) || (!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^ ((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))); !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2; ptr += 2;
hdrlen -= 2; hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
...@@ -187,48 +187,59 @@ match(const struct sk_buff *skb, ...@@ -187,48 +187,59 @@ match(const struct sk_buff *skb,
DEBUGP("Strict "); DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr); DEBUGP("#%d ",optinfo->optsnr);
for(temp=0; temp<optinfo->optsnr; temp++){ for(temp=0; temp<optinfo->optsnr; temp++){
optdesc = (void *)(skb->data)+ptr; /* type field exists ? */
if (hdrlen < 1)
break;
tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
&_opttype);
if (tp == NULL)
break;
/* Type check */ /* Type check */
if ( (unsigned char)*optdesc != if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){
(optinfo->opts[temp] & 0xFF00)>>8 ){
DEBUGP("Tbad %02X %02X\n", DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc, *tp,
(optinfo->opts[temp] & (optinfo->opts[temp] & 0xFF00)>>8);
0xFF00)>>8);
return 0; return 0;
} else { } else {
DEBUGP("Tok "); DEBUGP("Tok ");
} }
/* Length check */ /* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && if (*tp) {
(unsigned char)*optdesc != 0){ u16 spec_len;
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){ /* length field exists ? */
DEBUGP("Lbad %02X %04X %04X\n", if (hdrlen < 2)
(unsigned char)*optdesc, break;
ntohs((u16)*optdesc), lp = skb_header_pointer(skb, ptr + 1,
optinfo->opts[temp]); sizeof(_optlen),
&_optlen);
if (lp == NULL)
break;
spec_len = optinfo->opts[temp] & 0x00FF;
if (spec_len != 0x00FF && spec_len != *lp) {
DEBUGP("Lbad %02X %04X\n", *lp,
spec_len);
return 0; return 0;
} else {
DEBUGP("Lok ");
} }
} DEBUGP("Lok ");
/* Step to the next */ optlen = *lp + 2;
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
} else { } else {
ptr += LOW(ntohs(*optdesc)); DEBUGP("Pad1\n");
hdrlen -= LOW(ntohs(*optdesc)); optlen = 1;
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
} }
if (ptr > skb->len || ( !hdrlen &&
(temp != optinfo->optsnr - 1))) { /* Step to the next */
DEBUGP("len%04X \n", optlen);
if ((ptr > skb->len - optlen || hdrlen < optlen) &&
(temp < optinfo->optsnr - 1)) {
DEBUGP("new pointer is too large! \n"); DEBUGP("new pointer is too large! \n");
break; break;
} }
ptr += optlen;
hdrlen -= optlen;
} }
if (temp == optinfo->optsnr) if (temp == optinfo->optsnr)
return ret; return ret;
......
...@@ -20,7 +20,7 @@ MODULE_LICENSE("GPL"); ...@@ -20,7 +20,7 @@ MODULE_LICENSE("GPL");
static int match(const struct sk_buff *skb, const struct net_device *in, static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo, const struct net_device *out, const void *matchinfo,
int offset, const void *hdr, u_int16_t datalen, int offset, unsigned int protoff,
int *hotdrop) int *hotdrop)
{ {
const struct ip6t_hl_info *info = matchinfo; const struct ip6t_hl_info *info = matchinfo;
......
...@@ -31,8 +31,7 @@ ipv6header_match(const struct sk_buff *skb, ...@@ -31,8 +31,7 @@ ipv6header_match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct ip6t_ipv6header_info *info = matchinfo; const struct ip6t_ipv6header_info *info = matchinfo;
......
...@@ -23,8 +23,7 @@ match(const struct sk_buff *skb, ...@@ -23,8 +23,7 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct ip6t_length_info *info = matchinfo; const struct ip6t_length_info *info = matchinfo;
......
...@@ -57,8 +57,7 @@ ip6t_limit_match(const struct sk_buff *skb, ...@@ -57,8 +57,7 @@ ip6t_limit_match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master; struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master;
......
...@@ -25,8 +25,7 @@ match(const struct sk_buff *skb, ...@@ -25,8 +25,7 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct ip6t_mac_info *info = matchinfo; const struct ip6t_mac_info *info = matchinfo;
......
...@@ -24,8 +24,7 @@ match(const struct sk_buff *skb, ...@@ -24,8 +24,7 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct ip6t_mark_info *info = matchinfo; const struct ip6t_mark_info *info = matchinfo;
......
...@@ -53,28 +53,32 @@ match(const struct sk_buff *skb, ...@@ -53,28 +53,32 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct udphdr *udp = hdr; u16 _ports[2], *pptr;
const struct ip6t_multiport *multiinfo = matchinfo; const struct ip6t_multiport *multiinfo = matchinfo;
/* Must be big enough to read ports. */ /* Must not be a fragment. */
if (offset == 0 && datalen < sizeof(struct udphdr)) { if (offset)
return 0;
/* Must be big enough to read ports (both UDP and TCP have
them at the start). */
pptr = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports[0]);
if (pptr == NULL) {
/* We've been asked to examine this packet, and we /* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */ * can't. Hence, no choice but to drop.
duprintf("ip6t_multiport:" */
" Dropping evil offset=0 tinygram.\n"); duprintf("ip6t_multiport:"
*hotdrop = 1; " Dropping evil offset=0 tinygram.\n");
return 0; *hotdrop = 1;
return 0;
} }
/* Must not be a fragment. */ return ports_match(multiinfo->ports,
return !offset multiinfo->flags, multiinfo->count,
&& ports_match(multiinfo->ports, ntohs(pptr[0]), ntohs(pptr[1]));
multiinfo->flags, multiinfo->count,
ntohs(udp->source), ntohs(udp->dest));
} }
/* Called when user tries to insert an entry of this type. */ /* Called when user tries to insert an entry of this type. */
......
...@@ -92,8 +92,7 @@ match(const struct sk_buff *skb, ...@@ -92,8 +92,7 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
const struct ip6t_owner_info *info = matchinfo; const struct ip6t_owner_info *info = matchinfo;
......
...@@ -26,8 +26,7 @@ match(const struct sk_buff *skb, ...@@ -26,8 +26,7 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *hdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
int i; int i;
......
...@@ -47,11 +47,10 @@ match(const struct sk_buff *skb, ...@@ -47,11 +47,10 @@ match(const struct sk_buff *skb,
const struct net_device *out, const struct net_device *out,
const void *matchinfo, const void *matchinfo,
int offset, int offset,
const void *protohdr, unsigned int protoff,
u_int16_t datalen,
int *hotdrop) int *hotdrop)
{ {
struct ipv6_rt_hdr *route = NULL; struct ipv6_rt_hdr _route, *rh = NULL;
const struct ip6t_rt *rtinfo = matchinfo; const struct ip6t_rt *rtinfo = matchinfo;
unsigned int temp; unsigned int temp;
unsigned int len; unsigned int len;
...@@ -59,6 +58,7 @@ match(const struct sk_buff *skb, ...@@ -59,6 +58,7 @@ match(const struct sk_buff *skb,
unsigned int ptr; unsigned int ptr;
unsigned int hdrlen = 0; unsigned int hdrlen = 0;
unsigned int ret = 0; unsigned int ret = 0;
struct in6_addr *ap, _addr;
/* type of the 1st exthdr */ /* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr; nexthdr = skb->nh.ipv6h->nexthdr;
...@@ -69,7 +69,7 @@ match(const struct sk_buff *skb, ...@@ -69,7 +69,7 @@ match(const struct sk_buff *skb,
temp = 0; temp = 0;
while (ip6t_ext_hdr(nexthdr)) { while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr; struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_rt header iteration \n"); DEBUGP("ipv6_rt header iteration \n");
...@@ -85,15 +85,16 @@ match(const struct sk_buff *skb, ...@@ -85,15 +85,16 @@ match(const struct sk_buff *skb,
break; break;
} }
hdr=(struct ipv6_opt_hdr *)(skb->data+ptr); hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */ /* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8; hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH) } else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2; hdrlen = (hp->hdrlen+2)<<2;
else else
hdrlen = ipv6_optlen(hdr); hdrlen = ipv6_optlen(hp);
/* ROUTING -> evaluate */ /* ROUTING -> evaluate */
if (nexthdr == NEXTHDR_ROUTING) { if (nexthdr == NEXTHDR_ROUTING) {
...@@ -116,7 +117,7 @@ match(const struct sk_buff *skb, ...@@ -116,7 +117,7 @@ match(const struct sk_buff *skb,
break; break;
} }
nexthdr = hdr->nexthdr; nexthdr = hp->nexthdr;
len -= hdrlen; len -= hdrlen;
ptr += hdrlen; ptr += hdrlen;
if ( ptr > skb->len ) { if ( ptr > skb->len ) {
...@@ -138,20 +139,21 @@ match(const struct sk_buff *skb, ...@@ -138,20 +139,21 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
route = (struct ipv6_rt_hdr *) (skb->data + ptr); rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
BUG_ON(rh == NULL);
DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen); DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
DEBUGP("TYPE %04X ", route->type); DEBUGP("TYPE %04X ", rh->type);
DEBUGP("SGS_LEFT %u %02X\n", route->segments_left, route->segments_left); DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);
DEBUGP("IPv6 RT segsleft %02X ", DEBUGP("IPv6 RT segsleft %02X ",
(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
route->segments_left, rh->segments_left,
!!(rtinfo->invflags & IP6T_RT_INV_SGS)))); !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
DEBUGP("type %02X %02X %02X ", DEBUGP("type %02X %02X %02X ",
rtinfo->rt_type, route->type, rtinfo->rt_type, rh->type,
(!(rtinfo->flags & IP6T_RT_TYP) || (!(rtinfo->flags & IP6T_RT_TYP) ||
((rtinfo->rt_type == route->type) ^ ((rtinfo->rt_type == rh->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP)))); !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
DEBUGP("len %02X %04X %02X ", DEBUGP("len %02X %04X %02X ",
rtinfo->hdrlen, hdrlen, rtinfo->hdrlen, hdrlen,
...@@ -159,13 +161,13 @@ match(const struct sk_buff *skb, ...@@ -159,13 +161,13 @@ match(const struct sk_buff *skb,
((rtinfo->hdrlen == hdrlen) ^ ((rtinfo->hdrlen == hdrlen) ^
!!(rtinfo->invflags & IP6T_RT_INV_LEN)))); !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
DEBUGP("res %02X %02X %02X ", DEBUGP("res %02X %02X %02X ",
(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap, (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->bitmap,
!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap))); !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->bitmap)));
ret = (route != NULL) ret = (rh != NULL)
&& &&
(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
route->segments_left, rh->segments_left,
!!(rtinfo->invflags & IP6T_RT_INV_SGS))) !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
&& &&
(!(rtinfo->flags & IP6T_RT_LEN) || (!(rtinfo->flags & IP6T_RT_LEN) ||
...@@ -173,13 +175,19 @@ match(const struct sk_buff *skb, ...@@ -173,13 +175,19 @@ match(const struct sk_buff *skb,
!!(rtinfo->invflags & IP6T_RT_INV_LEN))) !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
&& &&
(!(rtinfo->flags & IP6T_RT_TYP) || (!(rtinfo->flags & IP6T_RT_TYP) ||
((rtinfo->rt_type == route->type) ^ ((rtinfo->rt_type == rh->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP))) !!(rtinfo->invflags & IP6T_RT_INV_TYP)));
&&
!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)); if (ret && (rtinfo->flags & IP6T_RT_RES)) {
u_int32_t *bp, _bitmap;
bp = skb_header_pointer(skb,
ptr + offsetof(struct rt0_hdr, bitmap),
sizeof(_bitmap), &_bitmap);
ret = (*bp == 0);
}
DEBUGP("#%d ",rtinfo->addrnr); DEBUGP("#%d ",rtinfo->addrnr);
temp = len = ptr = 0;
if ( !(rtinfo->flags & IP6T_RT_FST) ){ if ( !(rtinfo->flags & IP6T_RT_FST) ){
return ret; return ret;
} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) { } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
...@@ -188,32 +196,27 @@ match(const struct sk_buff *skb, ...@@ -188,32 +196,27 @@ match(const struct sk_buff *skb,
DEBUGP("There isn't enough space\n"); DEBUGP("There isn't enough space\n");
return 0; return 0;
} else { } else {
unsigned int i = 0;
DEBUGP("#%d ",rtinfo->addrnr); DEBUGP("#%d ",rtinfo->addrnr);
ptr = 0;
for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){ for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
len = 0; ap = skb_header_pointer(skb,
while ((u8)(((struct rt0_hdr *)route)-> ptr
addr[temp].s6_addr[len]) == + sizeof(struct rt0_hdr)
(u8)(rtinfo->addrs[ptr].s6_addr[len])){ + temp * sizeof(_addr),
DEBUGP("%02X?%02X ", sizeof(_addr),
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), &_addr);
(u8)(rtinfo->addrs[ptr].s6_addr[len]));
len++; BUG_ON(ap == NULL);
if ( len == 16 ) break;
} if (!ipv6_addr_cmp(ap, &rtinfo->addrs[i])) {
if (len==16) { DEBUGP("i=%d temp=%d;\n",i,temp);
DEBUGP("ptr=%d temp=%d;\n",ptr,temp); i++;
ptr++;
} else {
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[ptr].s6_addr[len]));
DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
} }
if (ptr==rtinfo->addrnr) break; if (i==rtinfo->addrnr) break;
} }
DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr); DEBUGP("i=%d #%d\n", i, rtinfo->addrnr);
if ( (len == 16) && (ptr == rtinfo->addrnr)) if (i == rtinfo->addrnr)
return ret; return ret;
else return 0; else return 0;
} }
...@@ -225,26 +228,19 @@ match(const struct sk_buff *skb, ...@@ -225,26 +228,19 @@ match(const struct sk_buff *skb,
} else { } else {
DEBUGP("#%d ",rtinfo->addrnr); DEBUGP("#%d ",rtinfo->addrnr);
for(temp=0; temp<rtinfo->addrnr; temp++){ for(temp=0; temp<rtinfo->addrnr; temp++){
len = 0; ap = skb_header_pointer(skb,
while ((u8)(((struct rt0_hdr *)route)-> ptr
addr[temp].s6_addr[len]) == + sizeof(struct rt0_hdr)
(u8)(rtinfo->addrs[temp].s6_addr[len])){ + temp * sizeof(_addr),
DEBUGP("%02X?%02X ", sizeof(_addr),
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), &_addr);
(u8)(rtinfo->addrs[temp].s6_addr[len])); BUG_ON(ap == NULL);
len++;
if ( len == 16 ) break; if (ipv6_addr_cmp(ap, &rtinfo->addrs[temp]))
}
if (len!=16) {
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[temp].s6_addr[len]));
DEBUGP("!len=%d temp=%d;\n",len,temp);
break; break;
}
} }
DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr); DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr);
if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16))) if ((temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
return ret; return ret;
else return 0; else return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment