netfilter: bridge: re-order check_hbh_len()
Prepare check_hbh_len() to be called from newly introduced br_validate_ipv6() in next commit. Signed-off-by: Bernhard Thaler <bernhard.thaler@wvnet.at> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:

committed by
Pablo Neira Ayuso

parent
77d574e728
commit
a4611d3b74
@@ -264,6 +264,62 @@ drop:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We only check the length. A bridge shouldn't do any hop-by-hop stuff
|
||||||
|
* anyway
|
||||||
|
*/
|
||||||
|
static int check_hbh_len(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
unsigned char *raw = (u8 *)(ipv6_hdr(skb) + 1);
|
||||||
|
u32 pkt_len;
|
||||||
|
const unsigned char *nh = skb_network_header(skb);
|
||||||
|
int off = raw - nh;
|
||||||
|
int len = (raw[1] + 1) << 3;
|
||||||
|
|
||||||
|
if ((raw + len) - skb->data > skb_headlen(skb))
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
off += 2;
|
||||||
|
len -= 2;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
int optlen = nh[off + 1] + 2;
|
||||||
|
|
||||||
|
switch (nh[off]) {
|
||||||
|
case IPV6_TLV_PAD1:
|
||||||
|
optlen = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IPV6_TLV_PADN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IPV6_TLV_JUMBO:
|
||||||
|
if (nh[off + 1] != 4 || (off & 3) != 2)
|
||||||
|
goto bad;
|
||||||
|
pkt_len = ntohl(*(__be32 *)(nh + off + 2));
|
||||||
|
if (pkt_len <= IPV6_MAXPLEN ||
|
||||||
|
ipv6_hdr(skb)->payload_len)
|
||||||
|
goto bad;
|
||||||
|
if (pkt_len > skb->len - sizeof(struct ipv6hdr))
|
||||||
|
goto bad;
|
||||||
|
if (pskb_trim_rcsum(skb,
|
||||||
|
pkt_len + sizeof(struct ipv6hdr)))
|
||||||
|
goto bad;
|
||||||
|
nh = skb_network_header(skb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (optlen > len)
|
||||||
|
goto bad;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
off += optlen;
|
||||||
|
len -= optlen;
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
bad:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void nf_bridge_update_protocol(struct sk_buff *skb)
|
static void nf_bridge_update_protocol(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
switch (skb->nf_bridge->orig_proto) {
|
switch (skb->nf_bridge->orig_proto) {
|
||||||
@@ -549,61 +605,6 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
|
|||||||
return skb->dev;
|
return skb->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */
|
|
||||||
static int check_hbh_len(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
unsigned char *raw = (u8 *)(ipv6_hdr(skb) + 1);
|
|
||||||
u32 pkt_len;
|
|
||||||
const unsigned char *nh = skb_network_header(skb);
|
|
||||||
int off = raw - nh;
|
|
||||||
int len = (raw[1] + 1) << 3;
|
|
||||||
|
|
||||||
if ((raw + len) - skb->data > skb_headlen(skb))
|
|
||||||
goto bad;
|
|
||||||
|
|
||||||
off += 2;
|
|
||||||
len -= 2;
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
int optlen = nh[off + 1] + 2;
|
|
||||||
|
|
||||||
switch (nh[off]) {
|
|
||||||
case IPV6_TLV_PAD1:
|
|
||||||
optlen = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IPV6_TLV_PADN:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IPV6_TLV_JUMBO:
|
|
||||||
if (nh[off + 1] != 4 || (off & 3) != 2)
|
|
||||||
goto bad;
|
|
||||||
pkt_len = ntohl(*(__be32 *) (nh + off + 2));
|
|
||||||
if (pkt_len <= IPV6_MAXPLEN ||
|
|
||||||
ipv6_hdr(skb)->payload_len)
|
|
||||||
goto bad;
|
|
||||||
if (pkt_len > skb->len - sizeof(struct ipv6hdr))
|
|
||||||
goto bad;
|
|
||||||
if (pskb_trim_rcsum(skb,
|
|
||||||
pkt_len + sizeof(struct ipv6hdr)))
|
|
||||||
goto bad;
|
|
||||||
nh = skb_network_header(skb);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (optlen > len)
|
|
||||||
goto bad;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
off += optlen;
|
|
||||||
len -= optlen;
|
|
||||||
}
|
|
||||||
if (len == 0)
|
|
||||||
return 0;
|
|
||||||
bad:
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Replicate the checks that IPv6 does on packet reception and pass the packet
|
/* Replicate the checks that IPv6 does on packet reception and pass the packet
|
||||||
* to ip6tables, which doesn't support NAT, so things are fairly simple. */
|
* to ip6tables, which doesn't support NAT, so things are fairly simple. */
|
||||||
static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
|
static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
|
||||||
|
Reference in New Issue
Block a user