بخش ۲: مبانی شبکه
اگر این سه موضوع را از هم جدا کنید، config WaterWall سادهتر میشود:
- ترافیک از کجا وارد WaterWall میشود؟
- WaterWall چه کاری روی ترافیک انجام میدهد؟
- WaterWall ترافیک را در ادامه به کجا میفرستد؟
در بیشتر مثالها، مسیر ترافیک را با فلش نشان میدهیم:
TcpListener -> MuxClient -> VlessClient -> TlsClient -> TcpConnector
ترافیک از سمت چپ وارد میشود، در جهت upstream از chain میگذرد و پاسخها در جهت مخالف و بهصورت downstream بازمیگردند.
آدرسهای IP
آدرس IP یک host یا interface را در شبکه مشخص میکند.
چند نمونهی متداول:
127.0.0.1 local machine only
0.0.0.0 bind on all IPv4 interfaces
192.168.1.10 private LAN address
203.0.113.10 public IPv4 documentation address
::1 IPv6 loopback
:: bind on all IPv6 interfaces
در nodeهای listener، گزینهی address معمولاً همان آدرس محلی است که node باید
روی آن bind شود.
در nodeهای connector، گزینهی address معمولاً مقصدی راه دور است که node باید
به آن متصل شود.
پورتها
پورت، یک سرویس را روی آدرس IP مشخص میکند. برای مثال:
22 SSH
53 DNS
80 HTTP
443 HTTPS
8080 common test HTTP port
معمولاً فقط یک process میتواند همزمان روی ترکیب یکسان آدرس، پروتکل و پورت گوش دهد. اگر WaterWall نتواند یک listener را bind کند، ممکن است process دیگری از قبل آن پورت را در اختیار داشته باشد.
در Linux، socketهای TCP در حال listen را با دستور زیر بررسی کنید:
ss -ltnp
برای UDP:
ss -lunp
TCP
TCP یک پروتکل connection-oriented است و میان دو endpoint یک stream میسازد.
در WaterWall، ترافیک TCP معمولاً با TcpListener آغاز میشود و به TcpConnector
میرسد:
client -> TcpListener -> ... -> TcpConnector -> remote server
TcpListener اتصالهای TCP ورودی را میپذیرد و بهازای هر اتصال پذیرفتهشده یک
line در WaterWall میسازد. TcpConnector در سوی دیگر chain، اتصال TCP خروجی را
باز میکند.
برای پروتکلهایی مانند HTTP، HTTPS، SSH، SOCKS و بیشتر ترافیک تونلهای proxy-style از TCP استفاده کنید.
UDP
UDP یک پروتکل message-oriented است و بهجای stream پیوسته، datagram میفرستد.
WaterWall برای هر دو حالت stateful و stateless، nodeهای UDP دارد:
UdpListener -> ... -> UdpConnector
UdpStatelessSocket -> packet-oriented chain
UDP معمولاً برای DNS، QUIC، WireGuard، ترافیک بازیها و انتقال صدا و تصویر بهصورت real-time به کار میرود. چون UDP بهتنهایی stream نمیسازد، nodeهای مرتبط در WaterWall باید نحوهی تشخیص peer و مسیریابی packetها را تعیین کنند.
localhost، IP خصوصی و IP عمومی
آدرس 127.0.0.1 فقط اتصالهای همان دستگاه را میپذیرد و برای تست محلی مناسب
است.
آدرسهای خصوصی مانند 10.0.0.0/8، 172.16.0.0/12 و 192.168.0.0/16 در شبکههای
خصوصی استفاده میشوند و مستقیماً از اینترنت عمومی در دسترس نیستند.
آدرس عمومی VPS زمانی از اینترنت در دسترس است که هم firewall شرکت ارائهدهنده و هم firewall سرور، پورت موردنظر را مجاز بدانند.
برای یک listener عمومی WaterWall روی VPS، معمولاً از آدرس bind زیر استفاده میشود:
{
"address": "0.0.0.0",
"port": 443
}
برای listener تست که فقط باید محلی باشد:
{
"address": "127.0.0.1",
"port": 8080
}
DNS و نام domain
nodeهای connector میتوانند از نام domain استفاده کنند:
{
"address": "example.com",
"port": 443
}
WaterWall domain را با DNS resolver مشترک خود resolve میکند. سیاست پیشفرض انتخاب
آدرس در dns.domain-strategy فایل core.json تنظیم میشود.
اگر domain هم رکورد IPv4 و هم IPv6 داشته باشد، domain-strategy مشخص میکند
WaterWall کدامیک را در اولویت قرار دهد.
NAT و port forwarding
بسیاری از دستگاهها پشت NAT قرار دارند. یک دستگاه با آدرس خصوصی معمولاً میتواند به بیرون متصل شود، اما clientهای بیرونی نمیتوانند به آن اتصال ورودی برقرار کنند؛ مگر اینکه router یا cloud firewall پورت را forward کند.
یک TCP forward ساده چنین مسیری دارد:
client -> VPS:8080 -> WaterWall -> example.com:80
chain WaterWall:
TcpListener(0.0.0.0:8080) -> TcpConnector(example.com:80)
این chain streamهای TCP را forward میکند، اما header مربوط به Host در HTTP را
خودکار تغییر نمیدهد و باعث نمیشود server مقصد تصور کند client مستقیماً به آن
متصل شده است.
streamها و packetها
WaterWall از ترافیک مبتنی بر stream و packet پشتیبانی میکند.
در مدل stream، دادهها بهصورت دنبالهای پیوسته از byteها منتقل میشوند:
TcpListener -> EncryptionClient -> TcpConnector
در مدل packet، با IP packetها یا datagramهایی سروکار داریم که مثل packet پردازش میشوند:
UdpStatelessSocket -> WireGuardDevice -> TunDevice
UdpStatelessSocket فقط در ابتدای chain قرار میگیرد؛ بنابراین در این چیدمان
باید پیش از WireGuardDevice باشد.
بعضی nodeها این دو مدل را به هم تبدیل میکنند. برای مثال، PacketsToStream
packetها را داخل یک stream قرار میدهد و StreamToPackets در سمت مقابل،
packetها را از همان stream جدا میکند.
ConnectionToPackets و PacketsToConnection نوع دیگری از bridge هستند. وقتی
یک node مثل Socks5Server مقصد TCP یا UDP را مشخص کند،
ConnectionToPackets یک flow از نوع IPv4 درون process باز میکند و raw packetهای IPv4
آن را میفرستد. PacketsToConnection تبدیل معکوس را انجام میدهد و از packetهای
دریافتی، lineهای اتصال عادی WaterWall میسازد. این کار زمانی مفید است که یک مسیر
proxy مبتنی بر اتصال، بدون استفاده از دستگاه TUN سیستمعامل، باید از یک توپولوژی
packet عبور کند. ConnectionToPackets فقط IPv4 را پشتیبانی میکند و به یک آدرس
مبدأ مجازی نیاز دارد که مسیر packet بتواند پاسخ را به آن بازگرداند.
با chainهای packet دقیقاً مانند chainهای TCP رفتار نکنید. یک chain packet ممکن است از packet lineهای مختص هر worker استفاده کند که در طول پردازش تعداد زیادی packet نامرتبط زنده میمانند.
خواندن فلشهای chain
chain زیر را در نظر بگیرید:
TcpListener -> MuxClient -> VlessClient -> TlsClient -> TcpConnector
مراحل آن چنین است:
TcpListenerاتصال یک client مبتنی بر TCP را میپذیرد.MuxClientچند اتصال منطقی را روی مسیر انتقال multiplex میکند.VlessClientpayload را در framing سمت client پروتکل VLESS قرار میدهد.TlsClientنتیجه را داخل یک اتصال TLS حمل میکند.TcpConnectorبه server راه دورِ مشخصشده متصل میشود.
ترافیک برگشتی از همین nodeها و در جهت مخالف عبور میکند.
هنگام طراحی chain، اول مسیر را با فلش مشخص کنید. بعد برای هر node در این مسیر، تنظیمات JSON را در فایل config بنویسید.