iptables v1.8.3
【预备知识】
使用getopt_long函数存在两个全局变量
全局变量:
(1)optarg:表示当前选项对应的参数值。
(2)optind:表示的是下一个将被处理到的参数在argv中的下标值。
【插入过程】
(1)
///< 命令行I选项:代表要在指定位置插入一条entry
1280 case 'I':
1281 add_command(&command, CMD_INSERT, CMD_NONE,
1282 cs.invert);
1283 chain = optarg; //指定了链表
1284 if (xs_has_arg(argc, argv))
1285 rulenum = parse_rulenumber(argv[optind++]); // 指定了插入位置
1286 else rulenum = 1;
1287 break;
(2)
///< ipt_entry生成(此处生成的ipt_entry, 主要是为了ipt_entry + ipt_match + ipt_target组合在一起,让其内存连续)
1723 e = generate_entry(&cs.fw, cs.matches, cs.target->t);
(2-1)
static struct ipt_entry *
generate_entry(const struct ipt_entry *fw,
struct xtables_rule_match *matches,
struct xt_entry_target *target)
{
unsigned int size;
struct xtables_rule_match *matchp;
struct ipt_entry *e;
size = sizeof(struct ipt_entry);
for (matchp = matches; matchp; matchp = matchp->next)
size += matchp->match->m->u.match_size;
e = xtables_malloc(size + target->u.target_size);
*e = *fw;
e->target_offset = size;
e->next_offset = size + target->u.target_size;
size = 0;
for (matchp = matches; matchp; matchp = matchp->next) {
memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
size += matchp->match->m->u.match_size;
}
memcpy(e->elems + size, target, target->u.target_size);
return e;
}
(2-2)
// cs.fw, cs.matches, cs.target->t这三个变量如何构建
首先看一下cs的结构
struct iptables_command_state cs = {
...
};
struct iptables_command_state {
union {
struct ebt_entry eb;
struct ipt_entry fw;
struct ip6t_entry fw6;
struct arpt_entry arp;
};
int invert;
int c;
unsigned int options;
struct xtables_rule_match *matches;
struct ebt_match *match_list;
struct xtables_target *target;
struct xt_counter counters;
char *protocol;
int proto_used;
const char *jumpto;
char **argv;
bool restore;
};
struct xtables_rule_match {
struct xtables_rule_match *next;
struct xtables_match *match;
/* Multiple matches of the same type: the ones before
the current one are completed from parsing point of view */
bool completed;
};
(2-2-1)
// cs.fw构建
数据结构
99 /* This structure defines each of the firewall rules. Consists of 3
100 parts which are 1) general IP header stuff 2) match specific
101 stuff 3) the target to perform if the rule matches */
102 struct ipt_entry {
103 struct ipt_ip ip;
104
105 /* Mark with fields that we care about. */
106 unsigned int nfcache;
107
108 /* Size of ipt_entry + matches */
109 __u16 target_offset;
110 /* Size of ipt_entry + matches + target */
111 __u16 next_offset;
112
113 /* Back pointer */
114 unsigned int comefrom;
115
116 /* Packet and byte counters. */
117 struct xt_counters counters;
118
119 /* The matches (if any), then the target. */
120 unsigned char elems[0];
121 };
67 struct ipt_ip {
68 /* Source and destination IP addr */
69 struct in_addr src, dst;
// 分析入设备和出设备
//1435 xtables_parse_interface(optarg,
//1436 cs.fw.ip.iniface,
//1437 cs.fw.ip.iniface_mask);
70 /* Mask for src and dest IP addr */
71 struct in_addr smsk, dmsk;
72 char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
73 unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
74
// 1392 cs.fw.ip.proto = xtables_parse_protocol(cs.protocol);
75 /* Protocol, 0 = ANY */
76 __u16 proto;
77
78 /* Flags word */
79 __u8 flags;
80 /* Inverse flags */
81 __u8 invflags;
82 };
(2-2-2)
// cs.matches构建
以"-m tcp --dport 1234"为例
// (a)以下为用户空间注册match
数据结构
/* 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 */
};
// libxt_tcp.c注册内容
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,
};
// 注册函数
void xtables_register_match(struct xtables_match *me)
{
if (me->next) {
fprintf(stderr, "%s: match \"%s\" already registered\n",
xt_params->program_name, me->name);
exit(1);
}
if (me->version == NULL) {
fprintf(stderr, "%s: match %s<%u> is missing a version\n",
xt_params->program_name, me->name, me->revision);
exit(1);
}
if (me->size != XT_ALIGN(me->size)) {
fprintf(stderr, "%s: match \"%s\" has invalid size %u.\n",
xt_params->program_name, me->name,
(unsigned int)me->size);
exit(1);
}
if (strcmp(me->version, XTABLES_VERSION) != 0) {
fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
"but \"%s\" is required.\n",
xt_params->program_name, me->name,
me->version, XTABLES_VERSION);
exit(1);
}
if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
fprintf(stderr, "%s: match `%s' has invalid name\n",
xt_params->program_name, me->name);
exit(1);
}
if (me->real_name && strlen(me->real_name) >= XT_EXTENSION_MAXNAMELEN) {
fprintf(stderr, "%s: match `%s' has invalid real name\n",
xt_params->program_name, me->real_name);
exit(1);
}
if (me->family >= NPROTO) {
fprintf(stderr,
"%s: BUG: match %s has invalid protocol family\n",
xt_params->program_name, me->name);
exit(1);
}
if (me->x6_options != NULL)
xtables_option_metavalidate(me->name, me->x6_options);
if (me->extra_opts != NULL)
xtables_check_options(me->name, me->extra_opts);
/* 将xtables_match放置到xtables_pending_matches的头部
(在xtables_find_match中通过xtables_pending_match链表进行查找,并进行注册)*/
/* place on linked list of matches pending full registration */
me->next = xtables_pending_matches;
xtables_pending_matches = me;
}
// (b)以下为iptables接收到command进行match相关的解析
// 对于match的data数据格式在成员声明时指定了大小 {.size = XT_ALIGN(sizeof(struct xt_tcp)),}
// 在do_command4的default中进行command_defult会进行解析match,将dport放入match(struct xt_tcp)中。
(2-2-3)
// cs.target构建
1758 case CMD_INSERT:
1759 ret = insert_entry(chain, e, rulenum - 1, // chain 通过参数I后的值(optarg)
1760 nsaddrs, saddrs, smasks,
1761 ndaddrs, daddrs, dmasks,
1762 cs.options&OPT_VERBOSE,
1763 *handle); // 此处的handle可以通过iptc_init(表名)获取
646 static int
647 insert_entry(const xt_chainlabel chain,
648 struct ipt_entry *fw,
649 unsigned int rulenum,
650 unsigned int nsaddrs,
651 const struct in_addr saddrs[],
652 const struct in_addr smasks[],
653 unsigned int ndaddrs,
654 const struct in_addr daddrs[],
655 const struct in_addr dmasks[],
656 int verbose,
657 struct xtc_handle *handle)
658 {
659 unsigned int i, j;
660 int ret = 1;
661
662 for (i = 0; i < nsaddrs; i++) {
663 fw->ip.src.s_addr = saddrs[i].s_addr;
664 fw->ip.smsk.s_addr = smasks[i].s_addr;
665 for (j = 0; j < ndaddrs; j++) {
666 fw->ip.dst.s_addr = daddrs[j].s_addr;
667 fw->ip.dmsk.s_addr = dmasks[j].s_addr;
668 if (verbose)
669 print_firewall_line(fw, handle); // 打印log:ACCEPT tcp opt -- in * out * 192.168.0.124 -> 0.0.0.0/0 tcp dpt:3339
670 ret &= iptc_insert_entry(chain, fw, rulenum, handle);
671 }
672 }
673
674 return ret;
675 }
有待于后续