藍森林首頁 | 返回主頁 | 本站地圖 | 站內搜索 | 聯繫信箱 |
 您目前的位置:首頁 > 自由軟件 > 技術交流 > 網絡通訊


    

藍森林 http://www.lslnet.com 2006年7月26日 13:28

配置 ipchains 做防火牆和透明代理的一些體會

最近我在我的 Linux (Debian 2.2 potato) 上配置了防火牆/透明代理,幾經周折,終於
成功了。好東西應該和大家分享,現在講講。(如果有錯誤,請批評指正)。

對於 2.2.x 版本的 Linux 內核而言,要使用 ipchains 防火牆和透明代理,應該先配置
內核以加入防火牆(透明代理)的支持:( 參照 IPCHAINS-HOWTO 和 IP-Masquerading-
HOWTO,我這只是簡要提一下 )

*Prompt for development and/or incomplete code/drivers
(CONFIG_EXPERIMENTAL)[Y/n/?]
YES:雖然不是 IP 偽裝所必須,但是此選項會激活其它偽裝模塊以用於端口轉發

*Enable loadable module support (CONFIG_MODULES)[Y/n/?]
YES:允許你載入內核的 IP 偽裝模塊

*Networking support (CONFIG_NET)[Y/n/?]
YES:激活網絡子系統

*Packet socket (CONFIG_PACKET)[Y/m/n/?]
YES:雖然這是可選的,但建議你激活此選項以便用 TCPDUMP 對 IP 偽裝的問題進行調試

*Kernel/User netlink socket (CONFIG_NETLINK) [Y/n/?]
YES:雖然這是可選的,但這項特性允許你對防火牆的攻擊 ( 原文是 hits ) 進行記帳

*Routing messages (CONFIG_RTNETLINK) [Y/n/?]
NO:這和防火牆記帳沒有任何關係 ( 我在這裡還是選擇了 YES,因為我有時也要查看一
下內核路由表信息 )

*Network firewalls (CONFIG_FIREWALL) [Y/n/?]
YES:激活 IPCHAINS 防火牆工具

*TCP/IP networking (CONFIG_INET) [Y/n/?]
YES:激活 TCP/IP 協議

*IP: advanced router (CONFIG_IP_ADVANCED_ROUTER) [Y/n/?]
NO:只是 CONFIG_IP_ROUTE_VERBOSE 和高級路由 ( 原文是 fancy routing ) 需要它 (與
ipchains/masq 獨立)

*IP: verbose route monitoring (CONFIG_IP_ROUTE_VERBOSE) [Y/n/?]
YES:這對於你對那些 IP 欺騙的包進行記帳很有用 ( 強烈建議 )

*IP: firewalling (CONFIG_IP_FIREWALL) [Y/n/?]
YES:激活防火牆特性

*IP: firewall packet netlink device (CONFIG_IP_FIREWALL_NETLINK) [Y/n/?]
YES: 雖然是可選項,但此特性可以增強對防火牆的記帳功能

*IP: always defragment ( required for masquerading)
(CONFIG_IP_ALWAYS_DEFRAG) [Y/n/?]
YES:此項對於 IP 偽裝/透明代理是必須的。此項特性也可優化 IP 偽裝聯接

*IP: masquerading (CONFIG_IP_MASQUERADE) [Y/n/?]
YES:激活 IP 偽裝,對從內部網向外部網的 IP 包重新分配地址

*IP: ICMP masquerading (CONFIG_IP_MASQUERADE_ICMP) [Y/n/?]
YES:對 ICMP ping 包進行偽裝 ( 對 ICMP 錯誤碼也一樣 )。這對網絡連接的排錯很有用

*IP: masquerading special modules support (CONFIG_IP_MASQUERADE_MOD) [Y/n/?]
YES:雖然這是可選項,但它會激活 TCP/IP 端口轉發系統以允許外部的計算機與內部偽裝
了的計算機建立直接的連接

*IP: ipautofw masq support (EXPERIMENTAL) (CONFIG_IP_MASQUERADE_IPAUTOFW)
[Y/n/m/?]
NO:IPautofw ( IP 自動轉發 ) 是一個傳統方法。它是一個 hack,現在用針對每種協議
的模塊會更好些。不建議

*IP: ipportfw masq support (EXPERITMENTAL) (CONFIG_IP_MASQUERADE_IPPORTFW)
[Y/n/m/?]
M:激活 IP 端口轉發
用這個選項,在 Internet 上的外部的計算機可以和在內部網已經偽裝了的計算
機直接通信。典型的應用就是從外部網訪問內部網的 smtp、telnet、www。

