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

RawSocket

RawSocket WaterWall را به capture و injection مربوط به packet‌های خام IPv4 متصل می‌کند. وقتی range مربوط به capture تنظیم شده باشد، این node می‌تواند packet‌ها را از network stack میزبان بگیرد و وارد یک chain لایه ۳ کند. مستقل از capture، packet‌های خام IP برگشتی از chain را نیز روی raw output device می‌نویسد.

در مستندات قدیمی ممکن است نام RawDevice را ببینید؛ نام نوع فعلی node RawSocket است.

RawSocket یک adapter لایه ۳ است، نه یک tunnel مبتنی بر connection. packet‌های captureشده روی worker packet line‌ها فرستاده می‌شوند و هر payloadی که از یکی از دو جهت chain به RawSocket برسد، یک packet خام و کامل IP در نظر گرفته می‌شود و روی raw output device نوشته خواهد شد.

در نسخهٔ فعلی، مرز backend منشأ checksum را نیز تعیین می‌کند: Windows flag‌های checksum/direction مربوط به WinDivert و Linux metadata مربوط به NFQUEUE را بررسی می‌کند. packet malformed یا packetی که checksum لازم آن معتبر نیست پیش از publication drop می‌شود. fragment IPv4 هیچ‌گاه transport checksum ساختگی از یک fragment ناقص دریافت نمی‌کند. reassemble پیش از publication، datagram کامل می‌سازد و preserve-fragments مرز fragment و worker affinity را حفظ می‌کند. buffer تحویل‌شده مالکیت معمول دارد و claim عمر fragment همراه آن نیست؛ ورودی stack شرط کامل‌بودن datagram را هنگام دریافت enforce می‌کند.

جایگاه رایج​

در لبه یک packet chain:

RawSocket -> PacketReceiver
PacketSender -> RawSocket
TunDevice -> IpManipulator -> RawSocket

همراه node‌های packet disguise:

TunDevice -> PingClient -> RawSocket
RawSocket -> PingServer -> TunDevice

وقتی RawSocket در جایگاه اول است، packet‌های wrap‌شده و captureشده را در جهت upstream وارد PingServer می‌کند. PingServer آن‌ها را به سمت TunDevice بازیابی می‌کند و فقط با تنظیم send-replies: true ابتدا Echo Reply دقیق را از raw output برمی‌گرداند. پیش‌فرض ارسال Reply در هر دو node Ping، false است و می‌توان آن را در هر سمت مستقل فعال کرد. packet‌های ساده‌ای که TunDevice می‌گیرد در جهت downstream از PingServer عبور می‌کنند تا در Echo Request جدید wrap شوند. Reply منطبق این request در PingServer مصرف می‌شود و به TUN تحویل داده نمی‌شود؛ این مصرف به تنظیم ارسال Reply وابسته نیست.

RawSocket می‌تواند node قبلی، node بعدی یا هر دو را داشته باشد. جهت ارسال packet‌های captureشده هنگام startup تعیین می‌شود:

جایگاه در chainpacket‌های IPv4 captureشده به کدام سمت فرستاده می‌شوند
RawSocket آخرین node chain استبه node قبلی، در جهت downstream
RawSocket آخرین node chain نیستبه node بعدی، در جهت upstream

هر payloadی که از upstream یا downstream به RawSocket برسد، از همان raw output device تزریق می‌شود.

نمونه تنظیم​

{
"name": "raw-ip",
"type": "RawSocket",
"settings": {
"fragment-policy": "preserve-fragments",
"capture-device-name": "capture-in",
"raw-device-name": "raw-out",
"capture-filter-mode": "source-ip",
"capture-ips": [
"192.0.2.10",
"198.51.100.0/24"
],
"bypass-conntrack": true
},
"next": "next-node-name"
}

برای packet injection فقط در جهت write، همه کلیدهای range مربوط به capture را حذف کنید:

{
"name": "raw-output",
"type": "RawSocket",
"settings": {
"fragment-policy": "preserve-fragments",
"raw-device-name": "raw-out",
"bypass-conntrack": true
}
}

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

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

فیلدنوعتوضیح
namestringنام دلخواه node. باید داخل فایل config یکتا باشد.
typestringباید دقیقاً "RawSocket" باشد.
settingsobjectتنظیمات RawSocket. فیلدهای capture داخل آن اختیاری هستند.

فیلدهای شرطی مربوط به capture داخل settings:

