libxt_MARK.c revision d09b6d591ca7d7d7575cb6aa20384c9830f777ab
1/* Shared library add-on to iptables to add MARK target support. */ 2#include <stdbool.h> 3#include <stdio.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7 8#include <xtables.h> 9#include <linux/netfilter/x_tables.h> 10#include <linux/netfilter/xt_MARK.h> 11 12/* Version 0 */ 13struct xt_mark_target_info { 14 unsigned long mark; 15}; 16 17/* Version 1 */ 18enum { 19 XT_MARK_SET=0, 20 XT_MARK_AND, 21 XT_MARK_OR, 22}; 23 24struct xt_mark_target_info_v1 { 25 unsigned long mark; 26 uint8_t mode; 27}; 28 29enum { 30 F_MARK = 1 << 0, 31}; 32 33static void MARK_help(void) 34{ 35 printf( 36"MARK target options:\n" 37" --set-mark value Set nfmark value\n" 38" --and-mark value Binary AND the nfmark with value\n" 39" --or-mark value Binary OR the nfmark with value\n"); 40} 41 42static const struct option MARK_opts[] = { 43 {.name = "set-mark", .has_arg = true, .val = '1'}, 44 {.name = "and-mark", .has_arg = true, .val = '2'}, 45 {.name = "or-mark", .has_arg = true, .val = '3'}, 46 XT_GETOPT_TABLEEND, 47}; 48 49static const struct option mark_tg_opts[] = { 50 {.name = "set-xmark", .has_arg = true, .val = 'X'}, 51 {.name = "set-mark", .has_arg = true, .val = '='}, 52 {.name = "and-mark", .has_arg = true, .val = '&'}, 53 {.name = "or-mark", .has_arg = true, .val = '|'}, 54 {.name = "xor-mark", .has_arg = true, .val = '^'}, 55 XT_GETOPT_TABLEEND, 56}; 57 58static void mark_tg_help(void) 59{ 60 printf( 61"MARK target options:\n" 62" --set-xmark value[/mask] Clear bits in mask and XOR value into nfmark\n" 63" --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n" 64" --and-mark bits Binary AND the nfmark with bits\n" 65" --or-mark bits Binary OR the nfmark with bits\n" 66" --xor-mask bits Binary XOR the nfmark with bits\n" 67"\n"); 68} 69 70/* Function which parses command options; returns true if it 71 ate an option */ 72static int 73MARK_parse_v0(int c, char **argv, int invert, unsigned int *flags, 74 const void *entry, struct xt_entry_target **target) 75{ 76 struct xt_mark_target_info *markinfo 77 = (struct xt_mark_target_info *)(*target)->data; 78 unsigned int mark = 0; 79 80 switch (c) { 81 case '1': 82 if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) 83 xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); 84 markinfo->mark = mark; 85 if (*flags) 86 xtables_error(PARAMETER_PROBLEM, 87 "MARK target: Can't specify --set-mark twice"); 88 *flags = 1; 89 break; 90 case '2': 91 xtables_error(PARAMETER_PROBLEM, 92 "MARK target: kernel too old for --and-mark"); 93 case '3': 94 xtables_error(PARAMETER_PROBLEM, 95 "MARK target: kernel too old for --or-mark"); 96 } 97 98 return 1; 99} 100 101static void MARK_check(unsigned int flags) 102{ 103 if (!flags) 104 xtables_error(PARAMETER_PROBLEM, 105 "MARK target: Parameter --set/and/or-mark" 106 " is required"); 107} 108 109static int 110MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags, 111 const void *entry, struct xt_entry_target **target) 112{ 113 struct xt_mark_target_info_v1 *markinfo 114 = (struct xt_mark_target_info_v1 *)(*target)->data; 115 unsigned int mark = 0; 116 117 switch (c) { 118 case '1': 119 markinfo->mode = XT_MARK_SET; 120 break; 121 case '2': 122 markinfo->mode = XT_MARK_AND; 123 break; 124 case '3': 125 markinfo->mode = XT_MARK_OR; 126 break; 127 } 128 129 if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) 130 xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); 131 markinfo->mark = mark; 132 if (*flags) 133 xtables_error(PARAMETER_PROBLEM, 134 "MARK target: Can't specify --set-mark twice"); 135 136 *flags = 1; 137 return 1; 138} 139 140static int mark_tg_parse(int c, char **argv, int invert, unsigned int *flags, 141 const void *entry, struct xt_entry_target **target) 142{ 143 struct xt_mark_tginfo2 *info = (void *)(*target)->data; 144 unsigned int value, mask = UINT32_MAX; 145 char *end; 146 147 switch (c) { 148 case 'X': /* --set-xmark */ 149 case '=': /* --set-mark */ 150 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 151 xtables_param_act(XTF_NO_INVERT, "MARK", "--set-xmark/--set-mark", invert); 152 if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX)) 153 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); 154 if (*end == '/') 155 if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 156 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); 157 if (*end != '\0') 158 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); 159 info->mark = value; 160 info->mask = mask; 161 162 if (c == '=') 163 info->mask = value | mask; 164 break; 165 166 case '&': /* --and-mark */ 167 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 168 xtables_param_act(XTF_NO_INVERT, "MARK", "--and-mark", invert); 169 if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX)) 170 xtables_param_act(XTF_BAD_VALUE, "MARK", "--and-mark", optarg); 171 info->mark = 0; 172 info->mask = ~mask; 173 break; 174 175 case '|': /* --or-mark */ 176 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 177 xtables_param_act(XTF_NO_INVERT, "MARK", "--or-mark", invert); 178 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 179 xtables_param_act(XTF_BAD_VALUE, "MARK", "--or-mark", optarg); 180 info->mark = value; 181 info->mask = value; 182 break; 183 184 case '^': /* --xor-mark */ 185 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 186 xtables_param_act(XTF_NO_INVERT, "MARK", "--xor-mark", invert); 187 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 188 xtables_param_act(XTF_BAD_VALUE, "MARK", "--xor-mark", optarg); 189 info->mark = value; 190 info->mask = 0; 191 break; 192 } 193 194 *flags |= F_MARK; 195 return true; 196} 197 198static void mark_tg_check(unsigned int flags) 199{ 200 if (flags == 0) 201 xtables_error(PARAMETER_PROBLEM, "MARK: One of the --set-xmark, " 202 "--{and,or,xor,set}-mark options is required"); 203} 204 205static void 206print_mark(unsigned long mark) 207{ 208 printf("0x%lx ", mark); 209} 210 211static void MARK_print_v0(const void *ip, 212 const struct xt_entry_target *target, int numeric) 213{ 214 const struct xt_mark_target_info *markinfo = 215 (const struct xt_mark_target_info *)target->data; 216 printf("MARK set "); 217 print_mark(markinfo->mark); 218} 219 220static void MARK_save_v0(const void *ip, const struct xt_entry_target *target) 221{ 222 const struct xt_mark_target_info *markinfo = 223 (const struct xt_mark_target_info *)target->data; 224 225 printf("--set-mark "); 226 print_mark(markinfo->mark); 227} 228 229static void MARK_print_v1(const void *ip, const struct xt_entry_target *target, 230 int numeric) 231{ 232 const struct xt_mark_target_info_v1 *markinfo = 233 (const struct xt_mark_target_info_v1 *)target->data; 234 235 switch (markinfo->mode) { 236 case XT_MARK_SET: 237 printf("MARK set "); 238 break; 239 case XT_MARK_AND: 240 printf("MARK and "); 241 break; 242 case XT_MARK_OR: 243 printf("MARK or "); 244 break; 245 } 246 print_mark(markinfo->mark); 247} 248 249static void mark_tg_print(const void *ip, const struct xt_entry_target *target, 250 int numeric) 251{ 252 const struct xt_mark_tginfo2 *info = (const void *)target->data; 253 254 if (info->mark == 0) 255 printf("MARK and 0x%x ", (unsigned int)(uint32_t)~info->mask); 256 else if (info->mark == info->mask) 257 printf("MARK or 0x%x ", info->mark); 258 else if (info->mask == 0) 259 printf("MARK xor 0x%x ", info->mark); 260 else if (info->mask == 0xffffffffU) 261 printf("MARK set 0x%x ", info->mark); 262 else 263 printf("MARK xset 0x%x/0x%x ", info->mark, info->mask); 264} 265 266static void MARK_save_v1(const void *ip, const struct xt_entry_target *target) 267{ 268 const struct xt_mark_target_info_v1 *markinfo = 269 (const struct xt_mark_target_info_v1 *)target->data; 270 271 switch (markinfo->mode) { 272 case XT_MARK_SET: 273 printf("--set-mark "); 274 break; 275 case XT_MARK_AND: 276 printf("--and-mark "); 277 break; 278 case XT_MARK_OR: 279 printf("--or-mark "); 280 break; 281 } 282 print_mark(markinfo->mark); 283} 284 285static void mark_tg_save(const void *ip, const struct xt_entry_target *target) 286{ 287 const struct xt_mark_tginfo2 *info = (const void *)target->data; 288 289 printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask); 290} 291 292static struct xtables_target mark_tg_reg[] = { 293 { 294 .family = NFPROTO_UNSPEC, 295 .name = "MARK", 296 .version = XTABLES_VERSION, 297 .revision = 0, 298 .size = XT_ALIGN(sizeof(struct xt_mark_target_info)), 299 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)), 300 .help = MARK_help, 301 .parse = MARK_parse_v0, 302 .final_check = MARK_check, 303 .print = MARK_print_v0, 304 .save = MARK_save_v0, 305 .extra_opts = MARK_opts, 306 }, 307 { 308 .family = NFPROTO_IPV4, 309 .name = "MARK", 310 .version = XTABLES_VERSION, 311 .revision = 1, 312 .size = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), 313 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), 314 .help = MARK_help, 315 .parse = MARK_parse_v1, 316 .final_check = MARK_check, 317 .print = MARK_print_v1, 318 .save = MARK_save_v1, 319 .extra_opts = MARK_opts, 320 }, 321 { 322 .version = XTABLES_VERSION, 323 .name = "MARK", 324 .revision = 2, 325 .family = NFPROTO_UNSPEC, 326 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), 327 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), 328 .help = mark_tg_help, 329 .parse = mark_tg_parse, 330 .final_check = mark_tg_check, 331 .print = mark_tg_print, 332 .save = mark_tg_save, 333 .extra_opts = mark_tg_opts, 334 }, 335}; 336 337void _init(void) 338{ 339 xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg)); 340} 341