TRAFGEN(8) netsniff-ng toolkit TRAFGEN(8)

trafgen - مولد ترافیک و بسته‌های شبکه سریع و چندنخی

trafgen [گزینه‌ها] [بسته]

ابزار trafgen یک مولد ترافیک شبکه سریع و مبتنی بر روش صفر-کپی (zero-copy) برای اشکال‌زدایی، ارزیابی کارایی و آزمون فازینگ (fuzz-testing) است. trafgen از رابط سوکت packet(7) لینوکس بهره می‌برد که کنترل کامل بر داده‌ها و سرایندهای بسته را به فضای کاربری واگذار می‌کند. این ابزار دارای یک زبان قدرتمند برای پیکربندی بسته‌ها است که نسبتاً سطح پایین بوده و محدود به پروتکل‌های خاصی نیست. بنابراین، trafgen می‌تواند برای اهداف متعددی استفاده شود. تنها محدودیت آن این است که نمی‌تواند جریان‌ها یا نشست‌های کامل (full streams resp. sessions) را شبیه‌سازی کند. با این حال، برای انواع مختلف آزمون‌های بارگذاری به منظور تحلیل و متعاقباً بهبود رفتار سیستم‌ها در سناریوهای حملات منع سرویس (DoS)، بسیار سودمند است.

ابزار trafgen مختص لینوکس است، به این معنی که همانند netsniff-ng(8)، هیچ پشتیبانی از سیستم‌عامل‌های دیگر وجود ندارد؛ بنابراین می‌توانیم ردپای کد را کاملاً کمینه و متمرکز بر هدف نگه داریم. trafgen از رابط TX_RING سوکت packet(7) هسته لینوکس استفاده می‌کند که یک بافر حلقوی mmap(2) شده مشترک میان فضای کاربری و فضای هسته است.

به‌طور پیش‌فرض، trafgen به تعداد پردازنده‌های (CPU) در دسترس پردازه ایجاد می‌کند، هر یک از آن‌ها را به پردازنده مربوط به خود متصل (pin) کرده و پس از کامپایل فهرستی از بسته‌ها برای ارسال، بافر حلقوی را در فضای پردازه اختصاصی هر کدام راه‌اندازی می‌کند. بنابراین، این احتمالاً سریع‌ترین کارایی ارسال از فضای کاربری است که می‌توان بدون نیاز به بارگذاری ماژول‌های هسته متفرقه یا خارج از شاخه اصلی (non-mainline) به دست آورد. در اترنت گیگابیتی، trafgen کارایی قابل مقایسه‌ای با pktgen (مولد ترافیک داخلی هسته لینوکس) دارد، با این تفاوت که trafgen از نظر انعطاف‌پذیری در پیکربندی بسته‌ها بسیار برتر است. در اترنت ۱۰ گیگابیت بر ثانیه، trafgen ممکن است به دلیل سربار جابه‌جایی میان فضای کاربری و هسته از pktgen کندتر باشد، اما همچنان برای هسته‌های استاندارد کارایی نسبتاً بالایی دارد.

ابزار trafgen دارای پتانسیل انجام آزمون فازینگ (fuzz testing) است؛ بدین معنا که می‌توان یک پیکربندی بسته با اعداد تصادفی در تمام یا برخی افست‌های معین بسته ایجاد کرد که در هر بار ارسال بسته از نو تولید شوند. با ابزار پینگ داخلی IPv4، ابزار trafgen می‌تواند پس از تزریق هر بسته، یک کاوشگر ICMP به میزبان راه دور بفرستد تا پاسخگو بودن و زنده بودن آن را بیازماید. با این فرض که پس از آستانه معینی از کاوش‌ها پاسخی از میزبان مقصد دریافت نشود، دستگاه از کار افتاده تلقی شده و آخرین بسته ارسال‌شده به همراه دانه تصادفی (random seed) مورد استفاده توسط trafgen چاپ می‌شود تا امکان بازتولید باگ فراهم گردد. شاید شانس چندانی برای فازینگ موفق هسته لینوکس نداشته باشید، اما احتمالاً سیستم‌های تعبیه‌شده تجاری باگ‌دار یا سفت‌افزارهای درایورهای شبکه وجود دارند که مستعد خطا هستند و trafgen می‌تواند در یافتن آن‌ها کمک کند.

زبان پیکربندی trafgen بسیار قدرتمند است، از جمله به این دلیل که از ماکروهای پیش‌پردازنده C پشتیبانی می‌کند. برای همین منظور، فایل stddef.h به همراه trafgen ارائه می‌شود تا بتوان تعاریف شناخته‌شده از هسته لینوکس یا برنامه‌نویسی شبکه را مجدداً استفاده کرد. پس از آن‌که فایل پیکربندی از مرحله پیش‌پردازنده C عبور کرد، توسط کامپایلر بسته trafgen پردازش می‌شود. خود زبان از قابلیت‌های متعددی پشتیبانی می‌کند که هنگام سرهم‌بندی بسته‌ها بسیار مفید هستند؛ مانند پشتیبانی داخلی از محاسبه چکسام در زمان اجرا برای IP، UDP و TCP. همچنین دارای یک ارزیاب عبارت (expression evaluator) است که محاسبات ریاضی (عملیات پایه، عملیات بیتی، شیفت بیت و...) روی عبارات ثابت را در زمان کامپایل به یک مقدار ثابت تبدیل می‌کند. از دیگر ویژگی‌ها ماکروهای پر کردن (''fill'') است که با آن‌ها می‌توان n بایت از بسته را با یک مقدار ثابت، یک عدد تصادفی زمان کامپایل یا عدد تصادفی زمان اجرا (همان‌طور که در آزمون فازینگ ذکر شد) پر کرد. همچنین netsniff-ng(8) قادر است یک فایل pcap را به فایل پیکربندی trafgen تبدیل کند؛ بنابراین می‌توان چنین پیکربندی را برای یک سناریوی معین بیشتر شخصی‌سازی کرد.

