最近我在我的 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 過濾數據包」
一起在命令行上跳舞吧……
|