Пример #1
0
/* Replicate the checks that IPv6 does on packet reception and pass the packet
 * to ip6tables.
 */
unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
				    struct sk_buff *skb,
				    const struct nf_hook_state *state)
{
	struct nf_bridge_info *nf_bridge;

	if (br_validate_ipv6(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->ipv6_daddr = ipv6_hdr(skb)->daddr;

	skb->protocol = htons(ETH_P_IPV6);
	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, state->sk, skb,
		skb->dev, NULL,
		br_nf_pre_routing_finish_ipv6);

	return NF_STOLEN;
}
Пример #2
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;
}
Пример #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(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;
}
Пример #4
0
/* 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(unsigned int hook,
    struct sk_buff *skb,
    const struct net_device *in,
    const struct net_device *out,
    int (*okfn)(struct sk_buff *)) {
  const struct ipv6hdr *hdr;
  u32 pkt_len;

  if (skb->len < sizeof(struct ipv6hdr)) {
    return NF_DROP;
  }

  if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) {
    return NF_DROP;
  }

  hdr = ipv6_hdr(skb);

  if (hdr->version != 6) {
    return NF_DROP;
  }

  pkt_len = ntohs(hdr->payload_len);

  if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
    if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
      return NF_DROP;
    }
    if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
      return NF_DROP;
    }
  }
  if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(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;
  }

  skb->protocol = htons(ETH_P_IPV6);
  NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
          br_nf_pre_routing_finish_ipv6);

  return NF_STOLEN;
}