فایل پیکربندی ورودی را مشخص می‌کند که می‌تواند به صورت یک فایل متنی ساده معمولی یا از طریق ورودی استاندارد (''-'') داده شود. توجه داشته باشید در حال حاضر، اگر پیکربندی از طریق ورودی استاندارد داده شود، تنها از ۱ پردازنده (CPU) استفاده خواهد شد. همچنین می‌توان یک فایل PCAP با پسوند .pcap را از طریق گزینه -i/--in مشخص کرد؛ به‌طور پیش‌فرض بسته‌ها با نرخی با در نظر گرفتن برچسب زمان (timestamp) موجود در فایل PCAP ارسال می‌شوند که می‌توان با گزینه -b یا -t آن را بازنشانی کرد.
دستگاه شبکه خروجی مانند eth0، wlan0 و غیره، یا یک فایل *.pcap یا *.cfg را تعیین می‌کند. فایل‌های pcap و پیکربندی از طریق پسوند فایل شناسایی می‌شوند.
پیکربندی بسته را پیش از خواندن در trafgen، از پیش‌پردازنده C عبور می‌دهد. این امکان استفاده از دستورات #define و #include (برای نمونه جهت گنجاندن تعاریف از هدرهای سیستم) را در فایل پیکربندی trafgen فراهم می‌سازد.
افزودن تعریف ماکرو برای پیش‌پردازنده C جهت استفاده در فایل trafgen. این گزینه در ترکیب با گزینه -p/--cpp استفاده می‌شود.
به‌طور پیش‌فرض فریم‌های بافر حلقوی trafgen اندازه ثابت ۲۰۴۸ بایت دارند. این بدان معناست که اگر انتظار دارید فریم‌های بزرگ (jumbo frames) یا حتی فریم‌های بسیار بزرگ (super jumbo frames) از خط شما عبور کنند، باید با کمک این گزینه پشتیبانی از آن را فعال کنید. با این حال، این کار عیب کاهش کارایی و اشغال حافظه بیشتر برای بافر حلقوی را به همراه دارد.
در صورتی که دستگاه شبکه خروجی یک دستگاه بی‌سیم باشد، با trafgen می‌توان آن را به حالت پایش (monitor mode) درآورد و یک دستگاه mon<X> ایجاد کرد که برای نمونه trafgen به جای wlan<X> روی آن ارسال کند. این کار به trafgen امکان تزریق فریم‌های خام 802.11 را می‌دهد. در صورتی که خروجی یک فایل pcap باشد، نوع پیوند روی 127 (ieee80211 radio tap) تنظیم می‌شود.
در صورتی که این گزینه فعال باشد، trafgen یک آزمون دود (smoke test) انجام خواهد داد. به عبارت دیگر، انتهای راه دور را که با آدرس <ipv4> مشخص شده و هدف ارسال ترافیک شبکه trafgen قرار دارد می‌آزماید تا ببیند همچنان زنده و پاسخگو است یا خیر. بدین معنا که پس از هر بسته ارسال‌شده که پیکربندی شده است، trafgen درخواست‌های پژواک ICMP (echo requests) ارسال کرده و پیش از ادامه منتظر پاسخ می‌ماند. در صورتی که انتهای راه دور بدون پاسخ بماند، trafgen فرض می‌کند که دستگاه دچار فروپاشی (crash) شده و محتوای آخرین بسته را به صورت یک پیکربندی بسته trafgen به همراه دانه تصادفی استفاده‌شده برای بازتولید باگ احتمالی چاپ می‌کند. این ویژگی ممکن است هنگام آزمایش دستگاه‌های تعبیه‌شده تجاری بسیار سودمند باشد. توصیه می‌شود بین میزبانی که trafgen را اجرا می‌کند و میزبانی که هدف ارسال trafgen قرار دارد یک اتصال مستقیم برقرار باشد.
پردازش تعداد مشخصی از بسته‌ها و سپس خروج. اگر تعداد بسته‌ها ۰ باشد، معادل بسته‌های نامحدود یا پردازش تا زمان توقف با وقفه است. در غیر این صورت، عددی که به صورت یک عدد صحیح بدون علامت داده شود پردازش را محدود خواهد کرد.
انتخاب بسته از فایل پیکربندی را تصادفی می‌کند. به‌طور پیش‌فرض، اگر بیش از یک بسته در یک پیکربندی بسته تعریف شده باشد، بسته‌ها برای ارسال با روش نوبت‌گردشی (round-robin) زمان‌بندی می‌شوند. با این گزینه، آن‌ها به جای آن به صورت تصادفی انتخاب می‌شوند.
تعداد پردازه‌هایی را که trafgen باید با fork(2) ایجاد کند مشخص می‌کند یا فهرست دقیق پردازنده‌هایی را که باید استفاده شوند ارائه می‌دهد. به‌طور پیش‌فرض trafgen به تعداد پردازنده‌های فعال سیستم پردازه ایجاد کرده و هر یک را به پردازنده مربوطه متصل (pin) می‌کند. یک عدد صحیح منفرد در بازه [1,CPUs] تعداد پردازه‌ها را بازنویسی می‌کند که از پردازنده اول ایجاد خواهند شد. یک جفت عدد صحیح در بازه [0,CPUs-1] که با ''-'' جدا شده‌اند بازه‌ای از پردازنده‌ها را نشان می‌دهد که برای ایجاد پردازه‌های کارگر استفاده خواهند شد.
مشخص کردن یک فاصله زمانی ایستا میان بسته‌ها بر حسب ثانیه، میلی‌ثانیه، میکروثانیه یا نانوثانیه: ''<num>s/ms/us/ns''. اگر هیچ پسوندی داده نشود، پیش‌فرض میکروثانیه خواهد بود. اگر این گزینه مشخص شود، آن‌گاه trafgen به جای رابط TX_RING سوکت packet(7)، از ورودی/خروجی sendto(2) برای بسته‌های شبکه استفاده خواهد کرد، حتی اگر آرگومان <time> برابر با ۰ باشد. این گزینه به چند دلیل سودمند است:
1) مقایسه کارایی میان sendto(2) و TX_RING
2) کاوش بسته با ترافیک کم در یک بازه زمانی معین
3) اشکال‌زدایی شبه‌پینگ با الگوهای بار داده (payload) مشخص

علاوه بر این، رابط TX_RING قابلیت تنظیم فواصل زمانی میان بسته‌ها را ندارد.

