我还包含了从 Linux netfilter Hacking HOWTO 中获取的简要描述(如果可用),在每个函数说明中。
原型: iptc_handle_t iptc_init(const char *tablename)
描述: 在调用任何其他函数之前,必须先调用此函数作为初始化器。
参数: tablename 是我们需要查询和/或修改的表的名称;这可以是 filter、mangle、nat 等。
请查看文件中的这段代码iptables-save.c了解如何调用此函数
h = iptc_init(tablename);
if (!h)
exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",iptc_strerror(errno)); |
原型: const char *iptc_strerror(int err)
描述: 此函数返回 iptc 库中失败代码的更具意义的解释。如果函数失败,它将始终设置 errno。可以将此值传递给 iptc_strerror() 以产生错误消息。
原型: const char *iptc_first_chain(iptc_handle_t *handle)
原型: const char *iptc_next_chain(iptc_handle_t *handle)
描述: 此函数返回表中的下一个链名称;NULL 表示没有更多链。
参数: 指向 iptc_handle_t 类型结构的指针,该指针是通过先前调用 iptc_init 获得的。
前两个函数允许我们遍历表的链,获取每个链的名称;iptc_first_chain 返回表的第一个链的名称;iptc_next_chain 返回下一个链的名称,当函数到达末尾时返回 NULL。
/*
* How to use libiptc- program #1
* /usr/local/src/p1.c
*/
#include <getopt.h>
#include <sys/errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <time.h>
#include "libiptc/libiptc.h"
#include "iptables.h"
int main(void)
{
iptc_handle_t h;
const char *chain = NULL;
const char *tablename = "filter";
program_name = "p1";
program_version = NETFILTER_VERSION;
h = iptc_init(tablename);
if ( !h ) {
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) {
printf("%s\n", chain);
}
exit(0);
} /* main */ |
编写此程序并将其另存为p1.c在/usr/local/src.
#!/bin/bash gcc -Wall -Wunused -DNETFILTER_VERSION=\"1.2.6\" -rdynamic -o $1 $1.c \ /usr/local/lib/iptables.o /usr/local/lib/libiptc.a -ldl |
将其另存为ipt-cc并且不要忘记 chmod 0700 ipt-cc。
bash# ./ipt-cc p1 |
bash# ./p1 |
INPUT FORWARD OUTPUT |
bash# iptables -N chain_1 bash# iptables -N chain_2 bash# ./p1 |
INPUT FORWARD OUTPUT chain_1 chain_2 |
尝试生成一个错误,将 tablename 初始化为 myfilter 而不是 filter。当您再次编译并执行程序时,您将得到
Error initializing: Table does not exist (do you need to insmod?) |
原型: int iptc_is_chain(const char *chain, const iptc_handle_t handle)
描述: 此函数检查参数 chain 中描述的链是否在表中存在。
参数: chain 是一个字符指针,包含我们要检查的链的名称。handle 是指向 iptc_handle_t 类型结构的指针,该指针是通过先前调用 iptc_init 获得的。
原型: int iptc_builtin(const char *chain, const iptc_handle_t handle)
参数: chain 是一个字符指针,包含我们要检查的链的名称。handle 是指向 iptc_handle_t 类型结构的指针,该指针是通过先前调用 iptc_init 获得的。
原型: const struct ipt_entry *iptc_first_rule(const char *chain, iptc_handle_t *handle)
描述: 此函数返回指向给定链名称中第一个规则的指针;对于空链,返回 NULL。
参数: chain 是一个字符指针,包含我们要获取规则的链的名称。handle 是指向 iptc_handle_t 类型结构的指针,该指针是通过先前调用 iptc_init 获得的。
原型: const struct ipt_entry *iptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle)
原型: const char *iptc_get_target(const struct ipt_entry *e, iptc_handle_t *handle)
返回值: 返回指向目标名称的字符指针。有关更多信息,请参见上面的描述。
现在是时候解释 ipt_entry 结构了;以下代码片段取自 iptables 包的源代码
/* Internet address. */
struct in_addr {
__u32 s_addr;
};
/* Yes, Virginia, you have to zero the padding. */
struct ipt_ip {
/* Source and destination IP addr */
struct in_addr src, dst;
/* Mask for src and dest IP addr */
struct in_addr smsk, dmsk;
char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
/* Protocol, 0 = ANY */
u_int16_t proto;
/* Flags word */
u_int8_t flags;
/* Inverse flags */
u_int8_t invflags;
};
struct ipt_counters
{
u_int64_t pcnt, bcnt; /* Packet and byte counters */
};
/* 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 */
u_int16_t target_offset;
/* Size of ipt_entry + matches + target */
u_int16_t next_offset;
/* Back pointer */
unsigned int comefrom;
/* Packet and byte counters. */
struct ipt_counters counters;
/* The matches (if any), then the target. */
unsigned char elems[0];
}; |
一个 ipt_counters 结构,包含规则的数据包 (pcnt) 和字节 (bcnt) 计数器。此信息对于带宽测量很重要。
未知字段:nfcache, comefrom, elems, next_offset。如果有人可以给我关于这些字段的反馈,我将不胜感激。
使用所有这些信息的简单方法是从以下位置借用一些函数iptables-save.cPaul Russell 和 Harald Welte。
这是另一个示例程序 程序 #2,在 Russell-Welte 的大力帮助下编写
/*
* How to use libiptc- program #2
* /usr/local/src/p1.c
*/
#include <getopt.h>
#include <sys/errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <time.h>
#include "libiptc/libiptc.h"
#include "iptables.h"
/* Here begins some of the code taken from iptables-save.c **************** */
#define IP_PARTS_NATIVE(n) \
(unsigned int)((n)>>24)&0xFF, \
(unsigned int)((n)>>16)&0xFF, \
(unsigned int)((n)>>8)&0xFF, \
(unsigned int)((n)&0xFF)
#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
/* This assumes that mask is contiguous, and byte-bounded. */
static void
print_iface(char letter, const char *iface, const unsigned char *mask,
int invert)
{
unsigned int i;
if (mask[0] == 0)
return;
printf("-%c %s", letter, invert ? "! " : "");
for (i = 0; i < IFNAMSIZ; i++) {
if (mask[i] != 0) {
if (iface[i] != '\0')
printf("%c", iface[i]);
} else {
/* we can access iface[i-1] here, because
* a few lines above we make sure that mask[0] != 0 */
if (iface[i-1] != '\0')
printf("+");
break;
}
}
printf(" ");
}
/* These are hardcoded backups in iptables.c, so they are safe */
struct pprot {
char *name;
u_int8_t num;
};
/* FIXME: why don't we use /etc/protocols ? */
static const struct pprot chain_protos[] = {
{ "tcp", IPPROTO_TCP },
{ "udp", IPPROTO_UDP },
{ "icmp", IPPROTO_ICMP },
{ "esp", IPPROTO_ESP },
{ "ah", IPPROTO_AH },
};
static void print_proto(u_int16_t proto, int invert)
{
if (proto) {
unsigned int i;
const char *invertstr = invert ? "! " : "";
for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
if (chain_protos[i].num == proto) {
printf("-p %s%s ",
invertstr, chain_protos[i].name);
return;
}
printf("-p %s%u ", invertstr, proto);
}
}
static int print_match(const struct ipt_entry_match *e,
const struct ipt_ip *ip)
{
struct iptables_match *match
= find_match(e->u.user.name, TRY_LOAD);
if (match) {
printf("-m %s ", e->u.user.name);
/* some matches don't provide a save function */
if (match->save)
match->save(ip, e);
} else {
if (e->u.match_size) {
fprintf(stderr,
"Can't find library for match `%s'\n",
e->u.user.name);
exit(1);
}
}
return 0;
}
/* print a given ip including mask if neccessary */
static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
{
if (!mask && !ip)
return;
printf("%s %s%u.%u.%u.%u",
prefix,
invert ? "! " : "",
IP_PARTS(ip));
if (mask != 0xffffffff)
printf("/%u.%u.%u.%u ", IP_PARTS(mask));
else
printf(" ");
}
/* We want this to be readable, so only print out neccessary fields.
* Because that's the kind of world I want to live in. */
static void print_rule(const struct ipt_entry *e,
iptc_handle_t *h, const char *chain, int counters)
{
struct ipt_entry_target *t;
const char *target_name;
/* print counters */
if (counters)
printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt);
/* print chain name */
printf("-A %s ", chain);
/* Print IP part. */
print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
e->ip.invflags & IPT_INV_SRCIP);
print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
e->ip.invflags & IPT_INV_DSTIP);
print_iface('i', e->ip.iniface, e->ip.iniface_mask,
e->ip.invflags & IPT_INV_VIA_IN);
print_iface('o', e->ip.outiface, e->ip.outiface_mask,
e->ip.invflags & IPT_INV_VIA_OUT);
print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
if (e->ip.flags & IPT_F_FRAG)
printf("%s-f ",
e->ip.invflags & IPT_INV_FRAG ? "! " : "");
/* Print matchinfo part */
if (e->target_offset) {
IPT_MATCH_ITERATE(e, print_match, &e->ip);
}
/* Print target name */
target_name = iptc_get_target(e, h);
if (target_name && (*target_name != '\0'))
printf("-j %s ", target_name);
/* Print targinfo part */
t = ipt_get_target((struct ipt_entry *)e);
if (t->u.user.name[0]) {
struct iptables_target *target
= find_target(t->u.user.name, TRY_LOAD);
if (!target) {
fprintf(stderr, "Can't find library for target `%s'\n",
t->u.user.name);
exit(1);
}
if (target->save)
target->save(&e->ip, t);
else {
/* If the target size is greater than ipt_entry_target
* there is something to be saved, we just don't know
* how to print it */
if (t->u.target_size !=
sizeof(struct ipt_entry_target)) {
fprintf(stderr, "Target `%s' is missing "
"save function\n",
t->u.user.name);
exit(1);
}
}
}
printf("\n");
}
/* Here ends some of the code taken from iptables-save.c ****************** */
int main(void)
{
iptc_handle_t h;
const struct ipt_entry *e;
const char *chain = NULL;
const char *tablename = "filter";
const int counters = 1;
program_name = "p2";
program_version = NETFILTER_VERSION;
/* initialize */
h = iptc_init(tablename);
if ( !h ) {
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
/* print chains and their rules */
for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) {
printf("%s\n", chain);
for (e = iptc_first_rule(chain, &h); e; e = iptc_next_rule(e, &h)) {
print_rule(e, &h, chain, counters);
}
}
exit(0);
} /* main */ |
从以下位置借用的函数 print_ruleiptables-save.c使用以下方法以可读形式打印有关规则的信息
在 main 中,我们遍历每个链,并为每个链遍历每个规则并打印它。
bash# ./ipt-cc p2 bash# ./p2 |
INPUT FORWARD OUTPUT chain_1 chain_2 |
bash# iptables -A INPUT -p tcp -i eth0 -s ! 192.168.1.1 --dport 20 -j ACCEPT bash# iptables -A chain_1 -p udp -o eth1 -s 192.168.2.0/24 --sport 33 -j DROP |
INPUT [0:0] -A INPUT -s ! 192.168.1.1 -i eth0 -p tcp -m tcp --dport 20 -j ACCEPT FORWARD OUTPUT chain_1 [0:0] -A chain_1 -s 192.168.2.0/255.255.255.0 -o eth1 -p udp -m udp --sport 33 -j DROP chain_2 |
描述: 此函数获取内置链的策略,并使用该策略的命中统计信息填充 counters 参数。
使用程序 1 和程序 2 的代码片段,我们可以编写程序 #3
/*
* How to use libiptc- program #3
* /usr/local/src/p3.c
*/
#include <getopt.h>
#include <sys/errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <time.h>
#include "libiptc/libiptc.h"
#include "iptables.h"
int main(void)
{
iptc_handle_t h;
const char *chain = NULL;
const char *policy = NULL;
const char *tablename = "filter";
struct ipt_counters counters;
program_name = "p3";
program_version = NETFILTER_VERSION;
/* initialize */
h = iptc_init(tablename);
if ( !h ) {
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
/* print built-in chains, their policies and counters */
printf("BUILT-IN POLICY PKTS-BYTES\n");
printf("-----------------------------\n");
for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) {
if ( !iptc_builtin(chain, h) )
continue;
if ( (policy = iptc_get_policy(chain, &counters, &h)) )
printf("%-10s %-10s [%llu:%llu]\n",
chain, policy, counters.pcnt, counters.bcnt);
}
exit(0);
} /* main */ |
bash# ./ipt-cc p3 bash# ./p3 |
BUILT-IN POLICY PKTS-BYTES ---------------------------- INPUT ACCEPT [0:0] FORWARD ACCEPT [0:0] OUTPUT ACCEPT [0:0] |