1 /* Code to take an arptables-style command line and do it. */ 2 3 /* 4 * arptables: 5 * Author: Bart De Schuymer <bdschuym (at) pandora.be>, but 6 * almost all code is from the iptables userspace program, which has main 7 * authors: Paul.Russell (at) rustcorp.com.au and mneuling (at) 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 */ 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 * 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 * 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 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 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 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 * 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 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 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 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 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 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 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 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