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

UdpListener

UdpListener یک Adapter سرور UDP است. این Node یک آدرس و پورت محلی UDP را Bind می‌کند، Datagramهای ورودی را بر اساس Peer راه دور گروه‌بندی می‌کند، به‌ازای هر Peer یک Line در WaterWall می‌سازد و Payloadها را در جهت upstream به Node بعدی می‌فرستد.

جایگاه معمول:

client -> UdpListener -> ... -> UdpConnector -> remote UDP service

این Node معمولاً ابتدای یک زنجیره‌ی UDP به‌شکل Stream قرار می‌گیرد.

چه کاری انجام می‌دهد؟

  • روی یک پورت UDP، چند پورت مشخص یا یک بازه‌ی پیوسته از پورت‌ها گوش می‌دهد.
  • Datagramهای UDP ورودی را از طریق Socket Manager در WaterWall دریافت می‌کند.
  • Filterهای اختیاری Listener، مانند whitelist، ‏blacklist و Balance Groupها را اعمال می‌کند.
  • به‌ازای هر ترکیب آدرس و پورت Peer راه دور، یک Line در WaterWall می‌سازد.
  • Datagramهای ورودی را به‌صورت Payload در upstream به Node بعدی می‌فرستد.
  • Payloadهای downstream را به آدرس Peer ذخیره‌شده بازمی‌گرداند.
  • Lineهای Peer را با Idle Timeout مربوط به UDP ردیابی می‌کند.

UDP ذاتاً Connectionless است، اما UdpListener برای بقیه‌ی زنجیره به‌ازای هر Peer یک Line پایدار فراهم می‌کند.

نمونه‌ی پیکربندی

{
"name": "udp-listener",
"type": "UdpListener",
"settings": {
"address": "0.0.0.0",
"port": [
5353,
853,
123
],
"large-send-buffer": true,
"large-recv-buffer": true,
"interface": "eth0",
"fwmark": 10,
"balance-group": "udp-public",
"balance-interval": 30000,
"multiport-backend": "socket",
"whitelist": [
"192.168.1.0/24",
"2001:db8::/64"
],
"blacklist": [
"192.168.1.50/32"
]
},
"next": "next-node-name"
}

فیلدهای الزامی

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

فیلدنوعتوضیح
nameStringنامی که کاربر برای Node انتخاب می‌کند و باید در فایل پیکربندی یکتا باشد.
typeStringباید دقیقاً "UdpListener" باشد.
nextStringنام Nodeای که Lineها و Payloadهای Peerهای UDP را دریافت می‌کند.

فیلدهای الزامی در settings:

فیلدنوعتوضیح
addressStringآدرس محلی برای Bind، مانند "0.0.0.0"، ‏"::" یا یک IP محلی مشخص.
port یا port-rangeNumber، ‏Array یا Range Arrayتعریف پورت Listen؛ وجود دقیقاً یکی از این دو فیلد الزامی است.

settings باید یک Object غیرخالی باشد.

تنظیم پورت

UdpListener سه حالت برای پورت دارد.

یک پورت

{
"settings": {
"address": "0.0.0.0",
"port": 5353
}
}

فهرست صریح پورت‌ها

{
"settings": {
"address": "0.0.0.0",
"port": [
5353,
853,
123
]
}
}

در این حالت فقط روی پورت‌های نوشته‌شده گوش داده می‌شود؛ این Array به‌معنای بازه‌ی 123 تا 5353 نیست.

بازه‌ی پیوسته‌ی پورت‌ها

{
"settings": {
"address": "0.0.0.0",
"port-range": [
20000,
20100
]
}
}

port-range باید Arrayای شامل دقیقاً دو پورت Integer مثبت به‌شکل [min, max] باشد. مقدار کمینه باید کوچک‌تر یا مساوی مقدار بیشینه باشد.

قواعد:

