Dynamic RAWNAT

หลังจากที่ห่างหายจากการพัฒนา RahuNAS มาสักระยะ เนื่องด้วยงานประจำที่ทำอยู่ก็หนักเอาการ แต่ด้วยการที่ตบปากรับคำกับทางมหาวิทยาลัยขอนแก่น ว่าจะพัฒนาส่วนต่อเพิ่มเติม เพื่อให้ระบบ RahuNAS สามารถแยกผู้ใช้ออกเป็นประเภท (Class-Of-Service) ได้

โดยเป้าหมายคือ การแปลงร่าง จากผู้ใช้ธรรมดา เป็นผู้ใช้พิเศษ ตามแต่ระบบจะกำหนด โดยใช้หลักการเรื่องการเปลี่ยน IP ต้นทาง - ปลายทาง (Source, Destination NAT - SNAT, DNAT) ซึ่งจะทำให้การจัดการที่ Packets Shaper หรือ Firewall ได้ง่ายขึ้น เนื่องจากว่า ถ้าผู้ใช้ท่านใด ได้รับสิทธิพิเศษ ระบบก็จะแปลงร่างผู้ใช้นั้น ๆ จาก IP ปกติ ไปเป็น IP กลุ่มพิเศษ ที่สามารถผ่าน Firewall หรือได้รับความเร็วพิเศษกว่าผู้ใช้ปกติได้ (หลายท่านที่เป็นเซียนทางด้านการปลอมตัว คงจะคิดว่า ถ้าล่วงรู้ IP ในกลุ่มพิเศษหละ ก็ออกเป็นกลุ่มพิเศษได้สิ คำตอบ คือ ถ้าแปลงร่างตั้งแต่ก่อนจะเข้าถึงเครื่องตรวจสอบสิทธิ์ ก็เปล่าประโยชน์ เนื่องจากระบบตรวจสอบสิทธิ์ ก็จะตรวจสอบ และแจ้งผู้ใช้ว่า เข้ามาอย่างไม่ถูกต้อง)

ระบบ NAT ที่เรารู้จักกันดี คือ target SNAT และ DNAT ซึ่งโดยหลักการแล้วก็ใช้ได้กับแนวคิดที่วางไว้ข้างต้น

Full NAT

 # iptables -t nat -A PREROUTING -d 10.0.0.10 -j DNAT --to-destination 172.30.0.10
 # iptables -t nat -A POSTROUTING -s 172.30.0.10 -j SNAT --to-source 10.0.0.10

แต่ปัญหาที่ตามมาคือ ถ้าใช้หลักการนี้ในการทำงานร่วมกับ Authentication Server สิ่งที่ตามมาคือ

  • จำนวน Rule จะเพิ่มขึ้นตามจำนวนของผู้ใช้ที่ได้รับสิทธิพิเศษ
  • ระบบจะทำงานช้าลง เป็นผลมาจากการ match Rule ที่มากขึ้น
  • ระบบจะใช้ Memory มากขึ้น เนื่องจาก SNAT และ DNAT ต้องอาศัย Connection Tracking ช่วย

เป็นอันว่า หลักการนี้ ทำงานได้ แต่ไม่ดีพอ จึงต้องคิดหาวิธีการที่ดีกว่าต่อไป

และจากสิ่งที่ต้องปรับปรุงของ RahuNAS เพื่อที่จะให้สามารถใช้งานใน Debian GNU/Linux รุ่นถัดมาจาก Lenny คือ Squeeze ซึ่งจะกลายไปเป็น Stable Release ในอนาคต ต้องมีการปรับปรุงหลายส่วน หนึ่งในนั้น คือ การเปลี่ยนมาใช้ xtables-addons แทน netfilter-extensions ซึ่งไม่ update มานานพอสมควรแล้วนั้น ก็ได้พบสิ่งที่น่าสนใจใน xtables-addons อย่างหนึ่งคือ RAWNAT target ซึ่งทำงานที่ raw table ซึ่งเกิดขึ้นก่อนที่จะมีการใช้งาน Connection Tracking (conntrack) ซึ่งถ้าพูดให้เป็นหลักการ คือ Stateless-NAT ซึ่งเข้าเค้ากับสิ่งที่เราต้องการ โดยการใช้งานก็คล้าย ๆ กับ SNAT และ DNAT ข้างต้น แต่ทำที่ raw table และที่สำคัญ RAWNAT ได้เพิ่ม rawpost table เข้ามาอีก ทำให้สามารถที่จะทำ Full Stateless-NAT ได้อย่างสมบูรณ์

Full Stateless-NAT

# iptables -t raw -A PREROUTING -d 10.0.0.10 -j RAWDNAT --to-destination 172.30.0.10
# iptables -t rawpost -A POSTROUTING -s 172.30.0.10 -j RAWSNAT --to-source 10.0.0.10

