示例#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;
}
示例#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;
}
示例#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;
}
示例#4
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(const struct nf_hook_ops *ops,
                                      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(ops, 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_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;

    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->sk, skb,
            skb->dev, NULL,
            br_nf_pre_routing_finish);

    return NF_STOLEN;
}
示例#5
0
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
	int ret;

	if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
	    skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
	    !skb_is_gso(skb)) {
		if (br_parse_ip_options(skb))
			/* Drop invalid packet */
			return NF_DROP;
		ret = ip_fragment(skb, br_dev_queue_push_xmit);
	} else
		ret = br_dev_queue_push_xmit(skb);

	return ret;
}
示例#6
0
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
	int ret;

	if (!skb_is_gso(skb) &&
	    skb->protocol == htons(ETH_P_IP) &&
	    skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu) {
		if (br_parse_ip_options(skb))
			/* Drop invalid packet */
			goto drop;
		ret = ip_fragment(skb, br_dev_queue_push_xmit);
	} else
		ret = br_dev_queue_push_xmit(skb);

	return ret;
drop:
	kfree_skb(skb);
	return 0;
}
示例#7
0
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
	int ret;
	int frag_max_size;

	/* This is wrong! We should preserve the original fragment
	 * boundaries by preserving frag_list rather than refragmenting.
	 */
	if (skb->protocol == htons(ETH_P_IP) &&
	    skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
	    !skb_is_gso(skb)) {
		frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size;
		if (br_parse_ip_options(skb))
			/* Drop invalid packet */
			return NF_DROP;
		IPCB(skb)->frag_max_size = frag_max_size;
		ret = ip_fragment(skb, br_dev_queue_push_xmit);
	} else
		ret = br_dev_queue_push_xmit(skb);

	return ret;
}
示例#8
0
static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb)
{
    int ret;
    int frag_max_size;
    unsigned int mtu_reserved;

    if (skb_is_gso(skb) || skb->protocol != htons(ETH_P_IP))
        return br_dev_queue_push_xmit(sk, skb);

    mtu_reserved = nf_bridge_mtu_reduction(skb);
    /* This is wrong! We should preserve the original fragment
     * boundaries by preserving frag_list rather than refragmenting.
     */
    if (skb->len + mtu_reserved > skb->dev->mtu) {
        struct brnf_frag_data *data;

        frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size;
        if (br_parse_ip_options(skb))
            /* Drop invalid packet */
            return NF_DROP;
        IPCB(skb)->frag_max_size = frag_max_size;

        nf_bridge_update_protocol(skb);

        data = this_cpu_ptr(&brnf_frag_data_storage);
        data->encap_size = nf_bridge_encap_header_len(skb);
        data->size = ETH_HLEN + data->encap_size;

        skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
                                         data->size);

        ret = ip_fragment(sk, skb, br_nf_push_frag_xmit);
    } else {
        ret = br_dev_queue_push_xmit(sk, skb);
    }

    return ret;
}