گزینهنوعتوضیح
capture-ips یا capture-ipstring یا آرایه stringدو نام معادل برای یک آدرس/range یا فهرستی از آدرس‌ها و range‌های IPv4. هر دو کلید هر دو شکل ورودی را می‌پذیرند.
capture-filter-modestringفقط وقتی حداقل یک range تنظیم شده باشد لازم است. parser مقدارهای "source-ip" و "dest-ip" را می‌شناسد، اما پیاده‌سازی فعلی فقط "source-ip" را می‌پذیرد. در حالت write-only خوانده نمی‌شود.

مقدار تکی یا هر عضو آرایه در capture-ips و capture-ip می‌تواند یک IPv4 تکی باشد:

"192.0.2.10"

یا یک CIDR IPv4:

"198.51.100.0/24"

مقادیر IPv6 رد می‌شوند. اگر هیچ‌کدام از کلیدهای capture وجود نداشته باشد، یا کلید انتخاب‌شده یک آرایه خالی باشد، capture غیرفعال است و فقط raw output device راه‌اندازی می‌شود.

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

گزینهنوعپیش‌فرضتوضیح
dont-capture-protocolsarray of integers[]شناسه‌های protocol در IPv4 که capture نمی‌شوند؛ فقط اعداد صحیح ۰ تا ۲۵۵ پذیرفته می‌شوند و تکراری‌ها نادیده گرفته می‌شوند. مقدار صفر همان protocol صفر است، نه همهٔ protocol‌ها.
multi-queuebooleantrueدر Linux، برای هر event worker یک receive queue درخواست می‌کند؛ اگر queue اضافی یا steering در دسترس نباشد، یک queue روی worker صفر استفاده می‌شود. مقدار false مستقیماً همین حالت تک‌صف را انتخاب می‌کند. پردازش packet همچنان از همهٔ workerها استفاده می‌کند. در Windows پذیرفته می‌شود ولی آرایش دریافت را تغییر نمی‌دهد. حالت write-only صف دریافت ندارد.
kernel-queue-tunebooleanدر Linux برابر true و در دیگر پلتفرم‌ها falseتنظیم صف‌های کرنل capture هنگام startup. مقدار false تنظیم پایهٔ NFQUEUE و receive buffer را حفظ می‌کند و همچنان آن‌ها را گزارش می‌دهد. مستقل از skip-sysctl و misc.tcp-tune است؛ در پلتفرم‌های دیگر و حالت write-only اثری ندارد.
kernel-queue-packetsintegerخودکار در صورت حذف گزینهتعداد packet در NFQUEUE برای کل capture device؛ میان صف‌های نهایی دریافت تقسیم می‌شود.
kernel-receive-bufferintegerخودکار در صورت حذف گزینهتعداد بایت receive buffer در Netlink برای کل capture device؛ میان socketهای نهایی دریافت تقسیم می‌شود. واحد آن درخواست SO_RCVBUF پیش از حسابداری دوبرابری Linux است.
capture-device-namestringunnamed-capture-deviceنامی که به capture-device backend داده می‌شود.
raw-device-namestringunnamed-raw-deviceنامی که به raw-output backend داده می‌شود.
bypass-conntrackbooleantrueدر Linux، NOTRACK را برای هر دو مسیر capture و raw output کنترل می‌کند: rule‌های source-range در raw PREROUTING و rule دقیق با mark خودکار در raw OUTPUT. مقدار false نصب هر دو را غیرفعال می‌کند؛ NFQUEUE و رفتار drop-and-dispatch همچنان فعال می‌مانند. در حالت write-only فقط rule خروجی لازم است. روی WinDivert ویندوز اثری ندارد.
markinteger0 در حالت غیرفعال بودن bypassmark صریح برای raw output؛ فقط با bypass-conntrack=false مجاز است. وقتی bypass فعال باشد، حتی mark: 0 یا mark: null رد می‌شود.
skip-sysctlbooleanfalseدر Linux، batch مربوط به تنظیمات performance با sysctl را اجرا نمی‌کند. تنظیم NFQUEUE و rule‌های ضروری iptables همچنان اجرا می‌شوند.

