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

PacketsToConnection

PacketsToConnection یک bridge میان packet و transport است که بر پایه lwIP کار می‌کند. این نود packetهای خام IPv4 را از سمت packet می‌گیرد، آن‌ها را به یک stack درون‌پردازه‌ای lwIP تزریق می‌کند و flowهای TCP/UDP حاصل را به شکل connectionهای معمول line_t در واتروال در اختیار tunnel بعدی قرار می‌دهد.

هرگاه یک chain مبتنی بر packet باید به بخش معمول connection-oriented واتروال وارد شود، از این نود استفاده کنید.

packet side -> PacketsToConnection -> normal WaterWall service chain
normal service response -> PacketsToConnection -> raw IPv4 packet side

چیستی این نود

PacketsToConnection بیشتر یک bridge کوچک برای transport stack است تا tunnelی برای framing کردن packetها.

مسئولیت‌های این نود:

  • دریافت packetهای کامل IPv4 از نود قبلی در سمت packet
  • تحویل packetهای پشتیبانی‌شده به lwIP
  • تبدیل connectionهای پذیرفته‌شده TCP به lineهای معمول واتروال
  • تبدیل 4-tupleهای UDP به lineهای معمول واتروال
  • نوشتن پاسخ‌های downstream مربوط به service chain از طریق lwIP
  • فرستادن packetهای خام IPv4 به سمت packet

چیزهایی که این نود مسئول نیست:

  • ساختن TUN device
  • تنظیم routeهای سیستم‌عامل، firewall mark یا policy routing
  • serialize کردن packetها روی یک byte stream
  • جایگزینی TunDevice
  • پردازش IPv6 یا ICMP

TunDevice سمت adapter واقعی packet را مدیریت می‌کند و PacketsToConnection مسئول سمت transport bridge در lwIP است.

جایگاه رایج

جریان مستقیم packet-to-service:

TunDevice -> PacketsToConnection -> TcpConnector

packet input با policy یا proxy chain بعد از بازسازی flow:

TunDevice -> PacketsToConnection -> Router -> TcpConnector

packet input منتقل شده توسط tunnel دیگر:

WireGuardDevice -> PacketsToConnection -> HttpClient -> TlsClient -> TcpConnector

سمت قبلی باید مبتنی بر packet باشد. سمت بعدی یک connection chain معمول واتروال است و lineهای ساخته‌شده برای هر flow را دریافت می‌کند.

نمونه‌های تنظیم

bridge حداقلی:

{
"name": "ptc",
"type": "PacketsToConnection",
"next": "service-chain-entry"
}

با تنظیم UDP idle و fake DNS:

{
"name": "ptc",
"type": "PacketsToConnection",
"settings": {
"udp-idle-timeout-ms": 120000,
"fake-dns": {
"address": "198.18.0.2",
"port": 53,
"network": "100.64.0.0",
"netmask": "255.192.0.0",
"cache-size": 10000,
"ttl": 1
}
},
"next": "service-chain-entry"
}

ترافیک پشتیبانی‌شده

ترافیکوضعیتنکات
IPv4پشتیبانی می‌شودورودی باید یک packet کامل IPv4 باشد.
TCP over IPv4پشتیبانی می‌شودlwIP آن را می‌پذیرد و به شکل lineهای معمول واتروال ارائه می‌کند.
UDP over IPv4پشتیبانی می‌شودبه شکل یک line واتروال برای هر 4-tuple همراه با idle timeout ارائه می‌شود.
IPv6پشتیبانی نمی‌شودtunnel فقط IPv4 را پردازش می‌کند و packetهای IPv6 کنار گذاشته می‌شوند.
ICMPپشتیبانی نمی‌شودpacketهای IPv4 غیر از TCP/UDP کنار گذاشته می‌شوند.

بررسی‌های packet input عمداً محافظه‌کارانه هستند:

  • طول packet باید حداقل یک IPv4 header باشد
  • IP version باید 4 باشد
  • IPv4 header length باید داخل buffer جا بگیرد
  • IP total length باید معتبر باشد
  • طول sbuf باید با IPv4 total length برابر باشد
  • protocol باید TCP یا UDP باشد، مگر اینکه packet توسط fake DNS مدیریت شود

