iptables เป็นระบบ packet filtering ใน Linux ทุกๆตัว เป็นตัวที่ใช้ในการจัดการ traffic ใดๆที่เกิดขึ้น โดยใช้สำหรับกรองข้อมูลเข้าและออกจากเครื่อง รวมถึงการกำหนด routing ของ network โดยใช้ forwarding packet

องค์ประกอบของ rule ที่สร้างจะมี tables, chains และ targets ซึ่งโดยปกติการใช้งานจะเป็น filter table แต่เราสามารถกำหนด chain มาร่วมการตัดสินใจของ packet ไปยัง target ใดๆได้

Tables

แบ่งด้วยกัน 4 table

  • filter table: เป็น table หลัก (default) และอาจจะเป็น table ที่ใช้มากที่สุด โดยการตัดสินใจขึ้นอยู่กับว่าจะ allow packet ไปยังปลายทางนั้นๆหรือไม่
  • mangle table: เป็น table ที่จะใช้อนุญาตให้คุณปรับเปลี่ยน packet headers ได้ เช่นการเปลี่ยน  TTL values เป็นต้น
  • nat table: เป็น table ที่จะใช้อนุญาตให้คุณ route packets ไปยังเครื่องอื่นๆผ่านการ NAT (Network Address Translation) ​โดยการเปลี่ยน source และ destination addresses ของ packets. ซึ่งจะใช้บ่อยในการเข้าถึง service ที่ไม่สามารถเข้าตรงๆได้เพราะอยู่หลัง NAT Network นั่นเอง
  • raw table: iptables  เป็น stateful firewall, หมายความว่า packets แต่ละอันจะถูกตรวจด้วย “state” ของแต่ละอัน. (หมายถึง packet ดังกล่าวเป็นส่วน connection ใหม่, หรือการตรวจสอบว่าเป็นส่วนหนึ่งของ connection ที่มีอยู่แล้ว.) raw table จะอนุญาตให้คุณจัดการ packet ใดๆก่อนที่ kernel จะเริ่มติด state ให้กับแต่ละ packet รวมถึงเราสามารถที่จะยกเลิกการ track ในบาง packet ได้ด้วย

Chains

ในแต่ละ table ประกอบด้วย default chain โดย chains แต่ละอันจะทำให้เราสามารถ filter packet ในจุดที่แตกต่างกันได้

  • PREROUTING chain: เป็น rule ที่จะใช้เมื่อ packet เพิ่งจะมาถึงเครื่อง (network interface) chain นี้ปรากฏใน nat, mangle และ raw tables.
  • INPUT chain: เป็น rule ที่จะใช้กับ packet ก่อนที่จะเข้าไปถึง process ใดๆ chain นี้ปรากฏใน mangle และ filter tables.
  • OUTPUT chain: เป็น rule ที่จะใช้กับ packet ที่กำลังจะออกจาก process. chain นี้ปรากฏใน raw, mangle, nat และ filter tables.
  • FORWARD chain: เป็น rule ที่จะใช้กับ packet ที่จะ routed ผ่านเครื่องที่รับ packet. chain นี้ปรากฏใน mangle และ filter tables.
  • POSTROUTING chain: เป็น rule ที่จะใช้กับ packet ที่กำลังจะออกจาก network interface. chain นี้ปรากฏใน nat และ mangle tables.

Diagram ลำดับการจัดการ packet ของทั้ง Table และ Chain ครับ

Targets

อย่างที่บอกไปก่อนหน้านี้, chains จะเป็นตัวอนุญาให้คุณ filter traffic ใดๆโดยการเพิ่ม rule เข้าไป ยกตัวอย่างเช่น เราสามารถเพิ่ม rule เข้าไปใน filter table เพื่อกรองขาเข้า port 22 ได้ผ่าน INPUT chain ส่วน action ที่เราจะทำอะไรขึ้นอยู่กับเรา โดย target ที่เป็น terminating คือการจบที่จุดนั้นๆเลย โดยมีทั้ง

  • ACCEPT: ปล่อยให้ packet ผ่านไป (ACCEPT Packet)
  • DROP: หาก iptables drops packet. หากตกที่ action นี้จะเปรียบเสมือนกับการไม่เคยมี packet นี้เกิดขึ้น
  • REJECT: หาก iptables “rejects” packet. ตัวเครื่องจะทำการส่ง “connection reset” packet ในกรณี TCP , หรือจะส่ง “destination host unreachable” packet กลับไปในกรณีที่เป็น UDP หรือ ICMP.

ส่วนหากเป็น non-terminating targets, หมายถึงจะเป็นการใช้ rule หลายๆ rule ในการตัดสินใจเช่นการใช้ LOG target.  เมื่อมี packet ตรง rule ที่เราสร้างตัว packet จะทำการ log ไว้ในส่วน kernel log แต่จากนั้นเราก็จะปล่อยให้มันตรวจสอบใน rule ถัดๆไป บางครั้งเราอาจจะพบ rule ที่ซับซ้อนมากๆ เพื่อตรวจกรองอย่างละเอียดตามเงื่อนไขเราจะกระโดดไปมาก็เป็นได้