هر دو گزینهٔ عددی صف کرنل فقط عدد صحیح در بازهٔ 1..2147483647 با سقف INT_MAX می‌پذیرند. صفر، عدد منفی یا کسری، string، boolean و null رد می‌شوند؛ فقط حذف گزینه اندازه‌گذاری خودکار را انتخاب می‌کند. override جای هدف خودکار را می‌گیرد، ولی مقدار پایه یا مقدار موجودِ بزرگ‌تر را کاهش نمی‌دهد و فقط با kernel-queue-tune: true اعمال می‌شود. هر سه گزینه حتی با tuning غیرفعال، capture غیرفعال یا روی پلتفرم غیر Linux اعتبارسنجی می‌شوند.

packet‌های ورودی با protocol موجود در dont-capture-protocols از هر دو rule مربوط به capture و NOTRACK ورودی همین node عبور می‌کنند و پردازش معمول conntrack و firewall میزبان را ادامه می‌دهند؛ حتی اگر bypass-conntrack فعال باشد. برای سپردن ICMP و TCP ورودی به میزبان، از [1, 6] استفاده کنید. حذف این گزینه یا آرایهٔ خالی، رفتار فعلی را حفظ می‌کند. این گزینه raw output را محدود نمی‌کند؛ packet‌هایی که WaterWall از raw socket می‌فرستد همچنان تابع bypass-conntrack هستند.

در Linux، آرایهٔ غیرخالی به matcher از نوع bpf در iptables (xt_bpf) نیاز دارد. یک فیلتر classic BPF با اندازهٔ ثابت، فقط بایت protocol در header IPv4 را در هر دو rule مربوط به NFQUEUE و NOTRACK بررسی می‌کند؛ fragment‌ها و protocol صفر نیز پشتیبانی می‌شوند و header لایهٔ transport تفسیر نمی‌شود. نبود پشتیبانی matcher باعث شکست startup و rollback می‌شود. آرایهٔ خالی matcher اضافه نمی‌کند. Windows همین استثناها را با مقایسهٔ ip.Protocol در فیلتر WinDivert اعمال می‌کند.

Alias‌های سازگاری:

Aliasمعنا
listen-ipsبه‌عنوان alias سازگاری پذیرفته می‌شود و مانند دو کلید اصلی string یا آرایه string می‌گیرد.
capture-ipنامی معادل capture-ips است؛ با وجود نام مفرد، string یا آرایه string را می‌پذیرد.

اندازهٔ صف دریافت کرنل در Linux​

اندازه‌گذاری از تعداد نهایی صف‌های فعال پس از هر fallback استفاده می‌کند. مقدار پایه برای کل دستگاه 65,536 packet در NFQUEUE و 64 MiB درخواست receive buffer در Netlink است. تنظیم خودکار از این بودجه‌ها شروع می‌کند و هدف‌های ترجیحی زیر را به‌ازای هر صف به کار می‌برد:

RAM profile تنظیم‌شدهpacket ترجیحی در هر صفدرخواست receive buffer ترجیحی برای هر socket
S1 / S21,0241 MiB
M1 / M2 (client / client-larger)2,0482 MiB
L1 / L2 (server)4,0964 MiB

برای هر منبع، هدف خودکار هر صف برابر بزرگ‌ترِ سهم پایه و هدف ترجیحی است؛ هدف ترجیحی با سهم آن صف از سقف 131,072 packet یا 128 MiB محدود می‌شود. تقسیم با تعداد واقعی صف‌ها انجام می‌شود. سقف‌ها فقط هدف خودکار را محدود می‌کنند، نه مقدار موجودِ بزرگ‌تر یا override صریح. مقدار کل صریح جای هدف خودکار همان منبع را می‌گیرد و بین صف‌ها تقسیم می‌شود، ولی حداقل سهم پایه حفظ می‌شود. با غیرفعال بودن tuning، تنظیم پایه همچنان اجرا می‌شود و overrideها اعمال نمی‌شوند.

profile سیاست حافظهٔ تنظیم‌شده است، نه RAM تشخیص‌داده‌شدهٔ میزبان. بودجهٔ هر capture device مستقل است؛ چند دستگاه بودجه‌های خود را به مصرف کل اضافه می‌کنند. این عددها RSS واقعی یا سقف بایت payload نیستند. Linux مقدار SO_RCVBUF را با حسابداری دوبرابری گزارش می‌کند و محدودیت‌های socket میزبان می‌توانند درخواست را کاهش دهند. اگر افزایش مؤثر قابل‌تأیید نباشد، tuning مقدار buffer موجود را حفظ می‌کند. صف بزرگ‌تر می‌تواند burst را جذب کند، ولی حافظه و تأخیر بیشتری مصرف می‌کند و تضمین throughput نیست.

