Linux 架設簡單的防火牆 來源:石頭閒語

參考文件:


情境

某位仁兄跟其他人分租了一條 Hinet 的 ADSL 的線路,他得到一個 IP 的使用權, 於是他想自已安裝一台 Linux 主機,安架設 mud 及其他服務,分享給其他人, 但同時,他本人又想使用 Windows 95/98 ,以便上網、玩遊戲、寫作業。

由於他只有一個 IP ,無法同時讓兩台電腦使用,不過他聽說 Linux 可以用很低階的機器,作防火牆,於是他跟別人以極便宜的價格, 頂了一台 Pentium 100 + 32 MB RAM 的機器,加上他升級換下的 1.7GB 硬碟, 拿了一片不知哪來的 Redhat 6.1 + CLE 光碟,請我幫他搞定。

我聽了他的需求,又要他再買一些配備後,就開始幫他搞定這個問題。 總計有下列需求:

原先使用 Redhat 6.1 + CLE 安裝的,但似乎光碟片有問題,安裝到一半都會失敗, 於是我改用我自已的 Slackware 7.0 安裝。

硬體環境

基本上,要安裝 Linux 的主機是一台 Pentium 100 的機器,外接一個單色顯示器, 內有 32MB RAM,一顆 1.7GB 硬碟,安裝兩張 NE2000 相容的 PCI 網路卡,一條一般網路線接在 Linux 主機與 ADSL Hub 間, 另一條跳接過的網路線接在 Linux 主機與 Win95 主機間。

在安裝過程中,另外裝上了一台可光碟開機的光碟機、一個鍵盤,安裝完後,就拿掉了。

軟體環境

我安裝 Slackware 7.0 ,分了 128MB 做 swap ,另外再分出 500MB 給 / , 剩下的全給了 /var ,將 /home 連結到 /var/home 。

安裝時,安裝了 A, AP, D, N 系列的軟體,因為只安裝了必要的, 故只使用了 200MB 左右。 安裝後,只使用其內建的 kernel ,不另外編譯。

安裝後,修改 /etc/rc.d/rc.netdevice 的內容,加上載入 NE2000 PCI 網路卡驅動程式的指令。

/sbin/modprobe ne2k-pci

我另外下載並安裝 Apache 1.3.12 ,以一般值編譯,並另外編譯了 Proxy module 。

設定網路卡

決定網路位址

在設定網路卡前,先決定網路位址的部份,有一個 Hinet ADSL 的 IP 設定,如下(假設值):

IPADDR="192.100.252.186"
NETMASK="255.255.255.248"
NETWORK="192.100.252.0"
BROADCAST="192.100.252.255"
GATEWAY="192.100.252.185"

而 192.168.1.0 是保留給私設(內部)網路使用的 class C 網路位址,通常 .1 是供 gateway/firewall 主機使用,其他內部網路的主機, 則使用 .2 到 .254 之間的 IP 。

IPADDR="192.168.1.1"
NETMASK="255.255.255.0"
NETWORK="192.168.1.0"
BROADCAST="192.168.1.255"
GATEWAY=""

以 eth0 (第一張網路卡) 連接網際網路,故配上 Hinet ADSL 的網路設定; 而 eth1 (第二張網路卡) 連接內部網路。

設定網路卡

Slackware 內附的 netconfig 指令,只能設定 eth0 ,不過對於使用 slackware 的人來說,手動設定應該不是什麼大問題。

先用 netconfig 設定 eth0 的內容, DNS 的部份設為 168.95.1.1 ,或自行編輯 /etc/resolve.conf 的內容, 加入 168.95.1.1 及 168.95.192.1 兩台 Hinet 的 DNS 。

為了配合 netconfig ,依然將 eth0 的設定部份保留在 /etc/rc.d/rc.inet1 中, 但另外寫了一個 /etc/rc.d/rc.eth1 以設定 eth1 的內容。 安裝 slackware 的慣例,我將自定的指令放在 /etc/rc.d/rc.local 中執行。

rc.eth1:
=============================
#!/bin/sh

IPADDR="192.168.1.1"
NETMASK="255.255.255.0"
NETWORK="192.168.1.0"
BROADCAST="192.168.1.255"
GATEWAY=""

echo "Configuring eth1 as ${IPADDR}..."
/sbin/ifconfig eth1 ${IPADDR} broadcast ${BROADCAST} netmask ${NETMASK}
=============================

rc.local:
==========================
  .
  .
if [ -x /etc/rc.d/rc.eth1 ]; then
    /etc/rc.d/rc.eth1
fi
==========================

設定其他內部網路的主機

以 Windows 95 為例, IP 位址: 192.168.1.2 (2 到 254), 子網路遮罩(Netmask): 255.255.255.0 ,通訊閘(Gateway): 192.168.1.1, DNS (名稱伺服器)的部份,設為 Hinet 的: 168.95.1.1 及 168.95.192.1 。

設定防火牆

Slackware 內定安裝的 kernel ,允許 IP forwarding/filter ,及 IP masquerade 。

我只使用 Linux 本身的防火牆功能,不打算使用 SOCKS 或 TIS ,不然怎麼簡單起來。

啟動 IP Forwarding

在 Kernel 2.0.34 以後的版本,預設是關閉 IP Forwarding (轉送)的,須以下列指令啟動:

