blob: ec2fe96aeb46260b8be59ce838cabc11f22dd4ca [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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_IPV4,
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_target6_v0 = {
311 .family = NFPROTO_IPV6,
312 .name = "MARK",
313 .version = XTABLES_VERSION,
314 .revision = 0,
315 .size = XT_ALIGN(sizeof(struct xt_mark_target_info)),
316 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
317 .help = MARK_help,
318 .parse = MARK_parse_v0,
319 .final_check = MARK_check,
320 .print = MARK_print_v0,
321 .save = MARK_save_v0,
322 .extra_opts = MARK_opts,
323};
324
325static struct xtables_target mark_tg_reg_v2 = {
326 .version = XTABLES_VERSION,
327 .name = "MARK",
328 .revision = 2,
329 .family = AF_UNSPEC,
330 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
331 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
332 .help = mark_tg_help,
333 .parse = mark_tg_parse,
334 .final_check = mark_tg_check,
335 .print = mark_tg_print,
336 .save = mark_tg_save,
337 .extra_opts = mark_tg_opts,
338};
339
340void _init(void)
341{
342 xtables_register_target(&mark_target_v0);
343 xtables_register_target(&mark_target_v1);
344 xtables_register_target(&mark_target6_v0);
345 xtables_register_target(&mark_tg_reg_v2);
346}