*IP: ip fwmark masq-forwarding support (EXPERITMENTAL) (CONFIG_IP_MASQUERAD_MFW)
[Y/m/n/?]
NO:允許你直接使用 IPCHAINS 進行端口轉發。現在這只是實驗性的代碼,建議你用
IPMASQADM 或者 IPPORTFW

*IP: optimize as a router not host (CONFIG_IP_ROUTER) [Y/n/?]
YES: 使內核對網絡子系統進行優化,雖然它 ( 原文是 it ) 不知道是否會有顯著的差別

*IP: GRE tunnels over IP (CONFIG_NET_IPGRE) [N/y/m/?]
NO:呵呵,看不懂,反正選 NO 就是了 :(

*IP: TCP syncookies support (not enable per default) (CONFIG_SYN_COOKIES)[y/n/?]
YES:為了基本的網絡安全,強烈建議選 YES

*Network device support (CONFIG_NETDEVICES) [Y/n/?]
YES:激活 Linux 網絡接口層

*Dummy net driver support (CONFIG_DUMMY) [M/n/y/?]
M:雖然是可選項,但對你調試錯誤有幫助

*** 如果你用的是 2.2.18 版本的內核,就有一項是 Transparency proxy support,選
*** 上它 (YES)

如果你用 make config/menuconfig/xconfig 看不到其中的某些選項,到 /usr/src/linux
下,打開 .config 文件直接編輯。然後再用 make menuconfig/xconfig 校驗一下,保存
改變。

接下來的內核 ( 模塊 ) 的編譯、lilo/grub 安裝,我就不贅述了。

好了,有關內核的就這麼多 (敲了半天鍵盤,歇一會兒,喝口水 :) 繼續 )

系統重啟後,去 /lib/modules/[version]/ipv4/ 下看看,應該有你所需要的模塊
ip_masq_cuseeme.o, ip_masq_irc.o, ip_masq_quake.o, ip_masq_user.o, ip_masq_ftp.o
ip_masq_portfw.o, ip_masq_port.o, ip_masq_raudio.o, ip_masq_vdolive.o

下面開始寫 shell 腳本:

#!/bin/sh
# 文件名:/root/firewall/fwrules
# 先設定腳本使用的路徑:
PATH=/sbin:/bin:/usr/sbin:/usr/bin

# 設定環境變量
OUT_INTERFACE=ppp0 # 外部網接口
IN_INTERFACE=eth0 # 內部網接口
INETADDR="`ifconfig ppp0|grep 'inet addr'|awk '{print $2}'|sed 's/.*://'`"
# 互聯網地址
LOCALADDR=192.168.1.1 # 內部網關
CLIENT_ONE=192.168.1.2 # 內部網另一台計算機
LOCALNET=192.168.1.0/255.255.255.0 # 內部網
DNSADDR=202.96.128.68 # 互聯網域名服務器地址

# 加載模塊:
modprobe ip_masq_ftp
modprobe ip_masq_raudio
modprobe ip_masq_irc
modprobe ip_masq_portfw

# 激活 IP 轉發:
echo 1 >/proc/sys/net/ipv4/ip_forward

# 對使用動態 IP 地址的人,比如撥號上網:
echo 1 >/proc/sys/net/ipv4/ip_dynaddr

# 對 ipchains 規則進行初始化:
ipchains -F
ipchains -I input 1 -j DENY # 堵住輸入鏈
ipchains -I output 1 -j DENY # 堵住輸出鏈
ipchains -I forward 1 -j DENY # 堵住轉發鏈

# 允許 lo 界面:
ipchains -A input -i lo -s 0/0 -d 0/0 -j ACCEPT
ipchains -A output -i lo -s 0/0 -d 0/0 -j ACCEPT

# 默認規則是「攔截」:
ipchains -P input DENY
ipchains -P output DENY
ipchains -P forward DENY

# 設置 ipchains 的 IP 偽裝超時,單位是秒:
ipchains -M -S 3600 10 120 # TCP 連接超時 1 小時,TCP FIN 超時 10 秒,
# UDP 超時 120 秒 )