ตัวอย่างการใช้งาน

Blocking IP

เป็นการกำหนดให้ block packet จาก IP ต้นทางเป็น 59.45.175.62 โดย -t เป็นการกำหนด table ส่วน -A เป็นการ append rule เข้าไปใน INPUT chain , -s หมายถึง source IP, -j คือการกำหนด target

Block Range 59.45.175.0/24

Block ขาออกผ่านทาง OUTPUT Chain ปลายทางคือ 31.13.78.35

Listing rules

โดยการ list rule ดังกล่าวจะเป็นของ filter table หากต้องการเปลี่ยนเป็น table อื่นให้ใช้เป็น -t ด้วย

Deleting rules

หากเราต้องการลบ iptables rule ให้ใช้ option -D 

หากต้องการลบ 2 rule ให้ใช้เป็น

เราสามารถลบ rule โดยการระบุเป็น line number ได้ด้วย

หากเราต้องการลบ rule ทั้งหมดจะใช้เป็น -F

Inserting and replacing rules

เพิ่ม rule เข้าไปตามตำแหน่งที่เราต้องการ โดยใช้ -I

หากเราต้องการ replace rule ใดๆจะใช้เป็น -R

Protocols and modules

หากเราต้องการ block all incoming TCP traffic. เราสามารถใช้ -p เป็นตัวกำหนดได้

หากเราต้องการ block SSH access ตาม IP range. เราจะกำหนดโดยใช้--dportที่เป็นส่วนหนึ่งของ tcp module

หากต้องการ block SSH และ VNC ตาม IP range. เราใช้เป็น multiport module เพื่อกำหนดหลายๆ port ในการ block ได้

หากเราต้องการ block ICMP address ที่เป็น requests (type 17). เราสามารถกำหนดรายละเอียดได้โดยใช้เป็นicmp-type ใน module icmp

connection tracking module

หากเราต้องการ block INPUT chain โดยดูจาก state ของ Packet สามารถกำหนดรายละเอียดลงไปได้ในส่วน conntrack module โดย state มีดังนี้

  • NEW: packet แรกของ connection.
  • ESTABLISHED: state เมื่อ packets เป็นส่วนหนึ่งของ connection ที่มีอยู่แล้ว. สำหรับ connection ที่อยู่ใน state นี้,จะเป็นการได้รับ reply มาจาก host อื่นๆ
  • RELATED: state นี้ถูกใช้ใน connections ที่เกี่ยวข้องกับ ESTABLISHED connection ที่มีอยู่หรือที่เกิดขึ้นแล้ว. ยกตัวอย่างเช่น FTP data connection — เราจะกำหนด “related” state ให้ เพราะมันเกี่ยวกับ “established” control connection.
  • INVALID: state นี้หมายถึง packet ไม่ได้มี state ที่เหมาะสม. อาจจะเกิดได้ด้วยหลายเหตุผล,  เช่น system เกิดไม่มี memory ขึ้นมาหรือเกิดจาก packet ของ ICMP traffic บางชนิด.
  • UNTRACKED: packet ใดๆที่ได้รับการยกเว้นการ track connectionจากส่วน raw table โดยใช้ NOTRACK target จะได้รับ UNTRACKED state
  • DNAT:  เป็น state เสมือนใช้เพื่อแสดงถึง packets ที่ปลายทางมีการเปลี่ยนแปลงโดย rules ใน nat table.
  • SNAT: คล้ายๆกับ DNAT, เป็น state เสมือนใช้เพื่อแสดงถึง packets ที่ source address มีการเปลี่ยนแปลงโดย rules ใน nat table.

เราสามารถกำหนด state ไว้ใน rule ได้โดยใช้  --ctstate ใน kernels เก่าๆจะใช้ module state แทนที่จะเป็น conntrack module, จากนั้นใช้ --state แทน --ctstate.

เราสามารถ drop INVALID state. โดยใช้เป็น

Changing the default policy

โดยปกติ default policy คือ ACCEPT เราสามารถกำหนด default policy ไปเป็นอย่างอื่นได้โดยใช้ -P

สิ่งที่เกิดขึ้นคือ หากไม่ตรง rule ใดๆแล้วจะทำตาม default policy ของเรานั่นเอง

Selecting interfaces

เราสามารถกำหนด interface ได้โดยใช้เป็น -i  เมื่อใช้ใน INPUT chain แต่หากเป็น OUTPUT Chain จะเป็น -o แทน

 

Negating conditions

หากเราอยากได้ผลที่ตรงข้ามจะใช้เป็น (!) เช่นหากเราต้องการ drop packet ใดๆ ยกเว้น 22,80,443 จะใช้เป็น (default policy เป็น ACCEPT)

Blocking invalid TCP packets with the tcp module

หากเราต้องการกำหนดระบุว่า flag ใดๆที่จะ DROP บ้าง สามารถใช้ tcp module พร้อมกับ –tcp-flags option ได้ ในที่นี้คือการ set FIN,PSH, URG ซึ่งเป็น Christmas tree packets เข้ามา

