libxt_CONNMARK.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
1/* Shared library add-on to iptables to add CONNMARK target support. 2 * 3 * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> 4 * by Henrik Nordstrom <hno@marasystems.com> 5 * 6 * Version 1.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22#include <stdbool.h> 23#include <stdio.h> 24#include <string.h> 25#include <stdlib.h> 26#include <getopt.h> 27 28#include <xtables.h> 29#include <linux/netfilter/x_tables.h> 30#include <linux/netfilter/xt_CONNMARK.h> 31 32struct xt_connmark_target_info { 33 unsigned long mark; 34 unsigned long mask; 35 uint8_t mode; 36}; 37 38enum { 39 F_MARK = 1 << 0, 40 F_SR_MARK = 1 << 1, 41}; 42 43static void CONNMARK_help(void) 44{ 45 printf( 46"CONNMARK target options:\n" 47" --set-mark value[/mask] Set conntrack mark value\n" 48" --save-mark [--mask mask] Save the packet nfmark in the connection\n" 49" --restore-mark [--mask mask] Restore saved nfmark value\n"); 50} 51 52static const struct option CONNMARK_opts[] = { 53 {.name = "set-mark", .has_arg = true, .val = '1'}, 54 {.name = "save-mark", .has_arg = false, .val = '2'}, 55 {.name = "restore-mark", .has_arg = false, .val = '3'}, 56 {.name = "mask", .has_arg = true, .val = '4'}, 57 XT_GETOPT_TABLEEND, 58}; 59 60static const struct option connmark_tg_opts[] = { 61 {.name = "set-xmark", .has_arg = true, .val = '='}, 62 {.name = "set-mark", .has_arg = true, .val = '-'}, 63 {.name = "and-mark", .has_arg = true, .val = '&'}, 64 {.name = "or-mark", .has_arg = true, .val = '|'}, 65 {.name = "xor-mark", .has_arg = true, .val = '^'}, 66 {.name = "save-mark", .has_arg = false, .val = 'S'}, 67 {.name = "restore-mark", .has_arg = false, .val = 'R'}, 68 {.name = "ctmask", .has_arg = true, .val = 'c'}, 69 {.name = "nfmask", .has_arg = true, .val = 'n'}, 70 {.name = "mask", .has_arg = true, .val = 'm'}, 71 XT_GETOPT_TABLEEND, 72}; 73 74static void connmark_tg_help(void) 75{ 76 printf( 77"CONNMARK target options:\n" 78" --set-xmark value[/ctmask] Zero mask bits and XOR ctmark with value\n" 79" --save-mark [--ctmask mask] [--nfmask mask]\n" 80" Copy ctmark to nfmark using masks\n" 81" --restore-mark [--ctmask mask] [--nfmask mask]\n" 82" Copy nfmark to ctmark using masks\n" 83" --set-mark value[/mask] Set conntrack mark value\n" 84" --save-mark [--mask mask] Save the packet nfmark in the connection\n" 85" --restore-mark [--mask mask] Restore saved nfmark value\n" 86" --and-mark value Binary AND the ctmark with bits\n" 87" --or-mark value Binary OR the ctmark with bits\n" 88" --xor-mark value Binary XOR the ctmark with bits\n" 89); 90} 91 92static void connmark_tg_init(struct xt_entry_target *target) 93{ 94 struct xt_connmark_tginfo1 *info = (void *)target->data; 95 96 /* 97 * Need these defaults for --save-mark/--restore-mark if no 98 * --ctmark or --nfmask is given. 99 */ 100 info->ctmask = UINT32_MAX; 101 info->nfmask = UINT32_MAX; 102} 103 104static int 105CONNMARK_parse(int c, char **argv, int invert, unsigned int *flags, 106 const void *entry, struct xt_entry_target **target) 107{ 108 struct xt_connmark_target_info *markinfo 109 = (struct xt_connmark_target_info *)(*target)->data; 110 111 switch (c) { 112 char *end; 113 case '1': 114 markinfo->mode = XT_CONNMARK_SET; 115 116 markinfo->mark = strtoul(optarg, &end, 0); 117 if (*end == '/' && end[1] != '\0') 118 markinfo->mask = strtoul(end+1, &end, 0); 119 120 if (*end != '\0' || end == optarg) 121 xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); 122 if (*flags) 123 xtables_error(PARAMETER_PROBLEM, 124 "CONNMARK target: Can't specify --set-mark twice"); 125 *flags = 1; 126 break; 127 case '2': 128 markinfo->mode = XT_CONNMARK_SAVE; 129 if (*flags) 130 xtables_error(PARAMETER_PROBLEM, 131 "CONNMARK target: Can't specify --save-mark twice"); 132 *flags = 1; 133 break; 134 case '3': 135 markinfo->mode = XT_CONNMARK_RESTORE; 136 if (*flags) 137 xtables_error(PARAMETER_PROBLEM, 138 "CONNMARK target: Can't specify --restore-mark twice"); 139 *flags = 1; 140 break; 141 case '4': 142 if (!*flags) 143 xtables_error(PARAMETER_PROBLEM, 144 "CONNMARK target: Can't specify --mask without a operation"); 145 markinfo->mask = strtoul(optarg, &end, 0); 146 147 if (*end != '\0' || end == optarg) 148 xtables_error(PARAMETER_PROBLEM, "Bad MASK value \"%s\"", optarg); 149 break; 150 } 151 152 return 1; 153} 154 155static int connmark_tg_parse(int c, char **argv, int invert, 156 unsigned int *flags, const void *entry, 157 struct xt_entry_target **target) 158{ 159 struct xt_connmark_tginfo1 *info = (void *)(*target)->data; 160 unsigned int value, mask = UINT32_MAX; 161 char *end; 162 163 switch (c) { 164 case '=': /* --set-xmark */ 165 case '-': /* --set-mark */ 166 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 167 if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX)) 168 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); 169 if (*end == '/') 170 if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 171 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); 172 if (*end != '\0') 173 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); 174 info->mode = XT_CONNMARK_SET; 175 info->ctmark = value; 176 info->ctmask = mask; 177 if (c == '-') 178 info->ctmask |= value; 179 *flags |= F_MARK; 180 return true; 181 182 case '&': /* --and-mark */ 183 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 184 if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX)) 185 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--and-mark", optarg); 186 info->mode = XT_CONNMARK_SET; 187 info->ctmark = 0; 188 info->ctmask = ~mask; 189 *flags |= F_MARK; 190 return true; 191 192 case '|': /* --or-mark */ 193 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 194 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 195 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--or-mark", optarg); 196 info->mode = XT_CONNMARK_SET; 197 info->ctmark = value; 198 info->ctmask = value; 199 *flags |= F_MARK; 200 return true; 201 202 case '^': /* --xor-mark */ 203 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 204 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 205 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--xor-mark", optarg); 206 info->mode = XT_CONNMARK_SET; 207 info->ctmark = value; 208 info->ctmask = 0; 209 *flags |= F_MARK; 210 return true; 211 212 case 'S': /* --save-mark */ 213 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 214 info->mode = XT_CONNMARK_SAVE; 215 *flags |= F_MARK | F_SR_MARK; 216 return true; 217 218 case 'R': /* --restore-mark */ 219 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 220 info->mode = XT_CONNMARK_RESTORE; 221 *flags |= F_MARK | F_SR_MARK; 222 return true; 223 224 case 'n': /* --nfmask */ 225 if (!(*flags & F_SR_MARK)) 226 xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " 227 "or --restore-mark is required for " 228 "--nfmask"); 229 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 230 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--nfmask", optarg); 231 info->nfmask = value; 232 return true; 233 234 case 'c': /* --ctmask */ 235 if (!(*flags & F_SR_MARK)) 236 xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " 237 "or --restore-mark is required for " 238 "--ctmask"); 239 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 240 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--ctmask", optarg); 241 info->ctmask = value; 242 return true; 243 244 case 'm': /* --mask */ 245 if (!(*flags & F_SR_MARK)) 246 xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " 247 "or --restore-mark is required for " 248 "--mask"); 249 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 250 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--mask", optarg); 251 info->nfmask = info->ctmask = value; 252 return true; 253 } 254 255 return false; 256} 257 258static void connmark_tg_check(unsigned int flags) 259{ 260 if (!flags) 261 xtables_error(PARAMETER_PROBLEM, 262 "CONNMARK target: No operation specified"); 263} 264 265static void 266print_mark(unsigned long mark) 267{ 268 printf("0x%lx", mark); 269} 270 271static void 272print_mask(const char *text, unsigned long mask) 273{ 274 if (mask != 0xffffffffUL) 275 printf("%s0x%lx", text, mask); 276} 277 278static void CONNMARK_print(const void *ip, 279 const struct xt_entry_target *target, int numeric) 280{ 281 const struct xt_connmark_target_info *markinfo = 282 (const struct xt_connmark_target_info *)target->data; 283 switch (markinfo->mode) { 284 case XT_CONNMARK_SET: 285 printf(" CONNMARK set "); 286 print_mark(markinfo->mark); 287 print_mask("/", markinfo->mask); 288 break; 289 case XT_CONNMARK_SAVE: 290 printf(" CONNMARK save "); 291 print_mask("mask ", markinfo->mask); 292 break; 293 case XT_CONNMARK_RESTORE: 294 printf(" CONNMARK restore "); 295 print_mask("mask ", markinfo->mask); 296 break; 297 default: 298 printf(" ERROR: UNKNOWN CONNMARK MODE"); 299 break; 300 } 301} 302 303static void 304connmark_tg_print(const void *ip, const struct xt_entry_target *target, 305 int numeric) 306{ 307 const struct xt_connmark_tginfo1 *info = (const void *)target->data; 308 309 switch (info->mode) { 310 case XT_CONNMARK_SET: 311 if (info->ctmark == 0) 312 printf(" CONNMARK and 0x%x", 313 (unsigned int)(uint32_t)~info->ctmask); 314 else if (info->ctmark == info->ctmask) 315 printf(" CONNMARK or 0x%x", info->ctmark); 316 else if (info->ctmask == 0) 317 printf(" CONNMARK xor 0x%x", info->ctmark); 318 else if (info->ctmask == 0xFFFFFFFFU) 319 printf(" CONNMARK set 0x%x", info->ctmark); 320 else 321 printf(" CONNMARK xset 0x%x/0x%x", 322 info->ctmark, info->ctmask); 323 break; 324 case XT_CONNMARK_SAVE: 325 if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX) 326 printf(" CONNMARK save"); 327 else if (info->nfmask == info->ctmask) 328 printf(" CONNMARK save mask 0x%x", info->nfmask); 329 else 330 printf(" CONNMARK save nfmask 0x%x ctmask ~0x%x", 331 info->nfmask, info->ctmask); 332 break; 333 case XT_CONNMARK_RESTORE: 334 if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX) 335 printf(" CONNMARK restore"); 336 else if (info->ctmask == info->nfmask) 337 printf(" CONNMARK restore mask 0x%x", info->ctmask); 338 else 339 printf(" CONNMARK restore ctmask 0x%x nfmask ~0x%x", 340 info->ctmask, info->nfmask); 341 break; 342 343 default: 344 printf(" ERROR: UNKNOWN CONNMARK MODE"); 345 break; 346 } 347} 348 349static void CONNMARK_save(const void *ip, const struct xt_entry_target *target) 350{ 351 const struct xt_connmark_target_info *markinfo = 352 (const struct xt_connmark_target_info *)target->data; 353 354 switch (markinfo->mode) { 355 case XT_CONNMARK_SET: 356 printf(" --set-mark "); 357 print_mark(markinfo->mark); 358 print_mask("/", markinfo->mask); 359 break; 360 case XT_CONNMARK_SAVE: 361 printf(" --save-mark "); 362 print_mask("--mask ", markinfo->mask); 363 break; 364 case XT_CONNMARK_RESTORE: 365 printf(" --restore-mark "); 366 print_mask("--mask ", markinfo->mask); 367 break; 368 default: 369 printf(" ERROR: UNKNOWN CONNMARK MODE"); 370 break; 371 } 372} 373 374static void CONNMARK_init(struct xt_entry_target *t) 375{ 376 struct xt_connmark_target_info *markinfo 377 = (struct xt_connmark_target_info *)t->data; 378 379 markinfo->mask = 0xffffffffUL; 380} 381 382static void 383connmark_tg_save(const void *ip, const struct xt_entry_target *target) 384{ 385 const struct xt_connmark_tginfo1 *info = (const void *)target->data; 386 387 switch (info->mode) { 388 case XT_CONNMARK_SET: 389 printf(" --set-xmark 0x%x/0x%x", info->ctmark, info->ctmask); 390 break; 391 case XT_CONNMARK_SAVE: 392 printf(" --save-mark --nfmask 0x%x --ctmask 0x%x", 393 info->nfmask, info->ctmask); 394 break; 395 case XT_CONNMARK_RESTORE: 396 printf(" --restore-mark --nfmask 0x%x --ctmask 0x%x", 397 info->nfmask, info->ctmask); 398 break; 399 default: 400 printf(" ERROR: UNKNOWN CONNMARK MODE"); 401 break; 402 } 403} 404 405static struct xtables_target connmark_tg_reg[] = { 406 { 407 .family = NFPROTO_UNSPEC, 408 .name = "CONNMARK", 409 .revision = 0, 410 .version = XTABLES_VERSION, 411 .size = XT_ALIGN(sizeof(struct xt_connmark_target_info)), 412 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)), 413 .help = CONNMARK_help, 414 .init = CONNMARK_init, 415 .parse = CONNMARK_parse, 416 .final_check = connmark_tg_check, 417 .print = CONNMARK_print, 418 .save = CONNMARK_save, 419 .extra_opts = CONNMARK_opts, 420 }, 421 { 422 .version = XTABLES_VERSION, 423 .name = "CONNMARK", 424 .revision = 1, 425 .family = NFPROTO_UNSPEC, 426 .size = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), 427 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), 428 .help = connmark_tg_help, 429 .init = connmark_tg_init, 430 .parse = connmark_tg_parse, 431 .final_check = connmark_tg_check, 432 .print = connmark_tg_print, 433 .save = connmark_tg_save, 434 .extra_opts = connmark_tg_opts, 435 }, 436}; 437 438void _init(void) 439{ 440 xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg)); 441} 442