Man pages sections > man8 > tc-pedit

pedit - generic packet editor action

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


pedit - generic packet editor action


tc ... action pedit munge { RAW_OP | LAYERED_OP } [ CONTROL ]
RAW_OP := offset OFFSET { u8 | u16 | u32 } [ AT_SPEC ] CMD_SPEC
AT_SPEC := at AT offmask MASK shift SHIFT
IPHDR_FIELD := { src | dst | tos | dsfield | ihl | protocol | precedence | nofrag | firstfrag | ce | df | mf | dport | sport | icmp_type | icmp_code }
CMD_SPEC := { clear | invert | set VAL | preserve } [ retain RVAL ]
CONTROL := { reclassify | pipe | drop | shot | continue | pass }


The pedit action can be used to change arbitrary packet data. The location of data to change can either be specified by giving an offset and size as in RAW_OP, or for header values by naming the header and field to edit the size is then chosen automatically based on the header field size. Currently this is supported only for IPv4 headers.


offset OFFSET { u32 | u16 | u8 }
Specify the offset at which to change data. OFFSET is a signed integer, it's base is automatically chosen (e.g. hex if prefixed by 0x or octal if prefixed by 0). The second argument specifies the length of data to change, that is four bytes (u32), two bytes (u16) or a single byte (u8).
at AT offmask MASK shift SHIFT
This is an optional part of RAW_OP which allows to have a variable OFFSET depending on packet data at offset AT, which is binary ANDed with MASK and right-shifted by SHIFT before adding it to OFFSET.
Change an IPv4 header field. The supported keywords for IPHDR_FIELD are:
dst Source or destination IP address, a four-byte value.
dsfield precedence Type Of Service field, an eight-bit value.
Change the IP Header Length field, a four-bit value.
Next-layer Protocol field, an eight-bit value.
firstfrag ce df mf Change IP header flags. Note that the value to pass to the set command is not just a bit value, but the full byte including the flags field. Though only the relevant bits of that value are respected, the rest ignored.
sport Destination or source port numbers, a 16-bit value. Indeed, IPv4 headers don't contain this information. Instead, this will set an offset which suits at least TCP and UDP if the IP header is of minimum size (20 bytes). If not, this will do unexpected things.
icmp_code Again, this allows to change data past the actual IP header itself. It assumes an ICMP header is present immediately following the (minimal sized) IP header. If it is not or the latter is bigger than the minimum of 20 bytes, this will do unexpected things. These fields are eight-bit values.
Clear the addressed data (i.e., set it to zero).
Swap every bit in the addressed data.
set VAL
Set the addressed data to a specific value. The size of VAL is defined by either one of the u32, u16 or u8 keywords in RAW_OP, or the size of the addressed header field in LAYERED_OP.
Keep the addressed data as is.
retain RVAL
This optional extra part of CMD_SPEC allows to exclude bits from being changed.
The following keywords allow to control how the tree of qdisc, classes, filters and actions is further traversed after this action.
Restart with the first filter in the current list.
Continue with the next action attached to the same filter.
shot Drop the packet.
Continue classification with the next filter in line.
Finish classification process and return to calling qdisc for further packet processing. This is the default.


Being able to edit packet data, one could do all kinds of things, such as e.g. implementing port redirection. Certainly not the most useful application, but as an example it should do:
First, qdiscs need to be set up to attach filters to. For the receive path, a simple ingress qdisc will do, for transmit path a classful qdisc (HTB in this case) is necessary:
tc qdisc replace dev eth0 root handle 1: htb
tc qdisc add dev eth0 ingress handle ffff:
Finally, a filter with pedit action can be added for each direction. In this case, u32 is used matching on the port number to redirect from, while pedit then does the actual rewriting:
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(8), tc-htb(8), tc-u32(8)
12 Jan 2015 iproute2