startup تعداد صف‌های فعال، منبع هدف (auto، override یا disabled)، سقف هر NFQUEUE که کرنل با ACK تأیید کرده و SO_RCVBUF درخواستی و خوانده‌شده را گزارش می‌دهد. سقف تأییدنشده به‌صورت unknown گزارش می‌شود. گزارش‌ها با tuning غیرفعال نیز ثبت می‌شوند. رد شدن tuning یا نبود readback هشدار ایجاد می‌کند و صف‌های capture قابل‌استفاده را متوقف نمی‌کند.

این تنظیم FIFO مشترک userspace، اندازهٔ batch callbackها یا backlog خروجی raw را تغییر نمی‌دهد. sysctl سراسری جدیدی نمی‌نویسد و مستقل از skip-sysctl و misc.tcp-tune در core است.

مسیر Capture​

در startup، RawSocket همیشه یک raw output device برای packet injection می‌سازد. فقط وقتی حداقل یک capture range تنظیم شده باشد، موارد زیر نیز ساخته و فعال می‌شوند:

  • یک capture device با range‌های IPv4 تنظیم‌شده
  • NFQUEUE socket، capture reader و rule‌های capture موردنیاز

اگر capture range وجود نداشته باشد، هیچ capture device یا کد setup مرتبط با capture اجرا نمی‌شود و node فقط در مسیر write کار می‌کند.

در Linux هر receive queue یک worker مشخص دارد و خواندن آن غیرمسدودکننده است. انتخاب صف TCP/UDP همچنان با hash متقارن آدرس‌ها، protocol و portها انجام می‌شود. در حالت چندصفی، همهٔ بسته‌های کامل روی worker خواننده ادامه می‌یابند؛ node مصرف‌کننده پس از تبدیل‌های لازم، مالکیت جریان را تعیین می‌کند. بسته‌های کاملِ پروتکل‌های دیگر به‌طور پیش‌فرض با ruleهای statistic --mode random به‌صورت تصادفی میان صف‌ها پخش می‌شوند و روی worker خواننده ادامه پیدا می‌کنند. احتمال‌های شرطی در ruleهای پشت‌سرهم سهم تقریباً برابری به هر صف می‌دهند؛ تعداد دقیق بسته‌ها و ترتیب آن‌ها تضمین نمی‌شود. شمارندهٔ مشترک انتخاب nth حذف می‌شود، اما این به معنی بدون‌قفل بودن همهٔ پیاده‌سازی‌های مولد تصادفی کرنل نیست. تنظیم جدید یا شناخت nodeهای بعدی لازم نیست. در حالت تک‌صف، packet کامل TCP/UDP با portهای قابل‌خواندن با hash متقارن جریان به یک worker ثابت می‌رود تا ترتیب ورودی همان جریان در FIFO حفظ شود. packetهای opaque یا غیرقابل‌تشخیص با شمارندهٔ محلی session بین workerها به‌صورت round-robin تقسیم می‌شوند؛ بنابراین پروتکل ۵۰ میان یک جفت IP همچنان موازی پردازش می‌شود و portی برای آن حدس زده نمی‌شود. capture در Windows نیز همین سیاست را دارد. fragmentها سیاست وابستگی قبلی را حفظ می‌کنند؛ datagram کامل‌شده پس از reassembly نیز مثل بستهٔ کامل توزیع می‌شود. مصرف‌کنندهٔ stateful پس از decode یا تغییر tuple، خودش worker جریان را تعیین می‌کند. در حالت چندصفی، برای هر capture range و receive queue یک rule جریان و یک rule بستهٔ غیر TCP/UDP وجود دارد؛ در حالت تک‌صف فقط یک rule برای هر capture range نصب می‌شود. هزینهٔ بررسی ruleها با تعداد queueها رشد می‌کند. توزیع تصادفی می‌تواند ترتیب رسیدن بسته‌ها از workerهای مختلف را تغییر دهد.

وقتی backend مربوط به capture یک packet دریافت می‌کند:

  1. RawSocket بررسی می‌کند که packet از نوع IPv4 باشد.
  2. packet‌های غیر IPv4 به pool برگردانده می‌شوند و به chain راه پیدا نمی‌کنند.
  3. packet‌های مطابق با فیلتر capture از network stack میزبان drop می‌شوند (توسط drop-and-dispatch در لینوکس یا packet diversion در ویندوز)؛ هنگام فعال بودن capture، تحویل معمول آن‌ها به لایهٔ transport محلی متوقف می‌شود و WaterWall کپی دریافت‌شده را پردازش می‌کند.
  4. worker packet line متناظر از chain گرفته می‌شود.
  5. packet IPv4 captureشده به سمت node مجاور انتخاب‌شده فرستاده می‌شود.

