libxt_MARK.c revision 3d915e1ac610bce44250b4aea556f4726387388d
1926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/* Shared library add-on to iptables to add MARK target support. */ 2926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <stdbool.h> 3926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <stdio.h> 4926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <string.h> 5926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <stdlib.h> 6926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <getopt.h> 7926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 8926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <xtables.h> 9926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <linux/netfilter/x_tables.h> 10926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <linux/netfilter/xt_MARK.h> 11926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 12926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)enum { 13926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) F_MARK = 1 << 0, 14926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}; 15926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 16926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static void MARK_help(void) 17926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 18926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) printf( 19926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"MARK target options:\n" 20926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)" --set-mark value Set nfmark value\n" 21926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)" --and-mark value Binary AND the nfmark with value\n" 22926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)" --or-mark value Binary OR the nfmark with value\n"); 23926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 24926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 25926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static const struct option MARK_opts[] = { 26926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) { "set-mark", 1, NULL, '1' }, 2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) { "and-mark", 1, NULL, '2' }, 28926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) { "or-mark", 1, NULL, '3' }, 2906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) { .name = NULL } 30d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}; 315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)static const struct option mark_tg_opts[] = { 3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) {.name = "set-xmark", .has_arg = true, .val = 'X'}, 34926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) {.name = "set-mark", .has_arg = true, .val = '='}, 35c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) {.name = "and-mark", .has_arg = true, .val = '&'}, 36926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) {.name = "or-mark", .has_arg = true, .val = '|'}, 37926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) {.name = "xor-mark", .has_arg = true, .val = '^'}, 38926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) { .name = NULL } 398abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)}; 4051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 41926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static void mark_tg_help(void) 42926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 43926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) printf( 44926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"MARK target options:\n" 45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)" --set-xmark value[/mask] Clear bits in mask and XOR value into nfmark\n" 46323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)" --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n" 47926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)" --and-mark bits Binary AND the nfmark with bits\n" 485d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)" --or-mark bits Binary OR the nfmark with bits\n" 4909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)" --xor-mask bits Binary XOR the nfmark with bits\n" 50521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)"\n"); 51521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)} 52926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 53926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/* Function which parses command options; returns true if it 54521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) ate an option */ 55926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static int 56926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)MARK_parse_v0(int c, char **argv, int invert, unsigned int *flags, 57d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) const void *entry, struct xt_entry_target **target) 58d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){ 59926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) struct xt_mark_target_info *markinfo 60521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) = (struct xt_mark_target_info *)(*target)->data; 61926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) unsigned int mark = 0; 62926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 63926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) switch (c) { 64926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) case '1': 65926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) 66926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); 67926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) markinfo->mark = mark; 68d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (*flags) 69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 70926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) "MARK target: Can't specify --set-mark twice"); 71926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *flags = 1; 72926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) break; 73926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) case '2': 74926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 75926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) "MARK target: kernel too old for --and-mark"); 76926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) case '3': 77926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 78926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) "MARK target: kernel too old for --or-mark"); 79926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) default: 80926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return 0; 81926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 82926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 83926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return 1; 84926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 85926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 86926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static void MARK_check(unsigned int flags) 87926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) if (!flags) 89926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 90d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) "MARK target: Parameter --set/and/or-mark" 91f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) " is required"); 92926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 93926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 94926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static int 95926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags, 96926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) const void *entry, struct xt_entry_target **target) 97926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 981e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) struct xt_mark_target_info_v1 *markinfo 99926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) = (struct xt_mark_target_info_v1 *)(*target)->data; 100d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) unsigned int mark = 0; 101d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 102926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) switch (c) { 103926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) case '1': 104926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) markinfo->mode = XT_MARK_SET; 105926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) break; 106926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) case '2': 107926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) markinfo->mode = XT_MARK_AND; 108926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) break; 109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) case '3': 110926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) markinfo->mode = XT_MARK_OR; 111926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) break; 112926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) default: 113926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return 0; 114926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 1155267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 1165267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) 1175267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); 1185267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) markinfo->mark = mark; 1195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) if (*flags) 120323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 121323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) "MARK target: Can't specify --set-mark twice"); 122323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) 123323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) *flags = 1; 124323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) return 1; 125323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)} 126926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 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 if (info->mask == 0xffffffffU) 251 printf("MARK set 0x%x ", info->mark); 252 else 253 printf("MARK xset 0x%x/0x%x ", info->mark, info->mask); 254} 255 256static void MARK_save_v1(const void *ip, const struct xt_entry_target *target) 257{ 258 const struct xt_mark_target_info_v1 *markinfo = 259 (const struct xt_mark_target_info_v1 *)target->data; 260 261 switch (markinfo->mode) { 262 case XT_MARK_SET: 263 printf("--set-mark "); 264 break; 265 case XT_MARK_AND: 266 printf("--and-mark "); 267 break; 268 case XT_MARK_OR: 269 printf("--or-mark "); 270 break; 271 } 272 print_mark(markinfo->mark); 273} 274 275static void mark_tg_save(const void *ip, const struct xt_entry_target *target) 276{ 277 const struct xt_mark_tginfo2 *info = (const void *)target->data; 278 279 printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask); 280} 281 282static struct xtables_target mark_tg_reg[] = { 283 { 284 .family = NFPROTO_UNSPEC, 285 .name = "MARK", 286 .version = XTABLES_VERSION, 287 .revision = 0, 288 .size = XT_ALIGN(sizeof(struct xt_mark_target_info)), 289 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)), 290 .help = MARK_help, 291 .parse = MARK_parse_v0, 292 .final_check = MARK_check, 293 .print = MARK_print_v0, 294 .save = MARK_save_v0, 295 .extra_opts = MARK_opts, 296 }, 297 { 298 .family = NFPROTO_IPV4, 299 .name = "MARK", 300 .version = XTABLES_VERSION, 301 .revision = 1, 302 .size = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), 303 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), 304 .help = MARK_help, 305 .parse = MARK_parse_v1, 306 .final_check = MARK_check, 307 .print = MARK_print_v1, 308 .save = MARK_save_v1, 309 .extra_opts = MARK_opts, 310 }, 311 { 312 .version = XTABLES_VERSION, 313 .name = "MARK", 314 .revision = 2, 315 .family = NFPROTO_UNSPEC, 316 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), 317 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), 318 .help = mark_tg_help, 319 .parse = mark_tg_parse, 320 .final_check = mark_tg_check, 321 .print = mark_tg_print, 322 .save = mark_tg_save, 323 .extra_opts = mark_tg_opts, 324 }, 325}; 326 327void _init(void) 328{ 329 xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg)); 330} 331