packetهایی که این شرایط را نداشته باشند به pool برگردانده می‌شوند و به نود بعدی نمی‌روند.

مدل جریان

worker packet line مشترک با lineهای TCP/UDP ساخته‌شده توسط این نود فرق دارد:

نوع lineمالکطول عمر
worker packet linetunnel chainline کمکی و پایدار worker که در runtime عادی بسته نمی‌شود.
TCP line ساخته‌شدهPacketsToConnectionconnection line معمول واتروال که با بسته شدن flow مربوط به TCP از بین می‌رود.
UDP line ساخته‌شدهPacketsToConnectionconnection line معمول واتروال که با idle timeout یا بسته شدن downstream از بین می‌رود.

Route Context های lwIP

برای IPv4، پیاده‌سازی فعلی route contextها را هنگام نیاز و به‌ازای هر packet worker می‌سازد، نه به‌ازای هر destination IP.

هر route context محلی worker شامل این موارد است:

  • یک lwIP netif
  • NETIF_FLAG_PRETEND
  • یک TCP listener wildcard pretend، اولین بار با اولین TCP packet ساخته می‌شود
  • یک UDP PCB wildcard pretend، اولین بار با اولین UDP packet ساخته می‌شود
  • یک UDP flow map با کلید packet 4-tuple

destination IP هم در packet IPv4 و هم در tuple مربوط به PCB در lwIP حفظ می‌شود، اما کلید ساخت route context جداگانه نیست. patch مربوط به حالت pretend در lwIP واتروال به PCBهای wildcard اجازه می‌دهد روی netif مجازی، ترافیک مربوط به هر destination address و port را بپذیرند و در عین حال local tuple اصلی flowهای پذیرفته‌شده را نگه دارند.

وقتی lwIP خروجی packet تولید می‌کند، PacketsToConnection آن را با tunnelPrevDownStreamPayload() به worker packet line می‌فرستد. اگر خروجی lwIP روی worker دیگری ایجاد شده باشد، بایت‌های packet در یک worker message کپی می‌شوند تا از packet worker درست ارسال شوند.

رفتار TCP

وقتی lwIP یک TCP flow می‌پذیرد:

  1. PacketsToConnection یک WaterWall line عادی روی owning packet worker می‌سازد.
  2. per-line state خودش را به‌عنوان یک TCP line مقداردهی اولیه می‌کند.
  3. source address context را از remote TCP peer پر می‌کند.
  4. destination address context را از original local destination IP و port، یا از fake DNS mapping در صورت وجود پر می‌کند.
  5. routing_context.local_listener_port را به original local port تنظیم می‌کند.
  6. Nagle را روی lwIP TCP PCB غیرفعال می‌کند.
  7. upstream Init را برای tunnel بعدی زمان‌بندی می‌کند.

payload ورودی TCP از lwIP در یک buffer واتروال کپی می‌شود و پس از ارسال upstream Init، با tunnelNextUpStreamPayload() در جهت upstream تحویل داده می‌شود.

payload در جهت downstream از tunnel بعدی با tcp_write() به lwIP نوشته می‌شود. پیاده‌سازی فعلی از TCP_WRITE_FLAG_COPY استفاده می‌کند؛ در نتیجه lwIP نسخه خودش را از بایت‌ها می‌گیرد و واتروال buffer اصلی را تا تکمیل حساب‌داری ارسال TCP نگه می‌دارد.

TCP Backpressure

نوشتن TCP در مسیر downstream با سازوکار pause/resume واتروال هماهنگ است:

  • اگر tcp_sndbuf() فضا نداشته باشد یا فقط بخشی از buffer قابل نوشتن باشد، داده باقی‌مانده در صف می‌ماند
  • tunnel بعدی با tunnelNextUpStreamPause() متوقف می‌شود
  • callbackهای lwIP tcp_sent acknowledgement queue را پیش می‌برند
  • بایت‌های صف‌شده با فراهم شدن فضای ارسال فرستاده می‌شوند
  • با خالی شدن write queue، tunnel بعدی با tunnelNextUpStreamResume() از حالت توقف خارج می‌شود

