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