===================userspace===============================
/* Include file for additions: new matches and targets. */
struct xtables_match {
/*
* ABI/API version this module requires. Must be first member,
* as the rest of this struct may be subject to ABI changes.
*/
const char *version;
struct xtables_match *next;
const char *name;
const char *real_name;
/* Revision of match (0 by default). */
uint8_t revision;
/* Extension flags */
uint8_t ext_flags;
uint16_t family;
/* Size of match data. */
size_t size;
/* Size of match data relevant for userspace comparison purposes */
size_t userspacesize;
/* Function which prints out usage message. */
void (*help)(void);
/* Initialize the match. */
void (*init)(struct xt_entry_match *m);
/* Function which parses command options; returns true if it
ate an option */
/* entry is struct ipt_entry for example */
int (*parse)(int c, char **argv, int invert, unsigned int *flags,
const void *entry,
struct xt_entry_match **match);
/* Final check; exit if not ok. */
void (*final_check)(unsigned int flags);
/* Prints out the match iff non-NULL: put space at end */
/* ip is struct ipt_ip * for example */
void (*print)(const void *ip,
const struct xt_entry_match *match, int numeric);
/* Saves the match info in parsable form to stdout. */
/* ip is struct ipt_ip * for example */
void (*save)(const void *ip, const struct xt_entry_match *match);
/* Print match name or alias */
const char *(*alias)(const struct xt_entry_match *match);
/* Pointer to list of extra command-line options */
const struct option *extra_opts;
/* New parser */
void (*x6_parse)(struct xt_option_call *);
void (*x6_fcheck)(struct xt_fcheck_call *);
const struct xt_option_entry *x6_options;
/* Translate iptables to nft */
int (*xlate)(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params);
/* Size of per-extension instance extra "global" scratch space */
size_t udata_size;
/* Ignore these men behind the curtain: */
void *udata;
unsigned int option_offset;
struct xt_entry_match *m;
unsigned int mflags;
unsigned int loaded; /* simulate loading so options are merged properly */
};
struct xt_tcp
/* TCP match stuff */
struct xt_tcp {
__u16 spts[2]; /* source port range */
__u16 dpts[2]; /* destination port range */
__u8 option; /* TCP Option iff non-zero */
__u8 flg_mask; /* Tcp flags mask byte */
__u8 flg_cmp; /* Tcp flags compare byte */
__u8 invflags; /* Inverse flags */
};
static struct xtables_match tcp_match = {
.family = NFPROTO_UNSPEC,
.name = "tcp",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_tcp)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tcp)),
.help = tcp_help,
.init = tcp_init,
.parse = tcp_parse,
.print = tcp_print,
.save = tcp_save,
.extra_opts = tcp_opts,
.xlate = tcp_xlate,
};
static const struct option tcp_optes[] = {
{.name = "source-port", .has_arg = true, .val = '1'},
{.name = "sport", .has_arg = true, .val = '1'},
{.name = "destination-port",.has_arg = true, .val = '2'},
{.name = "dport", .has_arg = true, .val = '2'},
{.name = "syn", .has_arg = true, .val = '3'},
{.name = "tcp-flags", .has_arg = true, .val = '4'},
{.name = "tcp-option", .has_arg = true, .val = '5'},
};
#define XT_FUNCTION_MAXNAMELEN 30
#define XT_EXTENSION_MAXNAMELEN 29
#define XT_TABLE_MAXNAMELEN 32
struct xt_entry_match {
union {
struct {
__u16 match_size;
/* Used by userspace */
char name[XT_EXTENSION_MAXNAMELEN]
} user;
struct {
__u16 match_size;
/* Used inside the kernel */
struct xt_match *match;
} kernel;
/* Total length */
__u16 match_size;
} u;
unsigned char data[0];
};
#define TCP_SRC_PORTS 0X01
#define TCP_DST_PORTS 0X02
#define TCP_FLAGS 0X04
#define TCP_OPTION 0X08
static int
tcp_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_tcp *tcpinfo = (struct xt_tcp *)(*match)->data;
switch (c) {
case '1':
...
break;
case '2':
if (*flags & TCP_DST_PORTS)
xtables_error(PARAMETER_PROBLEM,
"Only one '--destination-port' allowed");
parse_tcp_ports(optarg, tcpinfo->dpts); // 将设置的端口赋值到tcpinfo->dpts中
if (invert)
tcpinfo->invflags |= XT_TCP_NV_DSTPT;
*flags |= TCP_DST_PORTS;
break;
case ...
}
return 1;
}
============================kernel===================================
static struct xt_match tcpudp_mt_reg[] __read_mostly = {
{
.name = "tcp",
.family = NFPROTO_IPV4,
.checkentry = tcp_mt_check,
.match = tcp_mt,
.matchsize = sizeof(struct xt_tcp),
.proto = IPPROTO_TCP,
.me = THIS_MODULE,
}
...
};
static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct tcphdr *th;
struct tcphdr _tcph;
const struct xt_tcp *tcpinfo = par->matchinfo;
if (par->fragoff != 0) {
/* To quote Alan:
Don't allow a fragment of TCP 8 bytes in. Nobody normal
causes this. Its a cracker trying to break in by doing a
flag overwrite to pass the direction checks.
*/
if (par->fragoff == 1) {
pr_debug("Dropping evil TCP offset=1 frag.\n");
par->hotdrop = true;
}
/* Must not be a fragment. */
return false;
}
#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg)))
th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
if (th == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop*/
pr_debug("Dropping evil TCP offset=0 tinygram.\n");
par->hotdrop = true;
return false;
}
if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
ntohs(th->source),
!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
return false;
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
ntohs(th->dest),
!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
return false;
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
== tcpinfo->flg_cmp,
XT_TCP_INV_FLAGS))
return false;
if (tcpinfo->option) {
if (th->doff * 4 < sizeof(_tcph)) {
par->hotdrop = true;
return false;
}
if (!tcp_find_option(tcpinfo->option, skb, par->thoff,
th->doff*4 - sizeof(_tcph),
tcpinfo->invflags & XT_TCP_INV_OPTION,
&par->hotdrop))
return false;
}
return true;
}
xt_action_param中会将某条规则带入过来,然后再kernel的分析函数中(tcp_mt)对当前数据包进行分析。如果当前数据包符合xt_action_param带入的规则,则将返回true;否则返回false,并且在解析的过程中,存在明显的错误(如代码中,进行端口的判断,结果网络包中对传输层的头都不存在),除了返回错误之外,还将xt_action_param中的hotdrop设置为true(par->hotdrop = true),以便于之上层能够直接将数据进行drop等操作。