Generic packet editor action in tc(8) Linux Generic packet editor action in tc(8)

tc-pedit - اکشن عمومی ویرایش بسته


tc ... action pedit [ex] munge { RAW_OP | LAYERED_OP | EXTENDED_LAYERED_OP } [ CONTROL ]

RAW_OP := offset OFFSET { u8 | u16 | u32 } [ AT_SPEC ] CMD_SPEC

AT_SPEC := at AT offmask MASK shift SHIFT

LAYERED_OP := { ip IPHDR_FIELD | ip BEYOND_IPHDR_FIELD } CMD_SPEC

EXTENDED_LAYERED_OP := { eth ETHHDR_FIELD | ip IPHDR_FIELD | ip EX_IPHDR_FIELD | ip6 IP6HDR_FIELD | tcp TCPHDR_FIELD | udp UDPHDR_FIELD } CMD_SPEC

ETHHDR_FIELD := { src | dst | type }

IPHDR_FIELD := { src | dst | tos | dsfield | ihl | protocol | precedence | nofrag | firstfrag | ce | df }

BEYOND_IPHDR_FIELD := { dport | sport | icmp_type | icmp_code }

EX_IPHDR_FIELD := { ttl }

IP6HDR_FIELD := { src | dst | traffic_class | flow_lbl | payload_len | nexthdr | hoplimit }

TCPHDR_FIELD := { sport | dport | flags }

UDPHDR_FIELD := { sport | dport }

CMD_SPEC := { clear | invert | set VAL | add VAL | decrement | preserve } [ retain RVAL ]

CONTROL := { reclassify | pipe | drop | shot | continue | pass | goto chain CHAIN_INDEX }

کنش pedit می‌تواند برای تغییر داده‌های دلخواه بسته استفاده شود. موقعیت داده‌ای که باید تغییر یابد، می‌تواند با تعیین یک آفست و اندازه همانند RAW_OP مشخص شود، یا برای مقادیر سرایند (header) با ذکر نام سرایند و فیلدی که باید ویرایش شود تعیین گردد؛ در این صورت اندازه به صورت خودکار بر اساس اندازه فیلد سرایند انتخاب می‌شود.

استفاده از حالت گسترش‌یافته pedit. عملگر EXTENDED_LAYERED_OP و مقادیر add/decrement در CMD_SPEC تنها در این حالت مجاز هستند.
تعیین آفست (انحراف) محلی که داده‌ها باید تغییر کنند. OFFSET یک عدد صحیح دارای علامت است و مبنای عددی آن به طور خودکار انتخاب می‌شود (برای نمونه هگزادسیمال در صورت داشتن پیشوند 0x یا هشت‌هشتی در صورت داشتن پیشوند 0). آرگومان دوم طول داده‌ای که باید تغییر کند را تعیین می‌کند، یعنی چهار بایت (u32)، دو بایت (u16) یا یک بایت (u8).
این یک بخش اختیاری از RAW_OP است که امکان داشتن یک OFFSET متغیر را بر اساس داده‌های بسته در آفست AT فراهم می‌کند؛ این مقدار با MASK عملیات AND بیتی شده و پیش از اضافه شدن به OFFSET، به اندازه SHIFT به سمت راست شیفت داده می‌شود.
تغییر یک فیلد سرایند اترنت (ETH). کلیدواژه‌های پشتیبانی‌شده برای ETHHDR_FIELD عبارتند از:
آدرس MAC مبدأ یا مقصد در فرمت استاندارد: XX:XX:XX:XX:XX:XX
مقدار عددی نوع اترنت (Ether-type).
تغییر یک فیلد سرایند IPv4. کلیدواژه‌های پشتیبانی‌شده برای IPHDR_FIELD عبارتند از:
آدرس IP مبدأ یا مقصد، یک مقدار چهار بایتی.
فیلد نوع سرویس (Type Of Service)، یک مقدار هشت بیتی.
تغییر فیلد طول سرایند آی‌پی (IP Header Length)، یک مقدار چهار بیتی.
فیلد پروتکل لایه بعدی (Next-layer Protocol)، یک مقدار هشت بیتی.
تغییر فلگ‌های سرایند IP. توجه داشته باشید مقداری که به دستور set داده می‌شود فقط مقدار یک بیت نیست، بلکه کل بایت شامل فیلد فلگ‌ها است؛ با این حال تنها بیت‌های مربوط به آن مقدار در نظر گرفته شده و بقیه نادیده گرفته می‌شوند.
تنها برای عملیات‌های لایه‌ای غیرگسترش‌یافته (non-extended) پشتیبانی می‌شود. این به عنوان آفست‌های نسبی نسبت به ابتدای سرایند IP به هسته ارسال می‌شود و فرض می‌کند سرایند IP دارای حداقل اندازه (۲۰ بایت) است. کلیدواژه‌های پشتیبانی‌شده برای BEYOND_IPHDR_FIELD عبارتند از:
شماره پورت‌های مقصد یا مبدأ، یک مقدار ۱۶ بیتی. در واقع، سرایندهای IPv4 این اطلاعات را در بر ندارند؛ در عوض، این گزینه آفستی را تنظیم می‌کند که اگر سرایند IP حداقل اندازه (۲۰ بایت) را داشته باشد، حداقل برای TCP و UDP مناسب است. در غیر این صورت، رفتارهای غیرمنتظره‌ای رخ خواهد داد.
مجدداً، این گزینه امکان تغییر داده‌های فراتر از خود سرایند واقعی IP را فراهم می‌کند. فرض بر این است که یک سرایند ICMP بلافاصله پس از سرایند IP (با اندازه کمینه) قرار گرفته است. اگر چنین نباشد یا سرایند IP بزرگ‌تر از اندازه کمینه ۲۰ بایت باشد، رفتارهای غیرمنتظره‌ای رخ خواهد داد. این فیلدها مقادیر هشت بیتی هستند.
تنها زمانی که ex به کار رفته باشد پشتیبانی می‌شود. کلیدواژه‌های پشتیبانی‌شده برای EX_IPHDR_FIELD عبارتند از:
کلیدواژه‌های پشتیبانی‌شده برای IP6HDR_FIELD عبارتند از:
کلیدواژه‌های پشتیبانی‌شده برای TCPHDR_FIELD عبارتند از:
شماره پورت مبدأ یا مقصد TCP، یک مقدار ۱۶ بیتی.
کلیدواژه‌های پشتیبانی‌شده برای UDPHDR_FIELD عبارتند از:
شماره پورت مبدأ یا مقصد UDP، یک مقدار ۱۶ بیتی.
پاک‌سازی داده‌های آدرس‌دهی شده (یعنی صفر کردن آن‌ها).
معکوس کردن تمام بیت‌ها در داده‌های آدرس‌دهی شده.
تنظیم داده‌های آدرس‌دهی شده روی یک مقدار مشخص. اندازه VAL توسط یکی از کلیدواژه‌های u32، u16 یا u8 در RAW_OP یا اندازه فیلد سرایند آدرس‌دهی شده در LAYERED_OP تعیین می‌شود.
افزودن یک مقدار مشخص به داده‌های آدرس‌دهی شده. اندازه VAL توسط اندازه فیلد سرایند آدرس‌دهی شده در EXTENDED_LAYERED_OP تعیین می‌شود. این عملیات فقط برای عملیات‌های لایه‌ای گسترش‌یافته (extended layered op) پشتیبانی می‌شود.
کاهش یک واحدی داده‌های آدرس‌دهی شده. این عملیات فقط برای ip ttl و ip6 hoplimit. پشتیبانی می‌شود.
دست‌نخورده نگه داشتن داده‌های آدرس‌دهی شده.
این بخش اختیاری اضافه در CMD_SPEC امکان مستثنی کردن بیت‌ها از تغییر را فراهم می‌کند. تنها برای فیلدهای ۳۲ بیتی یا کوچک‌تر پشتیبانی می‌شود.
کلیدواژه‌های زیر به شما اجازه می‌دهند کنترل کنید که پس از این اکشن، درخت qdiscها، کلاس‌ها، فیلترها و اکشن‌ها چگونه پیمایش شوند.
شروع مجدد از اولین فیلتر در فهرست فعلی.
ادامه کار با اکشن بعدی متصل به همان فیلتر.
دور انداختن بسته.
ادامه دسته‌بندی با فیلتر بعدی در صف.
پایان فرآیند دسته‌بندی و بازگشت به qdisc فراخوان برای پردازش‌های بعدی بسته. این حالت پیش‌فرض است.

