libxt_SET.c revision fbe9f1ecccb5ac02858fa7eee2979e0e4d97bb5f
1/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> 2 * Patrick Schaaf <bof@bof.de> 3 * Martin Josefsson <gandalf@wlug.westbo.se> 4 * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@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 26static void 27set_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 37static 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 43static void 44set_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 51static void 52set_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 62static void 63parse_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 87static int 88set_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 107static void 108print_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 126static void 127set_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 136static void 137set_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 147#define set_target_help_v1 set_target_help_v0 148 149static void 150set_target_init_v1(struct xt_entry_target *target) 151{ 152 struct xt_set_info_target_v1 *info = 153 (struct xt_set_info_target_v1 *) target->data; 154 155 info->add_set.index = 156 info->del_set.index = IPSET_INVALID_ID; 157 158} 159 160#define SET_TARGET_ADD 0x1 161#define SET_TARGET_DEL 0x2 162#define SET_TARGET_EXIST 0x4 163#define SET_TARGET_TIMEOUT 0x8 164 165static void 166parse_target(char **argv, int invert, struct xt_set_info *info, 167 const char *what) 168{ 169 if (info->dim) 170 xtables_error(PARAMETER_PROBLEM, 171 "--%s can be specified only once", what); 172 if (!argv[optind] 173 || argv[optind][0] == '-' || argv[optind][0] == '!') 174 xtables_error(PARAMETER_PROBLEM, 175 "--%s requires two args.", what); 176 177 if (strlen(optarg) > IPSET_MAXNAMELEN - 1) 178 xtables_error(PARAMETER_PROBLEM, 179 "setname `%s' too long, max %d characters.", 180 optarg, IPSET_MAXNAMELEN - 1); 181 182 get_set_byname(optarg, info); 183 parse_dirs(argv[optind], info); 184 optind++; 185} 186 187static int 188set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags, 189 const void *entry, struct xt_entry_target **target) 190{ 191 struct xt_set_info_target_v1 *myinfo = 192 (struct xt_set_info_target_v1 *) (*target)->data; 193 194 switch (c) { 195 case '1': /* --add-set <set> <flags> */ 196 parse_target(argv, invert, &myinfo->add_set, "add-set"); 197 *flags |= SET_TARGET_ADD; 198 break; 199 case '2': /* --del-set <set>[:<flags>] <flags> */ 200 parse_target(argv, invert, &myinfo->del_set, "del-set"); 201 *flags |= SET_TARGET_DEL; 202 break; 203 } 204 return 1; 205} 206 207#define set_target_check_v1 set_target_check_v0 208 209static void 210print_target(const char *prefix, const struct xt_set_info *info) 211{ 212 int i; 213 char setname[IPSET_MAXNAMELEN]; 214 215 if (info->index == IPSET_INVALID_ID) 216 return; 217 get_set_byid(setname, info->index); 218 printf(" %s %s", prefix, setname); 219 for (i = 1; i <= info->dim; i++) { 220 printf("%s%s", 221 i == 1 ? " " : ",", 222 info->flags & (1 << i) ? "src" : "dst"); 223 } 224} 225 226static void 227set_target_print_v1(const void *ip, const struct xt_entry_target *target, 228 int numeric) 229{ 230 const struct xt_set_info_target_v1 *info = (const void *)target->data; 231 232 print_target("add-set", &info->add_set); 233 print_target("del-set", &info->del_set); 234} 235 236static void 237set_target_save_v1(const void *ip, const struct xt_entry_target *target) 238{ 239 const struct xt_set_info_target_v1 *info = (const void *)target->data; 240 241 print_target("--add-set", &info->add_set); 242 print_target("--del-set", &info->del_set); 243} 244 245#define set_target_opts_v1 set_target_opts_v0 246 247/* Revision 2 */ 248 249static void 250set_target_help_v2(void) 251{ 252 printf("SET target options:\n" 253 " --add-set name flags [--exist] [--timeout n]\n" 254 " --del-set name flags\n" 255 " add/del src/dst IP/port from/to named sets,\n" 256 " where flags are the comma separated list of\n" 257 " 'src' and 'dst' specifications.\n"); 258} 259 260static const struct option set_target_opts_v2[] = { 261 {.name = "add-set", .has_arg = true, .val = '1'}, 262 {.name = "del-set", .has_arg = true, .val = '2'}, 263 {.name = "exist", .has_arg = false, .val = '3'}, 264 {.name = "timeout", .has_arg = true, .val = '4'}, 265 XT_GETOPT_TABLEEND, 266}; 267 268static void 269set_target_check_v2(unsigned int flags) 270{ 271 if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL))) 272 xtables_error(PARAMETER_PROBLEM, 273 "You must specify either `--add-set' or `--del-set'"); 274 if (!(flags & SET_TARGET_ADD)) { 275 if (flags & SET_TARGET_EXIST) 276 xtables_error(PARAMETER_PROBLEM, 277 "Flag `--exist' can be used with `--add-set' only"); 278 if (flags & SET_TARGET_TIMEOUT) 279 xtables_error(PARAMETER_PROBLEM, 280 "Option `--timeout' can be used with `--add-set' only"); 281 } 282} 283 284 285static void 286set_target_init_v2(struct xt_entry_target *target) 287{ 288 struct xt_set_info_target_v2 *info = 289 (struct xt_set_info_target_v2 *) target->data; 290 291 info->add_set.index = 292 info->del_set.index = IPSET_INVALID_ID; 293 info->timeout = UINT32_MAX; 294} 295 296static int 297set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags, 298 const void *entry, struct xt_entry_target **target) 299{ 300 struct xt_set_info_target_v2 *myinfo = 301 (struct xt_set_info_target_v2 *) (*target)->data; 302 unsigned int timeout; 303 304 switch (c) { 305 case '1': /* --add-set <set> <flags> */ 306 parse_target(argv, invert, &myinfo->add_set, "add-set"); 307 *flags |= SET_TARGET_ADD; 308 break; 309 case '2': /* --del-set <set>[:<flags>] <flags> */ 310 parse_target(argv, invert, &myinfo->del_set, "del-set"); 311 *flags |= SET_TARGET_DEL; 312 break; 313 case '3': 314 myinfo->flags |= IPSET_FLAG_EXIST; 315 *flags |= SET_TARGET_EXIST; 316 break; 317 case '4': 318 if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1)) 319 xtables_error(PARAMETER_PROBLEM, 320 "Invalid value for option --timeout " 321 "or out of range 0-%u", UINT32_MAX - 1); 322 myinfo->timeout = timeout; 323 *flags |= SET_TARGET_TIMEOUT; 324 break; 325 } 326 return 1; 327} 328 329static void 330set_target_print_v2(const void *ip, const struct xt_entry_target *target, 331 int numeric) 332{ 333 const struct xt_set_info_target_v2 *info = (const void *)target->data; 334 335 print_target("add-set", &info->add_set); 336 if (info->flags & IPSET_FLAG_EXIST) 337 printf(" exist"); 338 if (info->timeout != UINT32_MAX) 339 printf(" timeout %u", info->timeout); 340 print_target("del-set", &info->del_set); 341} 342 343static void 344set_target_save_v2(const void *ip, const struct xt_entry_target *target) 345{ 346 const struct xt_set_info_target_v2 *info = (const void *)target->data; 347 348 print_target("--add-set", &info->add_set); 349 if (info->flags & IPSET_FLAG_EXIST) 350 printf(" --exist"); 351 if (info->timeout != UINT32_MAX) 352 printf(" --timeout %u", info->timeout); 353 print_target("--del-set", &info->del_set); 354} 355 356static struct xtables_target set_tg_reg[] = { 357 { 358 .name = "SET", 359 .revision = 0, 360 .version = XTABLES_VERSION, 361 .family = NFPROTO_IPV4, 362 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)), 363 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)), 364 .help = set_target_help_v0, 365 .init = set_target_init_v0, 366 .parse = set_target_parse_v0, 367 .final_check = set_target_check_v0, 368 .print = set_target_print_v0, 369 .save = set_target_save_v0, 370 .extra_opts = set_target_opts_v0, 371 }, 372 { 373 .name = "SET", 374 .revision = 1, 375 .version = XTABLES_VERSION, 376 .family = NFPROTO_UNSPEC, 377 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v1)), 378 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v1)), 379 .help = set_target_help_v1, 380 .init = set_target_init_v1, 381 .parse = set_target_parse_v1, 382 .final_check = set_target_check_v1, 383 .print = set_target_print_v1, 384 .save = set_target_save_v1, 385 .extra_opts = set_target_opts_v1, 386 }, 387 { 388 .name = "SET", 389 .revision = 2, 390 .version = XTABLES_VERSION, 391 .family = NFPROTO_UNSPEC, 392 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v2)), 393 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v2)), 394 .help = set_target_help_v2, 395 .init = set_target_init_v2, 396 .parse = set_target_parse_v2, 397 .final_check = set_target_check_v2, 398 .print = set_target_print_v2, 399 .save = set_target_save_v2, 400 .extra_opts = set_target_opts_v2, 401 }, 402}; 403 404void _init(void) 405{ 406 xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg)); 407} 408