Exemple #1
0
/* This is the 'purely bridged' case.  For IP, we pass the packet to
 * netfilter with indev and outdev set to the bridge device,
 * but we are still able to filter on the 'real' indev/outdev
 * because of the physdev module. For ARP, indev and outdev are the
 * bridge ports. */
static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops,
                                     struct sk_buff *skb,
                                     const struct nf_hook_state *state)
{
    struct nf_bridge_info *nf_bridge;
    struct net_device *parent;
    u_int8_t pf;

    if (!skb->nf_bridge)
        return NF_ACCEPT;

    /* Need exclusive nf_bridge_info since we might have multiple
     * different physoutdevs. */
    if (!nf_bridge_unshare(skb))
        return NF_DROP;

    nf_bridge = nf_bridge_info_get(skb);
    if (!nf_bridge)
        return NF_DROP;

    parent = bridge_parent(state->out);
    if (!parent)
        return NF_DROP;

    if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
        pf = NFPROTO_IPV4;
    else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
        pf = NFPROTO_IPV6;
    else
        return NF_ACCEPT;

    nf_bridge_pull_encap_header(skb);

    if (skb->pkt_type == PACKET_OTHERHOST) {
        skb->pkt_type = PACKET_HOST;
        nf_bridge->pkt_otherhost = true;
    }

    if (pf == NFPROTO_IPV4) {
        int frag_max = BR_INPUT_SKB_CB(skb)->frag_max_size;

        if (br_parse_ip_options(skb))
            return NF_DROP;

        IPCB(skb)->frag_max_size = frag_max;
    }

    nf_bridge->physoutdev = skb->dev;
    if (pf == NFPROTO_IPV4)
        skb->protocol = htons(ETH_P_IP);
    else
        skb->protocol = htons(ETH_P_IPV6);

    NF_HOOK(pf, NF_INET_FORWARD, NULL, skb,
            brnf_get_logical_dev(skb, state->in),
            parent,	br_nf_forward_finish);

    return NF_STOLEN;
}
Exemple #2
0
/* This is the 'purely bridged' case.  For IP, we pass the packet to
 * netfilter with indev and outdev set to the bridge device,
 * but we are still able to filter on the 'real' indev/outdev
 * because of the physdev module. For ARP, indev and outdev are the
 * bridge ports. */
static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                                     const struct net_device *in,
                                     const struct net_device *out,
                                     int (*okfn)(struct sk_buff *)) {
  struct nf_bridge_info *nf_bridge;
  struct net_device *parent;
  u_int8_t pf;

  if (!skb->nf_bridge) {
    return NF_ACCEPT;
  }

  /* Need exclusive nf_bridge_info since we might have multiple
   * different physoutdevs. */
  if (!nf_bridge_unshare(skb)) {
    return NF_DROP;
  }

  parent = bridge_parent(out);
  if (!parent) {
    return NF_DROP;
  }

  if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb)) {
    pf = NFPROTO_IPV4;
  } else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
    pf = NFPROTO_IPV6;
  } else {
    return NF_ACCEPT;
  }

  nf_bridge_pull_encap_header(skb);

  nf_bridge = skb->nf_bridge;
  if (skb->pkt_type == PACKET_OTHERHOST) {
    skb->pkt_type = PACKET_HOST;
    nf_bridge->mask |= BRNF_PKT_TYPE;
  }

  if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb)) {
    return NF_DROP;
  }

  /* The physdev module checks on this */
  nf_bridge->mask |= BRNF_BRIDGED;
  nf_bridge->physoutdev = skb->dev;
  if (pf == NFPROTO_IPV4) {
    skb->protocol = htons(ETH_P_IP);
  } else {
    skb->protocol = htons(ETH_P_IPV6);
  }

  NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, in), parent,
          br_nf_forward_finish);

  return NF_STOLEN;
}
Exemple #3
0
/* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
 * Replicate the checks that IPv4 does on packet reception.
 * Set skb->dev to the bridge device (i.e. parent of the
 * receiving device) to make netfilter happy, the REDIRECT
 * target in particular.  Save the original destination IP
 * address to be able to detect DNAT afterwards. */
static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
                                      const struct net_device *in,
                                      const struct net_device *out,
                                      int (*okfn)(struct sk_buff *)) {
  struct net_bridge_port *p;
  struct net_bridge *br;
  __u32 len = nf_bridge_encap_header_len(skb);

  if (unlikely(!pskb_may_pull(skb, len))) {
    return NF_DROP;
  }

  p = br_port_get_rcu(in);
  if (p == NULL) {
    return NF_DROP;
  }
  br = p->br;

  if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
    if (!brnf_call_ip6tables && !br->nf_call_ip6tables) {
      return NF_ACCEPT;
    }

    nf_bridge_pull_encap_header_rcsum(skb);
    return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
  }

  if (!brnf_call_iptables && !br->nf_call_iptables) {
    return NF_ACCEPT;
  }

  if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb)) {
    return NF_ACCEPT;
  }

  nf_bridge_pull_encap_header_rcsum(skb);

  if (br_parse_ip_options(skb)) {
    return NF_DROP;
  }

  nf_bridge_put(skb->nf_bridge);
  if (!nf_bridge_alloc(skb)) {
    return NF_DROP;
  }
  if (!setup_pre_routing(skb)) {
    return NF_DROP;
  }
  store_orig_dstaddr(skb);
  skb->protocol = htons(ETH_P_IP);

  NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
          br_nf_pre_routing_finish);

  return NF_STOLEN;
}
/* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
 * Replicate the checks that IPv4 does on packet reception.
 * Set skb->dev to the bridge device (i.e. parent of the
 * receiving device) to make netfilter happy, the REDIRECT
 * target in particular.  Save the original destination IP
 * address to be able to detect DNAT afterwards. */
