Turn Linux box into router

สิ่งที่ Linux ปกติต่างกับ router ก็เพียงแค่ว่า มันจะไม่ส่ง packet ที่ได้รับต่อไปที่อื่น (IP forwarding) เพราะก็แค่ไม่ได้เป็นความจำเป็นที่ต้องทำ แต่ถ้าต้องการมันก็สามารถทำง่ายๆ เพียงแค่คำสั่งเดียว

sudo sysctl -w net.ipv4.ip_forward=1

หรือเพิ่มใน /etc/sysctl.conf

net.ipv4.ip_forward=1

แล้วก็ sudo sysctl -p

เพียงเท่านี้ มันจะก็ยอมให้ packet ที่ได้รับมากจาก interface ไหนก็ตามถูก forward ไปอีก interface ได้ แต่การที่จะทำให้มันทำตัวเป็น router ได้นั้น กลับกลายเป็นอีกส่วนนั่นคือ routing table และ iptables

Routing

เดิมๆ ถ้าดู routing table มันก็จะเห็นประมาณ

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         10.1.1.1        0.0.0.0         UG    202    0        0 eth0
10.1.1.0        0.0.0.0         255.255.255.0   U     202    0        0 eth0

นั่นก็คือ packet ไหนที่ไม่ใช่ใน subnet เรา ก็ไปที่ Gateway 10.1.1.1 หมดแหละ หลักๆ คือ สิ่งที่เราต้องดูคือว่า เราต้องการแก้ไขอะไร ก็ให้มันไปให้ถูก gateway เช่น

sudo route -n add 10.1.0.0/24 10.1.1.61

ซึ่งจะได้ประมาณนี้ (ด้านล่างเป็น macOS หน้าตาก็ต่างไปนิดๆหน่อยๆ)

Routing tables

Internet:
Destination        Gateway            Flags        Netif Expire
default            10.1.1.1           UGSc           en0       
10.1/24            10.1.1.61          UGSc           en0   

ซึ่งแปลว่า 10.1.0.0/24 นี่ให้ไปอีก gateway นะ ไม่ได้ต้องไป gateway หลัก

IP Masquerading

ถึงจุดนี้จริงๆ packet มันก็ถูกส่งไปได้ละ แต่ว่า พวก packet นี้จะไปไหนนอก network เราไม่ได้ เราเลยต้องมาจะทำการลวงข้อมูลพวกนี้หน่อย เพื่อให้มันเดินทางไปต่อ network ภายนอกหรือ internet ได้ ซึ่งมันคือ IP masquerading (หลักๆ คือ จากที่ request มันจะมาจากไหนก็ตาม ก็จะเสมือนว่า มาจาก IP ของ ตัว Linux ของเราที่ทำเป็น router นี่แหละ

sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

อันนี้คือ บอกให้มัน route packet ที่เข้ามาไปที่ tun0 interface โดยมี tag MASQUERADE ซึ่งบอกว่า พวก packet พวกนี้ต้องแสร้งว่า มาจาก tun0 ในมุมมองของพวก network อื่นๆ

  • -t nat คือ กำหนดว่าใช้ NAT packet matching table
  • -A POSTROUTING -o tun0 คือ แก้ packet ให้มัน route ไป tun0
  • -j MASQUERADE คือ ซ่อน IP address ใน network ละแสร้งว่า เป็น IP ของ tun0 interface นี่แหละ

การทำแบบนี้มันจะแสดงให้เห็นใน iptables แบบนี้

$ sudo iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination         

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination         
235 14952 MASQUERADE  all  --  *      tun0    0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination

ข้อมูลเพิ่มเติมเรื่อง กฎ FORWARD กับ NAT อ่านที่ redhat ได้เค้าเขียนไว้ละเอียดดี