قاعدهرفتار
استفاده‌ی هم‌زمان از port و port-rangeراه‌اندازی متوقف می‌شود.
مقدار Number برای portروی یک پورت UDP گوش می‌دهد.
مقدار Array برای portروی پورت‌های صریح موجود در Array گوش می‌دهد.
مقدار Array برای port-rangeروی همه‌ی پورت‌های UDP از مقدار کمینه تا بیشینه گوش می‌دهد.
پورت نامعتبر، صفر، منفی یا بیشتر از 65535راه‌اندازی متوقف می‌شود.
هشدار

از بازه‌های قدیمی با قالب String، مانند "20000-20100"، استفاده نکنید. Parser فعلی برای port-range یک Array دومقداری انتظار دارد.

تنظیمات اختیاری

تنظیمنوعمقدار پیش‌فرضتوضیح
large-send-bufferBoolean یا Integer مثبتtrueمقدار SO_SNDBUF را روی Socketهای Listener نوع UDP تنظیم می‌کند.
large-recv-bufferBoolean یا Integer مثبتtrueمقدار SO_RCVBUF را روی Socketهای Listener نوع UDP تنظیم می‌کند.
interfaceStringتنظیم نشدهListener را به یک Interface محلی شبکه محدود می‌کند.
fwmarkIntegerتنظیم نشدهدر صورت پشتیبانی، یک Socket Mark به سبک Linux اعمال می‌کند.
balance-groupStringتنظیم نشدهListenerهای سازگار و هم‌پورت را برای توزیع پایدار Peerها در یک گروه قرار می‌دهد.
balance-intervalInteger، بر حسب میلی‌ثانیهمقدار پیش‌فرض Socket Managerمدت حفظ انتخاب قبلی برای Peerهای تکراری در Balance Group.
multiport-backendStringمقدار پیش‌فرض Runtime برای port-rangeBackend مربوط به بازه‌ی پیوسته‌ی پورت‌ها: "iptables" یا "socket".
whitelistArrayای از Stringهاتنظیم نشدهIPها یا بازه‌های CIDR مجاز برای Peer.
blacklistArrayای از Stringهاتنظیم نشدهIPها یا بازه‌های CIDR مسدود برای Peer.

گزینه‌های Socket Buffer

large-send-buffer و large-recv-buffer مقادیر زیر را می‌پذیرند:

مقدارمفهوم
trueاز اندازه‌ی پیش‌فرض WaterWall برای Socket Buffer بزرگ استفاده می‌کند که در حال حاضر 4194304 Byte است.
falseاین Socket Buffer را صریحاً تنظیم نمی‌کند و مقدار پیش‌فرض Kernel به کار می‌رود.
Integer مثبتهمان تعداد Byte را مستقیماً درخواست می‌کند.

هر دو گزینه برای Listenerهای UDP به‌صورت پیش‌فرض از Socket Buffer بزرگ WaterWall استفاده می‌کنند.

‏Interface و fwmark

interface، ‏Listener را به یک دستگاه محلی شبکه محدود می‌کند.

در Linux، ‏WaterWall از SO_BINDTODEVICE استفاده می‌کند. در Platformهایی که Bind به Device را پشتیبانی نمی‌کنند، WaterWall در صورت امکان روی آدرس IPv4 همان Interface Bind می‌شود.

fwmark در Platformهای پشتیبانی‌شده از SO_MARK استفاده می‌کند. این قابلیت به Platform وابسته است و در Windows در دسترس نیست.

Filter و توزیع

پیش از آنکه Datagram به UdpListener برسد، Socket Manager مشترک عملیات Filter و توزیع را انجام می‌دهد.

تنظیمرفتار
whitelistدر صورت تنظیم، فقط Peerهایی پذیرفته می‌شوند که IP آن‌ها با فهرست منطبق باشد.
blacklistPeerهایی را که IP آن‌ها با فهرست منطبق است رد می‌کند.
balance-groupتوزیع پایدار Peerها را میان Listenerهای سازگار روی یک پورت فعال می‌کند.
balance-intervalمشخص می‌کند Peer چه مدت به Listener انتخاب‌شده اختصاص داده شود.
multiport-backendروش پیاده‌سازی Listener دارای port-range پیوسته را تعیین می‌کند.

