1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem (at) linux.nu> 2 * Patrick Schaaf <bof (at) bof.de> 3 * Martin Josefsson <gandalf (at) wlug.westbo.se> 4 * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec (at) blackhole.kfki.hu> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 /* Shared library add-on to iptables to add IP set mangling target. */ 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <netdb.h> 15 #include <string.h> 16 #include <stdlib.h> 17 #include <getopt.h> 18 #include <ctype.h> 19 20 #include <xtables.h> 21 #include <linux/netfilter/xt_set.h> 22 #include "libxt_set.h" 23 24 /* Revision 0 */ 25 26 static void 27 set_target_help_v0(void) 28 { 29 printf("SET target options:\n" 30 " --add-set name flags\n" 31 " --del-set name flags\n" 32 " add/del src/dst IP/port from/to named sets,\n" 33 " where flags are the comma separated list of\n" 34 " 'src' and 'dst' specifications.\n"); 35 } 36 37 static const struct option set_target_opts_v0[] = { 38 {.name = "add-set", .has_arg = true, .val = '1'}, 39 {.name = "del-set", .has_arg = true, .val = '2'}, 40 XT_GETOPT_TABLEEND, 41 }; 42 43 static void 44 set_target_check_v0(unsigned int flags) 45 { 46 if (!flags) 47 xtables_error(PARAMETER_PROBLEM, 48 "You must specify either `--add-set' or `--del-set'"); 49 } 50 51 static void 52 set_target_init_v0(struct xt_entry_target *target) 53 { 54 struct xt_set_info_target_v0 *info = 55 (struct xt_set_info_target_v0 *) target->data; 56 57 info->add_set.index = 58 info->del_set.index = IPSET_INVALID_ID; 59 60 } 61 62 static void 63 parse_target_v0(char **argv, int invert, unsigned int *flags, 64 struct xt_set_info_v0 *info, const char *what) 65 { 66 if (info->u.flags[0]) 67 xtables_error(PARAMETER_PROBLEM, 68 "--%s can be specified only once", what); 69 70 if (!argv[optind] 71 || argv[optind][0] == '-' || argv[optind][0] == '!') 72 xtables_error(PARAMETER_PROBLEM, 73 "--%s requires two args.", what); 74 75 if (strlen(optarg) > IPSET_MAXNAMELEN - 1) 76 xtables_error(PARAMETER_PROBLEM, 77 "setname `%s' too long, max %d characters.", 78 optarg, IPSET_MAXNAMELEN - 1); 79 80 get_set_byname(optarg, (struct xt_set_info *)info); 81 parse_dirs_v0(argv[optind], info); 82 optind++; 83 84 *flags = 1; 85 } 86 87 static int 88 set_target_parse_v0(int c, char **argv, int invert, unsigned int *flags, 89 const void *entry, struct xt_entry_target **target) 90 { 91 struct xt_set_info_target_v0 *myinfo = 92 (struct xt_set_info_target_v0 *) (*target)->data; 93 94 switch (c) { 95 case '1': /* --add-set <set> <flags> */ 96 parse_target_v0(argv, invert, flags, 97 &myinfo->add_set, "add-set"); 98 break; 99 case '2': /* --del-set <set>[:<flags>] <flags> */ 100 parse_target_v0(argv, invert, flags, 101 &myinfo->del_set, "del-set"); 102 break; 103 } 104 return 1; 105 } 106 107 static void 108 print_target_v0(const char *prefix, const struct xt_set_info_v0 *info) 109 { 110 int i; 111 char setname[IPSET_MAXNAMELEN]; 112 113 if (info->index == IPSET_INVALID_ID) 114 return; 115 get_set_byid(setname, info->index); 116 printf(" %s %s", prefix, setname); 117 for (i = 0; i < IPSET_DIM_MAX; i++) { 118 if (!info->u.flags[i]) 119 break; 120 printf("%s%s", 121 i == 0 ? " " : ",", 122 info->u.flags[i] & IPSET_SRC ? "src" : "dst"); 123 } 124 } 125 126 static void 127 set_target_print_v0(const void *ip, const struct xt_entry_target *target, 128 int numeric) 129 { 130 const struct xt_set_info_target_v0 *info = (const void *)target->data; 131 132 print_target_v0("add-set", &info->add_set); 133 print_target_v0("del-set", &info->del_set); 134 } 135 136 static void 137 set_target_save_v0(const void *ip, const struct xt_entry_target *target) 138 { 139 const struct xt_set_info_target_v0 *info = (const void *)target->data; 140 141 print_target_v0("--add-set", &info->add_set); 142 print_target_v0("--del-set", &info->del_set); 143 } 144 145 /* Revision 1 */ 146 static void 147 set_target_init_v1(struct xt_entry_target *target) 148 { 149 struct xt_set_info_target_v1 *info = 150 (struct xt_set_info_target_v1 *) target->data; 151 152 info->add_set.index = 153 info->del_set.index = IPSET_INVALID_ID; 154 155 } 156 157 #define SET_TARGET_ADD 0x1 158 #define SET_TARGET_DEL 0x2 159 #define SET_TARGET_EXIST 0x4 160 #define SET_TARGET_TIMEOUT 0x8 161 #define SET_TARGET_MAP 0x10 162 #define SET_TARGET_MAP_MARK 0x20 163 #define SET_TARGET_MAP_PRIO 0x40 164 #define SET_TARGET_MAP_QUEUE 0x80 165 166 static void 167 parse_target(char **argv, int invert, struct xt_set_info *info, 168 const char *what) 169 { 170 if (info->dim) 171 xtables_error(PARAMETER_PROBLEM, 172 "--%s can be specified only once", what); 173 if (!argv[optind] 174 || argv[optind][0] == '-' || argv[optind][0] == '!') 175 xtables_error(PARAMETER_PROBLEM, 176 "--%s requires two args.", what); 177 178 if (strlen(optarg) > IPSET_MAXNAMELEN - 1) 179 xtables_error(PARAMETER_PROBLEM, 180 "setname `%s' too long, max %d characters.", 181 optarg, IPSET_MAXNAMELEN - 1); 182 183 get_set_byname(optarg, info); 184 parse_dirs(argv[optind], info); 185 optind++; 186 } 187 188 static int 189 set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags, 190 const void *entry, struct xt_entry_target **target) 191 { 192 struct xt_set_info_target_v1 *myinfo = 193 (struct xt_set_info_target_v1 *) (*target)->data; 194 195 switch (c) { 196 case '1': /* --add-set <set> <flags> */ 197 parse_target(argv, invert, &myinfo->add_set, "add-set"); 198 *flags |= SET_TARGET_ADD; 199 break; 200 case '2': /* --del-set <set>[:<flags>] <flags> */ 201 parse_target(argv, invert, &myinfo->del_set, "del-set"); 202 *flags |= SET_TARGET_DEL; 203 break; 204 } 205 return 1; 206 } 207 208 static void 209 print_target(const char *prefix, const struct xt_set_info *info) 210 { 211 int i; 212 char setname[IPSET_MAXNAMELEN]; 213 214 if (info->index == IPSET_INVALID_ID) 215 return; 216 get_set_byid(setname, info->index); 217 printf(" %s %s", prefix, setname); 218 for (i = 1; i <= info->dim; i++) { 219 printf("%s%s", 220 i == 1 ? " " : ",", 221 info->flags & (1 << i) ? "src" : "dst"); 222 } 223 } 224 225 static void 226 set_target_print_v1(const void *ip, const struct xt_entry_target *target, 227 int numeric) 228 { 229 const struct xt_set_info_target_v1 *info = (const void *)target->data; 230 231 print_target("add-set", &info->add_set); 232 print_target("del-set", &info->del_set); 233 } 234 235 static void 236 set_target_save_v1(const void *ip, const struct xt_entry_target *target) 237 { 238 const struct xt_set_info_target_v1 *info = (const void *)target->data; 239 240 print_target("--add-set", &info->add_set); 241 print_target("--del-set", &info->del_set); 242 } 243 244 /* Revision 2 */ 245 246 static void 247 set_target_help_v2(void) 248 { 249 printf("SET target options:\n" 250 " --add-set name flags [--exist] [--timeout n]\n" 251 " --del-set name flags\n" 252 " add/del src/dst IP/port from/to named sets,\n" 253 " where flags are the comma separated list of\n" 254 " 'src' and 'dst' specifications.\n"); 255 } 256 257 static const struct option set_target_opts_v2[] = { 258 {.name = "add-set", .has_arg = true, .val = '1'}, 259 {.name = "del-set", .has_arg = true, .val = '2'}, 260 {.name = "exist", .has_arg = false, .val = '3'}, 261 {.name = "timeout", .has_arg = true, .val = '4'}, 262 XT_GETOPT_TABLEEND, 263 }; 264 265 static void 266 set_target_check_v2(unsigned int flags) 267 { 268 if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL))) 269 xtables_error(PARAMETER_PROBLEM, 270 "You must specify either `--add-set' or `--del-set'"); 271 if (!(flags & SET_TARGET_ADD)) { 272 if (flags & SET_TARGET_EXIST) 273 xtables_error(PARAMETER_PROBLEM, 274 "Flag `--exist' can be used with `--add-set' only"); 275 if (flags & SET_TARGET_TIMEOUT) 276 xtables_error(PARAMETER_PROBLEM, 277 "Option `--timeout' can be used with `--add-set' only"); 278 } 279 } 280 281 282 static void 283 set_target_init_v2(struct xt_entry_target *target) 284 { 285 struct xt_set_info_target_v2 *info = 286 (struct xt_set_info_target_v2 *) target->data; 287 288 info->add_set.index = 289 info->del_set.index = IPSET_INVALID_ID; 290 info->timeout = UINT32_MAX; 291 } 292 293 static int 294 set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags, 295 const void *entry, struct xt_entry_target **target) 296 { 297 struct xt_set_info_target_v2 *myinfo = 298 (struct xt_set_info_target_v2 *) (*target)->data; 299 unsigned int timeout; 300 301 switch (c) { 302 case '1': /* --add-set <set> <flags> */ 303 parse_target(argv, invert, &myinfo->add_set, "add-set"); 304 *flags |= SET_TARGET_ADD; 305 break; 306 case '2': /* --del-set <set>[:<flags>] <flags> */ 307 parse_target(argv, invert, &myinfo->del_set, "del-set"); 308 *flags |= SET_TARGET_DEL; 309 break; 310 case '3': 311 myinfo->flags |= IPSET_FLAG_EXIST; 312 *flags |= SET_TARGET_EXIST; 313 break; 314 case '4': 315 if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1)) 316 xtables_error(PARAMETER_PROBLEM, 317 "Invalid value for option --timeout " 318 "or out of range 0-%u", UINT32_MAX - 1); 319 myinfo->timeout = timeout; 320 *flags |= SET_TARGET_TIMEOUT; 321 break; 322 } 323 return 1; 324 } 325 326 static void 327 set_target_print_v2(const void *ip, const struct xt_entry_target *target, 328 int numeric) 329 { 330 const struct xt_set_info_target_v2 *info = (const void *)target->data; 331 332 print_target("add-set", &info->add_set); 333 if (info->flags & IPSET_FLAG_EXIST) 334 printf(" exist"); 335 if (info->timeout != UINT32_MAX) 336 printf(" timeout %u", info->timeout); 337 print_target("del-set", &info->del_set); 338 } 339 340 static void 341 set_target_save_v2(const void *ip, const struct xt_entry_target *target) 342 { 343 const struct xt_set_info_target_v2 *info = (const void *)target->data; 344 345 print_target("--add-set", &info->add_set); 346 if (info->flags & IPSET_FLAG_EXIST) 347 printf(" --exist"); 348 if (info->timeout != UINT32_MAX) 349 printf(" --timeout %u", info->timeout); 350 print_target("--del-set", &info->del_set); 351 } 352 353 354 /* Revision 3 */ 355 356 static void 357 set_target_help_v3(void) 358 { 359 printf("SET target options:\n" 360 " --add-set name flags [--exist] [--timeout n]\n" 361 " --del-set name flags\n" 362 " --map-set name flags" 363 " [--map-mark] [--map-prio] [--map-queue]\n" 364 " add/del src/dst IP/port from/to named sets,\n" 365 " where flags are the comma separated list of\n" 366 " 'src' and 'dst' specifications.\n"); 367 } 368 369 static const struct option set_target_opts_v3[] = { 370 {.name = "add-set", .has_arg = true, .val = '1'}, 371 {.name = "del-set", .has_arg = true, .val = '2'}, 372 {.name = "exist", .has_arg = false, .val = '3'}, 373 {.name = "timeout", .has_arg = true, .val = '4'}, 374 {.name = "map-set", .has_arg = true, .val = '5'}, 375 {.name = "map-mark", .has_arg = false, .val = '6'}, 376 {.name = "map-prio", .has_arg = false, .val = '7'}, 377 {.name = "map-queue", .has_arg = false, .val = '8'}, 378 XT_GETOPT_TABLEEND, 379 }; 380 381 static void 382 set_target_check_v3(unsigned int flags) 383 { 384 if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL|SET_TARGET_MAP))) 385 xtables_error(PARAMETER_PROBLEM, 386 "You must specify either `--add-set' or " 387 "`--del-set' or `--map-set'"); 388 if (!(flags & SET_TARGET_ADD)) { 389 if (flags & SET_TARGET_EXIST) 390 xtables_error(PARAMETER_PROBLEM, 391 "Flag `--exist' can be used with `--add-set' only"); 392 if (flags & SET_TARGET_TIMEOUT) 393 xtables_error(PARAMETER_PROBLEM, 394 "Option `--timeout' can be used with `--add-set' only"); 395 } 396 if (!(flags & SET_TARGET_MAP)) { 397 if (flags & SET_TARGET_MAP_MARK) 398 xtables_error(PARAMETER_PROBLEM, 399 "Flag `--map-mark' can be used with `--map-set' only"); 400 if (flags & SET_TARGET_MAP_PRIO) 401 xtables_error(PARAMETER_PROBLEM, 402 "Flag `--map-prio' can be used with `--map-set' only"); 403 if (flags & SET_TARGET_MAP_QUEUE) 404 xtables_error(PARAMETER_PROBLEM, 405 "Flag `--map-queue' can be used with `--map-set' only"); 406 } 407 if ((flags & SET_TARGET_MAP) && !(flags & (SET_TARGET_MAP_MARK | 408 SET_TARGET_MAP_PRIO | 409 SET_TARGET_MAP_QUEUE))) 410 xtables_error(PARAMETER_PROBLEM, 411 "You must specify flags `--map-mark' or " 412 "'--map-prio` or `--map-queue'"); 413 } 414 415 static void 416 set_target_init_v3(struct xt_entry_target *target) 417 { 418 struct xt_set_info_target_v3 *info = 419 (struct xt_set_info_target_v3 *) target->data; 420 421 info->add_set.index = 422 info->del_set.index = 423 info->map_set.index = IPSET_INVALID_ID; 424 info->timeout = UINT32_MAX; 425 } 426 427 static int 428 set_target_parse_v3(int c, char **argv, int invert, unsigned int *flags, 429 const void *entry, struct xt_entry_target **target) 430 { 431 struct xt_set_info_target_v3 *myinfo = 432 (struct xt_set_info_target_v3 *) (*target)->data; 433 unsigned int timeout; 434 435 switch (c) { 436 case '1': /* --add-set <set> <flags> */ 437 parse_target(argv, invert, &myinfo->add_set, "add-set"); 438 *flags |= SET_TARGET_ADD; 439 break; 440 case '2': /* --del-set <set>[:<flags>] <flags> */ 441 parse_target(argv, invert, &myinfo->del_set, "del-set"); 442 *flags |= SET_TARGET_DEL; 443 break; 444 case '3': 445 myinfo->flags |= IPSET_FLAG_EXIST; 446 *flags |= SET_TARGET_EXIST; 447 break; 448 case '4': 449 if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1)) 450 xtables_error(PARAMETER_PROBLEM, 451 "Invalid value for option --timeout " 452 "or out of range 0-%u", UINT32_MAX - 1); 453 myinfo->timeout = timeout; 454 *flags |= SET_TARGET_TIMEOUT; 455 break; 456 case '5': /* --map-set <set> <flags> */ 457 parse_target(argv, invert, &myinfo->map_set, "map-set"); 458 *flags |= SET_TARGET_MAP; 459 break; 460 case '6': 461 myinfo->flags |= IPSET_FLAG_MAP_SKBMARK; 462 *flags |= SET_TARGET_MAP_MARK; 463 break; 464 case '7': 465 myinfo->flags |= IPSET_FLAG_MAP_SKBPRIO; 466 *flags |= SET_TARGET_MAP_PRIO; 467 break; 468 case '8': 469 myinfo->flags |= IPSET_FLAG_MAP_SKBQUEUE; 470 *flags |= SET_TARGET_MAP_QUEUE; 471 break; 472 } 473 return 1; 474 } 475 476 static void 477 set_target_print_v3(const void *ip, const struct xt_entry_target *target, 478 int numeric) 479 { 480 const struct xt_set_info_target_v3 *info = (const void *)target->data; 481 482 print_target("add-set", &info->add_set); 483 if (info->flags & IPSET_FLAG_EXIST) 484 printf(" exist"); 485 if (info->timeout != UINT32_MAX) 486 printf(" timeout %u", info->timeout); 487 print_target("del-set", &info->del_set); 488 print_target("map-set", &info->map_set); 489 if (info->flags & IPSET_FLAG_MAP_SKBMARK) 490 printf(" map-mark"); 491 if (info->flags & IPSET_FLAG_MAP_SKBPRIO) 492 printf(" map-prio"); 493 if (info->flags & IPSET_FLAG_MAP_SKBQUEUE) 494 printf(" map-queue"); 495 } 496 497 static void 498 set_target_save_v3(const void *ip, const struct xt_entry_target *target) 499 { 500 const struct xt_set_info_target_v3 *info = (const void *)target->data; 501 502 print_target("--add-set", &info->add_set); 503 if (info->flags & IPSET_FLAG_EXIST) 504 printf(" --exist"); 505 if (info->timeout != UINT32_MAX) 506 printf(" --timeout %u", info->timeout); 507 print_target("--del-set", &info->del_set); 508 print_target("--map-set", &info->map_set); 509 if (info->flags & IPSET_FLAG_MAP_SKBMARK) 510 printf(" --map-mark"); 511 if (info->flags & IPSET_FLAG_MAP_SKBPRIO) 512 printf(" --map-prio"); 513 if (info->flags & IPSET_FLAG_MAP_SKBQUEUE) 514 printf(" --map-queue"); 515 } 516 517 static struct xtables_target set_tg_reg[] = { 518 { 519 .name = "SET", 520 .revision = 0, 521 .version = XTABLES_VERSION, 522 .family = NFPROTO_IPV4, 523 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)), 524 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)), 525 .help = set_target_help_v0, 526 .init = set_target_init_v0, 527 .parse = set_target_parse_v0, 528 .final_check = set_target_check_v0, 529 .print = set_target_print_v0, 530 .save = set_target_save_v0, 531 .extra_opts = set_target_opts_v0, 532 }, 533 { 534 .name = "SET", 535 .revision = 1, 536 .version = XTABLES_VERSION, 537 .family = NFPROTO_UNSPEC, 538 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v1)), 539 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v1)), 540 .help = set_target_help_v0, 541 .init = set_target_init_v1, 542 .parse = set_target_parse_v1, 543 .final_check = set_target_check_v0, 544 .print = set_target_print_v1, 545 .save = set_target_save_v1, 546 .extra_opts = set_target_opts_v0, 547 }, 548 { 549 .name = "SET", 550 .revision = 2, 551 .version = XTABLES_VERSION, 552 .family = NFPROTO_UNSPEC, 553 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v2)), 554 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v2)), 555 .help = set_target_help_v2, 556 .init = set_target_init_v2, 557 .parse = set_target_parse_v2, 558 .final_check = set_target_check_v2, 559 .print = set_target_print_v2, 560 .save = set_target_save_v2, 561 .extra_opts = set_target_opts_v2, 562 }, 563 { 564 .name = "SET", 565 .revision = 3, 566 .version = XTABLES_VERSION, 567 .family = NFPROTO_UNSPEC, 568 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v3)), 569 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v3)), 570 .help = set_target_help_v3, 571 .init = set_target_init_v3, 572 .parse = set_target_parse_v3, 573 .final_check = set_target_check_v3, 574 .print = set_target_print_v3, 575 .save = set_target_save_v3, 576 .extra_opts = set_target_opts_v3, 577 }, 578 }; 579 580 void _init(void) 581 { 582 xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg)); 583 } 584