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;
}