VietFi.net Blog

NAT cứu tinh - NAT tội đồ (bài 2)

NAT để chia sẻ dịch vụ nhiều máy chủ, NAT để chia sẻ IP dịch vụ...
# NAT để mở dịch vụ ra Internet

Ở bài này tôi mô tả một ứng dụng hữu ích của NAT, được áp dụng rất phổ biến nhất là với Internet ở nhà bạn, đó là mở cổng dịch vụ ra Internet, dịch vụ từ một hoặc nhiều máy chủ phía sau một NAT gateway - hay cũng gọi là home router, Internet gateway.. tuỳ quy mô và nơi sử dụng. Kỹ thuật này có nhiều tên gọi, phổ biến là: "forward port", hoặc DNAT (destination NAT), hoặc Virtual Server. Tôi cũng nói về VoIP, các kỹ thuật ứng phó NAT dành cho client dùng dịch vụ VoIP mà đứng sau NAT như mô tả ở bài trước #2.

## Mô hình và kỹ thuật

Mô hình này, tương tự như chia sẻ một mạng LAN qua NAT gateway, một địa chỉ Public IP (hoặc có thể hơn một) được gắn cho giao tiếp mạng Internet của gateway, giao tiếp LAN còn lại thì sẽ được cố định và thường là default route của các máy trong mạng (ta gắn cho gw LAN địa chỉ 192.168.1.1 cho dễ). NAT gateway này sẽ đóng vai trò chia sẻ Internet cho các máy trong LAN nữa và vai trò này có ảnh hưởng ít nhiều tới dịch vụ.

Tùy thuộc vào giao thức lớp 4 và cổng tương ứng, mà dự định sẽ cung cấp ra, mà tạo rule. Thường thì giao thức TCP và các dịch vụ nổi tiếng như HTTP (80), HTTPS (443), SMTP hay SSH được chọn. Máy chủ bên trong cũng phải cố định địa chỉ LAN IP và chạy cùng giao thức, cổng dịch vụ không nhất thiết phải giống như cổng dự định cung cấp.

Phân tích kế tiếp nói kỹ hơn về quá trình này thông qua 1 ví dụ: cung cấp dịch vụ web HTTP (cổng 80), cho máy chủ có địa chỉ nội bộ 192.168.1.99 nhưng cổng dịch vụ đang chạy là 8080. Quản trị viên sẽ thiết lập NAT rule như sau:

* input Internet interface, destination = public-ip and tcp dest port = 80: change **destination to 192.168.1.99**, tcp dest port to 8080.
* *(tự động tạo)* input any interface, destination any, **source address = 192.168.1.99**, tcp source port = 8080: change source address to publish-ip, tcp source port 80

Khi client gửi gói TCP SYN yêu cầu kết nối tới public-ip và cổng chỉ định, trúng rule, thì hành động thay đổi diễn ra. Do bị thay đổi địa chỉ đích, nên tính chất định tuyến của gói tin thay đổi, **không còn là gửi tới chính dịch vụ trên gateway** nữa - dù gateway đang sở hữu public-ip hay có mở cổng dịch vụ đó - mà sẽ bị NAT rồi gói tin gửi tới đích mới. Bộ máy routing của gateway làm việc và nó sẽ ưu tiên định tuyến vào LAN subnet.

> Nếu không có NAT rule trên thì gói tin sẽ được chuyển cho cổng dịch vụ 80 trên chính gateway, do đó một số gateway trường hợp này để tránh vấn đề không vào được trang quản trị từ WAN/Internet, nó sẽ tự động đổi cổng quản trị sang cổng khác và thông báo cho bạn biết.

Gói tin đã bị thay đổi địa chỉ đích, được tiếp tục xử lý định tuyến bởi gateway và đi vào LAN tới máy chủ chỉ định. Server dịch vụ web sẽ nhận được gói tin như bình thường, như thể không hiện diện hành động NAT của gateway, và dịch vụ tiếp nhận kết nối sẽ trả về với gói tin SYN-ACK có địa chỉ nguồn đích đảo lại (nguồn server tức 192.168.1.99:8080).

Gateway nhận gói SYN-ACK từ server, đúng khớp rule tự động tạo kia (gọi là de-nat rule - giải trừ nat) để thay đổi lại địa chỉ cho phù hợp gói syn của client gửi tới (tức phải đúng là địa chỉ/cổng đảo nguồn đích), rồi mới định tuyến gói tin trả lại Internet. Các gói tin kế tiếp 2 chiều cũng tương tự lặp lại.