اگر هر دو ACL تنظیم شده باشند، Peer باید، در صورت وجود Whitelist، با آن منطبق باشد و نباید با Blacklist تطابق داشته باشد.

نمونه:

{
"settings": {
"address": "0.0.0.0",
"port": 5353,
"whitelist": [
"10.0.0.0/8",
"203.0.113.10/32",
"2001:db8::/64"
],
"blacklist": [
"10.0.0.99/32"
]
}
}

مدل یک Line به‌ازای هر Peer

UDP اتصال Transport ندارد؛ بنابراین UdpListener برای زنجیره یک مدل Pseudo-connection می‌سازد.

برای هر ترکیب یکتای آدرس و پورت Peer راه دور روی یک Socket در حال Listen:

  1. با نخستین Datagram پذیرفته‌شده، یک Line تازه در WaterWall ساخته می‌شود.
  2. آدرس Peer در Line State مربوط به Listener ذخیره می‌شود.
  3. Datagramهای بعدی همان Peer تا زمان انقضای Line از آن استفاده می‌کنند.
  4. Payloadهای downstream روی آن Line به Peer ذخیره‌شده بازگردانده می‌شوند.

به این ترتیب، Nodeهای Stream-style در ادامه‌ی زنجیره می‌توانند با Callbackهای عادی Line در WaterWall روی ترافیک UDP کار کنند.

جریان داده

از Peer به زنجیره:

UDP datagram -> UdpListener -> upstream payload -> next node

از زنجیره به Peer:

previous downstream payload -> UdpListener -> UDP send to remembered peer

Source Context مربوط به Line از آدرس Socket سمت Peer پر و به‌عنوان UDP علامت‌گذاری می‌شود.

معنای Establishment

Line جدید Peer با نخستین Datagram پذیرفته‌شده ساخته می‌شود، اما فقط زمانی Established خواهد شد که Callback مربوط به est در downstream از Node بعدی به UdpListener برسد.

رفتار Pause

وقتی Line مربوط به Peer در حالت Pause است، UdpListener، ‏Datagramهای ورودی را در صف نگه نمی‌دارد.

اگر Datagramی برای یک Line در حالت Pause برسد:

  • Datagram دور ریخته می‌شود؛
  • Line زنده می‌ماند؛
  • پس از Resume، ‏Datagramهای تازه‌ی همان Peer دوباره قابل Forward هستند.

این رفتار با Backpressure شبیه TCP متفاوت است. در این Node، ‏Pause یعنی دورریختن داده، نه نگه‌داشتن آن در Buffer.

Idle Timeout

هر Line مربوط به Peer در یک جدول Idle ردیابی می‌شود.

Timeoutهای فعلی:

وضعیتTimeout
Line تازه‌ساخته‌شده برای Peerحدود 30 seconds
Peer فعال پس از ادامه‌ی ترافیکحدود 300 seconds

اگر Line مربوط به Peer منقضی شود، UdpListener یک finish در upstream می‌فرستد و Lineای را که خودش ساخته است نابود می‌کند.

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

  • UdpListener یک Chain Head برای UDP است و به next نیاز دارد.
  • Arrayهای port فهرست صریح‌اند، نه بازه.
  • برای بازه‌های پیوسته از port-range استفاده کنید.
  • whitelist و blacklist، ‏Stringهای CIDR مربوط به IPv4 و IPv6 را می‌پذیرند.
  • fwmark و Bindشدن به Device به Platform وابسته‌اند.
  • Lineهای Peer در حالت Pause، ‏Datagramهای ورودی را به‌جای Bufferکردن دور می‌ریزند.
  • برای رفتار Stateless و در سطح Packet در UDP، شاید UdpStatelessSocket انتخاب مناسب‌تری از UdpListener باشد.