• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
explain(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
usage(void)55 usage(void)
56 {
57 	explain();
58 	exit(-1);
59 }
60 
61 static int
pedit_parse_nopopt(int * argc_p,char *** argv_p,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
get_pedit_kind(char * str)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
pack_key(struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
pack_key32(__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
pack_key16(__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
pack_key8(__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
parse_val(int * argc_p,char *** argv_p,__u32 * val,int type)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
parse_cmd(int * argc_p,char *** argv_p,__u32 len,int type,__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
parse_offset(int * argc_p,char *** argv_p,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
parse_munge(int * argc_p,char *** argv_p,struct tc_pedit_sel * sel)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
parse_pedit(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)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
print_pedit(struct action_util * au,FILE * f,struct rtattr * arg)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
pedit_print_xstats(struct action_util * au,FILE * f,struct rtattr * xstats)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