مشخص کردن نرخ ارسال بسته‌ها بر حسب واحدهای <num>pps/kpps/Mpps/B/kB/MB/GB/kbit/Mbit/Gbit/KiB/MiB/GiB. همانند گزینه -t/--gap، بسته‌ها در حالت آهسته (slow mode) ارسال می‌شوند.
تعریف دستی اندازه TX_RING بر حسب ''<num>KiB/MiB/GiB''. به‌طور پیش‌فرض، اندازه بر اساس نرخ اتصال شبکه تعیین می‌شود.
تنظیم دستی دانه (seed) برای مولد اعداد شبه‌تصادفی (PRNG) در trafgen. به‌طور پیش‌فرض، یک دانه تصادفی از /dev/urandom برای تغذیه PRNG مربوط به glibc استفاده می‌شود. اگر ناموفق باشد، به برچسب زمان یونیکس بازمی‌گردد. تنظیم دستی دانه می‌تواند برای بازتولید یک نشست trafgen، برای نمونه پس از آزمون فازینگ، مفید باشد.
پس از راه‌اندازی حلقه، دسترسی‌ها را به ترکیب کاربر/گروه غیر ریشه کاهش می‌دهد.
تنظیم این پردازه به عنوان یک پردازه با اولویت بالا به منظور دستیابی به نرخ زمان‌بندی یا زمان CPU بیشتر. با این حال این تنظیم پیش‌فرض نیست، زیرا ممکن است باعث گرسنگی (starvation) سایر پردازه‌ها، برای نمونه نخ‌های هسته با اولویت پایین شود.
عدم تغییر تنظیمات حافظه سوکت پیش‌فرض سیستم در طول اجرای آزمون. پیش‌فرض این است که حافظه بافر سوکت در طول آزمون به مقادیر زیر ارتقا داده شود:
/proc/sys/net/core/rmem_default:4194304
/proc/sys/net/core/wmem_default:4194304
/proc/sys/net/core/rmem_max:104857600
/proc/sys/net/core/wmem_max:104857600
تنظیمات وابستگی وقفه سخت‌افزاری (IRQ CPU affinity) کارت شبکه را بازنشانی یا دستکاری نکند.
از لینوکس ۳.۱۴، هسته از یک گزینه سوکت به نام PACKET_QDISC_BYPASS پشتیبانی می‌کند که trafgen به‌طور پیش‌فرض آن را فعال می‌کند. این گزینه میانبر qdisc را غیرفعال کرده و از مسیر ارسال معمول از طریق لایه qdisc (کنترل ترافیک) هسته استفاده می‌کند، که می‌تواند برای آزمودن مسیر qdisc مفید باشد.
حالت پرگویی trafgen را فعال می‌کند تا پیکربندی پردازش‌شده و برخی آمارهای بافر حلقوی را چاپ کند.
نمایش یک نمونه پیکربندی بسته داخلی. این گزینه می‌تواند نقطه شروع مناسبی برای یک سناریوی اولیه پیکربندی بسته باشد.
عدم چاپ آمارهای زمان CPU هنگام خروج.
نمایش اطلاعات نگارش و خروج.
نمایش راهنمای کاربر و خروج.

سینتکس پیکربندی بسته در trafgen نسبتاً ساده است. پایه‌ای‌ترین چیزی که باید بدانید این است که یک فایل پیکربندی یک فایل متنی ساده معمولی است که بسته‌ها در آن تعریف می‌شوند. این فایل می‌تواند حاوی یک یا چند بسته باشد. بسته‌ها میان آکولاد باز '{' و بسته '}' محصور می‌شوند، برای نمونه:


{ /* محتوای بسته ۱ در اینجا قرار می‌گیرد ... */ }
{ /* محتوای بسته ۲ در اینجا قرار می‌گیرد ... */ }

همچنین، بسته‌ها را می‌توان مستقیماً در خط فرمان نیز با همان سینتکس مورد استفاده در فایل‌های پیکربندی مشخص کرد.

هنگامی که trafgen با استفاده از چند پردازنده (پیش‌فرض) آغاز می‌شود، به‌طور پیش‌فرض هر یک از آن بسته‌ها برای ارسال روی همه پردازنده‌ها زمان‌بندی می‌شوند. با این حال، می‌توان به trafgen گفت که یک بسته را تنها روی یک پردازنده خاص زمان‌بندی کند:


cpu(1): { /* محتوای بسته ۱ در اینجا قرار می‌گیرد ... */ }
cpu(2-3): { /* محتوای بسته ۲ در اینجا قرار می‌گیرد ... */ }

بنابراین، در صورتی که یک دستگاه ۴ هسته‌ای با پردازنده‌های CPU0-CPU3 داشته باشیم، بسته ۱ تنها روی CPU1 و بسته ۲ روی CPU2 و CPU3 زمان‌بندی خواهد شد. هنگام استفاده از trafgen با گزینه --num، این محدودیت‌ها همچنان معتبر خواهند بود و بسته به‌طور عادلانه میان آن پردازنده‌ها توزیع می‌شود.

محتوای بسته با ویرگول (کاما) یا فاصله خالی، یا هر دو از یکدیگر جدا می‌شود:


{ 0xca, 0xfe, 0xba 0xbe }

محتوای بسته می‌تواند از انواع زیر باشد:

بایت‌های هگزادسیمال: 0xca, xff
ده‌دهی (دسیمال):      42
دودویی (باینری):     0b11110000, b11110000
هشت‌هشتی (اوکتال):     011
کاراکتر:             'a'
رشته:                "hello world"
شل‌کد:               "\x31\xdb\x8d\x43\x17\x99\xcd\x80\x31\xc9"

بنابراین، یک پیکربندی بسته که کاربرد چندانی ندارد ممکن است شبیه به این باشد (می‌توان این موضوع را هنگام اجرای آن با trafgen در ترکیب با -V بررسی کرد):


{ 0xca, 42, 0b11110000, 011, 'a', "hello world",
"\x31\xdb\x8d\x43\x17\x99\xcd\x80\x31\xc9" }

تعدادی تابع کمکی در زبان trafgen وجود دارد تا نگارش پیکربندی‌ها را آسان‌تر سازد:

i) توابع پر کردن با داده‌های بی‌استفاده (Garbage):

تابع پر کردن بایت:             fill(<content>, <times>): fill(0xca, 128)
تصادفی زمان کامپایل:          rnd(<times>): rnd(128), rnd()
اعداد تصادفی زمان اجرا:        drnd(<times>): drnd(128), drnd()
شمارنده زمان کامپایل:         seqinc(<start-val>, <times>, <increment>)
                              seqdec(<start-val>, <times>, <decrement>)
