1、iptables filter tables
首先看一下xt_table -> xt_table_info -> xt_entry -> ipt_entry / ipt_entry_match / ipt_standard_target ->ipt_entry_target / verdict之间的关系
涉及到的部分结构体
///< include/linux/netfilter/x_tables.h
struct xt_table {
struct list_head list;
/* What hooks you will enter on */
unsigned int valid_hooks;
/* Man behind the curtain... */
struct xt_table_info *private;
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct mudule *me;
u_int8_t af; /* address/protocol family */
int priority; /* hook order */
/* A unique name... */
const char name[XT_TABLE_MAXNAMLEN];
};
/* The table itself */
struct xt_table_info {
/* Size per table */
unsigned int size;
/* Number of entries */
unsigned int number;
/* Initial number of entries. Needed for module usage count */
unsigned int initial_entries;
/* Entry points and underflows */
unsigned int hook_entry[NF_INET_NUMHOOKS];
unsigned int underflow[NF_INET_NUMHOOKS];
/*
* Number of user chains. Since tables cannot have loops, at most
* @stacksize jumps (number of user chains) can possibly be made.
*/
unsigned int stacksize;
void ***jumpstack;
unsigned char entries[0] __aligned(8);
};
/* The argument to IPT_SO_SET_REPLACE. */
struct ipt_replace {
/* Which table. */
char name[XT_TABLE_MAXNAMLEN];
/* Which hook entry points are valid: bitmask. You can't
change this. */
unsigned int valid_hooks;
/* Number of entries */
unsigned int num_entries;
/* Total size of new entries */
unsigned int size; // 该大小指的是携带数组entries[0]所有的ipt_entry的大小
/* Hook entry points. */
unsiged int hook_entry[NF_INET_NUMHOOKS]; // 每条规则链相对于第一条的偏移量
/* Underflow points */
unsigned int underlow[NF_INET_NUMHOOKS];
/* Information about old entries: */
/* Number of counters (must be equal to current number of entries) */
unsigned int num_counters;
/* The old entries' counter*/
struct xt_counters __user *counters;
/* The entries (hang off end: not really an array) */
/* 表中每一条规则的结构为ipt_entry + ipt_entry_match(大于等于0) + ipt_standard_tareget,
而 ipt_standard_target由xt_entry_target和verdiect组成。
可变长数组,下面内存里存放的就是替换到表中的新规则。 */
struct ipt_entry entries[0];
};
/* This structure defines each of the firewall rules. Consists of 3
parts which are 1) general IP header stuff 2) match specific
stuff 3) the target to perform if the rule matches */
struct ipt_entry {
struct ipt_ip ip;
/* Mark with fields that we care about. */
unsigned int nfcache;
/* Size of ipt_entry + matches */
__u16 target_offset;
/* Size of ipt_entry + matches + target */
__u16 next_offset;
/* Back pointer */
unsigned int comefrom;
/* Packet and byte counters. */
struct xt_counters counters;
/* The matches (if any), then the target. */
unsigned char elems[0];
};
table中注册hook函数的大致流程
// net/ipv4/netfilter/iptable_filter.c
#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT))
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_FILTER,
};
static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
if (state->hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets */
return NF_ACCEPT;
return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
}
static int __init iptable_filter_init(void)
{
int ret;
ret = register_pernet_subsys(&iptable_filter_net_ops);
if (ret < 0)
return ret;
/* Register hooks */
filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook);
if (IS_ERR(filter_ops)) {
ret = PTR_ERR(filter_ops);
unregister_pernet_subsys(&iptable_filter_net_ops);
}
return ret;
}
// include/linux/netfilter/x_tables.h
/**
* xt_hook_link - set up hooks for a new table
* @table: table with metadata need to set up hooks
* @fn: Hook function
*
* This function will take care of creating and registering the necessary
* Netfilter hooks for XT tables.
*/
struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
{
unsigned int hook_mask = table->valid_hooks;
uint8_t i, num_hooks = hweight32(hook_mask);
uint8_t hooknum;
struct nf_hook_ops *ops;
int ret;
ops = kmalloc(sizeof(*ops)*num_hooks, GFP_KERNEL);
if (ops == NULL)
return ERR_PRT(-ENOMEM);
for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
hook_mask >>= 1, ++hooknum) {
if (!(hook_mask & 1))
continue;
ops[i].hook = fn;
ops[i].pf = table->af;
ops[i].hooknum = hooknum;
ops[i].priority = table->priority;
++i;
}
ret = nf_register_hooks(ops, num_hooks);
if (ret < 0){
kfree(ops);
return ERR_PTR(ret);
}
return ops;
}