หากมีการ set SYN,FIN เข้ามาพร้อมกันให้ drop จะใช้เป็น

หากเราต้องการสร้าง rule มาเมื่อมี connection ใหม่เข้ามา ให้เช็คว่ามีแค่ SYN Flag set เข้ามาหรือไม่ ถ้ามีการ set Flag อื่นๆเข้ามาด้วยทั้ง FIN, RST, ACK และ SYN flags; ให้เราทำการปฏิเสธ packet ทิ้ง

Limiting packets: the limit module

เราสามารถใช้ limit module ในการจำกัดจำนวน packets ท่ีจะผ่านเข้ามาได้ในเวลาที่กำหนด เช่น เราจะ limit 1 packet/second และหากเกินกว่านั้นก็จะข้าม Rule นั้นๆไป

Per-IP packet limits: the recent module

น่าเสียดายที่ limit module จะไม่สามารถจัดการ dynamic packet ได้ เป็นการควบคุมแต่ละ IP ได้ แต่เราสามารถใช้ recent module ในการจัดการได้​ เช่นหากเกิด brute force attacks เกิดขึ้นที่ SSH server. เราใช้ recent ในการเพิ่ม IP เข้าไปใน list ชื่อใดๆ จากนั้นสร้าง rule อีก rule เรามาตรวจสอบว่า IP ที่เข้ามานั้นซ้ำกับใน list ที่มีอยู่แล้วมั้ย ถ้าซ้ำตามจำนวนที่กำหนดก็จะทำการ drop:

ในตัวอย่างคือการสร้าง list ที่ชื่อว่า “SSHLIMIT” ขึ้นมา. ใน line แรกจะทำการเพิ่ม source IP เข้าไปใน list หาก IP นั้นอยู่ใน list อยู่แล้ว, ก็จะมีการ update list เพิ่ม count ของ IP นั้นๆ. ใน line ถัดมา, เราจะ check ว่า hit ครบ 5 ครั้งใน 180 วินาทีหรือไม่.​ถ้าครบก็จะ drop packet. เราจะอนุญาตให้สร้าง SSH Connection ใหม่แค่ 4 connections จากแต่ละ IP ใน3 นาที

อีกทั้งเรายังกำหนดโดยใช้ mask ในการสร้าง condition ในการตรวจสอบได้ด้วย

 

Custom chains

บางครั้งเราสามารถสร้าง chain ขึ้นมาใหม่ได้ เพื่อรวบ rule ที่คล้ายๆกันไปอยู่กลุ่มเดียวกัน เช่น

จะเห็นว่ามันเป็น rule เพื่อตรวจสอบ ssh เหมือนกัน ดังนั้นเราสามารถสร้าง chain ขึ้นมาเพื่อรวบ rule ดังกล่าวได้โดยใช้ -N

จากนั้นสร้าง rule ที่คล้ายๆกันไปไว้ใน custom chain ที่เราสร้างขึ้นมาใหม่

สุดท้ายคือการนำ packet ใดๆที่เป็น 22 ไปยัง custom rule ที่เรากำหนดไว้

หากเราต้องการลบ chain ทิ้งจะใช้เป็น

Logging packets: the LOG target

เราสามารถ log packet ได้โดยใช้ target เป็น LOG Target โดย log มักจะไปโผล่ใน /var/log/syslog  หรือ/var/log/messages.

เราสามารถกำหนด tag ได้โดยใช้--log-prefix option, ดังนั้นหากเราต้องการจะติดคำ iptables เข้าไปจะใช้เป็น:

iptables-save และ iptables-restore

เพื่อให้ง่ายต่อการแก้ไขเราสามารถ save rule iptables ทั้งหมดออกมาเป็นไฟล์ได้โดยใช้เป้น iptables-save และใช้ iptables-restore​ ในการ restore (โดยหากเป็น IPv6 จะใช้เป็น ip6tables-save และ ip6tables-restore).

Preserving iptables rules across reboots

ข้อเสียของการใช้งาน iptables คือมันจะไม่ save ไว้ให้ พอ restart ขึ้นมาแล้วมันจะกลายเป็นว่า rule ทั้งหมดจะหายไป ดังนั้นเราจำเป็นต้องติดตั้ง packet ในการจำเพิ่มเติม โดยหากเป็นใน  RHEL และ CentOS,จะใช้เป็น “iptables-services”

หากเป็น Debian และ Ubuntu, จะติดตั้ง packet ที่ชื่อว่า “iptables-persistent”

 

หรือหากเราต้องการให้มันทำการ restore rule ทุกครั้งที่ eth0 up ขึ้นมา เริ่มต้นด้วยการ save ไฟล์ไว้ที่ /etc/default/iptables-rules

จากนั้นให้มัน restore ทุกครั้งที่ interface eth0 up เข้าไปแก้ไขใน /etc/network/interfaces จะได้เป็น

Source:: Booleanworld