3286 lines
130 KiB
XML
3286 lines
130 KiB
XML
<?xml version="1.0" encoding="big5"?>
|
||
<!--
|
||
The FreeBSD Documentation Project
|
||
|
||
$FreeBSD$
|
||
Original revision: 1.66
|
||
-->
|
||
|
||
<chapter id="firewalls">
|
||
<chapterinfo>
|
||
<authorgroup>
|
||
<author>
|
||
<firstname>Joseph J.</firstname>
|
||
<surname>Barbish</surname>
|
||
<contrib>Contributed by </contrib>
|
||
</author>
|
||
</authorgroup>
|
||
<authorgroup>
|
||
<author>
|
||
<firstname>Brad</firstname>
|
||
<surname>Davis</surname>
|
||
<contrib>Converted to SGML and updated by </contrib>
|
||
</author>
|
||
</authorgroup>
|
||
</chapterinfo>
|
||
|
||
<title>防火牆</title>
|
||
|
||
<indexterm><primary>防火牆</primary></indexterm>
|
||
|
||
<indexterm>
|
||
<primary>安全</primary>
|
||
|
||
<secondary>防火牆</secondary>
|
||
</indexterm>
|
||
|
||
<sect1 id="firewalls-intro">
|
||
<title>概述</title>
|
||
|
||
<para>防火牆能夠過濾你的系統中進出的流量。
|
||
防火牆也能藉由設置一或多組「規則(rules)」
|
||
來檢查你的網路連結中進出的網路封包(network packets),
|
||
並且能允許或阻擋其通過。
|
||
這些防火牆的規則可以檢查封包中的特徵,
|
||
這些特徵涵蓋,但不限於某些通訊協定類型、主機位址的來源或目的,
|
||
以及連接埠(port)的來源及目的。</para>
|
||
|
||
<para>防火牆能夠大幅地增強主機或是網路的安全性。
|
||
它也能夠用來執行下列事項:</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>保護或隔離你內部網路的應用程式、服務以及機器,
|
||
免於被來自 Internet 中你不想要的傳輸所影響</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>限制或禁止內部網路對 Internet 的存取服務</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>支援「網路位址轉換」(network address translation
|
||
, <acronym>NAT</acronym>),它可以允許你的內部網路使用 private
|
||
<acronym>IP</acronym> 位址並可以共同分享一個單一連線到網際網路上
|
||
(可同時用單一<acronym>IP</acronym>位址或是一組公共網址)</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>讀完這章之後,你將會知道:</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>如何適當地訂出封包過濾的規則。</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>&os; 中內建的防火牆之間的差異。</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>如何使用及設定 OpenBSD 的
|
||
<application>PF</application> 防火牆。</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>如何使用及設定
|
||
<application>IPFILTER</application>。</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>如何使用及設定
|
||
<application>IPFW</application>。</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>在閱讀這章之前,你必須:</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>了解基本的 &os; 和 Internet 觀念</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</sect1>
|
||
|
||
<sect1 id="firewalls-concepts">
|
||
<title>淺談防火牆概念</title>
|
||
|
||
<indexterm>
|
||
<primary>防火牆</primary>
|
||
|
||
<secondary>規則</secondary>
|
||
</indexterm>
|
||
|
||
<para>基本上防火牆規則可分為兩種型態,分別為:「exclusive」以及
|
||
「inclusive」。
|
||
<!-- inclusive/exclusive 參考 Mattlinuxer 的意見
|
||
因為 exclusive 防火牆是先容許所有封包通過,再透過規則阻擋
|
||
不想讓其通過的封包。而 inclusive 則是檔掉所有,後來再容許
|
||
符合規則的封包通過。
|
||
-->
|
||
「exclusive」類似「黑名單」,它先允許所有封包通過,
|
||
然後違反規則的封包則禁止通過防火牆。
|
||
相反的,「inclusive」類似「白名單」,它先擋住所有封包通過,
|
||
然後只允許有符合規則的才可通過防火牆。</para>
|
||
|
||
<para>整體來說,「inclusive」式防火牆會比「exclusive」式防火牆安全些。
|
||
因為「inclusive」明顯降低了不必要的風險。</para>
|
||
|
||
<para>此外,使用「stateful firewall」可讓安全性更嚴密。
|
||
它會持續記錄通過防火牆開放的連線,
|
||
並且只允許符合現存或開啟新的連線才能通過防火牆。
|
||
狀態防火牆的缺點是如果在非常快的速度下開啟許多新連線,
|
||
就可能會受到阻絕式服務攻擊(<acronym>DoS</acronym>, Denial of Service)。
|
||
在大多數的防火牆方案中,也可以交叉運用「stateful 」及「non-stateful」
|
||
防火牆的組合,讓該網站的防火牆達到最佳化。</para>
|
||
</sect1>
|
||
|
||
<sect1 id="firewalls-apps">
|
||
<title>防火牆相關軟體</title>
|
||
|
||
|
||
<para>在 &os; 基本系統中內建有三種不同的防火牆軟體套件。
|
||
它們分別是 <emphasis>IPFILTER</emphasis>
|
||
(也就是 <acronym>IPF</acronym>)、
|
||
<emphasis>IPFIREWALL</emphasis> (也就是 <acronym>IPFW</acronym>),
|
||
以及<emphasis> OpenBSD 的 PacketFilter</emphasis> (即有名的
|
||
<acronym>PF</acronym>)。
|
||
&os; 也有兩個內建的流量控管套件(基本上是控制頻寬的使用):
|
||
&man.altq.4; 以及 &man.dummynet.4;。
|
||
通常我們習慣把 Dummynet 與 <acronym>IPFW</acronym> 一併運用,
|
||
而 <acronym>ALTQ</acronym> 則是搭配
|
||
<acronym>IPF</acronym>/<acronym>PF</acronym> 一同使用。
|
||
雖然 IPF、IPFW 以及 PF 是使用不同的實做方式及規則語法,
|
||
但是它們都使用規則來控制是否允許資料封包進出你的系統。</para>
|
||
|
||
<para>&os; 為何會內建許多不同的防火牆軟體套件,這是因為不同人會有不同的需求
|
||
、偏好,很難說哪一個防火牆軟體套件是最好的。</para>
|
||
|
||
<para>而筆者偏好 IPFILTER 的原因,是因為運用在 <acronym>NAT</acronym>
|
||
環境的時候,它的狀態規則是相對簡單許多的。
|
||
而且它內建的 FTP 代理,也簡化了如何設定安全的對外 FTP 服務規則。</para>
|
||
|
||
<!-- psilotum: 20060309: 這段實在翻的有點怪,參考 zh_CN 翻譯 -->
|
||
<para>正由於所有的防火牆都是以「檢查、控制所選定之封包」的實作,所以,
|
||
制定防火牆規則的人就更必須了解 <acronym>TCP</acronym>/IP 如何運作,
|
||
以及如何控制封包在正常 session 的各種作用。
|
||
更詳盡的說明,請參閱:
|
||
<ulink url="http://www.ipprimer.com/overview.cfm"></ulink>。</para>
|
||
|
||
</sect1>
|
||
|
||
<sect1 id="firewalls-pf">
|
||
<title>OpenBSD 封包過濾器 (Packet Filter, PF)及
|
||
<acronym>ALTQ</acronym></title>
|
||
|
||
<indexterm>
|
||
<primary>防火牆</primary>
|
||
|
||
<secondary>PF</secondary>
|
||
</indexterm>
|
||
|
||
<para>在 2003 年 6 月份,OpenBSD 的防火牆軟體 <acronym>PF</acronym>
|
||
被移植到 &os; 中,並且收錄於 Ports Collection 內。
|
||
而 2004 年 11 月份所發行的 &os; 5.3 版也是第一次將
|
||
<acronym>PF</acronym> 整合為基礎系統的一部分。
|
||
<acronym>PF</acronym>是個完備、全功能的防火牆,
|
||
並且具有選擇性 <acronym>ALTQ</acronym>(交錯佇列,Alternate Queuing)
|
||
<!--psilotum: 20060309 alternative queuing 參考 zh_CN 的翻譯 -->
|
||
的功能。
|
||
<acronym>ALTQ</acronym>提供了「<acronym>QoS</acronym>」
|
||
(Quality of Service)頻寬管制功能,
|
||
它可以用過濾規則的方式來保障各種不同服務的頻寬。
|
||
另外,OpenBSD 計劃中已經對 PF 的使用指南提供了詳盡的解說,
|
||
因此在這本手冊中我們不會作重複的贅述,而只介紹概要。</para>
|
||
<!--20060309 psilotum:怎麼翻譯都覺得有點怪,所以最後一句重寫-->
|
||
|
||
<para>更多關於 PF 的資訊可於下列網址查詢:<ulink
|
||
url="http://pf4freebsd.love2party.net/"></ulink>.</para>
|
||
|
||
<sect2>
|
||
<title>啟用 PF</title>
|
||
|
||
<para>PF 在 &os; 5.3 之後的系統中,就可以輕鬆使用 kernel 動態模組來載入。
|
||
在 rc.conf 中加入 <literal>pf_enable="YES"</literal> 後,
|
||
系統就會載入 PF 的 kernel 動態模組。這模組會在建立時也啟用 &man.pflog.4;
|
||
記錄功能。</para>
|
||
|
||
<note>
|
||
<para>這個模組會假設 kernel 內已有 <literal>options INET</literal> 和
|
||
<literal>device bpf</literal>。
|
||
除非編譯 kernel 時已在像是 &man.make.conf.5; 設定檔中加入
|
||
<literal>NOINET6</literal>(
|
||
&os; 6.0 以後的版本則是 <literal>NO_INET6</literal>)
|
||
這樣才會避免不打開 IPv6 支援,
|
||
否則 pf 模組同時也需要 <literal>options INET6</literal>,也就是 IPv6
|
||
支援。</para>
|
||
</note>
|
||
|
||
<para>一旦載入 PF 的 kernel 模組或是靜態編譯入 kernel 內,
|
||
就可以使用 <command>pfctl</command> 來啟動或關閉
|
||
<application>pf</application>。</para>
|
||
|
||
<para>下面這個例子示範如何啟動 <application>pf</application>:</para>
|
||
|
||
<screen>&prompt.root; <userinput>pfctl -e</userinput></screen>
|
||
|
||
<para><command>pfctl</command> 是使用 <application>pf</application>
|
||
防火牆的指令。 若要了解更詳盡的 <command>pfctl</command> 運用,請查閱
|
||
&man.pfctl.8; 線上手冊。</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>kernel 選項</title>
|
||
|
||
<indexterm>
|
||
<primary>kernel 選項</primary>
|
||
|
||
<secondary>device pf</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>kernel 選項</primary>
|
||
|
||
<secondary>device pflog</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>kernel 選項</primary>
|
||
|
||
<secondary>device pfsync</secondary>
|
||
</indexterm>
|
||
|
||
<para>在編譯 &os; kernel 時,並不必完全加入下列的選項來啟用 PF。
|
||
在這裡只是要列出給你參考的一些資訊而已。
|
||
將 PF 編譯入 kernel 中,會導致無法使用 kernel 的動態載入模組。</para>
|
||
|
||
<para>設定 PF 的 kernel 選項範例在 kernel 原始碼中的
|
||
<filename>/usr/src/sys/conf/NOTES</filename>,轉貼內容如下:</para>
|
||
|
||
<programlisting>device pf
|
||
device pflog
|
||
device pfsync</programlisting>
|
||
|
||
<para><literal>device pf</literal> 是用來啟動「packet filter(封包過濾)」
|
||
的防火牆支援。</para>
|
||
|
||
<para>而 <literal>device pflog</literal>,此功能要裝不裝皆可,它會啟動
|
||
&man.pflog.4;,以 &man.bpf.4; 格式來記錄網路流量。
|
||
&man.pflogd.8; daemon 則是用來紀錄這些訊息,並存在硬碟上。</para>
|
||
<!-- psilotum:20060311 參考 zh_CN 翻譯 -->
|
||
|
||
<para><literal>device pfsync</literal>,此功能要裝不裝皆可,它會啟動
|
||
&man.pfsync.4;,可以用來監控「狀態的改變」。 請注意:
|
||
<literal>device pfsync</literal>並不是 kernel 動態模組,要使用的話,
|
||
必須要編入自訂的 kernel 中才行。</para>
|
||
|
||
<para>這些設定將會在你編譯及安裝好新 kernel 後才會生效。</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>rc.conf 其他相關的選項</title>
|
||
|
||
<para>你需要在 <filename>/etc/rc.conf</filename>
|
||
中加入下列的設定,以便在系統啟動時啟用 PF:</para>
|
||
|
||
<programlisting>pf_enable="YES" # 啟用 PF (如果需要的話載入模組)
|
||
pf_rules="/etc/pf.conf" # PF 防火牆規則設定檔
|
||
pf_flags="" # pfctl 啟動時的附加選項
|
||
pflog_enable="YES" # 啟動 pflogd(8)
|
||
pflog_logfile="/var/log/pflog" # pflogd 儲存記錄檔案的地方
|
||
pflog_flags="" # pflogd 啟動時附加的選項</programlisting>
|
||
|
||
<para>如果您的防火牆後面有個 LAN(區域網路),並要透過它來轉送封包,
|
||
就必須要設定下列選項:</para>
|
||
|
||
<programlisting>gateway_enable="YES" # 啟用 LAN Gateway</programlisting>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>啟用 <acronym>ALTQ</acronym></title>
|
||
|
||
<para><acronym>ALTQ</acronym> 只有在編入 &os; kernel 中才能生效。
|
||
不是所有的網路卡驅動程式都支援 <acronym>ALTQ</acronym>。
|
||
請看 &man.altq.4; 線上手冊來了解你使用的 &os; 版本中支援驅動程式的清單。
|
||
下面所列的將會啟用 <acronym>ALTQ</acronym> 及其他附加功能:</para>
|
||
|
||
<programlisting>options ALTQ
|
||
options ALTQ_CBQ # Class Bases Queuing (CBQ)
|
||
options ALTQ_RED # Random Early Detection (RED)
|
||
options ALTQ_RIO # RED In/Out
|
||
options ALTQ_HFSC # Hierarchical Packet Scheduler (HFSC)
|
||
options ALTQ_PRIQ # Priority Queuing (PRIQ)
|
||
options ALTQ_NOPCC # Required for SMP build</programlisting>
|
||
|
||
<para><literal>options ALTQ</literal> 是啟用 <acronym>ALTQ</acronym> 主架構。</para>
|
||
|
||
<para><literal>options ALTQ_CBQ</literal> 會啟用「<acronym>CBQ</acronym>」
|
||
(Class Based Queuing)支援。
|
||
<acronym>CBQ</acronym> 允許你
|
||
divide a connection's bandwidth into different
|
||
classes or queues to prioritize traffic based on filter
|
||
rules.</para>
|
||
|
||
<para><literal>options ALTQ_RED</literal> enables Random Early
|
||
Detection (<acronym>RED</acronym>). <acronym>RED</acronym> is
|
||
used to avoid network congestion. <acronym>RED</acronym> does
|
||
this by measuring the length of the queue and comparing it to
|
||
the minimum and maximum thresholds for the queue. If the
|
||
queue is over the maximum all new packets will be dropped.
|
||
True to its name, <acronym>RED</acronym> drops packets from
|
||
different connections randomly.</para>
|
||
|
||
<para><literal>options ALTQ_RIO</literal> enables Random Early
|
||
Detection In and Out.</para>
|
||
|
||
<para><literal>options ALTQ_HFSC</literal> enables the
|
||
Hierarchical Fair Service Curve Packet Scheduler. For more
|
||
information about <acronym>HFSC</acronym> see: <ulink
|
||
url="http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html"></ulink>.</para>
|
||
|
||
<para><literal>options ALTQ_PRIQ</literal> enables Priority
|
||
Queuing (<acronym>PRIQ</acronym>). <acronym>PRIQ</acronym>
|
||
will always pass traffic that is in a higher queue
|
||
first.</para>
|
||
|
||
<para><literal>options ALTQ_NOPCC</literal> enables
|
||
<acronym>SMP</acronym> support for <acronym>ALTQ</acronym>.
|
||
This option is required on <acronym>SMP</acronym>
|
||
systems.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Creating Filtering Rules</title>
|
||
|
||
<para>The Packet Filter reads its configuration rules from the
|
||
&man.pf.conf.5; file and it modifies, drops or passes packets
|
||
according to the rules or definitions specified there. The &os;
|
||
installation comes with a default
|
||
<filename>/etc/pf.conf</filename> which contains useful examples
|
||
and explanations.</para>
|
||
|
||
<para>Although &os; has its own <filename>/etc/pf.conf</filename>
|
||
the syntax is the same as one used in OpenBSD. A great
|
||
resource for configuring the <application>pf</application>
|
||
firewall has been written by OpenBSD team and is available at
|
||
<ulink url="http://www.openbsd.org/faq/pf/"></ulink>.</para>
|
||
|
||
<warning>
|
||
<para>When browsing the pf user's guide, please keep in mind that
|
||
different versions of &os; contain different versions of pf. The
|
||
<application>pf</application> firewall in &os; 5.X is at the level
|
||
of OpenBSD version 3.5 and in &os; 6.X is at the level of OpenBSD
|
||
version 3.7.</para>
|
||
</warning>
|
||
|
||
<para>The &a.pf; is a good place to ask questions about
|
||
configuring and running the <application>pf</application>
|
||
firewall. Do not forget to check the mailing list archives
|
||
before asking questions.</para>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 id="firewalls-ipf">
|
||
<title>IPFILTER (IPF) 防火牆</title>
|
||
|
||
<indexterm>
|
||
<primary>防火牆</primary>
|
||
|
||
<secondary>IPFILTER</secondary>
|
||
</indexterm>
|
||
|
||
<note>
|
||
<para>此一節的內容仍在陸續補充、更新,所以本節內容可能並未完全符合現況。</para>
|
||
</note>
|
||
|
||
<para>IPFILTER 的作者為 Darren Reed。IPFILTER 並非得綁某特定作業系統才行:
|
||
它是個跨 OS 平台的 open source 應用程式,且已被移植到
|
||
&os;、NetBSD、OpenBSD、&sunos;、HP/UX 以及
|
||
&solaris; 這些作業系統上。此外,IPFILTER 的支援、維護也相當積極,也有定期釋出的更新版。</para>
|
||
|
||
<para>IPFILTER is based on a kernel-side firewall and
|
||
<acronym>NAT</acronym> mechanism that can be controlled and
|
||
monitored by userland interface programs. The firewall rules can
|
||
be set or deleted with the &man.ipf.8; utility. The
|
||
<acronym>NAT</acronym> rules can be set or deleted with the
|
||
&man.ipnat.1; utility. The &man.ipfstat.8; utility can print
|
||
run-time statistics for the kernel parts of IPFILTER. The
|
||
&man.ipmon.8; program can log IPFILTER actions to the system log
|
||
files.</para>
|
||
|
||
<para>IPF was originally written using a rule processing logic of
|
||
「the last matching rule wins」 and used only
|
||
stateless type of rules. Over time IPF has been enhanced to
|
||
include a 「quick」 option and a stateful 「keep
|
||
state」 option which drastically modernized the rules
|
||
processing logic. IPF's official documentation covers the legacy
|
||
rule coding parameters and the legacy rule file processing
|
||
logic. The modernized functions are only included as additional
|
||
options, completely understating their benefits in producing a
|
||
far superior secure firewall.</para>
|
||
|
||
<para>The instructions contained in this section are based on
|
||
using rules that contain the 「quick」 option and the
|
||
stateful 「keep state」 option. This is the basic
|
||
framework for coding an inclusive firewall rule set.</para>
|
||
|
||
<!-- XXX: something like this already in
|
||
<xref linkend="firewalls-concepts"/>
|
||
AND: the para below is repeated 3 times in this chapter-->
|
||
|
||
<para>An inclusive firewall only allows packets matching the rules
|
||
to pass through. This way you can control what services can
|
||
originate behind the firewall destined for the public Internet
|
||
and also control the services which can originate from the
|
||
public Internet accessing your private network. Everything else
|
||
is blocked and logged by default design. Inclusive firewalls are
|
||
much, much more secure than exclusive firewall rule sets and is
|
||
the only rule set type covered herein.</para>
|
||
|
||
<para>For detailed explanation of the legacy rules processing
|
||
method see: <ulink
|
||
url="http://www.obfuscation.org/ipf/ipf-howto.html#TOC_1"></ulink>
|
||
and <ulink
|
||
url="http://coombs.anu.edu.au/~avalon/ip-filter.html"></ulink>.</para>
|
||
|
||
<para>IPF 的 FAQ 位於 <ulink
|
||
url="http://www.phildev.net/ipf/index.html"></ulink>.</para>
|
||
|
||
<sect2>
|
||
<title>啟用 IPF</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>啟用</secondary>
|
||
</indexterm>
|
||
|
||
<para>IPF is included in the basic &os; install as a separate run
|
||
time loadable module. The system will dynamically load the IPF
|
||
kernel loadable module when the rc.conf statement
|
||
<literal>ipfilter_enable="YES"</literal> is used. The loadable
|
||
module was created with logging enabled and the
|
||
<literal>default pass all</literal> options. You do not need
|
||
to compile IPF into the &os; kernel just to change the default
|
||
to <literal>block all</literal>, you can do that by just coding
|
||
a block all rule at the end of your rule set.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>kernel 選項</title>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFILTER</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFILTER_LOG</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFILTER_DEFAULT_BLOCK</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>kernel options</secondary>
|
||
</indexterm>
|
||
|
||
<para>在編譯 &os; kernel 時,並不必完全加入下列的選項來啟用 IPF。
|
||
在這裡只是要列出給你參考的一些資訊而已。
|
||
將 IPF 編譯入 kernel 中,會導致無法使用 kernel 的動態載入模組。</para>
|
||
|
||
<para>Sample kernel config IPF option statements are in the
|
||
<filename>/usr/src/sys/conf/NOTES</filename> kernel source
|
||
(<filename>/usr/src/sys/<replaceable>arch</replaceable>/conf/LINT</filename>
|
||
for &os; 4.X) and are reproduced here:</para>
|
||
|
||
<programlisting>options IPFILTER
|
||
options IPFILTER_LOG
|
||
options IPFILTER_DEFAULT_BLOCK</programlisting>
|
||
|
||
<para><literal>options IPFILTER</literal> enables support for the
|
||
「IPFILTER」 firewall.</para>
|
||
|
||
<para><literal>options IPFILTER_LOG</literal> enables the option
|
||
to have IPF log traffic by writing to the
|
||
<devicename>ipl</devicename> packet logging pseudo—device
|
||
for every rule that has the <literal>log</literal>
|
||
keyword.</para>
|
||
|
||
<para><literal>options IPFILTER_DEFAULT_BLOCK</literal> changes
|
||
the default behavior so any packet not matching a firewall
|
||
<literal>pass</literal> rule gets blocked.</para>
|
||
|
||
<para>These settings will take effect only after you have built
|
||
and installed a kernel with them set.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>可用的 rc.conf 選項</title>
|
||
|
||
<para>須在 <filename>/etc/rc.conf</filename> 內加入下列內容,以便在開機時就會啟用 IPF:</para>
|
||
|
||
<programlisting>ipfilter_enable="YES" # Start ipf firewall
|
||
ipfilter_rules="/etc/ipf.rules" # IPF 防火牆規則設定檔
|
||
ipmon_enable="YES" # 啟用 IP 監控記錄
|
||
ipmon_flags="-Ds" # D = 使用服務程序 (daemon) 啟動
|
||
# s = 使用 syslog 記錄
|
||
# v = 記錄於 tcp window, ack, seq
|
||
# n = 將 IP 及 port 對應至名稱中</programlisting>
|
||
|
||
<para>If you have a LAN behind this firewall that uses the
|
||
reserved private IP address ranges, then you need to add the
|
||
following to enable <acronym>NAT</acronym>
|
||
functionality:</para>
|
||
|
||
<programlisting>gateway_enable="YES" # 啟用 LAN Gateway
|
||
ipnat_enable="YES" # Start ipnat function
|
||
ipnat_rules="/etc/ipnat.rules" # rules definition file for ipnat</programlisting>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IPF</title>
|
||
|
||
<indexterm><primary><command>ipf</command></primary></indexterm>
|
||
|
||
<para>The ipf command is used to load your rules file. Normally
|
||
you create a file containing your custom rules and use this
|
||
command to replace in mass the currently running firewall
|
||
internal rules:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipf -Fa -f /etc/ipf.rules</userinput></screen>
|
||
|
||
<para><option>-Fa</option> means flush all internal rules
|
||
tables.</para>
|
||
|
||
<para><option>-f</option> means this is the file to read for the
|
||
rules to load.</para>
|
||
|
||
<para>This gives you the ability to make changes to your custom
|
||
rules file, run the above IPF command, and thus update the
|
||
running firewall with a fresh copy of all the rules without
|
||
having to reboot the system. This method is very convenient
|
||
for testing new rules as the procedure can be executed as many
|
||
times as needed.</para>
|
||
|
||
<para>See the &man.ipf.8; manual page for details on the other
|
||
flags available with this command.</para>
|
||
|
||
<para>The &man.ipf.8; command expects the rules file to be a
|
||
standard text file. It will not accept a rules file written as
|
||
a script with symbolic substitution.</para>
|
||
|
||
<para>There is a way to build IPF rules that utilizes the power
|
||
of script symbolic substitution. For more information, see
|
||
<xref linkend="firewalls-ipf-rules-script"/>.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IPFSTAT</title>
|
||
|
||
<indexterm><primary><command>ipfstat</command></primary></indexterm>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>statistics</secondary>
|
||
</indexterm>
|
||
|
||
<para>The default behavior of &man.ipfstat.8; is to retrieve and
|
||
display the totals of the accumulated statistics gathered as a
|
||
result of applying the user coded rules against packets going
|
||
in and out of the firewall since it was last started, or since
|
||
the last time the accumulators were reset to zero by the
|
||
<command>ipf -Z</command> command.</para>
|
||
|
||
<para>See the &man.ipfstat.8; manual page for details.</para>
|
||
|
||
<para>The default &man.ipfstat.8; command output will look
|
||
something like this:</para>
|
||
|
||
<screen>input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
|
||
output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
|
||
input packets logged: blocked 99286 passed 0
|
||
output packets logged: blocked 0 passed 0
|
||
packets logged: input 0 output 0
|
||
log failures: input 3898 output 0
|
||
fragment state(in): kept 0 lost 0
|
||
fragment state(out): kept 0 lost 0
|
||
packet state(in): kept 169364 lost 0
|
||
packet state(out): kept 431395 lost 0
|
||
ICMP replies: 0 <acronym>TCP</acronym> RSTs sent: 0
|
||
Result cache hits(in): 1215208 (out): 1098963
|
||
IN Pullups succeeded: 2 failed: 0
|
||
OUT Pullups succeeded: 0 failed: 0
|
||
Fastroute successes: 0 failures: 0
|
||
<acronym>TCP</acronym> cksum fails(in): 0 (out): 0
|
||
Packet log flags set: (0)</screen>
|
||
|
||
<para>When supplied with either <option>-i</option> for inbound
|
||
or <option>-o</option> for outbound, it will retrieve and
|
||
display the appropriate list of filter rules currently
|
||
installed and in use by the kernel.</para>
|
||
|
||
<para><command>ipfstat -in</command> displays the inbound
|
||
internal rules table with rule number.</para>
|
||
|
||
<para><command>ipfstat -on</command> displays the outbound
|
||
internal rules table with the rule number.</para>
|
||
|
||
<para>The output will look something like this:</para>
|
||
|
||
<screen>@1 pass out on xl0 from any to any
|
||
@2 block out on dc0 from any to any
|
||
@3 pass out quick on dc0 proto tcp/udp from any to any keep state</screen>
|
||
|
||
<para><command>ipfstat -ih</command> displays the inbound
|
||
internal rules table, prefixing each rule with a count of how
|
||
many times the rule was matched.</para>
|
||
|
||
<para><command>ipfstat -oh</command> displays the outbound
|
||
internal rules table, prefixing each rule with a count of how
|
||
many times the rule was matched.</para>
|
||
|
||
<para>The output will look something like this:</para>
|
||
|
||
<screen>2451423 pass out on xl0 from any to any
|
||
354727 block out on dc0 from any to any
|
||
430918 pass out quick on dc0 proto tcp/udp from any to any keep state</screen>
|
||
|
||
<para>One of the most important functions of the
|
||
<command>ipfstat</command> command is the <option>-t</option>
|
||
flag which displays the state table in a way similar to the way
|
||
&man.top.1; shows the &os; running process table. When your
|
||
firewall is under attack this function gives you the ability to
|
||
identify, drill down to, and see the attacking packets. The
|
||
optional sub-flags give the ability to select the destination
|
||
or source IP, port, or protocol that you want to monitor in
|
||
real time. See the &man.ipfstat.8; manual page for
|
||
details.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IPMON</title>
|
||
|
||
<indexterm><primary><command>ipmon</command></primary></indexterm>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>logging</secondary>
|
||
</indexterm>
|
||
|
||
<para>In order for <command>ipmon</command> to work properly, the
|
||
kernel option IPFILTER_LOG must be turned on. This command has
|
||
two different modes that it can be used in. Native mode is the
|
||
default mode when you type the command on the command line
|
||
without the <option>-D</option> flag.</para>
|
||
|
||
<para>Daemon mode is for when you want to have a continuous
|
||
system log file available so that you can review logging of
|
||
past events. This is how &os; and IPFILTER are configured to
|
||
work together. &os; has a built in facility to automatically
|
||
rotate system logs. That is why outputting the log information
|
||
to syslogd is better than the default of outputting to a
|
||
regular file. In the default <filename>rc.conf</filename> file
|
||
you see the ipmon_flags statement uses the <option>-Ds</option>
|
||
flags:</para>
|
||
|
||
<programlisting>ipmon_flags="-Ds" # D = start as daemon
|
||
# s = log to syslog
|
||
# v = log tcp window, ack, seq
|
||
# n = map IP & port to names</programlisting>
|
||
|
||
<para>The benefits of logging are obvious. It provides the
|
||
ability to review, after the fact, information such as which
|
||
packets had been dropped, what addresses they came from and
|
||
where they were going. These all give you a significant edge
|
||
in tracking down attackers.</para>
|
||
|
||
<para>Even with the logging facility enabled, IPF will not
|
||
generate any rule logging on its own. The firewall
|
||
administrator decides what rules in the rule set he wants to
|
||
log and adds the log keyword to those rules. Normally only
|
||
deny rules are logged.</para>
|
||
|
||
<para>It is very customary to include a default deny everything
|
||
rule with the log keyword included as your last rule in the
|
||
rule set. This way you get to see all the packets that did not
|
||
match any of the rules in the rule set.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IPMON Logging</title>
|
||
|
||
<para><application>Syslogd</application> uses its own special
|
||
method for segregation of log data. It uses special groupings
|
||
called 「facility」 and <quote>level</quote>. IPMON
|
||
in <option>-Ds</option> mode uses <literal>security</literal>
|
||
(<literal>local0</literal> in 4.X) as the 「facility」
|
||
name. All IPMON logged data goes to <literal>security</literal>
|
||
(<literal>local0</literal> in 4.X). The following levels can be
|
||
used to further segregate the logged data if desired:</para>
|
||
|
||
<screen>LOG_INFO - packets logged using the "log" keyword as the action rather than pass or block.
|
||
LOG_NOTICE - packets logged which are also passed
|
||
LOG_WARNING - packets logged which are also blocked
|
||
LOG_ERR - packets which have been logged and which can be considered short</screen>
|
||
|
||
<!-- XXX: "can be considered short" == "with incomplete header" -->
|
||
|
||
<para>To setup IPFILTER to log all data to
|
||
<filename>/var/log/ipfilter.log</filename>, you will need to
|
||
create the file. The following command will do that:</para>
|
||
|
||
<screen>&prompt.root; <userinput>touch /var/log/ipfilter.log</userinput></screen>
|
||
|
||
<para>The syslog function is controlled by definition statements
|
||
in the <filename>/etc/syslog.conf</filename> file. The
|
||
<filename>syslog.conf</filename> file offers considerable
|
||
flexibility in how syslog will deal with system messages issued
|
||
by software applications like IPF.</para>
|
||
|
||
<para>Add the following statement to
|
||
<filename>/etc/syslog.conf</filename> for &os; 5.X and
|
||
later:</para>
|
||
|
||
<programlisting>security.* /var/log/ipfilter.log</programlisting>
|
||
|
||
<para>Or add the following statement to
|
||
<filename>/etc/syslog.conf</filename> for &os; 4.X:</para>
|
||
|
||
<programlisting>local0.* /var/log/ipfilter.log</programlisting>
|
||
|
||
<para>The <literal>security.*</literal> (<literal>local0</literal>
|
||
for 4.X) means to write all the logged messages to the coded
|
||
file location.</para>
|
||
|
||
<para>To activate the changes to <filename>/etc/syslog.conf
|
||
</filename> you can reboot or bump the syslog task into
|
||
re-reading <filename>/etc/syslog.conf</filename> by running
|
||
<command>/etc/rc.d/syslogd reload</command>
|
||
(<command>killall -HUP syslogd</command> in &os; 4.X).</para>
|
||
|
||
<para>Do not forget to change
|
||
<filename>/etc/newsyslog.conf</filename> to rotate the new log
|
||
you just created above.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>The Format of Logged Messages</title>
|
||
|
||
<para>Messages generated by <command>ipmon</command> consist of
|
||
data fields separated by white space. Fields common to all
|
||
messages are:</para>
|
||
|
||
<orderedlist>
|
||
<listitem>
|
||
<para>The date of packet receipt.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>The time of packet receipt. This is in the form
|
||
HH:MM:SS.F, for hours, minutes, seconds, and fractions of a
|
||
second (which can be several digits long).</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>The name of the interface the packet was processed on,
|
||
e.g. <devicename>dc0</devicename>.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>The group and rule number of the rule, e.g.
|
||
<literal>@0:17</literal>.</para>
|
||
</listitem>
|
||
</orderedlist>
|
||
|
||
<para>These can be viewed with <command>ipfstat
|
||
-in</command>.</para>
|
||
|
||
<orderedlist>
|
||
<listitem>
|
||
<para>The action: p for passed, b for blocked, S for a short
|
||
packet, n did not match any rules, L for a log rule. The
|
||
order of precedence in showing flags is: S, p, b, n, L. A
|
||
capital P or B means that the packet has been logged due to
|
||
a global logging setting, not a particular rule.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>The addresses. This is actually three fields: the
|
||
source address and port (separated by a comma), the ->
|
||
symbol, and the destination address and port.
|
||
209.53.17.22,80 -> 198.73.220.17,1722.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><literal>PR</literal> followed by the protocol name or
|
||
number, e.g. PR tcp.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><literal>len</literal> followed by the header length
|
||
and total length of the packet, e.g. len 20 40.</para>
|
||
</listitem>
|
||
</orderedlist>
|
||
|
||
<para>If the packet is a <acronym>TCP</acronym> packet, there
|
||
will be an additional field starting with a hyphen followed by
|
||
letters corresponding to any flags that were set. See the
|
||
&man.ipmon.8; manual page for a list of letters and their
|
||
flags.</para>
|
||
|
||
<para>If the packet is an ICMP packet, there will be two fields
|
||
at the end, the first always being 「ICMP」, and the
|
||
next being the ICMP message and sub-message type, separated by
|
||
a slash, e.g. ICMP 3/3 for a port unreachable message.</para>
|
||
</sect2>
|
||
|
||
<sect2 id="firewalls-ipf-rules-script">
|
||
<title>Building the Rule Script with Symbolic
|
||
Substitution</title>
|
||
|
||
<para>Some experienced IPF users create a file containing the
|
||
rules and code them in a manner compatible with running them as
|
||
a script with symbolic substitution. The major benefit of
|
||
doing this is that you only have to change the value associated
|
||
with the symbolic name and when the script is run all the rules
|
||
containing the symbolic name will have the value substituted in
|
||
the rules. Being a script, you can use symbolic substitution
|
||
to code frequently used values and substitute them in multiple
|
||
rules. You will see this in the following example.</para>
|
||
|
||
<para>The script syntax used here is compatible with the sh, csh,
|
||
and tcsh shells.</para>
|
||
|
||
<para>Symbolic substitution fields are prefixed with a dollar
|
||
sign: <literal>$</literal>.</para>
|
||
|
||
<para>Symbolic fields do not have the $ prefix.</para>
|
||
|
||
<para>The value to populate the symbolic field must be enclosed
|
||
with double quotes (<literal>"</literal>).</para>
|
||
|
||
<para>Start your rule file with something like this:</para>
|
||
|
||
<programlisting>############# IPF 規則命令稿的開始 ########################
|
||
|
||
oif="dc0" # 對外網路裝置的名稱
|
||
odns="192.0.2.11" # ISP 的 DNS 伺服器 IP 位址
|
||
myip="192.0.2.7" # 從我的 ISP 提供的靜態 IP
|
||
ks="keep state"
|
||
fks="flags S keep state"
|
||
|
||
# You can choose between building /etc/ipf.rules file
|
||
# from this script or running this script "as is".
|
||
#
|
||
# Uncomment only one line and comment out another.
|
||
#
|
||
# 1) This can be used for building /etc/ipf.rules:
|
||
#cat > /etc/ipf.rules << EOF
|
||
#
|
||
# 2) This can be used to run script "as is":
|
||
/sbin/ipf -Fa -f - << EOF
|
||
|
||
# Allow out access to my ISP's Domain name server.
|
||
pass out quick on $oif proto tcp from any to $odns port = 53 $fks
|
||
pass out quick on $oif proto udp from any to $odns port = 53 $ks
|
||
|
||
# Allow out non-secure standard www function
|
||
pass out quick on $oif proto tcp from $myip to any port = 80 $fks
|
||
|
||
# Allow out secure www function https over TLS SSL
|
||
pass out quick on $oif proto tcp from $myip to any port = 443 $fks
|
||
EOF
|
||
################## End of IPF rules script ########################</programlisting>
|
||
|
||
<para>That is all there is to it. The rules are not important in
|
||
this example; how the symbolic substitution fields are
|
||
populated and used are. If the above example was in a file
|
||
named <filename>/etc/ipf.rules.script</filename>, you could
|
||
reload these rules by entering the following command:</para>
|
||
|
||
<screen>&prompt.root; <userinput>sh /etc/ipf.rules.script</userinput></screen>
|
||
|
||
<para>There is one problem with using a rules file with embedded
|
||
symbolics: IPF does not understand symbolic substitution, and
|
||
cannot read such scripts directly.</para>
|
||
|
||
<para>This script can be used in one of two ways:</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>Uncomment the line that begins with
|
||
<literal>cat</literal>, and comment out the line that
|
||
begins with <literal>/sbin/ipf</literal>. Place
|
||
<literal>ipfilter_enable="YES"</literal> into
|
||
<filename>/etc/rc.conf</filename> as usual, and run script
|
||
once after each modification to create or update
|
||
<filename>/etc/ipf.rules</filename>.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Disable IPFILTER in system startup scripts by adding
|
||
<literal>ipfilter_enable="NO"</literal> (this is default
|
||
value) into <filename>/etc/rc.conf</filename> file.</para>
|
||
|
||
<para>Add a script like the following to your
|
||
<filename>/usr/local/etc/rc.d/</filename> startup
|
||
directory. The script should have an obvious name like
|
||
<filename>ipf.loadrules.sh</filename>. The
|
||
<filename>.sh</filename> extension is mandatory.</para>
|
||
|
||
<programlisting>#!/bin/sh
|
||
sh /etc/ipf.rules.script</programlisting>
|
||
|
||
<para>The permissions on this script file must be read,
|
||
write, execute for owner <username>root</username>.</para>
|
||
|
||
<screen>&prompt.root; <userinput>chmod 700 /usr/local/etc/rc.d/ipf.loadrules.sh</userinput></screen>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>從現在起,當系統開機時就會載入你所設的 IPF 規則。</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IPF 規則</title>
|
||
|
||
<!-- XXX: looks incorrect (and duplicated 2 times in this chapter):
|
||
1. Packet can be processed two times depend of firewall
|
||
firewall configuration, but "return trip back" is
|
||
another packet.
|
||
2. "Each TCP/IP service ... is predefined by its protocol ..."
|
||
- this shold be about packet and it's parameters
|
||
(source/destination address and port). -->
|
||
|
||
<para>A rule set is a group of ipf rules coded to pass or block
|
||
packets based on the values contained in the packet. The
|
||
bi-directional exchange of packets between hosts comprises a
|
||
session conversation. The firewall rule set processes the
|
||
packet two times, once on its arrival from the public Internet
|
||
host and again as it leaves for its return trip back to the
|
||
public Internet host. Each TCP/IP service (i.e. telnet, www,
|
||
mail, etc.) is predefined by its protocol, source and
|
||
destination IP address, or the source and destination port
|
||
number. This is the basic selection criteria used to create
|
||
rules which will pass or block services.</para>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>rule processing order</secondary>
|
||
</indexterm>
|
||
|
||
<para>IPF was originally written using a rules processing logic
|
||
of 「the last matching rule wins」 and used only
|
||
stateless rules. Over time IPF has been enhanced to include a
|
||
「quick」 option and a stateful 「keep
|
||
state」 option which drastically modernized the rule
|
||
processing logic.</para>
|
||
|
||
<para>The instructions contained in this section are based on
|
||
using rules that contain the 「quick」 option and
|
||
the stateful 「keep state」 option. This is the
|
||
basic framework for coding an inclusive firewall rule
|
||
set.</para>
|
||
|
||
<!-- XXX: something like this already in
|
||
<xref linkend="firewalls-concepts"/>
|
||
AND: the para below is repeated 3 times in this chapter-->
|
||
|
||
<para>An inclusive firewall only allows services matching the
|
||
rules through. This way you can control what services can
|
||
originate behind the firewall destined for the public Internet
|
||
and also control the services which can originate from the
|
||
public Internet accessing your private network. Everything
|
||
else is blocked and logged by default design. Inclusive
|
||
firewalls are much, much securer than exclusive firewall rule
|
||
sets and is the only rule set type covered herein.</para>
|
||
|
||
<warning>
|
||
<para>When working with the firewall rules, be <emphasis>very
|
||
careful</emphasis>. Some configurations <emphasis>will
|
||
lock you out</emphasis> of the server. To be on the safe
|
||
side, you may wish to consider performing the initial
|
||
firewall configuration from the local console rather than
|
||
doing it remotely e.g. via
|
||
<application>ssh</application>.</para>
|
||
</warning>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Rule Syntax</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>rule syntax</secondary>
|
||
</indexterm>
|
||
|
||
<para>The rule syntax presented here has been simplified to only
|
||
address the modern stateful rule context and 「first
|
||
matching rule wins」 logic. For the complete legacy rule
|
||
syntax description see the &man.ipf.8; manual page.</para>
|
||
|
||
<para>A <literal>#</literal> character is used to mark the start
|
||
of a comment and may appear at the end of a rule line or on its
|
||
own line. Blank lines are ignored.</para>
|
||
|
||
<para>Rules contain keywords. These keywords have to be coded in
|
||
a specific order from left to right on the line. Keywords are
|
||
identified in bold type. Some keywords have sub-options which
|
||
may be keywords themselves and also include more sub-options.
|
||
Each of the headings in the below syntax has a bold section
|
||
header which expands on the content.</para>
|
||
|
||
<!-- This section is probably wrong. See the OpenBSD flag -->
|
||
<!-- What is the "OpenBSD flag"? Reference please -->
|
||
|
||
<para><replaceable>ACTION IN-OUT OPTIONS SELECTION STATEFUL PROTO
|
||
SRC_ADDR,DST_ADDR OBJECT PORT_NUM TCP_FLAG
|
||
STATEFUL</replaceable></para>
|
||
|
||
<para><replaceable>ACTION</replaceable> = block | pass</para>
|
||
|
||
<para><replaceable>IN-OUT</replaceable> = in | out</para>
|
||
|
||
<para><replaceable>OPTIONS</replaceable> = log | quick | on
|
||
interface-name</para>
|
||
|
||
<para><replaceable>SELECTION</replaceable> = proto value |
|
||
source/destination IP | port = number | flags
|
||
flag-value</para>
|
||
|
||
<para><replaceable>PROTO</replaceable> = tcp/udp | udp | tcp |
|
||
icmp</para>
|
||
|
||
<para><replaceable>SRC_ADD,DST_ADDR</replaceable> = all | from
|
||
object to object</para>
|
||
|
||
<para><replaceable>OBJECT</replaceable> = IP address | any</para>
|
||
|
||
<para><replaceable>PORT_NUM</replaceable> = port number</para>
|
||
|
||
<para><replaceable>TCP_FLAG</replaceable> = S</para>
|
||
|
||
<para><replaceable>STATEFUL</replaceable> = keep state</para>
|
||
|
||
<sect3>
|
||
<title>ACTION</title>
|
||
|
||
<para>The action indicates what to do with the packet if it
|
||
matches the rest of the filter rule. Each rule
|
||
<emphasis>must</emphasis> have a action. The following
|
||
actions are recognized:</para>
|
||
|
||
<para><literal>block</literal> indicates that the packet should
|
||
be dropped if the selection parameters match the
|
||
packet.</para>
|
||
|
||
<para><literal>pass</literal> indicates that the packet should
|
||
exit the firewall if the selection parameters match the
|
||
packet.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>IN-OUT</title>
|
||
|
||
<para>A mandatory requirement is that each filter rule
|
||
explicitly state which side of the I/O it is to be used on.
|
||
The next keyword must be either in or out and one or the
|
||
other has to be coded or the rule will not pass syntax
|
||
checks.</para>
|
||
|
||
<para><literal>in</literal> means this rule is being applied
|
||
against an inbound packet which has just been received on the
|
||
interface facing the public Internet.</para>
|
||
|
||
<para><literal>out</literal> means this rule is being applied
|
||
against an outbound packet destined for the interface facing
|
||
the public Internet.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>OPTIONS</title>
|
||
|
||
<note>
|
||
<para>These options must be used in the order shown
|
||
here.</para>
|
||
</note>
|
||
|
||
<para><literal>log</literal> indicates that the packet header
|
||
will be written to
|
||
|
||
<!-- XXX - xref here -->
|
||
|
||
the <devicename>ipl</devicename> log (as described in the
|
||
LOGGING section below) if the selection parameters match the
|
||
packet.</para>
|
||
|
||
<para><literal>quick</literal> indicates that if the selection
|
||
parameters match the packet, this rule will be the last rule
|
||
checked, allowing a 「short-circuit」 path to avoid processing
|
||
any following rules for this packet. This option is a
|
||
mandatory requirement for the modernized rules processing
|
||
logic.</para>
|
||
|
||
<para><literal>on</literal> indicates the interface name to be
|
||
incorporated into the selection parameters. Interface names
|
||
are as displayed by &man.ifconfig.8;. Using this option, the
|
||
rule will only match if the packet is going through that
|
||
interface in the specified direction (in/out). This option
|
||
is a mandatory requirement for the modernized rules
|
||
processing logic.</para>
|
||
|
||
<para>When a packet is logged, the headers of the packet are
|
||
written to the IPL packet logging pseudo-device.
|
||
Immediately following the log keyword, the following
|
||
qualifiers may be used (in this order):</para>
|
||
|
||
<para><literal>body</literal> indicates that the first 128
|
||
bytes of the packet contents will be logged after the
|
||
headers.</para>
|
||
|
||
<para><literal>first</literal> If the <literal>log</literal>
|
||
keyword is being used in conjunction with a 「keep
|
||
state」 option, it is recommended that this option is
|
||
also applied so that only the triggering packet is logged and
|
||
not every packet which thereafter matches the 「keep
|
||
state」 information.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>SELECTION</title>
|
||
|
||
<para>The keywords described in this section are used to
|
||
describe attributes of the packet to be interrogated when
|
||
determining whether rules match or not. There is a
|
||
keyword subject, and it has sub-option keywords, one of
|
||
which has to be selected. The following general-purpose
|
||
attributes are provided for matching, and must be used in
|
||
this order:</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>PROTO</title>
|
||
|
||
<para><literal>proto</literal> is the subject keyword and must
|
||
be coded along with one of its corresponding keyword
|
||
sub-option values. The value allows a specific protocol to
|
||
be matched against. This option is a mandatory requirement
|
||
for the modernized rules processing logic.</para>
|
||
|
||
<para><literal>tcp/udp | udp | tcp | icmp</literal> or any
|
||
protocol names found in <filename>/etc/protocols</filename>
|
||
are recognized and may be used. The special protocol keyword
|
||
<literal>tcp/udp</literal> may be used to match either a
|
||
<acronym>TCP</acronym> or a UDP packet, and has been added as
|
||
a convenience to save duplication of otherwise identical
|
||
rules.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>SRC_ADDR/DST_ADDR</title>
|
||
|
||
<para>The <literal>all</literal> keyword is essentially a
|
||
synonym for 「from any to any」 with no other
|
||
match parameters.</para>
|
||
|
||
<para><literal>from src to dst</literal>: the from and to
|
||
keywords are used to match against IP addresses. Rules must
|
||
specify BOTH source and destination parameters.
|
||
<literal>any</literal> is a special keyword that matches any
|
||
IP address. Examples of use: 「from any to any」
|
||
or 「from 0.0.0.0/0 to any」 or <quote>from any to
|
||
0.0.0.0/0」 or 「from 0.0.0.0 to any</quote> or
|
||
「from any to 0.0.0.0」.</para>
|
||
|
||
<!-- XXX: Needs rewording -->
|
||
|
||
<para>IP addresses may be specified as a dotted IP address
|
||
numeric form/mask-length, or as single dotted IP address
|
||
numeric form.</para>
|
||
|
||
<para>There is no way to match ranges of IP addresses which
|
||
do not express themselves easily as mask-length. See this
|
||
web page for help on writing mask-length: <ulink
|
||
url="http://jodies.de/ipcalc"></ulink>.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>PORT</title>
|
||
|
||
<para>If a port match is included, for either or both of source
|
||
and destination, then it is only applied to
|
||
<acronym>TCP</acronym> and UDP packets. When composing port
|
||
comparisons, either the service name from
|
||
<filename>/etc/services</filename> or an integer port number
|
||
may be used. When the port appears as part of the from
|
||
object, it matches the source port number; when it appears
|
||
as part of the to object, it matches the destination port
|
||
number. The use of the port option with the
|
||
<literal>to</literal> object is a mandatory requirement for
|
||
the modernized rules processing logic. Example of use:
|
||
「from any to any port = 80」</para>
|
||
|
||
<!-- XXX: Needs rewriting -->
|
||
|
||
<para>Port comparisons may be done in a number of forms, with
|
||
a number of comparison operators, or port ranges may be
|
||
specified.</para>
|
||
|
||
<para>port "=" | "!=" | "<" | ">" | "<=" | ">=" |
|
||
"eq" | "ne" | "lt" | "gt" | "le" | "ge".</para>
|
||
|
||
<para>To specify port ranges, port "<>" |
|
||
"><"</para>
|
||
|
||
<warning>
|
||
<para>Following the source and destination matching
|
||
parameters, the following two parameters are mandatory
|
||
requirements for the modernized rules processing
|
||
logic.</para>
|
||
</warning>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title><acronym>TCP</acronym>_FLAG</title>
|
||
|
||
<para>Flags are only effective for <acronym>TCP</acronym>
|
||
filtering. The letters represents one of the possible flags
|
||
that can be interrogated in the <acronym>TCP</acronym> packet
|
||
header.</para>
|
||
|
||
<para>The modernized rules processing logic uses the
|
||
<literal>flags S</literal> parameter to identify the tcp
|
||
session start request.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>STATEFUL</title>
|
||
|
||
<para><literal>keep state</literal> indicates that on a pass
|
||
rule, any packets that match the rules selection parameters
|
||
should activate the stateful filtering facility.</para>
|
||
|
||
<note>
|
||
<para>This option is a mandatory requirement for the
|
||
modernized rules processing logic.</para>
|
||
</note>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Stateful Filtering</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFILTER</primary>
|
||
|
||
<secondary>stateful filtering</secondary>
|
||
</indexterm>
|
||
|
||
<!-- XXX: duplicated -->
|
||
|
||
<para>Stateful filtering treats traffic as a bi-directional
|
||
exchange of packets comprising a session conversation. When
|
||
activated, keep-state dynamically generates internal rules for
|
||
each anticipated packet being exchanged during the
|
||
bi-directional session conversation. It has the interrogation
|
||
abilities to determine if the session conversation between the
|
||
originating sender and the destination are following the valid
|
||
procedure of bi-directional packet exchange. Any packets that
|
||
do not properly fit the session conversation template are
|
||
automatically rejected as impostors.</para>
|
||
|
||
<para>Keep state will also allow ICMP packets related to a
|
||
<acronym>TCP</acronym> or UDP session through. So if you get
|
||
ICMP type 3 code 4 in response to some web surfing allowed out
|
||
by a keep state rule, they will be automatically allowed in.
|
||
Any packet that IPF can be certain is part of an active
|
||
session, even if it is a different protocol, will be let
|
||
in.</para>
|
||
|
||
<para>What happens is:</para>
|
||
|
||
<para>Packets destined to go out the interface connected to the
|
||
public Internet are first checked against the dynamic state
|
||
table, if the packet matches the next expected packet
|
||
comprising in a active session conversation, then it exits the
|
||
firewall and the state of the session conversation flow is
|
||
updated in the dynamic state table, the remaining packets get
|
||
checked against the outbound rule set.</para>
|
||
|
||
<para>Packets coming in to the interface connected to the public
|
||
Internet are first checked against the dynamic state table, if
|
||
the packet matches the next expected packet comprising a
|
||
active session conversation, then it exits the firewall and
|
||
the state of the session conversation flow is updated in the
|
||
dynamic state table, the remaining packets get checked against
|
||
the inbound rule set.</para>
|
||
|
||
<para>When the conversation completes it is removed from the
|
||
dynamic state table.</para>
|
||
|
||
<para>Stateful filtering allows you to focus on blocking/passing
|
||
new sessions. If the new session is passed, all its subsequent
|
||
packets will be allowed through automatically and any impostors
|
||
automatically rejected. If a new session is blocked, none of
|
||
its subsequent packets will be allowed through. Stateful
|
||
filtering has technically advanced interrogation abilities
|
||
capable of defending against the flood of different attack
|
||
methods currently employed by attackers.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<!-- XXX: This section needs a rewrite -->
|
||
|
||
<title>Inclusive Rule Set Example</title>
|
||
|
||
<para>The following rule set is an example of how to code a very
|
||
secure inclusive type of firewall. An inclusive firewall only
|
||
allows services matching pass rules through and blocks all
|
||
other by default. All firewalls have at the minimum two
|
||
interfaces which have to have rules to allow the firewall to
|
||
function.</para>
|
||
|
||
<para>All &unix; flavored systems including &os; are designed to
|
||
use interface <devicename>lo0</devicename> and IP address
|
||
<hostid role="ipaddr">127.0.0.1</hostid> for internal
|
||
communication within the operating system. The firewall rules
|
||
must contain rules to allow free unmolested movement of these
|
||
special internally used packets.</para>
|
||
|
||
<para>The interface which faces the public Internet is the one
|
||
where you place your rules to authorize and control access out
|
||
to the public Internet and access requests arriving from the
|
||
public Internet. This can be your user PPP
|
||
<devicename>tun0</devicename> interface or your NIC that is
|
||
connected to your DSL or cable modem.</para>
|
||
|
||
<para>In cases where one or more NICs are cabled to private LANs
|
||
behind the firewall, those interfaces must have a rule coded to
|
||
allow free unmolested movement of packets originating from
|
||
those LAN interfaces.</para>
|
||
|
||
<para>The rules should be first organized into three major
|
||
sections: all the free unmolested interfaces, the public
|
||
interface outbound, and the public interface inbound.</para>
|
||
|
||
<para>The rules in each of the public interface sections should
|
||
have the most frequently matched rules placed before less
|
||
commonly matched rules, with the last rule in the section
|
||
blocking and logging all packets on that interface and
|
||
direction.</para>
|
||
|
||
<para>The Outbound section in the following rule set only
|
||
contains 'pass' rules which contain selection values that
|
||
uniquely identify the service that is authorized for public
|
||
Internet access. All the rules have the 'quick', 'on',
|
||
'proto', 'port', and 'keep state' option coded. The 'proto
|
||
tcp' rules have the 'flag' option included to identify the
|
||
session start request as the triggering packet to activate the
|
||
stateful facility.</para>
|
||
|
||
<para>The Inbound section has all the blocking of undesirable
|
||
packets first, for two different reasons. The first is that
|
||
these things being blocked may be part of an otherwise valid
|
||
packet which may be allowed in by the later authorized service
|
||
rules. The second reason is that by having a rule that
|
||
explicitly blocks selected packets that I receive on an
|
||
infrequent basis and that I do not want to see in the log, they
|
||
will not be caught by the last rule in the section which blocks
|
||
and logs all packets which have fallen through the rules. The
|
||
last rule in the section which blocks and logs all packets is
|
||
how you create the legal evidence needed to prosecute the
|
||
people who are attacking your system.</para>
|
||
|
||
<para>Another thing you should take note of, is there is no
|
||
response returned for any of the undesirable stuff, their
|
||
packets just get dropped and vanish. This way the attacker
|
||
has no knowledge if his packets have reached your system. The
|
||
less the attackers can learn about your system, the more
|
||
time they must invest before actually doing something bad.
|
||
The inbound 'nmap OS fingerprint' attempts rule I log
|
||
|
||
<!-- XXX: what? -->
|
||
|
||
the first occurrence because this is something a attacker
|
||
would do.</para>
|
||
|
||
<para>Any time you see log messages on a rule with 'log first'.
|
||
You should do an <command>ipfstat -hio</command> command to see
|
||
the number of times the rule has been matched so you know if
|
||
you are being flooded, i.e. under attack.</para>
|
||
|
||
<para>When you log packets with port numbers you do not
|
||
recognize, look it up in <filename>/etc/services</filename> or
|
||
go to <ulink
|
||
url="http://www.securitystats.com/tools/portsearch.php"></ulink>
|
||
and do a port number lookup to find what the purpose of that
|
||
port number is.</para>
|
||
|
||
<para>Check out this link for port numbers used by Trojans <ulink
|
||
url="http://www.simovits.com/trojans/trojans.html"></ulink>.</para>
|
||
|
||
<para>The following rule set is a complete very secure
|
||
'inclusive' type of firewall rule set that I have used on my
|
||
system. You can not go wrong using this rule set for your own.
|
||
Just comment out any pass rules for services that you do not
|
||
want to authorize.</para>
|
||
|
||
<para>If you see messages in your log that you want to stop
|
||
seeing just add a block rule in the inbound section.</para>
|
||
|
||
<para>You have to change the <devicename>dc0</devicename>
|
||
interface name in every rule to the interface name of the Nic
|
||
card that connects your system to the public Internet. For
|
||
user PPP it would be <devicename>tun0</devicename>.</para>
|
||
|
||
<para>Add the following statements to
|
||
<filename>/etc/ipf.rules</filename>:</para>
|
||
|
||
<programlisting>#################################################################
|
||
# No restrictions on Inside LAN Interface for private network
|
||
# Not needed unless you have LAN
|
||
#################################################################
|
||
|
||
#pass out quick on xl0 all
|
||
#pass in quick on xl0 all
|
||
|
||
#################################################################
|
||
# No restrictions on Loopback Interface
|
||
#################################################################
|
||
pass in quick on lo0 all
|
||
pass out quick on lo0 all
|
||
|
||
#################################################################
|
||
# Interface facing Public Internet (Outbound Section)
|
||
# Interrogate session start requests originating from behind the
|
||
# firewall on the private network
|
||
# or from this gateway server destine for the public Internet.
|
||
#################################################################
|
||
|
||
# Allow out access to my ISP's Domain name server.
|
||
# xxx must be the IP address of your ISP's DNS.
|
||
# Dup these lines if your ISP has more than one DNS server
|
||
# Get the IP addresses from /etc/resolv.conf file
|
||
pass out quick on dc0 proto tcp from any to xxx port = 53 flags S keep state
|
||
pass out quick on dc0 proto udp from any to xxx port = 53 keep state
|
||
|
||
# Allow out access to my ISP's DHCP server for cable or DSL networks.
|
||
# This rule is not needed for 'user ppp' type connection to the
|
||
# public Internet, so you can delete this whole group.
|
||
# Use the following rule and check log for IP address.
|
||
# Then put IP address in commented out rule & delete first rule
|
||
pass out log quick on dc0 proto udp from any to any port = 67 keep state
|
||
#pass out quick on dc0 proto udp from any to z.z.z.z port = 67 keep state
|
||
|
||
|
||
# Allow out non-secure standard www function
|
||
pass out quick on dc0 proto tcp from any to any port = 80 flags S keep state
|
||
|
||
# Allow out secure www function https over TLS SSL
|
||
pass out quick on dc0 proto tcp from any to any port = 443 flags S keep state
|
||
|
||
# Allow out send & get email function
|
||
pass out quick on dc0 proto tcp from any to any port = 110 flags S keep state
|
||
pass out quick on dc0 proto tcp from any to any port = 25 flags S keep state
|
||
|
||
# Allow out Time
|
||
pass out quick on dc0 proto tcp from any to any port = 37 flags S keep state
|
||
|
||
# Allow out nntp news
|
||
pass out quick on dc0 proto tcp from any to any port = 119 flags S keep state
|
||
|
||
# Allow out gateway & LAN users non-secure FTP ( both passive & active modes)
|
||
# This function uses the IP<acronym>NAT</acronym> built in FTP proxy function coded in
|
||
# the nat rules file to make this single rule function correctly.
|
||
# If you want to use the pkg_add command to install application packages
|
||
# on your gateway system you need this rule.
|
||
pass out quick on dc0 proto tcp from any to any port = 21 flags S keep state
|
||
|
||
# Allow out secure FTP, Telnet, and SCP
|
||
# This function is using SSH (secure shell)
|
||
pass out quick on dc0 proto tcp from any to any port = 22 flags S keep state
|
||
|
||
# Allow out non-secure Telnet
|
||
pass out quick on dc0 proto tcp from any to any port = 23 flags S keep state
|
||
|
||
# Allow out FBSD CVSUP function
|
||
pass out quick on dc0 proto tcp from any to any port = 5999 flags S keep state
|
||
|
||
# Allow out ping to public Internet
|
||
pass out quick on dc0 proto icmp from any to any icmp-type 8 keep state
|
||
|
||
# Allow out whois for LAN PC to public Internet
|
||
pass out quick on dc0 proto tcp from any to any port = 43 flags S keep state
|
||
|
||
# Block and log only the first occurrence of everything
|
||
# else that's trying to get out.
|
||
# This rule enforces the block all by default logic.
|
||
block out log first quick on dc0 all
|
||
|
||
#################################################################
|
||
# Interface facing Public Internet (Inbound Section)
|
||
# Interrogate packets originating from the public Internet
|
||
# destine for this gateway server or the private network.
|
||
#################################################################
|
||
|
||
# Block all inbound traffic from non-routable or reserved address spaces
|
||
block in quick on dc0 from 192.168.0.0/16 to any #RFC 1918 private IP
|
||
block in quick on dc0 from 172.16.0.0/12 to any #RFC 1918 private IP
|
||
block in quick on dc0 from 10.0.0.0/8 to any #RFC 1918 private IP
|
||
block in quick on dc0 from 127.0.0.0/8 to any #loopback
|
||
block in quick on dc0 from 0.0.0.0/8 to any #loopback
|
||
block in quick on dc0 from 169.254.0.0/16 to any #DHCP auto-config
|
||
block in quick on dc0 from 192.0.2.0/24 to any #reserved for docs
|
||
block in quick on dc0 from 204.152.64.0/23 to any #Sun cluster interconnect
|
||
block in quick on dc0 from 224.0.0.0/3 to any #Class D & E multicast
|
||
|
||
##### Block a bunch of different nasty things. ############
|
||
# That I do not want to see in the log
|
||
|
||
# Block frags
|
||
block in quick on dc0 all with frags
|
||
|
||
# Block short tcp packets
|
||
block in quick on dc0 proto tcp all with short
|
||
|
||
# block source routed packets
|
||
block in quick on dc0 all with opt lsrr
|
||
block in quick on dc0 all with opt ssrr
|
||
|
||
# Block nmap OS fingerprint attempts
|
||
# Log first occurrence of these so I can get their IP address
|
||
block in log first quick on dc0 proto tcp from any to any flags FUP
|
||
|
||
# Block anything with special options
|
||
block in quick on dc0 all with ipopts
|
||
|
||
# Block public pings
|
||
block in quick on dc0 proto icmp all icmp-type 8
|
||
|
||
# Block ident
|
||
block in quick on dc0 proto tcp from any to any port = 113
|
||
|
||
# Block all Netbios service. 137=name, 138=datagram, 139=session
|
||
# Netbios is MS/Windows sharing services.
|
||
# Block MS/Windows hosts2 name server requests 81
|
||
block in log first quick on dc0 proto tcp/udp from any to any port = 137
|
||
block in log first quick on dc0 proto tcp/udp from any to any port = 138
|
||
block in log first quick on dc0 proto tcp/udp from any to any port = 139
|
||
block in log first quick on dc0 proto tcp/udp from any to any port = 81
|
||
|
||
# Allow traffic in from ISP's DHCP server. This rule must contain
|
||
# the IP address of your ISP's DHCP server as it's the only
|
||
# authorized source to send this packet type. Only necessary for
|
||
# cable or DSL configurations. This rule is not needed for
|
||
# 'user ppp' type connection to the public Internet.
|
||
# This is the same IP address you captured and
|
||
# used in the outbound section.
|
||
pass in quick on dc0 proto udp from z.z.z.z to any port = 68 keep state
|
||
|
||
# Allow in standard www function because I have apache server
|
||
pass in quick on dc0 proto tcp from any to any port = 80 flags S keep state
|
||
|
||
# Allow in non-secure Telnet session from public Internet
|
||
# labeled non-secure because ID/PW passed over public Internet as clear text.
|
||
# Delete this sample group if you do not have telnet server enabled.
|
||
#pass in quick on dc0 proto tcp from any to any port = 23 flags S keep state
|
||
|
||
# Allow in secure FTP, Telnet, and SCP from public Internet
|
||
# This function is using SSH (secure shell)
|
||
pass in quick on dc0 proto tcp from any to any port = 22 flags S keep state
|
||
|
||
# Block and log only first occurrence of all remaining traffic
|
||
# coming into the firewall. The logging of only the first
|
||
# occurrence stops a .denial of service. attack targeted
|
||
# at filling up your log file space.
|
||
# This rule enforces the block all by default logic.
|
||
block in log first quick on dc0 all
|
||
################### End of rules file #####################################</programlisting>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title><acronym>NAT</acronym></title>
|
||
|
||
<indexterm><primary>NAT</primary></indexterm>
|
||
|
||
<indexterm>
|
||
<primary>IP masquerading</primary>
|
||
|
||
<see>NAT</see>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>network address translation</primary>
|
||
|
||
<see>NAT</see>
|
||
</indexterm>
|
||
|
||
<para><acronym>NAT</acronym> stands for Network Address
|
||
Translation. To those familiar with &linux;, this concept is
|
||
called IP Masquerading; <acronym>NAT</acronym> and IP
|
||
Masquerading are the same thing. One of the many things the
|
||
IPF <acronym>NAT</acronym> function enables is the ability to
|
||
have a private Local Area Network (LAN) behind the firewall
|
||
sharing a single ISP assigned IP address on the public
|
||
Internet.</para>
|
||
|
||
<para>You may ask why would someone want to do this. ISPs
|
||
normally assign a dynamic IP address to their non-commercial
|
||
users. Dynamic means that the IP address can be different each
|
||
time you dial in and log on to your ISP, or for cable and DSL
|
||
modem users when you power off and then power on your modems
|
||
you can get assigned a different IP address. This IP address
|
||
is how you are known to the public Internet.</para>
|
||
|
||
<para>Now lets say you have five PCs at home and each one needs
|
||
Internet access. You would have to pay your ISP for an
|
||
individual Internet account for each PC and have five phone
|
||
lines.</para>
|
||
|
||
<para>With <acronym>NAT</acronym> you only need a single account
|
||
with your ISP, then cable your other four PCs to a switch and
|
||
the switch to the NIC in your &os; system which is going to
|
||
service your LAN as a gateway. <acronym>NAT</acronym> will
|
||
automatically translate the private LAN IP address for each
|
||
separate PC on the LAN to the single public IP address as it
|
||
exits the firewall bound for the public Internet. It also does
|
||
the reverse translation for returning packets.</para>
|
||
|
||
<para><acronym>NAT</acronym> is most often accomplished without
|
||
the approval, or knowledge, of your ISP and in most cases is
|
||
grounds for your ISP terminating your account if found out.
|
||
Commercial users pay a lot more for their Internet connection
|
||
and usually get assigned a block of static IP address which
|
||
never change. The ISP also expects and consents to their
|
||
Commercial customers using <acronym>NAT</acronym> for their
|
||
internal private LANs.</para>
|
||
|
||
<para>There is a special range of IP addresses reserved for
|
||
<acronym>NAT</acronym>ed private LAN IP address. According to
|
||
RFC 1918, you can use the following IP ranges for private nets
|
||
which will never be routed directly to the public
|
||
Internet:</para>
|
||
|
||
<informaltable frame="none" pgwide="1">
|
||
<tgroup cols="3">
|
||
<colspec colwidth="1*"/>
|
||
|
||
<colspec colwidth="1*"/>
|
||
|
||
<colspec colwidth="1*"/>
|
||
|
||
<tbody>
|
||
<row>
|
||
<entry>Start IP <hostid role="ipaddr">10.0.0.0</hostid></entry>
|
||
|
||
<entry>-</entry>
|
||
|
||
<entry>Ending IP <hostid role="ipaddr">10.255.255.255</hostid></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Start IP <hostid role="ipaddr">172.16.0.0</hostid></entry>
|
||
|
||
<entry>-</entry>
|
||
|
||
<entry>Ending IP <hostid role="ipaddr">172.31.255.255</hostid></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Start IP <hostid role="ipaddr">192.168.0.0</hostid></entry>
|
||
|
||
<entry>-</entry>
|
||
|
||
<entry>Ending IP <hostid role="ipaddr">192.168.255.255</hostid></entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</informaltable>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IP<acronym>NAT</acronym></title>
|
||
|
||
<indexterm>
|
||
<primary>NAT</primary>
|
||
|
||
<secondary>and IPFILTER</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm><primary><command>ipnat</command></primary></indexterm>
|
||
|
||
<para><acronym>NAT</acronym> rules are loaded by using the
|
||
<command>ipnat</command> command. Typically the
|
||
<acronym>NAT</acronym> rules are stored in
|
||
<filename>/etc/ipnat.rules</filename>. See &man.ipnat.1; for
|
||
details.</para>
|
||
|
||
<para>When changing the <acronym>NAT</acronym> rules after
|
||
<acronym>NAT</acronym> has been started, make your changes to
|
||
the file containing the NAT rules, then run ipnat command with
|
||
the <option>-CF</option> flags to delete the internal in use
|
||
<acronym>NAT</acronym> rules and flush the contents of the
|
||
translation table of all active entries.</para>
|
||
|
||
<para>To reload the <acronym>NAT</acronym> rules issue a command
|
||
like this:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipnat -CF -f /etc/ipnat.rules</userinput></screen>
|
||
|
||
<para>To display some statistics about your
|
||
<acronym>NAT</acronym>, use this command:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipnat -s</userinput></screen>
|
||
|
||
<para>To list the <acronym>NAT</acronym> table's current
|
||
mappings, use this command:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipnat -l</userinput></screen>
|
||
|
||
<para>To turn verbose mode on, and display information relating
|
||
to rule processing and active rules/table entries:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipnat -v</userinput></screen>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>IP<acronym>NAT</acronym> Rules</title>
|
||
|
||
<para><acronym>NAT</acronym> rules are very flexible and can
|
||
accomplish many different things to fit the needs of commercial
|
||
and home users.</para>
|
||
|
||
<para>The rule syntax presented here has been simplified to what
|
||
is most commonly used in a non-commercial environment. For a
|
||
complete rule syntax description see the &man.ipnat.5; manual
|
||
page.</para>
|
||
|
||
<para>The syntax for a <acronym>NAT</acronym> rule looks
|
||
something like this:</para>
|
||
|
||
<programlisting>map <replaceable>IF</replaceable> <replaceable>LAN_IP_RANGE</replaceable> -> <replaceable>PUBLIC_ADDRESS</replaceable></programlisting>
|
||
|
||
<para>The keyword <literal>map</literal> starts the rule.</para>
|
||
|
||
<para>Replace <replaceable>IF</replaceable> with the external
|
||
interface.</para>
|
||
|
||
<para>The <replaceable>LAN_IP_RANGE</replaceable> is what your
|
||
internal clients use for IP Addressing, usually this is
|
||
something like <hostid
|
||
role="ipaddr">192.168.1.0/24</hostid>.</para>
|
||
|
||
<para>The <replaceable>PUBLIC_ADDRESS</replaceable> can either
|
||
be the external IP address or the special keyword
|
||
<literal>0/32</literal>, which means to use the IP address
|
||
assigned to <replaceable>IF</replaceable>.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>How <acronym>NAT</acronym> works</title>
|
||
|
||
<para>A packet arrives at the firewall from the LAN with a public
|
||
destination. It passes through the outbound filter rules,
|
||
<acronym>NAT</acronym> gets his turn at the packet and applies
|
||
its rules top down, first matching rule wins.
|
||
<acronym>NAT</acronym> tests each of its rules against the
|
||
packets interface name and source IP address. When a packets
|
||
interface name matches a <acronym>NAT</acronym> rule then the
|
||
[source IP address, i.e. private LAN IP address] of the packet
|
||
is checked to see if it falls within the IP address range
|
||
specified to the left of the arrow symbol on the
|
||
<acronym>NAT</acronym> rule. On a match the packet has its
|
||
source IP address rewritten with the public IP address
|
||
obtained by the <literal>0/32</literal> keyword.
|
||
<acronym>NAT</acronym> posts a entry in its internal
|
||
<acronym>NAT</acronym> table so when the packet returns from
|
||
the public Internet it can be mapped back to its original
|
||
private IP address and then passed to the filter rules for
|
||
processing.</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Enabling IP<acronym>NAT</acronym></title>
|
||
|
||
<para>To enable IP<acronym>NAT</acronym> add these statements to
|
||
<filename>/etc/rc.conf</filename>.</para>
|
||
|
||
<para>To enable your machine to route traffic between
|
||
interfaces:</para>
|
||
|
||
<programlisting>gateway_enable="YES"</programlisting>
|
||
|
||
<para>To start IP<acronym>NAT</acronym> automatically each
|
||
time:</para>
|
||
|
||
<programlisting>ipnat_enable="YES"</programlisting>
|
||
|
||
<para>To specify where to load the IP<acronym>NAT</acronym> rules
|
||
from:</para>
|
||
|
||
<programlisting>ipnat_rules="/etc/ipnat.rules"</programlisting>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title><acronym>NAT</acronym> for a very large LAN</title>
|
||
|
||
<para>For networks that have large numbers of PC's on the LAN or
|
||
networks with more than a single LAN, the process of funneling
|
||
all those private IP addresses into a single public IP address
|
||
becomes a resource problem that may cause problems with the
|
||
same port numbers being used many times across many
|
||
<acronym>NAT</acronym>ed LAN PC's, causing collisions. There
|
||
are two ways to relieve this resource problem.</para>
|
||
|
||
<sect3>
|
||
<title>Assigning Ports to Use</title>
|
||
|
||
<!-- What does it mean ? Is there something missing ?-->
|
||
<!-- XXXBLAH <- Apparently you can't start a sect
|
||
with a <programlisting> tag ?-->
|
||
|
||
<para>A normal NAT rule would look like:</para>
|
||
|
||
<programlisting>map dc0 192.168.1.0/24 -> 0/32</programlisting>
|
||
|
||
<para>In the above rule the packet's source port is unchanged
|
||
as the packet passes through IP<acronym>NAT</acronym>. By
|
||
adding the portmap keyword you can tell
|
||
IP<acronym>NAT</acronym> to only use source ports in a range.
|
||
For example the following rule will tell
|
||
IP<acronym>NAT</acronym> to modify the source port to be
|
||
within that range:</para>
|
||
|
||
<programlisting>map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:60000</programlisting>
|
||
|
||
<para>Additionally we can make things even easier by using the
|
||
<literal>auto</literal> keyword to tell
|
||
IP<acronym>NAT</acronym> to determine by itself which ports
|
||
are available to use:</para>
|
||
|
||
<programlisting>map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp auto</programlisting>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Using a pool of public addresses</title>
|
||
|
||
<para>In very large LANs there comes a point where there are
|
||
just too many LAN addresses to fit into a single public
|
||
address. By changing the following rule:</para>
|
||
|
||
<programlisting>map dc0 192.168.1.0/24 -> 204.134.75.1</programlisting>
|
||
|
||
<para>Currently this rule maps all connections through <hostid
|
||
role="ipaddr">204.134.75.1</hostid>. This can be changed
|
||
to specify a range:</para>
|
||
|
||
<programlisting>map dc0 192.168.1.0/24 -> 204.134.75.1-10</programlisting>
|
||
|
||
<para>Or a subnet using CIDR notation such as:</para>
|
||
|
||
<programlisting>map dc0 192.168.1.0/24 -> 204.134.75.0/24</programlisting>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Port Redirection</title>
|
||
|
||
<para>A very common practice is to have a web server, email
|
||
server, database server and DNS server each segregated to a
|
||
different PC on the LAN. In this case the traffic from these
|
||
servers still have to be <acronym>NAT</acronym>ed, but there
|
||
has to be some way to direct the inbound traffic to the
|
||
correct LAN PCs. IP<acronym>NAT</acronym> has the redirection
|
||
facilities of <acronym>NAT</acronym> to solve this problem.
|
||
Lets say you have your web server on LAN address <hostid
|
||
role="ipaddr">10.0.10.25</hostid> and your single public IP
|
||
address is <hostid role="ipaddr">20.20.20.5</hostid> you would
|
||
code the rule like this:</para>
|
||
|
||
<programlisting>rdr dc0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80</programlisting>
|
||
|
||
<para>or:</para>
|
||
|
||
<programlisting>rdr dc0 0/32 port 80 -> 10.0.10.25 port 80</programlisting>
|
||
|
||
<para>or for a LAN DNS Server on LAN address of <hostid
|
||
role="ipaddr">10.0.10.33</hostid> that needs to receive
|
||
public DNS requests:</para>
|
||
|
||
<programlisting>rdr dc0 20.20.20.5/32 port 53 -> 10.0.10.33 port 53 udp</programlisting>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>FTP and <acronym>NAT</acronym></title>
|
||
|
||
<para>FTP is a dinosaur left over from the time before the
|
||
Internet as it is known today, when research universities were
|
||
leased lined together and FTP was used to share files among
|
||
research Scientists. This was a time when data security was
|
||
not a consideration. Over the years the FTP protocol became
|
||
buried into the backbone of the emerging Internet and its
|
||
username and password being sent in clear text was never
|
||
changed to address new security concerns. FTP has two flavors,
|
||
it can run in active mode or passive mode. The difference is
|
||
in how the data channel is acquired. Passive mode is more
|
||
secure as the data channel is acquired be the ordinal ftp
|
||
session requester. For a real good explanation of FTP and the
|
||
different modes see <ulink
|
||
url="http://www.slacksite.com/other/ftp.html"></ulink>.</para>
|
||
|
||
<sect3>
|
||
<title>IP<acronym>NAT</acronym> Rules</title>
|
||
|
||
<para>IP<acronym>NAT</acronym> has a special built in FTP proxy
|
||
option which can be specified on the <acronym>NAT</acronym>
|
||
map rule. It can monitor all outbound packet traffic for FTP
|
||
active or passive start session requests and dynamically
|
||
create temporary filter rules containing only the port number
|
||
really in use for the data channel. This eliminates the
|
||
security risk FTP normally exposes the firewall to from
|
||
having large ranges of high order port numbers open.</para>
|
||
|
||
<para>This rule will handle all the traffic for the internal
|
||
LAN:</para>
|
||
|
||
<programlisting>map dc0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp</programlisting>
|
||
|
||
<para>This rule handles the FTP traffic from the
|
||
gateway:</para>
|
||
|
||
<programlisting>map dc0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp</programlisting>
|
||
|
||
<para>This rule handles all non-FTP traffic from the internal
|
||
LAN:</para>
|
||
|
||
<programlisting>map dc0 10.0.10.0/29 -> 0/32</programlisting>
|
||
|
||
<para>The FTP map rule goes before our regular map rule. All
|
||
packets are tested against the first rule from the top.
|
||
Matches on interface name, then private LAN source IP
|
||
address, and then is it a FTP packet. If all that matches
|
||
then the special FTP proxy creates temp filter rules to let
|
||
the FTP session packets pass in and out, in addition to also
|
||
<acronym>NAT</acronym>ing the FTP packets. All LAN packets
|
||
that are not FTP do not match the first rule and fall
|
||
through to the third rule and are tested, matching on
|
||
interface and source IP, then are
|
||
<acronym>NAT</acronym>ed.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>IP<acronym>NAT</acronym> FTP Filter Rules</title>
|
||
|
||
<para>Only one filter rule is needed for FTP if the
|
||
<acronym>NAT</acronym> FTP proxy is used.</para>
|
||
|
||
<para>Without the FTP Proxy you will need the following three
|
||
rules:</para>
|
||
|
||
<programlisting># Allow out LAN PC client FTP to public Internet
|
||
# Active and passive modes
|
||
pass out quick on rl0 proto tcp from any to any port = 21 flags S keep state
|
||
|
||
# Allow out passive mode data channel high order port numbers
|
||
pass out quick on rl0 proto tcp from any to any port > 1024 flags S keep state
|
||
|
||
# Active mode let data channel in from FTP server
|
||
pass in quick on rl0 proto tcp from any to any port = 20 flags S keep state</programlisting>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>FTP <acronym>NAT</acronym> Proxy Bug</title>
|
||
|
||
<para>As of &os; 4.9 which includes IPFILTER version 3.4.31
|
||
the FTP proxy works as documented during the FTP session
|
||
until the session is told to close. When the close happens
|
||
packets returning from the remote FTP server are blocked and
|
||
logged coming in on port 21. The <acronym>NAT</acronym>
|
||
FTP/proxy appears to remove its temp rules prematurely,
|
||
before receiving the response from the remote FTP server
|
||
acknowledging the close. A problem report was posted to the
|
||
IPF mailing list.</para>
|
||
|
||
<para>The solution is to add a filter rule to get rid of these
|
||
unwanted log messages or do nothing and ignore FTP inbound
|
||
error messages in your log. Most people do not use outbound
|
||
FTP too often.</para>
|
||
|
||
<programlisting>block in quick on rl0 proto tcp from any to any port = 21</programlisting>
|
||
</sect3>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 id="firewalls-ipfw">
|
||
<title>IPFW</title>
|
||
|
||
<indexterm>
|
||
<primary>firewall</primary>
|
||
|
||
<secondary>IPFW</secondary>
|
||
</indexterm>
|
||
|
||
<note>
|
||
<para>此一節的內容仍在陸續補充、更新,所以本節內容可能並未完全符合現況。.</para>
|
||
</note>
|
||
|
||
<para>The IPFIREWALL (IPFW) is a &os; sponsored firewall software
|
||
application authored and maintained by &os; volunteer staff
|
||
members. It uses the legacy stateless rules and a legacy rule
|
||
coding technique to achieve what is referred to as Simple
|
||
Stateful logic.</para>
|
||
|
||
<para>The IPFW sample rule set (found in
|
||
<filename>/etc/rc.firewall</filename>) in the standard &os;
|
||
install is rather simple and it is not expected that it used
|
||
directly without modifications. The example does not use
|
||
stateful filtering, which is beneficial in most setups, so it
|
||
will not be used as base for this section.</para>
|
||
|
||
<para>The IPFW stateless rule syntax is empowered with technically
|
||
sophisticated selection capabilities which far surpasses the
|
||
knowledge level of the customary firewall installer. IPFW is
|
||
targeted at the professional user or the advanced technical
|
||
computer hobbyist who have advanced packet selection
|
||
requirements. A high degree of detailed knowledge into how
|
||
different protocols use and create their unique packet header
|
||
information is necessary before the power of the IPFW rules can
|
||
be unleashed. Providing that level of explanation is out of the
|
||
scope of this section of the handbook.</para>
|
||
|
||
<para>IPFW is composed of seven components, the primary component
|
||
is the kernel firewall filter rule processor and its integrated
|
||
packet accounting facility, the logging facility, the 'divert'
|
||
rule which triggers the <acronym>NAT</acronym> facility, and the
|
||
advanced special purpose facilities, the dummynet traffic shaper
|
||
facilities, the 'fwd rule' forward facility, the bridge
|
||
facility, and the ipstealth facility.</para>
|
||
|
||
<sect2 id="firewalls-ipfw-enable">
|
||
<title>Enabling IPFW</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFW</primary>
|
||
|
||
<secondary>enabling</secondary>
|
||
</indexterm>
|
||
|
||
<para>IPFW is included in the basic &os; install as a separate
|
||
run time loadable module. The system will dynamically load the
|
||
kernel module when the <filename>rc.conf</filename> statement
|
||
<literal>firewall_enable="YES"</literal> is used. You do not
|
||
need to compile IPFW into the &os; kernel unless you want
|
||
<acronym>NAT</acronym> function enabled.</para>
|
||
|
||
<para>After rebooting your system with
|
||
<literal>firewall_enable="YES"</literal> in
|
||
<filename>rc.conf</filename> the following white highlighted
|
||
message is displayed on the screen as part of the boot
|
||
process:</para>
|
||
|
||
<screen>ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to deny, logging disabled</screen>
|
||
|
||
<para>The loadable module does have logging ability
|
||
compiled in. To enable logging and set the verbose logging
|
||
limit, there is a knob you can set in
|
||
<filename>/etc/sysctl.conf</filename> by adding these
|
||
statements, logging will be enabled on future reboots:</para>
|
||
|
||
<programlisting>net.inet.ip.fw.verbose=1
|
||
net.inet.ip.fw.verbose_limit=5</programlisting>
|
||
</sect2>
|
||
|
||
<sect2 id="firewalls-ipfw-kernel">
|
||
<title>Kernel Options</title>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFIREWALL</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFIREWALL_VERBOSE</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFIREWALL_VERBOSE_LIMIT</secondary>
|
||
</indexterm>
|
||
|
||
<indexterm>
|
||
<primary>IPFW</primary>
|
||
|
||
<secondary>kernel options</secondary>
|
||
</indexterm>
|
||
|
||
<para>It is not a mandatory requirement that you enable IPFW by
|
||
compiling the following options into the &os; kernel unless
|
||
you need <acronym>NAT</acronym> function. It is presented here
|
||
as background information.</para>
|
||
|
||
<programlisting>options IPFIREWALL</programlisting>
|
||
|
||
<para>This option enables IPFW as part of the kernel</para>
|
||
|
||
<programlisting>options IPFIREWALL_VERBOSE</programlisting>
|
||
|
||
<para>Enables logging of packets that pass through IPFW and have
|
||
the 'log' keyword specified in the rule set.</para>
|
||
|
||
<programlisting>options IPFIREWALL_VERBOSE_LIMIT=5</programlisting>
|
||
|
||
<para>Limits the number of packets logged through &man.syslogd.8;
|
||
on a per entry basis. You may wish to use this option in
|
||
hostile environments which you want to log firewall activity.
|
||
This will close a possible denial of service attack via syslog
|
||
flooding.</para>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPFIREWALL_DEFAULT_TO_ACCEPT</secondary>
|
||
</indexterm>
|
||
|
||
<programlisting>options IPFIREWALL_DEFAULT_TO_ACCEPT</programlisting>
|
||
|
||
<para>This option will allow everything to pass through the
|
||
firewall by default, which is a good idea when you are first
|
||
setting up your firewall.</para>
|
||
|
||
<programlisting>options IPV6FIREWALL
|
||
options IPV6FIREWALL_VERBOSE
|
||
options IPV6FIREWALL_VERBOSE_LIMIT
|
||
options IPV6FIREWALL_DEFAULT_TO_ACCEPT</programlisting>
|
||
|
||
<para>These options are exactly the same as the IPv4 options but
|
||
they are for IPv6. If you do not use IPv6 you might want to
|
||
use IPV6FIREWALL without any rules to block all IPv6</para>
|
||
|
||
<indexterm>
|
||
<primary>kernel options</primary>
|
||
|
||
<secondary>IPDIVERT</secondary>
|
||
</indexterm>
|
||
|
||
<programlisting>options IPDIVERT</programlisting>
|
||
|
||
<para>This enables the use of <acronym>NAT</acronym>
|
||
functionality.</para>
|
||
|
||
<note>
|
||
<para>If you do not include IPFIREWALL_DEFAULT_TO_ACCEPT or set
|
||
your rules to allow incoming packets you will block all
|
||
packets going to and from this machine.</para>
|
||
</note>
|
||
</sect2>
|
||
|
||
<sect2 id="firewalls-ipfw-rc">
|
||
<title><filename>/etc/rc.conf</filename> Options</title>
|
||
|
||
<para>If you do not have IPFW compiled into your kernel you will
|
||
need to load it with the following statement in your
|
||
<filename>/etc/rc.conf</filename>:</para>
|
||
|
||
<programlisting>firewall_enable="YES"</programlisting>
|
||
|
||
<para>Set the script to run to activate your rules:</para>
|
||
|
||
<programlisting>firewall_script="/etc/ipfw.rules"</programlisting>
|
||
|
||
<para>Enable logging:</para>
|
||
|
||
<programlisting>firewall_logging="YES"</programlisting>
|
||
|
||
<warning>
|
||
<para>The only thing that the
|
||
<varname>firewall_logging</varname> variable will do is
|
||
setting the <varname>net.inet.ip.fw.verbose</varname> sysctl
|
||
variable to the value of <literal>1</literal> (see <xref
|
||
linkend="firewalls-ipfw-enable"/>). There is no
|
||
<filename>rc.conf</filename> variable to set log limitations,
|
||
but it can be set via sysctl variable, manually or from the
|
||
<filename>/etc/sysctl.conf</filename> file:</para>
|
||
|
||
<programlisting>net.inet.ip.fw.verbose_limit=5</programlisting>
|
||
</warning>
|
||
|
||
<para>If your machine is acting as a gateway, i.e. providing
|
||
Network Address Translation (NAT) via &man.natd.8;, please
|
||
refer to <xref linkend="network-natd"/> for information
|
||
regarding the required <filename>/etc/rc.conf</filename>
|
||
options.</para>
|
||
</sect2>
|
||
|
||
<sect2 id="firewalls-ipfw-cmd">
|
||
<title>The IPFW Command</title>
|
||
|
||
<indexterm><primary><command>ipfw</command></primary></indexterm>
|
||
|
||
<para>The ipfw command is the normal vehicle for making manual
|
||
single rule additions or deletions to the firewall active
|
||
internal rules while it is running. The problem with using
|
||
this method is once your system is shutdown or halted all the
|
||
rules you added or changed or deleted are lost. Writing all
|
||
your rules in a file and using that file to load the rules at
|
||
boot time, or to replace in mass the currently running firewall
|
||
rules with changes you made to the files content is the
|
||
recommended method used here.</para>
|
||
|
||
<para>The ipfw command is still a very useful to display the
|
||
running firewall rules to the console screen. The IPFW
|
||
accounting facility dynamically creates a counter for each
|
||
rule that counts each packet that matches the rule. During the
|
||
process of testing a rule, listing the rule with its counter
|
||
is the one of the ways of determining if the rule is
|
||
functioning.</para>
|
||
|
||
<para>To list all the rules in sequence:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw list</userinput></screen>
|
||
|
||
<para>To list all the rules with a time stamp of when the last
|
||
time the rule was matched:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw -t list</userinput></screen>
|
||
|
||
<para>To list the accounting information, packet count for
|
||
matched rules along with the rules themselves. The first
|
||
column is the rule number, followed by the number of outgoing
|
||
matched packets, followed by the number of incoming matched
|
||
packets, and then the rule itself.</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw -a list</userinput></screen>
|
||
|
||
<para>List the dynamic rules in addition to the static
|
||
rules:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw -d list</userinput></screen>
|
||
|
||
<para>Also show the expired dynamic rules:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw -d -e list</userinput></screen>
|
||
|
||
<para>Zero the counters:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw zero</userinput></screen>
|
||
|
||
<para>Zero the counters for just rule
|
||
<replaceable>NUM</replaceable>:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw zero NUM</userinput></screen>
|
||
</sect2>
|
||
|
||
<sect2 id="firewalls-ipfw-rules">
|
||
<title>IPFW Rule Sets</title>
|
||
|
||
<!-- XXX: looks incorrect (and duplicated 2 times in this chapter):
|
||
1. Packet can be processed two times depend of firewall
|
||
firewall configuration, but "return trip back" is
|
||
another packet.
|
||
2. "Each TCP/IP service ... is predefined by its protocol ..."
|
||
- this shold be about packet and it's parameters
|
||
(source/destination address and port). -->
|
||
|
||
<para>A rule set is a group of ipfw rules coded to allow or deny
|
||
packets based on the values contained in the packet. The
|
||
bi-directional exchange of packets between hosts comprises a
|
||
session conversation. The firewall rule set processes the
|
||
packet twice: once on its arrival from the public Internet host
|
||
and again as it leaves for its return trip back to the public
|
||
Internet host. Each tcp/ip service (i.e. telnet, www, mail,
|
||
etc.) is predefined by its protocol, and port number. This is
|
||
the basic selection criteria used to create rules which will
|
||
allow or deny services.</para>
|
||
|
||
<indexterm>
|
||
<primary>IPFW</primary>
|
||
|
||
<secondary>rule processing order</secondary>
|
||
</indexterm>
|
||
|
||
<!-- Needs rewording to include note below -->
|
||
|
||
<para>When a packet enters the firewall it is compared against
|
||
the first rule in the rule set and progress one rule at a time
|
||
moving from top to bottom of the set in ascending rule number
|
||
sequence order. When the packet matches a rule selection
|
||
parameters, the rules action field value is executed and the
|
||
search of the rule set terminates for that packet. This is
|
||
referred to as 「the first match wins」 search
|
||
method. If the packet does not match any of the rules, it gets
|
||
caught by the mandatory ipfw default rule, number 65535 which
|
||
denies all packets and discards them without any reply back to
|
||
the originating destination.</para>
|
||
|
||
<note>
|
||
<para>The search continues after <literal>count</literal>,
|
||
<literal>skipto</literal> and <literal>tee</literal>
|
||
rules.</para>
|
||
</note>
|
||
|
||
<para>The instructions contained here are based on using rules
|
||
that contain the stateful 'keep state', 'limit', 'in'/'out',
|
||
and via options. This is the basic framework for coding an
|
||
inclusive type firewall rule set.</para>
|
||
|
||
<!-- XXX: something like this already in
|
||
<xref linkend="firewalls-concepts"/>
|
||
AND: the para below is repeated 3 times in this chapter. -->
|
||
|
||
<para>An inclusive firewall only allows services matching the
|
||
rules through. This way you can control what services can
|
||
originate behind the firewall destine for the public Internet
|
||
and also control the services which can originate from the
|
||
public Internet accessing your private network. Everything
|
||
else is denied by default design. Inclusive firewalls are
|
||
much, much more secure than exclusive firewall rule sets and
|
||
is the only rule set type covered here in.</para>
|
||
|
||
<warning>
|
||
<para>When working with the firewall rules be careful, you can
|
||
end up locking your self out.</para>
|
||
</warning>
|
||
|
||
<sect3 id="firewalls-ipfw-rules-syntax">
|
||
<title>Rule Syntax</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFW</primary>
|
||
|
||
<secondary>rule syntax</secondary>
|
||
</indexterm>
|
||
|
||
<para>The rule syntax presented here has been simplified to
|
||
what is necessary to create a standard inclusive type
|
||
firewall rule set. For a complete rule syntax description
|
||
see the &man.ipfw.8; manual page.</para>
|
||
|
||
<para>Rules contain keywords: these keywords have to be coded
|
||
in a specific order from left to right on the line. Keywords
|
||
are identified in bold type. Some keywords have sub-options
|
||
which may be keywords them selves and also include more
|
||
sub-options.</para>
|
||
|
||
<para><literal>#</literal> is used to mark the start of a
|
||
comment and may appear at the end of a rule line or on its
|
||
own lines. Blank lines are ignored.</para>
|
||
|
||
<para><replaceable>CMD RULE_NUMBER ACTION LOGGING SELECTION
|
||
STATEFUL</replaceable></para>
|
||
|
||
<sect4>
|
||
<title>CMD</title>
|
||
|
||
<para>Each new rule has to be prefixed with
|
||
<parameter>add</parameter> to add the
|
||
rule to the internal table.</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title>RULE_NUMBER</title>
|
||
|
||
<para>Each rule has to have a rule number to go with
|
||
it.</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title>ACTION</title>
|
||
|
||
<para>A rule can be associated with one of the following
|
||
actions, which will be executed when the packet matches
|
||
the selection criterion of the rule.</para>
|
||
|
||
<para><parameter>allow | accept | pass |
|
||
permit</parameter></para>
|
||
|
||
<para>These all mean the same thing which is to allow packets
|
||
that match the rule to exit the firewall rule processing.
|
||
The search terminates at this rule.</para>
|
||
|
||
<para><parameter>check-state</parameter></para>
|
||
|
||
<para>Checks the packet against the dynamic rules table. If
|
||
a match is found, execute the action associated with the
|
||
rule which generated this dynamic rule, otherwise move to
|
||
the next rule. The check-state rule does not have
|
||
selection criterion. If no check-state rule is present in
|
||
the rule set, the dynamic rules table is checked at the
|
||
first keep-state or limit rule.</para>
|
||
|
||
<para><parameter>deny | drop</parameter></para>
|
||
|
||
<para>Both words mean the same thing which is to discard
|
||
packets that match this rule. The search
|
||
terminates.</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title>Logging</title>
|
||
|
||
<para><parameter>log</parameter> or
|
||
<parameter>logamount</parameter></para>
|
||
|
||
<para>When a packet matches a rule with the log keyword, a
|
||
message will be logged to syslogd with a facility name of
|
||
SECURITY. The logging only occurs if the number of
|
||
packets logged so far for that particular rule does not
|
||
exceed the logamount parameter. If no logamount is
|
||
specified, the limit is taken from the sysctl variable
|
||
net.inet.ip.fw.verbose_limit. In both cases, a value of
|
||
zero removes the logging limit. Once the limit is
|
||
reached, logging can be re-enabled by clearing the
|
||
logging counter or the packet counter for that rule, see
|
||
the ipfw reset log command.</para>
|
||
|
||
<note>
|
||
<para>Logging is done after
|
||
all other packet matching conditions have been
|
||
successfully verified, and before performing the final
|
||
action (accept, deny) on the packet. It is up to you to
|
||
decide which rules you want to enable logging on.</para>
|
||
</note>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title>Selection</title>
|
||
|
||
<para>The keywords described in this section are used to
|
||
describe attributes of the packet to be interrogated when
|
||
determining whether rules match the packet or not.
|
||
The following general-purpose attributes are provided for
|
||
matching, and must be used in this order:</para>
|
||
|
||
<para><parameter>udp | tcp | icmp</parameter></para>
|
||
|
||
<para>or any protocol names found in
|
||
<filename>/etc/protocols</filename> are recognized and may
|
||
be used. The value specified is protocol to be matched
|
||
against. This is a mandatory requirement.</para>
|
||
|
||
<para><parameter>from src to dst</parameter></para>
|
||
|
||
<para>The from and to keywords are used to match against IP
|
||
addresses. Rules must specify BOTH source and destination
|
||
parameters. <literal>any</literal> is a special keyword
|
||
that matches any IP address. <literal>me</literal> is a
|
||
special keyword that matches any IP address configured on
|
||
an interface in your &os; system to represent the PC the
|
||
firewall is running on (i.e. this box) as in 'from me to
|
||
any' or 'from any to me' or 'from 0.0.0.0/0 to any' or
|
||
'from any to 0.0.0.0/0' or 'from 0.0.0.0 to any' or 'from
|
||
any to 0.0.0.0' or 'from me to 0.0.0.0'. IP addresses are
|
||
specified as a dotted IP address numeric form/mask-length,
|
||
or as single dotted IP address numeric form. This is a
|
||
mandatory requirement. See this link for help on writing
|
||
mask-lengths. <ulink
|
||
url="http://jodies.de/ipcalc"></ulink></para>
|
||
|
||
<para><parameter>port number</parameter></para>
|
||
|
||
<para>For protocols which support port numbers (such as
|
||
<acronym>TCP</acronym> and UDP). It is mandatory that you
|
||
code the port number of the service you want to match
|
||
on. Service names (from
|
||
<filename>/etc/services</filename>) may be used instead of
|
||
numeric port values.</para>
|
||
|
||
<para><parameter>in | out</parameter></para>
|
||
|
||
<para>Matches incoming or outgoing packets, respectively.
|
||
The in and out are keywords and it is mandatory that you
|
||
code one or the other as part of your rule matching
|
||
criterion.</para>
|
||
|
||
<para><parameter>via IF</parameter></para>
|
||
|
||
<para>Matches packets going through the interface specified
|
||
by exact name. The <literal>via</literal> keyword causes
|
||
the interface to always be checked as part of the match
|
||
process.</para>
|
||
|
||
<para><parameter>setup</parameter></para>
|
||
|
||
<para>This is a mandatory keyword that identifies the session
|
||
start request for <acronym>TCP</acronym> packets.</para>
|
||
|
||
<para><parameter>keep-state</parameter></para>
|
||
|
||
<para>This is a mandatory> keyword. Upon a match, the
|
||
firewall will create a dynamic rule, whose default behavior
|
||
is to match bidirectional traffic between source and
|
||
destination IP/port using the same protocol.</para>
|
||
|
||
<para><parameter>limit {src-addr | src-port | dst-addr |
|
||
dst-port}</parameter></para>
|
||
|
||
<para>The firewall will only allow
|
||
<replaceable>N</replaceable> connections with the same set
|
||
of parameters as specified in the rule. One or more of
|
||
source and destination addresses and ports can be
|
||
specified. The 'limit' and 'keep-state' can not be used on
|
||
same rule. Limit provides the same stateful function as
|
||
'keep-state' plus its own functions.</para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Stateful Rule Option</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFW</primary>
|
||
|
||
<secondary>stateful filtering</secondary>
|
||
</indexterm>
|
||
|
||
<!-- XXX: duplicated -->
|
||
|
||
<para>Stateful filtering treats traffic as a bi-directional
|
||
exchange of packets comprising a session conversation. It
|
||
has the interrogation abilities to determine if the session
|
||
conversation between the originating sender and the
|
||
destination are following the valid procedure of
|
||
bi-directional packet exchange. Any packets that do not
|
||
properly fit the session conversation template are
|
||
automatically rejected as impostors.</para>
|
||
|
||
<para>'check-state' is used to identify where in the IPFW rules
|
||
set the packet is to be tested against the dynamic rules
|
||
facility. On a match the packet exits the firewall to
|
||
continue on its way and a new rule is dynamic created for
|
||
the next anticipated packet being exchanged during this
|
||
bi-directional session conversation. On a no match the
|
||
packet advances to the next rule in the rule set for
|
||
testing.</para>
|
||
|
||
<para>The dynamic rules facility is vulnerable to resource
|
||
depletion from a SYN-flood attack which would open a huge
|
||
number of dynamic rules. To counter this attack, &os;
|
||
version 4.5 added another new option named limit. This
|
||
option is used to limit the number of simultaneous session
|
||
conversations by interrogating the rules source or
|
||
destinations fields as directed by the limit option and
|
||
using the packet's IP address found there, in a search of
|
||
the open dynamic rules counting the number of times this
|
||
rule and IP address combination occurred, if this count is
|
||
greater that the value specified on the limit option, the
|
||
packet is discarded.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Logging Firewall Messages</title>
|
||
|
||
<indexterm>
|
||
<primary>IPFW</primary>
|
||
|
||
<secondary>logging</secondary>
|
||
</indexterm>
|
||
|
||
<para>The benefits of logging are obvious: it provides the
|
||
ability to review after the fact the rules you activated
|
||
logging on which provides information like, what packets had
|
||
been dropped, what addresses they came from, where they were
|
||
going, giving you a significant edge in tracking down
|
||
attackers.</para>
|
||
|
||
<para>Even with the logging facility enabled, IPFW will not
|
||
generate any rule logging on it's own. The firewall
|
||
administrator decides what rules in the rule set he wants
|
||
to log and adds the log verb to those rules. Normally only
|
||
deny rules are logged, like the deny rule for incoming
|
||
<acronym>ICMP</acronym> pings. It is very customary to
|
||
duplicate the ipfw default deny everything rule with the
|
||
log verb included as your last rule in the rule set. This
|
||
way you get to see all the packets that did not match any
|
||
of the rules in the rule set.</para>
|
||
|
||
<para>Logging is a two edged sword, if you are not careful, you
|
||
can lose yourself in the over abundance of log data and fill
|
||
your disk up with growing log files. DoS attacks that fill
|
||
up disk drives is one of the oldest attacks around. These
|
||
log message are not only written to syslogd, but also are
|
||
displayed on the root console screen and soon become very
|
||
annoying.</para>
|
||
|
||
<para>The <literal>IPFIREWALL_VERBOSE_LIMIT=5</literal>
|
||
kernel option limits the number of consecutive messages
|
||
sent to the system logger syslogd, concerning the packet
|
||
matching of a given rule. When this option is enabled in
|
||
the kernel, the number of consecutive messages concerning
|
||
a particular rule is capped at the number specified. There
|
||
is nothing to be gained from 200 log messages saying the
|
||
same identical thing. For instance, five consecutive
|
||
messages concerning a particular rule would be logged to
|
||
syslogd, the remainder identical consecutive messages would
|
||
be counted and posted to the syslogd with a phrase like
|
||
this:</para>
|
||
|
||
<programlisting>last message repeated 45 times</programlisting>
|
||
|
||
<para>All logged packets messages are written by default to
|
||
<filename>/var/log/security</filename> file, which is defined
|
||
in the <filename>/etc/syslog.conf</filename> file.</para>
|
||
</sect3>
|
||
|
||
<sect3 id="firewalls-ipfw-rules-script">
|
||
<title>Building a Rule Script</title>
|
||
|
||
<para>Most experienced IPFW users create a file containing the
|
||
rules and code them in a manner compatible with running them
|
||
as a script. The major benefit of doing this is the firewall
|
||
rules can be refreshed in mass without the need of rebooting
|
||
the system to activate the new rules. This method is very
|
||
convenient in testing new rules as the procedure can be
|
||
executed as many times as needed. Being a script, you can
|
||
use symbolic substitution to code frequent used values and
|
||
substitution them in multiple rules. You will see this in
|
||
the following example.</para>
|
||
|
||
<para>The script syntax used here is compatible with the 'sh',
|
||
'csh', 'tcsh' shells. Symbolic substitution fields are
|
||
prefixed with a dollar sign $. Symbolic fields do not
|
||
have the $ prefix. The value to populate the Symbolic
|
||
field must be enclosed to "double quotes".</para>
|
||
|
||
<para>Start your rules file like this:</para>
|
||
|
||
<programlisting>############### start of example ipfw rules script #############
|
||
#
|
||
ipfw -q -f flush # Delete all rules
|
||
# Set defaults
|
||
oif="tun0" # out interface
|
||
odns="192.0.2.11" # ISP's DNS server IP address
|
||
cmd="ipfw -q add " # build rule prefix
|
||
ks="keep-state" # just too lazy to key this each time
|
||
$cmd 00500 check-state
|
||
$cmd 00502 deny all from any to any frag
|
||
$cmd 00501 deny tcp from any to any established
|
||
$cmd 00600 allow tcp from any to any 80 out via $oif setup $ks
|
||
$cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks
|
||
$cmd 00611 allow udp from any to $odns 53 out via $oif $ks
|
||
################### End of example ipfw rules script ############</programlisting>
|
||
|
||
<para>That is all there is to it. The rules are not important
|
||
in this example, how the Symbolic substitution field are
|
||
populated and used are.</para>
|
||
|
||
<para>If the above example was in
|
||
<filename>/etc/ipfw.rules</filename> file, you could reload
|
||
these rules by entering on the command line.</para>
|
||
|
||
<screen>&prompt.root; <userinput>sh /etc/ipfw.rules</userinput></screen>
|
||
|
||
<para>The <filename>/etc/ipfw.rules</filename> file could be
|
||
located anywhere you want and the file could be named any
|
||
thing you would like.</para>
|
||
|
||
<para>The same thing could also be accomplished by running
|
||
these commands by hand:</para>
|
||
|
||
<screen>&prompt.root; <userinput>ipfw -q -f flush</userinput>
|
||
&prompt.root; <userinput>ipfw -q add check-state</userinput>
|
||
&prompt.root; <userinput>ipfw -q add deny all from any to any frag</userinput>
|
||
&prompt.root; <userinput>ipfw -q add deny tcp from any to any established</userinput>
|
||
&prompt.root; <userinput>ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state</userinput>
|
||
&prompt.root; <userinput>ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state</userinput>
|
||
&prompt.root; <userinput>ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state</userinput></screen>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Stateful Ruleset</title>
|
||
|
||
<para>The following non-<acronym>NAT</acronym>ed rule set is an
|
||
example of how to code a very secure 'inclusive' type of
|
||
firewall. An inclusive firewall only allows services
|
||
matching pass rules through and blocks all other by default.
|
||
All firewalls have at the minimum two interfaces which have
|
||
to have rules to allow the firewall to function.</para>
|
||
|
||
<para>All &unix; flavored operating systems, &os; included, are
|
||
designed to use interface <devicename>lo0</devicename> and IP
|
||
address <hostid role="ipaddr">127.0.0.1</hostid> for internal
|
||
communication with in the operating system. The firewall
|
||
rules must contain rules to allow free unmolested movement of
|
||
these special internally used packets.</para>
|
||
|
||
<para>The interface which faces the public Internet, is the one
|
||
which you code your rules to authorize and control access out
|
||
to the public Internet and access requests arriving from the
|
||
public Internet. This can be your ppp
|
||
<devicename>tun0</devicename> interface or your NIC that is
|
||
connected to your DSL or cable modem.</para>
|
||
|
||
<para>In cases where one or more than one NIC are connected to
|
||
a private LANs behind the firewall, those interfaces must
|
||
have rules coded to allow free unmolested movement of
|
||
packets originating from those LAN interfaces.</para>
|
||
|
||
<para>The rules should be first organized into three major
|
||
sections, all the free unmolested interfaces, public
|
||
interface outbound, and the public interface inbound.</para>
|
||
|
||
<para>The order of the rules in each of the public interface
|
||
sections should be in order of the most used rules being
|
||
placed before less often used rules with the last rule in
|
||
the section being a block log all packets on that interface
|
||
and direction.</para>
|
||
|
||
<para>The Outbound section in the following rule set only
|
||
contains 'allow' rules which contain selection values that
|
||
uniquely identify the service that is authorized for public
|
||
Internet access. All the rules have the, proto, port,
|
||
in/out, via and keep state option coded. The 'proto tcp'
|
||
rules have the 'setup' option included to identify the start
|
||
session request as the trigger packet to be posted to the
|
||
keep state stateful table.</para>
|
||
|
||
<para>The Inbound section has all the blocking of undesirable
|
||
packets first for two different reasons. First is these
|
||
things being blocked may be part of an otherwise valid packet
|
||
which may be allowed in by the later authorized service
|
||
rules. Second reason is that by having a rule that
|
||
explicitly blocks selected packets that I receive on an
|
||
infrequent bases and do not want to see in the log, this
|
||
keeps them from being caught by the last rule in the section
|
||
which blocks and logs all packets which have fallen through
|
||
the rules. The last rule in the section which blocks and
|
||
logs all packets is how you create the legal evidence needed
|
||
to prosecute the people who are attacking your system.</para>
|
||
|
||
<para>Another thing you should take note of, is there is no
|
||
response returned for any of the undesirable stuff, their
|
||
packets just get dropped and vanish. This way the attackers
|
||
has no knowledge if his packets have reached your system.
|
||
The less the attackers can learn about your system the more
|
||
secure it is. When you log packets with port numbers you do
|
||
not recognize, look the numbers up in
|
||
<filename>/etc/services/</filename> or go to <ulink
|
||
url="http://www.securitystats.com/tools/portsearch.php"></ulink>
|
||
and do a port number lookup to find what the purpose of that
|
||
port number is. Check out this link for port numbers used by
|
||
Trojans: <ulink
|
||
url="http://www.simovits.com/trojans/trojans.html"></ulink>.</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>An Example Inclusive Ruleset</title>
|
||
|
||
<para>The following non-<acronym>NAT</acronym>ed rule set is a
|
||
complete inclusive type ruleset. You can not go wrong using
|
||
this rule set for you own. Just comment out any pass rules
|
||
for services you do not want. If you see messages in your
|
||
log that you want to stop seeing just add a deny rule in the
|
||
inbound section. You have to change the 'dc0' interface name
|
||
in every rule to the interface name of the NIC that connects
|
||
your system to the public Internet. For user ppp it would be
|
||
'tun0'.</para>
|
||
|
||
<para>You will see a pattern in the usage of these
|
||
rules.</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>All statements that are a request to start a session
|
||
to the public Internet use keep-state.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>All the authorized services that originate from the
|
||
public Internet have the limit option to stop
|
||
flooding.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>All rules use in or out to clarify direction.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>All rules use via interface name to specify the
|
||
interface the packet is traveling over.</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>The following rules go into
|
||
<filename>/etc/ipfw.rules</filename>.</para>
|
||
|
||
<programlisting>################ Start of IPFW rules file ###############################
|
||
# Flush out the list before we begin.
|
||
ipfw -q -f flush
|
||
|
||
# Set rules command prefix
|
||
cmd="ipfw -q add"
|
||
pif="dc0" # public interface name of NIC
|
||
# facing the public Internet
|
||
|
||
#################################################################
|
||
# No restrictions on Inside LAN Interface for private network
|
||
# Not needed unless you have LAN.
|
||
# Change xl0 to your LAN NIC interface name
|
||
#################################################################
|
||
#$cmd 00005 allow all from any to any via xl0
|
||
|
||
#################################################################
|
||
# No restrictions on Loopback Interface
|
||
#################################################################
|
||
$cmd 00010 allow all from any to any via lo0
|
||
|
||
#################################################################
|
||
# Allow the packet through if it has previous been added to the
|
||
# the "dynamic" rules table by a allow keep-state statement.
|
||
#################################################################
|
||
$cmd 00015 check-state
|
||
|
||
#################################################################
|
||
# Interface facing Public Internet (Outbound Section)
|
||
# Interrogate session start requests originating from behind the
|
||
# firewall on the private network or from this gateway server
|
||
# destine for the public Internet.
|
||
#################################################################
|
||
|
||
# Allow out access to my ISP's Domain name server.
|
||
# x.x.x.x must be the IP address of your ISP.s DNS
|
||
# Dup these lines if your ISP has more than one DNS server
|
||
# Get the IP addresses from /etc/resolv.conf file
|
||
$cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state
|
||
$cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state
|
||
|
||
# Allow out access to my ISP's DHCP server for cable/DSL configurations.
|
||
# This rule is not needed for .user ppp. connection to the public Internet.
|
||
# so you can delete this whole group.
|
||
# Use the following rule and check log for IP address.
|
||
# Then put IP address in commented out rule & delete first rule
|
||
$cmd 00120 allow log udp from any to any 67 out via $pif keep-state
|
||
#$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state
|
||
|
||
# Allow out non-secure standard www function
|
||
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state
|
||
|
||
# Allow out secure www function https over TLS SSL
|
||
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state
|
||
|
||
# Allow out send & get email function
|
||
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
|
||
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state
|
||
|
||
# Allow out FBSD (make install & CVSUP) functions
|
||
# Basically give user root "GOD" privileges.
|
||
$cmd 00240 allow tcp from me to any out via $pif setup keep-state uid root
|
||
|
||
# Allow out ping
|
||
$cmd 00250 allow icmp from any to any out via $pif keep-state
|
||
|
||
# Allow out Time
|
||
$cmd 00260 allow tcp from any to any 37 out via $pif setup keep-state
|
||
|
||
# Allow out nntp news (i.e. news groups)
|
||
$cmd 00270 allow tcp from any to any 119 out via $pif setup keep-state
|
||
|
||
# Allow out secure FTP, Telnet, and SCP
|
||
# This function is using SSH (secure shell)
|
||
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state
|
||
|
||
# Allow out whois
|
||
$cmd 00290 allow tcp from any to any 43 out via $pif setup keep-state
|
||
|
||
# deny and log everything else that.s trying to get out.
|
||
# This rule enforces the block all by default logic.
|
||
$cmd 00299 deny log all from any to any out via $pif
|
||
|
||
#################################################################
|
||
# Interface facing Public Internet (Inbound Section)
|
||
# Interrogate packets originating from the public Internet
|
||
# destine for this gateway server or the private network.
|
||
#################################################################
|
||
|
||
# Deny all inbound traffic from non-routable reserved address spaces
|
||
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
|
||
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
|
||
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
|
||
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif #loopback
|
||
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif #loopback
|
||
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
|
||
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs
|
||
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster interconnect
|
||
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
|
||
|
||
# Deny public pings
|
||
$cmd 00310 deny icmp from any to any in via $pif
|
||
|
||
# Deny ident
|
||
$cmd 00315 deny tcp from any to any 113 in via $pif
|
||
|
||
# Deny all Netbios service. 137=name, 138=datagram, 139=session
|
||
# Netbios is MS/Windows sharing services.
|
||
# Block MS/Windows hosts2 name server requests 81
|
||
$cmd 00320 deny tcp from any to any 137 in via $pif
|
||
$cmd 00321 deny tcp from any to any 138 in via $pif
|
||
$cmd 00322 deny tcp from any to any 139 in via $pif
|
||
$cmd 00323 deny tcp from any to any 81 in via $pif
|
||
|
||
# Deny any late arriving packets
|
||
$cmd 00330 deny all from any to any frag in via $pif
|
||
|
||
# Deny ACK packets that did not match the dynamic rule table
|
||
$cmd 00332 deny tcp from any to any established in via $pif
|
||
|
||
# Allow traffic in from ISP's DHCP server. This rule must contain
|
||
# the IP address of your ISP.s DHCP server as it.s the only
|
||
# authorized source to send this packet type.
|
||
# Only necessary for cable or DSL configurations.
|
||
# This rule is not needed for .user ppp. type connection to
|
||
# the public Internet. This is the same IP address you captured
|
||
# and used in the outbound section.
|
||
#$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state
|
||
|
||
# Allow in standard www function because I have apache server
|
||
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2
|
||
|
||
# Allow in secure FTP, Telnet, and SCP from public Internet
|
||
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2
|
||
|
||
# Allow in non-secure Telnet session from public Internet
|
||
# labeled non-secure because ID & PW are passed over public
|
||
# Internet as clear text.
|
||
# Delete this sample group if you do not have telnet server enabled.
|
||
$cmd 00420 allow tcp from any to me 23 in via $pif setup limit src-addr 2
|
||
|
||
# Reject & Log all incoming connections from the outside
|
||
$cmd 00499 deny log all from any to any in via $pif
|
||
|
||
# Everything else is denied by default
|
||
# deny and log all packets that fell through to see what they are
|
||
$cmd 00999 deny log all from any to any
|
||
################ End of IPFW rules file ###############################</programlisting>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>An Example <acronym>NAT</acronym> and Stateful
|
||
Ruleset</title>
|
||
|
||
<indexterm>
|
||
<primary>NAT</primary>
|
||
|
||
<secondary>and IPFW</secondary>
|
||
</indexterm>
|
||
|
||
<para>There are some additional configuration statements that
|
||
need to be enabled to activate the <acronym>NAT</acronym>
|
||
function of IPFW. The kernel source needs 'option divert'
|
||
statement added to the other IPFIREWALL statements compiled
|
||
into a custom kernel.</para>
|
||
|
||
<para>In addition to the normal IPFW options in
|
||
<filename>/etc/rc.conf</filename>, the following are
|
||
needed.</para>
|
||
|
||
<programlisting>natd_enable="YES" # Enable <acronym>NAT</acronym>D function
|
||
natd_interface="rl0" # interface name of public Internet NIC
|
||
natd_flags="-dynamic -m" # -m = preserve port numbers if possible</programlisting>
|
||
|
||
<para>Utilizing stateful rules with divert natd rule (Network
|
||
Address Translation) greatly complicates the rule set coding
|
||
logic. The positioning of the check-state, and 'divert natd'
|
||
rules in the rule set becomes very critical. This is no
|
||
longer a simple fall-through logic flow. A new action type
|
||
is used, called 'skipto'. To use the skipto command it is
|
||
mandatory that you number each rule so you know exactly
|
||
where the skipto rule number is you are really jumping
|
||
to.</para>
|
||
|
||
<para>The following is an uncommented example of one coding
|
||
method, selected here to explain the sequence of the packet
|
||
flow through the rule sets.</para>
|
||
|
||
<para>The processing flow starts with the first rule from the
|
||
top of the rule file and progress one rule at a time deeper
|
||
into the file until the end is reach or the packet being
|
||
tested to the selection criteria matches and the packet is
|
||
released out of the firewall. It is important to take notice
|
||
of the location of rule numbers 100 101, 450, 500, and 510.
|
||
These rules control the translation of the outbound and
|
||
inbound packets so their entries in the keep-state dynamic
|
||
table always register the private LAN IP address. Next
|
||
notice that all the allow and deny rules specified the
|
||
direction the packet is going (IE outbound or inbound) and
|
||
the interface. Also notice that all the start outbound
|
||
session requests all skipto rule 500 for the network address
|
||
translation.</para>
|
||
|
||
<para>Lets say a LAN user uses their web browser to get a web
|
||
page. Web pages use port 80 to communicate over. So the
|
||
packet enters the firewall, It does not match 100 because it
|
||
is headed out not in. It passes rule 101 because this is the
|
||
first packet so it has not been posted to the keep-state
|
||
dynamic table yet. The packet finally comes to rule 125 a
|
||
matches. It is outbound through the NIC facing the public
|
||
Internet. The packet still has it's source IP address as a
|
||
private LAN IP address. On the match to this rule, two
|
||
actions take place. The keep-state option will post this
|
||
rule into the keep-state dynamic rules table and the
|
||
specified action is executed. The action is part of the info
|
||
posted to the dynamic table. In this case it is "skipto rule
|
||
500". Rule 500 <acronym>NAT</acronym>s the packet IP address
|
||
and out it goes. Remember this, this is very important.
|
||
This packet makes its way to the destination and returns and
|
||
enters the top of the rule set. This time it does match rule
|
||
100 and has it destination IP address mapped back to its
|
||
corresponding LAN IP address. It then is processed by the
|
||
check-state rule, it's found in the table as an existing
|
||
session conversation and released to the LAN. It goes to the
|
||
LAN PC that sent it and a new packet is sent requesting
|
||
another segment of the data from the remote server. This
|
||
time it gets checked by the check-state rule and its outbound
|
||
entry is found, the associated action, 'skipto 500', is
|
||
executed. The packet jumps to rule 500 gets
|
||
<acronym>NAT</acronym>ed and released on it's way out.</para>
|
||
|
||
<para>On the inbound side, everything coming in that is part
|
||
of an existing session conversation is being automatically
|
||
handled by the check-state rule and the properly placed
|
||
divert natd rules. All we have to address is denying all the
|
||
bad packets and only allowing in the authorized services.
|
||
Lets say there is a apache server running on the firewall box
|
||
and we want people on the public Internet to be able to
|
||
access the local web site. The new inbound start request
|
||
packet matches rule 100 and its IP address is mapped to LAN
|
||
IP for the firewall box. The packet is them matched against
|
||
all the nasty things we want to check for and finally matches
|
||
against rule 425. On a match two things occur. The packet
|
||
rule is posted to the keep-state dynamic table but this time
|
||
any new session requests originating from that source IP
|
||
address is limited to 2. This defends against DoS attacks of
|
||
service running on the specified port number. The action is
|
||
allow so the packet is released to the LAN. On return the
|
||
check-state rule recognizes the packet as belonging to an
|
||
existing session conversation sends it to rule 500 for
|
||
<acronym>NAT</acronym>ing and released to outbound
|
||
interface.</para>
|
||
|
||
<para>Example Ruleset #1:</para>
|
||
|
||
<programlisting>#!/bin/sh
|
||
cmd="ipfw -q add"
|
||
skip="skipto 500"
|
||
pif=rl0
|
||
ks="keep-state"
|
||
good_tcpo="22,25,37,43,53,80,443,110,119"
|
||
|
||
ipfw -q -f flush
|
||
|
||
$cmd 002 allow all from any to any via xl0 # exclude LAN traffic
|
||
$cmd 003 allow all from any to any via lo0 # exclude loopback traffic
|
||
|
||
$cmd 100 divert natd ip from any to any in via $pif
|
||
$cmd 101 check-state
|
||
|
||
# Authorized outbound packets
|
||
$cmd 120 $skip udp from any to xx.168.240.2 53 out via $pif $ks
|
||
$cmd 121 $skip udp from any to xx.168.240.5 53 out via $pif $ks
|
||
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
|
||
$cmd 130 $skip icmp from any to any out via $pif $ks
|
||
$cmd 135 $skip udp from any to any 123 out via $pif $ks
|
||
|
||
|
||
# Deny all inbound traffic from non-routable reserved address spaces
|
||
$cmd 300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
|
||
$cmd 301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
|
||
$cmd 302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
|
||
$cmd 303 deny all from 127.0.0.0/8 to any in via $pif #loopback
|
||
$cmd 304 deny all from 0.0.0.0/8 to any in via $pif #loopback
|
||
$cmd 305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
|
||
$cmd 306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs
|
||
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster
|
||
$cmd 308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
|
||
|
||
# Authorized inbound packets
|
||
$cmd 400 allow udp from xx.70.207.54 to any 68 in $ks
|
||
$cmd 420 allow tcp from any to me 80 in via $pif setup limit src-addr 1
|
||
|
||
|
||
$cmd 450 deny log ip from any to any
|
||
|
||
# This is skipto location for outbound stateful rules
|
||
$cmd 500 divert natd ip from any to any out via $pif
|
||
$cmd 510 allow ip from any to any
|
||
|
||
######################## end of rules ##################</programlisting>
|
||
|
||
<para>The following is pretty much the same as above, but uses
|
||
a self documenting coding style full of description comments
|
||
to help the inexperienced IPFW rule writer to better
|
||
understand what the rules are doing.</para>
|
||
|
||
<para>Example Ruleset #2:</para>
|
||
|
||
<programlisting>#!/bin/sh
|
||
################ Start of IPFW rules file ###############################
|
||
# Flush out the list before we begin.
|
||
ipfw -q -f flush
|
||
|
||
# Set rules command prefix
|
||
cmd="ipfw -q add"
|
||
skip="skipto 800"
|
||
pif="rl0" # public interface name of NIC
|
||
# facing the public Internet
|
||
|
||
#################################################################
|
||
# No restrictions on Inside LAN Interface for private network
|
||
# Change xl0 to your LAN NIC interface name
|
||
#################################################################
|
||
$cmd 005 allow all from any to any via xl0
|
||
|
||
#################################################################
|
||
# No restrictions on Loopback Interface
|
||
#################################################################
|
||
$cmd 010 allow all from any to any via lo0
|
||
|
||
#################################################################
|
||
# check if packet is inbound and nat address if it is
|
||
#################################################################
|
||
$cmd 014 divert natd ip from any to any in via $pif
|
||
|
||
#################################################################
|
||
# Allow the packet through if it has previous been added to the
|
||
# the "dynamic" rules table by a allow keep-state statement.
|
||
#################################################################
|
||
$cmd 015 check-state
|
||
|
||
#################################################################
|
||
# Interface facing Public Internet (Outbound Section)
|
||
# Interrogate session start requests originating from behind the
|
||
# firewall on the private network or from this gateway server
|
||
# destine for the public Internet.
|
||
#################################################################
|
||
|
||
# Allow out access to my ISP's Domain name server.
|
||
# x.x.x.x must be the IP address of your ISP's DNS
|
||
# Dup these lines if your ISP has more than one DNS server
|
||
# Get the IP addresses from /etc/resolv.conf file
|
||
$cmd 020 $skip tcp from any to x.x.x.x 53 out via $pif setup keep-state
|
||
|
||
|
||
# Allow out access to my ISP's DHCP server for cable/DSL configurations.
|
||
$cmd 030 $skip udp from any to x.x.x.x 67 out via $pif keep-state
|
||
|
||
# Allow out non-secure standard www function
|
||
$cmd 040 $skip tcp from any to any 80 out via $pif setup keep-state
|
||
|
||
# Allow out secure www function https over TLS SSL
|
||
$cmd 050 $skip tcp from any to any 443 out via $pif setup keep-state
|
||
|
||
# Allow out send & get email function
|
||
$cmd 060 $skip tcp from any to any 25 out via $pif setup keep-state
|
||
$cmd 061 $skip tcp from any to any 110 out via $pif setup keep-state
|
||
|
||
# Allow out FreeBSD (make install & CVSUP) functions
|
||
# Basically give user root "GOD" privileges.
|
||
$cmd 070 $skip tcp from me to any out via $pif setup keep-state uid root
|
||
|
||
# Allow out ping
|
||
$cmd 080 $skip icmp from any to any out via $pif keep-state
|
||
|
||
# Allow out Time
|
||
$cmd 090 $skip tcp from any to any 37 out via $pif setup keep-state
|
||
|
||
# Allow out nntp news (i.e. news groups)
|
||
$cmd 100 $skip tcp from any to any 119 out via $pif setup keep-state
|
||
|
||
# Allow out secure FTP, Telnet, and SCP
|
||
# This function is using SSH (secure shell)
|
||
$cmd 110 $skip tcp from any to any 22 out via $pif setup keep-state
|
||
|
||
# Allow out whois
|
||
$cmd 120 $skip tcp from any to any 43 out via $pif setup keep-state
|
||
|
||
# Allow ntp time server
|
||
$cmd 130 $skip udp from any to any 123 out via $pif keep-state
|
||
|
||
#################################################################
|
||
# Interface facing Public Internet (Inbound Section)
|
||
# Interrogate packets originating from the public Internet
|
||
# destine for this gateway server or the private network.
|
||
#################################################################
|
||
|
||
# Deny all inbound traffic from non-routable reserved address spaces
|
||
$cmd 300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
|
||
$cmd 301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
|
||
$cmd 302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
|
||
$cmd 303 deny all from 127.0.0.0/8 to any in via $pif #loopback
|
||
$cmd 304 deny all from 0.0.0.0/8 to any in via $pif #loopback
|
||
$cmd 305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
|
||
$cmd 306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs
|
||
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster
|
||
$cmd 308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
|
||
|
||
# 拒絕 ident
|
||
$cmd 315 deny tcp from any to any 113 in via $pif
|
||
|
||
# 拒絕所有的 Netbios 服務. 137=name, 138=datagram, 139=session
|
||
# Netbios 是 MS/Windows 網路分享服務
|
||
# 阻擋所有的 MS/Windows 主機名稱伺服器hosts2 name server requests 81
|
||
$cmd 320 deny tcp from any to any 137 in via $pif
|
||
$cmd 321 deny tcp from any to any 138 in via $pif
|
||
$cmd 322 deny tcp from any to any 139 in via $pif
|
||
$cmd 323 deny tcp from any to any 81 in via $pif
|
||
|
||
# 拒絕任何的延遲到達之封包
|
||
$cmd 330 deny all from any to any frag in via $pif
|
||
|
||
# Deny ACK packets that did not match the dynamic rule table
|
||
$cmd 332 deny tcp from any to any established in via $pif
|
||
|
||
# Allow traffic in from ISP's DHCP server. This rule must contain
|
||
# the IP address of your ISP's DHCP server as it's the only
|
||
# authorized source to send this packet type.
|
||
# Only necessary for cable or DSL configurations.
|
||
# This rule is not needed for 'user ppp' type connection to
|
||
# the public Internet. This is the same IP address you captured
|
||
# and used in the outbound section.
|
||
$cmd 360 allow udp from x.x.x.x to any 68 in via $pif keep-state
|
||
|
||
# Allow in standard www function because I have Apache server
|
||
$cmd 370 allow tcp from any to me 80 in via $pif setup limit src-addr 2
|
||
|
||
# Allow in secure FTP, Telnet, and SCP from public Internet
|
||
$cmd 380 allow tcp from any to me 22 in via $pif setup limit src-addr 2
|
||
|
||
# Allow in non-secure Telnet session from public Internet
|
||
# labeled non-secure because ID & PW are passed over public
|
||
# Internet as clear text.
|
||
# Delete this sample group if you do not have telnet server enabled.
|
||
$cmd 390 allow tcp from any to me 23 in via $pif setup limit src-addr 2
|
||
|
||
# Reject & Log all unauthorized incoming connections from the public Internet
|
||
$cmd 400 deny log all from any to any in via $pif
|
||
|
||
# Reject & Log all unauthorized out going connections to the public Internet
|
||
$cmd 450 deny log all from any to any out via $pif
|
||
|
||
# This is skipto location for outbound stateful rules
|
||
$cmd 800 divert natd ip from any to any out via $pif
|
||
$cmd 801 allow ip from any to any
|
||
|
||
# Everything else is denied by default
|
||
# deny and log all packets that fell through to see what they are
|
||
$cmd 999 deny log all from any to any
|
||
################ End of IPFW rules file ###############################</programlisting>
|
||
</sect3>
|
||
</sect2>
|
||
</sect1>
|
||
</chapter>
|