> Lưu ý rằng, nếu không có de-NAT rule kia thì gateway sẽ không hồi phục địa chỉ trả lời từ server sao cho hợp lý, client khi nhận gói tin nguyên mà server trả lại sẽ bỏ đi do sai khác địa chỉ nguồn. Nếu gói trả lại không trả lại đi cùng tuyến đến gateway, tức quay về Gw thì cũng không có de-NAT và sẽ bị client bỏ đi. Do đó cơ chế NAT này gần như là stateful, và rất nhạy cảm định tuyến nhiều hướng đi.

Không nhất thiết NAT rule chỉ đổi địa chỉ destination tới duy nhất 1 địa chỉ server IP, mà có thể là nhiều, xoay vòng nhau tùy thuộc client. Ví dụ có 2 server, thì client địa chỉ ip1 tới server1, ip2 tới server2, ip3 tới server1, ip4 - server2... Đây chính là kỹ thuật NAT áp dụng để cân bằng tải, cho phép nhiều server phục vụ và chia theo client (hoặc chia theo session).

Mặt khác, mỗi dịch vụ theo chuẩn sẽ có TCP/UDP port khác nhau, do đó có thể có nhiều rule trong đó mỗi rule một port và NAT vào các server khác nhau, cũng là hình thức san tải, tăng năng lực phục vụ.

## Điểm lợi và vấn đề

Điểm lợi đầu tiên là NAT cho phép chia sẻ: bạn chỉ có 1 public-ip nhưng lại có nhiều server, nhiều dịch vụ khác nhau? Hãy NAT. Đây là cách hiệu quả và đơn giản. Do đó, với mạng gia đình được NAT thì các router gia đình thường có sẵn khả năng NAT này (forward port).

Điểm lợi thứ hai: bạn có thể đổi port dịch vụ (quảng bá) khác với port mà server chạy giống ví dụ bên trên, để xử lý việc trùng port. Tuy không phải lúc nào đổi port cũng có thể áp dụng vì tùy thuộc giao thức, và với web app (HTTP) thì rất tùy thuộc vào app nào và cách tạo ra địa chỉ URL của nó, nhưng nói chung là không gặp vấn đề với đa số trường hợp.

Các vấn đề của nó, thường liên quan đến chính dịch vụ và máy chủ cung cấp dịch vụ, do lúc này máy chủ có IP là nội bộ, mà dịch vụ đó lại quảng bá ra là Public IP của gateway nên có sự sai khác. Thường thì một số dịch vụ cần IP Server này sẽ yêu cầu bạn phải khai báo địa chỉ Public IP nào và sẽ gặp khó khăn khi địa chỉ này lại động. Chi  tiết hơn tôi sẽ viết ở mục riêng bên dưới.

## Triển khai thực tế và quy mô

Như bạn thấy, khác với trường hợp NAT cho client dùng dịch vụ, NAT cho server cung cấp dịch vụ nói chung gw không cần state table, và cũng không lo lắng vì xung đột source port, trừ khi port được forward vào có thể bị dùng làm source port truy cập (và gateway đủ thông minh để tránh các nat rule trên). Do đó, dạng NAT này không gặp vấn đề hiệu năng dù thiết bị gateway không khỏe, gateway chỉ phải tác động lên gói tin header layer 3 và có thể thêm 4, không cần lưu trạng thái, nên tốn rất ít tài nguyên.

Tuy nhiên, do giới hạn của số lượng port tcp và udp, cộng với việc sử dụng chung IP cho nhiều server. Khiến ở quy mô lớn, việc NAT này rơi vào tình trạng thiếu số port để tạo phiên. Vấn đề này sẽ được mô tả ở một bài riêng.

## NAT địa chỉ 1-1 (layer 3 header only)

Có một kỹ thuật là trường hợp riêng của NAT cung cấp dịch vụ, là gateway có rule đơn giản hơn, chỉ đổi mỗi phần địa chỉ gói tin ở layer 3 header. Tức là lúc này mọi gói tin có địa chỉ chỉ định ở rule sẽ được đổi, bất kểt ip protocol bên trên ra sao.

Kỹ thuật này gọi là NAT 1-1, ánh xạ 1 địa chỉ public ip với 1 internal ip. Trong router gia đình thì tính năng kỹ thuật này gọi là DMZ host, tuy hoạt động có khác chút là ** tất cả gói tin không khớp rule nào thì chuyển cho host đó**. Bạn có thể tìm thấy màn hình thiết lập tham số này ở modem nhà bạn, ví dụ như cái nhà tôi, Linksys thì nó như hình chụp sau:

![DMZ Host NAT setup](linksys-dmz-setup.jpeg)

