mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-05 13:25:53 +00:00

Utilize the extended pedit netlink to set an offset relative to a specific header type. Old netlink only enabled the user to set approximated offset relative to the IPv4 header. To use this extended functionality need to use the 'ex' keyword after 'pedit' and before any 'munge'. e.g: $ tc filter add dev ens9 protocol ip parent ffff: \ flower \ ip_proto udp \ dst_port 80 \ action pedit ex munge \ ip dst set 1.1.1.1 \ pipe \ action mirred egress redirect dev veth0 Signed-off-by: Amir Vadai <amir@vadai.me>
173 lines
3.7 KiB
C
173 lines
3.7 KiB
C
/*
|
|
* m_pedit.c packet editor: IPV4/6 header
|
|
*
|
|
* This program is free software; you can distribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
* Authors: J Hadi Salim (hadi@cyberus.ca)
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <syslog.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <string.h>
|
|
#include "utils.h"
|
|
#include "tc_util.h"
|
|
#include "m_pedit.h"
|
|
|
|
static int
|
|
parse_ip(int *argc_p, char ***argv_p,
|
|
struct m_pedit_sel *sel, struct m_pedit_key *tkey)
|
|
{
|
|
int res = -1;
|
|
int argc = *argc_p;
|
|
char **argv = *argv_p;
|
|
|
|
if (argc < 2)
|
|
return -1;
|
|
|
|
tkey->htype = sel->extended ?
|
|
TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 :
|
|
TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
|
|
|
|
if (strcmp(*argv, "src") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 12;
|
|
res = parse_cmd(&argc, &argv, 4, TIPV4, RU32, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "dst") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 16;
|
|
res = parse_cmd(&argc, &argv, 4, TIPV4, RU32, sel, tkey);
|
|
goto done;
|
|
}
|
|
/* jamal - look at these and make them either old or new
|
|
** scheme given diffserv
|
|
** dont forget the CE bit
|
|
*/
|
|
if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 1;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "ihl") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 0;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, 0x0f, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "protocol") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 9;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
|
|
goto done;
|
|
}
|
|
/* jamal - fix this */
|
|
if (matches(*argv, "precedence") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 1;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
|
|
goto done;
|
|
}
|
|
/* jamal - validate this at some point */
|
|
if (strcmp(*argv, "nofrag") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 6;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, 0x3F, sel, tkey);
|
|
goto done;
|
|
}
|
|
/* jamal - validate this at some point */
|
|
if (strcmp(*argv, "firstfrag") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 6;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, 0x1F, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "ce") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 6;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, 0x80, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "df") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 6;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, 0x40, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "mf") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 6;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, 0x20, sel, tkey);
|
|
goto done;
|
|
}
|
|
|
|
if (sel->extended)
|
|
return -1; /* fields located outside IP header should be
|
|
* addressed using the relevant header type in
|
|
* extended pedit kABI
|
|
*/
|
|
|
|
if (strcmp(*argv, "dport") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 22;
|
|
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "sport") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 20;
|
|
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "icmp_type") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 20;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
|
|
goto done;
|
|
}
|
|
if (strcmp(*argv, "icmp_code") == 0) {
|
|
NEXT_ARG();
|
|
tkey->off = 20;
|
|
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
|
|
goto done;
|
|
}
|
|
return -1;
|
|
|
|
done:
|
|
*argc_p = argc;
|
|
*argv_p = argv;
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
parse_ip6(int *argc_p, char ***argv_p,
|
|
struct m_pedit_sel *sel, struct m_pedit_key *tkey)
|
|
{
|
|
int res = -1;
|
|
return res;
|
|
}
|
|
|
|
struct m_pedit_util p_pedit_ip = {
|
|
NULL,
|
|
"ip",
|
|
parse_ip,
|
|
};
|
|
|
|
|
|
struct m_pedit_util p_pedit_ip6 = {
|
|
NULL,
|
|
"ip6",
|
|
parse_ip6,
|
|
};
|