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 <stdint.h> 24#include <stdio.h> 25#include <xtables.h> 26#include <linux/netfilter/xt_CONNMARK.h> 27 28struct xt_connmark_target_info { 29 unsigned long mark; 30 unsigned long mask; 31 uint8_t mode; 32}; 33 34enum { 35 O_SET_MARK = 0, 36 O_SAVE_MARK, 37 O_SET_RETURN, 38 O_RESTORE_MARK, 39 O_AND_MARK, 40 O_OR_MARK, 41 O_XOR_MARK, 42 O_SET_XMARK, 43 O_CTMASK, 44 O_NFMASK, 45 O_MASK, 46 F_SET_MARK = 1 << O_SET_MARK, 47 F_SAVE_MARK = 1 << O_SAVE_MARK, 48 F_SET_RETURN = 1 << O_SET_RETURN, 49 F_RESTORE_MARK = 1 << O_RESTORE_MARK, 50 F_AND_MARK = 1 << O_AND_MARK, 51 F_OR_MARK = 1 << O_OR_MARK, 52 F_XOR_MARK = 1 << O_XOR_MARK, 53 F_SET_XMARK = 1 << O_SET_XMARK, 54 F_CTMASK = 1 << O_CTMASK, 55 F_NFMASK = 1 << O_NFMASK, 56 F_MASK = 1 << O_MASK, 57 F_OP_ANY = F_SET_MARK | F_SAVE_MARK | F_SET_RETURN | F_RESTORE_MARK | 58 F_AND_MARK | F_OR_MARK | F_XOR_MARK | F_SET_XMARK, 59}; 60 61static void CONNMARK_help(void) 62{ 63 printf( 64"CONNMARK target options:\n" 65" --set-mark value[/mask] Set conntrack mark value\n" 66" --set-return [--mask mask] Set conntrack mark & nfmark, RETURN\n" 67" --save-mark [--mask mask] Save the packet nfmark in the connection\n" 68" --restore-mark [--mask mask] Restore saved nfmark value\n"); 69} 70 71#define s struct xt_connmark_target_info 72static const struct xt_option_entry CONNMARK_opts[] = { 73 {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32, 74 .excl = F_OP_ANY}, 75 {.name = "save-mark", .id = O_SAVE_MARK, .type = XTTYPE_NONE, 76 .excl = F_OP_ANY}, 77 {.name = "set-return", .id = O_SET_RETURN, .type = XTTYPE_MARKMASK32, 78 .excl = F_OP_ANY}, 79 {.name = "restore-mark", .id = O_RESTORE_MARK, .type = XTTYPE_NONE, 80 .excl = F_OP_ANY}, 81 {.name = "mask", .id = O_MASK, .type = XTTYPE_UINT32}, 82 XTOPT_TABLEEND, 83}; 84#undef s 85 86#define s struct xt_connmark_tginfo1 87static const struct xt_option_entry connmark_tg_opts[] = { 88 {.name = "set-xmark", .id = O_SET_XMARK, .type = XTTYPE_MARKMASK32, 89 .excl = F_OP_ANY}, 90 {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32, 91 .excl = F_OP_ANY}, 92 {.name = "set-return", .id = O_SET_RETURN, .type = XTTYPE_MARKMASK32, 93 .excl = F_OP_ANY}, 94 {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32, 95 .excl = F_OP_ANY}, 96 {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32, 97 .excl = F_OP_ANY}, 98 {.name = "xor-mark", .id = O_XOR_MARK, .type = XTTYPE_UINT32, 99 .excl = F_OP_ANY}, 100 {.name = "save-mark", .id = O_SAVE_MARK, .type = XTTYPE_NONE, 101 .excl = F_OP_ANY}, 102 {.name = "restore-mark", .id = O_RESTORE_MARK, .type = XTTYPE_NONE, 103 .excl = F_OP_ANY}, 104 {.name = "ctmask", .id = O_CTMASK, .type = XTTYPE_UINT32, 105 .excl = F_MASK, .flags = XTOPT_PUT, XTOPT_POINTER(s, ctmask)}, 106 {.name = "nfmask", .id = O_NFMASK, .type = XTTYPE_UINT32, 107 .excl = F_MASK, .flags = XTOPT_PUT, XTOPT_POINTER(s, nfmask)}, 108 {.name = "mask", .id = O_MASK, .type = XTTYPE_UINT32, 109 .excl = F_CTMASK | F_NFMASK}, 110 XTOPT_TABLEEND, 111}; 112#undef s 113 114static void connmark_tg_help(void) 115{ 116 printf( 117"CONNMARK target options:\n" 118" --set-xmark value[/ctmask] Zero mask bits and XOR ctmark with value\n" 119" --save-mark [--ctmask mask] [--nfmask mask]\n" 120" Copy ctmark to nfmark using masks\n" 121" --restore-mark [--ctmask mask] [--nfmask mask]\n" 122" Copy nfmark to ctmark using masks\n" 123" --set-mark value[/mask] Set conntrack mark value\n" 124" --set-return value[/mask] Set conntrack mark & nfmark, RETURN\n" 125" --save-mark [--mask mask] Save the packet nfmark in the connection\n" 126" --restore-mark [--mask mask] Restore saved nfmark value\n" 127" --and-mark value Binary AND the ctmark with bits\n" 128" --or-mark value Binary OR the ctmark with bits\n" 129" --xor-mark value Binary XOR the ctmark with bits\n" 130); 131} 132 133static void connmark_tg_init(struct xt_entry_target *target) 134{ 135 struct xt_connmark_tginfo1 *info = (void *)target->data; 136 137 /* 138 * Need these defaults for --save-mark/--restore-mark if no 139 * --ctmark or --nfmask is given. 140 */ 141 info->ctmask = UINT32_MAX; 142 info->nfmask = UINT32_MAX; 143} 144 145static void CONNMARK_parse(struct xt_option_call *cb) 146{ 147 struct xt_connmark_target_info *markinfo = cb->data; 148 149 xtables_option_parse(cb); 150 switch (cb->entry->id) { 151 case O_SET_MARK: 152 markinfo->mode = XT_CONNMARK_SET; 153 markinfo->mark = cb->val.mark; 154 markinfo->mask = cb->val.mask; 155 break; 156 case O_SET_RETURN: 157 markinfo->mode = XT_CONNMARK_SET_RETURN; 158 markinfo->mark = cb->val.mark; 159 markinfo->mask = cb->val.mask; 160 break; 161 case O_SAVE_MARK: 162 markinfo->mode = XT_CONNMARK_SAVE; 163 break; 164 case O_RESTORE_MARK: 165 markinfo->mode = XT_CONNMARK_RESTORE; 166 break; 167 case O_MASK: 168 markinfo->mask = cb->val.u32; 169 break; 170 } 171} 172 173static void connmark_tg_parse(struct xt_option_call *cb) 174{ 175 struct xt_connmark_tginfo1 *info = cb->data; 176 177 xtables_option_parse(cb); 178 switch (cb->entry->id) { 179 case O_SET_XMARK: 180 info->mode = XT_CONNMARK_SET; 181 info->ctmark = cb->val.mark; 182 info->ctmask = cb->val.mask; 183 break; 184 case O_SET_MARK: 185 info->mode = XT_CONNMARK_SET; 186 info->ctmark = cb->val.mark; 187 info->ctmask = cb->val.mark | cb->val.mask; 188 break; 189 case O_SET_RETURN: 190 info->mode = XT_CONNMARK_SET_RETURN; 191 info->ctmark = cb->val.mark; 192 info->ctmask = cb->val.mask; 193 break; 194 case O_AND_MARK: 195 info->mode = XT_CONNMARK_SET; 196 info->ctmark = 0; 197 info->ctmask = ~cb->val.u32; 198 break; 199 case O_OR_MARK: 200 info->mode = XT_CONNMARK_SET; 201 info->ctmark = cb->val.u32; 202 info->ctmask = cb->val.u32; 203 break; 204 case O_XOR_MARK: 205 info->mode = XT_CONNMARK_SET; 206 info->ctmark = cb->val.u32; 207 info->ctmask = 0; 208 break; 209 case O_SAVE_MARK: 210 info->mode = XT_CONNMARK_SAVE; 211 break; 212 case O_RESTORE_MARK: 213 info->mode = XT_CONNMARK_RESTORE; 214 break; 215 case O_MASK: 216 info->nfmask = info->ctmask = cb->val.u32; 217 break; 218 } 219} 220 221static void connmark_tg_check(struct xt_fcheck_call *cb) 222{ 223 if (!(cb->xflags & F_OP_ANY)) 224 xtables_error(PARAMETER_PROBLEM, 225 "CONNMARK target: No operation specified"); 226} 227 228static void 229print_mark(unsigned long mark) 230{ 231 printf("0x%lx", mark); 232} 233 234static void 235print_mask(const char *text, unsigned long mask) 236{ 237 if (mask != 0xffffffffUL) 238 printf("%s0x%lx", text, mask); 239} 240 241static void CONNMARK_print(const void *ip, 242 const struct xt_entry_target *target, int numeric) 243{ 244 const struct xt_connmark_target_info *markinfo = 245 (const struct xt_connmark_target_info *)target->data; 246 switch (markinfo->mode) { 247 case XT_CONNMARK_SET: 248 printf(" CONNMARK set "); 249 print_mark(markinfo->mark); 250 print_mask("/", markinfo->mask); 251 break; 252 case XT_CONNMARK_SET_RETURN: 253 printf(" CONNMARK set-return "); 254 print_mark(markinfo->mark); 255 print_mask("/", markinfo->mask); 256 break; 257 case XT_CONNMARK_SAVE: 258 printf(" CONNMARK save "); 259 print_mask("mask ", markinfo->mask); 260 break; 261 case XT_CONNMARK_RESTORE: 262 printf(" CONNMARK restore "); 263 print_mask("mask ", markinfo->mask); 264 break; 265 default: 266 printf(" ERROR: UNKNOWN CONNMARK MODE"); 267 break; 268 } 269} 270 271static void 272connmark_tg_print(const void *ip, const struct xt_entry_target *target, 273 int numeric) 274{ 275 const struct xt_connmark_tginfo1 *info = (const void *)target->data; 276 277 switch (info->mode) { 278 case XT_CONNMARK_SET: 279 if (info->ctmark == 0) 280 printf(" CONNMARK and 0x%x", 281 (unsigned int)(uint32_t)~info->ctmask); 282 else if (info->ctmark == info->ctmask) 283 printf(" CONNMARK or 0x%x", info->ctmark); 284 else if (info->ctmask == 0) 285 printf(" CONNMARK xor 0x%x", info->ctmark); 286 else if (info->ctmask == 0xFFFFFFFFU) 287 printf(" CONNMARK set 0x%x", info->ctmark); 288 else 289 printf(" CONNMARK xset 0x%x/0x%x", 290 info->ctmark, info->ctmask); 291 break; 292 case XT_CONNMARK_SET_RETURN: 293 if (info->ctmask == 0xFFFFFFFFU) 294 printf(" CONNMARK set-return 0x%x", info->ctmark); 295 else 296 printf(" CONNMARK set-return 0x%x/0x%x", 297 info->ctmark, info->ctmask); 298 break; 299 case XT_CONNMARK_SAVE: 300 if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX) 301 printf(" CONNMARK save"); 302 else if (info->nfmask == info->ctmask) 303 printf(" CONNMARK save mask 0x%x", info->nfmask); 304 else 305 printf(" CONNMARK save nfmask 0x%x ctmask ~0x%x", 306 info->nfmask, info->ctmask); 307 break; 308 case XT_CONNMARK_RESTORE: 309 if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX) 310 printf(" CONNMARK restore"); 311 else if (info->ctmask == info->nfmask) 312 printf(" CONNMARK restore mask 0x%x", info->ctmask); 313 else 314 printf(" CONNMARK restore ctmask 0x%x nfmask ~0x%x", 315 info->ctmask, info->nfmask); 316 break; 317 318 default: 319 printf(" ERROR: UNKNOWN CONNMARK MODE"); 320 break; 321 } 322} 323 324static void CONNMARK_save(const void *ip, const struct xt_entry_target *target) 325{ 326 const struct xt_connmark_target_info *markinfo = 327 (const struct xt_connmark_target_info *)target->data; 328 329 switch (markinfo->mode) { 330 case XT_CONNMARK_SET: 331 printf(" --set-mark "); 332 print_mark(markinfo->mark); 333 print_mask("/", markinfo->mask); 334 break; 335 case XT_CONNMARK_SET_RETURN: 336 printf(" --set-return "); 337 print_mark(markinfo->mark); 338 print_mask("/", markinfo->mask); 339 break; 340 case XT_CONNMARK_SAVE: 341 printf(" --save-mark "); 342 print_mask("--mask ", markinfo->mask); 343 break; 344 case XT_CONNMARK_RESTORE: 345 printf(" --restore-mark "); 346 print_mask("--mask ", markinfo->mask); 347 break; 348 default: 349 printf(" ERROR: UNKNOWN CONNMARK MODE"); 350 break; 351 } 352} 353 354static void CONNMARK_init(struct xt_entry_target *t) 355{ 356 struct xt_connmark_target_info *markinfo 357 = (struct xt_connmark_target_info *)t->data; 358 359 markinfo->mask = 0xffffffffUL; 360} 361 362static void 363connmark_tg_save(const void *ip, const struct xt_entry_target *target) 364{ 365 const struct xt_connmark_tginfo1 *info = (const void *)target->data; 366 367 switch (info->mode) { 368 case XT_CONNMARK_SET: 369 printf(" --set-xmark 0x%x/0x%x", info->ctmark, info->ctmask); 370 break; 371 case XT_CONNMARK_SET_RETURN: 372 printf(" --set-return 0x%x/0x%x", info->ctmark, info->ctmask); 373 break; 374 case XT_CONNMARK_SAVE: 375 printf(" --save-mark --nfmask 0x%x --ctmask 0x%x", 376 info->nfmask, info->ctmask); 377 break; 378 case XT_CONNMARK_RESTORE: 379 printf(" --restore-mark --nfmask 0x%x --ctmask 0x%x", 380 info->nfmask, info->ctmask); 381 break; 382 default: 383 printf(" ERROR: UNKNOWN CONNMARK MODE"); 384 break; 385 } 386} 387 388static struct xtables_target connmark_tg_reg[] = { 389 { 390 .family = NFPROTO_UNSPEC, 391 .name = "CONNMARK", 392 .revision = 0, 393 .version = XTABLES_VERSION, 394 .size = XT_ALIGN(sizeof(struct xt_connmark_target_info)), 395 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)), 396 .help = CONNMARK_help, 397 .init = CONNMARK_init, 398 .print = CONNMARK_print, 399 .save = CONNMARK_save, 400 .x6_parse = CONNMARK_parse, 401 .x6_fcheck = connmark_tg_check, 402 .x6_options = CONNMARK_opts, 403 }, 404 { 405 .version = XTABLES_VERSION, 406 .name = "CONNMARK", 407 .revision = 1, 408 .family = NFPROTO_UNSPEC, 409 .size = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), 410 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), 411 .help = connmark_tg_help, 412 .init = connmark_tg_init, 413 .print = connmark_tg_print, 414 .save = connmark_tg_save, 415 .x6_parse = connmark_tg_parse, 416 .x6_fcheck = connmark_tg_check, 417 .x6_options = connmark_tg_opts, 418 }, 419}; 420 421void _init(void) 422{ 423 xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg)); 424} 425