Kỹ thuật này ít được áp dụng rộng rãi vì nó không có thêm ưu điểm nào ngoài việc 1 rule đơn giản, chạy nhanh hơn, nhưng vẫn thừa kế hàng loạt nhược điểm khác, và đặc biệt nó bắt buộc dành riêng 1 địa chỉ public IP cho mỗi máy, do đó nó không tận dụng được public IP cho nhiều việc, nhiều port dịch vụ khác nhau.

## Tình huống hài hước: LAN PC truy cập dịch vụ Public IP

Có 1 tính huống khá hài hước là, nếu PC trong LAN truy cập vào cổng 80 trên Public IP của NAT Gw thì sao? Bởi thường thì người ta sẽ không dùng IP - do nó là dynamic và gõ số thì cũng không thân thiện lắm - mà người ta dùng tên miền DNS, hay gặp nhất là một dynamic DNS tức tên miền của host được cập nhật theo sự thay đổi theo Public IP của NAT gw.

Ví dụ gần giống như trên, ta dùng tên *someweb.no-ip.com* gắn với Public IP ví dụ trên và forward port 80 vào 192.168.1.99:8080 (PC1). No-IP một dịch vụ dynamic DNS miễn phí khá tốt và không chơi không fair người dùng mua dịch vụ như đối thủ lớn nhất của họ. Giờ ta giả sử 1 PC khác trong LAN - PC2 - có địa chỉ là 192.168.1.88, truy cập dịch vụ theo tên và cổng 80 (chứ không tính tình huống nhập LAN IP và cổng 8080). Các bước sẽ như sau:

1. PC2 phân giải DNS tên someweb.no-ip.com, ra địa chỉ public IP, không phải cùng LAN nên nó gửi cho Gw.
2. Gw nhận thấy đây là 1 Interface Address của nó, dù là kênh Internet, nó xử lý sẽ áp rule theo luật đã lập.
3. NAT Rule sẽ áp dụng vào cổng 80, gói tin SYN sẽ bị **đổi phần đích đến là 192.168.1.99** và cổng TCP sang 8080, phần **địa chỉ nguồn không tác động** gì cả.
4. Gw định tuyến gói tin này, nó quay ngược trở lại LAN đến PC1.
5. PC1 nhận gói SYN, thấy cổng hợp lệ dịch vụ đang phục vụ, nó tiếp nhận và tạo gói SYN-ACK trả lời. Tuy nhiên gói SYN-ACK này có nguồn là **192.168.1.99**, đích lại là **192.168.1.88**.
6. Gói tin được PC1 định tuyến vào LAN vì nó cùng subnet, tới PC2.
7. PC2 nhận gói SYN-ACK, tỏ ra **bối rối vì không biết xử lý** ra sao cả. Bởi gói nhận được **không ăn khớp** bắt cặp địa chỉ đảo ngược với **gói SYN nó vừa gửi đi** (nguồn chính nó, đích là Public IP của Gw cơ mà?). Nó reset và bỏ phiên kết nối.

Như phân tích ở trên, NAT rule trong trường hợp này sẽ không chạy. Các bạn khi thực hiện forward port ở home router, thì khi các bạn vào đúng mạng LAN của home router đó, bạn không thể vào dịch vụ đã forward được. Nếu ở ngoài mạng, dùng 3G thì được, bởi lý do phân tích ở trên.

Nhưng có vài loại home router lại vẫn truy cập được, camera xem tốt dù ở ngoài hay ở trong, tại sao thế? Có gì tôi phân tích ở trên bị sai hay sao? Không phải đâu, một số loại router tự thêm 1 rule sau vào bảng NAT rule của nó, nằm trước cả NAT rule forward port:

* input LAN interface, source = LAN subnet, destination = public-ip and tcp dest port = 80: change **source to 192.168.1.1**, destination to 192.168.1.99, tcp dest port to 8080.

NAT gw đã đổi cả địa chỉ source thành chính địa chỉ Public của nó. Lúc này, ở bước số 3 của ví dụ trên, địa chỉ nguồn cũng bị thay đổi trước khi gửi cho PC1, PC1 phản hồi SYN-ACK về 192.168.1.1 chứ nó không gửi thẳng cho PC2 như trên, khi gói tin về đến 192.168.1.1, thì **De-NAT rule làm việc**, nó giải NAT rồi trả lại gói SYN-ACK cho PC2. Bước ép cho gói trả về (đảo ngược địa chỉ) phải đi vòng qua NAT gw 1 lần nữa, giống như máy bên ngoài truy cập dịch vụ của PC1 qua cổng được forward đó, chính là để De-NAT. Ở tình huống này thì vấn đề truy cập được giải quyết, nhưng ở trong cùng LAN truy cập cũng vẫn khiến NAT Gw chịu tải do gói tin đi vòng vèo qua nó (kết nối LAN bao giờ cũng lớn hơn Internet, do đó lượng dữ liệu có thể nhiều hơn cả đi Internet).

