kkkggg 发表于 2013-11-02 17:44

1个ipfw规则脚本(feebsd+ipfw+dummynet+http透明代理)

本帖最后由 kkkggg 于 2013-11-21 17:01 编辑

备忘。
dummynet的动态带宽分配功能很好用。在共享上网的环境下,要限制某些上传流量过大堵塞网络的ip的时候,按ip数动态分配带宽比按优先级或分配固定带宽的方式要更有效。

下面先简单描述一下数据包经过本防火墙规则匹配的流程,方便理清规则制定思路。复杂的地方在于本规则同时使用了透明代理和单ip流量控制以及状态规则。
以下规则适用于系统参数net.inet.ip.fw.one_pass为1时的情况。即数据包只在同一方向放行一次。

如果把数据包按经过接口方向划分类别的话,ipfw规则主要有in和out两大方向,再乘以接口数就等于数据包接口方向类型总数。每种类型的数据包只匹配于同种类型的规则(一条规则可能属于多种类型)。比方说通常一个数据包从内网传输到外网被看做是经过一个方向,但实际上这个数据包要至少匹配ipfw规则中的两种规则:内网in方向和外网out两种规则。
一般情况下(有一块内网网卡,一块外网网卡)的ipfw规则按接口方向分为6类
环路接口in
环路接口out
内网接口in
外网接口out
外网接口in
内网接口out


#环路接口in

放行所有数据包

#环路接口out

放行所有数据包

#内网接口in

拒绝指定的数据包
check-state
skipto跳转需要放行并进行上行流量控制的数据包到拒绝规则后面,并加上keep-state
拒绝未匹配到的数据包
动态单个ip上行流量控制(因为涉及http代理,所以在这里进行每个ip上行流量控制。因为在外网接口那里已经分不出经过代理的http数据包原始源ip,无法很好的为每个ip分配带宽)

#外网接口out

skipto跳转不需要http代理的数据包到fwd规则后面
fwd重定向访问http端口的数据包到本地http代理服务端口
nat源地址转换

#外网接口in

拒绝指定的数据包
nat目的地址转换

#内网接口out

check-stat
放行所有数据包


制定规则时,可以先按各个方向分别制定规则,然后把各个方向的规则根据优先级顺序拼在一起。规则匹配次数不一样,对CPU造成的负荷不一样。所以应该把匹配最频繁、最多数量的数据包的规则尽量靠前。check-state规则在每个方向上都进行匹配,要特别小心。由于本规则在内网in和外网out方向均有跳转语句,且跳转到的规则动作不同。要想两个这方向的规则互不影响的话,要把外网out规则放到前面,check-state放到中间,带状态的内网in规则放到后面。

下面是规则代码,nat用的是libalias#定义网络接口名变量

ext_if="tun0"
int_if="xl0"
lan_net="10.0.0.0/22"

#定义细分类端口变量(规则中不直接引用此类变量名,只为方便标识,后面会合并到主要分类中)

general_tcp_ports="25,53,110,143,443,636,993,995"        #smtp,dns,pop3,imap,https,ldap,ipops,imaps
general_udp_ports="53,123"                #dns,ntp
msn_tcp_ports="569,1503,1863,5061,7001"
government_tcp_ports="5222,5678,7002,7888,8980"                #某些政府服务器端口
working_tcp_ports="212,1433,3306"      #,mssql,mysql
qq_udp_ports="8000"

#定义主要分类端口变量(会在规则中直接引用的变量名)

http_proxy_ports="80"

#用户组1额外开放的端口
group1_tcp_ports="22,6618,8000,8080,9898"      #ssh,酷狗,手机软件,手机软件,手机软件
group1_udp_ports="3545,6618"           #酷狗,酷狗

#定义特殊应用1的目的端口
special_app1_tcp_ports="8080"                #手机QQ

#合并先前的细类,注意引号内不能有空格,一条规则端口参数项最多为30个
permitted_tcp_ports_1="$general_tcp_ports,$msn_tcp_ports,$government_tcp_ports,$working_tcp_ports"
permitted_udp_ports_1="$general_udp_ports,$qq_udp_ports"

