最近项目有个功能,需要读取linux服务器上iptables rule的信息。
一开始我是用popen 去调用命令“iptables -L -nv”,然后用fgets去获取命令返回结果。
但是这种方法CPU耗时非常打,特别是调用popen和fgets的开销大。
所以需要换一种方法,用libiptc的接口来实现。
但是在编译的时候,因为我是用的C++编译,但是失败了,
ip_tables.h:217: error:invalid conversion from 'void*' to 'xt_entry_target*'
这是因为我在#include “libiptc/libiptc.h”后,libiptc.h里面会再#include <linux/netfilter_ipv4/ip_tables.h>而#include <linux/netfilter_ipv4/ip_tables.h>是C语言的头文件,它允许将 'void*' 强制类型转换成 'xt_entry_target*',
但在C++编译器里面不允许这种类型转换。
我一开始去修改这个头文件,编译通过了。
static __inline__ struct xt_entry_target *
ipt_get_target(struct ipt_entry *e)
{
- return (void *)e +e->target_offset;
+ return (struct xt_entry_target*)((__u8 *)e + e->target_offset);
}
但是同事建议不要去修改系统带头文件,这样可能会造成其他代码出问题。
所以我只好另想一个workround的方法,写一个C代码去包含这个#include “libiptc/libiptc.h”(这个要放在.c文件里面) ,并在代码里面写一个函数将取到的iptables rule的结果存放到结构体数组里面,这样就可以用C编译器去编译这段代码。
然后再写一个和C代码对应的C头文件,在C++代码中用extern “C” {#include xxxxxx.h}去包含这个头文件,并调用C里面的函数来获取结果。
iptc.c
#include "libiptc/libiptc.h"
#include "string.h"
#include "WalIptc.h"
int GetRuleMatch(RuleMatch *rule_match)
{
const char *tablename = "filter";
const char *chain = "VLAN_CNT";
struct iptc_handle *h;
h = iptc_init(tablename);
if (!h){
return -1;
}
int match_num = 0;
const struct ipt_entry *e;
e = iptc_first_rule(chain, h);
while(e) {
strncpy((rule_match+match_num)->iniface, e->ip.iniface, INIFACE_LEN);
(rule_match+match_num)->pcnt = e->counters.pcnt;
++match_num;
e = iptc_next_rule(e, h);
}
iptc_free(h)
return match_num;
}
iptc.h
#ifndef _IPTC_YES
#define _IPTC_YES
#include <stdint.h>
#define INIFACE_LEN 15
#define RULEMATCH_LEN 10
typedef struct RuleMatchInfo{
char iniface[INIFACE_LEN];
uint64_t pcnt;
}RuleMatch;
int GetRuleMatch(RuleMatch *rule_match);
#endif //_IPTC_YES