Do đó khi triển khai dịch vụ traffic lớn, việc NAT kiểu này mà có nhiều giao tiếp nội bộ giữa các dịch vụ, máy chủ trong vùng NAT, thì sẽ gây tăng tải vô ích cho gw, muốn tránh thì phải dùng địa chỉ LAN IP của PC1 (kèm 1 với rắc rối khác port so với public, nếu có khác port). NAT để mở cổng dịch vụ lẫn phục vụ nội bộ là không tốt trong trường hợp này.

# Các dịch vụ tốt & không hoạt động tốt với NAT

Vấn đề lớn nhất khi áp dụng kỹ thuật NAT (forward port) ở đây chủ yếu là dịch vụ hoặc giao thực chạy, với đa số dịch vụ thì không có vấn đề, nếu chúng được xác định **tương thích với NAT** hay **NAT friendly**. Tuy nhiên số còn lại thì gặp vấn đề lớn, khó giải quyết và đôi khi do trách nhiệm giải quyết sự cố lại ở tầng hoạt động khác nhau (NAT ở tầng mạng mà dịch vụ lại tầng 7), nên các sys admin hay net admin lúng túng đổ lỗi cho nhau. Nói chung nếu bạn có thể tránh được kỹ thuật NAT thì tốt hơn bởi khai sinh ra Internet người ta thiết kế không có NAT, và các giao thức cổ xưa hoặc dạng **peer to peer** là hay gặp vấn đề hơn cả.

