1/* Shared library add-on to iptables to add MARK target support. */ 2#include <stdio.h> 3#include <string.h> 4#include <stdlib.h> 5#include <getopt.h> 6 7#include <iptables.h> 8#include <linux/netfilter_ipv4/ip_tables.h> 9/* For 64bit kernel / 32bit userspace */ 10#include "../include/linux/netfilter_ipv4/ipt_MARK.h" 11 12/* Function which prints out usage message. */ 13static void 14help(void) 15{ 16 printf( 17"MARK target v%s options:\n" 18" --set-mark value Set nfmark value\n" 19" --and-mark value Binary AND the nfmark with value\n" 20" --or-mark value Binary OR the nfmark with value\n" 21"\n", 22IPTABLES_VERSION); 23} 24 25static struct option opts[] = { 26 { "set-mark", 1, 0, '1' }, 27 { "and-mark", 1, 0, '2' }, 28 { "or-mark", 1, 0, '3' }, 29 { 0 } 30}; 31 32/* Initialize the target. */ 33static void 34init(struct ipt_entry_target *t, unsigned int *nfcache) 35{ 36} 37 38/* Function which parses command options; returns true if it 39 ate an option */ 40static int 41parse_v0(int c, char **argv, int invert, unsigned int *flags, 42 const struct ipt_entry *entry, 43 struct ipt_entry_target **target) 44{ 45 struct ipt_mark_target_info *markinfo 46 = (struct ipt_mark_target_info *)(*target)->data; 47 48 switch (c) { 49 case '1': 50#ifdef KERNEL_64_USERSPACE_32 51 if (string_to_number_ll(optarg, 0, 0, 52 &markinfo->mark)) 53#else 54 if (string_to_number_l(optarg, 0, 0, 55 &markinfo->mark)) 56#endif 57 exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); 58 if (*flags) 59 exit_error(PARAMETER_PROBLEM, 60 "MARK target: Can't specify --set-mark twice"); 61 *flags = 1; 62 break; 63 case '2': 64 exit_error(PARAMETER_PROBLEM, 65 "MARK target: kernel too old for --and-mark"); 66 case '3': 67 exit_error(PARAMETER_PROBLEM, 68 "MARK target: kernel too old for --or-mark"); 69 default: 70 return 0; 71 } 72 73 return 1; 74} 75 76static void 77final_check(unsigned int flags) 78{ 79 if (!flags) 80 exit_error(PARAMETER_PROBLEM, 81 "MARK target: Parameter --set/and/or-mark" 82 " is required"); 83} 84 85/* Function which parses command options; returns true if it 86 ate an option */ 87static int 88parse_v1(int c, char **argv, int invert, unsigned int *flags, 89 const struct ipt_entry *entry, 90 struct ipt_entry_target **target) 91{ 92 struct ipt_mark_target_info_v1 *markinfo 93 = (struct ipt_mark_target_info_v1 *)(*target)->data; 94 95 switch (c) { 96 case '1': 97 markinfo->mode = IPT_MARK_SET; 98 break; 99 case '2': 100 markinfo->mode = IPT_MARK_AND; 101 break; 102 case '3': 103 markinfo->mode = IPT_MARK_OR; 104 break; 105 default: 106 return 0; 107 } 108 109#ifdef KERNEL_64_USERSPACE_32 110 if (string_to_number_ll(optarg, 0, 0, &markinfo->mark)) 111#else 112 if (string_to_number_l(optarg, 0, 0, &markinfo->mark)) 113#endif 114 exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); 115 116 if (*flags) 117 exit_error(PARAMETER_PROBLEM, 118 "MARK target: Can't specify --set-mark twice"); 119 120 *flags = 1; 121 return 1; 122} 123 124#ifdef KERNEL_64_USERSPACE_32 125static void 126print_mark(unsigned long long mark) 127{ 128 printf("0x%llx ", mark); 129} 130#else 131static void 132print_mark(unsigned long mark) 133{ 134 printf("0x%lx ", mark); 135} 136#endif 137 138/* Prints out the targinfo. */ 139static void 140print_v0(const struct ipt_ip *ip, 141 const struct ipt_entry_target *target, 142 int numeric) 143{ 144 const struct ipt_mark_target_info *markinfo = 145 (const struct ipt_mark_target_info *)target->data; 146 printf("MARK set "); 147 print_mark(markinfo->mark); 148} 149 150/* Saves the union ipt_targinfo in parsable form to stdout. */ 151static void 152save_v0(const struct ipt_ip *ip, const struct ipt_entry_target *target) 153{ 154 const struct ipt_mark_target_info *markinfo = 155 (const struct ipt_mark_target_info *)target->data; 156 157 printf("--set-mark "); 158 print_mark(markinfo->mark); 159} 160 161/* Prints out the targinfo. */ 162static void 163print_v1(const struct ipt_ip *ip, 164 const struct ipt_entry_target *target, 165 int numeric) 166{ 167 const struct ipt_mark_target_info_v1 *markinfo = 168 (const struct ipt_mark_target_info_v1 *)target->data; 169 170 switch (markinfo->mode) { 171 case IPT_MARK_SET: 172 printf("MARK set "); 173 break; 174 case IPT_MARK_AND: 175 printf("MARK and "); 176 break; 177 case IPT_MARK_OR: 178 printf("MARK or "); 179 break; 180 } 181 print_mark(markinfo->mark); 182} 183 184/* Saves the union ipt_targinfo in parsable form to stdout. */ 185static void 186save_v1(const struct ipt_ip *ip, const struct ipt_entry_target *target) 187{ 188 const struct ipt_mark_target_info_v1 *markinfo = 189 (const struct ipt_mark_target_info_v1 *)target->data; 190 191 switch (markinfo->mode) { 192 case IPT_MARK_SET: 193 printf("--set-mark "); 194 break; 195 case IPT_MARK_AND: 196 printf("--and-mark "); 197 break; 198 case IPT_MARK_OR: 199 printf("--or-mark "); 200 break; 201 } 202 print_mark(markinfo->mark); 203} 204 205static 206struct iptables_target mark_v0 = { 207 .next = NULL, 208 .name = "MARK", 209 .version = IPTABLES_VERSION, 210 .revision = 0, 211 .size = IPT_ALIGN(sizeof(struct ipt_mark_target_info)), 212 .userspacesize = IPT_ALIGN(sizeof(struct ipt_mark_target_info)), 213 .help = &help, 214 .init = &init, 215 .parse = &parse_v0, 216 .final_check = &final_check, 217 .print = &print_v0, 218 .save = &save_v0, 219 .extra_opts = opts 220}; 221 222static 223struct iptables_target mark_v1 = { 224 .next = NULL, 225 .name = "MARK", 226 .version = IPTABLES_VERSION, 227 .revision = 1, 228 .size = IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1)), 229 .userspacesize = IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1)), 230 .help = &help, 231 .init = &init, 232 .parse = &parse_v1, 233 .final_check = &final_check, 234 .print = &print_v1, 235 .save = &save_v1, 236 .extra_opts = opts 237}; 238 239void _init(void) 240{ 241 register_target(&mark_v0); 242 register_target(&mark_v1); 243} 244