اعمال فیلتر IP تنظیم‌شده و جلوگیری از ادامهٔ پردازش packet‌ها در kernel بر عهده backend مربوط به capture است. RawSocket برای هر packet یک line معمول per-connection نمی‌سازد.

مسیر output​

وقتی upstream یا downstream payload به RawSocket می‌رسد:

  1. buffer مربوط به payload یک packet خام IP در نظر گرفته می‌شود.
  2. payload بررسی می‌شود تا دقیقاً یک packet کامل IPv4 باشد؛ header ناقص، طول ناسازگار و بایت‌های اضافی در انتها drop می‌شوند.
  3. اگر buffer همان packet درخواست checksum داشته باشد، WaterWall پیش از نوشتن checksum‌های قابل محاسبه را اصلاح می‌کند. شکست validation/checksum buffer را recycle می‌کند و raw writer فراخوانی نمی‌شود.
  4. packet از طریق raw output device نوشته می‌شود.
  5. اگر raw device در دسترس نباشد یا نوشتن شکست بخورد، buffer به pool برگردانده می‌شود.

هر دو callback upstream و downstream payload از همین write path استفاده می‌کنند.

خروجی در FIFO مربوط به همان event worker ارسال‌کننده صف می‌شود و بعداً روی همان worker نوشته می‌شود. bufferهای تمام‌شده به pool همان worker برمی‌گردند؛ raw writer دیگر thread یا pool اختصاصی ندارد و mutex سراسری نوشتن workerها را سری نمی‌کند. محدودیت کل device همچنان ۱۳۱٬۰۷۲ packet در Linux و ۲۵۶ packet در Windows است و خروجی صف‌شده و در حال ارسال را شامل می‌شود. ترتیب هر worker حفظ می‌شود؛ بین workerهای مستقل ترتیب سراسری وجود ندارد.

در Linux، هر flush حداکثر ۵۱۲ packet اصلی را با یک sendmmsg() غیرمسدودکننده ارسال می‌کند. در ارسال ناقص فقط prefix ارسال‌شده آزاد می‌شود و suffix باقی‌مانده پیش از packetهای جدید می‌ماند. EINTR تلاش بعدی را به callback بعدی می‌سپارد. پس از EAGAIN، retry روی worker با تأخیر ۱ ms و poll() با timeout صفر، آمادگی socket را بررسی می‌کند؛ event worker منتظر نمی‌ماند. خطاهای کمبود منابع kernel و خطاهای packet یا مقصد همچنان تنها packet اول ارسال‌نشده را drop می‌کنند؛ خطای دائمی descriptor درخواست shutdown می‌دهد. برای پر شدن batch هیچ timerی صبر نمی‌کند.

در Windows، خروجی WinDivert به‌صورت overlapped انجام می‌شود. packet اصلی تا پایان عملیات معلق حفظ می‌شود؛ اعلان native completion فقط کار را روی worker مالک صف می‌کند و به pool آن دست نمی‌زند. Stop پذیرش را می‌بندد، اعلان‌ها را quiesce می‌کند و پیش از آزاد کردن packetها دسترسی native معلق را تکمیل یا لغو می‌کند.

در Linux، این قابلیت به iptables، iptables-save و ip از iproute2 و مجوز مدیریت firewall (CAP_NET_ADMIN) نیاز دارد. پیش از فعال شدن writer، WaterWall وضعیت rule‌های IPv4 را می‌خواند، mark تصادفی انتخاب می‌کند، SO_MARK را تنظیم و rule اختصاصی NOTRACK را نصب می‌کند. شکست در خواندن policy، انتخاب mark، تنظیم socket یا نصب rule باعث شکست startup و تلاش برای rollback می‌شود.