با داشتن امکان ویرایش داده‌های بسته، می‌توان کارهای متنوعی انجام داد؛ به عنوان نمونه پیاده‌سازی تغییر مسیر پورت (port redirection). مسلماً این کاربردی‌ترین مورد استفاده نیست، اما به عنوان یک مثال مناسب خواهد بود:

ابتدا، لازم است qdiscها برای اتصال فیلترها به آن‌ها راه‌اندازی شوند. برای مسیر دریافت، یک qdisc ساده ingress کفایت می‌کند، و برای مسیر ارسال یک qdisc دارای کلاس (HTB در این مورد) مورد نیاز است:

tc qdisc replace dev eth0 root handle 1: htb
tc qdisc add dev eth0 ingress handle ffff:

در نهایت، یک فیلتر به همراه اکشن pedit می‌تواند برای هر مسیر اضافه شود. در این مورد، فیلتر u32 برای تطبیق روی شماره پورت جهت تغییر مسیر استفاده شده است، در حالی که pedit بازنویسی واقعی داده را انجام می‌دهد:

tc filter add dev eth0 parent 1: u32 \
	match ip dport 23 0xffff \
	action pedit pedit munge ip dport set 22
tc filter add dev eth0 parent ffff: u32 \
	match ip sport 22 0xffff \
	action pedit pedit munge ip sport set 23
tc filter add dev eth0 parent ffff: u32 \
	match ip sport 22 0xffff \
	action pedit ex munge ip dst set 192.168.1.199
tc filter add dev eth0 parent ffff: u32 \
	match ip sport 22 0xffff \
	action pedit ex munge ip6 dst set fe80::dacb:8aff:fec7:320e
tc filter add dev eth0 parent ffff: u32 \
	match ip sport 22 0xffff \
	action pedit ex munge eth dst set 11:22:33:44:55:66
tc filter add dev eth0 parent ffff: u32 \
	match ip dport 23 0xffff \
	action pedit ex munge tcp dport set 22

برای بازنویسی تنها بخشی از یک فیلد، از دستورالعمل retain استفاده کنید. به عنوان مثال برای رونویسی بخش DSCP از یک فیلد dsfield با $DSCP، بدون دستکاری ECN:

tc filter add dev eth0 ingress flower ... \
	action pedit ex munge ip dsfield set $((DSCP << 2)) retain 0xfc

و برعکس، برای تنظیم ECN مثلاً به مقدار 1 بدون تأثیر گذاشتن روی DSCP:

tc filter add dev eth0 ingress flower ... \
	action pedit ex munge ip dsfield set 1 retain 0x3

tc(8), tc-htb(8), tc-u32(8)

12 Jan 2015 iproute2