# 設置反 IP 欺騙 (anti-spoofing)
for LOOP in /proc/sys/net/ipv4/conf/*/rp_filter
do echo 1>$LOOP
done
ipchains -A input -i ! lo -s 127.0.0.0/8 -j DENY -l
ipchains -A input -i $OUT_INTERFACE -s $LOCALNET -d 0/0 -j DENY -l
ipchains -A output -i $OUT_INTERFACE -s 0/0 -d $LOCALNET -j DENY -l
ipchains -A output -i $OUT_INTERFACE -s $LOCALNET -d 0/0 -j DENY -l

# 禁止從 Internet 向內部網和防火牆的請求
ipchains -A input -i $OUT_INTERFACE -p tcp -d $LOCALNET 0:1023 -j DENY -l
ipchains -A input -i $OUT_INTERFACE -p tcp -y -d $INETADDR 0:1023 -j DENY -l

# ICMP 用戶鏈
ipchains -N c_icmp
# 規則
ipchains -A c_icmp -p icmp --icmp-type destination-unreachable -j ACCEPT
# 允許分段和目的不可達
ipchains -A c_icmp -p icmp --icmp-type parameter-problem -j ACCEPT
ipchains -A c_icmp -p icmp --icmp-type source-quench -j ACCEPT
ipchains -A c_icmp -p icmp --icmp-type time-exceeded -j ACCEPT
# 允許接收 ICMP 錯誤信息
ipchains -A c_icmp -p icmp --icmp-type router-advertisement -j ACCEPT
ipchains -A c_icmp -p icmp --icmp-type router-solicitation -j ACCEPT
# 允許路由器 ping
# 允許 ICMP ping 出,但不允許 ping 入
ipchains -A input -p icmp --icmp-type echo-request -i $OUT_INTERFACE -s 0/0 -d $INETADDR -j DENY -l
ipchains -A input -p icmp --icmp-type echo-request -i $IN_INTERFACE -s $LOCALNET -d 0/0 -j ACCEPT
ipchains -A output -p icmp --icmp-type echo-request -i $OUT_INTERFACE -s $INETADDR -d 0/0 -j ACCEPT
ipchains -A input -p icmp --icmp-type echo-reply -i $OUT_INTERFACE -s 0/0 -d $INETADDR -j ACCEPT
ipchains -A output -p icmp --icmp-type echo-reply -i $IN_INTERFACE -s 0/0 -d $LOCALNET -j ACCEPT
# 其它類型的 ICMP 請求和回應
ipchains -A input -p icmp -s 0/0 -d $INETADDR -j c_icmp
ipchains -A output -p icmp -s ! $LOCALNET -j c_icmp
# ICMP 規則結束

# 偽裝規則
ipchains -A forward -i $OUT_INTERFACE -s $LOCALNET -d 0/0 -j MASQ
# 偽裝規則結束

# DNS 規則:注意 DNS 同時需要使用 TCP 和 UDP 協議
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d $DNSADDR domain -j ACCEPT
ipchains -A input -i $IN_INTERFACE -p udp -s $LOCALNET 1024:65535 -d $DNSADDR domain -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d $DNSADDR domain -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p udp -s $INETADDR 1024:65535 -d $DNSADDR domain -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s $DNSADDR domain -d $INETADDR 1024:65535 -j ACCEPT ! -y
ipchains -A input -i $OUT_INTERFACE -p udp -s $DNSADDR domain -d $INETADDR 1024:65535 -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p tcp -s $DNSADDR domain -d $LOCALNET 1024:65535 -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p udp -s $DNSADDR domain -d $LOCALNET 1024:65535 -j ACCEPT
# DNS 規則結束

# FTP 規則:FTP 需要 20 和 21 端口,要允許服務器從 20 端口發來的請求,否則就
# 不能用 ls、put、get ...
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d 0/0 ftp -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d 0/0 ftp -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s 0/0 ftp -d $INETADDR 1024:65535 -j ACCEPT ! -y
ipchains -A output -i $IN_INTERFACE -p tcp -s 0/0 ftp -d $LOCALNET 1024:65535 -j ACCEPT
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d 0/0 ftp-data -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d 0/0 ftp-data -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s 0/0 ftp-data -d $INETADDR 1024:65535 -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p tcp -s 0/0 ftp-data -d $LOCALNET 1024:65535 -j ACCEPT
# FTP 規則結束

# POP-3 收信規則:也要同時用到 TCP 和 UDP 協議
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d 0/0 pop-3 -j ACCEPT
ipchains -A input -i $IN_INTERFACE -p udp -s $LOCALNET 1024:65535 -d 0/0 pop-3 -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d 0/0 pop-3 -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p udp -s $INETADDR 1024:65535 -d 0/0 pop-3 -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s 0/0 pop-3 -d $INETADDR 1024:65535 -j ACCEPT ! -y
ipchains -A input -i $OUT_INTERFACE -p udp -s 0/0 pop-3 -d $INETADDR 1024:65535 -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p tcp -s 0/0 pop-3 -d $LOCALNET 1024:65535 -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p udp -s 0/0 pop-3 -d $LOCALNET 1024:65535 -j ACCEPT
# POP-3 規則結束

# SMTP 發信規則
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d 0/0 smtp -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d 0/0 smtp -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s 0/0 smtp -d $INETADDR 1024:65535 -j ACCEPT ! -y
ipchains -A output -i $IN_INTERFACE -p tcp -s 0/0 smtp -d $LOCALNET 1024:65535 -j ACCEPT
# SMPT 規則結束

# 允許 WEB 瀏覽
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d 0/0 www -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d 0/0 www -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s 0/0 www -d $INETADDR 1024:65535 -j ACCEPT ! -y
ipchains -A output -i $IN_INTERFACE -p tcp -s 0/0 www -d $LOCALNET 1024:65535 -j ACCEPT
# WEB 瀏覽規則結束

# OICQ 規則:大麻煩!:(
#
## 使用端口轉發打開防火牆的 4000 端口,這對於註冊新號有用
ipmasqadm portfw -a -P udp -L $INETADDR 4000 -R $CLIENT_ONE 4000

## 允許 oicq 請求出站
ipchains -A input -i $IN_INTERFACE -p udp -s $LOCALNET 4000:4000 -d 0/0 1024:65535 -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p udp -s $INETADDR 1024:65535 -d 0/0 1024:65535 -j ACCEPT

## 允許對 oicq 的回應
ipchains -A input -i $OUT_INTERFACE -p udp -s 0/0 1024:65535 -d $INETADDR 1024:65535 -j ACCEPT
####這裡打開了防火牆上從 1024 到 65535 的所有端口,不安全,但也沒辦法!
ipchains -A output -i $IN_INTERFACE -p udp -s 0/0 1024:65535 -d $LOCALNET 4000:4000 -j ACCEPT
#
# oicq 規則結束

# 允許使用 BBS/telnet
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET 1024:65535 -d 0/0 telnet -j ACCEPT
ipchains -A output -i $OUT_INTERFACE -p tcp -s $INETADDR 1024:65535 -d 0/0 telnet -j ACCEPT
ipchains -A input -i $OUT_INTERFACE -p tcp -s 0/0 telnet -d $INETADDR 1024:65535 -j ACCEPT ! -y
ipchains -A output -i $IN_INTERFACE -p tcp -s 0/0 telnet -d $LOCALNET 1024:65535 -j ACCEPT
# BBS/telnet 規則結束

# 允許本地服務
ipchains -A input -i $IN_INTERFACE -p tcp -s $LOCALNET -d $LOCALNET -j ACCEPT
ipchains -A input -i $IN_INTERFACE -p udp -s $LOCALNET -d $LOCALNET -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p tcp -s $LOCALNET -d $LOCALNET -j ACCEPT
ipchains -A output -i $IN_INTERFACE -p udp -s $LOCALNET -d $LOCALNET -j ACCEPT
# 本地服務規則結束

# 「一網打盡」規則
ipchains -A input -l -j DENY
ipchains -A output -l -j DENY
ipchains -A forward -l -j DENY
# 規則結束

# 去掉 ipchains 初始化時的「堵塞規則」
ipchains -D input 1
ipchains -D output 1
ipchains -D forward 1
# 完成了!

現在寫防火牆啟動/終止腳本:

#!/bin/sh
# 文件名:/root/bin/firewall
PATH=/sbin:/bin:/usr/sbin:/usr/bin
RULES=/root/firewall/fwrules

if [ $# -eq 0 -o $# -gt 1 ] ; then
echo "Usage: $0 {start|close|open|save}"
exit 1
fi

case $1 in
start)
if [ ! -f /var/run/ppp0.pid ] ; then
echo "You have not ppp0 interface, can not start"
echo "IPCHAINS firewall!"
exit 1
fi
if [ -f $RULES ] ; then
sh $RULES
echo "Firewall is up"
else
echo "Firewall rules dose NOT exist, can not start."
exit 1
fi
;;
close)
ipmasqadm portfw -f
ipchains -F
ipchains -P input DENY
ipchains -P output DENY
ipchains -P forward DENY
ipchains -X c_icmp
echo 0 >/proc/sys/net/ipv4/ip_forward
echo 0 >/proc/sys/net/ipv4/ip_dynaddr
rmmod ip_masq_ftp
rmmod ip_masq_raudio
rmmod ip_masq_irc
rmmod ip_masq_portfw
echo "Fierwall is closed"
;;
open)
if [ -f /var/run/ppp0.pid ] ; then
echo "You have ppp0 working, daingours!"
echo "Firewall can NOT open!"
exit 1
fi
ipchains -P input ACCEPT
ipchains -P output ACCEPT
ipchains -P forward ACCEPT
echo "Firewall open"
;;
save)
ipchains-save > /root/firewall/cmprules
chmod go-r /root/firewall/cmprules
echo "Rules saved"
;;
*)
echo "Usage: $0 {start|clear|save}"
;;
esac
exit 0
# 完了!

在內部網的另一台計算機如何設置,請自己參照 IP-Masquerading-
HOWTO


撥號上網,啟動防火牆:
root@localhost:~# /root/bin/firewall start
Firewall is up

好了。如果想改規則,先將防火牆關閉:
root@localhost:~# /root/bin/firewall close
Firewall is closed

看看:
root@localhost:~# ipchains -L
Chain input (policy DENY):
Chain forward (policy DENY):
Chain output (policy DENY):

改完了,再重新啟動:
root@localhost:~# /root/bin/firewall start
Firewall is up


防火牆配置的一些體會:

這只是一個簡單的防火牆/透明代理,只不過「防守」嚴密了一些而已。配置防火牆,規則
的順序很重要。規則要反覆琢磨。

對於攔截、拒絕的包,盡量把它們記帳。對於系統日誌,要勤於查看。

如果在防火牆後面的是 Win9X/NT 的機器,每過一段時間就會發 ping ( 端口 3 ) 和 DNS
請求包 ( 端口 137 ),這些會記錄在系統日誌裡,多了就挺煩的。你可以在「一網打盡」
前加上兩條沒有記帳的攔截規則:

ipchains -A input -i $IN_INTERFACE -p icmp -s $LOCALNET -d 0/0 3:3 -j DENY
ipchains -A input -i $IN_INTERFACE -p udp -s $LOCALNET 137:137 -d $DNSADDR domain -j DENY

配置 oicq 規則是大麻煩,嚴了,你和別人的通信都通過服務器轉發,速度慢;鬆了,你
的系統的安全性又會降低。而且,如果是註冊新號,就一定要使用端口轉發:

ipmasqadm portfw -a -P udp -L $INETADDR 4000 -R $CLIENT_ONE 4000

理由很簡單,其實 ipchains 的 IP 偽裝不僅改變了源 IP 地址,而且改變了源端口,你
從 oicq 的 4000 端口發出的請求到防火牆轉發出去時,已經是另一個端口了 ( 通常是
61000 以後的端口 ),再當 oicq 服務器回應時,目的端口也就成了防火牆所發的端口,
這樣從輸入鏈到輸出鏈之間就可能斷開,這樣就無法完成新號的註冊過程。用 ipmasqadm
相當於從外到內架了一座橋,讓 oicq 服務器「以為」防火牆就是需要註冊認證的機器,
因為它的 4000 端口是打開的。這點是我看了 IP-Masquerading-HOWTO 中有關 ICQ 的設
置後才想到的。

由於規則設置比較嚴,如果防火牆後面的機器要使用如:WinAmp、realplay、ncftp、cterm
等軟件,就可能出現「服務器超時」,原因是包被攔截了。查看一下系統日誌,打開相應
的端口就行了。

* 最後說明一點,ipchains 的 IP 偽裝功能不能轉發已經對 IP 地址和端口加密了的
TCP/IP 網絡軟件之間的通訊。這種情況只能去用其它的代理服務器了。


** 參考文獻 **
IP-Masquerading-HOWTO, David Ranch, dranch@trinnet.net; Ambrose Au, ambrose@writeme.com
v1.81, January 2000
《Linux 系統安全使用手冊》,電子工業出版社,第十六章 「用 ipchains 過濾數據包」

一起在命令行跳舞吧……



Copyright © 1999-2000 LSLNET.COM. All rights reserved. 藍森林網站 版權所有。 E-mail : webmaster@lslnet.com