#本机开启服务端口
localhost_tcp_service="3000,3128,10000"                #ntop,squid,webmin
localhost_udp_service="53,123"                #dns,dhcp,ntp

#清空系统中已有的规则
ipfw -q flush
ipfw -q table all flush
ipfw -q pipe flush

#定义ip地址表

#定义私有网络地址表priv_net
ipfw table 5 add 127.0.0.0/8
ipfw table 5 add 192.168.0.0/16
ipfw table 5 add 172.16.0.0/12
ipfw table 5 add 10.0.0.0/8

#定义拒绝的外网源地址
ipfw table 10 add 200.0.0.1/32                #sample

#定义无网络权限客户机ip
ipfw table 15 add 10.0.1.25/32                #xxx

#定义拒绝访问目的地址ip
ipfw table 20 add 220.164.144.207

#无限制端口服务器地址
ipfw table 25 add 202.105.113.38/32

#定义允许访问所有tcp端口的目的地址(http端口数据包依然要通过代理服务)
ipfw table 30 add 116.228.70.245/32   #圆通物流

#定义高访问权限客户机ip地址(除了不允许访问的外网ip不能访问外)
ipfw table 35 add 10.0.0.9/32                #test
ipfw table 35 add 10.0.0.63/32                #voip

#定义不经过squid代理,直接访问的服务器ip地址
ipfw table 40 add 202.128.247.44/32        #海关物品编码查询
ipfw table 40 add 58.61.142.185/32        #顺丰快递查单
ipfw table 40 add 14.17.29.0/24                #qq离线文件服务器
ipfw table 40 add 113.108.0.0/19        #qq离线文件服务器
ipfw table 40 add 113.142.0.0/19        #qq离线文件服务器
ipfw table 40 add 115.236.128.0/19        #qq离线文件服务器
ipfw table 40 add 124.115.10.0/24        #qq离线文件服务器
ipfw table 40 add 182.131.0.0/19        #qq离线文件服务器
ipfw table 40 add 182.140.128.0/19        #qq离线文件服务器
ipfw table 40 add 119.146.200.0/27        #网易云阅读

#定义不经过squid代理的客户机ip
ipfw table 45 add 10.0.1.64/32                #xxx

#定义访问与$special_app1_tcp_ports端口对应的地址
ipfw table 50 add 121.14.64.0/18        #手机QQ

#定义用户组group1地址
ipfw table 55 add 10.0.0.3/32                #xxx
ipfw table 55 add 10.0.1.64/32                #xxx





#规则开始


#允许本地lo0接口双向访问
ipfw -q add 100 allow all from any to any via lo0

#放行发往内网的数据包
ipfw -q add 200 allow all from any to $lan_net out xmit $int_if

#丢弃指定外网ip发过来的数据包
ipfw -q add 300 deny ip from table\(10\) to any in recv $ext_if

#拒绝无网络权限客户机ip
ipfw -q add 400 reject ip from table\(15\) to any in recv $int_if

#丢弃ip分片包
ipfw -q add 500 deny ip from any to any in frag

#拒绝欺骗数据包进入
ipfw -q add 600 deny ip from me to any in
#ipfw -q add 700 deny ip from table\(5\) to any in recv $ext_if

#NAT接收到的外网接口的数据包
ipfw -q nat 1 config if $ext_if                #nat绑定到外网接口
ipfw -q add 999 nat 1 ip from any to any in recv $ext_if                #nat从外网来的数据包

#放行管理员客户机
#ipfw -q add 1100 allow ip from 10.0.1.10/32 to any in
#ipfw -q add 1200 allow ip from any to 10.0.1.10/32 out

#允许内网ssh连接本机(没使用状态规则,避免刷新规则时断开连接)
ipfw -q add 1300 allow tcp from any to me 22 in recv $int_if
#ipfw -q add 1400 allow tcp from me 22 to any out xmit $int_if

#允许本机dhcp服务
ipfw -q add 1500 allow udp from any 68 to any 67 in recv $int_if
#ipfw -q add 1600 allow udp from me 67 to any 68 out xmit $int_if

