libxt_CONNMARK.c revision 7ac405297ec38449b30e3b05fd6bf2082fd3d803
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 default: 151 return 0; 152 } 153 154 return 1; 155} 156 157static int connmark_tg_parse(int c, char **argv, int invert, 158 unsigned int *flags, const void *entry, 159 struct xt_entry_target **target) 160{ 161 struct xt_connmark_tginfo1 *info = (void *)(*target)->data; 162 unsigned int value, mask = UINT32_MAX; 163 char *end; 164 165 switch (c) { 166 case '=': /* --set-xmark */ 167 case '-': /* --set-mark */ 168 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 169 if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX)) 170 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); 171 if (*end == '/') 172 if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 173 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); 174 if (*end != '\0') 175 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); 176 info->mode = XT_CONNMARK_SET; 177 info->ctmark = value; 178 info->ctmask = mask; 179 if (c == '-') 180 info->ctmask |= value; 181 *flags |= F_MARK; 182 return true; 183 184 case '&': /* --and-mark */ 185 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 186 if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX)) 187 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--and-mark", optarg); 188 info->mode = XT_CONNMARK_SET; 189 info->ctmark = 0; 190 info->ctmask = ~mask; 191 *flags |= F_MARK; 192 return true; 193 194 case '|': /* --or-mark */ 195 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 196 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 197 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--or-mark", optarg); 198 info->mode = XT_CONNMARK_SET; 199 info->ctmark = value; 200 info->ctmask = value; 201 *flags |= F_MARK; 202 return true; 203 204 case '^': /* --xor-mark */ 205 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 206 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 207 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--xor-mark", optarg); 208 info->mode = XT_CONNMARK_SET; 209 info->ctmark = value; 210 info->ctmask = 0; 211 *flags |= F_MARK; 212 return true; 213 214 case 'S': /* --save-mark */ 215 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 216 info->mode = XT_CONNMARK_SAVE; 217 *flags |= F_MARK | F_SR_MARK; 218 return true; 219 220 case 'R': /* --restore-mark */ 221 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); 222 info->mode = XT_CONNMARK_RESTORE; 223 *flags |= F_MARK | F_SR_MARK; 224 return true; 225 226 case 'n': /* --nfmask */ 227 if (!(*flags & F_SR_MARK)) 228 xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " 229 "or --restore-mark is required for " 230 "--nfmask"); 231 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 232 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--nfmask", optarg); 233 info->nfmask = value; 234 return true; 235 236 case 'c': /* --ctmask */ 237 if (!(*flags & F_SR_MARK)) 238 xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " 239 "or --restore-mark is required for " 240 "--ctmask"); 241 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 242 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--ctmask", optarg); 243 info->ctmask = value; 244 return true; 245 246 case 'm': /* --mask */ 247 if (!(*flags & F_SR_MARK)) 248 xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " 249 "or --restore-mark is required for " 250 "--mask"); 251 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 252 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--mask", optarg); 253 info->nfmask = info->ctmask = value; 254 return true; 255 } 256 257 return false; 258} 259 260static void connmark_tg_check(unsigned int flags) 261{ 262 if (!flags) 263 xtables_error(PARAMETER_PROBLEM, 264 "CONNMARK target: No operation specified"); 265} 266 267static void 268print_mark(unsigned long mark) 269{ 270 printf("0x%lx", mark); 271} 272 273static void 274print_mask(const char *text, unsigned long mask) 275{ 276 if (mask != 0xffffffffUL) 277 printf("%s0x%lx", text, mask); 278} 279 280static void CONNMARK_print(const void *ip, 281 const struct xt_entry_target *target, int numeric) 282{ 283 const struct xt_connmark_target_info *markinfo = 284 (const struct xt_connmark_target_info *)target->data; 285 switch (markinfo->mode) { 286 case XT_CONNMARK_SET: 287 printf("CONNMARK set "); 288 print_mark(markinfo->mark); 289 print_mask("/", markinfo->mask); 290 printf(" "); 291 break; 292 case XT_CONNMARK_SAVE: 293 printf("CONNMARK save "); 294 print_mask("mask ", markinfo->mask); 295 printf(" "); 296 break; 297 case XT_CONNMARK_RESTORE: 298 printf("CONNMARK restore "); 299 print_mask("mask ", markinfo->mask); 300 break; 301 default: 302 printf("ERROR: UNKNOWN CONNMARK MODE "); 303 break; 304 } 305} 306 307static void 308connmark_tg_print(const void *ip, const struct xt_entry_target *target, 309 int numeric) 310{ 311 const struct xt_connmark_tginfo1 *info = (const void *)target->data; 312 313 switch (info->mode) { 314 case XT_CONNMARK_SET: 315 if (info->ctmark == 0) 316 printf("CONNMARK and 0x%x ", 317 (unsigned int)(uint32_t)~info->ctmask); 318 else if (info->ctmark == info->ctmask) 319 printf("CONNMARK or 0x%x ", info->ctmark); 320 else if (info->ctmask == 0) 321 printf("CONNMARK xor 0x%x ", info->ctmark); 322 else if (info->ctmask == 0xFFFFFFFFU) 323 printf("CONNMARK set 0x%x ", info->ctmark); 324 else 325 printf("CONNMARK xset 0x%x/0x%x ", 326 info->ctmark, info->ctmask); 327 break; 328 case XT_CONNMARK_SAVE: 329 if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX) 330 printf("CONNMARK save "); 331 else if (info->nfmask == info->ctmask) 332 printf("CONNMARK save mask 0x%x ", info->nfmask); 333 else 334 printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ", 335 info->nfmask, info->ctmask); 336 break; 337 case XT_CONNMARK_RESTORE: 338 if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX) 339 printf("CONNMARK restore "); 340 else if (info->ctmask == info->nfmask) 341 printf("CONNMARK restore mask 0x%x ", info->ctmask); 342 else 343 printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ", 344 info->ctmask, info->nfmask); 345 break; 346 347 default: 348 printf("ERROR: UNKNOWN CONNMARK MODE"); 349 break; 350 } 351} 352 353static void CONNMARK_save(const void *ip, const struct xt_entry_target *target) 354{ 355 const struct xt_connmark_target_info *markinfo = 356 (const struct xt_connmark_target_info *)target->data; 357 358 switch (markinfo->mode) { 359 case XT_CONNMARK_SET: 360 printf("--set-mark "); 361 print_mark(markinfo->mark); 362 print_mask("/", markinfo->mask); 363 printf(" "); 364 break; 365 case XT_CONNMARK_SAVE: 366 printf("--save-mark "); 367 print_mask("--mask ", markinfo->mask); 368 break; 369 case XT_CONNMARK_RESTORE: 370 printf("--restore-mark "); 371 print_mask("--mask ", markinfo->mask); 372 break; 373 default: 374 printf("ERROR: UNKNOWN CONNMARK MODE "); 375 break; 376 } 377} 378 379static void CONNMARK_init(struct xt_entry_target *t) 380{ 381 struct xt_connmark_target_info *markinfo 382 = (struct xt_connmark_target_info *)t->data; 383 384 markinfo->mask = 0xffffffffUL; 385} 386 387static void 388connmark_tg_save(const void *ip, const struct xt_entry_target *target) 389{ 390 const struct xt_connmark_tginfo1 *info = (const void *)target->data; 391 392 switch (info->mode) { 393 case XT_CONNMARK_SET: 394 printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask); 395 break; 396 case XT_CONNMARK_SAVE: 397 printf("--save-mark --nfmask 0x%x --ctmask 0x%x ", 398 info->nfmask, info->ctmask); 399 break; 400 case XT_CONNMARK_RESTORE: 401 printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ", 402 info->nfmask, info->ctmask); 403 break; 404 default: 405 printf("ERROR: UNKNOWN CONNMARK MODE"); 406 break; 407 } 408} 409 410static struct xtables_target connmark_tg_reg[] = { 411 { 412 .family = NFPROTO_UNSPEC, 413 .name = "CONNMARK", 414 .revision = 0, 415 .version = XTABLES_VERSION, 416 .size = XT_ALIGN(sizeof(struct xt_connmark_target_info)), 417 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)), 418 .help = CONNMARK_help, 419 .init = CONNMARK_init, 420 .parse = CONNMARK_parse, 421 .final_check = connmark_tg_check, 422 .print = CONNMARK_print, 423 .save = CONNMARK_save, 424 .extra_opts = CONNMARK_opts, 425 }, 426 { 427 .version = XTABLES_VERSION, 428 .name = "CONNMARK", 429 .revision = 1, 430 .family = NFPROTO_UNSPEC, 431 .size = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), 432 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), 433 .help = connmark_tg_help, 434 .init = connmark_tg_init, 435 .parse = connmark_tg_parse, 436 .final_check = connmark_tg_check, 437 .print = connmark_tg_print, 438 .save = connmark_tg_save, 439 .extra_opts = connmark_tg_opts, 440 }, 441}; 442 443void _init(void) 444{ 445 xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg)); 446} 447