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

PacketSender

PacketSender یک تولیدکننده packet لایه ۳ برای IPv4 است. این node هنگام startup، packet‌های خام IPv4 را از پیش می‌سازد و در مدت تعیین‌شده آن‌ها را روی worker packet line‌های WaterWall می‌فرستد.

کاربرد اصلی آن آزمایش کنترل‌شده مسیر packet است. در کنار PacketReceiver می‌توان از آن برای پیدا کردن source IP‌های قابل دسترس یا مجاز در محیط‌های محدودشده بر اساس IP استفاده کرد: از بازه‌های پیشنهادی packet بسازید، آن‌ها را از مسیر مورد نظر بفرستید و سپس گزارش گیرنده را بررسی کنید تا مشخص شود packet‌های کدام source IP رسیده‌اند.

هشدار

این node را فقط روی شبکه‌ها و بازه‌های آدرسی به کار ببرید که مجوز آزمایش آن‌ها را دارید. نتیجه آزمایش source IP به شبکه سمت sender نیز وابسته است. اگر provider، مسیر kernel، backend مربوط به raw socket یا شبکه upstream آدرس‌های source غیرمحلی را مسدود کند، ممکن است packet‌های تولیدشده اصلاً از sender خارج نشوند.

جایگاه رایج​

خروجی raw IPv4:

PacketSender -> RawSocket

همراه packet manipulation:

PacketSender -> IpManipulator -> RawSocket

packet transport شبیه WireGuard:

شاخه‌ی منبع Packet: PacketSender -> Bridge A
شاخه‌ی UDP/WireGuard: UdpStatelessSocket -> WireGuardDevice -> Bridge B

Bridge A و Bridge B را با هم جفت کنید. هر دو PacketSender و UdpStatelessSocket فقط در ابتدای chain قرار می‌گیرند؛ بنابراین باید در شاخه‌های جداگانه باشند.

سمت receiver متناظر:

RawSocket -> PacketReceiver

PacketSender یک adapter از نوع chain-head و singleton است. باید در ابتدای یک chain لایه ۳ قرار بگیرد و وجود next برای آن الزامی است.

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

  • یک بازه CIDR برای source IPv4 یا آرایه‌ای از این بازه‌ها را می‌پذیرد.
  • یک آدرس IPv4 برای destination می‌پذیرد.
  • برای TCP، UDP، ICMP یا ALL packet خام IPv4 می‌سازد.
  • ارسال از هر source IP را به تعداد packets-per-ip تکرار می‌کند.
  • پیش از آغاز ارسال، کل packet store را در حافظه می‌سازد.
  • index‌های packet را میان worker‌ها تقسیم می‌کند.
  • با تعیین deadline برای هر packet، ارسال‌ها را در طول duration-ms پخش می‌کند.
  • پیش از هر ارسال، routing context روی packet line را به‌روزرسانی می‌کند.
  • پس از پایان ارسال، worker packet line‌ها را نمی‌بندد و برایشان Finish نمی‌فرستد.
  • اگر سمت downstream روی worker packet line مربوطه Finish بفرستد، timer و حلقه ارسال آن worker را متوقف می‌کند.

بازه‌های source به همان ترتیبی که در config آمده‌اند پردازش می‌شوند و ارسال آن‌ها با هم interleave نمی‌شود.

تست source-IP Allowlist​

PacketSender و PacketReceiver برای سناریوهایی مناسب‌اند که دسترسی به مسیر یا سرویس بر اساس source IP محدود شده است. روال معمول چنین است:

  1. PacketSender را با بازه‌های IP مبدأ مورد نظر در source-ipv4-range تنظیم کنید.
  2. PacketReceiver را با همان range‌ها تنظیم کنید.
  3. packet‌ها را به سمت host یا packet chain گیرنده بفرستید.
  4. گزارش گیرنده را بخوانید.
  5. source IP‌هایی را که تحویل کامل یا نزدیک به کامل دارند به‌عنوان گزینه‌های بهتر در نظر بگیرید.