backpressure سمت دریافت نیز مدیریت می‌شود:

  • downstream Pause line ساخته‌شده را read-paused علامت می‌زند
  • در حالت read-paused، TCP receive credit به تعویق می‌افتد
  • downstream Resume credit انباشته‌شده tcp_recved() را به lwIP برمی‌گرداند

به این ترتیب flow control مربوط به TCP بدون بستن packet line حفظ می‌شود.

رفتار UDP

UDP نیز به شکل lineهای معمول واتروال ارائه می‌شود، اما مدل آن datagram-based است و state کمتری از TCP دارد.

کلید UDP flow:

فیلدمعنی
source IPv4 addressآدرس source اصلی packet.
destination IPv4 addressآدرس destination اصلی packet.
source portsource port اصلی UDP.
destination portdestination port اصلی UDP.

با اولین datagram برای یک 4-tuple جدید:

  1. PacketsToConnection یک WaterWall line عادی روی owning packet worker می‌سازد.
  2. UDP flow key و اطلاعات UDP PCB متصل را ذخیره می‌کند.
  3. source و destination address contextها را پر می‌کند.
  4. fake DNS mapping را به destination context اعمال می‌کند اگر destination یک fake IP mapped باشد.
  5. line را به UDP flow map route context اضافه می‌کند.
  6. upstream Init را زمان‌بندی می‌کند و datagramها را به شکل upstream payload تحویل می‌دهد.

فعالیت روی UDP line آن را زنده نگه می‌دارد. datagramهای ورودی و payloadهای downstream مربوط به UDP، idle timer را به‌روزرسانی می‌کنند. پس از رسیدن deadline تنظیم‌شده، line بسته و از UDP flow map حذف می‌شود.

محدودیت UDP Backpressure

UDP سازوکار واقعی backpressure مانند stream ندارد.

رفتار فعلی:

  • downstream Pause UDP line ساخته‌شده را read-paused علامت می‌زند
  • datagramهای UDP ورودی در حالت read-paused کنار گذاشته می‌شوند
  • downstream Resume paused state را پاک می‌کند
  • downstream payload از طریق UDP PCB متصل ارسال می‌شود و WaterWall buffer فوراً reuse می‌شود

این محدودیت در مسیر UDP عمدی است. اگر backpressure بدون از دست رفتن داده اهمیت دارد، از stream transport یا لایه‌ای استفاده کنید که retransmission و flow control خودش را فراهم می‌کند.

Fake DNS

fake-dns یک DNS responder اختیاری برای IPv4 درون tunnel است. زمانی مفید است که clientهای سمت packet باید به domain متصل شوند، اما مسیر packet در ابتدا فقط IP packet در اختیار دارد.

مسیر fake DNS این‌گونه کار می‌کند:

  1. یک packet client یک UDP DNS query به fake DNS address و port configure شده می‌فرستد.
  2. PacketsToConnection آن packet را قبل از inject به lwIP intercept می‌کند.
  3. برای هر سؤال A/IN، یک fake IPv4 address از fake network configure شده اختصاص می‌دهد یا reuse می‌کند.
  4. یک DNS response به packet side به‌عنوان یک UDP packet IPv4 خام می‌فرستد.
  5. بعداً packetهای TCP یا UDP که destination IP آن‌ها با یک ورودی fake DNS مطابقت داشته باشد، به‌جای IP destination context یک domain destination context می‌گیرند.

این کار باعث می‌شود نودهای downstream مانند TcpConnector، proxy clientها و routerها نام domain اصلی را ببینند، نه فقط IP ساختگی را.