انتخاب mark بازهٔ 0x80000000..0xffffffff را ترجیح می‌دهد و در صورت نیاز به مقادیر پایین‌تر مراجعه می‌کند؛ مقادیر کمتر از 0x00010000 انتخاب نمی‌شوند. مقایسه‌ها و انتساب‌های ثابت mark در iptables-save و selector‌های fwmark در ip -4 rule show، از جمله mask‌ها و نتیجهٔ تطبیق packet بدون mark، بررسی می‌شوند. مقدار انتخاب‌شده در log ثبت می‌شود. این کار فقط احتمال تداخل را کم می‌کند و رزرو سراسری نیست: policy بومی nftables، tc/eBPF، mark دیگر socket‌ها، تغییرات هم‌زمان و برنامه‌هایی که بعداً اجرا می‌شوند ممکن است دیده نشوند.

این معافیت فقط conntrack را کنار می‌گذارد؛ routing و firewall همچنان اعمال می‌شوند و خروجی معاف نباید به NAT یا stateful filtering مبتنی بر conntrack میزبان متکی باشد. اولویت معمول raw، پردازش fragment و محدودیت MTU تغییر نمی‌کند. برای mark صریح از تنظیم زیر استفاده کنید:

"settings": {
"fragment-policy": "preserve-fragments", "bypass-conntrack": false, "mark": 10 }

این گزینه معافیت conntrack هر دو مسیر capture و output همین node را غیرفعال می‌کند؛ rule‌های سایر مدیران مستقل می‌مانند. پیش از حذف rule با comment WWRAW_NOTRACK_...، پذیرش خروجی بسته و نوشتن‌های native پذیرفته‌شده تمام می‌شوند. Stop خروجی صف‌شده را آزاد می‌کند و callback قدیمی نمی‌تواند در device دوباره راه‌اندازی‌شده بنویسد. rollback و destroy حذف rule‌های معلق یا دارای نتیجهٔ نامشخص را دوباره امتحان می‌کنند. مرگ ناگهانی process یا شکست مداوم cleanup ممکن است rule را در raw OUTPUT باقی بگذارد؛ در این حالت rule با comment ثبت‌شده در log را دستی حذف کنید.

رفتار checksum​

RawSocket درخواست checksum را که node‌های قبلی روی buffer همان packet گذاشته‌اند رعایت می‌کند.

اگر sbufGetRecalculateChecksum(buf) مقدار true بدهد:

  • تلاش می‌شود checksum کامل packet دوباره محاسبه شود
  • flag پس از محاسبه دوباره پاک می‌شود
  • جزئیات checksum لایه transport در packet‌های fragment‌شده IPv4 به‌وسیله helper مشترک checksum مدیریت می‌شود
  • درخواست روی همان buffer در این مرز مصرف می‌شود؛ packetهای دیگر worker درخواست مستقل دارند
  • اگر محاسبه شکست بخورد یا ساختار نامعتبر باشد، packet با ثبت warning دارای rate limit کنار گذاشته می‌شود

این رفتار پس از node‌هایی مانند IpManipulator یا IpOverrider مفید است؛ node‌هایی که فیلدهای IPv4، TCP، UDP یا ICMP را تغییر می‌دهند و پیش از خروجی نهایی، ترمیم checksum را درخواست می‌کنند.

درخواست پاک‌شده تضمین معتبر بودن checksum نیست. packet بدون درخواست پس از بررسی ساختار با همان checksum قبلی نوشته می‌شود، حتی اگر checksum عمداً نامعتبر باشد.

محدودیت‌های Capture filter​

settings parser این مقدارها را می‌شناسد:

source-ip
dest-ip

وقتی capture فعال است، رفتار فعلی سخت‌گیرانه‌تر است:

  • source-ip پذیرفته می‌شود (packet‌های مطابق از network stack میزبان drop می‌شوند و تنها WaterWall آن‌ها را دریافت و پردازش می‌کند)
  • dest-ip باعث شکست ساخت tunnel می‌شود و پیام خطا، استفاده از TunDevice را برای capture ترافیک خروجی پیشنهاد می‌کند

در Linux، وقتی bypass-conntrack فعال باشد (پیش‌فرض)، برای هر source range مربوط به capture یک rule از نوع CT --notrack در raw PREROUTING نیز نصب می‌شود. شرط اضافهٔ --dst-type LOCAL این معافیت را به مقصدهای unicast محلی محدود می‌کند؛ ترافیک عبوری معمول، broadcast و multicast از conntrack معاف نمی‌شوند. فیلتر capture در INPUT، source range و استثناهای protocol را بدون این محدودیت نوع مقصد بررسی می‌کند. تطبیق در جدول raw پیش از DNAT انجام می‌شود؛ ترافیک معاف‌شده نباید به NAT یا rule‌های stateful وابسته به conntrack همین میزبان متکی باشد. مقدار bypass-conntrack=false معافیت هر دو مسیر را غیرفعال می‌کند؛ NFQUEUE capture و رفتار drop-and-dispatch آن همچنان فعال می‌مانند.