static unsigned int br_nf_pre_routing(void *priv,
				      struct sk_buff *skb,
				      const struct nf_hook_state *state)
{
	struct nf_bridge_info *nf_bridge;
	struct net_bridge_port *p;
	struct net_bridge *br;
	__u32 len = nf_bridge_encap_header_len(skb);

	if (unlikely(!pskb_may_pull(skb, len)))
		return NF_DROP;

	p = br_port_get_rcu(state->in);
	if (p == NULL)
		return NF_DROP;
	br = p->br;

	if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
		if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
			return NF_ACCEPT;

		nf_bridge_pull_encap_header_rcsum(skb);
		return br_nf_pre_routing_ipv6(priv, skb, state);
	}

	if (!brnf_call_iptables && !br->nf_call_iptables)
		return NF_ACCEPT;

	if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb))
		return NF_ACCEPT;

	nf_bridge_pull_encap_header_rcsum(skb);

	if (br_validate_ipv4(state->net, skb))
		return NF_DROP;

	nf_bridge_put(skb->nf_bridge);
	if (!nf_bridge_alloc(skb))
		return NF_DROP;
	if (!setup_pre_routing(skb))
		return NF_DROP;

	nf_bridge = nf_bridge_info_get(skb);
	nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr;

	skb->protocol = htons(ETH_P_IP);

	NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->net, state->sk, skb,
		skb->dev, NULL,
		br_nf_pre_routing_finish);

	return NF_STOLEN;
}
/* PF_BRIDGE/POST_ROUTING ********************************************/
static unsigned int br_nf_post_routing(void *priv,
				       struct sk_buff *skb,
				       const struct nf_hook_state *state)
{
	struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
	struct net_device *realoutdev = bridge_parent(skb->dev);
	u_int8_t pf;

	/* if nf_bridge is set, but ->physoutdev is NULL, this packet came in
	 * on a bridge, but was delivered locally and is now being routed:
	 *
	 * POST_ROUTING was already invoked from the ip stack.
	 */
	if (!nf_bridge || !nf_bridge->physoutdev)
		return NF_ACCEPT;

	if (!realoutdev)
		return NF_DROP;

	if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
		pf = NFPROTO_IPV4;
	else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
		pf = NFPROTO_IPV6;
	else
		return NF_ACCEPT;

	/* We assume any code from br_dev_queue_push_xmit onwards doesn't care
	 * about the value of skb->pkt_type. */
	if (skb->pkt_type == PACKET_OTHERHOST) {
		skb->pkt_type = PACKET_HOST;
		nf_bridge->pkt_otherhost = true;
	}

	nf_bridge_pull_encap_header(skb);
	if (pf == NFPROTO_IPV4)
		skb->protocol = htons(ETH_P_IP);
	else
		skb->protocol = htons(ETH_P_IPV6);

	NF_HOOK(pf, NF_INET_POST_ROUTING, state->net, state->sk, skb,
		NULL, realoutdev,
		br_nf_dev_queue_xmit);

	return NF_STOLEN;
}
Exemple #6
0
/* PF_BRIDGE/POST_ROUTING ********************************************/
static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
                                       const struct net_device *in,
                                       const struct net_device *out,
                                       int (*okfn)(struct sk_buff *)) {
  struct nf_bridge_info *nf_bridge = skb->nf_bridge;
  struct net_device *realoutdev = bridge_parent(skb->dev);
  u_int8_t pf;

  if (!nf_bridge || !(nf_bridge->mask & BRNF_BRIDGED)) {
    return NF_ACCEPT;
  }

  if (!realoutdev) {
    return NF_DROP;
  }

  if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb)) {
    pf = NFPROTO_IPV4;
  } else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
    pf = NFPROTO_IPV6;
  } else {
    return NF_ACCEPT;
  }

  /* We assume any code from br_dev_queue_push_xmit onwards doesn't care
   * about the value of skb->pkt_type. */
  if (skb->pkt_type == PACKET_OTHERHOST) {
    skb->pkt_type = PACKET_HOST;
    nf_bridge->mask |= BRNF_PKT_TYPE;
  }

  nf_bridge_pull_encap_header(skb);
  nf_bridge_save_header(skb);
  if (pf == NFPROTO_IPV4) {
    skb->protocol = htons(ETH_P_IP);
  } else {
    skb->protocol = htons(ETH_P_IPV6);
  }

  NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev,
          br_nf_dev_queue_xmit);

  return NF_STOLEN;
}