نکات مهم:

  • fake DNS به‌صورت پیش‌فرض غیرفعال است
  • مقدار boolean true آن را با defaultها فعال می‌کند
  • فرم object اجازه تنظیم listen address، fake network، cache size و TTL را می‌دهد
  • فقط UDP DNS packetهای IPv4 مدیریت می‌شوند
  • فقط سؤال‌های A/IN پاسخ A synthetic می‌گیرند
  • از هر DNS query حداکثر ۳۲ سؤال خوانده می‌شود
  • نام‌های سؤال قبل از ذخیره به lowercase تبدیل می‌شوند
  • map مربوط به fake IP از نوع LRU و محلی همان process است
  • DNS TTL اثر روی DNS response TTL دارد، نه انقضای سخت map in-process
  • اگر یک fake IP entry evict شود، flowهای آینده به آن old fake IP ممکن است دیگر به domain اصلی resolve نشوند

بازه شبکه‌ای که برای fake DNS تنظیم می‌کنید نباید در همان محیط packet شامل destinationهای واقعی باشد.

تنظیمات

فیلدهای سطح بالا:

فیلدنوعاجباریتوضیح
namestringبلهنام دلخواه نود. باید داخل فایل config یکتا باشد.
typestringبلهباید دقیقاً "PacketsToConnection" باشد.
settingsobjectخیرobject تنظیمات اختیاری. اگر وجود داشته باشد باید object باشد.
nextstringبله، برای runtime کاربردیورودی service chain معمول واتروال که lineهای ساخته‌شده را دریافت می‌کند.

فیلدهای settings:

گزینهنوعپیش‌فرضتوضیح
udp-idle-timeout-msinteger300000طول عمر idle برای UDP lineهای ساخته‌شده. حداقل 1.
fake-dnsboolean یا objectfalseفعال‌سازی و تنظیم fake DNS responder داخل tunnel.
fake_dnsboolean یا objectتنظیم نشدهalias برای fake-dns.
mapdnsboolean یا objectتنظیم نشدهalias قدیمی برای fake-dns.

فیلدهای object fake DNS:

فیلدنوعپیش‌فرضتوضیح
enabledbooleantrueاجازه می‌دهد فرم object حضور داشته باشد در حالی که fake DNS غیرفعال است.
addressIPv4 string198.18.0.2آدرس IPv4 که fake DNS responder روی آن listen می‌کند.
portinteger53UDP destination port برای DNS queryهای fake. باید 1..65535 باشد.
networkIPv4 string100.64.0.0شبکه پایه fake-IP. قبل از استفاده توسط netmask mask می‌شود.
netmaskIPv4 string255.192.0.0fake-IP network mask.
cache-sizeinteger10000تعداد record domain-to-fake-IP. حداقل 1 و باید داخل fake network جا بگیرد.
ttlinteger1DNS answer TTL بر حسب ثانیه. باید 0 یا بیشتر باشد.

اگر بیش از یکی از کلیدهای fake DNS وجود داشته باشد، source آن‌ها به‌ترتیب fake-dns، سپس fake_dns و در پایان mapdns بررسی می‌شود.

معناشناسی Callback و Lifecycle

callbackهای packet-side:

callback دریافت‌شده روی packet lineرفتار
upstream InitNo-op. packet-line init یک رویداد startup/bootstrap است.
upstream PayloadIPv4 را اعتبارسنجی می‌کند، در صورت فعال بودن fake DNS را مدیریت می‌کند و سپس packetهای TCP/UDP را به lwIP تحویل می‌دهد.
upstream Estfatal guard؛ روی packet line انتظار نمی‌رود.
upstream Pausefatal guard؛ روی packet line انتظار نمی‌رود.
upstream Resumefatal guard؛ روی packet line انتظار نمی‌رود.
upstream Finishfatal guard؛ packet lineها نباید در طول runtime عادی بسته شوند.

callbackهای connection line ساخته‌شده از tunnel بعدی:

callback از سمت بعدیرفتار
downstream Payloadbytes/datagramها را به lwIP می‌نویسد.
downstream Pauseخواندن از TCP/UDP line ساخته‌شده را متوقف می‌کند.
downstream Resumeخواندن را از سر می‌گیرد و در TCP، receive credit معوق را آزاد می‌کند.
downstream Finishسمت lwIP را می‌بندد و per-line state و line ساخته‌شده توسط این tunnel را از بین می‌برد.
downstream Initfatal guard؛ callback معتبری برای lineهای ساخته‌شده نیست.
downstream EstNo-op.

