1 /* Code to take an arptables-style command line and do it. */
2
3 /*
4 * arptables:
5 * Author: Bart De Schuymer <bdschuym@pandora.be>, but
6 * almost all code is from the iptables userspace program, which has main
7 * authors: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /*
25 Currently, only support for specifying hardware addresses for Ethernet
26 is available.
27 This tool is not luser-proof: you can specify an Ethernet source address
28 and set hardware length to something different than 6, f.e.
29 */
30 #include "config.h"
31 #include <getopt.h>
32 #include <string.h>
33 #include <netdb.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <inttypes.h>
38 #include <dlfcn.h>
39 #include <ctype.h>
40 #include <stdarg.h>
41 #include <limits.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <sys/wait.h>
45 #include <net/if.h>
46 #include <netinet/ether.h>
47 #include <iptables.h>
48 #include <xtables.h>
49
50 #include "xshared.h"
51
52 #include "nft.h"
53 #include "nft-arp.h"
54 #include <linux/netfilter_arp/arp_tables.h>
55
56 static struct option original_opts[] = {
57 { "append", 1, 0, 'A' },
58 { "delete", 1, 0, 'D' },
59 { "insert", 1, 0, 'I' },
60 { "replace", 1, 0, 'R' },
61 { "list", 2, 0, 'L' },
62 { "flush", 2, 0, 'F' },
63 { "zero", 2, 0, 'Z' },
64 { "new-chain", 1, 0, 'N' },
65 { "delete-chain", 2, 0, 'X' },
66 { "rename-chain", 1, 0, 'E' },
67 { "policy", 1, 0, 'P' },
68 { "source-ip", 1, 0, 's' },
69 { "destination-ip", 1, 0, 'd' },
70 { "src-ip", 1, 0, 's' },
71 { "dst-ip", 1, 0, 'd' },
72 { "source-mac", 1, 0, 2},
73 { "destination-mac", 1, 0, 3},
74 { "src-mac", 1, 0, 2},
75 { "dst-mac", 1, 0, 3},
76 { "h-length", 1, 0, 'l' },
77 { "p-length", 1, 0, 8 },
78 { "opcode", 1, 0, 4 },
79 { "h-type", 1, 0, 5 },
80 { "proto-type", 1, 0, 6 },
81 { "in-interface", 1, 0, 'i' },
82 { "jump", 1, 0, 'j' },
83 { "table", 1, 0, 't' },
84 { "match", 1, 0, 'm' },
85 { "numeric", 0, 0, 'n' },
86 { "out-interface", 1, 0, 'o' },
87 { "verbose", 0, 0, 'v' },
88 { "exact", 0, 0, 'x' },
89 { "version", 0, 0, 'V' },
90 { "help", 2, 0, 'h' },
91 { "line-numbers", 0, 0, '0' },
92 { "modprobe", 1, 0, 'M' },
93 { "set-counters", 1, 0, 'c' },
94 { 0 }
95 };
96
97 #define opts xt_params->opts
98
99 extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
100 struct xtables_globals arptables_globals = {
101 .option_offset = 0,
102 .program_version = PACKAGE_VERSION,
103 .orig_opts = original_opts,
104 .exit_err = xtables_exit_error,
105 .compat_rev = nft_compatible_revision,
106 };
107
108 /* index relates to bit of each OPT_* value */
109 static int inverse_for_options[] =
110 {
111 /* -n */ 0,
112 /* -s */ IPT_INV_SRCIP,
113 /* -d */ IPT_INV_DSTIP,
114 /* -p */ 0,
115 /* -j */ 0,
116 /* -v */ 0,
117 /* -x */ 0,
118 /* -i */ IPT_INV_VIA_IN,
119 /* -o */ IPT_INV_VIA_OUT,
120 /*--line*/ 0,
121 /* -c */ 0,
122 /* -f */ 0,
123 /* 2 */ IPT_INV_SRCDEVADDR,
124 /* 3 */ IPT_INV_TGTDEVADDR,
125 /* -l */ IPT_INV_ARPHLN,
126 /* 4 */ IPT_INV_ARPOP,
127 /* 5 */ IPT_INV_ARPHRD,
128 /* 6 */ IPT_INV_PROTO,
129 };
130
131 /***********************************************/
132 /* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
133 /***********************************************/
134
getlength_and_mask(char * from,uint8_t * to,uint8_t * mask)135 static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
136 {
137 char *p, *buffer;
138 int i;
139
140 if ( (p = strrchr(from, '/')) != NULL) {
141 *p = '\0';
142 i = strtol(p+1, &buffer, 10);
143 if (*buffer != '\0' || i < 0 || i > 255)
144 return -1;
145 *mask = (uint8_t)i;
146 } else
147 *mask = 255;
148 i = strtol(from, &buffer, 10);
149 if (*buffer != '\0' || i < 0 || i > 255)
150 return -1;
151 *to = (uint8_t)i;
152 return 0;
153 }
154
get16_and_mask(char * from,uint16_t * to,uint16_t * mask,int base)155 static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
156 {
157 char *p, *buffer;
158 int i;
159
160 if ( (p = strrchr(from, '/')) != NULL) {
161 *p = '\0';
162 i = strtol(p+1, &buffer, base);
163 if (*buffer != '\0' || i < 0 || i > 65535)
164 return -1;
165 *mask = htons((uint16_t)i);
166 } else
167 *mask = 65535;
168 i = strtol(from, &buffer, base);
169 if (*buffer != '\0' || i < 0 || i > 65535)
170 return -1;
171 *to = htons((uint16_t)i);
172 return 0;
173 }
174
175 /*********************************************/
176 /* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
177 /*********************************************/
178
179 static void
exit_tryhelp(int status)180 exit_tryhelp(int status)
181 {
182 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
183 arptables_globals.program_name,
184 arptables_globals.program_version);
185 exit(status);
186 }
187
188 static void
printhelp(void)189 printhelp(void)
190 {
191 struct xtables_target *t = NULL;
192 int i;
193
194 printf("%s v%s\n\n"
195 "Usage: %s -[AD] chain rule-specification [options]\n"
196 " %s -[RI] chain rulenum rule-specification [options]\n"
197 " %s -D chain rulenum [options]\n"
198 " %s -[LFZ] [chain] [options]\n"
199 " %s -[NX] chain\n"
200 " %s -E old-chain-name new-chain-name\n"
201 " %s -P chain target [options]\n"
202 " %s -h (print this help information)\n\n",
203 arptables_globals.program_name,
204 arptables_globals.program_version,
205 arptables_globals.program_name,
206 arptables_globals.program_name,
207 arptables_globals.program_name,
208 arptables_globals.program_name,
209 arptables_globals.program_name,
210 arptables_globals.program_name,
211 arptables_globals.program_name,
212 arptables_globals.program_name);
213 printf(
214 "Commands:\n"
215 "Either long or short options are allowed.\n"
216 " --append -A chain Append to chain\n"
217 " --delete -D chain Delete matching rule from chain\n"
218 " --delete -D chain rulenum\n"
219 " Delete rule rulenum (1 = first) from chain\n"
220 " --insert -I chain [rulenum]\n"
221 " Insert in chain as rulenum (default 1=first)\n"
222 " --replace -R chain rulenum\n"
223 " Replace rule rulenum (1 = first) in chain\n"
224 " --list -L [chain] List the rules in a chain or all chains\n"
225 " --flush -F [chain] Delete all rules in chain or all chains\n"
226 " --zero -Z [chain] Zero counters in chain or all chains\n"
227 " --new -N chain Create a new user-defined chain\n"
228 " --delete-chain\n"
229 " -X [chain] Delete a user-defined chain\n"
230 " --policy -P chain target\n"
231 " Change policy on chain to target\n"
232 " --rename-chain\n"
233 " -E old-chain new-chain\n"
234 " Change chain name, (moving any references)\n"
235
236 "Options:\n"
237 " --source-ip -s [!] address[/mask]\n"
238 " source specification\n"
239 " --destination-ip -d [!] address[/mask]\n"
240 " destination specification\n"
241 " --source-mac [!] address[/mask]\n"
242 " --destination-mac [!] address[/mask]\n"
243 " --h-length -l length[/mask] hardware length (nr of bytes)\n"
244 " --opcode code[/mask] operation code (2 bytes)\n"
245 " --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
246 " --proto-type type[/mask] protocol type (2 bytes)\n"
247 " --in-interface -i [!] input name[+]\n"
248 " network interface name ([+] for wildcard)\n"
249 " --out-interface -o [!] output name[+]\n"
250 " network interface name ([+] for wildcard)\n"
251 " --jump -j target\n"
252 " target for rule (may load target extension)\n"
253 " --match -m match\n"
254 " extended match (may load extension)\n"
255 " --numeric -n numeric output of addresses and ports\n"
256 " --table -t table table to manipulate (default: `filter')\n"
257 " --verbose -v verbose mode\n"
258 " --line-numbers print line numbers when listing\n"
259 " --exact -x expand numbers (display exact values)\n"
260 " --modprobe=<command> try to insert modules using this command\n"
261 " --set-counters -c PKTS BYTES set the counter during insert/append\n"
262 "[!] --version -V print package version.\n");
263 printf(" opcode strings: \n");
264 for (i = 0; i < NUMOPCODES; i++)
265 printf(" %d = %s\n", i + 1, arp_opcodes[i]);
266 printf(
267 " hardware type string: 1 = Ethernet\n"
268 " protocol type string: 0x800 = IPv4\n");
269
270 /* Print out any special helps. A user might like to be able
271 to add a --help to the commandline, and see expected
272 results. So we call help for all matches & targets */
273 for (t = xtables_targets; t; t = t->next) {
274 if (strcmp(t->name, "CLASSIFY") && strcmp(t->name, "mangle"))
275 continue;
276 printf("\n");
277 t->help();
278 }
279 }
280
281 static int
check_inverse(const char option[],int * invert,int * optidx,int argc)282 check_inverse(const char option[], int *invert, int *optidx, int argc)
283 {
284 if (option && strcmp(option, "!") == 0) {
285 if (*invert)
286 xtables_error(PARAMETER_PROBLEM,
287 "Multiple `!' flags not allowed");
288 *invert = true;
289 if (optidx) {
290 *optidx = *optidx+1;
291 if (argc && *optidx > argc)
292 xtables_error(PARAMETER_PROBLEM,
293 "no argument following `!'");
294 }
295
296 return true;
297 }
298 return false;
299 }
300
301 static void
set_option(unsigned int * options,unsigned int option,u_int16_t * invflg,int invert)302 set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
303 int invert)
304 {
305 if (*options & option)
306 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
307 opt2char(option));
308 *options |= option;
309
310 if (invert) {
311 unsigned int i;
312 for (i = 0; 1 << i != option; i++);
313
314 if (!inverse_for_options[i])
315 xtables_error(PARAMETER_PROBLEM,
316 "cannot have ! before -%c",
317 opt2char(option));
318 *invflg |= inverse_for_options[i];
319 }
320 }
321
322 static int
list_entries(struct nft_handle * h,const char * chain,const char * table,int rulenum,int verbose,int numeric,int expanded,int linenumbers)323 list_entries(struct nft_handle *h, const char *chain, const char *table,
324 int rulenum, int verbose, int numeric, int expanded,
325 int linenumbers)
326 {
327 unsigned int format;
328
329 format = FMT_OPTIONS;
330 if (!verbose)
331 format |= FMT_NOCOUNTS;
332 else
333 format |= FMT_VIA;
334
335 if (numeric)
336 format |= FMT_NUMERIC;
337
338 if (!expanded)
339 format |= FMT_KILOMEGAGIGA;
340
341 if (linenumbers)
342 format |= FMT_LINENUMBERS;
343
344 return nft_cmd_rule_list(h, chain, table, rulenum, format);
345 }
346
347 static int
append_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,int rulenum,unsigned int nsaddrs,const struct in_addr saddrs[],const struct in_addr smasks[],unsigned int ndaddrs,const struct in_addr daddrs[],const struct in_addr dmasks[],bool verbose,bool append)348 append_entry(struct nft_handle *h,
349 const char *chain,
350 const char *table,
351 struct iptables_command_state *cs,
352 int rulenum,
353 unsigned int nsaddrs,
354 const struct in_addr saddrs[],
355 const struct in_addr smasks[],
356 unsigned int ndaddrs,
357 const struct in_addr daddrs[],
358 const struct in_addr dmasks[],
359 bool verbose, bool append)
360 {
361 unsigned int i, j;
362 int ret = 1;
363
364 for (i = 0; i < nsaddrs; i++) {
365 cs->arp.arp.src.s_addr = saddrs[i].s_addr;
366 cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
367 for (j = 0; j < ndaddrs; j++) {
368 cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
369 cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
370 if (append) {
371 ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
372 verbose);
373 } else {
374 ret = nft_cmd_rule_insert(h, chain, table, cs,
375 rulenum, verbose);
376 }
377 }
378 }
379
380 return ret;
381 }
382
383 static int
replace_entry(const char * chain,const char * table,struct iptables_command_state * cs,unsigned int rulenum,const struct in_addr * saddr,const struct in_addr * smask,const struct in_addr * daddr,const struct in_addr * dmask,bool verbose,struct nft_handle * h)384 replace_entry(const char *chain,
385 const char *table,
386 struct iptables_command_state *cs,
387 unsigned int rulenum,
388 const struct in_addr *saddr,
389 const struct in_addr *smask,
390 const struct in_addr *daddr,
391 const struct in_addr *dmask,
392 bool verbose, struct nft_handle *h)
393 {
394 cs->arp.arp.src.s_addr = saddr->s_addr;
395 cs->arp.arp.tgt.s_addr = daddr->s_addr;
396 cs->arp.arp.smsk.s_addr = smask->s_addr;
397 cs->arp.arp.tmsk.s_addr = dmask->s_addr;
398
399 return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
400 }
401
402 static int
delete_entry(const char * chain,const char * table,struct iptables_command_state * cs,unsigned int nsaddrs,const struct in_addr saddrs[],const struct in_addr smasks[],unsigned int ndaddrs,const struct in_addr daddrs[],const struct in_addr dmasks[],bool verbose,struct nft_handle * h)403 delete_entry(const char *chain,
404 const char *table,
405 struct iptables_command_state *cs,
406 unsigned int nsaddrs,
407 const struct in_addr saddrs[],
408 const struct in_addr smasks[],
409 unsigned int ndaddrs,
410 const struct in_addr daddrs[],
411 const struct in_addr dmasks[],
412 bool verbose, struct nft_handle *h)
413 {
414 unsigned int i, j;
415 int ret = 1;
416
417 for (i = 0; i < nsaddrs; i++) {
418 cs->arp.arp.src.s_addr = saddrs[i].s_addr;
419 cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
420 for (j = 0; j < ndaddrs; j++) {
421 cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
422 cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
423 ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
424 }
425 }
426
427 return ret;
428 }
429
nft_init_arp(struct nft_handle * h,const char * pname)430 int nft_init_arp(struct nft_handle *h, const char *pname)
431 {
432 arptables_globals.program_name = pname;
433 if (xtables_init_all(&arptables_globals, NFPROTO_ARP) < 0) {
434 fprintf(stderr, "%s/%s Failed to initialize arptables-compat\n",
435 arptables_globals.program_name,
436 arptables_globals.program_version);
437 exit(1);
438 }
439
440 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
441 init_extensionsa();
442 #endif
443
444 if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
445 xtables_error(OTHER_PROBLEM,
446 "Could not initialize nftables layer.");
447
448 return 0;
449 }
450
do_commandarp(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)451 int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
452 bool restore)
453 {
454 struct iptables_command_state cs = {
455 .jumpto = "",
456 .arp.arp = {
457 .arhln = 6,
458 .arhln_mask = 255,
459 .arhrd = htons(ARPHRD_ETHER),
460 .arhrd_mask = 65535,
461 },
462 };
463 int invert = 0;
464 unsigned int nsaddrs = 0, ndaddrs = 0;
465 struct in_addr *saddrs = NULL, *smasks = NULL;
466 struct in_addr *daddrs = NULL, *dmasks = NULL;
467
468 int c, verbose = 0;
469 const char *chain = NULL;
470 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
471 const char *policy = NULL, *newname = NULL;
472 unsigned int rulenum = 0, options = 0, command = 0;
473 const char *pcnt = NULL, *bcnt = NULL;
474 int ret = 1;
475 struct xtables_target *t;
476
477 /* re-set optind to 0 in case do_command gets called
478 * a second time */
479 optind = 0;
480
481 for (t = xtables_targets; t; t = t->next) {
482 t->tflags = 0;
483 t->used = 0;
484 }
485
486 /* Suppress error messages: we may add new options if we
487 demand-load a protocol. */
488 opterr = 0;
489
490 opts = xt_params->orig_opts;
491 while ((c = getopt_long(argc, argv,
492 "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:",
493 opts, NULL)) != -1) {
494 switch (c) {
495 /*
496 * Command selection
497 */
498 case 'A':
499 add_command(&command, CMD_APPEND, CMD_NONE,
500 invert);
501 chain = optarg;
502 break;
503
504 case 'D':
505 add_command(&command, CMD_DELETE, CMD_NONE,
506 invert);
507 chain = optarg;
508 if (xs_has_arg(argc, argv)) {
509 rulenum = parse_rulenumber(argv[optind++]);
510 command = CMD_DELETE_NUM;
511 }
512 break;
513
514 case 'R':
515 add_command(&command, CMD_REPLACE, CMD_NONE,
516 invert);
517 chain = optarg;
518 if (xs_has_arg(argc, argv))
519 rulenum = parse_rulenumber(argv[optind++]);
520 else
521 xtables_error(PARAMETER_PROBLEM,
522 "-%c requires a rule number",
523 cmd2char(CMD_REPLACE));
524 break;
525
526 case 'I':
527 add_command(&command, CMD_INSERT, CMD_NONE,
528 invert);
529 chain = optarg;
530 if (xs_has_arg(argc, argv))
531 rulenum = parse_rulenumber(argv[optind++]);
532 else rulenum = 1;
533 break;
534
535 case 'L':
536 add_command(&command, CMD_LIST, CMD_ZERO,
537 invert);
538 if (optarg) chain = optarg;
539 else if (xs_has_arg(argc, argv))
540 chain = argv[optind++];
541 break;
542
543 case 'F':
544 add_command(&command, CMD_FLUSH, CMD_NONE,
545 invert);
546 if (optarg) chain = optarg;
547 else if (xs_has_arg(argc, argv))
548 chain = argv[optind++];
549 break;
550
551 case 'Z':
552 add_command(&command, CMD_ZERO, CMD_LIST,
553 invert);
554 if (optarg) chain = optarg;
555 else if (xs_has_arg(argc, argv))
556 chain = argv[optind++];
557 break;
558
559 case 'N':
560 if (optarg && *optarg == '-')
561 xtables_error(PARAMETER_PROBLEM,
562 "chain name not allowed to start "
563 "with `-'\n");
564 if (xtables_find_target(optarg, XTF_TRY_LOAD))
565 xtables_error(PARAMETER_PROBLEM,
566 "chain name may not clash "
567 "with target name\n");
568 add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
569 invert);
570 chain = optarg;
571 break;
572
573 case 'X':
574 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
575 invert);
576 if (optarg) chain = optarg;
577 else if (xs_has_arg(argc, argv))
578 chain = argv[optind++];
579 break;
580
581 case 'E':
582 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
583 invert);
584 chain = optarg;
585 if (xs_has_arg(argc, argv))
586 newname = argv[optind++];
587 else
588 xtables_error(PARAMETER_PROBLEM,
589 "-%c requires old-chain-name and "
590 "new-chain-name",
591 cmd2char(CMD_RENAME_CHAIN));
592 break;
593
594 case 'P':
595 add_command(&command, CMD_SET_POLICY, CMD_NONE,
596 invert);
597 chain = optarg;
598 if (xs_has_arg(argc, argv))
599 policy = argv[optind++];
600 else
601 xtables_error(PARAMETER_PROBLEM,
602 "-%c requires a chain and a policy",
603 cmd2char(CMD_SET_POLICY));
604 break;
605
606 case 'h':
607 if (!optarg)
608 optarg = argv[optind];
609
610 printhelp();
611 command = CMD_NONE;
612 break;
613 case 's':
614 check_inverse(optarg, &invert, &optind, argc);
615 set_option(&options, OPT_SOURCE, &cs.arp.arp.invflags,
616 invert);
617 shostnetworkmask = argv[optind-1];
618 break;
619
620 case 'd':
621 check_inverse(optarg, &invert, &optind, argc);
622 set_option(&options, OPT_DESTINATION, &cs.arp.arp.invflags,
623 invert);
624 dhostnetworkmask = argv[optind-1];
625 break;
626
627 case 2:/* src-mac */
628 check_inverse(optarg, &invert, &optind, argc);
629 set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
630 invert);
631 if (xtables_parse_mac_and_mask(argv[optind - 1],
632 cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
633 xtables_error(PARAMETER_PROBLEM, "Problem with specified "
634 "source mac");
635 break;
636
637 case 3:/* dst-mac */
638 check_inverse(optarg, &invert, &optind, argc);
639 set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
640 invert);
641
642 if (xtables_parse_mac_and_mask(argv[optind - 1],
643 cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
644 xtables_error(PARAMETER_PROBLEM, "Problem with specified "
645 "destination mac");
646 break;
647
648 case 'l':/* hardware length */
649 check_inverse(optarg, &invert, &optind, argc);
650 set_option(&options, OPT_H_LENGTH, &cs.arp.arp.invflags,
651 invert);
652 getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln,
653 &cs.arp.arp.arhln_mask);
654
655 if (cs.arp.arp.arhln != 6) {
656 xtables_error(PARAMETER_PROBLEM,
657 "Only harware address length of"
658 " 6 is supported currently.");
659 }
660
661 break;
662
663 case 8: /* was never supported, not even in arptables-legacy */
664 xtables_error(PARAMETER_PROBLEM, "not supported");
665 case 4:/* opcode */
666 check_inverse(optarg, &invert, &optind, argc);
667 set_option(&options, OPT_OPCODE, &cs.arp.arp.invflags,
668 invert);
669 if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop,
670 &cs.arp.arp.arpop_mask, 10)) {
671 int i;
672
673 for (i = 0; i < NUMOPCODES; i++)
674 if (!strcasecmp(arp_opcodes[i], optarg))
675 break;
676 if (i == NUMOPCODES)
677 xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
678 cs.arp.arp.arpop = htons(i+1);
679 }
680 break;
681
682 case 5:/* h-type */
683 check_inverse(optarg, &invert, &optind, argc);
684 set_option(&options, OPT_H_TYPE, &cs.arp.arp.invflags,
685 invert);
686 if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd,
687 &cs.arp.arp.arhrd_mask, 16)) {
688 if (strcasecmp(argv[optind-1], "Ethernet"))
689 xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
690 cs.arp.arp.arhrd = htons(1);
691 }
692 break;
693
694 case 6:/* proto-type */
695 check_inverse(optarg, &invert, &optind, argc);
696 set_option(&options, OPT_P_TYPE, &cs.arp.arp.invflags,
697 invert);
698 if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro,
699 &cs.arp.arp.arpro_mask, 0)) {
700 if (strcasecmp(argv[optind-1], "ipv4"))
701 xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
702 cs.arp.arp.arpro = htons(0x800);
703 }
704 break;
705
706 case 'j':
707 set_option(&options, OPT_JUMP, &cs.arp.arp.invflags,
708 invert);
709 command_jump(&cs, optarg);
710 break;
711
712 case 'i':
713 check_inverse(optarg, &invert, &optind, argc);
714 set_option(&options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
715 invert);
716 xtables_parse_interface(argv[optind-1],
717 cs.arp.arp.iniface,
718 cs.arp.arp.iniface_mask);
719 break;
720
721 case 'o':
722 check_inverse(optarg, &invert, &optind, argc);
723 set_option(&options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
724 invert);
725 xtables_parse_interface(argv[optind-1],
726 cs.arp.arp.outiface,
727 cs.arp.arp.outiface_mask);
728 break;
729
730 case 'v':
731 if (!verbose)
732 set_option(&options, OPT_VERBOSE,
733 &cs.arp.arp.invflags, invert);
734 verbose++;
735 break;
736
737 case 'm': /* ignored by arptables-legacy */
738 break;
739 case 'n':
740 set_option(&options, OPT_NUMERIC, &cs.arp.arp.invflags,
741 invert);
742 break;
743
744 case 't':
745 if (invert)
746 xtables_error(PARAMETER_PROBLEM,
747 "unexpected ! flag before --table");
748 /* ignore this option.
749 * arptables-legacy parses it, but libarptc doesn't use it.
750 * arptables only has a 'filter' table anyway.
751 */
752 break;
753
754 case 'V':
755 if (invert)
756 printf("Not %s ;-)\n", arptables_globals.program_version);
757 else
758 printf("%s v%s (nf_tables)\n",
759 arptables_globals.program_name,
760 arptables_globals.program_version);
761 exit(0);
762
763 case '0':
764 set_option(&options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
765 invert);
766 break;
767
768 case 'M':
769 //modprobe = optarg;
770 break;
771
772 case 'c':
773
774 set_option(&options, OPT_COUNTERS, &cs.arp.arp.invflags,
775 invert);
776 pcnt = optarg;
777 if (xs_has_arg(argc, argv))
778 bcnt = argv[optind++];
779 else
780 xtables_error(PARAMETER_PROBLEM,
781 "-%c requires packet and byte counter",
782 opt2char(OPT_COUNTERS));
783
784 if (sscanf(pcnt, "%llu", &cs.arp.counters.pcnt) != 1)
785 xtables_error(PARAMETER_PROBLEM,
786 "-%c packet counter not numeric",
787 opt2char(OPT_COUNTERS));
788
789 if (sscanf(bcnt, "%llu", &cs.arp.counters.bcnt) != 1)
790 xtables_error(PARAMETER_PROBLEM,
791 "-%c byte counter not numeric",
792 opt2char(OPT_COUNTERS));
793
794 break;
795
796
797 case 1: /* non option */
798 if (optarg[0] == '!' && optarg[1] == '\0') {
799 if (invert)
800 xtables_error(PARAMETER_PROBLEM,
801 "multiple consecutive ! not"
802 " allowed");
803 invert = true;
804 optarg[0] = '\0';
805 continue;
806 }
807 printf("Bad argument `%s'\n", optarg);
808 exit_tryhelp(2);
809
810 default:
811 if (cs.target) {
812 xtables_option_tpcall(c, argv,
813 invert, cs.target, &cs.arp);
814 }
815 break;
816 }
817 invert = false;
818 }
819
820 if (cs.target)
821 xtables_option_tfcall(cs.target);
822
823 if (optind < argc)
824 xtables_error(PARAMETER_PROBLEM,
825 "unknown arguments found on commandline");
826 if (invert)
827 xtables_error(PARAMETER_PROBLEM,
828 "nothing appropriate following !");
829
830 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
831 if (!(options & OPT_DESTINATION))
832 dhostnetworkmask = "0.0.0.0/0";
833 if (!(options & OPT_SOURCE))
834 shostnetworkmask = "0.0.0.0/0";
835 }
836
837 if (shostnetworkmask)
838 xtables_ipparse_multiple(shostnetworkmask, &saddrs,
839 &smasks, &nsaddrs);
840
841 if (dhostnetworkmask)
842 xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
843 &dmasks, &ndaddrs);
844
845 if ((nsaddrs > 1 || ndaddrs > 1) &&
846 (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
847 xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
848 " source or destination IP addresses");
849
850 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
851 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
852 "specify a unique address");
853
854 if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
855 xtables_error(PARAMETER_PROBLEM,
856 "chain name `%s' too long (must be under %i chars)",
857 chain, ARPT_FUNCTION_MAXNAMELEN);
858
859 if (command == CMD_APPEND
860 || command == CMD_DELETE
861 || command == CMD_INSERT
862 || command == CMD_REPLACE) {
863 if (strcmp(chain, "PREROUTING") == 0
864 || strcmp(chain, "INPUT") == 0) {
865 /* -o not valid with incoming packets. */
866 if (options & OPT_VIANAMEOUT)
867 xtables_error(PARAMETER_PROBLEM,
868 "Can't use -%c with %s\n",
869 opt2char(OPT_VIANAMEOUT),
870 chain);
871 }
872
873 if (strcmp(chain, "POSTROUTING") == 0
874 || strcmp(chain, "OUTPUT") == 0) {
875 /* -i not valid with outgoing packets */
876 if (options & OPT_VIANAMEIN)
877 xtables_error(PARAMETER_PROBLEM,
878 "Can't use -%c with %s\n",
879 opt2char(OPT_VIANAMEIN),
880 chain);
881 }
882 }
883
884 switch (command) {
885 case CMD_APPEND:
886 ret = append_entry(h, chain, *table, &cs, 0,
887 nsaddrs, saddrs, smasks,
888 ndaddrs, daddrs, dmasks,
889 options&OPT_VERBOSE, true);
890 break;
891 case CMD_DELETE:
892 ret = delete_entry(chain, *table, &cs,
893 nsaddrs, saddrs, smasks,
894 ndaddrs, daddrs, dmasks,
895 options&OPT_VERBOSE, h);
896 break;
897 case CMD_DELETE_NUM:
898 ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
899 break;
900 case CMD_REPLACE:
901 ret = replace_entry(chain, *table, &cs, rulenum - 1,
902 saddrs, smasks, daddrs, dmasks,
903 options&OPT_VERBOSE, h);
904 break;
905 case CMD_INSERT:
906 ret = append_entry(h, chain, *table, &cs, rulenum - 1,
907 nsaddrs, saddrs, smasks,
908 ndaddrs, daddrs, dmasks,
909 options&OPT_VERBOSE, false);
910 break;
911 case CMD_LIST:
912 ret = list_entries(h, chain, *table,
913 rulenum,
914 options&OPT_VERBOSE,
915 options&OPT_NUMERIC,
916 /*options&OPT_EXPANDED*/0,
917 options&OPT_LINENUMBERS);
918 break;
919 case CMD_FLUSH:
920 ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
921 break;
922 case CMD_ZERO:
923 ret = nft_cmd_chain_zero_counters(h, chain, *table,
924 options & OPT_VERBOSE);
925 break;
926 case CMD_LIST|CMD_ZERO:
927 ret = list_entries(h, chain, *table, rulenum,
928 options&OPT_VERBOSE,
929 options&OPT_NUMERIC,
930 /*options&OPT_EXPANDED*/0,
931 options&OPT_LINENUMBERS);
932 if (ret)
933 ret = nft_cmd_chain_zero_counters(h, chain, *table,
934 options & OPT_VERBOSE);
935 break;
936 case CMD_NEW_CHAIN:
937 ret = nft_cmd_chain_user_add(h, chain, *table);
938 break;
939 case CMD_DELETE_CHAIN:
940 ret = nft_cmd_chain_user_del(h, chain, *table,
941 options & OPT_VERBOSE);
942 break;
943 case CMD_RENAME_CHAIN:
944 ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
945 break;
946 case CMD_SET_POLICY:
947 ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
948 if (ret < 0)
949 xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
950 policy);
951 break;
952 case CMD_NONE:
953 break;
954 default:
955 /* We should never reach this... */
956 exit_tryhelp(2);
957 }
958
959 free(saddrs);
960 free(smasks);
961 free(daddrs);
962 free(dmasks);
963
964 nft_clear_iptables_command_state(&cs);
965 xtables_free_opts(1);
966
967 /* if (verbose > 1)
968 dump_entries(*handle);*/
969
970 return ret;
971 }
972