因为老师留作业要对Netfilter内核模块进行扩展编程,因此在此之前先学习了一下iptables的用法,笔记一下,忘了就来看看。
首先推荐一篇不错的博客,作为参考补充:
http://www.cnblogs.com/JemBai/archive/2009/03/19/1416364.html
先说一下iptables和netfilter的关系:
netfilter在内核空间的代码根据table中的rules,完成对packet的分析和处置。但是这些table中的具体的防火墙rules,还是必须由系统管理员亲自编写。内核中的netfilter只是提供了一个机制,它并不知道该怎样利用这个机制,写出合适的rules,来实现一个网络防火墙。
那么,系统管理员编写的rules,怎样进入位于内核空间中的netfilter维护的table中去呢?这个任务是由iptables这个工具来完成的。
说白了就是netfilter是位于内核里的,iptables是位于用户空间的管理工具。有了iptables,用户空间就可以和内核中的netfilter进行交流,维护table中的防火墙rules了。
iptables 包含 5 张表(tables):
- raw 用于配置数据包,raw 中的数据包不会被系统跟踪。
- filter 是用于存放所有与防火墙相关操作的默认表。
- nat 用于 网络地址转换(例如:端口转发)。
- mangle 用于对特定数据包的修改(参考 损坏数据包)。
- security 用于 强制访问控制 网络规则(例如: SELinux – 详细信息参考 该文章)。
大部分情况仅需要使用 filter 和 nat。其他表用于更复杂的情况——包括多路由和路由判定。
我们暂时主要了解一下filter的过滤好了。
表由链组成,链是一些按顺序排列的规则的列表。默认的 filter 表包含 INPUT, OUTPUT 和 FORWARD 3条内建的链,这3条链用于数据包过滤。
数据包的过滤基于规则。规则由一个目标(数据包包匹配所有条件后的动作)和很多匹配(导致该规则可以应用的数据包所满足的条件)指定。一个规则的典型匹配事项是数据包进入的端口(例如:eth0 或者 eth1)、数据包的类型(ICMP, TCP, 或者 UDP)和数据包的目的端口。
在我的Arch上,执行iptables的话需要root权限,毕竟是对内核功能的操作。
查看当前iptables的设置
pArch# iptables -nvL
Chain INPUT (policy ACCEPT 1 packets, 52 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 1 packets, 52 bytes)
pkts bytes target prot opt in out source destination
以上参数的意义:
-L, --list [chain]
List all rules in the selected chain. If no chain is selected, all chains are listed.
-n, --numeric
Numeric output. IP addresses and port numbers will be printed in numeric format. By default, the program will try to display them as host names, network names, or services (whenever applicable).
-v, --verbose
Verbose output. This option makes the list command show the interface name, the rule options (if any), and the TOS masks. The packet and byte counters are also listed, with the suffix 'K', 'M' or 'G' for 1000, 1,000,000 and 1,000,000,000 multipliers respectively.
上面的三条链INPUT/FORWARD/OUTPUT的policy都是ACCEPTED,表明还没有配置规则。没有数据包被阻止,均被接受。
清除原有规则
pArch# iptables -F #清除预设表filter中的所有规则链的规则
pArch# iptables -X #清除预设表filter中使用者自定链中的规则
如果已经有了过滤规则,可以通过以上命令清空,然后再一步步设置。
预设规则
比如将INPUT(所有接收的包)默认都丢掉:
pArch# iptables -P INPUT DROP
pArch# iptables -nvL
Chain INPUT (policy DROP 26 packets, 3074 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 22 packets, 1626 bytes)
pkts bytes target prot opt in out source destination
其中参数:
-P, --policy chain target
Set the policy for the chain to the given target. Only built-in (non-user-defined) chains can have policies, and neither built-in nor user-defined chains can be policy targets.
可以看到,INPUT的policy已经变成DROP了,而立刻就有妄图发到我的电脑的26 packets, 3074 bytes被丢弃了。
注:如果你是远程SSH登陆的话,当你输入第一个命令回车的时候就应该掉了,因为设置完默认丢弃所有包之后,没有设置任何可以接收的包。掉线了怎么办呢,只能去本机操作了=.=!
添加规则
由于刚刚我们默认INPUT为DROP,则所有进入计算机的包都会被防火墙丢掉,本机收不到任何包。也就是说此时如果进行ping www.baidu.com
的话是不会成功的,因为icmp的echo request报文虽然发出去了,但是echo response报文被drop了。
为了能ping通,我们需要设置icmp报文为可接受状态:
pArch# iptables -A INPUT -p icmp -j ACCEPT
pArch# iptables -nvL --line-numbers
Chain INPUT (policy DROP 227 packets, 36248 bytes)
num pkts bytes target prot opt in out source destination
1 18 1869 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
其中:
-A, --append chain rule-specification
Append one or more rules to the end of the selected chain. When the source and/or destination names resolve to more than one address, a rule will be added for each possible address combination.
[!] -p, --protocol protocol
The protocol of the rule or of the packet to check. The specified protocol can be one of tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh or the special keyword "all", or it can be a numeric value, representing one of these pro‐tocols or a different one.
-j, --jump target
This specifies the target of the rule; i.e., what to do if the packet matches it.
所以iptables -A INPUT -p icmp -j ACCEPT
的意思就是给INPUT链添加一条规则,对于所有的icmp协议,都ACCEPT。
这样的话ping就可以执行了。
我们都知道访问服务器的80端口可以上网,所以我们使用iptables对自己的防火墙进行设置:除了上网的报文,其余所有出去的报文均被拦截。
设置之后的效果:
pArch# iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
pArch# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 1 packets, 52 bytes)
num pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 171K 11M ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
其中--dport
代表destination port,目的端口号;--sport
代表source port,源端口号。
上面的设置就是说我的电脑对访问外服务器的80端口的tcp协议报文是放行的,即对请求网页的报文是放行的,再说白点儿就是允许上网。
然后当我在浏览器中上百度的时候却发现无论如何都上不去。这不科学!应该是可以上网的啊,我已经把通往外网80端口的数据包默认放行了啊!
后来找了半天原因,才发现百度的网址是https://www.baidu.com/,是https而不是http,而https所对应的端口是443(443/TCP HTTPS - HTTP over TLS/SSL(加密传输)),不是80(80/TCP HTTP(超文本传输协议)- 用于传输网页)。
于是我果断换了个网址,访问新浪http://www.sina.com.cn/,果然就成功了。
然后把443端口也设为ACCEPT,iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
,再上百度果然就行了。
最后说一下iptables的配置问题,参考https://wiki.archlinux.org/index.php/Iptables
iptables 是一个 Systemd 服务,因此可以这样启动:
systemctl start iptables
但是,除非有 /etc/iptables/iptables.rules 文件,否则服务不会启动,Arch iptables 包不包含默认的 iptables.rules 文件。因此,第一次启动服务时使用以下命令:
touch /etc/iptables/iptables.rules
systemctl start iptables
或者
cp /etc/iptables/empty.rules /etc/iptables/iptables.rules
systemctl start iptables
和其他服务一样,如果希望启动时自动加载 iptables,必须启用该服务:
systemctl enable iptables
通过命令行添加规则,配置文件不会自动改变,所以必须手动保存:
iptables-save > /etc/iptables/iptables.rules
修改配置文件后,需要重新加载服务:
systemctl reload iptables
或者通过 iptables 直接加载:
iptables-restore < /etc/iptables/iptables.rules