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