การทำงานของ RAWNAT คือการแก้ไขที่ระดับ IP Packet ทำให้การทำงานเร็วกว่า และใช้ Memory น้อยกว่า Stateful-NAT และที่สำคัญ เหมาะกับแนวคิดที่วางไว้ คือ อยากให้ระบบทำการ NAT แบบโง่ ๆ ที่สุด

การใช้ RAWNAT เป็นทางออกในขั้นต้น แต่ทว่าการที่ใช้รูปแบบคล้ายเดิม แสดงว่าเราต้องเพิ่ม Rule เท่ากับจำนวนของผู้ใช้ที่ได้รับสิทธิพิเศษเช่นเดิม การแก้ปัญหาต่อมาคือ การทำ Dynamic RAWNAT ซึ่งแนวคิดก็ต่อยอดมาจาก IPSet ซึ่งในรุ่นล่าสุดคือ Version 4.2 นั้นมีการเพิ่มความสามารถเข้ามาอีกหลายส่วน ซึ่งส่วนที่ได้นำมาดัดแปลงใช้งานคือ ipportiphash โดยที่ต้นฉบับ ใช้ data structure เป็น hash table ซึ่งมีประสิทธิภาพดีในเรื่องความเร็วในการค้นข้อมูล ซึ่งคำว่า ipportip นั้น ต้นฉบับ ใช้สำหรับการ match packet ที่มี ip:port และ ip อีกชุด ในการ match อย่างเช่น src-ip:src-port ร่วมกับ dest-ip ในการ match ก็หมายความว่า สามารถที่จะ match ip ต้นทาง และ port ต้นทาง ร่วมกับ ip ปลายทางได้ ถ้าครบเงื่อนไขตามนี้ คือ match ถ้าไม่ครบ ก็ไม่ match

ดังนั้น การดัดแปลงจึงเริ่มขึ้น เป้าหมายของเราคือ IP => IP mapping จึงได้เกิด rahunas_ipiphash match set ขึ้นมา
ซึ่งการใช้งาน ก็เหมือน การใช้งาน ipset ในส่วนของ set module อื่น ๆ ทั่วไป

ก่อนอื่น ก็ต้องติดตั้ง xtables-addons ที่มีส่วนของ rahunas code เข้าไปในระบบก่อน

# echo "deb ftp://ftp.rahunas.org/rahunas unstable main" > /etc/apt/sources.list.d/rahunas.list
# apt-get update
# apt-get --allow-unauthenticated install rahunas-archive-keyring
# apt-get update
# apt-get install xtables-addons
# m-a a-i xtables-addons 

ระบบติดตั้งเรียบร้อย ก็พร้อมทดสอบ
สร้าง mapping set เพื่อเตรียมพร้อมใช้งานร่วมกับ Dynamic RAWNAT

# ipset -N test rahunas_ipiphash
# ipset -A test 172.30.0.10,10.0.0.10
# ipset -A test 10.0.0.10,172.30.0.10
# ipset -nL
Name: test
Type: rahunas_ipiphash
References: 0
Header: hashsize: 1024 probes: 8 resize: 50
Members:
10.0.0.10 => 172.30.0.10
172.30.0.10 => 10.0.0.10

จะเห็นว่า ใน set มี mapping ip ปรากฎให้เห็นแล้ว ต่อไปคือการตั้งค่า Dynamic RAWNAT

# iptables -t raw -A PREROUTING -j RAHURAWDNAT --bind-set test
# iptables -t rawpost -A POSTROUTING -j RAHURAWSNAT --bind-set test

เท่านี้ ระบบ Dynamic Stateless-NAT ก็ใช้งานได้ โดยที่คราวนี้ เราเพิ่ม Rule เข้าไปในระบบ เพียง 2 Rule และการทำ Mapping ทั้งหมด อ่านค่าจาก rahunas_ipiphash set ทั้งหมด ตอนนี้ อยาก map ยังไง ก็แล้วแต่จะเพิ่มเข้าไปใน set ชีวิตง่ายขึ้นเยอะ

และนี่คือเป้าหมายที่เราต้องการ โดยแก้ปัญหาที่เกิดขึ้นในตอนเริ่มต้นได้ หลังจากนี้ ก็ใช้หลักการที่เคยเขียน RahuNAS ติดต่อกับ ipset เพื่อทำการ เพิ่ม/ลด mapping ip ตามแต่ต้องการได้เลย

คิดว่า ในส่วนของ RahuNAS สำหรับเรื่อง Class-Of-Service น่าจะเป็นรูปเป็นร่างในเร็ววันนี้ และจะเป็นอีก Feature หนึ่งที่ระบบเครือข่ายที่ค่อนข้างซับซ้อนอย่างมหาวิทยาลัยต้องการ อย่างน้อย ๆ ก็ ม.ขอนแก่น ที่หนึ่ง

คาดว่า การเปลี่ยนแปลงหลาย ๆ อย่างนี้ จะออกมาพร้อมกับ RahuNAS 0.2.0