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
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 typedef char arpt_chainlabel[32];
57
58 #ifndef TRUE
59 #define TRUE 1
60 #endif
61 #ifndef FALSE
62 #define FALSE 0
63 #endif
64
65 /* XXX: command defined by nft-shared.h do not overlap with these two */
66 #undef CMD_CHECK
67 #undef CMD_RENAME_CHAIN
68
69 #define CMD_NONE 0x0000U
70 #define CMD_INSERT 0x0001U
71 #define CMD_DELETE 0x0002U
72 #define CMD_DELETE_NUM 0x0004U
73 #define CMD_REPLACE 0x0008U
74 #define CMD_APPEND 0x0010U
75 #define CMD_LIST 0x0020U
76 #define CMD_FLUSH 0x0040U
77 #define CMD_ZERO 0x0080U
78 #define CMD_NEW_CHAIN 0x0100U
79 #define CMD_DELETE_CHAIN 0x0200U
80 #define CMD_SET_POLICY 0x0400U
81 #define CMD_CHECK 0x0800U
82 #define CMD_RENAME_CHAIN 0x1000U
83 #define NUMBER_OF_CMD 13
84 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
85 'N', 'X', 'P', 'E' };
86
87 #define OPTION_OFFSET 256
88
89 #define OPT_NONE 0x00000U
90 #define OPT_NUMERIC 0x00001U
91 #define OPT_S_IP 0x00002U
92 #define OPT_D_IP 0x00004U
93 #define OPT_S_MAC 0x00008U
94 #define OPT_D_MAC 0x00010U
95 #define OPT_H_LENGTH 0x00020U
96 #define OPT_P_LENGTH 0x00040U
97 #define OPT_OPCODE 0x00080U
98 #define OPT_H_TYPE 0x00100U
99 #define OPT_P_TYPE 0x00200U
100 #define OPT_JUMP 0x00400U
101 #define OPT_VERBOSE 0x00800U
102 #define OPT_VIANAMEIN 0x01000U
103 #define OPT_VIANAMEOUT 0x02000U
104 #define OPT_LINENUMBERS 0x04000U
105 #define OPT_COUNTERS 0x08000U
106 #define NUMBER_OF_OPT 16
107 static const char optflags[NUMBER_OF_OPT]
108 = { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'};
109
110 static struct option original_opts[] = {
111 { "append", 1, 0, 'A' },
112 { "delete", 1, 0, 'D' },
113 { "insert", 1, 0, 'I' },
114 { "replace", 1, 0, 'R' },
115 { "list", 2, 0, 'L' },
116 { "flush", 2, 0, 'F' },
117 { "zero", 2, 0, 'Z' },
118 { "new-chain", 1, 0, 'N' },
119 { "delete-chain", 2, 0, 'X' },
120 { "rename-chain", 1, 0, 'E' },
121 { "policy", 1, 0, 'P' },
122 { "source-ip", 1, 0, 's' },
123 { "destination-ip", 1, 0, 'd' },
124 { "src-ip", 1, 0, 's' },
125 { "dst-ip", 1, 0, 'd' },
126 { "source-mac", 1, 0, 2},
127 { "destination-mac", 1, 0, 3},
128 { "src-mac", 1, 0, 2},
129 { "dst-mac", 1, 0, 3},
130 { "h-length", 1, 0, 'l' },
131 { "p-length", 1, 0, 8 },
132 { "opcode", 1, 0, 4 },
133 { "h-type", 1, 0, 5 },
134 { "proto-type", 1, 0, 6 },
135 { "in-interface", 1, 0, 'i' },
136 { "jump", 1, 0, 'j' },
137 { "table", 1, 0, 't' },
138 { "match", 1, 0, 'm' },
139 { "numeric", 0, 0, 'n' },
140 { "out-interface", 1, 0, 'o' },
141 { "verbose", 0, 0, 'v' },
142 { "exact", 0, 0, 'x' },
143 { "version", 0, 0, 'V' },
144 { "help", 2, 0, 'h' },
145 { "line-numbers", 0, 0, '0' },
146 { "modprobe", 1, 0, 'M' },
147 { 0 }
148 };
149
150 int RUNTIME_NF_ARP_NUMHOOKS = 3;
151
152 static struct option *opts = original_opts;
153 static unsigned int global_option_offset = 0;
154
155 extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
156 struct xtables_globals arptables_globals = {
157 .option_offset = 0,
158 .program_version = IPTABLES_VERSION,
159 .orig_opts = original_opts,
160 .exit_err = xtables_exit_error,
161 .compat_rev = nft_compatible_revision,
162 };
163
164 /* Table of legal combinations of commands and options. If any of the
165 * given commands make an option legal, that option is legal (applies to
166 * CMD_LIST and CMD_ZERO only).
167 * Key:
168 * + compulsory
169 * x illegal
170 * optional
171 */
172
173 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
174 /* Well, it's better than "Re: Linux vs FreeBSD" */
175 {
176 /* -n -s -d -p -j -v -x -i -o -f --line */
177 /*INSERT*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
178 /*DELETE*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
179 /*DELETE_NUM*/{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
180 /*REPLACE*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
181 /*APPEND*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
182 /*LIST*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
183 /*FLUSH*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
184 /*ZERO*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
185 /*NEW_CHAIN*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
186 /*DEL_CHAIN*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
187 /*SET_POLICY*/{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
188 /*CHECK*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
189 /*RENAME*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}
190 };
191
192 static int inverse_for_options[NUMBER_OF_OPT] =
193 {
194 /* -n */ 0,
195 /* -s */ ARPT_INV_SRCIP,
196 /* -d */ ARPT_INV_TGTIP,
197 /* 2 */ ARPT_INV_SRCDEVADDR,
198 /* 3 */ ARPT_INV_TGTDEVADDR,
199 /* -l */ ARPT_INV_ARPHLN,
200 /* 8 */ 0,
201 /* 4 */ ARPT_INV_ARPOP,
202 /* 5 */ ARPT_INV_ARPHRD,
203 /* 6 */ ARPT_INV_ARPPRO,
204 /* -j */ 0,
205 /* -v */ 0,
206 /* -i */ ARPT_INV_VIA_IN,
207 /* -o */ ARPT_INV_VIA_OUT,
208 /*--line*/ 0,
209 /* -c */ 0,
210 };
211
212 const char *program_version = XTABLES_VERSION;
213 const char *program_name = "arptables";
214
215 /* A few hardcoded protocols for 'all' and in case the user has no
216 /etc/protocols */
217 struct pprot {
218 char *name;
219 u_int8_t num;
220 };
221
222 /* Primitive headers... */
223 /* defined in netinet/in.h */
224 #if 0
225 #ifndef IPPROTO_ESP
226 #define IPPROTO_ESP 50
227 #endif
228 #ifndef IPPROTO_AH
229 #define IPPROTO_AH 51
230 #endif
231 #endif
232
233 /***********************************************/
234 /* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
235 /***********************************************/
236
237 unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
238 unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
239 unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
240 unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
241 unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
242 unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
243
244 /*
245 * put the mac address into 6 (ETH_ALEN) bytes
246 */
getmac_and_mask(char * from,char * to,char * mask)247 static int getmac_and_mask(char *from, char *to, char *mask)
248 {
249 char *p;
250 int i;
251 struct ether_addr *addr;
252
253 if (strcasecmp(from, "Unicast") == 0) {
254 memcpy(to, mac_type_unicast, ETH_ALEN);
255 memcpy(mask, msk_type_unicast, ETH_ALEN);
256 return 0;
257 }
258 if (strcasecmp(from, "Multicast") == 0) {
259 memcpy(to, mac_type_multicast, ETH_ALEN);
260 memcpy(mask, msk_type_multicast, ETH_ALEN);
261 return 0;
262 }
263 if (strcasecmp(from, "Broadcast") == 0) {
264 memcpy(to, mac_type_broadcast, ETH_ALEN);
265 memcpy(mask, msk_type_broadcast, ETH_ALEN);
266 return 0;
267 }
268 if ( (p = strrchr(from, '/')) != NULL) {
269 *p = '\0';
270 if (!(addr = ether_aton(p + 1)))
271 return -1;
272 memcpy(mask, addr, ETH_ALEN);
273 } else
274 memset(mask, 0xff, ETH_ALEN);
275 if (!(addr = ether_aton(from)))
276 return -1;
277 memcpy(to, addr, ETH_ALEN);
278 for (i = 0; i < ETH_ALEN; i++)
279 to[i] &= mask[i];
280 return 0;
281 }
282
getlength_and_mask(char * from,uint8_t * to,uint8_t * mask)283 static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
284 {
285 char *p, *buffer;
286 int i;
287
288 if ( (p = strrchr(from, '/')) != NULL) {
289 *p = '\0';
290 i = strtol(p+1, &buffer, 10);
291 if (*buffer != '\0' || i < 0 || i > 255)
292 return -1;
293 *mask = (uint8_t)i;
294 } else
295 *mask = 255;
296 i = strtol(from, &buffer, 10);
297 if (*buffer != '\0' || i < 0 || i > 255)
298 return -1;
299 *to = (uint8_t)i;
300 return 0;
301 }
302
get16_and_mask(char * from,uint16_t * to,uint16_t * mask,int base)303 static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
304 {
305 char *p, *buffer;
306 int i;
307
308 if ( (p = strrchr(from, '/')) != NULL) {
309 *p = '\0';
310 i = strtol(p+1, &buffer, base);
311 if (*buffer != '\0' || i < 0 || i > 65535)
312 return -1;
313 *mask = htons((uint16_t)i);
314 } else
315 *mask = 65535;
316 i = strtol(from, &buffer, base);
317 if (*buffer != '\0' || i < 0 || i > 65535)
318 return -1;
319 *to = htons((uint16_t)i);
320 return 0;
321 }
322
323 static int
string_to_number(const char * s,unsigned int min,unsigned int max,unsigned int * ret)324 string_to_number(const char *s, unsigned int min, unsigned int max,
325 unsigned int *ret)
326 {
327 long number;
328 char *end;
329
330 /* Handle hex, octal, etc. */
331 errno = 0;
332 number = strtol(s, &end, 0);
333 if (*end == '\0' && end != s) {
334 /* we parsed a number, let's see if we want this */
335 if (errno != ERANGE && min <= number && number <= max) {
336 *ret = number;
337 return 0;
338 }
339 }
340 return -1;
341 }
342
343 /*********************************************/
344 /* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
345 /*********************************************/
346
347 static struct in_addr *
dotted_to_addr(const char * dotted)348 dotted_to_addr(const char *dotted)
349 {
350 static struct in_addr addr;
351 unsigned char *addrp;
352 char *p, *q;
353 unsigned int onebyte;
354 int i;
355 char buf[20];
356
357 /* copy dotted string, because we need to modify it */
358 strncpy(buf, dotted, sizeof(buf) - 1);
359 addrp = (unsigned char *) &(addr.s_addr);
360
361 p = buf;
362 for (i = 0; i < 3; i++) {
363 if ((q = strchr(p, '.')) == NULL)
364 return (struct in_addr *) NULL;
365
366 *q = '\0';
367 if (string_to_number(p, 0, 255, &onebyte) == -1)
368 return (struct in_addr *) NULL;
369
370 addrp[i] = (unsigned char) onebyte;
371 p = q + 1;
372 }
373
374 /* we've checked 3 bytes, now we check the last one */
375 if (string_to_number(p, 0, 255, &onebyte) == -1)
376 return (struct in_addr *) NULL;
377
378 addrp[3] = (unsigned char) onebyte;
379
380 return &addr;
381 }
382
383 static struct in_addr *
network_to_addr(const char * name)384 network_to_addr(const char *name)
385 {
386 struct netent *net;
387 static struct in_addr addr;
388
389 if ((net = getnetbyname(name)) != NULL) {
390 if (net->n_addrtype != AF_INET)
391 return (struct in_addr *) NULL;
392 addr.s_addr = htonl((unsigned long) net->n_net);
393 return &addr;
394 }
395
396 return (struct in_addr *) NULL;
397 }
398
399 static void
inaddrcpy(struct in_addr * dst,struct in_addr * src)400 inaddrcpy(struct in_addr *dst, struct in_addr *src)
401 {
402 /* memcpy(dst, src, sizeof(struct in_addr)); */
403 dst->s_addr = src->s_addr;
404 }
405
406 static void
exit_tryhelp(int status)407 exit_tryhelp(int status)
408 {
409 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
410 program_name, program_name );
411 exit(status);
412 }
413
414 static void
exit_printhelp(void)415 exit_printhelp(void)
416 {
417 struct xtables_target *t = NULL;
418 int i;
419
420 printf("%s v%s\n\n"
421 "Usage: %s -[AD] chain rule-specification [options]\n"
422 " %s -[RI] chain rulenum rule-specification [options]\n"
423 " %s -D chain rulenum [options]\n"
424 " %s -[LFZ] [chain] [options]\n"
425 " %s -[NX] chain\n"
426 " %s -E old-chain-name new-chain-name\n"
427 " %s -P chain target [options]\n"
428 " %s -h (print this help information)\n\n",
429 program_name, program_version, program_name, program_name,
430 program_name, program_name, program_name, program_name,
431 program_name, program_name);
432
433 printf(
434 "Commands:\n"
435 "Either long or short options are allowed.\n"
436 " --append -A chain Append to chain\n"
437 " --delete -D chain Delete matching rule from chain\n"
438 " --delete -D chain rulenum\n"
439 " Delete rule rulenum (1 = first) from chain\n"
440 " --insert -I chain [rulenum]\n"
441 " Insert in chain as rulenum (default 1=first)\n"
442 " --replace -R chain rulenum\n"
443 " Replace rule rulenum (1 = first) in chain\n"
444 " --list -L [chain] List the rules in a chain or all chains\n"
445 " --flush -F [chain] Delete all rules in chain or all chains\n"
446 " --zero -Z [chain] Zero counters in chain or all chains\n"
447 " --new -N chain Create a new user-defined chain\n"
448 " --delete-chain\n"
449 " -X [chain] Delete a user-defined chain\n"
450 " --policy -P chain target\n"
451 " Change policy on chain to target\n"
452 " --rename-chain\n"
453 " -E old-chain new-chain\n"
454 " Change chain name, (moving any references)\n"
455
456 "Options:\n"
457 " --source-ip -s [!] address[/mask]\n"
458 " source specification\n"
459 " --destination-ip -d [!] address[/mask]\n"
460 " destination specification\n"
461 " --source-mac [!] address[/mask]\n"
462 " --destination-mac [!] address[/mask]\n"
463 " --h-length -l length[/mask] hardware length (nr of bytes)\n"
464 " --opcode code[/mask] operation code (2 bytes)\n"
465 " --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
466 " --proto-type type[/mask] protocol type (2 bytes)\n"
467 " --in-interface -i [!] input name[+]\n"
468 " network interface name ([+] for wildcard)\n"
469 " --out-interface -o [!] output name[+]\n"
470 " network interface name ([+] for wildcard)\n"
471 " --jump -j target\n"
472 " target for rule (may load target extension)\n"
473 " --match -m match\n"
474 " extended match (may load extension)\n"
475 " --numeric -n numeric output of addresses and ports\n"
476 " --table -t table table to manipulate (default: `filter')\n"
477 " --verbose -v verbose mode\n"
478 " --line-numbers print line numbers when listing\n"
479 " --exact -x expand numbers (display exact values)\n"
480 " --modprobe=<command> try to insert modules using this command\n"
481 " --set-counters PKTS BYTES set the counter during insert/append\n"
482 "[!] --version -V print package version.\n");
483 printf(" opcode strings: \n");
484 for (i = 0; i < NUMOPCODES; i++)
485 printf(" %d = %s\n", i + 1, opcodes[i]);
486 printf(
487 " hardware type string: 1 = Ethernet\n"
488 " protocol type string: 0x800 = IPv4\n");
489
490 /* Print out any special helps. A user might like to be able
491 to add a --help to the commandline, and see expected
492 results. So we call help for all matches & targets */
493 for (t = xtables_targets; t; t = t->next) {
494 if (strcmp(t->name, "CLASSIFY") && strcmp(t->name, "mangle"))
495 continue;
496 printf("\n");
497 t->help();
498 }
499 exit(0);
500 }
501
502 static void
generic_opt_check(int command,int options)503 generic_opt_check(int command, int options)
504 {
505 int i, j, legal = 0;
506
507 /* Check that commands are valid with options. Complicated by the
508 * fact that if an option is legal with *any* command given, it is
509 * legal overall (ie. -z and -l).
510 */
511 for (i = 0; i < NUMBER_OF_OPT; i++) {
512 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
513
514 for (j = 0; j < NUMBER_OF_CMD; j++) {
515 if (!(command & (1<<j)))
516 continue;
517
518 if (!(options & (1<<i))) {
519 if (commands_v_options[j][i] == '+')
520 xtables_error(PARAMETER_PROBLEM,
521 "You need to supply the `-%c' "
522 "option for this command\n",
523 optflags[i]);
524 } else {
525 if (commands_v_options[j][i] != 'x')
526 legal = 1;
527 else if (legal == 0)
528 legal = -1;
529 }
530 }
531 if (legal == -1)
532 xtables_error(PARAMETER_PROBLEM,
533 "Illegal option `-%c' with this command\n",
534 optflags[i]);
535 }
536 }
537
538 static char
opt2char(int option)539 opt2char(int option)
540 {
541 const char *ptr;
542 for (ptr = optflags; option > 1; option >>= 1, ptr++);
543
544 return *ptr;
545 }
546
547 static char
cmd2char(int option)548 cmd2char(int option)
549 {
550 const char *ptr;
551 for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
552
553 return *ptr;
554 }
555
556 static void
add_command(unsigned int * cmd,const int newcmd,const unsigned int othercmds,int invert)557 add_command(unsigned int *cmd, const int newcmd, const unsigned int othercmds, int invert)
558 {
559 if (invert)
560 xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
561 if (*cmd & (~othercmds))
562 xtables_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
563 cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
564 *cmd |= newcmd;
565 }
566
567 static int
check_inverse(const char option[],int * invert,int * optidx,int argc)568 check_inverse(const char option[], int *invert, int *optidx, int argc)
569 {
570 if (option && strcmp(option, "!") == 0) {
571 if (*invert)
572 xtables_error(PARAMETER_PROBLEM,
573 "Multiple `!' flags not allowed");
574 *invert = TRUE;
575 if (optidx) {
576 *optidx = *optidx+1;
577 if (argc && *optidx > argc)
578 xtables_error(PARAMETER_PROBLEM,
579 "no argument following `!'");
580 }
581
582 return TRUE;
583 }
584 return FALSE;
585 }
586
587 static struct in_addr *
host_to_addr(const char * name,unsigned int * naddr)588 host_to_addr(const char *name, unsigned int *naddr)
589 {
590 struct in_addr *addr;
591 struct addrinfo hints;
592 struct addrinfo *res, *p;
593 int err;
594 unsigned int i;
595
596 memset(&hints, 0, sizeof(hints));
597 hints.ai_flags = AI_CANONNAME;
598 hints.ai_family = AF_INET;
599 hints.ai_socktype = SOCK_RAW;
600
601 *naddr = 0;
602 err = getaddrinfo(name, NULL, &hints, &res);
603 if (err != 0)
604 return NULL;
605 else {
606 for (p = res; p != NULL; p = p->ai_next)
607 (*naddr)++;
608 addr = xtables_calloc(*naddr, sizeof(struct in_addr));
609 for (i = 0, p = res; p != NULL; p = p->ai_next)
610 memcpy(&addr[i++],
611 &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
612 sizeof(struct in_addr));
613 freeaddrinfo(res);
614 return addr;
615 }
616
617 return (struct in_addr *) NULL;
618 }
619
620 /*
621 * All functions starting with "parse" should succeed, otherwise
622 * the program fails.
623 * Most routines return pointers to static data that may change
624 * between calls to the same or other routines with a few exceptions:
625 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
626 * return global static data.
627 */
628
629 static struct in_addr *
parse_hostnetwork(const char * name,unsigned int * naddrs)630 parse_hostnetwork(const char *name, unsigned int *naddrs)
631 {
632 struct in_addr *addrp, *addrptmp;
633
634 if ((addrptmp = dotted_to_addr(name)) != NULL ||
635 (addrptmp = network_to_addr(name)) != NULL) {
636 addrp = xtables_malloc(sizeof(struct in_addr));
637 inaddrcpy(addrp, addrptmp);
638 *naddrs = 1;
639 return addrp;
640 }
641 if ((addrp = host_to_addr(name, naddrs)) != NULL)
642 return addrp;
643
644 xtables_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
645 }
646
647 static struct in_addr *
parse_mask(char * mask)648 parse_mask(char *mask)
649 {
650 static struct in_addr maskaddr;
651 struct in_addr *addrp;
652 unsigned int bits;
653
654 if (mask == NULL) {
655 /* no mask at all defaults to 32 bits */
656 maskaddr.s_addr = 0xFFFFFFFF;
657 return &maskaddr;
658 }
659 if ((addrp = dotted_to_addr(mask)) != NULL)
660 /* dotted_to_addr already returns a network byte order addr */
661 return addrp;
662 if (string_to_number(mask, 0, 32, &bits) == -1)
663 xtables_error(PARAMETER_PROBLEM,
664 "invalid mask `%s' specified", mask);
665 if (bits != 0) {
666 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
667 return &maskaddr;
668 }
669
670 maskaddr.s_addr = 0L;
671 return &maskaddr;
672 }
673
674 static void
parse_hostnetworkmask(const char * name,struct in_addr ** addrpp,struct in_addr * maskp,unsigned int * naddrs)675 parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
676 struct in_addr *maskp, unsigned int *naddrs)
677 {
678 struct in_addr *addrp;
679 char buf[256];
680 char *p;
681 int i, j, k, n;
682
683 strncpy(buf, name, sizeof(buf) - 1);
684 if ((p = strrchr(buf, '/')) != NULL) {
685 *p = '\0';
686 addrp = parse_mask(p + 1);
687 } else
688 addrp = parse_mask(NULL);
689 inaddrcpy(maskp, addrp);
690
691 /* if a null mask is given, the name is ignored, like in "any/0" */
692 if (maskp->s_addr == 0L)
693 strcpy(buf, "0.0.0.0");
694
695 addrp = *addrpp = parse_hostnetwork(buf, naddrs);
696 n = *naddrs;
697 for (i = 0, j = 0; i < n; i++) {
698 addrp[j++].s_addr &= maskp->s_addr;
699 for (k = 0; k < j - 1; k++) {
700 if (addrp[k].s_addr == addrp[j - 1].s_addr) {
701 (*naddrs)--;
702 j--;
703 break;
704 }
705 }
706 }
707 }
708
709 static void
parse_interface(const char * arg,char * vianame,unsigned char * mask)710 parse_interface(const char *arg, char *vianame, unsigned char *mask)
711 {
712 int vialen = strlen(arg);
713 unsigned int i;
714
715 memset(mask, 0, IFNAMSIZ);
716 memset(vianame, 0, IFNAMSIZ);
717
718 if (vialen + 1 > IFNAMSIZ)
719 xtables_error(PARAMETER_PROBLEM,
720 "interface name `%s' must be shorter than IFNAMSIZ"
721 " (%i)", arg, IFNAMSIZ-1);
722
723 strcpy(vianame, arg);
724 if (vialen == 0)
725 memset(mask, 0, IFNAMSIZ);
726 else if (vianame[vialen - 1] == '+') {
727 memset(mask, 0xFF, vialen - 1);
728 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
729 /* Don't remove `+' here! -HW */
730 } else {
731 /* Include nul-terminator in match */
732 memset(mask, 0xFF, vialen + 1);
733 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
734 for (i = 0; vianame[i]; i++) {
735 if (!isalnum(vianame[i])
736 && vianame[i] != '_'
737 && vianame[i] != '.') {
738 printf("Warning: weird character in interface"
739 " `%s' (No aliases, :, ! or *).\n",
740 vianame);
741 break;
742 }
743 }
744 }
745 }
746
747 /* Can't be zero. */
748 static int
parse_rulenumber(const char * rule)749 parse_rulenumber(const char *rule)
750 {
751 unsigned int rulenum;
752
753 if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
754 xtables_error(PARAMETER_PROBLEM,
755 "Invalid rule number `%s'", rule);
756
757 return rulenum;
758 }
759
760 static const char *
parse_target(const char * targetname)761 parse_target(const char *targetname)
762 {
763 const char *ptr;
764
765 if (strlen(targetname) < 1)
766 xtables_error(PARAMETER_PROBLEM,
767 "Invalid target name (too short)");
768
769 if (strlen(targetname)+1 > sizeof(arpt_chainlabel))
770 xtables_error(PARAMETER_PROBLEM,
771 "Invalid target name `%s' (%zu chars max)",
772 targetname, sizeof(arpt_chainlabel)-1);
773
774 for (ptr = targetname; *ptr; ptr++)
775 if (isspace(*ptr))
776 xtables_error(PARAMETER_PROBLEM,
777 "Invalid target name `%s'", targetname);
778 return targetname;
779 }
780
781 static void
set_option(unsigned int * options,unsigned int option,u_int16_t * invflg,int invert)782 set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
783 int invert)
784 {
785 if (*options & option)
786 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
787 opt2char(option));
788 *options |= option;
789
790 if (invert) {
791 unsigned int i;
792 for (i = 0; 1 << i != option; i++);
793
794 if (!inverse_for_options[i])
795 xtables_error(PARAMETER_PROBLEM,
796 "cannot have ! before -%c",
797 opt2char(option));
798 *invflg |= inverse_for_options[i];
799 }
800 }
801
802 static int
list_entries(struct nft_handle * h,const char * chain,const char * table,int rulenum,int verbose,int numeric,int expanded,int linenumbers)803 list_entries(struct nft_handle *h, const char *chain, const char *table,
804 int rulenum, int verbose, int numeric, int expanded,
805 int linenumbers)
806 {
807 unsigned int format;
808
809 format = FMT_OPTIONS;
810 if (!verbose)
811 format |= FMT_NOCOUNTS;
812 else
813 format |= FMT_VIA;
814
815 if (numeric)
816 format |= FMT_NUMERIC;
817
818 if (!expanded)
819 format |= FMT_KILOMEGAGIGA;
820
821 if (linenumbers)
822 format |= FMT_LINENUMBERS;
823
824 return nft_rule_list(h, chain, table, rulenum, format);
825 }
826
command_jump(struct arpt_entry * fw,const char * jumpto)827 static struct xtables_target *command_jump(struct arpt_entry *fw,
828 const char *jumpto)
829 {
830 struct xtables_target *target;
831 size_t size;
832
833 /* XTF_TRY_LOAD (may be chain name) */
834 target = xtables_find_target(jumpto, XTF_TRY_LOAD);
835
836 if (!target)
837 return NULL;
838
839 size = XT_ALIGN(sizeof(struct xt_entry_target))
840 + target->size;
841
842 target->t = xtables_calloc(1, size);
843 target->t->u.target_size = size;
844 strncpy(target->t->u.user.name, jumpto, sizeof(target->t->u.user.name));
845 target->t->u.user.name[sizeof(target->t->u.user.name)-1] = '\0';
846 target->t->u.user.revision = target->revision;
847
848 xs_init_target(target);
849
850 if (target->x6_options != NULL)
851 opts = xtables_options_xfrm(arptables_globals.orig_opts,
852 opts, target->x6_options,
853 &target->option_offset);
854 else
855 opts = xtables_merge_options(arptables_globals.orig_opts,
856 opts, target->extra_opts,
857 &target->option_offset);
858
859 return target;
860 }
861
862 static int
append_entry(struct nft_handle * h,const char * chain,const char * table,struct arptables_command_state * cs,int rulenum,unsigned int nsaddrs,const struct in_addr saddrs[],unsigned int ndaddrs,const struct in_addr daddrs[],bool verbose,bool append)863 append_entry(struct nft_handle *h,
864 const char *chain,
865 const char *table,
866 struct arptables_command_state *cs,
867 int rulenum,
868 unsigned int nsaddrs,
869 const struct in_addr saddrs[],
870 unsigned int ndaddrs,
871 const struct in_addr daddrs[],
872 bool verbose, bool append)
873 {
874 unsigned int i, j;
875 int ret = 1;
876
877 for (i = 0; i < nsaddrs; i++) {
878 cs->fw.arp.src.s_addr = saddrs[i].s_addr;
879 for (j = 0; j < ndaddrs; j++) {
880 cs->fw.arp.tgt.s_addr = daddrs[j].s_addr;
881 if (append) {
882 ret = nft_rule_append(h, chain, table, cs, 0,
883 verbose);
884 } else {
885 ret = nft_rule_insert(h, chain, table, cs,
886 rulenum, verbose);
887 }
888 }
889 }
890
891 return ret;
892 }
893
894 static int
replace_entry(const char * chain,const char * table,struct arptables_command_state * cs,unsigned int rulenum,const struct in_addr * saddr,const struct in_addr * daddr,bool verbose,struct nft_handle * h)895 replace_entry(const char *chain,
896 const char *table,
897 struct arptables_command_state *cs,
898 unsigned int rulenum,
899 const struct in_addr *saddr,
900 const struct in_addr *daddr,
901 bool verbose, struct nft_handle *h)
902 {
903 cs->fw.arp.src.s_addr = saddr->s_addr;
904 cs->fw.arp.tgt.s_addr = daddr->s_addr;
905
906 return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
907 }
908
909 static int
delete_entry(const char * chain,const char * table,struct arptables_command_state * cs,unsigned int nsaddrs,const struct in_addr saddrs[],unsigned int ndaddrs,const struct in_addr daddrs[],bool verbose,struct nft_handle * h)910 delete_entry(const char *chain,
911 const char *table,
912 struct arptables_command_state *cs,
913 unsigned int nsaddrs,
914 const struct in_addr saddrs[],
915 unsigned int ndaddrs,
916 const struct in_addr daddrs[],
917 bool verbose, struct nft_handle *h)
918 {
919 unsigned int i, j;
920 int ret = 1;
921
922 for (i = 0; i < nsaddrs; i++) {
923 cs->fw.arp.src.s_addr = saddrs[i].s_addr;
924 for (j = 0; j < ndaddrs; j++) {
925 cs->fw.arp.tgt.s_addr = daddrs[j].s_addr;
926 ret = nft_rule_delete(h, chain, table, cs, verbose);
927 }
928 }
929
930 return ret;
931 }
932
do_commandarp(struct nft_handle * h,int argc,char * argv[],char ** table)933 int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
934 {
935 struct arptables_command_state cs;
936 int invert = 0;
937 unsigned int nsaddrs = 0, ndaddrs = 0;
938 struct in_addr *saddrs = NULL, *daddrs = NULL;
939
940 int c, verbose = 0;
941 const char *chain = NULL;
942 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
943 const char *policy = NULL, *newname = NULL;
944 unsigned int rulenum = 0, options = 0, command = 0;
945 const char *pcnt = NULL, *bcnt = NULL;
946 int ret = 1;
947 struct xtables_target *t;
948
949 memset(&cs, 0, sizeof(cs));
950 cs.jumpto = "";
951
952 opts = original_opts;
953 global_option_offset = 0;
954
955 xtables_globals.orig_opts = original_opts;
956
957 /* re-set optind to 0 in case do_command gets called
958 * a second time */
959 optind = 0;
960
961 for (t = xtables_targets; t; t = t->next) {
962 t->tflags = 0;
963 t->used = 0;
964 }
965
966 /* Suppress error messages: we may add new options if we
967 demand-load a protocol. */
968 opterr = 0;
969
970 while ((c = getopt_long(argc, argv,
971 "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:",
972 opts, NULL)) != -1) {
973 switch (c) {
974 /*
975 * Command selection
976 */
977 case 'A':
978 add_command(&command, CMD_APPEND, CMD_NONE,
979 invert);
980 chain = optarg;
981 break;
982
983 case 'D':
984 add_command(&command, CMD_DELETE, CMD_NONE,
985 invert);
986 chain = optarg;
987 if (xs_has_arg(argc, argv)) {
988 rulenum = parse_rulenumber(argv[optind++]);
989 command = CMD_DELETE_NUM;
990 }
991 break;
992
993 case 'R':
994 add_command(&command, CMD_REPLACE, CMD_NONE,
995 invert);
996 chain = optarg;
997 if (xs_has_arg(argc, argv))
998 rulenum = parse_rulenumber(argv[optind++]);
999 else
1000 xtables_error(PARAMETER_PROBLEM,
1001 "-%c requires a rule number",
1002 cmd2char(CMD_REPLACE));
1003 break;
1004
1005 case 'I':
1006 add_command(&command, CMD_INSERT, CMD_NONE,
1007 invert);
1008 chain = optarg;
1009 if (xs_has_arg(argc, argv))
1010 rulenum = parse_rulenumber(argv[optind++]);
1011 else rulenum = 1;
1012 break;
1013
1014 case 'L':
1015 add_command(&command, CMD_LIST, CMD_ZERO,
1016 invert);
1017 if (optarg) chain = optarg;
1018 else if (xs_has_arg(argc, argv))
1019 chain = argv[optind++];
1020 break;
1021
1022 case 'F':
1023 add_command(&command, CMD_FLUSH, CMD_NONE,
1024 invert);
1025 if (optarg) chain = optarg;
1026 else if (xs_has_arg(argc, argv))
1027 chain = argv[optind++];
1028 break;
1029
1030 case 'Z':
1031 add_command(&command, CMD_ZERO, CMD_LIST,
1032 invert);
1033 if (optarg) chain = optarg;
1034 else if (xs_has_arg(argc, argv))
1035 chain = argv[optind++];
1036 break;
1037
1038 case 'N':
1039 if (optarg && *optarg == '-')
1040 xtables_error(PARAMETER_PROBLEM,
1041 "chain name not allowed to start "
1042 "with `-'\n");
1043 if (xtables_find_target(optarg, XTF_TRY_LOAD))
1044 xtables_error(PARAMETER_PROBLEM,
1045 "chain name may not clash "
1046 "with target name\n");
1047 add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
1048 invert);
1049 chain = optarg;
1050 break;
1051
1052 case 'X':
1053 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
1054 invert);
1055 if (optarg) chain = optarg;
1056 else if (xs_has_arg(argc, argv))
1057 chain = argv[optind++];
1058 break;
1059
1060 case 'E':
1061 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
1062 invert);
1063 chain = optarg;
1064 if (xs_has_arg(argc, argv))
1065 newname = argv[optind++];
1066 else
1067 xtables_error(PARAMETER_PROBLEM,
1068 "-%c requires old-chain-name and "
1069 "new-chain-name",
1070 cmd2char(CMD_RENAME_CHAIN));
1071 break;
1072
1073 case 'P':
1074 add_command(&command, CMD_SET_POLICY, CMD_NONE,
1075 invert);
1076 chain = optarg;
1077 if (xs_has_arg(argc, argv))
1078 policy = argv[optind++];
1079 else
1080 xtables_error(PARAMETER_PROBLEM,
1081 "-%c requires a chain and a policy",
1082 cmd2char(CMD_SET_POLICY));
1083 break;
1084
1085 case 'h':
1086 if (!optarg)
1087 optarg = argv[optind];
1088
1089 exit_printhelp();
1090 break;
1091 case 's':
1092 check_inverse(optarg, &invert, &optind, argc);
1093 set_option(&options, OPT_S_IP, &cs.fw.arp.invflags,
1094 invert);
1095 shostnetworkmask = argv[optind-1];
1096 break;
1097
1098 case 'd':
1099 check_inverse(optarg, &invert, &optind, argc);
1100 set_option(&options, OPT_D_IP, &cs.fw.arp.invflags,
1101 invert);
1102 dhostnetworkmask = argv[optind-1];
1103 break;
1104
1105 case 2:/* src-mac */
1106 check_inverse(optarg, &invert, &optind, argc);
1107 set_option(&options, OPT_S_MAC, &cs.fw.arp.invflags,
1108 invert);
1109 if (getmac_and_mask(argv[optind - 1],
1110 cs.fw.arp.src_devaddr.addr, cs.fw.arp.src_devaddr.mask))
1111 xtables_error(PARAMETER_PROBLEM, "Problem with specified "
1112 "source mac");
1113 break;
1114
1115 case 3:/* dst-mac */
1116 check_inverse(optarg, &invert, &optind, argc);
1117 set_option(&options, OPT_D_MAC, &cs.fw.arp.invflags,
1118 invert);
1119
1120 if (getmac_and_mask(argv[optind - 1],
1121 cs.fw.arp.tgt_devaddr.addr, cs.fw.arp.tgt_devaddr.mask))
1122 xtables_error(PARAMETER_PROBLEM, "Problem with specified "
1123 "destination mac");
1124 break;
1125
1126 case 'l':/* hardware length */
1127 check_inverse(optarg, &invert, &optind, argc);
1128 set_option(&options, OPT_H_LENGTH, &cs.fw.arp.invflags,
1129 invert);
1130 getlength_and_mask(argv[optind - 1], &cs.fw.arp.arhln,
1131 &cs.fw.arp.arhln_mask);
1132
1133 if (cs.fw.arp.arhln != 6) {
1134 xtables_error(PARAMETER_PROBLEM,
1135 "Only harware address length of"
1136 " 6 is supported currently.");
1137 }
1138
1139 break;
1140
1141 case 8:/* protocol length */
1142 xtables_error(PARAMETER_PROBLEM, "not supported");
1143 /*
1144 check_inverse(optarg, &invert, &optind, argc);
1145 set_option(&options, OPT_P_LENGTH, &cs.fw.arp.invflags,
1146 invert);
1147
1148 getlength_and_mask(argv[optind - 1], &cs.fw.arp.arpln,
1149 &cs.fw.arp.arpln_mask);
1150 break;
1151 */
1152
1153 case 4:/* opcode */
1154 check_inverse(optarg, &invert, &optind, argc);
1155 set_option(&options, OPT_OPCODE, &cs.fw.arp.invflags,
1156 invert);
1157 if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpop,
1158 &cs.fw.arp.arpop_mask, 10)) {
1159 int i;
1160
1161 for (i = 0; i < NUMOPCODES; i++)
1162 if (!strcasecmp(opcodes[i], optarg))
1163 break;
1164 if (i == NUMOPCODES)
1165 xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
1166 cs.fw.arp.arpop = htons(i+1);
1167 }
1168 break;
1169
1170 case 5:/* h-type */
1171 check_inverse(optarg, &invert, &optind, argc);
1172 set_option(&options, OPT_H_TYPE, &cs.fw.arp.invflags,
1173 invert);
1174 if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arhrd,
1175 &cs.fw.arp.arhrd_mask, 16)) {
1176 if (strcasecmp(argv[optind-1], "Ethernet"))
1177 xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
1178 cs.fw.arp.arhrd = htons(1);
1179 }
1180 break;
1181
1182 case 6:/* proto-type */
1183 check_inverse(optarg, &invert, &optind, argc);
1184 set_option(&options, OPT_P_TYPE, &cs.fw.arp.invflags,
1185 invert);
1186 if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpro,
1187 &cs.fw.arp.arpro_mask, 0)) {
1188 if (strcasecmp(argv[optind-1], "ipv4"))
1189 xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
1190 cs.fw.arp.arpro = htons(0x800);
1191 }
1192 break;
1193
1194 case 'j':
1195 set_option(&options, OPT_JUMP, &cs.fw.arp.invflags,
1196 invert);
1197 cs.jumpto = parse_target(optarg);
1198 cs.target = command_jump(&cs.fw, cs.jumpto);
1199 break;
1200
1201 case 'i':
1202 check_inverse(optarg, &invert, &optind, argc);
1203 set_option(&options, OPT_VIANAMEIN, &cs.fw.arp.invflags,
1204 invert);
1205 parse_interface(argv[optind-1],
1206 cs.fw.arp.iniface,
1207 cs.fw.arp.iniface_mask);
1208 /* cs.fw.nfcache |= NFC_IP_IF_IN; */
1209 break;
1210
1211 case 'o':
1212 check_inverse(optarg, &invert, &optind, argc);
1213 set_option(&options, OPT_VIANAMEOUT, &cs.fw.arp.invflags,
1214 invert);
1215 parse_interface(argv[optind-1],
1216 cs.fw.arp.outiface,
1217 cs.fw.arp.outiface_mask);
1218 /* cs.fw.nfcache |= NFC_IP_IF_OUT; */
1219 break;
1220
1221 case 'v':
1222 if (!verbose)
1223 set_option(&options, OPT_VERBOSE,
1224 &cs.fw.arp.invflags, invert);
1225 verbose++;
1226 break;
1227
1228 case 'm': /*{
1229 size_t size;
1230
1231 if (invert)
1232 exit_error(PARAMETER_PROBLEM,
1233 "unexpected ! flag before --match");
1234
1235 m = find_match(optarg, LOAD_MUST_SUCCEED);
1236 size = ARPT_ALIGN(sizeof(struct arpt_entry_match))
1237 + m->size;
1238 m->m = fw_calloc(1, size);
1239 m->m->u.match_size = size;
1240 strcpy(m->m->u.user.name, m->name);
1241 m->init(m->m, &fw.nfcache);
1242 opts = merge_options(opts, m->extra_opts, &m->option_offset);
1243 }*/
1244 break;
1245
1246 case 'n':
1247 set_option(&options, OPT_NUMERIC, &cs.fw.arp.invflags,
1248 invert);
1249 break;
1250
1251 case 't':
1252 if (invert)
1253 xtables_error(PARAMETER_PROBLEM,
1254 "unexpected ! flag before --table");
1255 *table = argv[optind-1];
1256 break;
1257
1258 case 'V':
1259 if (invert)
1260 printf("Not %s ;-)\n", program_version);
1261 else
1262 printf("%s v%s\n",
1263 program_name, program_version);
1264 exit(0);
1265
1266 case '0':
1267 set_option(&options, OPT_LINENUMBERS, &cs.fw.arp.invflags,
1268 invert);
1269 break;
1270
1271 case 'M':
1272 //modprobe = optarg;
1273 break;
1274
1275 case 'c':
1276
1277 set_option(&options, OPT_COUNTERS, &cs.fw.arp.invflags,
1278 invert);
1279 pcnt = optarg;
1280 if (xs_has_arg(argc, argv))
1281 bcnt = argv[optind++];
1282 else
1283 xtables_error(PARAMETER_PROBLEM,
1284 "-%c requires packet and byte counter",
1285 opt2char(OPT_COUNTERS));
1286
1287 if (sscanf(pcnt, "%llu", &cs.fw.counters.pcnt) != 1)
1288 xtables_error(PARAMETER_PROBLEM,
1289 "-%c packet counter not numeric",
1290 opt2char(OPT_COUNTERS));
1291
1292 if (sscanf(bcnt, "%llu", &cs.fw.counters.bcnt) != 1)
1293 xtables_error(PARAMETER_PROBLEM,
1294 "-%c byte counter not numeric",
1295 opt2char(OPT_COUNTERS));
1296
1297 break;
1298
1299
1300 case 1: /* non option */
1301 if (optarg[0] == '!' && optarg[1] == '\0') {
1302 if (invert)
1303 xtables_error(PARAMETER_PROBLEM,
1304 "multiple consecutive ! not"
1305 " allowed");
1306 invert = TRUE;
1307 optarg[0] = '\0';
1308 continue;
1309 }
1310 printf("Bad argument `%s'\n", optarg);
1311 exit_tryhelp(2);
1312
1313 default:
1314 if (cs.target) {
1315 xtables_option_tpcall(c, argv,
1316 invert, cs.target, &cs.fw);
1317 }
1318 break;
1319 }
1320 invert = FALSE;
1321 }
1322
1323 if (cs.target)
1324 xtables_option_tfcall(cs.target);
1325
1326 if (optind < argc)
1327 xtables_error(PARAMETER_PROBLEM,
1328 "unknown arguments found on commandline");
1329 if (!command)
1330 xtables_error(PARAMETER_PROBLEM, "no command specified");
1331 if (invert)
1332 xtables_error(PARAMETER_PROBLEM,
1333 "nothing appropriate following !");
1334
1335 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
1336 if (!(options & OPT_D_IP))
1337 dhostnetworkmask = "0.0.0.0/0";
1338 if (!(options & OPT_S_IP))
1339 shostnetworkmask = "0.0.0.0/0";
1340 }
1341
1342 if (shostnetworkmask)
1343 parse_hostnetworkmask(shostnetworkmask, &saddrs,
1344 &(cs.fw.arp.smsk), &nsaddrs);
1345
1346 if (dhostnetworkmask)
1347 parse_hostnetworkmask(dhostnetworkmask, &daddrs,
1348 &(cs.fw.arp.tmsk), &ndaddrs);
1349
1350 if ((nsaddrs > 1 || ndaddrs > 1) &&
1351 (cs.fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
1352 xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
1353 " source or destination IP addresses");
1354
1355 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
1356 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1357 "specify a unique address");
1358
1359 generic_opt_check(command, options);
1360
1361 if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
1362 xtables_error(PARAMETER_PROBLEM,
1363 "chain name `%s' too long (must be under %i chars)",
1364 chain, ARPT_FUNCTION_MAXNAMELEN);
1365
1366 if (nft_init(h, xtables_arp) < 0)
1367 xtables_error(OTHER_PROBLEM,
1368 "Could not initialize nftables layer.");
1369
1370 h->ops = nft_family_ops_lookup(h->family);
1371 if (h->ops == NULL)
1372 xtables_error(PARAMETER_PROBLEM, "Unknown family");
1373
1374 if (command == CMD_APPEND
1375 || command == CMD_DELETE
1376 || command == CMD_INSERT
1377 || command == CMD_REPLACE) {
1378 if (strcmp(chain, "PREROUTING") == 0
1379 || strcmp(chain, "INPUT") == 0) {
1380 /* -o not valid with incoming packets. */
1381 if (options & OPT_VIANAMEOUT)
1382 xtables_error(PARAMETER_PROBLEM,
1383 "Can't use -%c with %s\n",
1384 opt2char(OPT_VIANAMEOUT),
1385 chain);
1386 }
1387
1388 if (strcmp(chain, "POSTROUTING") == 0
1389 || strcmp(chain, "OUTPUT") == 0) {
1390 /* -i not valid with outgoing packets */
1391 if (options & OPT_VIANAMEIN)
1392 xtables_error(PARAMETER_PROBLEM,
1393 "Can't use -%c with %s\n",
1394 opt2char(OPT_VIANAMEIN),
1395 chain);
1396 }
1397
1398 if (!cs.target && strlen(cs.jumpto) != 0) {
1399 size_t size;
1400
1401 cs.target = xtables_find_target(XT_STANDARD_TARGET,
1402 XTF_LOAD_MUST_SUCCEED);
1403 size = sizeof(struct arpt_entry_target) + cs.target->size;
1404 cs.target->t = xtables_calloc(1, size);
1405 cs.target->t->u.target_size = size;
1406 strcpy(cs.target->t->u.user.name, cs.jumpto);
1407 }
1408 }
1409
1410 switch (command) {
1411 case CMD_APPEND:
1412 ret = append_entry(h, chain, *table, &cs, 0,
1413 nsaddrs, saddrs, ndaddrs, daddrs,
1414 options&OPT_VERBOSE, true);
1415 break;
1416 case CMD_DELETE:
1417 ret = delete_entry(chain, *table, &cs,
1418 nsaddrs, saddrs, ndaddrs, daddrs,
1419 options&OPT_VERBOSE, h);
1420 break;
1421 case CMD_DELETE_NUM:
1422 ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
1423 break;
1424 case CMD_REPLACE:
1425 ret = replace_entry(chain, *table, &cs, rulenum - 1,
1426 saddrs, daddrs, options&OPT_VERBOSE, h);
1427 break;
1428 case CMD_INSERT:
1429 ret = append_entry(h, chain, *table, &cs, rulenum - 1,
1430 nsaddrs, saddrs, ndaddrs, daddrs,
1431 options&OPT_VERBOSE, false);
1432 break;
1433 case CMD_LIST:
1434 ret = list_entries(h, chain, *table,
1435 rulenum,
1436 options&OPT_VERBOSE,
1437 options&OPT_NUMERIC,
1438 /*options&OPT_EXPANDED*/0,
1439 options&OPT_LINENUMBERS);
1440 break;
1441 case CMD_FLUSH:
1442 ret = nft_rule_flush(h, chain, *table);
1443 break;
1444 case CMD_ZERO:
1445 ret = nft_chain_zero_counters(h, chain, *table);
1446 break;
1447 case CMD_LIST|CMD_ZERO:
1448 ret = list_entries(h, chain, *table, rulenum,
1449 options&OPT_VERBOSE,
1450 options&OPT_NUMERIC,
1451 /*options&OPT_EXPANDED*/0,
1452 options&OPT_LINENUMBERS);
1453 if (ret)
1454 ret = nft_chain_zero_counters(h, chain, *table);
1455 break;
1456 case CMD_NEW_CHAIN:
1457 ret = nft_chain_user_add(h, chain, *table);
1458 break;
1459 case CMD_DELETE_CHAIN:
1460 ret = nft_chain_user_del(h, chain, *table);
1461 break;
1462 case CMD_RENAME_CHAIN:
1463 ret = nft_chain_user_rename(h, chain, *table, newname);
1464 break;
1465 case CMD_SET_POLICY:
1466 ret = nft_chain_set(h, *table, chain, policy, NULL);
1467 if (ret < 0)
1468 xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
1469 policy);
1470 break;
1471 default:
1472 /* We should never reach this... */
1473 exit_tryhelp(2);
1474 }
1475
1476 /* if (verbose > 1)
1477 dump_entries(*handle);*/
1478
1479 return ret;
1480 }
1481