remarkable-linux/net/netfilter/nft_fib_inet.c
Florian Westphal f6d0cbcf09 netfilter: nf_tables: add fib expression
Add FIB expression, supported for ipv4, ipv6 and inet family (the latter
just dispatches to ipv4 or ipv6 one based on nfproto).

Currently supports fetching output interface index/name and the
rtm_type associated with an address.

This can be used for adding path filtering. rtm_type is useful
to e.g. enforce a strong-end host model where packets
are only accepted if daddr is configured on the interface the
packet arrived on.

The fib expression is a native nftables alternative to the
xtables addrtype and rp_filter matches.

FIB result order for oif/oifname retrieval is as follows:
 - if packet is local (skb has rtable, RTF_LOCAL set, this
   will also catch looped-back multicast packets), set oif to
   the loopback interface.
 - if fib lookup returns an error, or result points to local,
   store zero result.  This means '--local' option of -m rpfilter
   is not supported. It is possible to use 'fib type local' or add
   explicit saddr/daddr matching rules to create exceptions if this
   is really needed.
 - store result in the destination register.
   In case of multiple routes, search set for desired oif in case
   strict matching is requested.

ipv4 and ipv6 behave fib expressions are supposed to behave the same.

[ I have collapsed Arnd Bergmann's ("netfilter: nf_tables: fib warnings")

	http://patchwork.ozlabs.org/patch/688615/

  to address fallout from this patch after rebasing nf-next, that was
  posted to address compilation warnings. --pablo ]

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-11-01 20:50:14 +01:00

83 lines
2 KiB
C

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nft_fib.h>
static void nft_fib_inet_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
{
const struct nft_fib *priv = nft_expr_priv(expr);
switch (pkt->pf) {
case NFPROTO_IPV4:
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
case NFT_FIB_RESULT_OIFNAME:
return nft_fib4_eval(expr, regs, pkt);
case NFT_FIB_RESULT_ADDRTYPE:
return nft_fib4_eval_type(expr, regs, pkt);
}
break;
case NFPROTO_IPV6:
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
case NFT_FIB_RESULT_OIFNAME:
return nft_fib6_eval(expr, regs, pkt);
case NFT_FIB_RESULT_ADDRTYPE:
return nft_fib6_eval_type(expr, regs, pkt);
}
break;
}
regs->verdict.code = NF_DROP;
}
static struct nft_expr_type nft_fib_inet_type;
static const struct nft_expr_ops nft_fib_inet_ops = {
.type = &nft_fib_inet_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_fib)),
.eval = nft_fib_inet_eval,
.init = nft_fib_init,
.dump = nft_fib_dump,
.validate = nft_fib_validate,
};
static struct nft_expr_type nft_fib_inet_type __read_mostly = {
.family = NFPROTO_INET,
.name = "fib",
.ops = &nft_fib_inet_ops,
.policy = nft_fib_policy,
.maxattr = NFTA_FIB_MAX,
.owner = THIS_MODULE,
};
static int __init nft_fib_inet_module_init(void)
{
return nft_register_expr(&nft_fib_inet_type);
}
static void __exit nft_fib_inet_module_exit(void)
{
nft_unregister_expr(&nft_fib_inet_type);
}
module_init(nft_fib_inet_module_init);
module_exit(nft_fib_inet_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
MODULE_ALIAS_NFT_AF_EXPR(1, "fib");