در گیرنده، PacketReceiver.protocol-number را برابر protocol‌های مورد انتظار و PacketReceiver.expected-packets-per-ip را در همه حالت‌ها، از جمله ALL، برابر PacketSender.packets-per-ip بگذارید. گیرنده مجموع هر IP را خودش محاسبه می‌کند و protocol‌ها را جداگانه گزارش می‌دهد. برای چند protocol می‌توان از آرایه‌هایی مانند [6, 17] یا ["TCP", "UDP"] استفاده کرد.

نمونه تنظیم​

ICMP probing:

{
"name": "packet-sender",
"type": "PacketSender",
"settings": {
"source-ipv4-range": [
"198.51.100.0/24",
"203.0.113.0/24"
],
"dest-ipv4": "203.0.113.20",
"protocol-number": "ICMP",
"duration-ms": 5000,
"packets-per-ip": 100
},
"next": "raw-ip"
}

TCP-shaped probing:

{
"name": "packet-sender",
"type": "PacketSender",
"settings": {
"source-ipv4-range": "198.51.100.0/24",
"dest-ipv4": "203.0.113.20",
"protocol-number": "TCP",
"duration-ms": 5000,
"packets-per-ip": 10,
"dest-port": 443,
"src-port": "random"
},
"next": "raw-ip"
}

فیلدهای ضروری​

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

فیلدنوعتوضیح
namestringنام دلخواه node. باید داخل فایل config یکتا باشد.
typestringباید دقیقاً "PacketSender" باشد.
settingsobjectلازم است و نباید خالی باشد.
nextstringلازم است. node لایه ۳ بعدی packet‌های تولیدشده را دریافت می‌کند.

فیلدهای ضروری داخل settings:

فیلدنوعتوضیح
source-ipv4-rangestring یا آرایه stringیک CIDR range از نوع IPv4، یا آرایه‌ای از CIDR range‌های IPv4.
dest-ipv4stringآدرس IPv4 مقصد. باید IPv4 تکی باشد، نه CIDR.
protocol-numberstringیکی از TCP، UDP، ICMP یا ALL. به حروف کوچک و بزرگ حساس نیست.
duration-msintegerمدت ارسال مثبت، بر حسب میلی‌ثانیه.
dest-portintegerبرای TCP، UDP و ALL لازم است. باید غیرصفر و در بازه 0..65535 باشد.
src-portinteger یا "random"برای TCP، UDP و ALL لازم است. باید غیرصفر یا "random" باشد.

dest-port و src-port برای ICMP لازم نیستند.

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

گزینهنوعپیش‌فرضتوضیح
packets-per-ipinteger1تعداد تکرار ارسال از هر source IP؛ باید مثبت باشد. در حالت ALL، هر بار برای ۲۵۵ protocol مختلف packet فرستاده می‌شود.

وقتی src-port برابر "random" باشد، پیاده‌سازی فعلی بر اساس source IP، destination IP و protocol یک port ثابت از بازه ephemeral یعنی 49152..65535 انتخاب می‌کند. این انتخاب برای شکل packet تولیدشده deterministic است و برای هر packet دوباره تصادفی نمی‌شود.

شکل packet‌های تولیدشده​

همه packet‌های تولیدشده IPv4 هستند و این ویژگی‌ها را دارند:

فیلدمقدار
TTL64
fragment flagDon't fragment (DF)
source IPیک آدرس از source-ipv4-range
destination IPdest-ipv4
checksumsپیش از ساخته شدن packet store محاسبه می‌شوند

شکل‌های protocol-specific:

protocol-numberpacket تولیدشده
TCPTCP segment حداقلی با flag ACK، sequence/ack number‌های deterministic، port‌های تنظیم‌شده و checksum معتبر.
UDPUDP datagram حداقلی با port‌های تنظیم‌شده و checksum معتبر.
ICMPICMP echo request با identifier/sequence deterministic و checksum معتبر.
ALLبرای هر source IP و هر تکرار، یک packet برای protocol number‌های 0 تا 254 می‌سازد. protocol‌های 6، 17 و 1 به‌ترتیب شکل معتبر TCP، UDP و ICMP دارند؛ سایر موارد packet‌های IPv4 با payload هشت‌بایتی opaque هستند.

حالت ALL در هر تکرار برای 255 protocol مختلف packet تولید می‌کند، نه 256.

زمان‌بندی و worker‌ها​

پیش از شروع runtime، PacketSender همه packet‌ها را در یک packet store پیوسته می‌سازد. هنگام startup:

  • index‌های کل packet‌ها میان worker‌ها تقسیم می‌شوند
  • هر worker از worker packet line پایدار خودش استفاده می‌کند
  • هر packet بر اساس index و duration-ms یک deadline سراسری می‌گیرد
  • worker‌ها packet‌های آماده را می‌فرستند و اگر زمان packet بعدی هنوز نرسیده باشد، one-shot timer را دوباره فعال می‌کنند

به این ترتیب packet‌ها در تمام مدت تعیین‌شده پخش می‌شوند و کل store یک‌باره به‌صورت burst ارسال نمی‌شود. اگر موعد چند packet هم‌زمان برسد، ممکن است یک worker آن‌ها را پشت سر هم بفرستد.

محدودیت‌ها​

  • تعداد کل source IP‌ها باید داخل uint32_t جا شود.
  • تعداد کل packet‌ها باید داخل uint64_t جا شود.
  • مجموع اندازهٔ packet‌های ساخته‌شده در حافظه باید در size_t جا شود.
  • اندازهٔ packet store در حافظه به 8 GiB محدود است.
  • required_padding_left = 0.

بازه‌های بزرگ، حالت ALL و مقدارهای زیاد packets-per-ip مصرف حافظه را سریع بالا می‌برند. در صورت نیاز تست را با بازه‌های کوچک‌تر یا در چند اجرای جدا انجام دهید.

معناشناسی packet-line​

PacketSender از worker packet line‌هایی استفاده می‌کند که chain ساخته است. این‌ها line‌های کمکی و پایدار هر worker هستند، نه line‌های جداگانه برای هر connection.

PacketSender packet line‌ها را از بین نمی‌برد و Finish را نشانه تکمیل موفق نمی‌داند. یک Finish از سمت downstream، timer و حلقه ارسال worker مربوطه را برای همیشه متوقف می‌کند؛ در حالت تکمیل عادی، فقط زمانی در log ثبت می‌شود که همه packet‌های تخصیص‌یافته ارسال شده باشند.

نکته‌های عملی​

  • در سمت مقصد از PacketReceiver استفاده کنید تا تعداد packet‌های دریافتی از هر source IP را ببینید.
  • مقدار report-after-ms در PacketReceiver را بیشتر از duration-ms فرستنده بگذارید و برای تأخیر شبکه و جابه‌جایی احتمالی ترتیب packet‌ها هم زمان در نظر بگیرید.
  • اگر شبکه اجازه می‌دهد، برای probe سادهٔ مسیر از ICMP استفاده کنید.
  • وقتی محیط محدودشده رفتار متفاوتی بر اساس protocol یا port دارد، از TCP، UDP یا ALL استفاده کنید.
  • اگر شبکه سمت sender اعتبارسنجی source address انجام دهد، ممکن است بازه‌های source جعلی یا غیرمحلی پیش از رسیدن به peer WaterWall فیلتر شوند.

متادیتای node​

متادیتای برگرفته از کد منبع:

ویژگیمقدار
node flagskNodeFlagChainHead | kNodeFlagSingleton
can_have_prevfalse
can_have_nexttrue
layer_groupkNodeLayer3
layer_group_prev_nodekNodeLayerNone
layer_group_next_nodekNodeLayer3
required_padding_left0 بایت