Skip to content

Commit

Permalink
netfilter: bridge: re-order check_hbh_len()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Bernhard Thaler authored and Pablo Neira Ayuso committed Jun 12, 2015
1 parent 77d574e commit a4611d3
Showing 1 changed file with 56 additions and 55 deletions.
111 changes: 56 additions & 55 deletions net/bridge/br_netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,62 @@ static int br_validate_ipv4(struct sk_buff *skb)
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)
{
switch (skb->nf_bridge->orig_proto) {
Expand Down Expand Up @@ -549,61 +605,6 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
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
* 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,
Expand Down

0 comments on commit a4611d3

Please sign in to comment.