• 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 static int pedit_debug;
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 
get_pedit_kind(const char * str)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
pack_key(struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
pack_key32(__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
pack_key16(__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
pack_key8(__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
parse_val(int * argc_p,char *** argv_p,__u32 * val,int type)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
parse_cmd(int * argc_p,char *** argv_p,__u32 len,int type,__u32 retain,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
parse_offset(int * argc_p,char *** argv_p,struct tc_pedit_sel * sel,struct tc_pedit_key * tkey)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
parse_munge(int * argc_p,char *** argv_p,struct tc_pedit_sel * sel)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
parse_pedit(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)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
print_pedit(struct action_util * au,FILE * f,struct rtattr * arg)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
pedit_print_xstats(struct action_util * au,FILE * f,struct rtattr * xstats)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