اولویت معمول raw حفظ می‌شود؛ reassembly مربوط به fragment‌ها و محدودیت capture برابر با ۱٬۵۰۰ بایت تغییر نمی‌کنند. این rule‌ها MTU را تغییر نمی‌دهند و جایگزین PMTU discovery نیستند؛ پیام‌های ICMP لازم باید همچنان به stack مسئول برسند. گزینهٔ skip-sysctl نصب NOTRACK را غیرفعال نمی‌کند.

ابتدا همهٔ rule‌های INPUT نصب می‌شوند، سپس در صورت فعال بودن این گزینه rule‌های NOTRACK اضافه می‌شوند. coordinator هنگام اجرای این فرمان‌های تحت نظارت، queueهای غیرفعال را با NF_ACCEPT سرویس می‌کند. capture پس از نصب همهٔ rule‌های انتخاب‌شده فعال می‌شود. اگر نصب rule‌های چندصفی شکست بخورد، rule‌های جزئی حذف می‌شوند و نصب با یک queue تکرار می‌شود. شکست نصب تک‌صفی، نصب NOTRACK یا rollback ناقص باعث شکست startup می‌شود. cleanup ابتدا حذف NOTRACK و سپس حذف NFQUEUE را امتحان می‌کند؛ شکست در حذف NOTRACK مانع تلاش برای حذف NFQUEUE نمی‌شود. وضعیت هر rule، از جمله نتیجهٔ نامعلوم پس از timeout، جداگانه در جدول مربوط به خودش پیگیری می‌شود. شکست reader باعث درخواست shutdown منظم می‌شود و مالک lifecycle پاک‌سازی rule‌ها را انجام می‌دهد. حذف NOTRACK رهگیری packet‌های بعدی را برمی‌گرداند، نه packet‌هایی که قبلاً untracked شده‌اند. --queue-bypass فقط روی NFQUEUE اثر دارد؛ مرگ ناگهانی process یا شکست نهایی cleanup ممکن است rule‌های WWCAP_NOTRACK_... را باقی بگذارد که برای بازگشت conntrack باید توسط مدیر سیستم از raw PREROUTING حذف شوند.

در Linux، ‏rule‌های NFQUEUE از --queue-bypass استفاده می‌کنند. اگر WaterWall روی queue گوش نکند، packet‌های matching به‌جای drop شدن به‌علت نبود queue، از firewall میزبان عبور می‌کنند. این یک سیاست availability از نوع fail-open است: تا وقتی listener وجود ندارد، packet‌ها capture یا transform نمی‌شوند. این گزینه در زمانی که WaterWall هنوز به queue متصل است، overflow شدن queue را fail-open نمی‌کند. WaterWall از شماره queue‌هایی که از قبل در rule‌های INPUT استفاده شده‌اند دوری می‌کند. شکست startup، queueها را می‌بندد؛ rollback کامل اجازهٔ restart بعدی را می‌دهد. cleanup ناموفق ruleها یا خطای I/O در queue غیرفعال، capture-device object را غیرقابل restart می‌کند. بسته‌شدن queueها باعث فعال‌شدن --queue-bypass برای ruleهای NFQUEUE باقی‌مانده می‌شود. پیش از فعال‌شدن capture و پس از جداشدن watcherهای workerها، coordinator در زمان نصب rule، rollback و cleanup هنگام bring-down، خواندن‌های محدود و nonblocking با verdict برابر NF_ACCEPT انجام می‌دهد. raw output device پیش از فعال‌شدن capture آماده است. فعال‌سازی دریافت پس از packet Init در صف هر worker قرار می‌گیرد. هنگام فرمان‌های بعدی startup، capture از NF_DROP استفاده می‌کند و packetها را با همان بودجهٔ مشترک برای تحویل روی worker در صف می‌گذارد؛ پرشدن FIFO نشست، خواندن native را متوقف می‌کند. تا زمان اجرای event loop ممکن است packetها در queueهای محدود kernel و FIFO نشست باقی بمانند. worker فعال از drop-and-dispatch استفاده می‌کند. هنگام shutdown، capture غیرفعال و پذیرش دریافت بسته می‌شود؛ هر watcher روی worker مالک جدا می‌شود و سپس ruleها پاک و descriptorها آزاد می‌شوند. خطای نهایی دریافت، پذیرش را می‌بندد و cleanup منظم را درخواست می‌کند؛ بسته‌شدن socket صف باعث می‌شود ruleهای باقی‌مانده fail-open شوند. در Linux هیچ thread اختصاصی برای capture reader یا cleanup ساخته نمی‌شود.

