m_ipt.c revision 1ffd7fd23eeaff57eb3b83b9dbbbda89ddf030e3
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * m_ipt.c iptables based targets 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * utilities mostly ripped from iptables <duh, its the linux way> 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This program is free software; you can distribute it and/or 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modify it under the terms of the GNU General Public License 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * as published by the Free Software Foundation; either version 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2 of the License, or (at your option) any later version. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Authors: J Hadi Salim (hadi@cyberus.ca) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * TODO: bad bad hardcoding IPT_LIB_DIR and PROC_SYS_MODPROBE 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <syslog.h> 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h> 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in.h> 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h> 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <iptables.h> 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/netfilter_ipv4/ip_tables.h> 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "utils.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tc_util.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/tc_act/tc_ipt.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dlfcn.h> 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h> 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netdb.h> 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h> 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h> 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h> 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/wait.h> 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *pname = "tc-ipt"; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *tname = "mangle"; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *pversion = "0.1"; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef TRUE 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TRUE 1 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef FALSE 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FALSE 0 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef IPT_LIB_DIR 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IPT_LIB_DIR "/usr/local/lib/iptables" 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef PROC_SYS_MODPROBE 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *ipthooks[] = { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "NF_IP_PRE_ROUTING", 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "NF_IP_LOCAL_IN", 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "NF_IP_FORWARD", 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "NF_IP_LOCAL_OUT", 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "NF_IP_POST_ROUTING", 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct option original_opts[] = { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {"jump", 1, 0, 'j'}, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {0, 0, 0, 0} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct iptables_target *t_list = NULL; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned int global_option_offset = 0; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define OPTION_OFFSET 256 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* no clue why register match is within targets 77 figure out later. Talk to Harald -- JHS 78*/ 79void 80register_match(struct iptables_match *me) 81{ 82/* fprintf(stderr, "\nDummy register_match\n"); */ 83} 84 85void 86register_target(struct iptables_target *me) 87{ 88/* fprintf(stderr, "\nDummy register_target %s \n", me->name); 89*/ 90 me->next = t_list; 91 t_list = me; 92 93} 94#endif 95 96void 97exit_tryhelp(int status) 98{ 99 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", 100 pname, pname); 101 exit(status); 102} 103 104void 105exit_error(enum exittype status, char *msg, ...) 106{ 107 va_list args; 108 109 va_start(args, msg); 110 fprintf(stderr, "%s v%s: ", pname, pversion); 111 vfprintf(stderr, msg, args); 112 va_end(args); 113 fprintf(stderr, "\n"); 114 if (status == PARAMETER_PROBLEM) 115 exit_tryhelp(status); 116 if (status == VERSION_PROBLEM) 117 fprintf(stderr, 118 "Perhaps iptables or your kernel needs to be upgraded.\n"); 119 exit(status); 120} 121 122/* stolen from iptables 1.2.11 123They should really have them as a library so i can link to them 124Email them next time i remember 125*/ 126 127char * 128addr_to_dotted(const struct in_addr *addrp) 129{ 130 static char buf[20]; 131 const unsigned char *bytep; 132 133 bytep = (const unsigned char *) &(addrp->s_addr); 134 sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); 135 return buf; 136} 137 138int string_to_number_ll(const char *s, unsigned long long min, 139 unsigned long long max, 140 unsigned long long *ret) 141{ 142 unsigned long long number; 143 char *end; 144 145 /* Handle hex, octal, etc. */ 146 errno = 0; 147 number = strtoull(s, &end, 0); 148 if (*end == '\0' && end != s) { 149 /* we parsed a number, let's see if we want this */ 150 if (errno != ERANGE && min <= number && (!max || number <= max)) { 151 *ret = number; 152 return 0; 153 } 154 } 155 return -1; 156} 157 158int string_to_number_l(const char *s, unsigned long min, unsigned long max, 159 unsigned long *ret) 160{ 161 int result; 162 unsigned long long number; 163 164 result = string_to_number_ll(s, min, max, &number); 165 *ret = (unsigned long)number; 166 167 return result; 168} 169 170int string_to_number(const char *s, unsigned int min, unsigned int max, 171 unsigned int *ret) 172{ 173 int result; 174 unsigned long number; 175 176 result = string_to_number_l(s, min, max, &number); 177 *ret = (unsigned int)number; 178 179 return result; 180} 181 182#if 0 183static int 184string_to_number(const char *s, unsigned int min, unsigned int max, 185 unsigned int *ret) 186{ 187 long number; 188 char *end; 189 190 /* Handle hex, octal, etc. */ 191 errno = 0; 192 number = strtol(s, &end, 0); 193 if (*end == '\0' && end != s) { 194 /* we parsed a number, let's see if we want this */ 195 if (errno != ERANGE && min <= number && number <= max) { 196 *ret = number; 197 return 0; 198 } 199 } 200 return -1; 201} 202#endif 203 204static struct option * 205copy_options(struct option *oldopts) 206{ 207 struct option *merge; 208 unsigned int num_old; 209 for (num_old = 0; oldopts[num_old].name; num_old++) ; 210 merge = malloc(sizeof (struct option) * (num_old + 1)); 211 if (NULL == merge) 212 return NULL; 213 memcpy(merge, oldopts, num_old * sizeof (struct option)); 214 memset(merge + num_old, 0, sizeof (struct option)); 215 return merge; 216} 217 218static struct option * 219merge_options(struct option *oldopts, const struct option *newopts, 220 unsigned int *option_offset) 221{ 222 struct option *merge; 223 unsigned int num_old, num_new, i; 224 225 for (num_old = 0; oldopts[num_old].name; num_old++) ; 226 for (num_new = 0; newopts[num_new].name; num_new++) ; 227 228 *option_offset = global_option_offset + OPTION_OFFSET; 229 230 merge = malloc(sizeof (struct option) * (num_new + num_old + 1)); 231 memcpy(merge, oldopts, num_old * sizeof (struct option)); 232 for (i = 0; i < num_new; i++) { 233 merge[num_old + i] = newopts[i]; 234 merge[num_old + i].val += *option_offset; 235 } 236 memset(merge + num_old + num_new, 0, sizeof (struct option)); 237 238 return merge; 239} 240 241static void * 242fw_calloc(size_t count, size_t size) 243{ 244 void *p; 245 246 if ((p = (void *) calloc(count, size)) == NULL) { 247 perror("iptables: calloc failed"); 248 exit(1); 249 } 250 return p; 251} 252 253#if 0 254static void * 255fw_malloc(size_t size) 256{ 257 void *p; 258 259 if ((p = (void *) malloc(size)) == NULL) { 260 perror("iptables: malloc failed"); 261 exit(1); 262 } 263 return p; 264} 265 266static int 267check_inverse(const char option[], int *invert) 268{ 269 if (option && strcmp(option, "!") == 0) { 270 if (*invert) 271 exit_error(PARAMETER_PROBLEM, 272 "Multiple `!' flags not allowed"); 273 274 *invert = TRUE; 275 return TRUE; 276 } 277 return FALSE; 278} 279#endif 280 281static struct iptables_target * 282find_t(char *name) 283{ 284 struct iptables_target *m; 285 for (m = t_list; m; m = m->next) { 286 if (strcmp(m->name, name) == 0) 287 return m; 288 } 289 290 return NULL; 291} 292 293static struct iptables_target * 294get_target_name(char *name) 295{ 296 void *handle; 297 char *error; 298 char *new_name, *lname; 299 struct iptables_target *m; 300 301 char path[sizeof (IPT_LIB_DIR) + sizeof ("/libipt_.so") + strlen(name)]; 302 303 new_name = malloc(strlen(name) + 1); 304 lname = malloc(strlen(name) + 1); 305 if (new_name) 306 memset(new_name, '\0', strlen(name) + 1); 307 else 308 exit_error(PARAMETER_PROBLEM, "get_target_name"); 309 310 if (lname) 311 memset(lname, '\0', strlen(name) + 1); 312 else 313 exit_error(PARAMETER_PROBLEM, "get_target_name"); 314 315 strcpy(new_name, name); 316 strcpy(lname, name); 317 318 if (isupper(lname[0])) { 319 int i; 320 for (i = 0; i < strlen(name); i++) { 321 lname[i] = tolower(lname[i]); 322 } 323 } 324 325 if (islower(new_name[0])) { 326 int i; 327 for (i = 0; i < strlen(new_name); i++) { 328 new_name[i] = toupper(new_name[i]); 329 } 330 } 331 332 sprintf(path, IPT_LIB_DIR "/libipt_%s.so", new_name); 333 handle = dlopen(path, RTLD_LAZY); 334 if (!handle) { 335 sprintf(path, IPT_LIB_DIR "/libipt_%s.so", lname); 336 handle = dlopen(path, RTLD_LAZY); 337 if (!handle) { 338 fputs(dlerror(), stderr); 339 printf("\n"); 340 return NULL; 341 } 342 } 343 344 m = dlsym(handle, new_name); 345 if ((error = dlerror()) != NULL) { 346 m = (struct iptables_target *) dlsym(handle, lname); 347 if ((error = dlerror()) != NULL) { 348 m = find_t(new_name); 349 if (NULL == m) { 350 m = find_t(lname); 351 if (NULL == m) { 352 fputs(error, stderr); 353 fprintf(stderr, "\n"); 354 dlclose(handle); 355 return NULL; 356 } 357 } 358 } 359 } 360 361 return m; 362} 363 364#if 0 365static char * 366addr_to_dotted(const struct in_addr *addrp) 367{ 368 static char buf[20]; 369 const unsigned char *bytep; 370 371 bytep = (const unsigned char *) &(addrp->s_addr); 372 sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); 373 return buf; 374} 375#endif 376 377struct in_addr *dotted_to_addr(const char *dotted) 378{ 379 static struct in_addr addr; 380 unsigned char *addrp; 381 char *p, *q; 382 unsigned int onebyte; 383 int i; 384 char buf[20]; 385 386 /* copy dotted string, because we need to modify it */ 387 strncpy(buf, dotted, sizeof (buf) - 1); 388 addrp = (unsigned char *) &(addr.s_addr); 389 390 p = buf; 391 for (i = 0; i < 3; i++) { 392 if ((q = strchr(p, '.')) == NULL) 393 return (struct in_addr *) NULL; 394 395 *q = '\0'; 396 if (string_to_number(p, 0, 255, &onebyte) == -1) 397 return (struct in_addr *) NULL; 398 399 addrp[i] = (unsigned char) onebyte; 400 p = q + 1; 401 } 402 403 /* we've checked 3 bytes, now we check the last one */ 404 if (string_to_number(p, 0, 255, &onebyte) == -1) 405 return (struct in_addr *) NULL; 406 407 addrp[3] = (unsigned char) onebyte; 408 409 return &addr; 410} 411 412int 413build_st(struct iptables_target *target, struct ipt_entry_target *t) 414{ 415 unsigned int nfcache = 0; 416 417 if (target) { 418 size_t size; 419 420 size = 421 IPT_ALIGN(sizeof (struct ipt_entry_target)) + target->size; 422 423 if (NULL == t) { 424 target->t = fw_calloc(1, size); 425 target->init(target->t, &nfcache); 426 target->t->u.target_size = size; 427 } else { 428 target->t = t; 429 } 430 strcpy(target->t->u.user.name, target->name); 431 return 0; 432 } 433 434 return -1; 435} 436 437static int parse_ipt(struct action_util *a,int *argc_p, 438 char ***argv_p, int tca_id, struct nlmsghdr *n) 439{ 440 struct iptables_target *m = NULL; 441 struct ipt_entry fw; 442 struct rtattr *tail; 443 int c; 444 int rargc = *argc_p; 445 char **argv = *argv_p; 446 struct option *opts; 447 int argc = 0, iargc = 0; 448 char k[16]; 449 int res = -1; 450 int size = 0; 451 int iok = 0, ok = 0; 452 __u32 hook = 0, index = 0; 453 res = 0; 454 455 { 456 int i; 457 for (i = 0; i < rargc; i++) { 458 if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { 459 break; 460 } 461 } 462 iargc = argc = i; 463 } 464 465 if (argc <= 2) { 466 fprintf(stderr,"bad arguements to ipt %d vs %d \n", argc, rargc); 467 return -1; 468 } 469 470 opts = copy_options(original_opts); 471 472 if (NULL == opts) 473 return -1; 474 475 while (1) { 476 c = getopt_long(argc, argv, "j:", opts, NULL); 477 if (c == -1) 478 break; 479 switch (c) { 480 case 'j': 481 m = get_target_name(optarg); 482 if (NULL != m) { 483 484 if (0 > build_st(m, NULL)) { 485 printf(" %s error \n", m->name); 486 return -1; 487 } 488 opts = 489 merge_options(opts, m->extra_opts, 490 &m->option_offset); 491 } else { 492 fprintf(stderr," failed to find target %s\n\n", optarg); 493 return -1; 494 } 495 ok++; 496 break; 497 498 default: 499 memset(&fw, 0, sizeof (fw)); 500 if (m) { 501 unsigned int fake_flags = 0; 502 m->parse(c - m->option_offset, argv, 0, 503 &fake_flags, NULL, &m->t); 504 } else { 505 fprintf(stderr," failed to find target %s\n\n", optarg); 506 return -1; 507 508 } 509 ok++; 510 511 /*m->final_check(m->t); -- Is this necessary? 512 ** useful when theres depencies 513 ** eg ipt_TCPMSS.c has have the TCP match loaded 514 ** before this can be used; 515 ** also seems the ECN target needs it 516 */ 517 518 break; 519 520 } 521 } 522 523 if (iargc > optind) { 524 if (matches(argv[optind], "index") == 0) { 525 if (get_u32(&index, argv[optind + 1], 10)) { 526 fprintf(stderr, "Illegal \"index\"\n"); 527 return -1; 528 } 529 iok++; 530 531 optind += 2; 532 } 533 } 534 535 if (!ok && !iok) { 536 fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); 537 return -1; 538 } 539 540 { 541 struct tcmsg *t = NLMSG_DATA(n); 542 if (t->tcm_parent != TC_H_ROOT 543 && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { 544 hook = NF_IP_PRE_ROUTING; 545 } else { 546 hook = NF_IP_POST_ROUTING; 547 } 548 } 549 550 tail = (struct rtattr *) (((void *) n) + NLMSG_ALIGN(n->nlmsg_len)); 551 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 552 fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]); 553 fprintf(stdout, "\ttarget: "); 554 555 if (m) 556 m->print(NULL, m->t, 0); 557 fprintf(stdout, " index %d\n", index); 558 559 if (strlen(tname) > 16) { 560 size = 16; 561 k[15] = 0; 562 } else { 563 size = 1 + strlen(tname); 564 } 565 strncpy(k, tname, size); 566 567 addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size); 568 addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4); 569 addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4); 570 if (m) 571 addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size); 572 tail->rta_len = 573 (((void *) n) + NLMSG_ALIGN(n->nlmsg_len)) - (void *) tail; 574 575 argc -= optind; 576 argv += optind; 577 *argc_p = rargc - iargc; 578 *argv_p = argv; 579 580 optind = 1; 581 582 return 0; 583 584} 585 586static int 587print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) 588{ 589 struct rtattr *tb[TCA_IPT_MAX + 1]; 590 struct ipt_entry_target *t = NULL; 591 struct option *opts; 592 593 if (arg == NULL) 594 return -1; 595 596 opts = copy_options(original_opts); 597 598 if (NULL == opts) 599 return -1; 600 memset(tb, 0, sizeof (tb)); 601 parse_rtattr(tb, TCA_IPT_MAX, RTA_DATA(arg), RTA_PAYLOAD(arg)); 602 603 if (tb[TCA_IPT_TABLE] == NULL) { 604 fprintf(f, "[NULL ipt table name ] assuming mangle "); 605 } else { 606 fprintf(f, "tablename: %s ", 607 (char *) RTA_DATA(tb[TCA_IPT_TABLE])); 608 } 609 610 if (tb[TCA_IPT_HOOK] == NULL) { 611 fprintf(f, "[NULL ipt hook name ]\n "); 612 return -1; 613 } else { 614 __u32 hook; 615 hook = *(__u32 *) RTA_DATA(tb[TCA_IPT_HOOK]); 616 fprintf(f, " hook: %s \n", ipthooks[hook]); 617 } 618 619 if (tb[TCA_IPT_TARG] == NULL) { 620 fprintf(f, "\t[NULL ipt target parameters ] \n"); 621 return -1; 622 } else { 623 struct iptables_target *m = NULL; 624 t = RTA_DATA(tb[TCA_IPT_TARG]); 625 m = get_target_name(t->u.user.name); 626 if (NULL != m) { 627 if (0 > build_st(m, t)) { 628 fprintf(stderr, " %s error \n", m->name); 629 return -1; 630 } 631 632 opts = 633 merge_options(opts, m->extra_opts, 634 &m->option_offset); 635 } else { 636 fprintf(stderr, " failed to find target %s\n\n", 637 t->u.user.name); 638 return -1; 639 } 640 fprintf(f, "\ttarget "); 641 m->print(NULL, m->t, 0); 642 if (tb[TCA_IPT_INDEX] == NULL) { 643 fprintf(f, " [NULL ipt target index ]\n"); 644 } else { 645 __u32 index; 646 index = *(__u32 *) RTA_DATA(tb[TCA_IPT_INDEX]); 647 fprintf(f, " \n\tindex %d", index); 648 } 649 650 if (tb[TCA_IPT_CNT]) { 651 struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; 652 fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); 653 } 654 if (show_stats) { 655 if (tb[TCA_IPT_TM]) { 656 struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); 657 print_tm(f,tm); 658 } 659 } 660 fprintf(f, " \n"); 661 662 } 663 664 return 0; 665} 666 667struct action_util ipt_action_util = { 668 .id = "ipt", 669 .parse_aopt = parse_ipt, 670 .print_aopt = print_ipt, 671}; 672 673