> tôi sẽ coi vấn đề của NAT là của NAT forward port nhiều hơn là vì NAT ở phía sử dụng dịch vụ (tức client - nói ở bài trước [2|NAT cứu tinh - NAT tội đồ (bài 1)], do với client chúng ta không có lựa chọn, một số trục trặc do NAT của client nói ở bài trước, vẫn có thể giải quyết được nhờ **không NAT ở server**.

Các giao thức sau đây là **tương thích với NAT**:

* **HTTP và HTTPS**: đây là giao thực phổ biến nhất, nó may mắn là tương thích NAT. Do việc truyền lệnh (request/response) và dữ liệu (trong body, content) thì đều nằm cùng trên 1 phiên kết nối (TCP) nên cả client và server không quan tâm nhiều đến địa chỉ kết nối nữa, một khi phiên TCP đã thiết lập.
* Các giao thức email **SMTP, IMAP4 và POP3**: tương tự, các giao thực trên cũng không mấy quan tâm đến địa chỉ (trừ SMTP có quan tâm để chống SPAM).
* SSH và Telnet: cũng rất ok với NAT, trừ việc có thể có *timeout* state table khiến kết nối bị đứt khi giữ lâu mà không truyền gì (ví dụ gõ lệnh chờ lâu không in ra gì, dễ khiến đứt kết nối, mất phiên truy cập và kết quả lệnh chạy không rõ ra sao).
* Nhiều giao thức dựa trên TCP khác, nếu không trao đổi địa chỉ bên trong payload. Và không đòi hỏi Real time.

## FTP và FTPS: không tương thích NAT nhưng có thể gateway hỗ trợ

FTP là giao thức truyền file cổ xưa, có từ thời TCP/IP được phát minh ra. Qua nhiều cải biến (nhờ các RFC) để hỗ trợ, đến nay thì FTP cũng không còn phổ biến Internet, một phần vì nó không tương thích NAT, một phần do nó được thiết kế không tính tới các yếu tố bảo mật, gặp nhiều vấn đề với bảo mật.

Phân tích một chút để hiểu tại sao FTP không tương thích NAT, tôi mô tả sơ bộ cách thức hoạt động của FTP và vấn đề như sau:

1. FTP có **kênh điều khiển** độc lập **kênh data**: kênh điều khiển là phiên TCP kết nối tới port 21 của server, sau khi thực hiện xác thực, thì client bắt đầu gửi các lệnh (LIST, GET, PUT) và nhận thông tin mã lỗi, thông tin bắt tay kênh data (thường qua port 20). Sau đó kênh data được bắt tay (động, tức sau lệnh mới bắt tay) thì dữ liệu mới được gửi hoặc nhận qua đó.
2. Chính cách thiết kế tách rời 2 kênh, trong đó kênh data tạo ra tùy thuộc trao đổi trong kênh điều khiển (gồm địa chỉ IP 2 bên, port 2 bên), khiến cho FTP khó khăn khi tạo kênh data và chúng ta hay thấy "treo" sau lệnh GET/PUT.

Kênh data của FTP có 2 kiểu bắt tay: active (PORT) và passive (PASV):

* Ở chế độ active (PORT), thì cllient sẽ gửi địa chỉ IP và port của nó đã mở sẵn, gửi cho server qua lệnh **PORT thông-số**, chờ server kết nối lại (với source port là 20) để đẩy dữ liệu vào đó (lúc này client trở thành TCP server của port đó).
* Ở chế độ passive (PASV), thì client gửi lệnh PASV, server trả về địa chỉ IP và port (thường là port 20 hoặc tùy ý), và client kết nối vào đó, gửi nhận dữ liệu qua đó.

![Hình minh họa bắt tay kênh data của FTP ở Wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Passive_FTP_Verbindung.svg/640px-Passive_FTP_Verbindung.svg.png)

Ở đây ta thấy rõ vấn đề, với chế độ FTP active, thì buộc client phải gửi IP/port của nó, điều gì xảy ra nếu client đang đứng sau NAT gateway nào đó? Nó sẽ không biết và chỉ biết lấy IP của nó (gắn trên máy nó) chứ không phải IP gateway để gửi. Và khi server kết nối ngược lại, đương nhiên không thể được. May mắn thay, nhiều NAT gateway đủ thông minh và nó có một tính năng gọi là FTP ALG (application layer gateway), nó lắng nghe trên port 21 TCP khi client gửi ra, nếu phát hiện lệnh PORT của FTP, nó tự động đổi IP của gateway trong PORT thông-số ở phiên điều khiển FTP này và gửi cho server, server kết nối lại thì tự động nó forward vào đúng client, phiên kết nối hoàn thành. Chỉ có vấn đề khi server dùng FTP port khác chuẩn 21 mà thôi (tức FTP ALG không kích hoạt ở port khác).

Ở chế độ passive thì sao? giờ vấn đề lại chuyển cho phía server. Server gửi IP/Port của nó cho client qua kênh điều khiển. Nếu nó đang cung cấp dịch vụ thông qua NAT forward port thì sao? lúc đó vấn đề lại xảy ra tương tự, sai IP (không phải public IP mà lại là private IP của server) và một lần nữa, FTP ALG lại trợ giúp. Dĩ nhiên nếu server không chạy qua NAT thì luôn thành công, do chả bao giờ nó gửi sai IP trong thông-số cả.

FTP ALG đã giúp ích cho đa số trường hợp với FTP, trừ khi bạn đổi port FTP chuẩn từ 21 qua cái khác, thì phải khai báo kích hoạt ở NAT gateway rằng FTP ALG sẽ giám sát trên port đó. FTP ALG thực sự chỉ có vấn đề khi bạn chạy FTPS (FTP over SSL/TLS), lúc này kênh điều khiển 21 đã được mã hóa SSL để an toàn, FTP ALG chịu thua không thể vọc vào phiên TCP đó được, và lúc này thì FTPS chỉ chạy được nếu không có NAT, hoặc FTPS Server khai báo đúng Public IP/Port sẽ gửi đi cho client mà thôi.

Trường hợp FTP server phía sau NAT gw thì sao? Điều tương tự xảy ra và ALG giúp ích cho 1 số trường hợp, cũng sẽ rất khó khăn và rất không nên chạy như thế.

## VoIP hay OTT các kiểu: rất khó xài NAT

Khác với dạng dịch vụ gia tăng khác, VoIP tuy ra đời sau khi có NAT nhưng do đặc tính truyền gói tin mã hoá âm thanh/hình ảnh, cần độ trễ thấp nên các giao thức VoIP đều sử dụng các kĩ thuật sau:

1. Sử dụng giao thức UDP để truyền hình ảnh, âm thanh. Kênh truyền này gọi là media channels, rất hay được triển khai là RTP (Real time protocol). Lý do dùng UDP là vì UDP không bắt tay, không truyền lại nếu mất, ít trễ xử lý... nhược là các chuẩn mã hoá âm thanh phải chấp nhận sự mất gói của UDP, tỉ lệ mất càng cao chất lượng âm thanh càng kém.
2. Luôn có xu hướng truyền trực tiếp giữa 2 peer tham gia vào cuộc gọi, để giảm trễ mạng luôn có. Một số trường hợp đặc biệt nó mới truyền qua một trung gian gọi là relay server.
3. Các giao thức VoIP hay OTT đều có kênh truyền gói tin điều khiển riêng, đôi khi được sử dụng để truyền cả thông điệp ít cần real time (như chat message) sẽ được trung chuyển qua server dịch vụ.

Để đáp ứng điều số 2, hầu như các giao thức đều trao đổi cho cả 2 peer địa chỉ của bên kia, để các peer khi truyền RTP sẽ truyền thẳng cho nhau không qua server, bạn nhìn 2 ví dụ gói tin giao thức SIP - một giao thức VoIP phổ biến - sẽ thấy có thông tin này (tôi copy từ tài liệu của IETF):

~~~
F1 INVITE User A -> User B:

   INVITE sip:UserB@there.com SIP/2.0
   Via: SIP/2.0/UDP here.com:5060
   From: BigGuy <sip:UserA@here.com>
   To: LittleGuy <sip:UserB@there.com>
   Call-ID: 12345601@here.com
   CSeq: 1 INVITE
   Contact: <sip:UserA@100.101.102.103>
   Content-Type: application/sdp
   Content-Length: 147

   v=0
   o=UserA 2890844526 2890844526 IN IP4 here.com
   s=Session SDP
   c=IN IP4 100.101.102.103
   t=0 0
   m=audio 49172 RTP/AVP 0
   a=rtpmap:0 PCMU/8000

... lược bỏ ...

F4 200 OK User B -> User A

   SIP/2.0 200 OK
   Via: SIP/2.0/UDP here.com:5060
   From: BigGuy <sip:UserA@here.com>
   To: LittleGuy <sip:UserB@there.com>;tag=8321234356
   Call-ID: 12345601@here.com
   CSeq: 1 INVITE
   Contact: <sip:UserB@110.111.112.113>
   Content-Type: application/sdp
   Content-Length: 147

   v=0
   o=UserB 2890844527 2890844527 IN IP4 there.com
   s=Session SDP
   c=IN IP4 110.111.112.113
   t=0 0
   m=audio 3456 RTP/AVP 0
   a=rtpmap:0 PCMU/8000

F5 ACK User A -> User B
...
~~~

Bạn sẽ thấy UserA ở địa chỉ *100.101.102.103* khi gọi cho UserB ở địa chỉ *110.111.112.113*, gói INVITE và trả lời 200 đều chứa thông tin địa chỉ này ở trong SDP để bên kia biết mà gửi. Dĩ nhiên cả port và thông tin loại mã hoá áp dụng, ở đây là PCMU/8000 được chọn.

Vậy **điều gì nếu User A hoặc B ở sau NAT Gw?** như bài trước, client trên PC hay IP Phone sẽ chỉ nhận được 1 địa chỉ private, và nếu không có gì đặc biệt thì **nó không có ý niệm gì về public IP address** mà gw đang sở hữu. Thực chất client public IP là không thể biết nếu không có sự trợ giúp gw hoặc từ ngoài. Nếu nó điền địa chỉ private là 192.168.0.5 chẳng hạn khi INVITE cuộc gọi, thì phía user B nhận được cũng không thể dùng nổi thông tin này, gửi trực tiếp RTP sẽ không đến được.

Để truyền được RTP, thì điều bắt buộc với giải pháp phải là: 

* user A và B phải biết được thông tin địa chỉ IP truyền trực tiếp đến cho nhau, bên này biết bên kia, dù địa chỉ đó nếu là đại diện (là public IP của NAT gw) thì cũng phải gửi cho đúng. Vậy là user client phía sau NAT gw cần được biết IP public của chính gw mà nó sẽ đi ra (nếu bạn có nhiều gw, nhiều IP thì chọn 1 đúng cái nó sẽ dùng).
* gửi gói RTP đến IP port khi bắt tay xong đó, phải đến được port nhận cuối cùng, cả hai chiều thông nhau. Nếu chỉ có 1 thì bên này nghe thấy bên kia nói mà bên kia không nghe thấy gì cả.

Các giải pháp mà người ta đã nghĩ ra để giải quyết tình trạng này như sau:

1. Giải pháp **ALG**: tương tự FTP, nhiều home router hỗ trợ SIP ALG. Tuy nhiên giao thức nào có ALG và đúng port mới chạy, ok không phải làm gì. Và nó cũng bó tay nếu chạy SIPS (SIP over TLS) có mã hoá do không vọc vào được. Các OTT độc quyền là thua vì chả có ALG nào hỗ trợ. Ở giải pháp này thì client nói chung không cần biết public IP mà nó dùng, ALG tự biến đổi gói SIP để nó đúng địa chỉ. Nhưng rất tiếc không phải gw nào cũng có ALG, tỉ dụ pfSense.
2. Giải pháp tự **forward port**: cái này khỏi nói, thủ công và không áp dụng nếu bạn không thạo kĩ thuật.
3. **UPnP hỗ trợ bởi home router** và cả IP Phone: đây là giải pháp thường thấy cho home router và giải quyết nhiều vấn đề NAT khác. Rất tiếc nó không thể áp dụng cho mạng doanh nghiệp nhiều tầng lớp mạng, và nó cũng gây ra một số vấn đề bảo mật. Tôi sẽ nói mục này kĩ hơn sau.
4. Giải pháp **đục lỗ NAT** (NAT traversal) trên gw bằng mẹo: các giải pháp này là STUN, ICE, TURN. Các giải pháp này có thể chạy trong một số tình huống thôi (như gặp gw có restrict NAT là thua). Tuy thế đây cũng vẫn là các cách work around, không toàn diện, nó thường chậm khi mở kết nối. Lưu ý các cách này chỉ đáp ứng cho các giao thức RTP chạy UDP mà thôi.
5. Giải pháp **relay server** hay B2BUA: giải pháp này là chia đổi hai bên NAT thành 2 hướng truyền qua trung gian, không phải NAT mà thực sự là chân (leg) trong cuộc gọi VoIP. Cách này là cách mà các OTT hay áp dụng nhất. Tôi nói về cái này ở mục kế tiếp.

### B2BUA cho VoIP

Tôi mượn hình sau đây từ wikipedia.org để mô tả tình huống SIP Server kiêm Media relayer sẽ có các bước trao đổi để tạo cuộc gọi.

![back to back call flow](https://upload.wikimedia.org/wikipedia/commons/e/e2/SIP-B2BUA-call-flow.png)

Mô hình trên được gọi là back to back user agent call. Mô hình này cho phép 2 thuê bao Alice và Boris có thể gọi cho nhau, dù cho về mặt IP họ không thể trao đổi trực tiếp được, lỗi ví dụ do vướng NAT, công nghệ hoặc giao thức khác nhau. B2BUA sẽ có cả 2 chân (có 2 kết nối mạng), mỗi bên sẽ giao tiếp trực tiếp IP/UDP với thuê bên cần và server sẽ trung chuyển gói tin media RTP hai bên, và khi bắt tay kết nối mỗi bên khi INVITE/200 response, thì B2BUA lấy địa chỉ IP hai chân tương ứng của nó để gửi chứ không dùng địa IP của Alice gửi Boris hay ngược lại. Một dịch vụ trên B2BUA sẽ mở cổng cho cả 2 phía, nhận bên này chuyển lại cho bên kia và ngược lại.

B2BUA là giải pháp rất hiệu quả khi nó đóng vai trò gateway giữa mạng nội bộ và Internet, giữa mạng IP với mạng thoại TDM, hay cả IPv4 và IPv6, giúp cuộc gọi diễn ra thông suốt dù hai bên không trực tiếp giao tiếp. Phần mềm Asterisk VoIP Software áp dụng giải pháp này phổ biến, đặc biệt khi chạy giao thức IAX của riêng nó (IAX và IAX2 là tương thích NAT, do nó không hỗ trợ peer to peer mà chỉ hỗ trợ B2BUA). Nhược điểm là B2BUA hoặc bất kỳ relay server nào cũng sẽ phải gánh trách nhiệm trung chuyển tất cả traffic RTP giữa 2 bên, tải nặng nếu nhiều hơn, lại có thêm trễ xử lý lẫn trễ đường truyền đi và về, băng thông nhân 2, nên thường chỉ chạy được ở quy mô nhỏ (đến 100 cuộc gọi cùng lúc là hiếm có).

B2BUA cũng dùng để giải quyết trường hợp 2 client đều ở phía sau NAT Gw, nên khó trao đổi trực tiếp RTP được, thông qua B2BUA để trung chuyển. Trường hợp này gọi là VoIP Relay Server. Thực tế nó phụ thuộc dịch vụ Internet bạn dùng nó triển khai ở đâu, nếu dịch vụ ở Vn, relay server ở Vn thì trễ thấp (50ms), call chất lượng sẽ thấy ok. Chứ nếu server đặt bên Mỹ, ping thông thường mất đến 300-500ms, thì bạn sẽ thấy âm thanh cuộc gọi rất tệ, như nói chuyện với người ở Sao Hoả ấy.

### Peer to peer với TCP: relay hoặc UPnP

Như bạn biết, với UDP thì các giải pháp đục lỗ NAT hoặc ALG là chạy được. Nhưng nếu truyền tin tin cậy dùng TCP giữa 2 user A và B sau NAT thì sao? Tỉ dụ truyền file giữa 2 máy chạy Skype chat với nhau.

Bạn có để ý rằng, nếu dùng Skype cùng mạng LAN, thì hai người truyền file qua nhau sẽ rất nhanh, nhưng khác mạng thì lâu, chậm hơn hẳn. Lý do là Skype hoặc Jabber, hoặc các trình chat PC khác nó sẽ thực hiện mở kết nối theo thứ tự sau:

1. Trực tiếp, dĩ nhiên user A biết địa chỉ user B, địa chỉ private mà PC đang nhận.
2. Qua thiết lập forward port động bởi UPnP: một bên biết public IP bên kia, qua sự hỗ trợ của UPnP.
3. Trung giao qua proxy (hay relay server) của nhà cung cấp dịch vụ chat. Skype gọi tình huống này là relay qua SuperNode. Với phiên bản cũ trước khi Skype bị Microsoft thâu tóm thì Super node thường chính là các PC cài trên client, đang login và có public IP hoặc UPnP, các PC này sẽ bị biến thành trạm trung chuyển dành cho tình huống NAT ngăn cản phương án 1 xảy ra. Do trung gian đó là chính, tận dụng chính máy PC cũng là của Skype user nên Skype mới được gọi là peer to peer network, nhà cung cấp dịch vụ có rất ít super node do họ vận hành.

Như trên nhắc đến UPnP, vậy nó là gì? UPnP hay Universal Plug and Play, là một chuẩn do Intel và một số công ty công nghệ sáng tạo ra. Nó là công nghệ giao tiếp dành cho device nói chuyện với device, hay là dành cho IoT. UPnP được dựa trên HTTP nhưng nó chạy trên UDP, địa chỉ trao đổi là multicast/broadcast. Nên nó có thể trao đổi trong cùng subnet mạng LAN một cách tự động giữa 2 device. Chi tiết xin tham khảo thêm về [UPnP trên Wikipedia](https://en.m.wikipedia.org/wiki/Universal_Plug_and_Play).

Dù UPnP không phổ biến như ý định nhà thiết kế, tỉ dụ thiết bị đèn thông minh kết nối wifi theo demo sẽ hỗ trợ UPnP để mở tắt đèn, rất hiếm có. Nhưng UPnP lại rất phổ biến trong wifi home router và các ứng dụng Internet cần forward port cho NAT, điển hình là Skype. Ngoài ra UPnP cũng phổ biến cho thiết bị lưu trữ, phát nhạc hoặc smart TV trong mạng wifi/LAN gia đình, với sự đi kèm thêm của chuẩn gọi là DLNA.

UPnP trên home router hay gateway của mạng gia đình, nó có thể làm các điều sau:

1. Giúp các client trong LAN có thể xác định đang có 1 router hỗ trợ/bật chạy UPnP, và cho biết thông tin model, loại, nhà sản xuất, địa chỉ IP cả public và private, loại kết nối, trạng thái kết nối của router với Internet... (Mấy cái hình vẽ đẹp đẹp, sơ đồ mạng nối Internet trong Win 7 là do cái này cung cấp).
2. Nhận yêu cầu mở và forward port từ ứng dụng lúc cần thiết, cả cho TCP và UDP, nếu client cần gửi yêu cầu tới và router chấp nhận.
3. Có thể thậm chí ra lệnh disconnect, connect kết nối Internet nếu router cho phép.

> UPnP cũng được dùng tích cực bởi các game online, các ứng dụng OTT trên cả điện thoại thông minh nữa. Gần như hỗ trợ nó là de-factor của các home router hiện nay.

Hình sau tôi lấy đâu đó trên Internet, để thể hiện thông tin mà home router cung cấp cho máy chạy Windows 7. Đó là lợi ích thấy được của UPnP và bạn biết mạng của bạn đang chạy nó, máy biết được gw hãng nào, có dây hay không. Tuy nhiên biết các PC khác cùng mạng thì do giao thức khác.

![win 7, switch và home router trong network map](win7-network-map.png)

UPnP chỉ chạy được nếu các client cùng LAN, cùng subnet vì trao đổi nó là  multicast, broadcast. Nếu như bị triển khai double NAT, hoặc với mạng doanh nghiệp phức tạp, thì nó không chạy được.

Một điểm dở nữa của UPnP là bảo mật. UPnP không có xác thực, nếu cho mở cổng forward port từ yêu cầu của client, thì client nào trong mạng cũng mở được. Nếu như 1 client trong mạng của bạn dính mã mồi của chương trình virus, nó có thể cậy nhờ UPnP của gw mở cổng ra Internet và đã mở đường từ ngoài đi vào mạng LAN của bạn thông qua PC đó hoặc PC bất kì trong mạng khác nó muốn (do với UDP bạn có thể spoof IP dễ dàng, ra yêu cầu với IP giả với gateway).

----------------------------

Còn tiếp, tôi sẽ viết bài 3 với Carrier NAT, NAT quy mô cực khủng.

Add new comment



Comments

1. Thach Anh Tran

Tôi không có thời gian để viết nữa... hic. reply

> full lists