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