ดาวน์โหลดเอกสาร PDF ของบทความนี้
การติดตั้ง Asterisk ไว้หลัง NAT รวมทั้งการใช้งาน VoIP แบบ SIP ผ่าน NAT มีข้อจำกัดและปัญหาในการใช้งานอยู่พอสมควรครับ แต่ปัญหานี้ก็ไม่ได้ใหญ่โตอะไรมากมายจนเราใช้งานไม่ได้ มีเทคนิคอยู่หลายอย่างที่ให้เราเลือกมาใช้แก้ปัญหา
ปัญหาที่ผมเกริ่นมานี้ส่วนใหญ่แล้วจะเกิดขึ้นกับการวาง SIP Server ไว้หลัง NAT นะครับ ในขณะที่การวาง SIP Client ไว้หลัง NAT (แต่ SIP Server ไม่ได้อยู่หลัง NAT) นั้นไม่ค่อยพบปัญหาครับ
เมื่อเราติดตั้ง Asterisk ไว้หลัง NAT ก็แน่นอนว่าพอร์ต LAN จะเป็น Private IP หรือที่เรามักเรียกว่าไอพีปลอม ซึ่ง IP Address นี้ (และเบอร์พอร์ต) เมื่อมองจาก Client ที่อยู่ในวงแลนเดียวกันกับ Asterisk กับมองจาก Client ที่อยู่ในอินเตอร์เน็ตจะเห็น IP Address ของ Asterisk เป็นคนละค่ากันนะครับ เห็นเป็นคนละ IP คนละ Port
ตัว Asterisk เองเมื่อมันจะสื่อสารกับ Client ในวงแลน (ทั้งส่ง SIP และ SDP Message) มันจะใช้ Private IP แต่เมื่อมันจะสื่อสารกับ Client ในอินเตอร์เน็ตมันต้องใช้ Public IP ซึ่งมันต้องรู้ว่าขณะนี้ Public IP เป็นหมายเลขอะไร ถ้า Asterisk ไม่รู้ Public IP ก็จะสื่อสารกับ Client ในอินเตอร์เน็ตไม่ได้ครับ เนื้อหาส่วนใหญ่ของบทความนี้จะแนะนำวิธีการคอนฟิก Asterisk ให้มันรู้จักค่า Public IP ครับ
คอนเซ็ปต์ของ NAT นั้นนะครับ จะแบ่งเน็ตเวอร์คออกเป็น 2 ด้าน คือ ภายใน ซึ่งเรียกว่า "inside" และ ภายนอก ซึ่งเรียกว่า "outside" โดยที่ inside หมายถึงด้านที่เป็น Private มีไอพีเป็นไอพีปลอม เช่น 192.168.x.x ส่วน outside หมายถึงด้านที่เป็น Public IP มีไอพีของจริง มีอยู่พารามิเตอร์หนึ่งที่ใช้คอนฟิกบอก Asterisk ให้รู้ว่าเน็ตเวอร์คหรือซับเน็ตอะไรบ้างที่เป็น internal พารามิเตอร์นี้คือ "localnet"
สมมติว่า IP ของ Asterisk คือ 192.168.0.55 ซับเน็ตมาส์ค 255.255.255.0 แสดงว่าซับเน็ตไอพี inside ของเราคือ 192.168.0.0 ซับเน็ตมาส์ค 255.255.255.0 ก็คอนฟิก localnet แบบนี้ครับ
localnet = 192.168.0.0/255.255.0.0
และถ้ามีหลายซับเน็ต มีหลายสาขา เช่น 192.168.0.0/255.255.255.0, 192.168.1.0/255.255.255.0, 192.168.2.0/255.255.255.0, 10.255.255.0/255.255.255.0 ก็ใส่แบบนี้
localnet = 192.168.0.0/255.255.0.0
localnet = 10.255.255.0/255.255.255.0
การติดต่อกับโฮสต์ที่อยู่ใน inside หรือ localnet นั้น Asterisk จะใช้ Private IP ติดต่อครับ
ในการติดต่อกับโฮสต์ที่อยู่ภายนอกหรือ "outside" นั้น Asterisk จะต้องใช้ Public IP ติดต่อ จะใช้ Private IP ไม่ได้เนื่องจากโฮสต์ใน Internet ไม่สามารถติดต่อกับโฮสต์ที่ใช้ Private IP ได้ ดังนั้นมีความจำเป็นอย่างยิ่งเลยนะครับที่ Asterisk จะต้องรู้ว่า "มันต้องใช้ IP และ Port อะไรในการติดต่อกับโฮสต์ภายนอก" เราต้องคอนฟิกบอก Asterisk ให้รู้จักวิธีการหาครับ โดยใช้พารามิเตอร์ใดพารามิเตอร์หนึ่งใน 3 พารามิเตอร์ดังต่อไปนี้
1. externip = hostname[:port]
คอนฟิกบอก address[:port] แบบ static ให้ Asterisk รู้โดยตรง เพื่อให้มันใช้ IP นี้ในการส่ง SIP และ SDP message กับโฮสต์ภายนอก ซึ่ง Asterisk จะเช็ค IP ของ hostname แค่ครั้งเดียวตอนที่เรารีโหลด sip.conf (ใช้คำสั่ง sip reload จาก Asterisk Console) ถ้าเราไม่ได้คอนฟิก port ใส่เข้าไปด้วยมันจะเอาเลขพอร์ตมาจากบรรทัด bindport ในไฟล์ sip.conf ซึ่งก็อาจจะทำงานได้ไม่ดีนักเนื่องจาก Port ที่โฮสต์ภายนอกเห็นอาจจะไม่ใช่ Port ที่ Asterisk ใช้จริงๆ เนื่องจาก ADSL Router อาจจะแปลง Port ไปเป็นค่าอื่นที่มันเห็นว่าเหมาะสมควรใช้พารามิเตอร์นี้ถ้าหากว่าเราสามารถคอนฟิก ADSL Router ให้แม๊บพอร์ตแบบ Static ได้ เช่นเร้าท์เตอร์ที่มีคุณสมบัติ Static NAT หรือ PAT
externip = 25.2.25.32
externip = 25.2.25.32:9900
externip = kikka.dyndns.org:12600
แม๊ปพอร์ต TCP (เมื่อใช้งาน SIP แบบ TCP) ที่จะใช้ติดต่อกับภายนอก "externtcpport" จะมีค่าดีฟอลท์เป็น port ของ externip หรือ externhost ถ้าระบุไว้
externtcpport=9900
แม๊ปพอร์ต TLS (ถ้าใช้งาน) เมื่อ Asterisk อยู่หลัง Static NAT หรือ PAT ดีฟอลท์พอร์ตของ externtlsport มีค่า 5061 เป็นพอร์ตมาตรฐาน
externtlsport=12600
2. externhost = hostname[:port]
คล้ายกับวิธี "externip" ยกเว้นตรงที่การใช้ "externhost" นี้นะครับจะมีการตรวจเช็ค (หรือที่เรียกว่า look up) hostname ทุกๆ "externrefresh" วินาที ดีฟอลท์คือ 10 วินาที วิธีนี้จะเป็นประโยชน์เมื่อเราคอนฟิกเลือกพอร์ตบน NAT Device ได้ แต่ IP เป็นแบบไดนามิค และวิธีนี้อาจมีปัญหาได้ถ้า Asterisk ไม่สามารถ lookup หาไอพีจาก DNS Server ได้
externhost = kikka.dyndns.org
externrefresh=60
และเราต้องคอนฟิก ADSL Router ให้ลงทะเบียนกับ Dynamic DNS ด้วยชื่อ kikka.dyndns.org
3. stunaddr = stun.server[:port]
Asterisk จะทำตัวเป็น STUN Client ไปคิวรี่ STUN Server ที่ระบุไว้ แล้วมันก็จะรู้ External (Public) IP Address และ Port ส่งไปคิวรี่ใหม่ทุกๆ "externrefresh" วินาที ข้อดีของการใช้ "stunaddr" นี้นะครับนอกจาก Asterisk จะรู้ Public IP และ Port แล้วยังเป็นการส่ง keepalive กระตุ้นให้ NAT Device เปิดพอร์ตค้างไว้ด้วย
stunaddr = stun.xten.com:3478
externrefresh = 30
ทั้ง 3 วิธีนี้นะครับต่างก็เป็นกลไกลที่จะทำให้ใช้งาน Asterisk หลัง NAT Device ได้ ซึ่งเมื่อ Asterisk ได้ค่า externip/externhost/stunaddr มาแล้ว มันก็จะเอามาใช้ทั้งตอนที่ส่ง SIP และ SDP message ไปยังโฮสต์ภายนอก แต่ถ้าแม๊บเบอร์ Port แบบ Static ไม่ได้ ก็อาจจะทำให้เกิดปัญหาการใช้งานได้ ต้องลองใช้งานดูครับ คนอื่นใช้แล้วมีปัญหาแต่เราอาจไม่มีปัญหาเหมือนเขาก็ได้ เพราะสิ่งแวดล้อมมันไม่เหมือนกันครับ เช่น ใช้เน็ตคนละเจ้า ใช้เร้าท์เตอร์คนละยี่ห้อ
แต่ผมข้อแนะนำในการเลือกใช้ externip, externhost และ stunaddr มาฝากครับ ว่ากรณีไหนควรจะใช้อะไร
1. ถ้า NAT device ทำการแม๊ป Port ลักษณะที่ว่า Internal Port และ External Port เป็นคนละค่ากัน (ADSL Router ส่วนใหญ่ก็ทำแบบนี้อยู่ครับ) การใช้ "externip" และ "externhost" อาจไม่ช่วยแก้ปัญหา ก็ให้ใช้ "stunaddr" แทน
2. เมื่อใช้ "externip" หรือ "externhost" ค่า IP Address ที่ Asterisk ใช้จะเป็นค่าที่ได้จากพารามิเตอร์ที่ใช้ และ Asterisk ก็จะใช้ IP นี้ใน SDP session ด้วย ถ้าเราใช้ "stunaddr" ตอนที่ Asterisk คิวรี่ไปที่ STUN เพื่อหา IP และ Port มันก็จะใช้ค่าที่ได้นี้ทั้งตอนที่ส่ง SIP และ SDP Message ก็จะแม๊บหมายเลข Port ได้ถูกต้อง
นอกจากนี้ Asterisk มีพารามิเตอร์ "nat" ด้วยซึ่งจะช่วยพิจารณาว่า SIP หรือ SDP session ที่มันกำลังรับเข้ามานั้น ส่งมาจาก Client ที่อยู่หลัง NAT หรือไม่ ซึ่งก็แล้วแต่ว่าเราคอนฟิกค่า "nat=" ไว้ยังไง บางครั้ง Asterisk จะเปลี่ยน IP Address/Port ใน SIP/SDP message เป็นค่าใหม่โดยแทนที่ด้วย IP Address ของต้นทางที่ส่ง Message มา เป็นประโยชน์ต่อ External Traffic ที่เข้ามายัง Asterisk
พารามิเตอร์ nat มีออปชั่นดังต่อไปนี้ครับ คอนฟิกได้ทั้งใน [general] และบนแต่ละ SIP account
nat = no
ดีฟอลท์ ใช้ rport ถ้า Client ต้องการใช้ (มี rport อยู่ใน message ด้วย)
nat = force_rport
ใช้ rport เสมอ
nat = yes
ใช้ rport เสมอและทำงานแบบ Symmetric RTP
nat = comedia
ใช้ rport ถ้า Client ต้องการใช้และทำงานแบบ Symmetric RTP
เราสามารถเปลี่ยนไอพีแอดเดรสที่จะใช้สำหรับมีเดีย (เช่น audio, video และ text) ใน SDP message ได้ด้วยนะครับ (ดีฟอลท์คือ IP Address ของ Asterisk เอง) ใช้พารามิเตอร์ "media_address" คอนฟิกได้ที่ [general] ที่เดียว
media_address = 192.168.4.55
บทความที่เกี่ยวข้อง
เทคนิคการติดตั้ง Asterisk ไว้หลัง NAT มีตัวอย่างให้ดู
เทคนิคการติดตั้ง Asterisk ไว้หลัง NAT device
เทคนิคการตรวจสอบและแก้ไขปัญหาไม่สามารถโทรหากันได้บน Elastix เมื่อ Net ดาวน์