Skip to content

Commit

Permalink
netfilter: nf_tables_bridge: use nft_set_pktinfo_ipv{4, 6}_validate
Browse files Browse the repository at this point in the history
Consolidate pktinfo setup and validation by using the new generic
functions so we converge to the netdev family codebase.

We only need a linear IPv4 and IPv6 header from the reject expression,
so move nft_bridge_iphdr_validate() and nft_bridge_ip6hdr_validate()
to net/bridge/netfilter/nft_reject_bridge.c.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Pablo Neira Ayuso committed Sep 12, 2016
1 parent ddc8b60 commit 10151d7
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 78 deletions.
7 changes: 0 additions & 7 deletions include/net/netfilter/nf_tables_bridge.h

This file was deleted.

72 changes: 2 additions & 70 deletions net/bridge/netfilter/nf_tables_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,79 +13,11 @@
#include <linux/module.h>
#include <linux/netfilter_bridge.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_bridge.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/netfilter/nf_tables_ipv4.h>
#include <net/netfilter/nf_tables_ipv6.h>

int nft_bridge_iphdr_validate(struct sk_buff *skb)
{
struct iphdr *iph;
u32 len;

if (!pskb_may_pull(skb, sizeof(struct iphdr)))
return 0;

iph = ip_hdr(skb);
if (iph->ihl < 5 || iph->version != 4)
return 0;

len = ntohs(iph->tot_len);
if (skb->len < len)
return 0;
else if (len < (iph->ihl*4))
return 0;

if (!pskb_may_pull(skb, iph->ihl*4))
return 0;

return 1;
}
EXPORT_SYMBOL_GPL(nft_bridge_iphdr_validate);

int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
{
struct ipv6hdr *hdr;
u32 pkt_len;

if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
return 0;

hdr = ipv6_hdr(skb);
if (hdr->version != 6)
return 0;

pkt_len = ntohs(hdr->payload_len);
if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
return 0;

return 1;
}
EXPORT_SYMBOL_GPL(nft_bridge_ip6hdr_validate);

static inline void nft_bridge_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
if (nft_bridge_iphdr_validate(skb))
nft_set_pktinfo_ipv4(pkt, skb, state);
else
nft_set_pktinfo_unspec(pkt, skb, state);
}

static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
#if IS_ENABLED(CONFIG_IPV6)
if (nft_bridge_ip6hdr_validate(skb) &&
nft_set_pktinfo_ipv6(pkt, skb, state) == 0)
return;
#endif
nft_set_pktinfo_unspec(pkt, skb, state);
}

static unsigned int
nft_do_chain_bridge(void *priv,
struct sk_buff *skb,
Expand All @@ -95,10 +27,10 @@ nft_do_chain_bridge(void *priv,

switch (eth_hdr(skb)->h_proto) {
case htons(ETH_P_IP):
nft_bridge_set_pktinfo_ipv4(&pkt, skb, state);
nft_set_pktinfo_ipv4_validate(&pkt, skb, state);
break;
case htons(ETH_P_IPV6):
nft_bridge_set_pktinfo_ipv6(&pkt, skb, state);
nft_set_pktinfo_ipv6_validate(&pkt, skb, state);
break;
default:
nft_set_pktinfo_unspec(&pkt, skb, state);
Expand Down
44 changes: 43 additions & 1 deletion net/bridge/netfilter/nft_reject_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nft_reject.h>
#include <net/netfilter/nf_tables_bridge.h>
#include <net/netfilter/ipv4/nf_reject.h>
#include <net/netfilter/ipv6/nf_reject.h>
#include <linux/ip.h>
Expand All @@ -37,6 +36,30 @@ static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
skb_pull(nskb, ETH_HLEN);
}

static int nft_bridge_iphdr_validate(struct sk_buff *skb)
{
struct iphdr *iph;
u32 len;

if (!pskb_may_pull(skb, sizeof(struct iphdr)))
return 0;

iph = ip_hdr(skb);
if (iph->ihl < 5 || iph->version != 4)
return 0;

len = ntohs(iph->tot_len);
if (skb->len < len)
return 0;
else if (len < (iph->ihl*4))
return 0;

if (!pskb_may_pull(skb, iph->ihl*4))
return 0;

return 1;
}

/* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT)
* or the bridge port (NF_BRIDGE PREROUTING).
*/
Expand Down Expand Up @@ -143,6 +166,25 @@ static void nft_reject_br_send_v4_unreach(struct net *net,
br_forward(br_port_get_rcu(dev), nskb, false, true);
}

static int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
{
struct ipv6hdr *hdr;
u32 pkt_len;

if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
return 0;

hdr = ipv6_hdr(skb);
if (hdr->version != 6)
return 0;

pkt_len = ntohs(hdr->payload_len);
if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
return 0;

return 1;
}

static void nft_reject_br_send_v6_tcp_reset(struct net *net,
struct sk_buff *oldskb,
const struct net_device *dev,
Expand Down

0 comments on commit 10151d7

Please sign in to comment.