شمارنده زمان اجرا (۱ بایت):   dinc(<min-val>, <max-val>, <increment>)
                              ddec(<min-val>, <max-val>, <decrement>)

ii) توابع کمکی چکسام (افست‌های بسته از ۰ شروع می‌شوند):

چکسام IP/ICMP:                csumip/csumicmp(<off-from>, <off-to>)
چکسام UDP:                    csumudp(<off-iphdr>, <off-udpdr>)
چکسام TCP:                    csumtcp(<off-iphdr>, <off-tcphdr>)
چکسام UDP در IPv6:            csumudp6(<off-ip6hdr>, <off-udpdr>)
چکسام TCP در IPv6:            csumtcp6(<off-ip6hdr>, <off-tcphdr>)

iii) توابع چندبایتی، ارزیابی عبارت در زمان کامپایل:


const8(<content>), c8(<content>), const16(<content>), c16(<content>),
const32(<content>), c32(<content>), const64(<content>), c64(<content>)

این توابع نتیجه خود را با ترتیب بایت شبکه در پیکربندی بسته می‌نویسند؛ برای نمونه const16(0xaa) به خروجی ''00 aa'' منجر خواهد شد. در توابع ()*c، امکان انجام برخی محاسبات حسابی وجود دارد: -,+,*,/,%,&,|,<<,>>,^ برای نمونه (((1<<8)+0x32)|0b110)*2)const16 به ''02 6c'' ارزیابی خواهد شد.

iv) توابع سرایند پروتکل (Protocol header functions):
توابع سرایند پروتکل امکان پر کردن فیلدهای سرایند پروتکل را با استفاده از نحو عمومی زیر فراهم می‌کنند:


<proto>(<field>=<value>,<field2>=<value2>,...,<field3>,...)



اگر فیلدی مشخص نشود، از مقدار پیش‌فرض استفاده خواهد شد (معمولاً ۰). فیلدهای پروتکل ممکن است به هر ترتیبی تنظیم شوند؛ با این حال، افست فیلدها در بسته نهایی مطابق با پروتکل مربوطه خواهد بود.

هر فیلد ممکن است با تابعی تنظیم شود که مقدار فیلد را در زمان اجرا با افزایش تدریجی یا تصادفی‌سازی تولید می‌کند. برای پروتکل‌های L3/L4، اگر فیلد به‌صورت پویا با تابع مشخص‌شده تغییر کرده باشد، چکسام به‌طور خودکار محاسبه می‌شود. توابع فیلد زیر پشتیبانی می‌شوند:

dinc - افزایش مقدار فیلد در زمان اجرا. به‌طور پیش‌فرض گام افزایش '1' است. پارامترهای min و max برای افزایش فیلد تنها در محدوده مشخص‌شده استفاده می‌شوند؛ به‌طور پیش‌فرض از مقدار اولیه فیلد استفاده می‌شود. اگر طول فیلد بیشتر از ۴ بایت باشد، تنها ۴ بایت آخر افزایش می‌یابند (برای آدرس‌های MAC و IPv6 کاربرد دارد):

<field> = dinc() | dinc(min, max) | dinc(min, max, step)

drnd - تصادفی‌سازی مقدار فیلد در زمان اجرا. پارامترهای min و max برای تصادفی‌سازی فیلد تنها در محدوده مشخص‌شده استفاده می‌شوند:

<field> = drnd() | drnd(min, max)

نمونه استفاده از توابع پویا:

{

eth(saddr=aa:bb:cc:dd:ee:ff, saddr=dinc()),
ipv4(saddr=dinc()),
udp(sport=dinc(1, 13, 2), dport=drnd(80, 100))
}


فیلدها را می‌توان با یک تابع در یک افست مشخص نیز بیشتر دستکاری کرد:


<field>[<index>] | <field>[<index>:<length>]


<index> - افست نسبی فیلد در محدوده 0..<field.len> - 1

<length> - طول/اندازه مقداری که تنظیم خواهد شد؛ ۱، ۲ یا ۴ بایت (پیش‌فرض: ۱)

مقدار <index> از نخستین بایت فیلد بر اساس ترتیب شبکه (network order) آغاز می‌شود.

این نحو مشابه سینتکس مورد استفاده در فیلترهای pcap (صفحه راهنمای pcap-filter) برای تطبیق فیلد سرایند در یک افست مشخص است.

نمونه‌های استفاده از افست فیلد (نمایش اثر در یک خروجی خلاصه‌شده از netsniff-ng):


1) trafgen -o lo --cpus 1 -n 3 '{ eth(da=11:22:33:44:55:66, da[0]=dinc()), tcp() }'


