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
/* Return true or false: return FALSE and set *hotdrop = 1 to
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,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop);
/* Called when user tries to insert an entry of this type. */
......@@ -386,11 +388,13 @@ struct ip6t_target
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 hooknum,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userdata);
......
......@@ -352,16 +352,14 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
{
struct ip_conntrack_tuple_hash *h;
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);
list_for_each_entry(h, &ip_conntrack_hash[hash], list) {
if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) {
per_cpu(ip_conntrack_stat, cpu).found++;
CONNTRACK_STAT_INC(found);
return h;
}
per_cpu(ip_conntrack_stat, cpu).searched++;
CONNTRACK_STAT_INC(searched);
}
return NULL;
......@@ -436,13 +434,14 @@ __ip_conntrack_confirm(struct sk_buff *skb)
add_timer(&ct->timeout);
atomic_inc(&ct->ct_general.use);
set_bit(IPS_CONFIRMED_BIT, &ct->status);
WRITE_UNLOCK(&ip_conntrack_lock);
CONNTRACK_STAT_INC(insert);
WRITE_UNLOCK(&ip_conntrack_lock);
return NF_ACCEPT;
}
WRITE_UNLOCK(&ip_conntrack_lock);
CONNTRACK_STAT_INC(insert_failed);
WRITE_UNLOCK(&ip_conntrack_lock);
return NF_DROP;
}
......
......@@ -60,7 +60,7 @@ target(struct sk_buff **pskb,
break;
case IPT_CONNMARK_RESTORE:
nfmark = (*pskb)->nfmark;
diff = (ct->mark ^ nfmark & markinfo->mask);
diff = (ct->mark ^ nfmark) & markinfo->mask;
if (diff != 0) {
(*pskb)->nfmark = nfmark ^ diff;
(*pskb)->nfcache |= NFC_ALTERED;
......
......@@ -81,8 +81,8 @@ masquerade_target(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo;
const struct ip_nat_multi_range *mr;
struct ip_nat_multi_range newrange;
u_int32_t newsrc;
struct rtable *rt;
u_int32_t newsrc;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
......@@ -96,36 +96,13 @@ masquerade_target(struct sk_buff **pskb,
|| ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
mr = targinfo;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = (*pskb)->nh.iph->daddr,
.tos = (RT_TOS((*pskb)->nh.iph->tos) |
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;
}
rt = (struct rtable *)(*pskb)->dst;
newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
if (!newsrc) {
printk("MASQUERADE: %s ate my IP address\n", out->name);
return NF_DROP;
}
newsrc = rt->rt_src;
DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
ip_rt_put(rt);
WRITE_LOCK(&masq_lock);
ct->nat.masq_index = out->ifindex;
WRITE_UNLOCK(&masq_lock);
......@@ -157,6 +134,18 @@ device_cmp(const struct ip_conntrack *i, void *_ina)
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,
unsigned long event,
void *ptr)
......@@ -166,6 +155,8 @@ static int masq_inet_event(struct notifier_block *this,
* entries. */
if (event == NETDEV_UP)
ip_ct_selective_cleanup(device_cmp, ptr);
else if (event == NETDEV_DOWN)
ip_ct_selective_cleanup(connect_unassure, ptr);
return NOTIFY_DONE;
}
......
......@@ -158,14 +158,15 @@ ip6t_ext_hdr(u8 nexthdr)
/* Returns whether matches rule or not. */
static inline int
ip6_packet_match(const struct sk_buff *skb,
const struct ipv6hdr *ipv6,
const char *indev,
const char *outdev,
const struct ip6t_ip6 *ip6info,
int isfrag)
unsigned int *protoff,
int *fragoff)
{
size_t i;
unsigned long ret;
const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
......@@ -216,9 +217,10 @@ ip6_packet_match(const struct sk_buff *skb,
/* look for the desired protocol header */
if((ip6info->flags & IP6T_F_PROTO)) {
u_int8_t currenthdr = ipv6->nexthdr;
struct ipv6_opt_hdr *hdrptr;
struct ipv6_opt_hdr _hdr, *hp;
u_int16_t ptr; /* Header offset in skb */
u_int16_t hdrlen; /* Header */
u_int16_t _fragoff = 0, *fp = NULL;
ptr = IPV6_HDR_LEN;
......@@ -234,23 +236,41 @@ ip6_packet_match(const struct sk_buff *skb,
(currenthdr == IPPROTO_ESP))
return 0;
hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Size calculation */
if (currenthdr == IPPROTO_FRAGMENT) {
fp = skb_header_pointer(skb,
ptr+offsetof(struct frag_hdr,
frag_off),
sizeof(_fragoff),
&_fragoff);
if (fp == NULL)
return 0;
_fragoff = ntohs(*fp) & ~0x7;
hdrlen = 8;
} else if (currenthdr == IPPROTO_AH)
hdrlen = (hdrptr->hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdrptr);
hdrlen = ipv6_optlen(hp);
currenthdr = hdrptr->nexthdr;
currenthdr = hp->nexthdr;
ptr += hdrlen;
/* ptr is too large */
if ( ptr > skb->len )
return 0;
if (_fragoff) {
if (ip6t_ext_hdr(currenthdr))
return 0;
break;
}
}
*protoff = ptr;
*fragoff = _fragoff;
/* currenthdr contains the protocol header */
dprintf("Packet protocol %hi ?= %s%hi.\n",
......@@ -292,9 +312,9 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
static unsigned int
ip6t_error(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
{
......@@ -310,13 +330,12 @@ int do_match(struct ip6t_entry_match *m,
const struct net_device *in,
const struct net_device *out,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
/* Stop iteration if it doesn't match */
if (!m->u.kernel.match->match(skb, in, out, m->data,
offset, hdr, datalen, hotdrop))
offset, protoff, hotdrop))
return 1;
else
return 0;
......@@ -338,10 +357,8 @@ ip6t_do_table(struct sk_buff **pskb,
void *userdata)
{
static const char nulldevname[IFNAMSIZ];
u_int16_t offset = 0;
struct ipv6hdr *ipv6;
void *protohdr;
u_int16_t datalen;
int offset = 0;
unsigned int protoff = 0;
int hotdrop = 0;
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
......@@ -354,9 +371,6 @@ ip6t_do_table(struct sk_buff **pskb,
return NF_DROP;
/* Initialization */
ipv6 = (*pskb)->nh.ipv6h;
protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
datalen = (*pskb)->len - IPV6_HDR_LEN;
indev = in ? in->name : nulldevname;
outdev = out ? out->name : nulldevname;
......@@ -393,17 +407,19 @@ ip6t_do_table(struct sk_buff **pskb,
IP_NF_ASSERT(e);
IP_NF_ASSERT(back);
(*pskb)->nfcache |= e->nfcache;
if (ip6_packet_match(*pskb, ipv6, indev, outdev,
&e->ipv6, offset)) {
if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
&protoff, &offset)) {
struct ip6t_entry_target *t;
if (IP6T_MATCH_ITERATE(e, do_match,
*pskb, in, out,
offset, protohdr,
datalen, &hotdrop) != 0)
offset, protoff, &hotdrop) != 0)
goto no_match;
ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1);
ADD_COUNTER(e->counters,
ntohs((*pskb)->nh.ipv6h->payload_len)
+ IPV6_HDR_LEN,
1);
t = ip6t_get_target(e);
IP_NF_ASSERT(t->u.kernel.target);
......@@ -443,8 +459,8 @@ ip6t_do_table(struct sk_buff **pskb,
= 0xeeeeeeec;
#endif
verdict = t->u.kernel.target->target(pskb,
hook,
in, out,
hook,
t->data,
userdata);
......@@ -459,11 +475,6 @@ ip6t_do_table(struct sk_buff **pskb,
((struct ip6t_entry *)table_base)->comefrom
= 0x57acc001;
#endif
/* Target might have changed stuff. */
ipv6 = (*pskb)->nh.ipv6h;
protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
datalen = (*pskb)->len - IPV6_HDR_LEN;
if (verdict == IP6T_CONTINUE)
e = (void *)e + e->next_offset;
else
......@@ -1535,26 +1546,31 @@ port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
static int
tcp_find_option(u_int8_t option,
const struct tcphdr *tcp,
u_int16_t datalen,
const struct sk_buff *skb,
unsigned int tcpoff,
unsigned int optlen,
int invert,
int *hotdrop)
{
unsigned int i = sizeof(struct tcphdr);
const u_int8_t *opt = (u_int8_t *)tcp;
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
unsigned int i;
duprintf("tcp_match: finding option\n");
if (!optlen)
return invert;
/* If we don't have the whole header, drop packet. */
if (tcp->doff * 4 < sizeof(struct tcphdr) ||
tcp->doff * 4 > datalen) {
op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
_opt);
if (op == NULL) {
*hotdrop = 1;
return 0;
}
while (i < tcp->doff * 4) {
if (opt[i] == option) return !invert;
if (opt[i] < 2) i++;
else i += opt[i+1]?:1;
for (i = 0; i < optlen; ) {
if (op[i] == option) return !invert;
if (op[i] < 2) i++;
else i += op[i+1]?:1;
}
return invert;
......@@ -1566,27 +1582,31 @@ tcp_match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct tcphdr *tcp;
struct tcphdr _tcph, *th;
const struct ip6t_tcp *tcpinfo = matchinfo;
int tcpoff;
u8 nexthdr = skb->nh.ipv6h->nexthdr;
/* To quote Alan:
Don't allow a fragment of TCP 8 bytes in. Nobody normal
causes this. Its a cracker trying to break in by doing a
flag overwrite to pass the direction checks.
*/
if (offset) {
/* To quote Alan:
if (offset == 1) {
duprintf("Dropping evil TCP offset=1 frag.\n");
*hotdrop = 1;
Don't allow a fragment of TCP 8 bytes in. Nobody normal
causes this. Its a cracker trying to break in by doing a
flag overwrite to pass the direction checks.
*/
if (offset == 1) {
duprintf("Dropping evil TCP offset=1 frag.\n");
*hotdrop = 1;
}
/* Must not be a fragment. */
return 0;
} else if (offset == 0 && datalen < sizeof(struct tcphdr)) {
}
#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
if (th == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil TCP offset=0 tinygram.\n");
......@@ -1594,45 +1614,30 @@ tcp_match(const struct sk_buff *skb,
return 0;
}
tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff);
if (tcpoff < 0 || tcpoff > skb->len) {
duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
*hotdrop = 1;
if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
ntohs(th->source),
!!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
return 0;
} else if (nexthdr == IPPROTO_FRAGMENT)
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
ntohs(th->dest),
!!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
return 0;
else if (nexthdr != IPPROTO_TCP ||
skb->len - tcpoff < sizeof(struct tcphdr)) {
/* cannot be occured */
duprintf("tcp_match: cannot get TCP header. Dropping.\n");
*hotdrop = 1;
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
== tcpinfo->flg_cmp,
IP6T_TCP_INV_FLAGS))
return 0;
if (tcpinfo->option) {
if (th->doff * 4 < sizeof(_tcph)) {
*hotdrop = 1;
return 0;
}
if (!tcp_find_option(tcpinfo->option, skb, protoff,
th->doff*4 - sizeof(*th),
tcpinfo->invflags & IP6T_TCP_INV_OPTION,
hotdrop))
return 0;
}
tcp = (struct tcphdr *)(skb->data + tcpoff);
/* FIXME: Try tcp doff >> packet len against various stacks --RR */
#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
/* Must not be a fragment. */
return !offset
&& port_match(tcpinfo->spts[0], tcpinfo->spts[1],
ntohs(tcp->source),
!!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))
&& port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
ntohs(tcp->dest),
!!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))
&& FWINVTCP((((unsigned char *)tcp)[13]
& tcpinfo->flg_mask)
== tcpinfo->flg_cmp,
IP6T_TCP_INV_FLAGS)
&& (!tcpinfo->option
|| tcp_find_option(tcpinfo->option, tcp, datalen,
tcpinfo->invflags
& IP6T_TCP_INV_OPTION,
hotdrop));
return 1;
}
/* Called when user tries to insert an entry of this type. */
......@@ -1658,16 +1663,18 @@ udp_match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct udphdr *udp;
struct udphdr _udph, *uh;
const struct ip6t_udp *udpinfo = matchinfo;
int udpoff;
u8 nexthdr = skb->nh.ipv6h->nexthdr;
if (offset == 0 && datalen < sizeof(struct udphdr)) {
/* Must not be a fragment. */
if (offset)
return 0;
uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
if (uh == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil UDP tinygram.\n");
......@@ -1675,30 +1682,11 @@ udp_match(const struct sk_buff *skb,
return 0;
}
udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff);
if (udpoff < 0 || udpoff > skb->len) {
duprintf("udp_match: cannot skip exthdr. Dropping.\n");
*hotdrop = 1;
return 0;
} else if (nexthdr == IPPROTO_FRAGMENT)
return 0;
else if (nexthdr != IPPROTO_UDP ||
skb->len - udpoff < sizeof(struct udphdr)) {
duprintf("udp_match: cannot get UDP header. Dropping.\n");
*hotdrop = 1;
return 0;
}
udp = (struct udphdr *)(skb->data + udpoff);
/* Must not be a fragment. */
return !offset
&& port_match(udpinfo->spts[0], udpinfo->spts[1],
ntohs(udp->source),
!!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
return port_match(udpinfo->spts[0], udpinfo->spts[1],
ntohs(uh->source),
!!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
ntohs(udp->dest),
ntohs(uh->dest),
!!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
}
......@@ -1748,14 +1736,18 @@ icmp6_match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct icmp6hdr *icmp = hdr;
struct icmp6hdr _icmp, *ic;
const struct ip6t_icmp *icmpinfo = matchinfo;
if (offset == 0 && datalen < 2) {
/* Must not be a fragment. */
if (offset)
return 0;
ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
if (ic == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil ICMP tinygram.\n");
......@@ -1763,13 +1755,11 @@ icmp6_match(const struct sk_buff *skb,
return 0;
}
/* Must not be a fragment. */
return !offset
&& icmp6_type_code_match(icmpinfo->type,
icmpinfo->code[0],
icmpinfo->code[1],
icmp->icmp6_type, icmp->icmp6_code,
!!(icmpinfo->invflags&IP6T_ICMP_INV));
return icmp6_type_code_match(icmpinfo->type,
icmpinfo->code[0],
icmpinfo->code[1],
ic->icmp6_type, ic->icmp6_code,
!!(icmpinfo->invflags&IP6T_ICMP_INV));
}
/* Called when user tries to insert an entry of this type. */
......
......@@ -40,120 +40,166 @@ struct in_device;
#define DEBUGP(format, args...)
#endif
struct esphdr {
__u32 spi;
}; /* FIXME evil kludge */
/* Use lock to serialize, so printks don't overlap */
static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
/* takes in current header and pointer to the header */
/* if another header exists, sets hdrptr to the next header
and returns the new header value, else returns IPPROTO_NONE */
static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t **hdrptr)
{
u_int8_t hdrlen, nexthdr = IPPROTO_NONE;
switch(currenthdr){
case IPPROTO_AH:
/* whoever decided to do the length of AUTH for ipv6
in 32bit units unlike other headers should be beaten...
repeatedly...with a large stick...no, an even LARGER
stick...no, you're still not thinking big enough */
nexthdr = **hdrptr;
hdrlen = (*hdrptr)[1] * 4 + 8;
*hdrptr = *hdrptr + hdrlen;
break;
/*stupid rfc2402 */
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_HOPOPTS:
nexthdr = **hdrptr;
hdrlen = (*hdrptr)[1] * 8 + 8;
*hdrptr = *hdrptr + hdrlen;
break;
case IPPROTO_FRAGMENT:
nexthdr = **hdrptr;
*hdrptr = *hdrptr + 8;
break;
}
return nexthdr;
}
/* One level of recursion won't kill us */
static void dump_packet(const struct ip6t_log_info *info,
struct ipv6hdr *ipv6h, int recurse)
const struct sk_buff *skb, unsigned int ip6hoff,
int recurse)
{
u_int8_t currenthdr = ipv6h->nexthdr;
u_int8_t *hdrptr;
u_int8_t currenthdr;
int fragment;
struct ipv6hdr _ip6h, *ih;
unsigned int ptr;
unsigned int hdrlen = 0;
ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
if (ih == NULL) {
printk("TRUNCATED");
return;
}
/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */
printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->saddr));
printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->saddr));
printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->daddr));
/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
ntohs(ipv6h->payload_len) + sizeof(struct ipv6hdr),
(ntohl(*(u_int32_t *)ipv6h) & 0x0ff00000) >> 20,
ipv6h->hop_limit,
(ntohl(*(u_int32_t *)ipv6h) & 0x000fffff));
ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
(ntohl(*(u_int32_t *)ih) & 0x0ff00000) >> 20,
ih->hop_limit,
(ntohl(*(u_int32_t *)ih) & 0x000fffff));
fragment = 0;
hdrptr = (u_int8_t *)(ipv6h + 1);
while (currenthdr != IPPROTO_NONE) {
if ((currenthdr == IPPROTO_TCP) ||
(currenthdr == IPPROTO_UDP) ||
(currenthdr == IPPROTO_ICMPV6))
break;
ptr = ip6hoff + sizeof(struct ipv6hdr);
currenthdr = ih->nexthdr;
while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
struct ipv6_opt_hdr _hdr, *hp;
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
if (hp == NULL) {
printk("TRUNCATED");
return;
}
/* Max length: 48 "OPT (...) " */
printk("OPT ( ");
if (info->logflags & IP6T_LOG_IPOPT)
printk("OPT ( ");
switch (currenthdr) {
case IPPROTO_FRAGMENT: {
struct frag_hdr *fhdr = (struct frag_hdr *)hdrptr;
struct frag_hdr _fhdr, *fh;
printk("FRAG:");
fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
&_fhdr);
if (fh == NULL) {
printk("TRUNCATED ");
return;
}
/* Max length: 11 "FRAG:65535 " */
printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8);
/* Max length: 6 "65535 " */
printk("%u ", ntohs(fh->frag_off) & 0xFFF8);
/* Max length: 11 "INCOMPLETE " */
if (fhdr->frag_off & htons(0x0001))
if (fh->frag_off & htons(0x0001))
printk("INCOMPLETE ");
printk("ID:%08x ", fhdr->identification);
printk("ID:%08x ", ntohl(fh->identification));
if (ntohs(fhdr->frag_off) & 0xFFF8)
if (ntohs(fh->frag_off) & 0xFFF8)
fragment = 1;
hdrlen = 8;
break;
}
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_HOPOPTS:
if (fragment) {
if (info->logflags & IP6T_LOG_IPOPT)
printk(")");
return;
}
hdrlen = ipv6_optlen(hp);
break;
/* Max Length */
case IPPROTO_AH:
if (info->logflags & IP6T_LOG_IPOPT) {
struct ip_auth_hdr _ahdr, *ah;
/* Max length: 3 "AH " */
printk("AH ");
if (fragment) {
printk(")");
return;
}
ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
&_ahdr);
if (ah == NULL) {
/*
* Max length: 26 "INCOMPLETE [65535
* bytes] )"
*/
printk("INCOMPLETE [%u bytes] )",
skb->len - ptr);
return;
}
/* Length: 15 "SPI=0xF1234567 */
printk("SPI=0x%x ", ntohl(ah->spi));
}
hdrlen = (hp->hdrlen+2)<<2;
break;
case IPPROTO_ESP:
if (info->logflags & IP6T_LOG_IPOPT) {
struct esphdr *esph = (struct esphdr *)hdrptr;
int esp = (currenthdr == IPPROTO_ESP);
struct ip_esp_hdr _esph, *eh;
/* Max length: 4 "ESP " */
printk("%s ",esp ? "ESP" : "AH");
printk("ESP ");
if (fragment) {
printk(")");
return;
}
/*
* Max length: 26 "INCOMPLETE [65535 bytes] )"
*/
eh = skb_header_pointer(skb, ptr, sizeof(_esph),
&_esph);
if (eh == NULL) {
printk("INCOMPLETE [%u bytes] )",
skb->len - ptr);
return;
}
/* Length: 16 "SPI=0xF1234567 )" */
printk("SPI=0x%x )", ntohl(eh->spi) );
/* Length: 15 "SPI=0xF1234567 " */
printk("SPI=0x%x ", ntohl(esph->spi) );
break;
}
return;
default:
break;
/* Max length: 20 "Unknown Ext Hdr 255" */
printk("Unknown Ext Hdr %u", currenthdr);
return;
}
printk(") ");
currenthdr = ip6_nexthdr(currenthdr, &hdrptr);
if (info->logflags & IP6T_LOG_IPOPT)
printk(") ");
currenthdr = hp->nexthdr;
ptr += hdrlen;
}
switch (currenthdr) {
case IPPROTO_TCP: {
struct tcphdr *tcph = (struct tcphdr *)hdrptr;
struct tcphdr _tcph, *th;
/* Max length: 10 "PROTO=TCP " */
printk("PROTO=TCP ");
......@@ -161,51 +207,69 @@ static void dump_packet(const struct ip6t_log_info *info,
if (fragment)
break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph);
if (th == NULL) {
printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
return;
}
/* Max length: 20 "SPT=65535 DPT=65535 " */
printk("SPT=%u DPT=%u ",
ntohs(tcph->source), ntohs(tcph->dest));
ntohs(th->source), ntohs(th->dest));
/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
if (info->logflags & IP6T_LOG_TCPSEQ)
printk("SEQ=%u ACK=%u ",
ntohl(tcph->seq), ntohl(tcph->ack_seq));
ntohl(th->seq), ntohl(th->ack_seq));
/* Max length: 13 "WINDOW=65535 " */
printk("WINDOW=%u ", ntohs(tcph->window));
/* Max length: 9 "RES=0x3F " */
printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22));
printk("WINDOW=%u ", ntohs(th->window));
/* Max length: 9 "RES=0x3C " */
printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
if (tcph->cwr)
if (th->cwr)
printk("CWR ");
if (tcph->ece)
if (th->ece)
printk("ECE ");
if (tcph->urg)
if (th->urg)
printk("URG ");
if (tcph->ack)
if (th->ack)
printk("ACK ");
if (tcph->psh)
if (th->psh)
printk("PSH ");
if (tcph->rst)
if (th->rst)
printk("RST ");
if (tcph->syn)
if (th->syn)
printk("SYN ");
if (tcph->fin)
if (th->fin)
printk("FIN ");
/* Max length: 11 "URGP=65535 " */
printk("URGP=%u ", ntohs(tcph->urg_ptr));
printk("URGP=%u ", ntohs(th->urg_ptr));
if ((info->logflags & IP6T_LOG_TCPOPT)
&& tcph->doff * 4 != sizeof(struct tcphdr)) {
&& th->doff * 4 > sizeof(struct tcphdr)) {
u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
unsigned int i;
unsigned int optsize = th->doff * 4
- sizeof(struct tcphdr);
op = skb_header_pointer(skb,
ptr + sizeof(struct tcphdr),
optsize, _opt);
if (op == NULL) {
printk("OPT (TRUNCATED)");
return;
}
/* Max length: 127 "OPT (" 15*4*2chars ") " */
printk("OPT (");
for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++)
printk("%02X", ((u_int8_t *)tcph)[i]);
for (i =0; i < optsize; i++)
printk("%02X", op[i]);
printk(") ");
}
break;
}
case IPPROTO_UDP: {
struct udphdr *udph = (struct udphdr *)hdrptr;
struct udphdr _udph, *uh;
/* Max length: 10 "PROTO=UDP " */
printk("PROTO=UDP ");
......@@ -213,14 +277,21 @@ static void dump_packet(const struct ip6t_log_info *info,
if (fragment)
break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph);
if (uh == NULL) {
printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
return;
}
/* Max length: 20 "SPT=65535 DPT=65535 " */
printk("SPT=%u DPT=%u LEN=%u ",
ntohs(udph->source), ntohs(udph->dest),
ntohs(udph->len));
ntohs(uh->source), ntohs(uh->dest),
ntohs(uh->len));
break;
}
case IPPROTO_ICMPV6: {
struct icmp6hdr *icmp6h = (struct icmp6hdr *)hdrptr;
struct icmp6hdr _icmp6h, *ic;
/* Max length: 13 "PROTO=ICMPv6 " */
printk("PROTO=ICMPv6 ");
......@@ -228,16 +299,23 @@ static void dump_packet(const struct ip6t_log_info *info,
if (fragment)
break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
if (ic == NULL) {
printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
return;
}
/* Max length: 18 "TYPE=255 CODE=255 " */
printk("TYPE=%u CODE=%u ", icmp6h->icmp6_type, icmp6h->icmp6_code);
printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);
switch (icmp6h->icmp6_type) {
switch (ic->icmp6_type) {
case ICMPV6_ECHO_REQUEST:
case ICMPV6_ECHO_REPLY:
/* Max length: 19 "ID=65535 SEQ=65535 " */
printk("ID=%u SEQ=%u ",
ntohs(icmp6h->icmp6_identifier),
ntohs(icmp6h->icmp6_sequence));
ntohs(ic->icmp6_identifier),
ntohs(ic->icmp6_sequence));
break;
case ICMPV6_MGM_QUERY:
case ICMPV6_MGM_REPORT:
......@@ -246,7 +324,7 @@ static void dump_packet(const struct ip6t_log_info *info,
case ICMPV6_PARAMPROB:
/* Max length: 17 "POINTER=ffffffff " */
printk("POINTER=%08x ", ntohl(icmp6h->icmp6_pointer));
printk("POINTER=%08x ", ntohl(ic->icmp6_pointer));
/* Fall through */
case ICMPV6_DEST_UNREACH:
case ICMPV6_PKT_TOOBIG:
......@@ -254,13 +332,14 @@ static void dump_packet(const struct ip6t_log_info *info,
/* Max length: 3+maxlen */
if (recurse) {
printk("[");
dump_packet(info, (struct ipv6hdr *)(icmp6h + 1), 0);
dump_packet(info, skb, ptr + sizeof(_icmp6h),
0);
printk("] ");
}
/* Max length: 10 "MTU=65535 " */
if (icmp6h->icmp6_type == ICMPV6_PKT_TOOBIG)
printk("MTU=%u ", ntohl(icmp6h->icmp6_mtu));
if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
printk("MTU=%u ", ntohl(ic->icmp6_mtu));
}
break;
}
......@@ -328,16 +407,16 @@ ip6t_log_packet(unsigned int hooknum,
printk(" ");
}
dump_packet(loginfo, ipv6h, 1);
dump_packet(loginfo, skb, (u8*)skb->nh.ipv6h - skb->data, 1);
printk("\n");
spin_unlock_bh(&log_lock);
}
static unsigned int
ip6t_log_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
{
......
......@@ -20,9 +20,9 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
static unsigned int
target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
{
......
......@@ -31,12 +31,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{
int r=0;
DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
r=(spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r;
int r=0;
DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
r = (spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r;
}
static int
......@@ -45,125 +45,124 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct ip_auth_hdr *ah = NULL;
const struct ip6t_ah *ahinfo = matchinfo;
unsigned int temp;
int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
/*DEBUGP("IPv6 AH entered\n");*/
/* if (opt->auth == 0) return 0;
* It does not filled on output */
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
DEBUGP("ipv6_ah header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* AH -> evaluate */
if (nexthdr == NEXTHDR_AUTH) {
temp |= MASK_AH;
break;
}
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
struct ip_auth_hdr *ah = NULL, _ah;
const struct ip6t_ah *ahinfo = matchinfo;
unsigned int temp;
int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
/*DEBUGP("IPv6 AH entered\n");*/
/* if (opt->auth == 0) return 0;
* It does not filled on output */
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_ah header iteration \n");
/* Is there enough space for the next ext header? */
if (len < sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE)
break;
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP)
break;
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT)
hdrlen = 8;
else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hp);
/* AH -> evaluate */
if (nexthdr == NEXTHDR_AUTH) {
temp |= MASK_AH;
break;
}
/* set the flag */
switch (nexthdr) {
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
return 0;
}
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if (ptr > skb->len) {
DEBUGP("ipv6_ah: new pointer too large! \n");
break;
}
}
/* AH header not found */
if ( temp != MASK_AH ) return 0;
if (len < (int)sizeof(struct ip_auth_hdr)){
*hotdrop = 1;
return 0;
}
ah = (struct ip_auth_hdr *) (skb->data + ptr);
DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
DEBUGP("RES %04X ", ah->reserved);
DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
DEBUGP("IPv6 AH spi %02X ",
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi),
!!(ahinfo->invflags & IP6T_AH_INV_SPI))));
DEBUGP("len %02X %04X %02X ",
ahinfo->hdrlen, hdrlen,
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
!!(ahinfo->invflags & IP6T_AH_INV_LEN)));
DEBUGP("res %02X %04X %02X\n",
ahinfo->hdrres, ah->reserved,
!(ahinfo->hdrres && ah->reserved));
return (ah != NULL)
&&
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi),
!!(ahinfo->invflags & IP6T_AH_INV_SPI)))
&&
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
!!(ahinfo->invflags & IP6T_AH_INV_LEN))
&&
!(ahinfo->hdrres && ah->reserved);
}
/* AH header not found */
if (temp != MASK_AH)
return 0;
if (len < sizeof(struct ip_auth_hdr)){
*hotdrop = 1;
return 0;
}
ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
BUG_ON(ah == NULL);
DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
DEBUGP("RES %04X ", ah->reserved);
DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
DEBUGP("IPv6 AH spi %02X ",
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi),
!!(ahinfo->invflags & IP6T_AH_INV_SPI))));
DEBUGP("len %02X %04X %02X ",
ahinfo->hdrlen, hdrlen,
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
!!(ahinfo->invflags & IP6T_AH_INV_LEN)));
DEBUGP("res %02X %04X %02X\n",
ahinfo->hdrres, ah->reserved,
!(ahinfo->hdrres && ah->reserved));
return (ah != NULL)
&&
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi),
!!(ahinfo->invflags & IP6T_AH_INV_SPI)))
&&
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
!!(ahinfo->invflags & IP6T_AH_INV_LEN))
&&
!(ahinfo->hdrres && ah->reserved);
}
/* Called when user tries to insert an entry of this type. */
......@@ -174,20 +173,18 @@ checkentry(const char *tablename,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_ah *ahinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
DEBUGP("ip6t_ah: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
return 0;
}
if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
DEBUGP("ip6t_ah: unknown flags %X\n",
ahinfo->invflags);
return 0;
}
return 1;
const struct ip6t_ah *ahinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
DEBUGP("ip6t_ah: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
return 0;
}
if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
return 0;
}
return 1;
}
static struct ip6t_match ah_match = {
......@@ -199,12 +196,12 @@ static struct ip6t_match ah_match = {
static int __init init(void)
{
return ip6t_register_match(&ah_match);
return ip6t_register_match(&ah_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&ah_match);
ip6t_unregister_match(&ah_match);
}
module_init(init);
......
......@@ -7,7 +7,6 @@
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
......@@ -20,8 +19,6 @@
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 0
MODULE_LICENSE("GPL");
......@@ -48,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
* 0 -> invariant
* 1 -> can change the routing
* (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2)
* 0 -> Pad1 (only 1 byte!)
* 1 -> PadN LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x
*/
......@@ -60,11 +57,10 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct ipv6_opt_hdr *optsh = NULL;
struct ipv6_opt_hdr _optsh, *oh;
const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp;
unsigned int len;
......@@ -72,7 +68,9 @@ match(const struct sk_buff *skb,
unsigned int ptr;
unsigned int hdrlen = 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 */
nexthdr = skb->nh.ipv6h->nexthdr;
......@@ -83,7 +81,7 @@ match(const struct sk_buff *skb,
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_opts header iteration \n");
......@@ -99,15 +97,16 @@ match(const struct sk_buff *skb,
break;
}
hdr=(void *)(skb->data)+ptr;
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
hdrlen = ipv6_optlen(hp);
/* OPTS -> evaluate */
#if HOPBYHOP
......@@ -135,7 +134,7 @@ match(const struct sk_buff *skb,
break;
}
nexthdr = hdr->nexthdr;
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
......@@ -161,9 +160,10 @@ match(const struct sk_buff *skb,
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 ",
optinfo->hdrlen, hdrlen,
......@@ -171,13 +171,12 @@ match(const struct sk_buff *skb,
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (optsh != NULL)
ret = (oh != NULL)
&&
(!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2;
hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
......@@ -188,48 +187,59 @@ match(const struct sk_buff *skb,
DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr);
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 */
if ( (unsigned char)*optdesc !=
(optinfo->opts[temp] & 0xFF00)>>8 ){
if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){
DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc,
(optinfo->opts[temp] &
0xFF00)>>8);
*tp,
(optinfo->opts[temp] & 0xFF00)>>8);
return 0;
} else {
DEBUGP("Tok ");
}
/* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
(unsigned char)*optdesc != 0){
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){
DEBUGP("Lbad %02X %04X %04X\n",
(unsigned char)*optdesc,
ntohs((u16)*optdesc),
optinfo->opts[temp]);
if (*tp) {
u16 spec_len;
/* length field exists ? */
if (hdrlen < 2)
break;
lp = skb_header_pointer(skb, ptr + 1,
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;
} else {
DEBUGP("Lok ");
}
}
/* Step to the next */
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
DEBUGP("Lok ");
optlen = *lp + 2;
} else {
ptr += LOW(ntohs(*optdesc));
hdrlen -= LOW(ntohs(*optdesc));
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
DEBUGP("Pad1\n");
optlen = 1;
}
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");
break;
}
ptr += optlen;
hdrlen -= optlen;
}
if (temp == optinfo->optsnr)
return ret;
......@@ -271,6 +281,7 @@ static struct ip6t_match opts_match = {
#endif
.match = &match,
.checkentry = &checkentry,
.me = THIS_MODULE,
};
static int __init init(void)
......
......@@ -32,8 +32,8 @@ static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{
int r=0;
DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
r=(spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r;
......@@ -45,11 +45,10 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct ip_esp_hdr *esp = NULL;
struct ip_esp_hdr _esp, *eh = NULL;
const struct ip6t_esp *espinfo = matchinfo;
unsigned int temp;
int len;
......@@ -67,73 +66,74 @@ match(const struct sk_buff *skb,
len = skb->len - ptr;
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
int hdrlen;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr _hdr, *hp;
int hdrlen;
DEBUGP("ipv6_esp header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
if (len < sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
if (nexthdr == NEXTHDR_NONE)
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
if (nexthdr == NEXTHDR_ESP) {
temp |= MASK_ESP;
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 */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
if (nexthdr == NEXTHDR_FRAGMENT)
hdrlen = 8;
else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hp);
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
return 0;
break;
switch (nexthdr) {
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
return 0;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if (ptr > skb->len) {
DEBUGP("ipv6_esp: new pointer too large! \n");
break;
}
}
}
/* ESP header not found */
if ( temp != MASK_ESP ) return 0;
if (temp != MASK_ESP)
return 0;
if (len < (int)sizeof(struct ip_esp_hdr)){
*hotdrop = 1;
return 0;
}
if (len < sizeof(struct ip_esp_hdr)) {
*hotdrop = 1;
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],
ntohl(esp->spi),
ntohl(eh->spi),
!!(espinfo->invflags & IP6T_ESP_INV_SPI));
}
......@@ -157,7 +157,6 @@ checkentry(const char *tablename,
espinfo->invflags);
return 0;
}
return 1;
}
......
......@@ -24,8 +24,7 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
......
......@@ -45,11 +45,10 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct frag_hdr *frag = NULL;
struct frag_hdr _frag, *fh = NULL;
const struct ip6t_frag *fraginfo = matchinfo;
unsigned int temp;
int len;
......@@ -66,7 +65,7 @@ match(const struct sk_buff *skb,
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_frag header iteration \n");
......@@ -82,15 +81,16 @@ match(const struct sk_buff *skb,
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 */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
hdrlen = ipv6_optlen(hp);
/* FRAG -> evaluate */
if (nexthdr == NEXTHDR_FRAGMENT) {
......@@ -113,7 +113,7 @@ match(const struct sk_buff *skb,
break;
}
nexthdr = hdr->nexthdr;
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
......@@ -130,57 +130,58 @@ match(const struct sk_buff *skb,
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("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7);
DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6);
DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF));
DEBUGP("ID %u %08X\n", ntohl(frag->identification),
ntohl(frag->identification));
DEBUGP("INFO %04X ", fh->frag_off);
DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF));
DEBUGP("ID %u %08X\n", ntohl(fh->identification),
ntohl(fh->identification));
DEBUGP("IPv6 FRAG id %02X ",
(id_match(fraginfo->ids[0], fraginfo->ids[1],
ntohl(frag->identification),
ntohl(fh->identification),
!!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
DEBUGP("res %02X %02X%04X %02X ",
(fraginfo->flags & IP6T_FRAG_RES), frag->reserved,
ntohs(frag->frag_off) & 0x6,
(fraginfo->flags & IP6T_FRAG_RES), fh->reserved,
ntohs(fh->frag_off) & 0x6,
!((fraginfo->flags & IP6T_FRAG_RES)
&& (frag->reserved || (ntohs(frag->frag_off) & 0x6))));
&& (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
DEBUGP("first %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_FST),
ntohs(frag->frag_off) & ~0x7,
ntohs(fh->frag_off) & ~0x7,
!((fraginfo->flags & IP6T_FRAG_FST)
&& (ntohs(frag->frag_off) & ~0x7)));
&& (ntohs(fh->frag_off) & ~0x7)));
DEBUGP("mf %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_MF),
ntohs(frag->frag_off) & IP6_MF,
ntohs(fh->frag_off) & IP6_MF,
!((fraginfo->flags & IP6T_FRAG_MF)
&& !((ntohs(frag->frag_off) & IP6_MF))));
&& !((ntohs(fh->frag_off) & IP6_MF))));
DEBUGP("last %02X %02X %02X\n",
(fraginfo->flags & IP6T_FRAG_NMF),
ntohs(frag->frag_off) & IP6_MF,
ntohs(fh->frag_off) & IP6_MF,
!((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],
ntohl(frag->identification),
ntohl(fh->identification),
!!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
&&
!((fraginfo->flags & IP6T_FRAG_RES)
&& (frag->reserved || (ntohs(frag->frag_off) & 0x6)))
&& (fh->reserved || (ntohs(fh->frag_off) & 0x6)))
&&
!((fraginfo->flags & IP6T_FRAG_FST)
&& (ntohs(frag->frag_off) & ~0x7))
&& (ntohs(fh->frag_off) & ~0x7))
&&
!((fraginfo->flags & IP6T_FRAG_MF)
&& !(ntohs(frag->frag_off) & IP6_MF))
&& !(ntohs(fh->frag_off) & IP6_MF))
&&
!((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. */
......
......@@ -19,8 +19,6 @@
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 1
MODULE_LICENSE("GPL");
......@@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
* 0 -> invariant
* 1 -> can change the routing
* (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2)
* 0 -> Pad1 (only 1 byte!)
* 1 -> PadN LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x
*/
......@@ -59,11 +57,10 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct ipv6_opt_hdr *optsh = NULL;
struct ipv6_opt_hdr _optsh, *oh;
const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp;
unsigned int len;
......@@ -71,7 +68,9 @@ match(const struct sk_buff *skb,
unsigned int ptr;
unsigned int hdrlen = 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 */
nexthdr = skb->nh.ipv6h->nexthdr;
......@@ -82,7 +81,7 @@ match(const struct sk_buff *skb,
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_opts header iteration \n");
......@@ -98,15 +97,16 @@ match(const struct sk_buff *skb,
break;
}
hdr=(void *)(skb->data)+ptr;
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
hdrlen = ipv6_optlen(hp);
/* OPTS -> evaluate */
#if HOPBYHOP
......@@ -134,7 +134,7 @@ match(const struct sk_buff *skb,
break;
}
nexthdr = hdr->nexthdr;
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
......@@ -160,9 +160,10 @@ match(const struct sk_buff *skb,
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 ",
optinfo->hdrlen, hdrlen,
......@@ -170,13 +171,12 @@ match(const struct sk_buff *skb,
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (optsh != NULL)
ret = (oh != NULL)
&&
(!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2;
hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
......@@ -187,48 +187,59 @@ match(const struct sk_buff *skb,
DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr);
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 */
if ( (unsigned char)*optdesc !=
(optinfo->opts[temp] & 0xFF00)>>8 ){
if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){
DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc,
(optinfo->opts[temp] &
0xFF00)>>8);
*tp,
(optinfo->opts[temp] & 0xFF00)>>8);
return 0;
} else {
DEBUGP("Tok ");
}
/* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
(unsigned char)*optdesc != 0){
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){
DEBUGP("Lbad %02X %04X %04X\n",
(unsigned char)*optdesc,
ntohs((u16)*optdesc),
optinfo->opts[temp]);
if (*tp) {
u16 spec_len;
/* length field exists ? */
if (hdrlen < 2)
break;
lp = skb_header_pointer(skb, ptr + 1,
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;
} else {
DEBUGP("Lok ");
}
}
/* Step to the next */
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
DEBUGP("Lok ");
optlen = *lp + 2;
} else {
ptr += LOW(ntohs(*optdesc));
hdrlen -= LOW(ntohs(*optdesc));
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
DEBUGP("Pad1\n");
optlen = 1;
}
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");
break;
}
ptr += optlen;
hdrlen -= optlen;
}
if (temp == optinfo->optsnr)
return ret;
......
......@@ -20,7 +20,7 @@ MODULE_LICENSE("GPL");
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
int offset, const void *hdr, u_int16_t datalen,
int offset, unsigned int protoff,
int *hotdrop)
{
const struct ip6t_hl_info *info = matchinfo;
......
......@@ -31,8 +31,7 @@ ipv6header_match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct ip6t_ipv6header_info *info = matchinfo;
......
......@@ -23,8 +23,7 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct ip6t_length_info *info = matchinfo;
......
......@@ -57,8 +57,7 @@ ip6t_limit_match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master;
......
......@@ -25,8 +25,7 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct ip6t_mac_info *info = matchinfo;
......
......@@ -24,8 +24,7 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct ip6t_mark_info *info = matchinfo;
......
......@@ -53,28 +53,32 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct udphdr *udp = hdr;
u16 _ports[2], *pptr;
const struct ip6t_multiport *multiinfo = matchinfo;
/* Must be big enough to read ports. */
if (offset == 0 && datalen < sizeof(struct udphdr)) {
/* Must not be a fragment. */
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
can't. Hence, no choice but to drop. */
duprintf("ip6t_multiport:"
" Dropping evil offset=0 tinygram.\n");
*hotdrop = 1;
return 0;
* can't. Hence, no choice but to drop.
*/
duprintf("ip6t_multiport:"
" Dropping evil offset=0 tinygram.\n");
*hotdrop = 1;
return 0;
}
/* Must not be a fragment. */
return !offset
&& ports_match(multiinfo->ports,
multiinfo->flags, multiinfo->count,
ntohs(udp->source), ntohs(udp->dest));
return ports_match(multiinfo->ports,
multiinfo->flags, multiinfo->count,
ntohs(pptr[0]), ntohs(pptr[1]));
}
/* Called when user tries to insert an entry of this type. */
......
......@@ -92,8 +92,7 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
const struct ip6t_owner_info *info = matchinfo;
......
......@@ -26,8 +26,7 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
int i;
......
......@@ -47,11 +47,10 @@ match(const struct sk_buff *skb,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
unsigned int protoff,
int *hotdrop)
{
struct ipv6_rt_hdr *route = NULL;
struct ipv6_rt_hdr _route, *rh = NULL;
const struct ip6t_rt *rtinfo = matchinfo;
unsigned int temp;
unsigned int len;
......@@ -59,6 +58,7 @@ match(const struct sk_buff *skb,
unsigned int ptr;
unsigned int hdrlen = 0;
unsigned int ret = 0;
struct in6_addr *ap, _addr;
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
......@@ -69,7 +69,7 @@ match(const struct sk_buff *skb,
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_rt header iteration \n");
......@@ -85,15 +85,16 @@ match(const struct sk_buff *skb,
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 */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
hdrlen = ipv6_optlen(hp);
/* ROUTING -> evaluate */
if (nexthdr == NEXTHDR_ROUTING) {
......@@ -116,7 +117,7 @@ match(const struct sk_buff *skb,
break;
}
nexthdr = hdr->nexthdr;
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
......@@ -138,20 +139,21 @@ match(const struct sk_buff *skb,
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("TYPE %04X ", route->type);
DEBUGP("SGS_LEFT %u %02X\n", route->segments_left, route->segments_left);
DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
DEBUGP("TYPE %04X ", rh->type);
DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);
DEBUGP("IPv6 RT segsleft %02X ",
(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
route->segments_left,
rh->segments_left,
!!(rtinfo->invflags & IP6T_RT_INV_SGS))));
DEBUGP("type %02X %02X %02X ",
rtinfo->rt_type, route->type,
rtinfo->rt_type, rh->type,
(!(rtinfo->flags & IP6T_RT_TYP) ||
((rtinfo->rt_type == route->type) ^
((rtinfo->rt_type == rh->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP))));
DEBUGP("len %02X %04X %02X ",
rtinfo->hdrlen, hdrlen,
......@@ -159,13 +161,13 @@ match(const struct sk_buff *skb,
((rtinfo->hdrlen == hdrlen) ^
!!(rtinfo->invflags & IP6T_RT_INV_LEN))));
DEBUGP("res %02X %02X %02X ",
(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
!((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 *)rh)->bitmap)));
ret = (route != NULL)
ret = (rh != NULL)
&&
(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
route->segments_left,
rh->segments_left,
!!(rtinfo->invflags & IP6T_RT_INV_SGS)))
&&
(!(rtinfo->flags & IP6T_RT_LEN) ||
......@@ -173,13 +175,19 @@ match(const struct sk_buff *skb,
!!(rtinfo->invflags & IP6T_RT_INV_LEN)))
&&
(!(rtinfo->flags & IP6T_RT_TYP) ||
((rtinfo->rt_type == route->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP)))
&&
!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap));
((rtinfo->rt_type == rh->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP)));
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);
temp = len = ptr = 0;
if ( !(rtinfo->flags & IP6T_RT_FST) ){
return ret;
} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
......@@ -188,32 +196,27 @@ match(const struct sk_buff *skb,
DEBUGP("There isn't enough space\n");
return 0;
} else {
unsigned int i = 0;
DEBUGP("#%d ",rtinfo->addrnr);
ptr = 0;
for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
len = 0;
while ((u8)(((struct rt0_hdr *)route)->
addr[temp].s6_addr[len]) ==
(u8)(rtinfo->addrs[ptr].s6_addr[len])){
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[ptr].s6_addr[len]));
len++;
if ( len == 16 ) break;
}
if (len==16) {
DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
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);
ap = skb_header_pointer(skb,
ptr
+ sizeof(struct rt0_hdr)
+ temp * sizeof(_addr),
sizeof(_addr),
&_addr);
BUG_ON(ap == NULL);
if (!ipv6_addr_cmp(ap, &rtinfo->addrs[i])) {
DEBUGP("i=%d temp=%d;\n",i,temp);
i++;
}
if (ptr==rtinfo->addrnr) break;
if (i==rtinfo->addrnr) break;
}
DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
if ( (len == 16) && (ptr == rtinfo->addrnr))
DEBUGP("i=%d #%d\n", i, rtinfo->addrnr);
if (i == rtinfo->addrnr)
return ret;
else return 0;
}
......@@ -225,26 +228,19 @@ match(const struct sk_buff *skb,
} else {
DEBUGP("#%d ",rtinfo->addrnr);
for(temp=0; temp<rtinfo->addrnr; temp++){
len = 0;
while ((u8)(((struct rt0_hdr *)route)->
addr[temp].s6_addr[len]) ==
(u8)(rtinfo->addrs[temp].s6_addr[len])){
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[temp].s6_addr[len]));
len++;
if ( len == 16 ) break;
}
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);
ap = skb_header_pointer(skb,
ptr
+ sizeof(struct rt0_hdr)
+ temp * sizeof(_addr),
sizeof(_addr),
&_addr);
BUG_ON(ap == NULL);
if (ipv6_addr_cmp(ap, &rtinfo->addrs[temp]))
break;
}
}
DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr);
if ((temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
return ret;
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