#让不使用http代理的数据包跳过下面的2999转发规则
ipfw -q add 1700 skipto 3999 tcp from any to table\(25\) out recv $int_if        #无限制外网ip
ipfw -q add 1800 skipto 3999 tcp from table\(35\) to any out recv $int_if        #无限制用户
ipfw -q add 1900 skipto 3999 tcp from any to table\(40\) $http_proxy_ports out recv $int_if        #访问指定不使用http代理的服务器地址
ipfw -q add 2000 skipto 3999 tcp from table\(45\) to any $http_proxy_ports out recv $int_if        #指定不使用http代理的客户机

#转发从内网接口进入的要出去的端口为$http_proxy_ports的非本机数据包到本机的3128端口(squid代理)
ipfw -q add 2999 fwd 127.0.0.1,3128 tcp from $lan_net to not me $http_proxy_ports out recv $int_if

#NAT要从外网接口出去的数据包
ipfw -q add 3999 nat 1 ip from $lan_net to any out xmit $ext_if

#状态检查
ipfw -q add 4999 check-state

#拒绝访问指定目的地址
ipfw -q add 5100 reject ip from any to table\(20\) in recv $int_if

#允许指定放行的上行数据跳到规则10100进行流量控制

#放行访问指定本地服务端口的数据包(带状态)
ipfw -q add 5200 skipto 10100 udp from any to me $localhost_udp_service in recv $int_if keep-state
ipfw -q add 5300 skipto 10100 tcp from any to me $localhost_tcp_service in setup recv $int_if keep-state

#放行访问任意端口的指定服务器地址
ipfw -q add 5400 skipto 10100 ip from any to table\(25\) in recv $int_if keep-state

#放行内网进入,访问网页代理端口$http_proxy_ports的数据包
ipfw -q add 5500 skipto 10100 tcp from any to any $http_proxy_ports in recv $int_if

#放行内网进入,$permitted_tcp_ports_1指定tcp端口的数据包
ipfw -q add 5600 skipto 10100 tcp from any to any $permitted_tcp_ports_1 in setup recv $int_if keep-state

#放行内网进入,$permitted_udp_ports_1指定udp端口的数据包
ipfw -q add 5700 skipto 10100 udp from any to any $permitted_udp_ports_1 in recv $int_if keep-state

#允许访问所有tcp端口的指定目的地址(http依然要通过代理)
ipfw -q add 5800 skipto 10100 tcp from any to table\(30\) in setup recv $int_if keep-state

#放行高访问权限客户机
ipfw -q add 5900 skipto 10100 ip from table\(35\) to any in recv $int_if keep-state

#放行指定group1用户组指定tcp端口的数据包
ipfw -q add 6000 skipto 10100 tcp from table\(55\) to any $group1_tcp_ports in setup recv $int_if keep-state

#放行指定group1用户组指定udp端口的数据包
ipfw -q add 6100 skipto 10100 udp from table\(55\) to any $group1_udp_ports in recv $int_if keep-state

#放行访问特殊应用1目的地址和tcp端口的数据包
ipfw -q add 6200 skipto 10100 tcp from any to table\(50\) $special_app1_tcp_ports in setup recv $int_if keep-state        #手机QQ

#放行icmp
ipfw -q add 6300 skipto 10100 icmp from any to any in recv $int_if keep-state

#拒绝以上规则未匹配到的内网数据包并返馈回源地址
ipfw -q add 9999 reject ip from $lan_net to any in recv $int_if

#流量控制(包括http代理在内的本机外出数据包没有到达这里的流量控制规则)

#内网接口上绑定队列
ipfw -q add 10100 queue 1 ip from $lan_net to not me in recv $int_if
ipfw -q add 10200 queue 1 tcp from $lan_net to me 3128 in recv $int_if        #直接访问本机http代理的数据包

#为队列指定pipe下,设定源地址匹配掩码,按实时ip数平分带宽
ipfw -q queue 1 config pipe 1 mask src-ip 0x000003ff

#设定管道带宽(adsl上传带宽本应为500Kbit左右,但要为本机发出的数据包留出部分带宽,否则http代理可能无法正常工作)
ipfw -q pipe 1 config bw 420Kbit/s

#最后一条
ipfw -q add 65000 allow ip from any to any
页: [1]
查看完整版本: 1个ipfw规则脚本(feebsd+ipfw+dummynet+http透明代理)