การทำ Inbound & Outbound NAT + Firewall บน Linux ด้วย iptables
ตัวอย่างเครือข่ายและ script นี้ดัดแปลงจาก www.boingworld.com

บทนำ
การนำเอา
Linux Server มาทำเป็น Firewall ให้กับองค์กรในการใช้งานอินเตอร์เน็ต  เป็นทางเลือกทางหนึ่งที่ได้ผลดีเนื่องจาก Linux OS เป็นของฟรี และมี Applications ต่าง ๆ มากับแผ่นให้เลือกใช้ได้มากมาย  ในที่นี้จะขอเน้นเรื่อง Firewall ที่มีมากับ Linux OS นั่นคือ iptables ซึ่งเป็น Stateful Firewall ที่สามารถนำมาประยุกต์ใช้งานได้โดยที่ไม่ต้องซื้อ Firewall ราคาแพงมาใช้

ในตัวอย่างที่จะเสนอต่อไปนี้ เป็นรูปเบบการเชื่อมต่ออินเตอร์เน็ตแบบที่มี
Registered IP แค่ IP เดียว  แต่ภายในองค์กรประกอบด้วย Server ต่าง ๆ อยู่ซึ่งจะต้องใช้ Private IP  ดังรูป
 

หมายเหตุ ถ้าองค์กรของท่านมี Registered IP หลาย IP ก็สามารถใช้รูปข้างบนนี้มาประยุกต์ใช้ได้เช่นกัน  นั่นคือการกำหนดให้ eth0 เป็นหลาย IP ตามจำนวนของ Server ภายใน เช่นจากรูปข้างบนนี้ก็อาจจะกำหนด IP ของ eth0 เป็น 4 IP (1 IP ของ Linux Server + 3 IP ของ Server) จากนั้นก็ทำ Inbound NAT ที่จะได้กล่าวต่อไป

ิธีการ
จากรูปข้างบนก็นำ
Linux Server มาใช้งานโดยให้มีการ์ดแลน 2 การ์ด การ์ดหนี่งให้เป็น Public IP (202.129.16.30) และอีกการ์ดเป็น Private IP (192.168.1.1) ส่วนเครื่อง Server และ Client ก็ใช้ Private IP ดังรูป  โดยบนเครื่อง Linux Server ให้ใช้ iptables ในการควบคุมการไหลของข้อมูล 

ความต้องการของระบบ
มีความต้องการอยู่ 2 อย่างคือ
1
. Linux Server ต้องทำหน้าที่แปลง IP ของเครือข่ายภายในทั้งหมดซึ่งเป็น Private IP ให้กลายเป็น Public IP ซึ่งในที่นี้คือ 202.129.16.30 เพื่อให้สามารถติดต่อกับเครือข่ายภายนอกได้
2. เมื่อเครือข่ายภายนอกมีการเรียกใช้งานเข้ามาที่
DNS Server , Web Server และ Mail Server ซึ่งจะถูกประกาศให้เครือข่ายภานนอกรู้จักเป็น Public IP อันเดียวกันคือ 202.129.16.30 นั้น  ตัว Linux Server ต้องทำการแปลง Public IP ให้กลายเป็น Private IP เพื่อที่จะให้เครือข่ายภายนอกสามารถติดต่อเข้าสู่ Server ทั้ง 3 ได้  ด้วยความแตกต่างของ Port ดังนี้ :

     -
DNS Server ทำงานที่พอร์ต TCP:53 และ UDP:53
     -
Web Server (http) ทำงานที่พอร์ต TCP:80
     - Mail Server (smtp) ทำงานที่พอร์ต TCP:25

ในกรณีที่มี
Server อื่น ๆ นอกเหนือจากนี้ก็สามารถทำได้ด้วยหลักการเดียวกัน
3. การทำ Firewall

คำสั่ง
iptables ที่ใช้
คำสั่งที่ใช้ทั้งหมดเป็นดังนี้
:

#----Start script------#

# Define variable
INET_IP="202.129.16.30"
INET_IFACE="eth0"

DNS_IP="202.129.16.
30"
HTTP_IP="202.129.16.
30"
SMTP_IP="202.129.16.
30"

LAN_IP="
192.168.1.1"
LAN_BCAST_ADRESS="
192.168.1.255"
LAN_IFACE="eth1"

LAN_DNS_IP="
192.168.1.2"
LAN_HTTP_IP="
192.168.1.3"
LAN_SMTP_IP="
192.168.1.4"

LO_IFACE="lo"
LO_IP="127.0.0.1"


# Enable ip_forward, this is critical since it is turned off as defaul in  Linux.
echo "1" > /proc/sys/net/ipv4/ip_forward


#Clear all chains of rule
iptables -F
iptables -X allowed
iptables -X icmp_packets
iptables -X tcp_packets
iptables -X udpincoming_packets
iptables -t nat -F


# Enable simple IP Forwarding and Network Address Translation
(Outbound NAT)
iptables -t nat -A POSTROUTING -o $INET_IFACE -j SNAT --to-source $INET_IP


# Bad TCP packets we don't want
iptables -A FORWARD -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
iptables -A FORWARD -p tcp ! --syn -m state --state NEW -j DROP


