libxt_MARK.c revision 7ac405297ec38449b30e3b05fd6bf2082fd3d803
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 default: 97 return 0; 98 } 99 100 return 1; 101} 102 103static void MARK_check(unsigned int flags) 104{ 105 if (!flags) 106 xtables_error(PARAMETER_PROBLEM, 107 "MARK target: Parameter --set/and/or-mark" 108 " is required"); 109} 110 111static int 112MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags, 113 const void *entry, struct xt_entry_target **target) 114{ 115 struct xt_mark_target_info_v1 *markinfo 116 = (struct xt_mark_target_info_v1 *)(*target)->data; 117 unsigned int mark = 0; 118 119 switch (c) { 120 case '1': 121 markinfo->mode = XT_MARK_SET; 122 break; 123 case '2': 124 markinfo->mode = XT_MARK_AND; 125 break; 126 case '3': 127 markinfo->mode = XT_MARK_OR; 128 break; 129 default: 130 return 0; 131 } 132 133 if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) 134 xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); 135 markinfo->mark = mark; 136 if (*flags) 137 xtables_error(PARAMETER_PROBLEM, 138 "MARK target: Can't specify --set-mark twice"); 139 140 *flags = 1; 141 return 1; 142} 143 144static int mark_tg_parse(int c, char **argv, int invert, unsigned int *flags, 145 const void *entry, struct xt_entry_target **target) 146{ 147 struct xt_mark_tginfo2 *info = (void *)(*target)->data; 148 unsigned int value, mask = UINT32_MAX; 149 char *end; 150 151 switch (c) { 152 case 'X': /* --set-xmark */ 153 case '=': /* --set-mark */ 154 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 155 xtables_param_act(XTF_NO_INVERT, "MARK", "--set-xmark/--set-mark", invert); 156 if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX)) 157 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); 158 if (*end == '/') 159 if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) 160 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); 161 if (*end != '\0') 162 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); 163 info->mark = value; 164 info->mask = mask; 165 166 if (c == '=') 167 info->mask = value | mask; 168 break; 169 170 case '&': /* --and-mark */ 171 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 172 xtables_param_act(XTF_NO_INVERT, "MARK", "--and-mark", invert); 173 if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX)) 174 xtables_param_act(XTF_BAD_VALUE, "MARK", "--and-mark", optarg); 175 info->mark = 0; 176 info->mask = ~mask; 177 break; 178 179 case '|': /* --or-mark */ 180 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 181 xtables_param_act(XTF_NO_INVERT, "MARK", "--or-mark", invert); 182 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 183 xtables_param_act(XTF_BAD_VALUE, "MARK", "--or-mark", optarg); 184 info->mark = value; 185 info->mask = value; 186 break; 187 188 case '^': /* --xor-mark */ 189 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); 190 xtables_param_act(XTF_NO_INVERT, "MARK", "--xor-mark", invert); 191 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) 192 xtables_param_act(XTF_BAD_VALUE, "MARK", "--xor-mark", optarg); 193 info->mark = value; 194 info->mask = 0; 195 break; 196 197 default: 198 return false; 199 } 200 201 *flags |= F_MARK; 202 return true; 203} 204 205static void mark_tg_check(unsigned int flags) 206{ 207 if (flags == 0) 208 xtables_error(PARAMETER_PROBLEM, "MARK: One of the --set-xmark, " 209 "--{and,or,xor,set}-mark options is required"); 210} 211 212static void 213print_mark(unsigned long mark) 214{ 215 printf("0x%lx ", mark); 216} 217 218static void MARK_print_v0(const void *ip, 219 const struct xt_entry_target *target, int numeric) 220{ 221 const struct xt_mark_target_info *markinfo = 222 (const struct xt_mark_target_info *)target->data; 223 printf("MARK set "); 224 print_mark(markinfo->mark); 225} 226 227static void MARK_save_v0(const void *ip, const struct xt_entry_target *target) 228{ 229 const struct xt_mark_target_info *markinfo = 230 (const struct xt_mark_target_info *)target->data; 231 232 printf("--set-mark "); 233 print_mark(markinfo->mark); 234} 235 236static void MARK_print_v1(const void *ip, const struct xt_entry_target *target, 237 int numeric) 238{ 239 const struct xt_mark_target_info_v1 *markinfo = 240 (const struct xt_mark_target_info_v1 *)target->data; 241 242 switch (markinfo->mode) { 243 case XT_MARK_SET: 244 printf("MARK set "); 245 break; 246 case XT_MARK_AND: 247 printf("MARK and "); 248 break; 249 case XT_MARK_OR: 250 printf("MARK or "); 251 break; 252 } 253 print_mark(markinfo->mark); 254} 255 256static void mark_tg_print(const void *ip, const struct xt_entry_target *target, 257 int numeric) 258{ 259 const struct xt_mark_tginfo2 *info = (const void *)target->data; 260 261 if (info->mark == 0) 262 printf("MARK and 0x%x ", (unsigned int)(uint32_t)~info->mask); 263 else if (info->mark == info->mask) 264 printf("MARK or 0x%x ", info->mark); 265 else if (info->mask == 0) 266 printf("MARK xor 0x%x ", info->mark); 267 else if (info->mask == 0xffffffffU) 268 printf("MARK set 0x%x ", info->mark); 269 else 270 printf("MARK xset 0x%x/0x%x ", info->mark, info->mask); 271} 272 273static void MARK_save_v1(const void *ip, const struct xt_entry_target *target) 274{ 275 const struct xt_mark_target_info_v1 *markinfo = 276 (const struct xt_mark_target_info_v1 *)target->data; 277 278 switch (markinfo->mode) { 279 case XT_MARK_SET: 280 printf("--set-mark "); 281 break; 282 case XT_MARK_AND: 283 printf("--and-mark "); 284 break; 285 case XT_MARK_OR: 286 printf("--or-mark "); 287 break; 288 } 289 print_mark(markinfo->mark); 290} 291 292static void mark_tg_save(const void *ip, const struct xt_entry_target *target) 293{ 294 const struct xt_mark_tginfo2 *info = (const void *)target->data; 295 296 printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask); 297} 298 299static struct xtables_target mark_tg_reg[] = { 300 { 301 .family = NFPROTO_UNSPEC, 302 .name = "MARK", 303 .version = XTABLES_VERSION, 304 .revision = 0, 305 .size = XT_ALIGN(sizeof(struct xt_mark_target_info)), 306 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)), 307 .help = MARK_help, 308 .parse = MARK_parse_v0, 309 .final_check = MARK_check, 310 .print = MARK_print_v0, 311 .save = MARK_save_v0, 312 .extra_opts = MARK_opts, 313 }, 314 { 315 .family = NFPROTO_IPV4, 316 .name = "MARK", 317 .version = XTABLES_VERSION, 318 .revision = 1, 319 .size = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), 320 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), 321 .help = MARK_help, 322 .parse = MARK_parse_v1, 323 .final_check = MARK_check, 324 .print = MARK_print_v1, 325 .save = MARK_save_v1, 326 .extra_opts = MARK_opts, 327 }, 328 { 329 .version = XTABLES_VERSION, 330 .name = "MARK", 331 .revision = 2, 332 .family = NFPROTO_UNSPEC, 333 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), 334 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), 335 .help = mark_tg_help, 336 .parse = mark_tg_parse, 337 .final_check = mark_tg_check, 338 .print = mark_tg_print, 339 .save = mark_tg_save, 340 .extra_opts = mark_tg_opts, 341 }, 342}; 343 344void _init(void) 345{ 346 xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg)); 347} 348