Home | History | Annotate | Download | only in tc
      1 /*
      2  * m_pedit.c		generic packet editor actions module
      3  *
      4  *		This program is free software; you can distribute it and/or
      5  *		modify it under the terms of the GNU General Public License
      6  *		as published by the Free Software Foundation; either version
      7  *		2 of the License, or (at your option) any later version.
      8  *
      9  * Authors:  J Hadi Salim (hadi (at) cyberus.ca)
     10  *
     11  * TODO:
     12  *	1) Big endian broken in some spots
     13  *	2) A lot of this stuff was added on the fly; get a big double-double
     14  *	and clean it up at some point.
     15  *
     16  */
     17 
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <unistd.h>
     21 #include <syslog.h>
     22 #include <fcntl.h>
     23 #include <sys/socket.h>
     24 #include <netinet/in.h>
     25 #include <arpa/inet.h>
     26 #include <string.h>
     27 #include <dlfcn.h>
     28 #include "utils.h"
     29 #include "tc_util.h"
     30 #include "m_pedit.h"
     31 
     32 static struct m_pedit_util *pedit_list;
     33 static int pedit_debug;
     34 
     35 static void
     36 explain(void)
     37 {
     38 	fprintf(stderr, "Usage: ... pedit munge <MUNGE>\n");
     39 	fprintf(stderr,
     40 		"Where: MUNGE := <RAW>|<LAYERED>\n"
     41 		"\t<RAW>:= <OFFSETC>[ATC]<CMD>\n "
     42 		"\t\tOFFSETC:= offset <offval> <u8|u16|u32>\n "
     43 		"\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n "
     44 		"\t\tNOTE: offval is byte offset, must be multiple of 4\n "
     45 		"\t\tNOTE: maskval is a 32 bit hex number\n "
     46 		"\t\tNOTE: shiftval is a is a shift value\n "
     47 		"\t\tCMD:= clear | invert | set <setval>| retain\n "
     48 		"\t<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n "
     49 		" \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n"
     50 		"For Example usage look at the examples directory\n");
     51 
     52 }
     53 
     54 static void
     55 usage(void)
     56 {
     57 	explain();
     58 	exit(-1);
     59 }
     60 
     61 static int
     62 pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
     63 {
     64 	int argc = *argc_p;
     65 	char **argv = *argv_p;
     66 
     67 	if (argc) {
     68 		fprintf(stderr, "Unknown action  hence option \"%s\" is unparsable\n", *argv);
     69 			return -1;
     70 	}
     71 
     72 	return 0;
     73 
     74 }
     75 
     76 static struct m_pedit_util *get_pedit_kind(const char *str)
     77 {
     78 	static void *pBODY;
     79 	void *dlh;
     80 	char buf[256];
     81 	struct  m_pedit_util *p;
     82 
     83 	for (p = pedit_list; p; p = p->next) {
     84 		if (strcmp(p->id, str) == 0)
     85 			return p;
     86 	}
     87 
     88 	snprintf(buf, sizeof(buf), "p_%s.so", str);
     89 	dlh = dlopen(buf, RTLD_LAZY);
     90 	if (dlh == NULL) {
     91 		dlh = pBODY;
     92 		if (dlh == NULL) {
     93 			dlh = pBODY = dlopen(NULL, RTLD_LAZY);
     94 			if (dlh == NULL)
     95 				goto noexist;
     96 		}
     97 	}
     98 
     99 	snprintf(buf, sizeof(buf), "p_pedit_%s", str);
    100 	p = dlsym(dlh, buf);
    101 	if (p == NULL)
    102 		goto noexist;
    103 
    104 reg:
    105 	p->next = pedit_list;
    106 	pedit_list = p;
    107 	return p;
    108 
    109 noexist:
    110 	p = malloc(sizeof(*p));
    111 	if (p) {
    112 		memset(p, 0, sizeof(*p));
    113 		strncpy(p->id, str, sizeof(p->id)-1);
    114 		p->parse_peopt = pedit_parse_nopopt;
    115 		goto reg;
    116 	}
    117 	return p;
    118 }
    119 
    120 int
    121 pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    122 {
    123 	int hwm = sel->nkeys;
    124 
    125 	if (hwm >= MAX_OFFS)
    126 		return -1;
    127 
    128 	if (tkey->off % 4) {
    129 		fprintf(stderr, "offsets MUST be in 32 bit boundaries\n");
    130 		return -1;
    131 	}
    132 
    133 	sel->keys[hwm].val = tkey->val;
    134 	sel->keys[hwm].mask = tkey->mask;
    135 	sel->keys[hwm].off = tkey->off;
    136 	sel->keys[hwm].at = tkey->at;
    137 	sel->keys[hwm].offmask = tkey->offmask;
    138 	sel->keys[hwm].shift = tkey->shift;
    139 	sel->nkeys++;
    140 	return 0;
    141 }
    142 
    143 
    144 int
    145 pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    146 {
    147 	if (tkey->off > (tkey->off & ~3)) {
    148 		fprintf(stderr,
    149 			"pack_key32: 32 bit offsets must begin in 32bit boundaries\n");
    150 		return -1;
    151 	}
    152 
    153 	tkey->val = htonl(tkey->val & retain);
    154 	tkey->mask = htonl(tkey->mask | ~retain);
    155 	/* jamal remove this - it is not necessary given the if check above */
    156 	tkey->off &= ~3;
    157 	return pack_key(sel,tkey);
    158 }
    159 
    160 int
    161 pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    162 {
    163 	int ind, stride;
    164 	__u32 m[4] = {0xFFFF0000,0xFF0000FF,0x0000FFFF};
    165 
    166 	if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) {
    167 		fprintf(stderr, "pack_key16 bad value\n");
    168 		return -1;
    169 	}
    170 
    171 	ind = tkey->off & 3;
    172 
    173 	if (ind == 3) {
    174 		fprintf(stderr, "pack_key16 bad index value %d\n",ind);
    175 		return -1;
    176 	}
    177 
    178 	stride = 8 * ind;
    179 	tkey->val = htons(tkey->val);
    180 	tkey->val <<= stride;
    181 	tkey->mask <<= stride;
    182 	retain <<= stride;
    183 	tkey->mask = retain|m[ind];
    184 
    185 	tkey->off &= ~3;
    186 
    187 	if (pedit_debug)
    188 		printf("pack_key16: Final val %08x mask %08x \n",tkey->val,tkey->mask);
    189 	return pack_key(sel,tkey);
    190 
    191 }
    192 
    193 int
    194 pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    195 {
    196 	int ind, stride;
    197 	__u32 m[4] = {0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,0x00FFFFFF};
    198 
    199 	if (tkey->val > 0xFF || tkey->mask > 0xFF) {
    200 		fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask);
    201 		return -1;
    202 	}
    203 
    204 	ind = tkey->off & 3;
    205 
    206 	stride = 8 * ind;
    207 	tkey->val <<= stride;
    208 	tkey->mask <<= stride;
    209 	retain <<= stride;
    210 	tkey->mask = retain|m[ind];
    211 
    212 	tkey->off &= ~3;
    213 
    214 	if (pedit_debug)
    215 		printf("pack_key8: Final word off %d  val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask);
    216 	return pack_key(sel,tkey);
    217 }
    218 
    219 int
    220 parse_val(int *argc_p, char ***argv_p, __u32 * val, int type)
    221 {
    222 	int argc = *argc_p;
    223 	char **argv = *argv_p;
    224 
    225 	if (argc <= 0)
    226 		return -1;
    227 
    228 	if (TINT == type)
    229 		return get_integer((int *) val, *argv, 0);
    230 
    231 	if (TU32 == type)
    232 		return get_u32(val, *argv, 0);
    233 
    234 	if (TIPV4 == type) {
    235 		inet_prefix addr;
    236 		if (get_prefix_1(&addr, *argv, AF_INET)) {
    237 			return -1;
    238 		}
    239 		*val=addr.data[0];
    240 		return 0;
    241 	}
    242 	if (TIPV6 == type) {
    243 		/* not implemented yet */
    244 		return -1;
    245 	}
    246 
    247 	return -1;
    248 }
    249 
    250 int
    251 parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    252 {
    253 	__u32 mask = 0, val = 0;
    254 	__u32 o = 0xFF;
    255 	int res = -1;
    256 	int argc = *argc_p;
    257 	char **argv = *argv_p;
    258 
    259 	if (argc <= 0)
    260 		return -1;
    261 
    262 	if (pedit_debug)
    263 		printf("parse_cmd argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len);
    264 
    265 	if (len == 2)
    266 		o = 0xFFFF;
    267 	if (len == 4)
    268 		o = 0xFFFFFFFF;
    269 
    270 	if (matches(*argv, "invert") == 0) {
    271 		retain = val = mask = o;
    272 	} else if (matches(*argv, "set") == 0) {
    273 		NEXT_ARG();
    274 		if (parse_val(&argc, &argv, &val, type))
    275 			return -1;
    276 	} else if (matches(*argv, "preserve") == 0) {
    277 		retain = mask = o;
    278 	} else {
    279 		if (matches(*argv, "clear") != 0)
    280 			return -1;
    281 	}
    282 
    283 	argc--; argv++;
    284 
    285 	if (argc && matches(*argv, "retain") == 0) {
    286 		NEXT_ARG();
    287 		if (parse_val(&argc, &argv, &retain, TU32))
    288 			return -1;
    289 		argc--; argv++;
    290 	}
    291 
    292 	tkey->val = val;
    293 
    294 	if (len == 1) {
    295 		tkey->mask = 0xFF;
    296 		res = pack_key8(retain,sel,tkey);
    297 		goto done;
    298 	}
    299 	if (len == 2) {
    300 		tkey->mask = mask;
    301 		res = pack_key16(retain,sel,tkey);
    302 		goto done;
    303 	}
    304 	if (len == 4) {
    305 		tkey->mask = mask;
    306 		res = pack_key32(retain,sel,tkey);
    307 		goto done;
    308 	}
    309 
    310 	return -1;
    311 done:
    312 	if (pedit_debug)
    313 		printf("parse_cmd done argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len);
    314 	*argc_p = argc;
    315 	*argv_p = argv;
    316 	return res;
    317 
    318 }
    319 
    320 int
    321 parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    322 {
    323 	int off;
    324 	__u32 len, retain;
    325 	int argc = *argc_p;
    326 	char **argv = *argv_p;
    327 	int res = -1;
    328 
    329 	if (argc <= 0)
    330 		return -1;
    331 
    332 	if (get_integer(&off, *argv, 0))
    333 		return -1;
    334 	tkey->off = off;
    335 
    336 	argc--;
    337 	argv++;
    338 
    339 	if (argc <= 0)
    340 		return -1;
    341 
    342 
    343 	if (matches(*argv, "u32") == 0) {
    344 		len = 4;
    345 		retain = 0xFFFFFFFF;
    346 		goto done;
    347 	}
    348 	if (matches(*argv, "u16") == 0) {
    349 		len = 2;
    350 		retain = 0x0;
    351 		goto done;
    352 	}
    353 	if (matches(*argv, "u8") == 0) {
    354 		len = 1;
    355 		retain = 0x0;
    356 		goto done;
    357 	}
    358 
    359 	return -1;
    360 
    361 done:
    362 
    363 	NEXT_ARG();
    364 
    365 	/* [at <someval> offmask <maskval> shift <shiftval>] */
    366 	if (matches(*argv, "at") == 0) {
    367 
    368 		__u32 atv=0,offmask=0x0,shift=0;
    369 
    370 		NEXT_ARG();
    371 		if (get_u32(&atv, *argv, 0))
    372 			return -1;
    373 		tkey->at = atv;
    374 
    375 		NEXT_ARG();
    376 
    377 		if (get_u32(&offmask, *argv, 16))
    378 			return -1;
    379 		tkey->offmask = offmask;
    380 
    381 		NEXT_ARG();
    382 
    383 		if (get_u32(&shift, *argv, 0))
    384 			return -1;
    385 		tkey->shift = shift;
    386 
    387 		NEXT_ARG();
    388 	}
    389 
    390 	res = parse_cmd(&argc, &argv, len, TU32,retain,sel,tkey);
    391 
    392 	*argc_p = argc;
    393 	*argv_p = argv;
    394 	return res;
    395 }
    396 
    397 static int
    398 parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel)
    399 {
    400 	struct tc_pedit_key tkey;
    401 	int argc = *argc_p;
    402 	char **argv = *argv_p;
    403 	int res = -1;
    404 
    405 	if (argc <= 0)
    406 		return -1;
    407 
    408 	memset(&tkey, 0, sizeof(tkey));
    409 
    410 	if (matches(*argv, "offset") == 0) {
    411 		NEXT_ARG();
    412 		res = parse_offset(&argc, &argv,sel,&tkey);
    413 		goto done;
    414 	} else {
    415 		char k[16];
    416 		struct m_pedit_util *p = NULL;
    417 
    418 		strncpy(k, *argv, sizeof (k) - 1);
    419 
    420 		if (argc > 0 ) {
    421 			p = get_pedit_kind(k);
    422 			if (NULL == p)
    423 				goto bad_val;
    424 			res = p->parse_peopt(&argc, &argv, sel,&tkey);
    425 			if (res < 0) {
    426 				fprintf(stderr,"bad pedit parsing\n");
    427 				goto bad_val;
    428 			}
    429 			goto done;
    430 		}
    431 	}
    432 
    433 bad_val:
    434 	return -1;
    435 
    436 done:
    437 
    438 	*argc_p = argc;
    439 	*argv_p = argv;
    440 	return res;
    441 }
    442 
    443 int
    444 parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
    445 {
    446 	struct {
    447 		struct tc_pedit_sel sel;
    448 		struct tc_pedit_key keys[MAX_OFFS];
    449 	} sel;
    450 
    451 	int argc = *argc_p;
    452 	char **argv = *argv_p;
    453 	int ok = 0, iok = 0;
    454 	struct rtattr *tail;
    455 
    456 	memset(&sel, 0, sizeof(sel));
    457 
    458 	while (argc > 0) {
    459 		if (pedit_debug > 1)
    460 			fprintf(stderr, "while pedit (%d:%s)\n",argc, *argv);
    461 		if (matches(*argv, "pedit") == 0) {
    462 			NEXT_ARG();
    463 			ok++;
    464 			continue;
    465 		} else if (matches(*argv, "help") == 0) {
    466 			usage();
    467 		} else if (matches(*argv, "munge") == 0) {
    468 			if (!ok) {
    469 				fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
    470 				explain();
    471 				return -1;
    472 			}
    473 			NEXT_ARG();
    474 			if (parse_munge(&argc, &argv,&sel.sel)) {
    475 				fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
    476 				explain();
    477 				return -1;
    478 			}
    479 			ok++;
    480 		} else {
    481 			break;
    482 		}
    483 
    484 	}
    485 
    486 	if (!ok) {
    487 		explain();
    488 		return -1;
    489 	}
    490 
    491 	if (argc) {
    492 		if (matches(*argv, "reclassify") == 0) {
    493 			sel.sel.action = TC_ACT_RECLASSIFY;
    494 			NEXT_ARG();
    495 		} else if (matches(*argv, "pipe") == 0) {
    496 			sel.sel.action = TC_ACT_PIPE;
    497 			NEXT_ARG();
    498 		} else if (matches(*argv, "drop") == 0 ||
    499 			matches(*argv, "shot") == 0) {
    500 			sel.sel.action = TC_ACT_SHOT;
    501 			NEXT_ARG();
    502 		} else if (matches(*argv, "continue") == 0) {
    503 			sel.sel.action = TC_ACT_UNSPEC;
    504 			NEXT_ARG();
    505 		} else if (matches(*argv, "pass") == 0) {
    506 			sel.sel.action = TC_ACT_OK;
    507 			NEXT_ARG();
    508 		}
    509 	}
    510 
    511 	if (argc) {
    512 		if (matches(*argv, "index") == 0) {
    513 			NEXT_ARG();
    514 			if (get_u32(&sel.sel.index, *argv, 10)) {
    515 				fprintf(stderr, "Pedit: Illegal \"index\"\n");
    516 				return -1;
    517 			}
    518 			argc--;
    519 			argv++;
    520 			iok++;
    521 		}
    522 	}
    523 
    524 	tail = NLMSG_TAIL(n);
    525 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
    526 	addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS,&sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key));
    527 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
    528 
    529 	*argc_p = argc;
    530 	*argv_p = argv;
    531 	return 0;
    532 }
    533 
    534 int
    535 print_pedit(struct action_util *au,FILE * f, struct rtattr *arg)
    536 {
    537 	struct tc_pedit_sel *sel;
    538 	struct rtattr *tb[TCA_PEDIT_MAX + 1];
    539 	SPRINT_BUF(b1);
    540 
    541 	if (arg == NULL)
    542 		return -1;
    543 
    544 	parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
    545 
    546 	if (tb[TCA_PEDIT_PARMS] == NULL) {
    547 		fprintf(f, "[NULL pedit parameters]");
    548 		return -1;
    549 	}
    550 	sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
    551 
    552 	fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)),sel->nkeys);
    553 	fprintf(f, "\t index %d ref %d bind %d", sel->index,sel->refcnt, sel->bindcnt);
    554 
    555 	if (show_stats) {
    556 		if (tb[TCA_PEDIT_TM]) {
    557 			struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
    558 			print_tm(f,tm);
    559 		}
    560 	}
    561 	if (sel->nkeys) {
    562 		int i;
    563 		struct tc_pedit_key *key = sel->keys;
    564 
    565 		for (i=0; i<sel->nkeys; i++, key++) {
    566 			fprintf(f, "\n\t key #%d",i);
    567 			fprintf(f, "  at %d: val %08x mask %08x",
    568 			(unsigned int)key->off,
    569 			(unsigned int)ntohl(key->val),
    570 			(unsigned int)ntohl(key->mask));
    571 		}
    572 	} else {
    573 		fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,sel->nkeys);
    574 	}
    575 
    576 
    577 	fprintf(f, "\n ");
    578 	return 0;
    579 }
    580 
    581 int
    582 pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
    583 {
    584 	return 0;
    585 }
    586 
    587 struct action_util pedit_action_util = {
    588 	.id = "pedit",
    589 	.parse_aopt = parse_pedit,
    590 	.print_aopt = print_pedit,
    591 };
    592