# Accept the packets we actually want to forward
iptables -A FORWARD -i $LAN_IFACE -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT FORWARD packet died: "


# Set default policies for the INPUT, FORWARD and OUTPUT chains
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP


# Create separate chains for ICMP, TCP and UDP to traverse
iptables -N icmp_packets
iptables -N tcp_packets
iptables -N udpincoming_packets


# The allowed chain for TCP connections
iptables -N allowed
iptables -A allowed -p TCP --syn -j ACCEPT
iptables -A allowed -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A allowed -p TCP -j DROP


# ICMP rules
iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 0 -j ACCEPT
iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 3 -j ACCEPT
iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 5 -j ACCEPT
iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT


# TCP rules
iptables -A tcp_packets -p TCP -s 0/0 --dport 21 -j allowed
iptables -A tcp_packets -p TCP -s 0/0 --dport 22 -j allowed
iptables -A tcp_packets -p TCP -s 0/0 --dport 25 -j allowed
iptables -A tcp_packets -p TCP -s 0/0 --dport 80 -j allowed
iptables -A tcp_packets -p TCP -s 0/0 --dport 113 -j allowed


# UDP ports
iptables -A udpincoming_packets -p UDP -s 0/0 --source-port 53 -j ACCEPT
iptables -A udpincoming_packets -p UDP -s 0/0 --source-port 123 -j ACCEPT
iptables -A udpincoming_packets -p UDP -s 0/0 --source-port 2074 -j ACCEPT
iptables -A udpincoming_packets -p UDP -s 0/0 --source-port 4000 -j ACCEPT


# PREROUTING chain.
# Do some checks for obviously spoofed IP's
iptables -t nat -A PREROUTING -i $INET_IFACE -s 192.168.0.0/16 -j DROP
iptables -t nat -A PREROUTING -i $INET_IFACE -s 10.0.0.0/8 -j DROP
iptables -t nat -A PREROUTING -i $INET_IFACE -s 172.16.0.0/12 -j DROP

#Inbound Nat
iptables -t nat -A PREROUTING -p TCP -i $INET_IFACE -d $DNS_IP --dport 53 -j DNAT --to-destination $LAN_DNS_IP
iptables -t nat -A PREROUTING -p UDP -i $INET_IFACE -d $DNS_IP --dport 53 -j DNAT --to-destination $LAN_DNS_IP
iptables -t nat -A PREROUTING -p TCP -i $INET_IFACE -d $HTTP_IP --dport 80 -j DNAT --to-destination $LAN_HTTP_IP
iptables -t nat -A PREROUTING -p TCP -i $INET_IFACE -d $SMTP_IP --dport 25 -j DNAT --to-destination $LAN_SMTP_IP


#
FORWARD chain

#
Forward for DNS server
iptables -A FORWARD -p TCP -i $INET_IFACE -o $LAN_IFACE -d $LAN_DNS_IP --dport 53 -j allowed
iptables -A FORWARD -p UDP -i $INET_IFACE -o $LAN_IFACE -d $LAN_DNS_IP --dport 53 -j ACCEPT
iptables -A FORWARD -p ICMP -i $INET_IFACE -o $LAN_IFACE -d $LAN_DNS_IP -j icmp_packets

#
Forward  for HTTP server
iptables -A FORWARD -p TCP -i $INET_IFACE -o $LAN_IFACE -d $LAN_HTTP_IP --dport 80 -j allowed
iptables -A FORWARD -p ICMP -i $INET_IFACE -o $LAN_IFACE -d $LAN_HTTP_IP -j icmp_packets

#
Forward for  SMTP server
iptables -A FORWARD -p TCP -i $INET_IFACE -o $LAN_IFACE -d $LAN_SMTP_IP --dport 25 -j allowed
iptables -A FORWARD -p ICMP -i $INET_IFACE -o $LAN_IFACE -d $LAN_SMTP_IP -j icmp_packets


# INPUT chain

# Take care of bad TCP packets that we don't want
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

# Rules for incoming packets from the internet
iptables -A INPUT -p ICMP -i $INET_IFACE -j icmp_packets
iptables -A INPUT -p TCP -i $INET_IFACE -j tcp_packets
iptables -A INPUT -p UDP -i $INET_IFACE -j udpincoming_packets

# Rules for special networks not part of the Internet
iptables -A INPUT -p ALL -i $LAN_IFACE -d $LAN_BCAST_ADRESS -j ACCEPT
iptables -A INPUT -p ALL -i $LO_IFACE -d $LO_IP -j ACCEPT
iptables -A INPUT -p ALL -i $LAN_IFACE -d $LAN_IP -j ACCEPT
iptables -A INPUT -p ALL -d $INET_IP -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT INPUT packet died: "


# OUTPUT chain
iptables -A OUTPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
iptables -A OUTPUT -p tcp ! --syn -m state --state NEW -j DROP

iptables -A OUTPUT -p ALL -s $LO_IP -j ACCEPT
iptables -A OUTPUT -p ALL -s $LAN_IP -j ACCEPT
iptables -A OUTPUT -p ALL -s $INET_IP -j ACCEPT
iptables -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT OUTPUT packet died: "

#----End script------#