linux/net/bridge/netfilter/ebtable_broute.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  ebtable_broute
   4 *
   5 *      Authors:
   6 *      Bart De Schuymer <bdschuym@pandora.be>
   7 *
   8 *  April, 2002
   9 *
  10 *  This table lets you choose between routing and bridging for frames
  11 *  entering on a bridge enslaved nic. This table is traversed before any
  12 *  other ebtables table. See net/bridge/br_input.c.
  13 */
  14
  15#include <linux/netfilter_bridge/ebtables.h>
  16#include <linux/module.h>
  17#include <linux/if_bridge.h>
  18
  19#include "../br_private.h"
  20
  21/* EBT_ACCEPT means the frame will be bridged
  22 * EBT_DROP means the frame will be routed
  23 */
  24static struct ebt_entries initial_chain = {
  25        .name           = "BROUTING",
  26        .policy         = EBT_ACCEPT,
  27};
  28
  29static struct ebt_replace_kernel initial_table = {
  30        .name           = "broute",
  31        .valid_hooks    = 1 << NF_BR_BROUTING,
  32        .entries_size   = sizeof(struct ebt_entries),
  33        .hook_entry     = {
  34                [NF_BR_BROUTING]        = &initial_chain,
  35        },
  36        .entries        = (char *)&initial_chain,
  37};
  38
  39static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
  40{
  41        if (valid_hooks & ~(1 << NF_BR_BROUTING))
  42                return -EINVAL;
  43        return 0;
  44}
  45
  46static const struct ebt_table broute_table = {
  47        .name           = "broute",
  48        .table          = &initial_table,
  49        .valid_hooks    = 1 << NF_BR_BROUTING,
  50        .check          = check,
  51        .me             = THIS_MODULE,
  52};
  53
  54static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
  55                               const struct nf_hook_state *s)
  56{
  57        struct net_bridge_port *p = br_port_get_rcu(skb->dev);
  58        struct nf_hook_state state;
  59        unsigned char *dest;
  60        int ret;
  61
  62        if (!p || p->state != BR_STATE_FORWARDING)
  63                return NF_ACCEPT;
  64
  65        nf_hook_state_init(&state, NF_BR_BROUTING,
  66                           NFPROTO_BRIDGE, s->in, NULL, NULL,
  67                           s->net, NULL);
  68
  69        ret = ebt_do_table(skb, &state, state.net->xt.broute_table);
  70
  71        if (ret != NF_DROP)
  72                return ret;
  73
  74        /* DROP in ebtables -t broute means that the
  75         * skb should be routed, not bridged.
  76         * This is awkward, but can't be changed for compatibility
  77         * reasons.
  78         *
  79         * We map DROP to ACCEPT and set the ->br_netfilter_broute flag.
  80         */
  81        BR_INPUT_SKB_CB(skb)->br_netfilter_broute = 1;
  82
  83        /* undo PACKET_HOST mangling done in br_input in case the dst
  84         * address matches the logical bridge but not the port.
  85         */
  86        dest = eth_hdr(skb)->h_dest;
  87        if (skb->pkt_type == PACKET_HOST &&
  88            !ether_addr_equal(skb->dev->dev_addr, dest) &&
  89             ether_addr_equal(p->br->dev->dev_addr, dest))
  90                skb->pkt_type = PACKET_OTHERHOST;
  91
  92        return NF_ACCEPT;
  93}
  94
  95static const struct nf_hook_ops ebt_ops_broute = {
  96        .hook           = ebt_broute,
  97        .pf             = NFPROTO_BRIDGE,
  98        .hooknum        = NF_BR_PRE_ROUTING,
  99        .priority       = NF_BR_PRI_FIRST,
 100};
 101
 102static int __net_init broute_net_init(struct net *net)
 103{
 104        return ebt_register_table(net, &broute_table, &ebt_ops_broute,
 105                                  &net->xt.broute_table);
 106}
 107
 108static void __net_exit broute_net_exit(struct net *net)
 109{
 110        ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute);
 111}
 112
 113static struct pernet_operations broute_net_ops = {
 114        .init = broute_net_init,
 115        .exit = broute_net_exit,
 116};
 117
 118static int __init ebtable_broute_init(void)
 119{
 120        return register_pernet_subsys(&broute_net_ops);
 121}
 122
 123static void __exit ebtable_broute_fini(void)
 124{
 125        unregister_pernet_subsys(&broute_net_ops);
 126}
 127
 128module_init(ebtable_broute_init);
 129module_exit(ebtable_broute_fini);
 130MODULE_LICENSE("GPL");
 131