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 int pedit_debug = 1;
     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 struct m_pedit_util
     77 *get_pedit_kind(char *str)
     78 {
     79 	static void *pBODY;
     80 	void *dlh;
     81 	char buf[256];
     82 	struct  m_pedit_util *p;
     83 
     84 	for (p = pedit_list; p; p = p->next) {
     85 		if (strcmp(p->id, str) == 0)
     86 			return p;
     87 	}
     88 
     89 	snprintf(buf, sizeof(buf), "p_%s.so", str);
     90 	dlh = dlopen(buf, RTLD_LAZY);
     91 	if (dlh == NULL) {
     92 		dlh = pBODY;
     93 		if (dlh == NULL) {
     94 			dlh = pBODY = dlopen(NULL, RTLD_LAZY);
     95 			if (dlh == NULL)
     96 				goto noexist;
     97 		}
     98 	}
     99 
    100 	snprintf(buf, sizeof(buf), "p_pedit_%s", str);
    101 	p = dlsym(dlh, buf);
    102 	if (p == NULL)
    103 		goto noexist;
    104 
    105 reg:
    106 	p->next = pedit_list;
    107 	pedit_list = p;
    108 	return p;
    109 
    110 noexist:
    111 	p = malloc(sizeof(*p));
    112 	if (p) {
    113 		memset(p, 0, sizeof(*p));
    114 		strncpy(p->id, str, sizeof(p->id)-1);
    115 		p->parse_peopt = pedit_parse_nopopt;
    116 		goto reg;
    117 	}
    118 	return p;
    119 }
    120 
    121 int
    122 pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    123 {
    124 	int hwm = sel->nkeys;
    125 
    126 	if (hwm >= MAX_OFFS)
    127 		return -1;
    128 
    129 	if (tkey->off % 4) {
    130 		fprintf(stderr, "offsets MUST be in 32 bit boundaries\n");
    131 		return -1;
    132 	}
    133 
    134 	sel->keys[hwm].val = tkey->val;
    135 	sel->keys[hwm].mask = tkey->mask;
    136 	sel->keys[hwm].off = tkey->off;
    137 	sel->keys[hwm].at = tkey->at;
    138 	sel->keys[hwm].offmask = tkey->offmask;
    139 	sel->keys[hwm].shift = tkey->shift;
    140 	sel->nkeys++;
    141 	return 0;
    142 }
    143 
    144 
    145 int
    146 pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    147 {
    148 	if (tkey->off > (tkey->off & ~3)) {
    149 		fprintf(stderr,
    150 			"pack_key32: 32 bit offsets must begin in 32bit boundaries\n");
    151 		return -1;
    152 	}
    153 
    154 	tkey->val = htonl(tkey->val & retain);
    155 	tkey->mask = htonl(tkey->mask | ~retain);
    156 	/* jamal remove this - it is not necessary given the if check above */
    157 	tkey->off &= ~3;
    158 	return pack_key(sel,tkey);
    159 }
    160 
    161 int
    162 pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    163 {
    164 	int ind = 0, stride = 0;
    165 	__u32 m[4] = {0xFFFF0000,0xFF0000FF,0x0000FFFF};
    166 
    167 	if (0 > tkey->off) {
    168 		ind = tkey->off + 1;
    169 		if (0 > ind)
    170 			ind = -1*ind;
    171 	} else {
    172 		ind = tkey->off;
    173 	}
    174 
    175 	if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) {
    176 		fprintf(stderr, "pack_key16 bad value\n");
    177 		return -1;
    178 	}
    179 
    180 	ind = tkey->off & 3;
    181 
    182 	if (0 > ind || 2 < ind) {
    183 		fprintf(stderr, "pack_key16 bad index value %d\n",ind);
    184 		return -1;
    185 	}
    186 
    187 	stride = 8 * ind;
    188 	tkey->val = htons(tkey->val);
    189 	if (stride > 0) {
    190 		tkey->val <<= stride;
    191 		tkey->mask <<= stride;
    192 		retain <<= stride;
    193 	}
    194 	tkey->mask = retain|m[ind];
    195 
    196 	tkey->off &= ~3;
    197 
    198 	if (pedit_debug)
    199 		printf("pack_key16: Final val %08x mask %08x \n",tkey->val,tkey->mask);
    200 	return pack_key(sel,tkey);
    201 
    202 }
    203 
    204 int
    205 pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    206 {
    207 	int ind = 0, stride = 0;
    208 	__u32 m[4] = {0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,0x00FFFFFF};
    209 
    210 	if (0 > tkey->off) {
    211 		ind = tkey->off + 1;
    212 		if (0 > ind)
    213 			ind = -1*ind;
    214 	} else {
    215 		ind = tkey->off;
    216 	}
    217 
    218 	if (tkey->val > 0xFF || tkey->mask > 0xFF) {
    219 		fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask);
    220 		return -1;
    221 	}
    222 
    223 	ind = tkey->off & 3;
    224 	stride = 8 * ind;
    225 	tkey->val <<= stride;
    226 	tkey->mask <<= stride;
    227 	retain <<= stride;
    228 	tkey->mask = retain|m[ind];
    229 	tkey->off &= ~3;
    230 
    231 	if (pedit_debug)
    232 		printf("pack_key8: Final word off %d  val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask);
    233 	return pack_key(sel,tkey);
    234 }
    235 
    236 int
    237 parse_val(int *argc_p, char ***argv_p, __u32 * val, int type)
    238 {
    239 	int argc = *argc_p;
    240 	char **argv = *argv_p;
    241 
    242 	if (argc <= 0)
    243 		return -1;
    244 
    245 	if (TINT == type)
    246 		return get_integer((int *) val, *argv, 0);
    247 
    248 	if (TU32 == type)
    249 		return get_u32(val, *argv, 0);
    250 
    251 	if (TIPV4 == type) {
    252 		inet_prefix addr;
    253 		if (get_prefix_1(&addr, *argv, AF_INET)) {
    254 			return -1;
    255 		}
    256 		*val=addr.data[0];
    257 		return 0;
    258 	}
    259 	if (TIPV6 == type) {
    260 		/* not implemented yet */
    261 		return -1;
    262 	}
    263 
    264 	return -1;
    265 }
    266 
    267 int
    268 parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    269 {
    270 	__u32 mask = 0, val = 0;
    271 	__u32 o = 0xFF;
    272 	int res = -1;
    273 	int argc = *argc_p;
    274 	char **argv = *argv_p;
    275 
    276 	if (argc <= 0)
    277 		return -1;
    278 
    279 	if (pedit_debug)
    280 		printf("parse_cmd argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len);
    281 
    282 	if (len == 2)
    283 		o = 0xFFFF;
    284 	if (len == 4)
    285 		o = 0xFFFFFFFF;
    286 
    287 	if (matches(*argv, "invert") == 0) {
    288 		retain = val = mask = o;
    289 	} else if (matches(*argv, "set") == 0) {
    290 		NEXT_ARG();
    291 		if (parse_val(&argc, &argv, &val, type))
    292 			return -1;
    293 	} else if (matches(*argv, "preserve") == 0) {
    294 		retain = mask = o;
    295 	} else {
    296 		if (matches(*argv, "clear") != 0)
    297 			return -1;
    298 	}
    299 
    300 	argc--; argv++;
    301 
    302 	if (argc && matches(*argv, "retain") == 0) {
    303 		NEXT_ARG();
    304 		if (parse_val(&argc, &argv, &retain, TU32))
    305 			return -1;
    306 		argc--; argv++;
    307 	}
    308 
    309 	tkey->val = val;
    310 
    311 	if (len == 1) {
    312 		tkey->mask = 0xFF;
    313 		res = pack_key8(retain,sel,tkey);
    314 		goto done;
    315 	}
    316 	if (len == 2) {
    317 		tkey->mask = mask;
    318 		res = pack_key16(retain,sel,tkey);
    319 		goto done;
    320 	}
    321 	if (len == 4) {
    322 		tkey->mask = mask;
    323 		res = pack_key32(retain,sel,tkey);
    324 		goto done;
    325 	}
    326 
    327 	return -1;
    328 done:
    329 	if (pedit_debug)
    330 		printf("parse_cmd done argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len);
    331 	*argc_p = argc;
    332 	*argv_p = argv;
    333 	return res;
    334 
    335 }
    336 
    337 int
    338 parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
    339 {
    340 	int off;
    341 	__u32 len, retain;
    342 	int argc = *argc_p;
    343 	char **argv = *argv_p;
    344 	int res = -1;
    345 
    346 	if (argc <= 0)
    347 		return -1;
    348 
    349 	if (get_integer(&off, *argv, 0))
    350 		return -1;
    351 	tkey->off = off;
    352 
    353 	argc--;
    354 	argv++;
    355 
    356 	if (argc <= 0)
    357 		return -1;
    358 
    359 
    360 	if (matches(*argv, "u32") == 0) {
    361 		len = 4;
    362 		retain = 0xFFFFFFFF;
    363 		goto done;
    364 	}
    365 	if (matches(*argv, "u16") == 0) {
    366 		len = 2;
    367 		retain = 0x0;
    368 		goto done;
    369 	}
    370 	if (matches(*argv, "u8") == 0) {
    371 		len = 1;
    372 		retain = 0x0;
    373 		goto done;
    374 	}
    375 
    376 	return -1;
    377 
    378 done:
    379 
    380 	NEXT_ARG();
    381 
    382 	/* [at <someval> offmask <maskval> shift <shiftval>] */
    383 	if (matches(*argv, "at") == 0) {
    384 
    385 		__u32 atv=0,offmask=0x0,shift=0;
    386 
    387 		NEXT_ARG();
    388 		if (get_u32(&atv, *argv, 0))
    389 			return -1;
    390 		tkey->at = atv;
    391 
    392 		NEXT_ARG();
    393 
    394 		if (get_u32(&offmask, *argv, 16))
    395 			return -1;
    396 		tkey->offmask = offmask;
    397 
    398 		NEXT_ARG();
    399 
    400 		if (get_u32(&shift, *argv, 0))
    401 			return -1;
    402 		tkey->shift = shift;
    403 
    404 		NEXT_ARG();
    405 	}
    406 
    407 	res = parse_cmd(&argc, &argv, len, TU32,retain,sel,tkey);
    408 
    409 	*argc_p = argc;
    410 	*argv_p = argv;
    411 	return res;
    412 }
    413 
    414 int
    415 parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel)
    416 {
    417 	struct tc_pedit_key tkey;
    418 	int argc = *argc_p;
    419 	char **argv = *argv_p;
    420 	int res = -1;
    421 
    422 	if (argc <= 0)
    423 		return -1;
    424 
    425 	memset(&tkey, 0, sizeof(tkey));
    426 
    427 	if (matches(*argv, "offset") == 0) {
    428 		NEXT_ARG();
    429 		res = parse_offset(&argc, &argv,sel,&tkey);
    430 		goto done;
    431 	} else {
    432 		char k[16];
    433 		struct m_pedit_util *p = NULL;
    434 
    435 		strncpy(k, *argv, sizeof (k) - 1);
    436 
    437 		if (argc > 0 ) {
    438 			p = get_pedit_kind(k);
    439 			if (NULL == p)
    440 				goto bad_val;
    441 			res = p->parse_peopt(&argc, &argv, sel,&tkey);
    442 			if (res < 0) {
    443 				fprintf(stderr,"bad pedit parsing\n");
    444 				goto bad_val;
    445 			}
    446 			goto done;
    447 		}
    448 	}
    449 
    450 bad_val:
    451 	return -1;
    452 
    453 done:
    454 
    455 	*argc_p = argc;
    456 	*argv_p = argv;
    457 	return res;
    458 }
    459 
    460 int
    461 parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
    462 {
    463 	struct {
    464 		struct tc_pedit_sel sel;
    465 		struct tc_pedit_key keys[MAX_OFFS];
    466 	} sel;
    467 
    468 	int argc = *argc_p;
    469 	char **argv = *argv_p;
    470 	int ok = 0, iok = 0;
    471 	struct rtattr *tail;
    472 
    473 	memset(&sel, 0, sizeof(sel));
    474 
    475 	while (argc > 0) {
    476 		if (pedit_debug > 1)
    477 			fprintf(stderr, "while pedit (%d:%s)\n",argc, *argv);
    478 		if (matches(*argv, "pedit") == 0) {
    479 			NEXT_ARG();
    480 			ok++;
    481 			continue;
    482 		} else if (matches(*argv, "help") == 0) {
    483 			usage();
    484 		} else if (matches(*argv, "munge") == 0) {
    485 			if (!ok) {
    486 				fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
    487 				explain();
    488 				return -1;
    489 			}
    490 			NEXT_ARG();
    491 			if (parse_munge(&argc, &argv,&sel.sel)) {
    492 				fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
    493 				explain();
    494 				return -1;
    495 			}
    496 			ok++;
    497 		} else {
    498 			break;
    499 		}
    500 
    501 	}
    502 
    503 	if (!ok) {
    504 		explain();
    505 		return -1;
    506 	}
    507 
    508 	if (argc) {
    509 		if (matches(*argv, "reclassify") == 0) {
    510 			sel.sel.action = TC_ACT_RECLASSIFY;
    511 			NEXT_ARG();
    512 		} else if (matches(*argv, "pipe") == 0) {
    513 			sel.sel.action = TC_ACT_PIPE;
    514 			NEXT_ARG();
    515 		} else if (matches(*argv, "drop") == 0 ||
    516 			matches(*argv, "shot") == 0) {
    517 			sel.sel.action = TC_ACT_SHOT;
    518 			NEXT_ARG();
    519 		} else if (matches(*argv, "continue") == 0) {
    520 			sel.sel.action = TC_ACT_UNSPEC;
    521 			NEXT_ARG();
    522 		} else if (matches(*argv, "pass") == 0) {
    523 			sel.sel.action = TC_ACT_OK;
    524 			NEXT_ARG();
    525 		}
    526 	}
    527 
    528 	if (argc) {
    529 		if (matches(*argv, "index") == 0) {
    530 			NEXT_ARG();
    531 			if (get_u32(&sel.sel.index, *argv, 10)) {
    532 				fprintf(stderr, "Pedit: Illegal \"index\"\n");
    533 				return -1;
    534 			}
    535 			argc--;
    536 			argv++;
    537 			iok++;
    538 		}
    539 	}
    540 
    541 	tail = NLMSG_TAIL(n);
    542 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
    543 	addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS,&sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key));
    544 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
    545 
    546 	*argc_p = argc;
    547 	*argv_p = argv;
    548 	return 0;
    549 }
    550 
    551 int
    552 print_pedit(struct action_util *au,FILE * f, struct rtattr *arg)
    553 {
    554 	struct tc_pedit_sel *sel;
    555 	struct rtattr *tb[TCA_PEDIT_MAX + 1];
    556 	SPRINT_BUF(b1);
    557 
    558 	if (arg == NULL)
    559 		return -1;
    560 
    561 	parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
    562 
    563 	if (tb[TCA_PEDIT_PARMS] == NULL) {
    564 		fprintf(f, "[NULL pedit parameters]");
    565 		return -1;
    566 	}
    567 	sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
    568 
    569 	fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)),sel->nkeys);
    570 	fprintf(f, "\t index %d ref %d bind %d", sel->index,sel->refcnt, sel->bindcnt);
    571 
    572 	if (show_stats) {
    573 		if (tb[TCA_PEDIT_TM]) {
    574 			struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
    575 			print_tm(f,tm);
    576 		}
    577 	}
    578 	if (sel->nkeys) {
    579 		int i;
    580 		struct tc_pedit_key *key = sel->keys;
    581 
    582 		for (i=0; i<sel->nkeys; i++, key++) {
    583 			fprintf(f, "\n\t key #%d",i);
    584 			fprintf(f, "  at %d: val %08x mask %08x",
    585 			(unsigned int)key->off,
    586 			(unsigned int)ntohl(key->val),
    587 			(unsigned int)ntohl(key->mask));
    588 		}
    589 	} else {
    590 		fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,sel->nkeys);
    591 	}
    592 
    593 
    594 	fprintf(f, "\n ");
    595 	return 0;
    596 }
    597 
    598 int
    599 pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
    600 {
    601 	return 0;
    602 }
    603 
    604 struct action_util pedit_action_util = {
    605 	.id = "pedit",
    606 	.parse_aopt = parse_pedit,
    607 	.print_aopt = print_pedit,
    608 };
    609