[ Eth MAC (00:00:00:00:00:00 => 11:22:33:44:55:66)

[ Eth MAC (00:00:00:00:00:00 => 12:22:33:44:55:66)

[ Eth MAC (00:00:00:00:00:00 => 13:22:33:44:55:66)

2) trafgen -o lo --cpus 1 -n 3 '{ ipv4(da=1.2.3.4, da[0]=dinc()), tcp() }'


[ IPv4 Addr (127.0.0.1 => 1.2.3.4)

[ IPv4 Addr (127.0.0.1 => 2.2.3.4)

[ IPv4 Addr (127.0.0.1 => 3.2.3.4)



تمامی سرایندهای لایه پایین‌تر مورد نیاز، در صورتی که توسط کاربر مشخص نشده باشند، به‌طور خودکار پر خواهند شد. سرایندها به همان ترتیبی که مشخص شده‌اند پر می‌شوند. هر سرایند با مجموعه‌ای کمینه از فیلدهای الزامی پر خواهد شد.


سرایندهای پروتکل پشتیبانی‌شده:

Ethernet : eth(da=<mac>, sa=<mac>, type=<number>)


da|daddr - آدرس MAC مقصد (پیش‌فرض: 00:00:00:00:00:00)

sa|saddr - آدرس MAC مبدأ (پیش‌فرض: آدرس MAC دستگاه)

etype|type|prot|proto - نوع اترنت (Ethernet type) (پیش‌فرض: 0)

PAUSE (IEEE 802.3X) : pause(code=<number>, time=<number>)


code - آپ‌کد کنترل MAC (پیش‌فرض: 0x0001)

time - زمان مکث (پیش‌فرض: 0)

به‌طور پیش‌فرض سرایند اترنت با فیلدهای زیر افزوده می‌شود:

نوع اترنت - 0x8808

آدرس MAC مقصد - 01:80:C2:00:00:01


PFC : pfc(pri|prio(<number>)=<number>, time(<number>)=<number>)


code - آپ‌کد کنترل MAC (پیش‌فرض: 0x0101)

pri|prio - بردار فعال‌سازی اولویت (پیش‌فرض: 0)

pri|prio(<number>) - فعال/غیرفعال‌سازی (۰ - غیرفعال، ۱ - فعال) مکث برای اولویت <number> (پیش‌فرض: 0)

time(<number>) - تنظیم زمان مکث برای اولویت <number> (پیش‌فرض: 0)

به‌طور پیش‌فرض سرایند اترنت با فیلدهای زیر افزوده می‌شود:

نوع اترنت - 0x8808

آدرس MAC مقصد - 01:80:C2:00:00:01


VLAN : vlan(tpid=<number>, id=<number>, dei=<number>, tci=<number>, pcp=<number>, 1q, 1ad)


tpid|prot|proto - شناسه پروتکل برچسب (TPID) (پیش‌فرض: 0x8100)

tci - فیلد اطلاعات کنترل برچسب (TCI) (شامل VLAN Id + PCP + DEI) (پیش‌فرض: 0)

dei|cfi - نشانگر شایستگی دور انداختن (DEI)، که قبلاً نشانگر قالب استاندارد (CFI) نامیده می‌شد (پیش‌فرض: 0)

pcp - نقطه کد اولویت (PCP) (پیش‌فرض: 0)

id - شناسه VLAN (پیش‌فرض: 0)

1q - تنظیم سرایند 802.1q (با TPID: 0x8100)

1ad - تنظیم سرایند 802.1ad (با TPID: 0x88a8)


به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر اترنت باشد، فیلد نوع اترنت (EtherType) آن بر روی 0x8100 (802.1q) تنظیم می‌شود.

MPLS : mpls(label=<number>, tc|exp=<number>, last=<number>, ttl=<number>)


label|lbl - مقدار برچسب MPLS (پیش‌فرض: 0)

tclass|tc|exp - کلاس ترافیک برای فیلد کیفیت خدمات (QoS) (پیش‌فرض: 0)

last - فلگ انتهای پشته S-flag (پیش‌فرض: ۱ برای آخرین برچسب)

ttl - طول عمر (TTL) (پیش‌فرض: 0)


به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر اترنت باشد، فیلد EtherType آن بر روی 0x8847 (MPLS Unicast) تنظیم می‌شود. فلگ S به‌طور خودکار برای آخرین برچسب روی ۱ تنظیم شده و اگر برچسب MPLS پایین‌تری پس از آن افزوده شود، به ۰ بازنشانی می‌گردد.

ARP : arp(htype=<number>, ptype=<number>, op=<request|reply|number>, request, reply, smac=<mac>, sip=<ip4_addr>, tmac=<mac>, tip=<ip4_addr>)


htype - نوع سخت‌افزار ARP (پیش‌فرض: 1 [Ethernet])

ptype - نوع پروتکل ARP (پیش‌فرض: 0x0800 [IPv4])

op - نوع عملیات ARP (درخواست/پاسخ) (پیش‌فرض: request)

req|request - نوع عملیات درخواست ARP

reply - نوع عملیات پاسخ ARP

smac|sha - آدرس سخت‌افزاری (MAC) فرستنده (پیش‌فرض: آدرس MAC دستگاه)

sip|spa - آدرس پروتکل (IPv4) فرستنده (پیش‌فرض: آدرس IPv4 دستگاه)

tmac|tha - آدرس سخت‌افزاری (MAC) هدف (پیش‌فرض: 00:00:00:00:00:00)

tip|tpa - آدرس پروتکل (IPv4) هدف (پیش‌فرض: آدرس IPv4 دستگاه)

به‌طور پیش‌فرض، فیلد عملیات ARP روی request و آدرس MAC مقصد اترنت روی آدرس همگانی (ff:ff:ff:ff:ff:ff) تنظیم می‌شود.

IPv4 : ip4|ipv4(ihl=<number>, ver=<number>, len=<number>, csum=<number>, ttl=<number>, tos=<number>, dscp=<number>, ecn=<number>,
id=<number>, flags=<number>, frag=<number>, df, mf, da=<ip4_addr>, sa=<ip4_addr>, prot[o]=<number>)


ver|version - فیلد نگارش (پیش‌فرض: 4)

ihl - طول سرایند بر حسب تعداد کلمات ۳۲ بیتی (پیش‌فرض: 5)

tos - فیلد نوع سرویس (ToS) (پیش‌فرض: 0)

dscp - فیلد نقطه کد خدمات تفکیک‌شده (DSCP, DiffServ) (پیش‌فرض: 0)

ecn - فیلد اعلان صریح ازدحام (ECN) (پیش‌فرض: 0)

len|length - طول کل سرایند و بار داده (به‌طور پیش‌فرض محاسبه می‌شود)

id - شناسه دیتاگرام IPv4 (پیش‌فرض: 0)

flags - مقدار فلگ‌های IPv4 (DF, MF) (پیش‌فرض: 0)

df - فلگ عدم تکه‌تکه‌سازی (DF) (پیش‌فرض: 0)

mf - فلگ تکه‌های بیشتر (MF) (پیش‌فرض: 0)

frag - فیلد افست تکه بر حسب تعداد بلوک‌های ۸ بایتی (پیش‌فرض: 0)

ttl - فیلد طول عمر (TTL) (پیش‌فرض: 0)

csum - چکسام سرایند (به‌طور پیش‌فرض محاسبه می‌شود)

sa|saddr - آدرس IPv4 مبدأ (پیش‌فرض: آدرس IPv4 دستگاه)

da|daddr - آدرس IPv4 مقصد (پیش‌فرض: 0.0.0.0)

prot|proto - شماره پروتکل IPv4 (پیش‌فرض: 0)

به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر اترنت باشد، فیلد EtherType آن بر روی 0x0800 (IPv4) تنظیم می‌شود. اگر سرایند سطح پایین‌تر IPv4 باشد، فیلد پروتکل آن بر روی 0x4 (IP-in-IP) تنظیم می‌گردد.

IPv6 : ip6|ipv6(ver=<number>, class=<number>, flow=<number> len=<number>, nexthdr=<number>, hoplimit=<number>,
da=<ip6_addr>, sa=<ip6_addr>)


ver|version - فیلد نگارش (پیش‌فرض: 6)

tc|tclass - کلاس ترافیک (Traffic class) (پیش‌فرض: 0)

fl|flow - برچسب جریان (Flow label) (پیش‌فرض: 0)

len|length - طول بار داده (به‌طور پیش‌فرض محاسبه می‌شود)

nh|nexthdr - نوع سرایند بعدی، یعنی شماره پروتکل لایه انتقال (پیش‌فرض: 0)

hl|hoplimit|ttl - محدودیت جهش، یعنی طول عمر (پیش‌فرض: 0)

sa|saddr - آدرس IPv6 مبدأ (پیش‌فرض: آدرس IPv6 دستگاه)

da|daddr - آدرس IPv6 مقصد (پیش‌فرض: 0:0:0:0:0:0:0:0)

به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر اترنت باشد، فیلد EtherType آن بر روی 0x86DD (IPv6) تنظیم می‌شود.

ICMPv4 : icmp4|icmpv4(type=<number>, code=<number>, echorequest, echoreply, csum=<number>, mtu=<number>, seq=<number>, id=<number>, addr=<ip4_addr>)


type - نوع پیام (پیش‌فرض: 0 - Echo reply)

code - کد پیام (پیش‌فرض: 0)

echorequest - درخواست پژواک (پینگ) ICMPv4 (نوع: 8، کد: 0)

echoreply - پاسخ پژواک (پینگ) ICMPv4 (نوع: 0، کد: 0)

csum - چکسام سرایند و بار داده ICMPv4 (به‌طور پیش‌فرض محاسبه می‌شود)

mtu - فیلد MTU جهش بعدی مورد استفاده در نوع پیام 'Datagram is too big' (پیش‌فرض: 0)

seq - شماره توالی مورد استفاده در پیام‌های Echo/Timestamp/Address mask (پیش‌فرض: 0)

id - شناسه مورد استفاده در پیام‌های Echo/Timestamp/Address mask (پیش‌فرض: 0)

addr - آدرس IPv4 مورد استفاده در پیام‌های تغییر مسیر (Redirect) (پیش‌فرض: 0.0.0.0)

نمونه درخواست پژواک ICMP (پینگ):

{ icmpv4(echorequest, seq=1, id=1326) }

ICMPv6 : icmp6|icmpv6(type=<number>, echorequest, echoreply, code=<number>, csum=<number>)


type - نوع پیام (پیش‌فرض: 0)

code - کد (پیش‌فرض: 0)

echorequest - درخواست پژواک (پینگ) ICMPv6

echoreply - پاسخ پژواک (پینگ) ICMPv6

csum - چکسام پیام (به‌طور پیش‌فرض محاسبه می‌شود)

به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر IPv6 باشد، فیلد Next Header آن بر روی 58 (ICMPv6) تنظیم می‌شود.

UDP : udp(sp=<number>, dp=<number>, len=<number>, csum=<number>)


sp|sport - درگاه مبدأ (پیش‌فرض: 0)

dp|dport - درگاه مقصد (پیش‌فرض: 0)

len|length - طول سرایند و داده‌های UDP (به‌طور پیش‌فرض محاسبه می‌شود)

csum - فیلد چکسام روی شبه‌سرایند IPv4 (به‌طور پیش‌فرض محاسبه می‌شود)

به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر IPv4 باشد، فیلد پروتکل آن بر روی 0x11 (UDP) تنظیم می‌شود.

TCP : tcp(sp=<number>, dp=<number>, seq=<number>, aseq|ackseq=<number>, doff|hlen=<number>, cwr, ece|ecn, urg, ack, psh, rst, syn, fin, win|window=<number>, csum=<number>, urgptr=<number>)


sp|sport - درگاه مبدأ (پیش‌فرض: 0)

dp|dport - درگاه مقصد (پیش‌فرض: 0)

seq - شماره توالی (پیش‌فرض: 0)

aseq|ackseq - شماره تأیید دریافت (پیش‌فرض: 0)

doff|hlen - اندازه سرایند (افست داده) بر حسب تعداد کلمات ۳۲ بیتی (پیش‌فرض: 5)

cwr - فلگ کاهش پنجره ازدحام (CWR) (پیش‌فرض: 0)

ece|ecn - فلگ بازتاب ECN (ECE) (پیش‌فرض: 0)

urg - فلگ اضطراری (URG) (پیش‌فرض: 0)

ack - فلگ تأیید دریافت (ACK) (پیش‌فرض: 0)

psh - فلگ ارسال فوری (PSH) (پیش‌فرض: 0)

rst - فلگ بازنشانی (RST) (پیش‌فرض: 0)

syn - فلگ همگام‌سازی (SYN) (پیش‌فرض: 0)

fin - فلگ پایان (FIN) (پیش‌فرض: 0)

win|window - اندازه پنجره دریافت (پیش‌فرض: 0)

csum - فیلد چکسام روی شبه‌سرایند IPv4 (به‌طور پیش‌فرض محاسبه می‌شود)

urgptr - اشاره‌گر اضطراری (پیش‌فرض: 0)

به‌طور پیش‌فرض، اگر سرایند سطح پایین‌تر IPv4 باشد، فیلد پروتکل آن بر روی 0x6 (TCP) تنظیم می‌شود.

مثال ساده از یک بسته UDP Echo:



{
eth(da=11:22:33:44:55:66),
ipv4(daddr=1.2.3.4)
udp(dp=7),
"Hello world"
}

علاوه بر این، دو نوع توضیح (کامنت) در فایل‌های پیکربندی trafgen وجود دارد:


1. توضیحات چندخطی به سبک C: /* put comment here */
2. توضیحات تک‌خطی به سبک شل: # put comment here

در کنار همه این‌ها، یک پیکربندی می‌تواند قبل از مشاهده توسط کامپایلر trafgen با استفاده از گزینه --cpp از پیش‌پردازنده C عبور داده شود. برای آشنایی با یک نمونه پیشرفته‌تر، دستور ''trafgen -e'' را اجرا کنید؛ فیلدهای آن با کامنت توضیح داده شده است:


/* نکته: عناصر پویا trafgen را کندتر می‌کنند! */
#include <stddef.h>


{
/* آدرس MAC مقصد */
fill(0xff, ETH_ALEN),
/* آدرس MAC مبدأ */
0x00, 0x02, 0xb3, drnd(3),
/* پروتکل IPv4 */
c16(ETH_P_IP),
/* نگارش IPv4، اندازه IHL و TOS */
0b01000101, 0,
/* طول کل IPv4 */
c16(59),
/* شناسه IPv4 */
drnd(2),
/* فلگ‌های IPv4، افست تکه */
0b01000000, 0,
/* طول عمر (TTL) در IPv4 */
64,
/* پروتکل TCP */
0x06,
/* چکسام IPv4 (سرایند IP از، تا) */
csumip(14, 33),
/* آدرس IP مبدأ */
drnd(4),
/* آدرس IP مقصد */
drnd(4),
/* درگاه مبدأ TCP */
drnd(2),
/* درگاه مقصد TCP */
c16(80),
/* شماره توالی TCP */
drnd(4),
/* شماره تأیید دریافت TCP */
c32(0),
/* طول سرایند TCP + فلگ TCP SYN/ECN */
c16((8 << 12) | TCP_FLAG_SYN | TCP_FLAG_ECE)
/* اندازه پنجره */
c16(16),
/* چکسام TCP (افست IP، افست TCP) */
csumtcp(14, 34),
/* گزینه‌های TCP */
0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x06,
0x91, 0x68, 0x7d, 0x06, 0x91, 0x68, 0x6f,
/* بخش داده */
"gotcha!",
}

یک نمونه واقعی دیگر از Jesper Dangaard Brouer [1]:


{
# --- سرایند اترنت ---
0x00, 0x1b, 0x21, 0x3c, 0x9d, 0xf8, # آدرس mac مقصد
0x90, 0xe2, 0xba, 0x0a, 0x56, 0xb4, # آدرس mac مبدأ
const16(0x0800), # پروتکل
# --- سرایند ip ---
# نگارش ipv4 (۴ بیت) + ihl (۴ بیت)، tos
0b01000101, 0,
# طول کل ipv4
const16(40),
# شناسه (نکته: تصادفی پویا در زمان اجرا)
drnd(2),
# فلگ‌های ۳ بیتی ipv4 + افست تکه ۱۳ بیتی
# 001 = تکه‌های بیشتر (more fragments)
0b00100000, 0,
64, # ttl
17, # پروتکل udp
# چکسام پویا ip (نکته: افست‌ها از صفر شروع می‌شوند)
csumip(14, 33),
192, 168, 51, 1, # آدرس ip مبدأ
192, 168, 51, 2, # آدرس ip مقصد
# --- سرایند udp ---
# از آنجا که این یک تکه است، موارد زیر اهمیت چندانی ندارند
const16(48054), # درگاه مبدأ
const16(43514), # درگاه مقصد
const16(20), # طول udp
# چکسام udp می‌تواند به صورت پویا با csumudp(offset ip, offset tcp) محاسبه شود
# که برابر است با csumudp(14, 34)، اما برای udp مقدار صفر مجاز است
const16(0),
# بار داده
'A', fill(0x41, 11),
}


[1] https://marc.info/?l=linux-netdev&m=135903630614184

نمونه بالا بازنویسی‌شده با استفاده از توابع تولید سرایند:


{
# --- ethernet header ---
eth(da=00:1b:21:3c:9d:f8, sa=90:e2:ba:0a:56:b4)
# --- ip header ---
ipv4(id=drnd(), mf, ttl=64, sa=192.168.51.1, da=192.168.51.2)
# --- udp header ---
udp(sport=48054, dport=43514, csum=0)
# payload
'A', fill(0x41, 11),
}

این ساده‌ترین و احتمالاً رایج‌ترین کاربرد trafgen است. ترافیک تعریف‌شده در فایل پیکربندی ''trafgen.cfg'' را تولید کرده و آن را از طریق دستگاه شبکه ''eth0'' ارسال می‌کند. از تمامی پردازنده‌های فعال سیستم استفاده می‌شود.
به جای استفاده از تمام پردازنده‌های فعال، ترافیک را تنها از پردازنده‌های ۲، ۳ و ۴ ارسال می‌کند.
این مثالی است که در آن یک بسته از نمونه داخلی را از طریق دستگاه loopback ارسال می‌کنیم. پیکربندی نمونه از طریق ورودی استاندارد (stdin) و همچنین پیش از دیده‌شدن توسط کامپایلر بسته trafgen، از پیش‌پردازنده C عبور داده می‌شود.
فایل پیکربندی بسته ''fuzzing.cfg'' (که حاوی فراخوانی‌های ()drnd است) را خوانده و بسته‌های تولیدشده را به دستگاه ''eth0'' ارسال می‌کند. پس از ارسال هر بسته، میزبان مورد حمله با آدرس 10.0.0.1 را با پینگ کاوش می‌کند تا ببیند آیا هنوز زنده است یا خیر. این همچنین به این معنی است که ما تنها از ۱ پردازنده استفاده می‌کنیم و از TX_RING استفاده نکرده، بلکه به دلیل «حالت آهسته» از ورودی/خروجی بسته sendto(2) بهره می‌بریم.
از دستگاه ''wlan0'' به عنوان دستگاه خروجی استفاده شده و در حالت پایش (monitor mode) قرار می‌گیرد؛ بنابراین فریم‌های خام 802.11 را در هوا ارسال خواهیم کرد. از فایل پیکربندی ''beacon-test.txf'' استفاده کرده، trafgen را در حالت پرگو قرار می‌دهد و تنها از ۲ پردازنده با شروع از CPU 0 استفاده می‌کند.
از trafgen در حالت sendto(2) به جای حالت TX_RING استفاده می‌کند و پس از هر بسته ارسال‌شده به مدت ۱۰۰۰ میکروثانیه به عنوان فاصله زمانی ایستا به خواب می‌رود. بسته‌ها را از ''frag_dos.cfg'' تولید کرده و بسته‌های بعدی برای ارسال را به صورت تصادفی به جای نوبت‌گردشی انتخاب می‌کند. دستگاه خروجی برای بسته‌ها ''em1'' است.
تنها ۱۴۰۰۰۰۰ بسته را با استفاده از فایل پیکربندی ''icmp.cfg'' ارسال کرده و سپس از trafgen خارج می‌شود. بسته‌ها را برای ارسال به صورت تصادفی از آن فایل انتخاب کرده و آن‌ها را از طریق ''eth0'' ارسال می‌کند. همچنین، هسته را هر ۱۰۰۰ میکروثانیه برای دسته‌بندی فریم‌های حلقه از فضای کاربری برمی‌انگیزد (پیش‌فرض ۱۰ میکروثانیه است).
بسته‌های تولیدشده از فایل پیکربندی ''tcp_syn.cfg'' را از طریق دستگاه شبکه ''eth0'' ارسال می‌کند. پس از راه‌اندازی حلقه برای ارسال، اختیارات را به کاربر/گروه غیر ریشه bob/bob کاهش می‌دهد.
ارسال ۱ بسته نامعتبر IPv4 ساخته‌شده در خط فرمان به همه میزبان‌ها.

ابزار trafgen می‌تواند یک پیوند اترنت گیگابیتی را بدون مشکل اشباع کند. البته همانند همیشه، این موضوع به سخت‌افزار شما نیز بستگی دارد. هر جا که روی جعبه عبارت اترنت گیگابیتی نوشته شده باشد، لزوماً به نرخ فیزیکی کامل خط نخواهید رسید! لطفاً بخش NOTE از صفحه راهنمای netsniff-ng(8) را نیز برای جزئیات بیشتر درباره تنظیم دقیق سیستم خود، برای نمونه با tuned(8)، مطالعه کنید.

اگر قصد دارید از trafgen روی یک کارت شبکه اترنت ۱۰ گیگابیت بر ثانیه استفاده کنید، مطمئن شوید که از یک انضباط چندصفی tc(8) استفاده می‌کنید، و اطمینان حاصل کنید که بسته‌هایی که با trafgen تولید می‌کنید توزیع مناسبی میان tx_hashها داشته باشند تا در عمل از صف‌های چندگانه بهره ببرید.

برای وارد کردن خطاهای بیتی، تأخیرها با تغییرات تصادفی و موارد دیگر، هیچ گزینه داخلی در trafgen وجود ندارد. در عوض، باید از روش‌های موجود برای این کار که به خوبی با trafgen یکپارچه می‌شوند، مانند tc(8) با انضباط‌های مختلف آن، یعنی netem، استفاده کنید.

برای پیکربندی‌های پیچیده‌تر بسته‌ها، توصیه می‌شود از اسکریپت‌نویسی سطح بالا برای تولید پیکربندی‌های بسته trafgen به روشی خودکارتر استفاده کنید، از جمله برای ایجاد توزیع‌های ترافیکی مختلف که برای معیارسنجی صنعتی رایج هستند:

Traffic model              Distribution
IMIX                       64:7,  570:4,  1518:1
Tolly                      64:55,  78:5,   576:17, 1518:23
Cisco                      64:7,  594:4,  1518:1
RPR Trimodal               64:60, 512:20, 1518:20
RPR Quadrimodal            64:50, 512:15, 1518:15, 9218:20

ماهیت سطح پایین trafgen باعث می‌شود که نسبتاً مستقل از پروتکل باشد و بنابراین در سناریوهای بسیاری که به آزمون فشار نیاز است مفید واقع شود. با این حال، اگر یک مولد ترافیک با توصیف بسته‌ها در سطح بالاتر مد نظر باشد، mausezahn(8) از مجموعه netsniff-ng نیز می‌تواند بسیار کاربردی باشد.

برای آزمون دود/فازینگ با trafgen، توصیه می‌شود بین میزبانی که می‌خواهید تحلیل کنید (دستگاه «قربانی») و میزبانی که trafgen را روی آن اجرا می‌کنید (دستگاه «حمله‌کننده»)، یک پیوند مستقیم وجود داشته باشد. اگر پاسخ ICMP از سوی قربانی دریافت نشود، فرض می‌کنیم که احتمالاً هسته آن دچار فروپاشی شده است؛ بنابراین آخرین بسته ارسالی را به همراه دانه چاپ کرده و کاوش را متوقف می‌کنیم. شاید یافتن چنین «پینگ مرگ» (ping-of-death) روی سیستم‌های لینوکسی مدرن بسیار نامحتمل باشد. با این حال، ممکن است شانس خوبی برای یافتن آن روی برخی سیستم‌های اختصاصی (مانند دستگاه‌های تعبیه‌شده) یا سفت‌افزارهای درایور باگ‌دار موجود در بازار وجود داشته باشد. همچنین آزمون فازینگ می‌تواند روی فریم‌های خام 802.11 نیز انجام شود. در صورتی که یک پینگ مرگ پیدا کردید، لطفاً در پیام کامیت رفع باگ خود ذکر کنید که از trafgen استفاده می‌کردید!

تنها در نگارش‌های قدیمی trafgen، امکان فروپاشی هسته وجود داشت: ما این باگ را در هسته‌های اصلی و پایدار تحت کامیت 7f5c3e3a8 (''af_packet: remove BUG statement in tpacket_destruct_skb'') و همچنین در خود trafgen برطرف کرده‌ایم.

احتمالاً بهترین راه این است که trafgen را به آخرین نگارش ارتقا دهید.

ابزار trafgen تحت مجوز عمومی گنو (GNU GPL) نگارش ۲.۰ منتشر شده است.

ابزار trafgen در ابتدا برای جعبه‌ابزار netsniff-ng توسط Daniel Borkmann نوشته شد. در حال حاضر توسط Tobias Klauser <tklauser@distanz.ch> و Daniel Borkmann <dborkma@tik.ee.ethz.ch> نگهداری می‌شود.

netsniff-ng(8), mausezahn(8), ifpps(8), bpfc(8), flowtop(8), astraceroute(8), curvetun(8)

این صفحه راهنما توسط Daniel Borkmann نوشته شده است.

این صفحه بخشی از پروژه جعبه‌ابزار netsniff-ng لینوکس است. توضیحات مربوط به پروژه و اطلاعات پیرامون گزارش اشکالات را می‌توان در http://netsniff-ng.org یافت.

03 March 2013 Linux