echo "1" > /proc/sys/net/ipv4/ip_forward

Slackware 將這段指令,設定在 /etc/rc.d/rc.inet2 中,將變數 IPV4_FORWARD 設為 1 即可。

設定 IP chains

有一套 IP forwarding 設定的管理工具, slackware 沒有提供,即 ipchains ,我安裝了 RedHat 6.1 所提供的 ipchains-1.3.9-3.i386.rpm 。 關於 IP chains 最簡單的設定方式如下:

ipchains -P forward DENY
ipchains -A forward -s yyy.yyy.yyy.yyy/x -j MASQ

yyy.yyy.yyy.yyy 是網路位址, x 視子網路而定,其值如下:

netmask         | x  | subnet
----------------+----+----------------
255.0.0.0       | 8  | Class A
255.255.0.0     | 16 | Class B
255.255.255.0   | 24 | Class C
255.255.255.255 | 32 | Point-to-Point

x 的部份,也可以設為 netmask 。

允許內部網路的所有機器透過 Gateway/Firewall 主機連到網際網路的設法如下:

ipchains -P forward DENY
ipchains -A forward -s 192.168.1.0/24 -j MASQ

如果只允許內部網路的少數機器可連到網際網路,假設只允許 192.168.1.2 這台出去,則設法如下:

ipchains -P forward DENY
ipchains -A forward -s 192.168.1.2/32 -j MASQ

我將這些指令寫在 /etc/rc.d/rc.ipfw 中,並在 rc.local 中啟動。

rc.ipfw
==================================
#!/bin/sh

NETWORK="192.168.1.0"
NETMASK="255.255.255.0"

# Enable IP forwarding
/sbin/ipchains -P forward DENY
/sbin/ipchains -A forward -s ${NETWORK}/${NETMASK} -j MASQ
==================================

到目前為止,其他內部網路主機已經可以連結到網際網路了,可用 ping 測試。

設定IP偽裝

由於部份網路協定的特色限制,如 ftp, irc, real audio 等,內部網路主機不能依靠單純的 IP forwarding 去連結網際網路上提供那些服務的主機, 必須再啟動 IP masqerade (IP偽裝)的功能。

Slackware 已提供了 IP masqerade 所需的模組,我們只需載入即可,可查看 /lib/modules/2.2.x/ipv4 的內容,看看有那些模組可用。 一般說來,需要載入 ip_masq_portfw ,建議載入 ip_masq_autofw, ip_masq_ftp, 及 ip_masq_raudio 。

我將載入的動作,寫在 /etc/rc.d/rc.ipmasq 中,同樣地以 rc.local 啟動。

rc.ipmasq:
===========================
#!/bin/sh

# Required
/sbin/modprobe ip_masq_portfw

# Recommend
/sbin/modprobe ip_masq_autofw
/sbin/modprobe ip_masq_ftp
/sbin/modprobe ip_masq_raudio
============================

中場休息

我修改或需要變動的檔案有:

rc.local 如下:
================================
  .
  .
  .
if [ -x /etc/rc.d/rc.eth1 ]; then
    /etc/rc.d/rc.eth1
fi

if [ -x /etc/rc.d/rc.ipfw ]; then
    /etc/rc.d/rc.ipfw
fi

if [ -x /etc/rc.d/rc.ipmasq ]; then
    /etc/rc.d/rc.ipmasq
fi
================================

HTTP proxy

由於我打算讓連結內外部網路的主機,兼具 http proxy 的功能,由它去向外部網路的 proxy 索取資料, 而內部網路的主機就不需要自行連到外部網路的 proxy 去,如此一來,可以減輕網路傳輸上的負擔。

雖然一般都是使用 squid 做為 proxy server 的軟體,但我認為它對我的情形而言,太複雜了,所以我改用 Apache 的 proxy 功能。

Apache 的 proxy 功能,通常不會編入 httpd 中,需要以 module 載入。 執行 httpd -l 可以查看那些功能被編入 httpd 中了。

假設已經有 apache 的 proxy module 了,使用 apxs 加上載入動作。 進入 apache 放置 proxy module 的目錄,如: $APACHE_SRC/src/modules/proxy ,執行:

apxs -i -a mod_proxy.c

接著設定 httpd.conf 中,關於 Proxy 的部份。 找到 httpd.conf 中最下面的部份,會有關於 proxy 功能的部份,不過都被 mark 了,消掉應該消掉的 mark ,開始設定:

ProxyRequests On
ProxyRemote * http://proxy.hinet.net:80
# 以 proxy.hinet.net 做為上游 proxy 。
NoProxy 192.168.1.0
# 不對自身做 proxy ,否則會使 Apache 原有的 web 功能發生錯誤。

<Directory proxy:80>
    Order allow,deny
    Allow from all
</Directory>

ProxyVia On

CacheRoot "/var/proxy"
CacheSize 300
# 設定 300MB 的快取空間。
CacheGcInterval 4
CacheMaxExpire 24
CacheLastModifiedFactor 0.1
CacheDefaultExpire 1
NoCache 192.168.1.0

除了 ProxyRemote 及 NoProxy 外,其他按預設值設定即可,重新啟動 apache 使之生效。

內部主機的瀏覽器設定 proxy 為: 192.168.1.1:80

小恐龍工作坊 提供