一点ebtables的心得
项目用到了ebtables,抽空研究了以下。可能是因为ebtables在实际运用中使用得比较少的原因吧,提供的接口没有iptables方便。
iptables提供一个libiptc的库,其中提供获取策略列表、修改策略列表、实施策略等相关函数,二次开发者可以很简单使用这些函数运用自定义模块。
两者都提供很好的扩展机制,用于解析自定义的过滤或者目标(ebtables还有watch类型)模块。但很多时候为了效率,并不推荐使用程序里面还使用shell命令,特别像很多新手还喜欢疯狂的使用system()函数--当然这个函数本身并没有什么问题,但是我们很难获取运行结果--扯远了。
以前在看iptables代码时没有太认真,而且当时自己也很缺乏这方面的知识,因为ebtables代码比较少,可以比较快的整理出它的整体结构
关于扩展模块支持,最重要的问题还是怎么注册一个解析器,也就是怎么维护这些加载了的插件呢?以前曾经想写具有扩展功能的程序,才发现这的确是个问题。iptables/ebtables都一样--把管理插件的功能函数放到一个动态库中,在动态库中维护插件列表。在编译是首先编译这个动态库 在编译主程序和扩展模块的时候就可以使用这个动态库来编译如此就可以编译通过。在运行期间使用dlopen来加载扩展模块,而模块被加载时系统会自动调用该模块中的void _init(void)函数,只要在这个函数内注册自己就可以达到我们的目的。而在使用dlclose卸载模块时,系统会调用void _fini(void)函数,在这个函数中注销自己
ebtables与内核交互格式:
ebt_replace|ebt_entries|ebt_entry|ebt_entry|...|ebt_entries|ebt_entry|...|ebt_entries|...
ebtables中的几个结构说明:
ebt_replace
name 表名 (filter nat broute)
valid_hooks 掩码形式 表示在使用的钩子
nentries 策略条目总数
entries_size 策略总大小 (包括所有ebt_entries和所有ebt_entry的大小)
hook_entry 最重要的部分 确定每个chain(也就是钩子)策略的起始位置
本以为会使用偏移量 最终发现它使用的实际地址位置
num_counters 用户态希望计数器数量
counters 内核返回计数器位置
entries 策略开始指针 没有使用char[0]的标签功能
老实说个人对这个结构实在不太恭维 总体上来说容错还是很不错的 几个地方(hook_entry和entries)没有使用偏移量表示 而是使用了用户态指针 估计是考虑到整个结构比较庞大 可以不必使用完全的连续内存吧。这种做法是仁者见仁智者见智了。
本人认为既然最大内存使用的策略部分已经要求连续内存了又何必对此一举呢?
ebt_entries
distinguisher 兼容部分 直接飘过 zero it
name chain名称(filter: PREROUTING INPUT OUTPUT POSTROUTING
nat: PREROUTING INPUT OUTPUT POSTROUTING broute: BROUTING)
counter_offset
policy chain默认的策略 可以是accept drop return 就是对待数据包最后方式了
nentries 本chain的策略总数
data[0] 这地方就是说明 需要连续内存地址了
简单明了的结构 但是在这 我还是犯了困 counter_offset内核注释是这样的counter offset for this chain 按理说:总的counter是0这地方怎么会不是0呢 可惜它就是不是0 它等于前面所有chain的策略总数 到现在还是没想明白这是为什么
ebt_entry
bitmask 有效位置掩码
invflags 无效位置掩码
ethproto 以太网协议类型
in 输入设备名
logical_in 逻辑输入设备
out 输出设备名
logical_out 逻辑输出设备名
sourcemac 源MAC地址
sourcemask 源MAC地址掩码
destmac 目标MAC地址
destmask 目标MAC地址掩码
watchers_offset 该策略watcher的偏移地址(这里是相对偏移量)
target_offset 该策略target的偏移地址
next_offset 下一条策略的偏移地址(实际上是本策略的总长度)
每条策略都必须以ebt_entry开头 策略可以包含多个match和多个watcher但是只能有一个target
match是紧跟着ebt_entry 没有设置其的起始
watcher的位置由watchers_offset指定 如果没有那么它应该与target_offset相等
target任何策略都“必须”有一个target
这部分与iptables相似 只是多了watcher 以及其中的内容不同
还有一点重大区别是 ebtalbes并没有对match watcher和target的内容长度进行对齐