رفتار close سمت network:

  • TCP close/error و UDP idle close اول lwIP state را جدا می‌کنند
  • این tunnel per-line state خودش را از بین می‌برد
  • اگر upstream Init قبلاً ارسال شده باشد، upstream Finish به tunnel بعدی ارسال می‌شود
  • سپس PacketsToConnection، lineای را که خودش ساخته بود از بین می‌برد

بسته شدن flowهای جداگانه هرگز packet line مشترک را از بین نمی‌برد؛ این line تا زمان از بین رفتن tunnel chain زنده می‌ماند.

نگاشت Address Context

برای TCP و UDP lineهای ساخته‌شده:

Contextمقدار
source address contextآدرس peer packet اصلی، peer port و protocol.
destination address contextآدرس destination packet اصلی و port، مگر اینکه fake DNS destination IP را به domain map کند.
destination domain strategyprefer-ipv4 وقتی fake DNS mapping اعمال می‌شود.
routing_context.local_listener_portlocal destination port اصلی.

به همین دلیل PacketsToConnection با نودهای معمولی که destination را می‌شناسند سازگار است. برای نمونه، connector بعدی می‌تواند به مقصد اصلی packet وصل شود و router نیز بر اساس protocol، port، IP یا domain بازیابی‌شده توسط fake DNS تصمیم بگیرد.

نکات Buffer و Padding

metadata نود backed از source:

ویژگیمقدار
node flagskNodeFlagNone
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayerAnything
layer_group_prev_nodekNodeLayerAnything
layer_group_next_nodekNodeLayerAnything
required_padding_left0

tunnel برای هر payload، framing header اضافه نمی‌کند و به left padding نیاز ندارد. در صورت امکان bufferهای ورودی packet در pbufهای lwIP قرار می‌گیرند؛ packetهای خروجی نیز از worker buffer pool مربوط به packet line یا، در صورت نیاز، از یک buffer تازه با padding کافی گرفته می‌شوند.

نکات تخصصی و محدودیت‌ها

  • PacketsToConnection یک policy engine برای NAT نیست. فقط flowها را بازسازی و به‌صورت lineهای واتروال ارائه می‌کند؛ اگر به filtering یا انتخاب مسیر نیاز دارید، نودهای routing یا policy را پس از آن قرار دهید.
  • route contextهای IPv4 فعلاً با packet worker id کلیدگذاری می‌شوند، نه destination IP.
  • PCBهای TCP و UDP listener pretend wildcard PCBهایی روی worker-local netif هستند، نه یک listener به‌ازای هر destination port.
  • UDP lineهای ساخته‌شده per 4-tuple هستند و با idle timeout بسته می‌شوند.
  • pause در UDP با از دست رفتن داده همراه است؛ datagramهای ورودی هنگام توقف کنار گذاشته می‌شوند.
  • Fake DNS یک mapper درون‌پردازه‌ای برای A-recordهای ساختگی است، نه یک DNS resolver بازگشتی.
  • map مربوط به fake DNS فقط در همین tunnel instance وجود دارد و با از بین رفتن tunnel پاک می‌شود.
  • packet-line Finish در طول runtime نقض قرارداد به حساب می‌آید.
  • IPv6 و ICMP فعلاً کنار گذاشته می‌شوند.
  • packetهایی که پس از IPv4 total length بایت اضافه دارند کنار گذاشته می‌شوند؛ زیرا پیاده‌سازی به برابری دقیق طول sbuf و IP total length نیاز دارد.

تفاوت با PacketsToStream

وقتی فقط می‌خواهید مرز packetهای خام را روی stream transport حفظ کنید، PacketsToStream را همراه StreamToPackets به کار ببرید.

اگر می‌خواهید lwIP flowهای TCP/UDP را بازسازی و آن‌ها را به شکل connection lineهای معمول واتروال ارائه کند، از PacketsToConnection استفاده کنید.