iptables已经发展成为一个功能强大的防火墙,它已具备通常只会在专有的商业防火墙中才能发现的大多数功能。例如,iptables提供了全面的协议状态跟踪、数据包的应用层检查、速率限制和一个功能强大的机制以指定过滤策略和提供NAT功能。我在工作中逐渐领略到它的强大,在此跟大家分享一下我工作中的经验。
iptables相关概念:
1、表
2、链
3、匹配条件
4、动作
5、iptables语法
6、企业应用案例
(1)流量访问控制
(2)日志记录
1、表:
表是iptables构建块,它描述了其功能的大类,iptables共有4个表:filter、nat、mangle、和raw。过滤规则应用于filter、NAT规则应用于nat表,用于修改分组数据的特定规则应用于mangle表,而独立于Netfilter连接跟踪子系统起作用的规则应用于raw表。
2、链:
每个表都有自己的一组内置链,用户还可以对链进行自定义;当一个数据包由内核中的路由计算确定为指向本地linux系统,它将经过INPUT链的检查;OUTPUT链保留给有Linux系统自身生成的数据包;FORWARD链管理经过linux系统路由的数据包(即iptables防火墙用于连接两个网络,并且两个网络之间的数据包必须流经该防火墙)。nat表中的PREROUTING和POSTROUTING分别用于在内核进行IP路由计算之前和之后修改数据包的头部。
3、匹配条件:
iptables匹配指的是数据包必须匹配的条件,只有当数据包满足所有的匹配条件时,iptables才会采取相应的动作;匹配分为通用匹配和扩展匹配:
通用匹配:
-s | --src | --source [!] HOST/NET
-d |--dst | --destination [!] HOST/NET
#iptables -t filter -A INPUT -s 172.16.0.0/16 -d 172.16.1.1 -j ACCEPT
-i incoming_interface 指定报文进入接口
-o outgoing_interface 指定报文流出接口
EXT3文件写操作
如果应用层发起的是一个Word文档的写操作请求,那么通过上述分析,IO会走到sys_write的地方,然后执行file->f_op->write方法。对于EXT3,该方法注册的是do_sync_writeDo_sync_write的实现如下:
ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) struct iovec iov = { .iov_base = ( void __user *)buf, .iov_len = len }; struct kiocb kiocb; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; kiocb.ki_left = len; ret = filp->f_op->aio_write(&kiocb, &iov, 1 , kiocb.ki_pos); if (ret != -EIOCBRETRY) wait_on_retry_sync_kiocb(&kiocb); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; |
该方法会直接调用非阻塞写处理函数,然后等待IO完成。对于具体EXT3文件读写过程函数调用关系可以参考《Ext3文件系统读写过程分析》。对EXT3文件写操作主要考虑两种情况,一种情况是DIRECTIO方式;另一种情况是pagecache的写方式。DirectIO方式会直接绕过缓存处理机制,pagecache缓存方式是应用中经常采用的方式,性能会比DirectIO高出不少。对于每一个EXT3文件,都会在内存中维护一棵Radixtree,这棵radixtree就是用来管理来pagecache页的。当IO想往磁盘上写入的时候,EXT3会查找其对应的radixtree,看是否已经存在与写入地址相匹配的page页,如果存在那么直接将数据合并到这个page页中,并且结束一次IO过程,直接结束应用层请求。如果被访问的地址还没有对应的page页,那么需要为访问的地址空间分配page页,并且从磁盘上加载数据到page页内存,最后将这个page页加入到radixtree中。
对于一些大文件,如果不采用radixtree去管理page页,那么需要耗费大量的时间去查找一个文件内对应地址的page页。为了提高查找效率,Linux采用了radixtree的这种管理方式。Radixtree是通用的字典类型数据结构,radixtree又被称之为PAT位树(PatriciaTrieorcritbittree)。Radixtree是一种多叉搜索树,树的叶子节点是实际的数据条目。下图是一个radixtree的例子,该radixtree的分叉为4,树高为4,树中的每个叶子节点用来快速定位8位文件内偏移地址,可以定位256个page页。例如,图中虚线对应的两个叶子节点的地址值为0x00000010和0x11111010,通过这两个地址值,可以很容易的定位到相应的page缓存页。
通过radixtree可以解决大文件page页查询问题。在Linux的实现过程中,EXT3写操作处理函数会调用generic_file_buffered_write完成page页缓存写过程。在该函数中,其实现逻辑说明如下:
generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos, loff_t *ppos, size_t count, ssize_t written) /* 找到缓存的page页 */ page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); /* 处理ext3日志等事情 */ status = a_ops->prepare_write(file, page, offset, offset+bytes); /* 将用户数据拷贝至page页 */ copied = filemap_copy_from_user(page, offset, buf, bytes); /* 设置page页为dirty */ status = a_ops->commit_write(file, page, offset, offset+bytes); |
第一步通过radixtree找到内存中缓存的page页,如果page页不存在,重新分配一个。第二步通过ext3_prepare_write处理EXT3日志,并且如果page是一个新页的话,那么需要从磁盘读入数据,装载进page页。第三步是将用户数据拷贝至指定的page页。最后一步将操作的Page页设置成dirty。便于writeback机制将dirty页同步到磁盘。
Pagecache会占用Linux的大量内存,当内存紧张的时候,需要从pagecache中回收一些内存页,另外,dirtypage在内存中聚合一段时间之后,需要被同步到磁盘。应该在3.0内核之前,Linux采用pdflush机制将dirtypage同步到磁盘,在之后的版本中,Linux采用了writeback机制进行dirtypage的刷新工作。有关于writeback机制的一些源码分析可以参考《writeback机制源码分析》。总的来说,如果用户需要写EXT3文件时,默认采用的是writeback的
没有评论:
发表评论