به‌صورت پیش‌فرض backend لینوکس پیش از ساخت resource‌های NFQUEUE یک batch از تنظیمات best-effort مربوط به backlog و سایر پارامترهای TCP را با sysctl اعمال می‌کند. نوشتن net.core.rmem_max، net.core.wmem_max، net.ipv4.tcp_rmem و net.ipv4.tcp_wmem به گزینه‌ی misc.tcp-tune در هسته تعلق دارد. گزینه "skip-sysctl": true فقط همین batch را حذف می‌کند؛ operation‌های netlink و command‌های iptables لازم برای ساخت و هدایت NFQUEUE همچنان اجرا می‌شوند.

اگر به رفتار virtual interface یا پردازش routed برای packet‌های خروجی نیاز دارید، از TunDevice استفاده کنید. RawSocket برای زمانی است که مشخصاً capture از host stack همراه با تزریق خام IPv4 می‌خواهید.

رفتار direction و lifecycle​

callbackرفتار
upstream Payloadpayload را از طریق raw output device تزریق می‌کند.
downstream Payloadpayload را از طریق raw output device تزریق می‌کند.
captured packet callbackpacket IPv4 captureشده را روی worker packet line به node مجاور انتخاب‌شده می‌فرستد.
Init, Est, Pause, Resumeterminal absorber‌های بدون per-line resource هستند.
Finish در هر جهتنقض fatal قرارداد packet line است و process را abort می‌کند؛ no-op نیست.

RawSocket یک adapter است و در runtime معمول packet line‌ها را از بین نمی‌برد. worker packet line‌ها متعلق به chain هستند و line state این node صفر بایت است.

این node protocol header اضافه نمی‌کند و به left padding نیاز ندارد.

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

  • برنامه را با دسترسی‌های لازم برای backend مربوط به raw/capture در همان platform اجرا کنید.
  • برای حالت capture از هرکدام از capture-ips یا capture-ip با یک string یا آرایه string استفاده کنید.
  • حذف range‌ها یا آرایه خالی عمداً حالت write-only را انتخاب می‌کند.
  • مسیر دریافت فعلی فقط packet‌های IPv4 را عبور می‌دهد.
  • رفتار هر platform به raw socket و backend‌های موجود برای capture و firewall mark وابسته است.

متادیتای node​

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

ویژگیمقدار
node flagskNodeFlagChainHead | kNodeFlagChainEnd
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayer3
layer_group_prev_nodekNodeLayer3
layer_group_next_nodekNodeLayer3
required_padding_left0 بایت

fragment-policy (اختیاری، پیش‌فرض: reassemble)​

حذف این تنظیم مقدار reassemble را انتخاب می‌کند: fragment‌های IPv4 پیش از تحویل به chain بازسازی می‌شوند. preserve-fragments بایت‌ها و مرز fragment‌ها را حفظ می‌کند. برای این policy فهرست مجاز نام node یا topology وجود ندارد؛ validation عادی لایه‌ها و chain همچنان برقرار است. مقدار نامعتبر، از جمله null، startup را رد می‌کند.

ورودی packet در جهت upstream برای PacketsToConnection و در جهت downstream برای ConnectionToPackets فقط datagram کامل IPv4 می‌پذیرد. رسیدن fragment به هر یک نقض قرارداد runtime است و با پیام fatal دربارهٔ نیاز به reassembly، کل برنامه در Debug و Release خاتمه می‌یابد. پیش از این consumer‌ها reassembly لازم است، مستقل از policy دستگاه یا node‌های میانی. بیت DF به‌تنهایی fragment نیست؛ MF یا offset غیرصفر نشانهٔ fragmentation است.

بازسازی تا ۶۵٬۵۳۵ بایت را تحویل می‌دهد، ولی سقف خروجی packet یا MTU را بالا نمی‌برد و fragmentation دوبارهٔ خروجی را خودکار انجام نمی‌دهد. محدودیت‌های نگهداری و مالکیت packet در بخش چهارم راهنمای توسعه‌دهنده آمده است.