You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
netfilter: add nftables
This patch adds nftables which is the intended successor of iptables. This packet filtering framework reuses the existing netfilter hooks, the connection tracking system, the NAT subsystem, the transparent proxying engine, the logging infrastructure and the userspace packet queueing facilities. In a nutshell, nftables provides a pseudo-state machine with 4 general purpose registers of 128 bits and 1 specific purpose register to store verdicts. This pseudo-machine comes with an extensible instruction set, a.k.a. "expressions" in the nftables jargon. The expressions included in this patch provide the basic functionality, they are: * bitwise: to perform bitwise operations. * byteorder: to change from host/network endianess. * cmp: to compare data with the content of the registers. * counter: to enable counters on rules. * ct: to store conntrack keys into register. * exthdr: to match IPv6 extension headers. * immediate: to load data into registers. * limit: to limit matching based on packet rate. * log: to log packets. * meta: to match metainformation that usually comes with the skbuff. * nat: to perform Network Address Translation. * payload: to fetch data from the packet payload and store it into registers. * reject (IPv4 only): to explicitly close connection, eg. TCP RST. Using this instruction-set, the userspace utility 'nft' can transform the rules expressed in human-readable text representation (using a new syntax, inspired by tcpdump) to nftables bytecode. nftables also inherits the table, chain and rule objects from iptables, but in a more configurable way, and it also includes the original datatype-agnostic set infrastructure with mapping support. This set infrastructure is enhanced in the follow up patch (netfilter: nf_tables: add netlink set API). This patch includes the following components: * the netlink API: net/netfilter/nf_tables_api.c and include/uapi/netfilter/nf_tables.h * the packet filter core: net/netfilter/nf_tables_core.c * the expressions (described above): net/netfilter/nft_*.c * the filter tables: arp, IPv4, IPv6 and bridge: net/ipv4/netfilter/nf_tables_ipv4.c net/ipv6/netfilter/nf_tables_ipv6.c net/ipv4/netfilter/nf_tables_arp.c net/bridge/netfilter/nf_tables_bridge.c * the NAT table (IPv4 only): net/ipv4/netfilter/nf_table_nat_ipv4.c * the route table (similar to mangle): net/ipv4/netfilter/nf_table_route_ipv4.c net/ipv6/netfilter/nf_table_route_ipv6.c * internal definitions under: include/net/netfilter/nf_tables.h include/net/netfilter/nf_tables_core.h * It also includes an skeleton expression: net/netfilter/nft_expr_template.c and the preliminary implementation of the meta target net/netfilter/nft_meta_target.c It also includes a change in struct nf_hook_ops to add a new pointer to store private data to the hook, that is used to store the rule list per chain. This patch is based on the patch from Patrick McHardy, plus merged accumulated cleanups, fixes and small enhancements to the nftables code that has been done since 2009, which are: From Patrick McHardy: * nf_tables: adjust netlink handler function signatures * nf_tables: only retry table lookup after successful table module load * nf_tables: fix event notification echo and avoid unnecessary messages * nft_ct: add l3proto support * nf_tables: pass expression context to nft_validate_data_load() * nf_tables: remove redundant definition * nft_ct: fix maxattr initialization * nf_tables: fix invalid event type in nf_tables_getrule() * nf_tables: simplify nft_data_init() usage * nf_tables: build in more core modules * nf_tables: fix double lookup expression unregistation * nf_tables: move expression initialization to nf_tables_core.c * nf_tables: build in payload module * nf_tables: use NFPROTO constants * nf_tables: rename pid variables to portid * nf_tables: save 48 bits per rule * nf_tables: introduce chain rename * nf_tables: check for duplicate names on chain rename * nf_tables: remove ability to specify handles for new rules * nf_tables: return error for rule change request * nf_tables: return error for NLM_F_REPLACE without rule handle * nf_tables: include NLM_F_APPEND/NLM_F_REPLACE flags in rule notification * nf_tables: fix NLM_F_MULTI usage in netlink notifications * nf_tables: include NLM_F_APPEND in rule dumps From Pablo Neira Ayuso: * nf_tables: fix stack overflow in nf_tables_newrule * nf_tables: nft_ct: fix compilation warning * nf_tables: nft_ct: fix crash with invalid packets * nft_log: group and qthreshold are 2^16 * nf_tables: nft_meta: fix socket uid,gid handling * nft_counter: allow to restore counters * nf_tables: fix module autoload * nf_tables: allow to remove all rules placed in one chain * nf_tables: use 64-bits rule handle instead of 16-bits * nf_tables: fix chain after rule deletion * nf_tables: improve deletion performance * nf_tables: add missing code in route chain type * nf_tables: rise maximum number of expressions from 12 to 128 * nf_tables: don't delete table if in use * nf_tables: fix basechain release From Tomasz Bursztyka: * nf_tables: Add support for changing users chain's name * nf_tables: Change chain's name to be fixed sized * nf_tables: Add support for replacing a rule by another one * nf_tables: Update uapi nftables netlink header documentation From Florian Westphal: * nft_log: group is u16, snaplen u32 From Phil Oester: * nf_tables: operational limit match Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
committed by
Pablo Neira Ayuso
parent
f59cb0453c
commit
96518518cc
@@ -53,12 +53,13 @@ struct nf_hook_ops {
|
||||
struct list_head list;
|
||||
|
||||
/* User fills in from here down. */
|
||||
nf_hookfn *hook;
|
||||
struct module *owner;
|
||||
u_int8_t pf;
|
||||
unsigned int hooknum;
|
||||
nf_hookfn *hook;
|
||||
struct module *owner;
|
||||
void *priv;
|
||||
u_int8_t pf;
|
||||
unsigned int hooknum;
|
||||
/* Hooks are ordered in ascending priority. */
|
||||
int priority;
|
||||
int priority;
|
||||
};
|
||||
|
||||
struct nf_sockopt_ops {
|
||||
|
||||
301
include/net/netfilter/nf_tables.h
Normal file
301
include/net/netfilter/nf_tables.h
Normal file
@@ -0,0 +1,301 @@
|
||||
#ifndef _NET_NF_TABLES_H
|
||||
#define _NET_NF_TABLES_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
struct nft_pktinfo {
|
||||
struct sk_buff *skb;
|
||||
const struct net_device *in;
|
||||
const struct net_device *out;
|
||||
u8 hooknum;
|
||||
u8 nhoff;
|
||||
u8 thoff;
|
||||
};
|
||||
|
||||
struct nft_data {
|
||||
union {
|
||||
u32 data[4];
|
||||
struct {
|
||||
u32 verdict;
|
||||
struct nft_chain *chain;
|
||||
};
|
||||
};
|
||||
} __attribute__((aligned(__alignof__(u64))));
|
||||
|
||||
static inline int nft_data_cmp(const struct nft_data *d1,
|
||||
const struct nft_data *d2,
|
||||
unsigned int len)
|
||||
{
|
||||
return memcmp(d1->data, d2->data, len);
|
||||
}
|
||||
|
||||
static inline void nft_data_copy(struct nft_data *dst,
|
||||
const struct nft_data *src)
|
||||
{
|
||||
BUILD_BUG_ON(__alignof__(*dst) != __alignof__(u64));
|
||||
*(u64 *)&dst->data[0] = *(u64 *)&src->data[0];
|
||||
*(u64 *)&dst->data[2] = *(u64 *)&src->data[2];
|
||||
}
|
||||
|
||||
static inline void nft_data_debug(const struct nft_data *data)
|
||||
{
|
||||
pr_debug("data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n",
|
||||
data->data[0], data->data[1],
|
||||
data->data[2], data->data[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct nft_ctx - nf_tables rule context
|
||||
*
|
||||
* @afi: address family info
|
||||
* @table: the table the chain is contained in
|
||||
* @chain: the chain the rule is contained in
|
||||
*/
|
||||
struct nft_ctx {
|
||||
const struct nft_af_info *afi;
|
||||
const struct nft_table *table;
|
||||
const struct nft_chain *chain;
|
||||
};
|
||||
|
||||
enum nft_data_types {
|
||||
NFT_DATA_VALUE,
|
||||
NFT_DATA_VERDICT,
|
||||
};
|
||||
|
||||
struct nft_data_desc {
|
||||
enum nft_data_types type;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
extern int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
|
||||
struct nft_data_desc *desc, const struct nlattr *nla);
|
||||
extern void nft_data_uninit(const struct nft_data *data,
|
||||
enum nft_data_types type);
|
||||
extern int nft_data_dump(struct sk_buff *skb, int attr,
|
||||
const struct nft_data *data,
|
||||
enum nft_data_types type, unsigned int len);
|
||||
|
||||
static inline enum nft_data_types nft_dreg_to_type(enum nft_registers reg)
|
||||
{
|
||||
return reg == NFT_REG_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE;
|
||||
}
|
||||
|
||||
extern int nft_validate_input_register(enum nft_registers reg);
|
||||
extern int nft_validate_output_register(enum nft_registers reg);
|
||||
extern int nft_validate_data_load(const struct nft_ctx *ctx,
|
||||
enum nft_registers reg,
|
||||
const struct nft_data *data,
|
||||
enum nft_data_types type);
|
||||
|
||||
/**
|
||||
* struct nft_expr_ops - nf_tables expression operations
|
||||
*
|
||||
* @eval: Expression evaluation function
|
||||
* @init: initialization function
|
||||
* @destroy: destruction function
|
||||
* @dump: function to dump parameters
|
||||
* @list: used internally
|
||||
* @name: Identifier
|
||||
* @owner: module reference
|
||||
* @policy: netlink attribute policy
|
||||
* @maxattr: highest netlink attribute number
|
||||
* @size: full expression size, including private data size
|
||||
*/
|
||||
struct nft_expr;
|
||||
struct nft_expr_ops {
|
||||
void (*eval)(const struct nft_expr *expr,
|
||||
struct nft_data data[NFT_REG_MAX + 1],
|
||||
const struct nft_pktinfo *pkt);
|
||||
int (*init)(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[]);
|
||||
void (*destroy)(const struct nft_expr *expr);
|
||||
int (*dump)(struct sk_buff *skb,
|
||||
const struct nft_expr *expr);
|
||||
|
||||
struct list_head list;
|
||||
const char *name;
|
||||
struct module *owner;
|
||||
const struct nla_policy *policy;
|
||||
unsigned int maxattr;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
#define NFT_EXPR_SIZE(size) (sizeof(struct nft_expr) + \
|
||||
ALIGN(size, __alignof__(struct nft_expr)))
|
||||
|
||||
/**
|
||||
* struct nft_expr - nf_tables expression
|
||||
*
|
||||
* @ops: expression ops
|
||||
* @data: expression private data
|
||||
*/
|
||||
struct nft_expr {
|
||||
const struct nft_expr_ops *ops;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
static inline void *nft_expr_priv(const struct nft_expr *expr)
|
||||
{
|
||||
return (void *)expr->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct nft_rule - nf_tables rule
|
||||
*
|
||||
* @list: used internally
|
||||
* @rcu_head: used internally for rcu
|
||||
* @handle: rule handle
|
||||
* @dlen: length of expression data
|
||||
* @data: expression data
|
||||
*/
|
||||
struct nft_rule {
|
||||
struct list_head list;
|
||||
struct rcu_head rcu_head;
|
||||
u64 handle:48,
|
||||
dlen:16;
|
||||
unsigned char data[]
|
||||
__attribute__((aligned(__alignof__(struct nft_expr))));
|
||||
};
|
||||
|
||||
static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule)
|
||||
{
|
||||
return (struct nft_expr *)&rule->data[0];
|
||||
}
|
||||
|
||||
static inline struct nft_expr *nft_expr_next(const struct nft_expr *expr)
|
||||
{
|
||||
return ((void *)expr) + expr->ops->size;
|
||||
}
|
||||
|
||||
static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
|
||||
{
|
||||
return (struct nft_expr *)&rule->data[rule->dlen];
|
||||
}
|
||||
|
||||
/*
|
||||
* The last pointer isn't really necessary, but the compiler isn't able to
|
||||
* determine that the result of nft_expr_last() is always the same since it
|
||||
* can't assume that the dlen value wasn't changed within calls in the loop.
|
||||
*/
|
||||
#define nft_rule_for_each_expr(expr, last, rule) \
|
||||
for ((expr) = nft_expr_first(rule), (last) = nft_expr_last(rule); \
|
||||
(expr) != (last); \
|
||||
(expr) = nft_expr_next(expr))
|
||||
|
||||
enum nft_chain_flags {
|
||||
NFT_BASE_CHAIN = 0x1,
|
||||
NFT_CHAIN_BUILTIN = 0x2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nft_chain - nf_tables chain
|
||||
*
|
||||
* @rules: list of rules in the chain
|
||||
* @list: used internally
|
||||
* @rcu_head: used internally
|
||||
* @handle: chain handle
|
||||
* @flags: bitmask of enum nft_chain_flags
|
||||
* @use: number of jump references to this chain
|
||||
* @level: length of longest path to this chain
|
||||
* @name: name of the chain
|
||||
*/
|
||||
struct nft_chain {
|
||||
struct list_head rules;
|
||||
struct list_head list;
|
||||
struct rcu_head rcu_head;
|
||||
u64 handle;
|
||||
u8 flags;
|
||||
u16 use;
|
||||
u16 level;
|
||||
char name[NFT_CHAIN_MAXNAMELEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nft_base_chain - nf_tables base chain
|
||||
*
|
||||
* @ops: netfilter hook ops
|
||||
* @chain: the chain
|
||||
*/
|
||||
struct nft_base_chain {
|
||||
struct nf_hook_ops ops;
|
||||
struct nft_chain chain;
|
||||
};
|
||||
|
||||
static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chain)
|
||||
{
|
||||
return container_of(chain, struct nft_base_chain, chain);
|
||||
}
|
||||
|
||||
extern unsigned int nft_do_chain(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *));
|
||||
|
||||
enum nft_table_flags {
|
||||
NFT_TABLE_BUILTIN = 0x1,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nft_table - nf_tables table
|
||||
*
|
||||
* @list: used internally
|
||||
* @chains: chains in the table
|
||||
* @sets: sets in the table
|
||||
* @hgenerator: handle generator state
|
||||
* @use: number of chain references to this table
|
||||
* @flags: table flag (see enum nft_table_flags)
|
||||
* @name: name of the table
|
||||
*/
|
||||
struct nft_table {
|
||||
struct list_head list;
|
||||
struct list_head chains;
|
||||
struct list_head sets;
|
||||
u64 hgenerator;
|
||||
u32 use;
|
||||
u16 flags;
|
||||
char name[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nft_af_info - nf_tables address family info
|
||||
*
|
||||
* @list: used internally
|
||||
* @family: address family
|
||||
* @nhooks: number of hooks in this family
|
||||
* @owner: module owner
|
||||
* @tables: used internally
|
||||
* @hooks: hookfn overrides for packet validation
|
||||
*/
|
||||
struct nft_af_info {
|
||||
struct list_head list;
|
||||
int family;
|
||||
unsigned int nhooks;
|
||||
struct module *owner;
|
||||
struct list_head tables;
|
||||
nf_hookfn *hooks[NF_MAX_HOOKS];
|
||||
};
|
||||
|
||||
extern int nft_register_afinfo(struct nft_af_info *);
|
||||
extern void nft_unregister_afinfo(struct nft_af_info *);
|
||||
|
||||
extern int nft_register_table(struct nft_table *, int family);
|
||||
extern void nft_unregister_table(struct nft_table *, int family);
|
||||
|
||||
extern int nft_register_expr(struct nft_expr_ops *);
|
||||
extern void nft_unregister_expr(struct nft_expr_ops *);
|
||||
|
||||
#define MODULE_ALIAS_NFT_FAMILY(family) \
|
||||
MODULE_ALIAS("nft-afinfo-" __stringify(family))
|
||||
|
||||
#define MODULE_ALIAS_NFT_TABLE(family, name) \
|
||||
MODULE_ALIAS("nft-table-" __stringify(family) "-" name)
|
||||
|
||||
#define MODULE_ALIAS_NFT_EXPR(name) \
|
||||
MODULE_ALIAS("nft-expr-" name)
|
||||
|
||||
#endif /* _NET_NF_TABLES_H */
|
||||
25
include/net/netfilter/nf_tables_core.h
Normal file
25
include/net/netfilter/nf_tables_core.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _NET_NF_TABLES_CORE_H
|
||||
#define _NET_NF_TABLES_CORE_H
|
||||
|
||||
extern int nf_tables_core_module_init(void);
|
||||
extern void nf_tables_core_module_exit(void);
|
||||
|
||||
extern int nft_immediate_module_init(void);
|
||||
extern void nft_immediate_module_exit(void);
|
||||
|
||||
extern int nft_cmp_module_init(void);
|
||||
extern void nft_cmp_module_exit(void);
|
||||
|
||||
extern int nft_lookup_module_init(void);
|
||||
extern void nft_lookup_module_exit(void);
|
||||
|
||||
extern int nft_bitwise_module_init(void);
|
||||
extern void nft_bitwise_module_exit(void);
|
||||
|
||||
extern int nft_byteorder_module_init(void);
|
||||
extern void nft_byteorder_module_exit(void);
|
||||
|
||||
extern int nft_payload_module_init(void);
|
||||
extern void nft_payload_module_exit(void);
|
||||
|
||||
#endif /* _NET_NF_TABLES_CORE_H */
|
||||
@@ -5,6 +5,7 @@ header-y += nf_conntrack_ftp.h
|
||||
header-y += nf_conntrack_sctp.h
|
||||
header-y += nf_conntrack_tcp.h
|
||||
header-y += nf_conntrack_tuple_common.h
|
||||
header-y += nf_tables.h
|
||||
header-y += nf_nat.h
|
||||
header-y += nfnetlink.h
|
||||
header-y += nfnetlink_acct.h
|
||||
|
||||
@@ -25,6 +25,10 @@ enum ip_conntrack_info {
|
||||
IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
|
||||
};
|
||||
|
||||
#define NF_CT_STATE_INVALID_BIT (1 << 0)
|
||||
#define NF_CT_STATE_BIT(ctinfo) (1 << ((ctinfo) % IP_CT_IS_REPLY + 1))
|
||||
#define NF_CT_STATE_UNTRACKED_BIT (1 << (IP_CT_NUMBER + 1))
|
||||
|
||||
/* Bitset representing status of connection. */
|
||||
enum ip_conntrack_status {
|
||||
/* It's an expected connection: bit 0 set. This bit never changed */
|
||||
|
||||
582
include/uapi/linux/netfilter/nf_tables.h
Normal file
582
include/uapi/linux/netfilter/nf_tables.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,8 @@ enum nfnetlink_groups {
|
||||
#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
|
||||
NFNLGRP_CONNTRACK_EXP_DESTROY,
|
||||
#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
|
||||
NFNLGRP_NFTABLES,
|
||||
#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
|
||||
__NFNLGRP_MAX,
|
||||
};
|
||||
#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
|
||||
@@ -51,6 +53,7 @@ struct nfgenmsg {
|
||||
#define NFNL_SUBSYS_ACCT 7
|
||||
#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
|
||||
#define NFNL_SUBSYS_CTHELPER 9
|
||||
#define NFNL_SUBSYS_COUNT 10
|
||||
#define NFNL_SUBSYS_NFTABLES 10
|
||||
#define NFNL_SUBSYS_COUNT 11
|
||||
|
||||
#endif /* _UAPI_NFNETLINK_H */
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#
|
||||
# Bridge netfilter configuration
|
||||
#
|
||||
#
|
||||
config NF_TABLES_BRIDGE
|
||||
tristate "Ethernet Bridge nf_tables support"
|
||||
|
||||
menuconfig BRIDGE_NF_EBTABLES
|
||||
tristate "Ethernet Bridge tables (ebtables) support"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Makefile for the netfilter modules for Link Layer filtering on a bridge.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o
|
||||
|
||||
obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
|
||||
|
||||
# tables
|
||||
|
||||
37
net/bridge/netfilter/nf_tables_bridge.c
Normal file
37
net/bridge/netfilter/nf_tables_bridge.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
static struct nft_af_info nft_af_bridge __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.nhooks = NF_BR_NUMHOOKS,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init nf_tables_bridge_init(void)
|
||||
{
|
||||
return nft_register_afinfo(&nft_af_bridge);
|
||||
}
|
||||
|
||||
static void __exit nf_tables_bridge_exit(void)
|
||||
{
|
||||
nft_unregister_afinfo(&nft_af_bridge);
|
||||
}
|
||||
|
||||
module_init(nf_tables_bridge_init);
|
||||
module_exit(nf_tables_bridge_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_FAMILY(AF_BRIDGE);
|
||||
@@ -36,6 +36,22 @@ config NF_CONNTRACK_PROC_COMPAT
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config NF_TABLES_IPV4
|
||||
depends on NF_TABLES
|
||||
tristate "IPv4 nf_tables support"
|
||||
|
||||
config NFT_REJECT_IPV4
|
||||
depends on NF_TABLES_IPV4
|
||||
tristate "nf_tables IPv4 reject support"
|
||||
|
||||
config NF_TABLE_ROUTE_IPV4
|
||||
depends on NF_TABLES_IPV4
|
||||
tristate "IPv4 nf_tables route table support"
|
||||
|
||||
config NF_TABLE_NAT_IPV4
|
||||
depends on NF_TABLES_IPV4
|
||||
tristate "IPv4 nf_tables nat table support"
|
||||
|
||||
config IP_NF_IPTABLES
|
||||
tristate "IP tables support (required for filtering/masq/NAT)"
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
|
||||
@@ -27,6 +27,11 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
|
||||
# NAT protocols (nf_nat)
|
||||
obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
|
||||
|
||||
obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
|
||||
obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
|
||||
obj-$(CONFIG_NF_TABLE_ROUTE_IPV4) += nf_table_route_ipv4.o
|
||||
obj-$(CONFIG_NF_TABLE_NAT_IPV4) += nf_table_nat_ipv4.o
|
||||
|
||||
# generic IP tables
|
||||
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
|
||||
|
||||
|
||||
409
net/ipv4/netfilter/nf_table_nat_ipv4.c
Normal file
409
net/ipv4/netfilter/nf_table_nat_ipv4.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/netfilter/nf_nat_core.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_nat_l3proto.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
struct nft_nat {
|
||||
enum nft_registers sreg_addr_min:8;
|
||||
enum nft_registers sreg_addr_max:8;
|
||||
enum nft_registers sreg_proto_min:8;
|
||||
enum nft_registers sreg_proto_max:8;
|
||||
enum nf_nat_manip_type type;
|
||||
};
|
||||
|
||||
static void nft_nat_eval(const struct nft_expr *expr,
|
||||
struct nft_data data[NFT_REG_MAX + 1],
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
const struct nft_nat *priv = nft_expr_priv(expr);
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
|
||||
struct nf_nat_range range;
|
||||
|
||||
memset(&range, 0, sizeof(range));
|
||||
if (priv->sreg_addr_min) {
|
||||
range.min_addr.ip = data[priv->sreg_addr_min].data[0];
|
||||
range.max_addr.ip = data[priv->sreg_addr_max].data[0];
|
||||
range.flags |= NF_NAT_RANGE_MAP_IPS;
|
||||
}
|
||||
|
||||
if (priv->sreg_proto_min) {
|
||||
range.min_proto.all = data[priv->sreg_proto_min].data[0];
|
||||
range.max_proto.all = data[priv->sreg_proto_max].data[0];
|
||||
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
|
||||
}
|
||||
|
||||
data[NFT_REG_VERDICT].verdict =
|
||||
nf_nat_setup_info(ct, &range, priv->type);
|
||||
}
|
||||
|
||||
static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
|
||||
[NFTA_NAT_ADDR_MIN] = { .type = NLA_U32 },
|
||||
[NFTA_NAT_ADDR_MAX] = { .type = NLA_U32 },
|
||||
[NFTA_NAT_PROTO_MIN] = { .type = NLA_U32 },
|
||||
[NFTA_NAT_PROTO_MAX] = { .type = NLA_U32 },
|
||||
[NFTA_NAT_TYPE] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_nat *priv = nft_expr_priv(expr);
|
||||
int err;
|
||||
|
||||
if (tb[NFTA_NAT_TYPE] == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
|
||||
case NFT_NAT_SNAT:
|
||||
priv->type = NF_NAT_MANIP_SRC;
|
||||
break;
|
||||
case NFT_NAT_DNAT:
|
||||
priv->type = NF_NAT_MANIP_DST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[NFTA_NAT_ADDR_MIN]) {
|
||||
priv->sreg_addr_min = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MIN]));
|
||||
err = nft_validate_input_register(priv->sreg_addr_min);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (tb[NFTA_NAT_ADDR_MAX]) {
|
||||
priv->sreg_addr_max = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MAX]));
|
||||
err = nft_validate_input_register(priv->sreg_addr_max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else
|
||||
priv->sreg_addr_max = priv->sreg_addr_min;
|
||||
|
||||
if (tb[NFTA_NAT_PROTO_MIN]) {
|
||||
priv->sreg_proto_min = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MIN]));
|
||||
err = nft_validate_input_register(priv->sreg_proto_min);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (tb[NFTA_NAT_PROTO_MAX]) {
|
||||
priv->sreg_proto_max = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MAX]));
|
||||
err = nft_validate_input_register(priv->sreg_proto_max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else
|
||||
priv->sreg_proto_max = priv->sreg_proto_min;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
{
|
||||
const struct nft_nat *priv = nft_expr_priv(expr);
|
||||
|
||||
switch (priv->type) {
|
||||
case NF_NAT_MANIP_SRC:
|
||||
if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case NF_NAT_MANIP_DST:
|
||||
if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nla_put_be32(skb, NFTA_NAT_ADDR_MIN, htonl(priv->sreg_addr_min)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb, NFTA_NAT_ADDR_MAX, htonl(priv->sreg_addr_max)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb, NFTA_NAT_PROTO_MIN, htonl(priv->sreg_proto_min)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb, NFTA_NAT_PROTO_MAX, htonl(priv->sreg_proto_max)))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct nft_expr_ops nft_nat_ops __read_mostly = {
|
||||
.name = "nat",
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
|
||||
.owner = THIS_MODULE,
|
||||
.eval = nft_nat_eval,
|
||||
.init = nft_nat_init,
|
||||
.dump = nft_nat_dump,
|
||||
.policy = nft_nat_policy,
|
||||
.maxattr = NFTA_NAT_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* NAT table
|
||||
*/
|
||||
|
||||
static unsigned int nf_nat_fn(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
|
||||
struct nf_conn_nat *nat;
|
||||
enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
|
||||
unsigned int ret;
|
||||
|
||||
if (ct == NULL || nf_ct_is_untracked(ct))
|
||||
return NF_ACCEPT;
|
||||
|
||||
NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
|
||||
|
||||
nat = nfct_nat(ct);
|
||||
if (nat == NULL) {
|
||||
/* Conntrack module was loaded late, can't add extension. */
|
||||
if (nf_ct_is_confirmed(ct))
|
||||
return NF_ACCEPT;
|
||||
nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
|
||||
if (nat == NULL)
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
switch (ctinfo) {
|
||||
case IP_CT_RELATED:
|
||||
case IP_CT_RELATED + IP_CT_IS_REPLY:
|
||||
if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
|
||||
if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
|
||||
ops->hooknum))
|
||||
return NF_DROP;
|
||||
else
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
/* Fall through */
|
||||
case IP_CT_NEW:
|
||||
if (nf_nat_initialized(ct, maniptype))
|
||||
break;
|
||||
|
||||
ret = nft_do_chain(ops, skb, in, out, okfn);
|
||||
if (ret != NF_ACCEPT)
|
||||
return ret;
|
||||
if (!nf_nat_initialized(ct, maniptype)) {
|
||||
ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
|
||||
if (ret != NF_ACCEPT)
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
|
||||
}
|
||||
|
||||
static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
__be32 daddr = ip_hdr(skb)->daddr;
|
||||
unsigned int ret;
|
||||
|
||||
ret = nf_nat_fn(ops, skb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN &&
|
||||
ip_hdr(skb)->daddr != daddr) {
|
||||
skb_dst_drop(skb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
enum ip_conntrack_info ctinfo __maybe_unused;
|
||||
const struct nf_conn *ct __maybe_unused;
|
||||
unsigned int ret;
|
||||
|
||||
ret = nf_nat_fn(ops, skb, in, out, okfn);
|
||||
#ifdef CONFIG_XFRM
|
||||
if (ret != NF_DROP && ret != NF_STOLEN &&
|
||||
(ct = nf_ct_get(skb, &ctinfo)) != NULL) {
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
if (ct->tuplehash[dir].tuple.src.u3.ip !=
|
||||
ct->tuplehash[!dir].tuple.dst.u3.ip ||
|
||||
ct->tuplehash[dir].tuple.src.u.all !=
|
||||
ct->tuplehash[!dir].tuple.dst.u.all)
|
||||
return nf_xfrm_me_harder(skb, AF_INET) == 0 ?
|
||||
ret : NF_DROP;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int nf_nat_output(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
enum ip_conntrack_info ctinfo;
|
||||
const struct nf_conn *ct;
|
||||
unsigned int ret;
|
||||
|
||||
ret = nf_nat_fn(ops, skb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN &&
|
||||
(ct = nf_ct_get(skb, &ctinfo)) != NULL) {
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
if (ct->tuplehash[dir].tuple.dst.u3.ip !=
|
||||
ct->tuplehash[!dir].tuple.src.u3.ip) {
|
||||
if (ip_route_me_harder(skb, RTN_UNSPEC))
|
||||
ret = NF_DROP;
|
||||
}
|
||||
#ifdef CONFIG_XFRM
|
||||
else if (ct->tuplehash[dir].tuple.dst.u.all !=
|
||||
ct->tuplehash[!dir].tuple.src.u.all)
|
||||
if (nf_xfrm_me_harder(skb, AF_INET))
|
||||
ret = NF_DROP;
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nft_base_chain nf_chain_nat_prerouting __read_mostly = {
|
||||
.chain = {
|
||||
.name = "PREROUTING",
|
||||
.rules = LIST_HEAD_INIT(nf_chain_nat_prerouting.chain.rules),
|
||||
.flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
|
||||
},
|
||||
.ops = {
|
||||
.hook = nf_nat_prerouting,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = NFPROTO_IPV4,
|
||||
.hooknum = NF_INET_PRE_ROUTING,
|
||||
.priority = NF_IP_PRI_NAT_DST,
|
||||
.priv = &nf_chain_nat_prerouting.chain,
|
||||
},
|
||||
};
|
||||
|
||||
static struct nft_base_chain nf_chain_nat_postrouting __read_mostly = {
|
||||
.chain = {
|
||||
.name = "POSTROUTING",
|
||||
.rules = LIST_HEAD_INIT(nf_chain_nat_postrouting.chain.rules),
|
||||
.flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
|
||||
},
|
||||
.ops = {
|
||||
.hook = nf_nat_postrouting,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = NFPROTO_IPV4,
|
||||
.hooknum = NF_INET_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_NAT_SRC,
|
||||
.priv = &nf_chain_nat_postrouting.chain,
|
||||
},
|
||||
};
|
||||
|
||||
static struct nft_base_chain nf_chain_nat_output __read_mostly = {
|
||||
.chain = {
|
||||
.name = "OUTPUT",
|
||||
.rules = LIST_HEAD_INIT(nf_chain_nat_output.chain.rules),
|
||||
.flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
|
||||
},
|
||||
.ops = {
|
||||
.hook = nf_nat_output,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = NFPROTO_IPV4,
|
||||
.hooknum = NF_INET_LOCAL_OUT,
|
||||
.priority = NF_IP_PRI_NAT_DST,
|
||||
.priv = &nf_chain_nat_output.chain,
|
||||
},
|
||||
};
|
||||
|
||||
static struct nft_base_chain nf_chain_nat_input __read_mostly = {
|
||||
.chain = {
|
||||
.name = "INPUT",
|
||||
.rules = LIST_HEAD_INIT(nf_chain_nat_input.chain.rules),
|
||||
.flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
|
||||
},
|
||||
.ops = {
|
||||
.hook = nf_nat_fn,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = NFPROTO_IPV4,
|
||||
.hooknum = NF_INET_LOCAL_IN,
|
||||
.priority = NF_IP_PRI_NAT_SRC,
|
||||
.priv = &nf_chain_nat_input.chain,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static struct nft_table nf_table_nat_ipv4 __read_mostly = {
|
||||
.name = "nat",
|
||||
.chains = LIST_HEAD_INIT(nf_table_nat_ipv4.chains),
|
||||
};
|
||||
|
||||
static int __init nf_table_nat_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
list_add_tail(&nf_chain_nat_prerouting.chain.list,
|
||||
&nf_table_nat_ipv4.chains);
|
||||
list_add_tail(&nf_chain_nat_postrouting.chain.list,
|
||||
&nf_table_nat_ipv4.chains);
|
||||
list_add_tail(&nf_chain_nat_output.chain.list,
|
||||
&nf_table_nat_ipv4.chains);
|
||||
list_add_tail(&nf_chain_nat_input.chain.list,
|
||||
&nf_table_nat_ipv4.chains);
|
||||
|
||||
err = nft_register_table(&nf_table_nat_ipv4, NFPROTO_IPV4);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
err = nft_register_expr(&nft_nat_ops);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
nft_unregister_table(&nf_table_nat_ipv4, NFPROTO_IPV4);
|
||||
err1:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit nf_table_nat_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_nat_ops);
|
||||
nft_unregister_table(&nf_table_nat_ipv4, AF_INET);
|
||||
}
|
||||
|
||||
module_init(nf_table_nat_init);
|
||||
module_exit(nf_table_nat_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_TABLE(AF_INET, "nat");
|
||||
MODULE_ALIAS_NFT_EXPR("nat");
|
||||
97
net/ipv4/netfilter/nf_table_route_ipv4.c
Normal file
97
net/ipv4/netfilter/nf_table_route_ipv4.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/route.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
unsigned int ret;
|
||||
u32 mark;
|
||||
__be32 saddr, daddr;
|
||||
u_int8_t tos;
|
||||
const struct iphdr *iph;
|
||||
|
||||
/* root is playing with raw sockets. */
|
||||
if (skb->len < sizeof(struct iphdr) ||
|
||||
ip_hdrlen(skb) < sizeof(struct iphdr))
|
||||
return NF_ACCEPT;
|
||||
|
||||
mark = skb->mark;
|
||||
iph = ip_hdr(skb);
|
||||
saddr = iph->saddr;
|
||||
daddr = iph->daddr;
|
||||
tos = iph->tos;
|
||||
|
||||
ret = nft_do_chain(ops, skb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_QUEUE) {
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
if (iph->saddr != saddr ||
|
||||
iph->daddr != daddr ||
|
||||
skb->mark != mark ||
|
||||
iph->tos != tos)
|
||||
if (ip_route_me_harder(skb, RTN_UNSPEC))
|
||||
ret = NF_DROP;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nft_base_chain nf_chain_route_output __read_mostly = {
|
||||
.chain = {
|
||||
.name = "OUTPUT",
|
||||
.rules = LIST_HEAD_INIT(nf_chain_route_output.chain.rules),
|
||||
.flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
|
||||
},
|
||||
.ops = {
|
||||
.hook = nf_route_table_hook,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = NFPROTO_IPV4,
|
||||
.hooknum = NF_INET_LOCAL_OUT,
|
||||
.priority = NF_IP_PRI_MANGLE,
|
||||
.priv = &nf_chain_route_output.chain,
|
||||
},
|
||||
};
|
||||
|
||||
static struct nft_table nf_table_route_ipv4 __read_mostly = {
|
||||
.name = "route",
|
||||
.chains = LIST_HEAD_INIT(nf_table_route_ipv4.chains),
|
||||
};
|
||||
|
||||
static int __init nf_table_route_init(void)
|
||||
{
|
||||
list_add_tail(&nf_chain_route_output.chain.list,
|
||||
&nf_table_route_ipv4.chains);
|
||||
return nft_register_table(&nf_table_route_ipv4, NFPROTO_IPV4);
|
||||
}
|
||||
|
||||
static void __exit nf_table_route_exit(void)
|
||||
{
|
||||
nft_unregister_table(&nf_table_route_ipv4, NFPROTO_IPV4);
|
||||
}
|
||||
|
||||
module_init(nf_table_route_init);
|
||||
module_exit(nf_table_route_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_TABLE(AF_INET, "route");
|
||||
59
net/ipv4/netfilter/nf_tables_ipv4.c
Normal file
59
net/ipv4/netfilter/nf_tables_ipv4.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
if (unlikely(skb->len < sizeof(struct iphdr) ||
|
||||
ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
|
||||
if (net_ratelimit())
|
||||
pr_info("nf_tables_ipv4: ignoring short SOCK_RAW "
|
||||
"packet\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
return nft_do_chain(ops, skb, in, out, okfn);
|
||||
}
|
||||
|
||||
static struct nft_af_info nft_af_ipv4 __read_mostly = {
|
||||
.family = NFPROTO_IPV4,
|
||||
.nhooks = NF_INET_NUMHOOKS,
|
||||
.owner = THIS_MODULE,
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nft_ipv4_output,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_ipv4_init(void)
|
||||
{
|
||||
return nft_register_afinfo(&nft_af_ipv4);
|
||||
}
|
||||
|
||||
static void __exit nf_tables_ipv4_exit(void)
|
||||
{
|
||||
nft_unregister_afinfo(&nft_af_ipv4);
|
||||
}
|
||||
|
||||
module_init(nf_tables_ipv4_init);
|
||||
module_exit(nf_tables_ipv4_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_FAMILY(AF_INET);
|
||||
117
net/ipv4/netfilter/nft_reject_ipv4.c
Normal file
117
net/ipv4/netfilter/nft_reject_ipv4.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#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.h>
|
||||
#include <net/icmp.h>
|
||||
|
||||
struct nft_reject {
|
||||
enum nft_reject_types type:8;
|
||||
u8 icmp_code;
|
||||
};
|
||||
|
||||
static void nft_reject_eval(const struct nft_expr *expr,
|
||||
struct nft_data data[NFT_REG_MAX + 1],
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
struct nft_reject *priv = nft_expr_priv(expr);
|
||||
|
||||
switch (priv->type) {
|
||||
case NFT_REJECT_ICMP_UNREACH:
|
||||
icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0);
|
||||
break;
|
||||
case NFT_REJECT_TCP_RST:
|
||||
break;
|
||||
}
|
||||
|
||||
data[NFT_REG_VERDICT].verdict = NF_DROP;
|
||||
}
|
||||
|
||||
static const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
|
||||
[NFTA_REJECT_TYPE] = { .type = NLA_U32 },
|
||||
[NFTA_REJECT_ICMP_CODE] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
static int nft_reject_init(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_reject *priv = nft_expr_priv(expr);
|
||||
|
||||
if (tb[NFTA_REJECT_TYPE] == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
|
||||
switch (priv->type) {
|
||||
case NFT_REJECT_ICMP_UNREACH:
|
||||
if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
|
||||
return -EINVAL;
|
||||
priv->icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
|
||||
case NFT_REJECT_TCP_RST:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
{
|
||||
const struct nft_reject *priv = nft_expr_priv(expr);
|
||||
|
||||
if (nla_put_be32(skb, NFTA_REJECT_TYPE, priv->type))
|
||||
goto nla_put_failure;
|
||||
|
||||
switch (priv->type) {
|
||||
case NFT_REJECT_ICMP_UNREACH:
|
||||
if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct nft_expr_ops reject_ops __read_mostly = {
|
||||
.name = "reject",
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
|
||||
.owner = THIS_MODULE,
|
||||
.eval = nft_reject_eval,
|
||||
.init = nft_reject_init,
|
||||
.dump = nft_reject_dump,
|
||||
.policy = nft_reject_policy,
|
||||
.maxattr = NFTA_REJECT_MAX,
|
||||
};
|
||||
|
||||
static int __init nft_reject_module_init(void)
|
||||
{
|
||||
return nft_register_expr(&reject_ops);
|
||||
}
|
||||
|
||||
static void __exit nft_reject_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&reject_ops);
|
||||
}
|
||||
|
||||
module_init(nft_reject_module_init);
|
||||
module_exit(nft_reject_module_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_EXPR("reject");
|
||||
@@ -25,6 +25,14 @@ config NF_CONNTRACK_IPV6
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NF_TABLES_IPV6
|
||||
depends on NF_TABLES
|
||||
tristate "IPv6 nf_tables support"
|
||||
|
||||
config NF_TABLE_ROUTE_IPV6
|
||||
depends on NF_TABLES_IPV6
|
||||
tristate "IPv6 nf_tables route table support"
|
||||
|
||||
config IP6_NF_IPTABLES
|
||||
tristate "IP6 tables support (required for filtering)"
|
||||
depends on INET && IPV6
|
||||
|
||||
@@ -23,6 +23,10 @@ obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
|
||||
nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
|
||||
obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
|
||||
|
||||
# nf_tables
|
||||
obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
|
||||
obj-$(CONFIG_NF_TABLE_ROUTE_IPV6) += nf_table_route_ipv6.o
|
||||
|
||||
# matches
|
||||
obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
|
||||
|
||||
93
net/ipv6/netfilter/nf_table_route_ipv6.c
Normal file
93
net/ipv6/netfilter/nf_table_route_ipv6.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/route.h>
|
||||
|
||||
static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
unsigned int ret;
|
||||
struct in6_addr saddr, daddr;
|
||||
u_int8_t hop_limit;
|
||||
u32 mark, flowlabel;
|
||||
|
||||
/* save source/dest address, mark, hoplimit, flowlabel, priority */
|
||||
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
|
||||
memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
|
||||
mark = skb->mark;
|
||||
hop_limit = ipv6_hdr(skb)->hop_limit;
|
||||
|
||||
/* flowlabel and prio (includes version, which shouldn't change either */
|
||||
flowlabel = *((u32 *)ipv6_hdr(skb));
|
||||
|
||||
ret = nft_do_chain(ops, skb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_QUEUE &&
|
||||
(memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
|
||||
memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
|
||||
skb->mark != mark ||
|
||||
ipv6_hdr(skb)->hop_limit != hop_limit ||
|
||||
flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
|
||||
return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nft_base_chain nf_chain_route_output __read_mostly = {
|
||||
.chain = {
|
||||
.name = "OUTPUT",
|
||||
.rules = LIST_HEAD_INIT(nf_chain_route_output.chain.rules),
|
||||
.flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
|
||||
},
|
||||
.ops = {
|
||||
.hook = nf_route_table_hook,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = NFPROTO_IPV6,
|
||||
.hooknum = NF_INET_LOCAL_OUT,
|
||||
.priority = NF_IP6_PRI_MANGLE,
|
||||
.priv = &nf_chain_route_output.chain,
|
||||
},
|
||||
};
|
||||
|
||||
static struct nft_table nf_table_route_ipv6 __read_mostly = {
|
||||
.name = "route",
|
||||
.chains = LIST_HEAD_INIT(nf_table_route_ipv6.chains),
|
||||
};
|
||||
|
||||
static int __init nf_table_route_init(void)
|
||||
{
|
||||
list_add_tail(&nf_chain_route_output.chain.list,
|
||||
&nf_table_route_ipv6.chains);
|
||||
return nft_register_table(&nf_table_route_ipv6, NFPROTO_IPV6);
|
||||
}
|
||||
|
||||
static void __exit nf_table_route_exit(void)
|
||||
{
|
||||
nft_unregister_table(&nf_table_route_ipv6, NFPROTO_IPV6);
|
||||
}
|
||||
|
||||
module_init(nf_table_route_init);
|
||||
module_exit(nf_table_route_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_TABLE(AF_INET6, "route");
|
||||
57
net/ipv6/netfilter/nf_tables_ipv6.c
Normal file
57
net/ipv6/netfilter/nf_tables_ipv6.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
|
||||
if (net_ratelimit())
|
||||
pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
|
||||
"packet\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
return nft_do_chain(ops, skb, in, out, okfn);
|
||||
}
|
||||
|
||||
static struct nft_af_info nft_af_ipv6 __read_mostly = {
|
||||
.family = NFPROTO_IPV6,
|
||||
.nhooks = NF_INET_NUMHOOKS,
|
||||
.owner = THIS_MODULE,
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nft_ipv6_output,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nf_tables_ipv6_init(void)
|
||||
{
|
||||
return nft_register_afinfo(&nft_af_ipv6);
|
||||
}
|
||||
|
||||
static void __exit nf_tables_ipv6_exit(void)
|
||||
{
|
||||
nft_unregister_afinfo(&nft_af_ipv6);
|
||||
}
|
||||
|
||||
module_init(nf_tables_ipv6_init);
|
||||
module_exit(nf_tables_ipv6_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_FAMILY(AF_INET6);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user