پرش به مطلب اصلی

بخش ۲: مبانی شبکه

اگر این سه موضوع را از هم جدا کنید، 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

مراحل آن چنین است:

  1. TcpListener اتصال یک client مبتنی بر TCP را می‌پذیرد.
  2. MuxClient چند اتصال منطقی را روی مسیر انتقال multiplex می‌کند.
  3. VlessClient payload را در framing سمت client پروتکل VLESS قرار می‌دهد.
  4. TlsClient نتیجه را داخل یک اتصال TLS حمل می‌کند.
  5. TcpConnector به server راه دورِ مشخص‌شده متصل می‌شود.

ترافیک برگشتی از همین node‌ها و در جهت مخالف عبور می‌کند.

هنگام طراحی chain، اول مسیر را با فلش مشخص کنید. بعد برای هر node در این مسیر، تنظیمات JSON را در فایل config بنویسید.