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 line | tunnel chain | line کمکی و پایدار worker که در runtime عادی بسته نمیشود. |
| TCP line ساختهشده | PacketsToConnection | connection line معمول واتروال که با بسته شدن flow مربوط به TCP از بین میرود. |
| UDP line ساختهشده | PacketsToConnection | connection 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 میپذیرد:
PacketsToConnectionیک WaterWall line عادی روی owning packet worker میسازد.- per-line state خودش را بهعنوان یک TCP line مقداردهی اولیه میکند.
- source address context را از remote TCP peer پر میکند.
- destination address context را از original local destination IP و port، یا از fake DNS mapping در صورت وجود پر میکند.
routing_context.local_listener_portرا به original local port تنظیم میکند.- Nagle را روی lwIP TCP PCB غیرفعال میکند.
- 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_sentacknowledgement queue را پیش میبرند - بایتهای صفشده با فراهم شدن فضای ارسال فرستاده میشوند
- با خالی شدن write queue، tunnel بعدی با
tunnelNextUpStreamResume()از حالت توقف خارج میشود
backpressure سمت دریافت نیز مدیریت میشود:
- downstream
Pauseline ساختهشده را read-paused علامت میزند - در حالت read-paused، TCP receive credit به تعویق میافتد
- downstream
Resumecredit انباشتهشده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 port | source port اصلی UDP. |
| destination port | destination port اصلی UDP. |
با اولین datagram برای یک 4-tuple جدید:
PacketsToConnectionیک WaterWall line عادی روی owning packet worker میسازد.- UDP flow key و اطلاعات UDP PCB متصل را ذخیره میکند.
- source و destination address contextها را پر میکند.
- fake DNS mapping را به destination context اعمال میکند اگر destination یک fake IP mapped باشد.
- line را به UDP flow map route context اضافه میکند.
- upstream
Initرا زمانبندی میکند و datagramها را به شکل upstream payload تحویل میدهد.
فعالیت روی UDP line آن را زنده نگه میدارد. datagramهای ورودی و payloadهای downstream مربوط به UDP، idle timer را بهروزرسانی میکنند. پس از رسیدن deadline تنظیمشده، line بسته و از UDP flow map حذف میشود.
محدودیت UDP Backpressure
UDP سازوکار واقعی backpressure مانند stream ندارد.
رفتار فعلی:
- downstream
PauseUDP line ساختهشده را read-paused علامت میزند - datagramهای UDP ورودی در حالت read-paused کنار گذاشته میشوند
- downstream
Resumepaused 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 اینگونه کار میکند:
- یک packet client یک UDP DNS query به fake DNS address و port configure شده میفرستد.
PacketsToConnectionآن packet را قبل از inject به lwIP intercept میکند.- برای هر سؤال
A/IN، یک fake IPv4 address از fake network configure شده اختصاص میدهد یا reuse میکند. - یک DNS response به packet side بهعنوان یک UDP packet IPv4 خام میفرستد.
- بعداً 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های واقعی باشد.
تنظیمات
فیلدهای سطح بالا:
| فیلد | نوع | اجباری | توضیح |
|---|---|---|---|
name | string | بله | نام دلخواه نود. باید داخل فایل config یکتا باشد. |
type | string | بله | باید دقیقاً "PacketsToConnection" باشد. |
settings | object | خیر | object تنظیمات اختیاری. اگر وجود داشته باشد باید object باشد. |
next | string | بله، برای runtime کاربردی | ورودی service chain معمول واتروال که lineهای ساختهشده را دریافت میکند. |
فیلدهای settings:
| گزینه | نوع | پیشفرض | توضیح |
|---|---|---|---|
udp-idle-timeout-ms | integer | 300000 | طول عمر idle برای UDP lineهای ساختهشده. حداقل 1. |
fake-dns | boolean یا object | false | فعالسازی و تنظیم fake DNS responder داخل tunnel. |
fake_dns | boolean یا object | تنظیم نشده | alias برای fake-dns. |
mapdns | boolean یا object | تنظیم نشده | alias قدیمی برای fake-dns. |
فیلدهای object fake DNS:
| فیلد | نوع | پیشفرض | توضیح |
|---|---|---|---|
enabled | boolean | true | اجازه میدهد فرم object حضور داشته باشد در حالی که fake DNS غیرفعال است. |
address | IPv4 string | 198.18.0.2 | آدرس IPv4 که fake DNS responder روی آن listen میکند. |
port | integer | 53 | UDP destination port برای DNS queryهای fake. باید 1..65535 باشد. |
network | IPv4 string | 100.64.0.0 | شبکه پایه fake-IP. قبل از استفاده توسط netmask mask میشود. |
netmask | IPv4 string | 255.192.0.0 | fake-IP network mask. |
cache-size | integer | 10000 | تعداد record domain-to-fake-IP. حداقل 1 و باید داخل fake network جا بگیرد. |
ttl | integer | 1 | DNS answer TTL بر حسب ثانیه. باید 0 یا بیشتر باشد. |
اگر بیش از یکی از کلیدهای fake DNS وجود داشته باشد، source آنها بهترتیب fake-dns، سپس fake_dns و در پایان mapdns بررسی میشود.
معناشناسی Callback و Lifecycle
callbackهای packet-side:
| callback دریافتشده روی packet line | رفتار |
|---|---|
upstream Init | No-op. packet-line init یک رویداد startup/bootstrap است. |
upstream Payload | IPv4 را اعتبارسنجی میکند، در صورت فعال بودن fake DNS را مدیریت میکند و سپس packetهای TCP/UDP را به lwIP تحویل میدهد. |
upstream Est | fatal guard؛ روی packet line انتظار نمیرود. |
upstream Pause | fatal guard؛ روی packet line انتظار نمیرود. |
upstream Resume | fatal guard؛ روی packet line انتظار نمیرود. |
upstream Finish | fatal guard؛ packet lineها نباید در طول runtime عادی بسته شوند. |
callbackهای connection line ساختهشده از tunnel بعدی:
| callback از سمت بعدی | رفتار |
|---|---|
downstream Payload | bytes/datagramها را به lwIP مینویسد. |
downstream Pause | خواندن از TCP/UDP line ساختهشده را متوقف میکند. |
downstream Resume | خواندن را از سر میگیرد و در TCP، receive credit معوق را آزاد میکند. |
downstream Finish | سمت lwIP را میبندد و per-line state و line ساختهشده توسط این tunnel را از بین میبرد. |
downstream Init | fatal guard؛ callback معتبری برای lineهای ساختهشده نیست. |
downstream Est | No-op. |
رفتار close سمت network:
- TCP close/error و UDP idle close اول lwIP state را جدا میکنند
- این tunnel per-line state خودش را از بین میبرد
- اگر upstream
Initقبلاً ارسال شده باشد، upstreamFinishبه 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 strategy | prefer-ipv4 وقتی fake DNS mapping اعمال میشود. |
routing_context.local_listener_port | local destination port اصلی. |
به همین دلیل PacketsToConnection با نودهای معمولی که destination را میشناسند سازگار است. برای نمونه، connector بعدی میتواند به مقصد اصلی packet وصل شود و router نیز بر اساس protocol، port، IP یا domain بازیابیشده توسط fake DNS تصمیم بگیرد.
نکات Buffer و Padding
metadata نود backed از source:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagNone |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayerAnything |
layer_group_prev_node | kNodeLayerAnything |
layer_group_next_node | kNodeLayerAnything |
required_padding_left | 0 |
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 استفاده کنید.