diff options
Diffstat (limited to 'ip6tables.c')
-rw-r--r-- | ip6tables.c | 1792 |
1 files changed, 656 insertions, 1136 deletions
diff --git a/ip6tables.c b/ip6tables.c index 211b81a..e2359df 100644 --- a/ip6tables.c +++ b/ip6tables.c @@ -31,17 +31,19 @@ #include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <dlfcn.h> #include <ctype.h> #include <stdarg.h> +#include <stdbool.h> #include <limits.h> #include <ip6tables.h> +#include <xtables.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> -#include <sys/wait.h> #include <sys/types.h> #include <sys/socket.h> +#include "ip6tables-multi.h" +#include "xshared.h" #ifndef TRUE #define TRUE 1 @@ -50,10 +52,6 @@ #define FALSE 0 #endif -#ifndef PROC_SYS_MODPROBE -#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" -#endif - #define FMT_NUMERIC 0x0001 #define FMT_NOCOUNTS 0x0002 #define FMT_KILOMEGAGIGA 0x0004 @@ -82,11 +80,11 @@ #define CMD_DELETE_CHAIN 0x0200U #define CMD_SET_POLICY 0x0400U #define CMD_RENAME_CHAIN 0x0800U -#define NUMBER_OF_CMD 13 +#define CMD_LIST_RULES 0x1000U +#define CMD_ZERO_NUM 0x2000U +#define NUMBER_OF_CMD 15 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', - 'N', 'X', 'P', 'E' }; - -#define OPTION_OFFSET 256 + 'Z', 'N', 'X', 'P', 'E', 'S' }; #define OPT_NONE 0x00000U #define OPT_NUMERIC 0x00001U @@ -105,36 +103,38 @@ static const char optflags[NUMBER_OF_OPT] = { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'}; static struct option original_opts[] = { - { "append", 1, 0, 'A' }, - { "delete", 1, 0, 'D' }, - { "insert", 1, 0, 'I' }, - { "replace", 1, 0, 'R' }, - { "list", 2, 0, 'L' }, - { "flush", 2, 0, 'F' }, - { "zero", 2, 0, 'Z' }, - { "new-chain", 1, 0, 'N' }, - { "delete-chain", 2, 0, 'X' }, - { "rename-chain", 1, 0, 'E' }, - { "policy", 1, 0, 'P' }, - { "source", 1, 0, 's' }, - { "destination", 1, 0, 'd' }, - { "src", 1, 0, 's' }, /* synonym */ - { "dst", 1, 0, 'd' }, /* synonym */ - { "protocol", 1, 0, 'p' }, - { "in-interface", 1, 0, 'i' }, - { "jump", 1, 0, 'j' }, - { "table", 1, 0, 't' }, - { "match", 1, 0, 'm' }, - { "numeric", 0, 0, 'n' }, - { "out-interface", 1, 0, 'o' }, - { "verbose", 0, 0, 'v' }, - { "exact", 0, 0, 'x' }, - { "version", 0, 0, 'V' }, - { "help", 2, 0, 'h' }, - { "line-numbers", 0, 0, '0' }, - { "modprobe", 1, 0, 'M' }, - { "set-counters", 1, 0, 'c' }, - { 0 } + {.name = "append", .has_arg = 1, .val = 'A'}, + {.name = "delete", .has_arg = 1, .val = 'D'}, + {.name = "insert", .has_arg = 1, .val = 'I'}, + {.name = "replace", .has_arg = 1, .val = 'R'}, + {.name = "list", .has_arg = 2, .val = 'L'}, + {.name = "list-rules", .has_arg = 2, .val = 'S'}, + {.name = "flush", .has_arg = 2, .val = 'F'}, + {.name = "zero", .has_arg = 2, .val = 'Z'}, + {.name = "new-chain", .has_arg = 1, .val = 'N'}, + {.name = "delete-chain", .has_arg = 2, .val = 'X'}, + {.name = "rename-chain", .has_arg = 1, .val = 'E'}, + {.name = "policy", .has_arg = 1, .val = 'P'}, + {.name = "source", .has_arg = 1, .val = 's'}, + {.name = "destination", .has_arg = 1, .val = 'd'}, + {.name = "src", .has_arg = 1, .val = 's'}, /* synonym */ + {.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */ + {.name = "protocol", .has_arg = 1, .val = 'p'}, + {.name = "in-interface", .has_arg = 1, .val = 'i'}, + {.name = "jump", .has_arg = 1, .val = 'j'}, + {.name = "table", .has_arg = 1, .val = 't'}, + {.name = "match", .has_arg = 1, .val = 'm'}, + {.name = "numeric", .has_arg = 0, .val = 'n'}, + {.name = "out-interface", .has_arg = 1, .val = 'o'}, + {.name = "verbose", .has_arg = 0, .val = 'v'}, + {.name = "exact", .has_arg = 0, .val = 'x'}, + {.name = "version", .has_arg = 0, .val = 'V'}, + {.name = "help", .has_arg = 2, .val = 'h'}, + {.name = "line-numbers", .has_arg = 0, .val = '0'}, + {.name = "modprobe", .has_arg = 1, .val = 'M'}, + {.name = "set-counters", .has_arg = 1, .val = 'c'}, + {.name = "goto", .has_arg = 1, .val = 'g'}, + {NULL}, }; /* we need this for ip6tables-restore. ip6tables-restore.c sets line to the @@ -143,8 +143,14 @@ static struct option original_opts[] = { * magic number of -1 */ int line = -1; -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); +struct xtables_globals ip6tables_globals = { + .option_offset = 0, + .program_version = IPTABLES_VERSION, + .opts = original_opts, + .orig_opts = original_opts, + .exit_err = ip6tables_exit_error, +}; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -158,7 +164,7 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -n -s -d -p -j -v -x -i -o --line -c */ + /* -n -s -d -p -j -v -x -i -o --line -c */ /*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '}, /*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'}, /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, @@ -167,10 +173,12 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x'}, /*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, /*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, +/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, -/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x'}, -/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'} +/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' '}, +/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, +/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x'} }; static int inverse_for_options[NUMBER_OF_OPT] = @@ -188,20 +196,9 @@ static int inverse_for_options[NUMBER_OF_OPT] = /* -c */ 0, }; -const char *program_version; -const char *program_name; -char *lib_dir; - -/* the path to command to load kernel module */ -const char *modprobe = NULL; - -/* Keeping track of external matches and targets: linked lists. */ -struct ip6tables_match *ip6tables_matches = NULL; -struct ip6tables_target *ip6tables_targets = NULL; - -/* Extra debugging from libiptc */ -extern void dump_entries6(const ip6tc_handle_t handle); - +#define opts ip6tables_globals.opts +#define prog_name ip6tables_globals.program_name +#define prog_vers ip6tables_globals.program_version /* A few hardcoded protocols for 'all' and in case the user has no /etc/protocols */ struct pprot { @@ -209,28 +206,7 @@ struct pprot { u_int8_t num; }; -/* Primitive headers... */ -/* defined in netinet/in.h */ -#if 0 -#ifndef IPPROTO_ESP -#define IPPROTO_ESP 50 -#endif -#ifndef IPPROTO_AH -#define IPPROTO_AH 51 -#endif -#endif - -static const struct pprot chain_protos[] = { - { "tcp", IPPROTO_TCP }, - { "udp", IPPROTO_UDP }, - { "udplite", IPPROTO_UDPLITE }, - { "icmpv6", IPPROTO_ICMPV6 }, - { "ipv6-icmp", IPPROTO_ICMPV6 }, - { "esp", IPPROTO_ESP }, - { "ah", IPPROTO_AH }, -}; - -static char * +static const char * proto_to_name(u_int8_t proto, int nolookup) { unsigned int i; @@ -241,103 +217,41 @@ proto_to_name(u_int8_t proto, int nolookup) return pent->p_name; } - for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++) - if (chain_protos[i].num == proto) - return chain_protos[i].name; + for (i = 0; xtables_chain_protos[i].name != NULL; ++i) + if (xtables_chain_protos[i].num == proto) + return xtables_chain_protos[i].name; return NULL; } -int -service_to_port(const char *name, const char *proto) -{ - struct servent *service; - - if ((service = getservbyname(name, proto)) != NULL) - return ntohs((unsigned short) service->s_port); - - return -1; -} - -u_int16_t -parse_port(const char *port, const char *proto) -{ - unsigned int portnum; - - if ((string_to_number(port, 0, 65535, &portnum)) != -1 || - (portnum = service_to_port(port, proto)) != -1) - return (u_int16_t)portnum; - - exit_error(PARAMETER_PROBLEM, - "invalid port/service `%s' specified", port); -} - static void -in6addrcpy(struct in6_addr *dst, struct in6_addr *src) -{ - memcpy(dst, src, sizeof(struct in6_addr)); - /* dst->s6_addr = src->s6_addr; */ -} - -static void free_opts(int reset_offset) -{ - if (opts != original_opts) { - free(opts); - opts = original_opts; - if (reset_offset) - global_option_offset = 0; - } -} - -void -exit_error(enum exittype status, char *msg, ...) -{ - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", program_name, program_version); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps ip6tables or your kernel needs to be upgraded.\n"); - /* On error paths, make sure that we don't leak memory */ - free_opts(1); - exit(status); -} - -void exit_tryhelp(int status) { if (line != -1) fprintf(stderr, "Error occurred at line: %d\n", line); fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - program_name, program_name ); - free_opts(1); + prog_name, prog_name); + xtables_free_opts(1); exit(status); } -void -exit_printhelp(struct ip6tables_rule_match *matches) +static void +exit_printhelp(struct xtables_rule_match *matches) { - struct ip6tables_rule_match *matchp = NULL; - struct ip6tables_target *t = NULL; - printf("%s v%s\n\n" "Usage: %s -[AD] chain rule-specification [options]\n" -" %s -[RI] chain rulenum rule-specification [options]\n" +" %s -I chain [rulenum] rule-specification [options]\n" +" %s -R chain rulenum rule-specification [options]\n" " %s -D chain rulenum [options]\n" -" %s -[LFZ] [chain] [options]\n" +" %s -[LS] [chain [rulenum]] [options]\n" +" %s -[FZ] [chain] [options]\n" " %s -[NX] chain\n" " %s -E old-chain-name new-chain-name\n" " %s -P chain target [options]\n" " %s -h (print this help information)\n\n", - program_name, program_version, program_name, program_name, - program_name, program_name, program_name, program_name, - program_name, program_name); + prog_name, prog_vers, prog_name, prog_name, + prog_name, prog_name, prog_name, prog_name, + prog_name, prog_name, prog_name, prog_name); printf( "Commands:\n" @@ -350,9 +264,13 @@ exit_printhelp(struct ip6tables_rule_match *matches) " Insert in chain as rulenum (default 1=first)\n" " --replace -R chain rulenum\n" " Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain] List the rules in a chain or all chains\n" +" --list -L [chain [rulenum]]\n" +" List the rules in a chain or all chains\n" +" --list-rules -S [chain [rulenum]]\n" +" Print the rules in a chain or all chains\n" " --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain] Zero counters in chain or all chains\n" +" --zero -Z [chain [rulenum]]\n" +" Zero counters in chain or all chains\n" " --new -N chain Create a new user-defined chain\n" " --delete-chain\n" " -X [chain] Delete a user-defined chain\n" @@ -363,19 +281,23 @@ exit_printhelp(struct ip6tables_rule_match *matches) " Change chain name, (moving any references)\n" "Options:\n" -" --proto -p [!] proto protocol: by number or name, eg. `tcp'\n" -" --source -s [!] address[/mask]\n" +"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n" +"[!] --source -s address[/mask][,...]\n" " source specification\n" -" --destination -d [!] address[/mask]\n" +"[!] --destination -d address[/mask][,...]\n" " destination specification\n" -" --in-interface -i [!] input name[+]\n" +"[!] --in-interface -i input name[+]\n" " network interface name ([+] for wildcard)\n" " --jump -j target\n" " target for rule (may load target extension)\n" +#ifdef IP6T_F_GOTO +" --goto -g chain\n" +" jump to chain with no return\n" +#endif " --match -m match\n" " extended match (may load extension)\n" " --numeric -n numeric output of addresses and ports\n" -" --out-interface -o [!] output name[+]\n" +"[!] --out-interface -o output name[+]\n" " network interface name ([+] for wildcard)\n" " --table -t table table to manipulate (default: `filter')\n" " --verbose -v verbose mode\n" @@ -386,22 +308,30 @@ exit_printhelp(struct ip6tables_rule_match *matches) " --set-counters PKTS BYTES set the counter during insert/append\n" "[!] --version -V print package version.\n"); - /* Print out any special helps. A user might like to be able to add a --help - to the commandline, and see expected results. So we call help for all - specified matches & targets */ - for (t = ip6tables_targets; t; t = t->next) { - if (t->used) { - printf("\n"); - t->help(); - } - } - for (matchp = matches; matchp; matchp = matchp->next) { - printf("\n"); - matchp->match->help(); - } + print_extension_helps(xtables_targets, matches); exit(0); } +void +ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s v%s: ", prog_name, prog_vers); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + if (status == PARAMETER_PROBLEM) + exit_tryhelp(status); + if (status == VERSION_PROBLEM) + fprintf(stderr, + "Perhaps ip6tables or your kernel needs to be upgraded.\n"); + /* On error paths, make sure that we don't leak memory */ + xtables_free_opts(1); + exit(status); +} + static void generic_opt_check(int command, int options) { @@ -420,7 +350,7 @@ generic_opt_check(int command, int options) if (!(options & (1<<i))) { if (commands_v_options[j][i] == '+') - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "You need to supply the `-%c' " "option for this command\n", optflags[i]); @@ -432,7 +362,7 @@ generic_opt_check(int command, int options) } } if (legal == -1) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "Illegal option `-%c' with this command\n", optflags[i]); } @@ -461,186 +391,13 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds, int invert) { if (invert) - exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); + xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag"); if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n", + xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n", cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); *cmd |= newcmd; } -int -check_inverse(const char option[], int *invert, int *optind, int argc) -{ - if (option && strcmp(option, "!") == 0) { - if (*invert) - exit_error(PARAMETER_PROBLEM, - "Multiple `!' flags not allowed"); - *invert = TRUE; - if (optind) { - *optind = *optind+1; - if (argc && *optind > argc) - exit_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } - - return TRUE; - } - return FALSE; -} - -static void * -fw_calloc(size_t count, size_t size) -{ - void *p; - - if ((p = calloc(count, size)) == NULL) { - perror("ip6tables: calloc failed"); - exit(1); - } - return p; -} - -static void * -fw_malloc(size_t size) -{ - void *p; - - if ((p = malloc(size)) == NULL) { - perror("ip6tables: malloc failed"); - exit(1); - } - return p; -} - -static char * -addr_to_numeric(const struct in6_addr *addrp) -{ - /* 0000:0000:0000:0000:0000:000.000.000.000 - * 0000:0000:0000:0000:0000:0000:0000:0000 */ - static char buf[50+1]; - return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); -} - -static struct in6_addr * -numeric_to_addr(const char *num) -{ - static struct in6_addr ap; - int err; - if ((err=inet_pton(AF_INET6, num, &ap)) == 1) - return ≈ -#ifdef DEBUG - fprintf(stderr, "\nnumeric2addr: %d\n", err); -#endif - return (struct in6_addr *)NULL; -} - - -static struct in6_addr * -host_to_addr(const char *name, unsigned int *naddr) -{ - struct addrinfo hints; - struct addrinfo *res; - static struct in6_addr *addr; - int err; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags=AI_CANONNAME; - hints.ai_family=AF_INET6; - hints.ai_socktype=SOCK_RAW; - hints.ai_protocol=41; - hints.ai_next=NULL; - - *naddr = 0; - if ( (err=getaddrinfo(name, NULL, &hints, &res)) != 0 ){ -#ifdef DEBUG - fprintf(stderr,"Name2IP: %s\n",gai_strerror(err)); -#endif - return (struct in6_addr *) NULL; - } else { - if (res->ai_family != AF_INET6 || - res->ai_addrlen != sizeof(struct sockaddr_in6)) - return (struct in6_addr *) NULL; - -#ifdef DEBUG - fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen, - addr_to_numeric(&(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr))); -#endif - /* Get the first element of the address-chain */ - addr = fw_calloc(1, sizeof(struct in6_addr)); - in6addrcpy(addr, (struct in6_addr *) - &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr); - freeaddrinfo(res); - *naddr = 1; - return addr; - } - - return (struct in6_addr *) NULL; -} - -static char * -addr_to_host(const struct in6_addr *addr) -{ - struct sockaddr_in6 saddr; - int err; - static char hostname[NI_MAXHOST]; - - memset(&saddr, 0, sizeof(struct sockaddr_in6)); - in6addrcpy(&(saddr.sin6_addr),(struct in6_addr *)addr); - saddr.sin6_family = AF_INET6; - - if ( (err=getnameinfo((struct sockaddr *)&saddr, - sizeof(struct sockaddr_in6), - hostname, sizeof(hostname)-1, - NULL, 0, 0)) != 0 ){ -#ifdef DEBUG - fprintf(stderr,"IP2Name: %s\n",gai_strerror(err)); -#endif - return (char *) NULL; - } else { -#ifdef DEBUG - fprintf (stderr, "\naddr2host: %s\n", hostname); -#endif - - return hostname; - } - - return (char *) NULL; -} - -static char * -mask_to_numeric(const struct in6_addr *addrp) -{ - static char buf[50+2]; - int l = ipv6_prefix_length(addrp); - if (l == -1) { - strcpy(buf, "/"); - strcat(buf, addr_to_numeric(addrp)); - return buf; - } - sprintf(buf, "/%d", l); - return buf; -} - -static struct in6_addr * -network_to_addr(const char *name) -{ - /* abort();*/ - /* TODO: not implemented yet, but the exception breaks the - * name resolvation */ - return (struct in6_addr *)NULL; -} - -static char * -addr_to_anyname(const struct in6_addr *addr) -{ - char *name; - - if ((name = addr_to_host(addr)) != NULL) - return name; - - return addr_to_numeric(addr); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. @@ -650,289 +407,41 @@ addr_to_anyname(const struct in6_addr *addr) * return global static data. */ -static struct in6_addr * -parse_hostnetwork(const char *name, unsigned int *naddrs) -{ - struct in6_addr *addrp, *addrptmp; - - if ((addrptmp = numeric_to_addr(name)) != NULL || - (addrptmp = network_to_addr(name)) != NULL) { - addrp = fw_malloc(sizeof(struct in6_addr)); - in6addrcpy(addrp, addrptmp); - *naddrs = 1; - return addrp; - } - if ((addrp = host_to_addr(name, naddrs)) != NULL) - return addrp; - - exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name); -} - -static struct in6_addr * -parse_mask(char *mask) -{ - static struct in6_addr maskaddr; - struct in6_addr *addrp; - unsigned int bits; - - if (mask == NULL) { - /* no mask at all defaults to 128 bits */ - memset(&maskaddr, 0xff, sizeof maskaddr); - return &maskaddr; - } - if ((addrp = numeric_to_addr(mask)) != NULL) - return addrp; - if (string_to_number(mask, 0, 128, &bits) == -1) - exit_error(PARAMETER_PROBLEM, - "invalid mask `%s' specified", mask); - if (bits != 0) { - char *p = (char *)&maskaddr; - memset(p, 0xff, bits / 8); - memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); - p[bits / 8] = 0xff << (8 - (bits & 7)); - return &maskaddr; - } - - memset(&maskaddr, 0, sizeof maskaddr); - return &maskaddr; -} - -void -parse_hostnetworkmask(const char *name, struct in6_addr **addrpp, - struct in6_addr *maskp, unsigned int *naddrs) -{ - struct in6_addr *addrp; - char buf[256]; - char *p; - int i, j, n; - - strncpy(buf, name, sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - addrp = parse_mask(p + 1); - } else - addrp = parse_mask(NULL); - in6addrcpy(maskp, addrp); - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (!memcmp(maskp, &in6addr_any, sizeof(in6addr_any))) - strcpy(buf, "::"); - - addrp = *addrpp = parse_hostnetwork(buf, naddrs); - n = *naddrs; - for (i = 0, j = 0; i < n; i++) { - int k; - for (k = 0; k < 4; k++) - addrp[j].in6_u.u6_addr32[k] &= maskp->in6_u.u6_addr32[k]; - j++; - for (k = 0; k < j - 1; k++) { - if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) { - (*naddrs)--; - j--; - break; - } - } - } -} - -struct ip6tables_match * -find_match(const char *match_name, enum ip6t_tryload tryload, struct ip6tables_rule_match **matches) -{ - struct ip6tables_match *ptr; - const char *icmp6 = "icmp6"; - const char *name; - - /* This is ugly as hell. Nonetheless, there is no way of changing - * this without hurting backwards compatibility */ - if ( (strcmp(match_name,"icmpv6") == 0) || - (strcmp(match_name,"ipv6-icmp") == 0) || - (strcmp(match_name,"icmp6") == 0) ) - name = icmp6; - else - name = match_name; - - for (ptr = ip6tables_matches; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) { - struct ip6tables_match *clone; - - /* First match of this type: */ - if (ptr->m == NULL) - break; - - /* Second and subsequent clones */ - clone = fw_malloc(sizeof(struct ip6tables_match)); - memcpy(clone, ptr, sizeof(struct ip6tables_match)); - clone->mflags = 0; - /* This is a clone: */ - clone->next = clone; - - ptr = clone; - break; - } - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) { - char path[strlen(lib_dir) + sizeof("/libip6t_.so") - + strlen(name)]; - sprintf(path, "%s/libip6t_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) { - /* Found library. If it didn't register itself, - maybe they specified target as match. */ - ptr = find_match(name, DONT_LOAD, NULL); - - if (!ptr) - exit_error(PARAMETER_PROBLEM, - "Couldn't load match `%s'\n", - name); - } else if (tryload == LOAD_MUST_SUCCEED) - exit_error(PARAMETER_PROBLEM, - "Couldn't load match `%s':%s\n", - name, dlerror()); - } -#else - if (ptr && !ptr->loaded) { - if (tryload != DONT_LOAD) - ptr->loaded = 1; - else - ptr = NULL; - } - if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { - exit_error(PARAMETER_PROBLEM, - "Couldn't find match `%s'\n", name); - } -#endif - - if (ptr && matches) { - struct ip6tables_rule_match **i; - struct ip6tables_rule_match *newentry; - - newentry = fw_malloc(sizeof(struct ip6tables_rule_match)); - - for (i = matches; *i; i = &(*i)->next) { - if (strcmp(name, (*i)->match->name) == 0) - (*i)->completed = 1; - } - newentry->match = ptr; - newentry->completed = 0; - newentry->next = NULL; - *i = newentry; - } - - return ptr; -} - /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static struct ip6tables_match * -find_proto(const char *pname, enum ip6t_tryload tryload, int nolookup, struct ip6tables_rule_match **matches) +static struct xtables_match * +find_proto(const char *pname, enum xtables_tryload tryload, + int nolookup, struct xtables_rule_match **matches) { unsigned int proto; - if (string_to_number(pname, 0, 255, &proto) != -1) { - char *protoname = proto_to_name(proto, nolookup); + if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) { + const char *protoname = proto_to_name(proto, nolookup); if (protoname) - return find_match(protoname, tryload, matches); + return xtables_find_match(protoname, tryload, matches); } else - return find_match(pname, tryload, matches); + return xtables_find_match(pname, tryload, matches); return NULL; } -u_int16_t -parse_protocol(const char *s) -{ - unsigned int proto; - - if (string_to_number(s, 0, 255, &proto) == -1) { - struct protoent *pent; - - /* first deal with the special case of 'all' to prevent - * people from being able to redefine 'all' in nsswitch - * and/or provoke expensive [not working] ldap/nis/... - * lookups */ - if (!strcmp(s, "all")) - return 0; - - if ((pent = getprotobyname(s))) - proto = pent->p_proto; - else { - unsigned int i; - for (i = 0; - i < sizeof(chain_protos)/sizeof(struct pprot); - i++) { - if (strcmp(s, chain_protos[i].name) == 0) { - proto = chain_protos[i].num; - break; - } - } - if (i == sizeof(chain_protos)/sizeof(struct pprot)) - exit_error(PARAMETER_PROBLEM, - "unknown protocol `%s' specified", - s); - } - } - - return (u_int16_t)proto; -} - -/* proto means IPv6 extension header ? */ +/* These are invalid numbers as upper layer protocol */ static int is_exthdr(u_int16_t proto) { - return (proto == IPPROTO_HOPOPTS || - proto == IPPROTO_ROUTING || + return (proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT || - proto == IPPROTO_ESP || proto == IPPROTO_AH || proto == IPPROTO_DSTOPTS); } -void parse_interface(const char *arg, char *vianame, unsigned char *mask) -{ - int vialen = strlen(arg); - unsigned int i; - - memset(mask, 0, IFNAMSIZ); - memset(vianame, 0, IFNAMSIZ); - - if (vialen + 1 > IFNAMSIZ) - exit_error(PARAMETER_PROBLEM, - "interface name `%s' must be shorter than IFNAMSIZ" - " (%i)", arg, IFNAMSIZ-1); - - strcpy(vianame, arg); - if ((vialen == 0) || (vialen == 1 && vianame[0] == '+')) - memset(mask, 0, IFNAMSIZ); - else if (vianame[vialen - 1] == '+') { - memset(mask, 0xFF, vialen - 1); - memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1); - /* Don't remove `+' here! -HW */ - } else { - /* Include nul-terminator in match */ - memset(mask, 0xFF, vialen + 1); - memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1); - for (i = 0; vianame[i]; i++) { - if (vianame[i] == ':' || - vianame[i] == '!' || - vianame[i] == '*') { - printf("Warning: weird character in interface" - " `%s' (No aliases, :, ! or *).\n", - vianame); - break; - } - } - } -} - /* Can't be zero. */ static int parse_rulenumber(const char *rule) { unsigned int rulenum; - if (string_to_number(rule, 1, INT_MAX, &rulenum) == -1) - exit_error(PARAMETER_PROBLEM, + if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX)) + xtables_error(PARAMETER_PROBLEM, "Invalid rule number `%s'", rule); return rulenum; @@ -944,72 +453,27 @@ parse_target(const char *targetname) const char *ptr; if (strlen(targetname) < 1) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "Invalid target name (too short)"); if (strlen(targetname)+1 > sizeof(ip6t_chainlabel)) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "Invalid target name `%s' (%u chars max)", targetname, (unsigned int)sizeof(ip6t_chainlabel)-1); for (ptr = targetname; *ptr; ptr++) if (isspace(*ptr)) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "Invalid target name `%s'", targetname); return targetname; } -int -string_to_number_ll(const char *s, unsigned long long min, unsigned long long max, - unsigned long long *ret) -{ - unsigned long long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtoull(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && (!max || number <= max)) { - *ret = number; - return 0; - } - } - return -1; -} - -int -string_to_number_l(const char *s, unsigned long min, unsigned long max, - unsigned long *ret) -{ - int result; - unsigned long long number; - - result = string_to_number_ll(s, min, max, &number); - *ret = (unsigned long)number; - - return result; -} - -int string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - int result; - unsigned long number; - - result = string_to_number_l(s, min, max, &number); - *ret = (unsigned int)number; - - return result; -} - static void set_option(unsigned int *options, unsigned int option, u_int8_t *invflg, int invert) { if (*options & option) - exit_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", + xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", opt2char(option)); *options |= option; @@ -1018,220 +482,13 @@ set_option(unsigned int *options, unsigned int option, u_int8_t *invflg, for (i = 0; 1 << i != option; i++); if (!inverse_for_options[i]) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "cannot have ! before -%c", opt2char(option)); *invflg |= inverse_for_options[i]; } } -struct ip6tables_target * -find_target(const char *name, enum ip6t_tryload tryload) -{ - struct ip6tables_target *ptr; - - /* Standard target? */ - if (strcmp(name, "") == 0 - || strcmp(name, IP6TC_LABEL_ACCEPT) == 0 - || strcmp(name, IP6TC_LABEL_DROP) == 0 - || strcmp(name, IP6TC_LABEL_QUEUE) == 0 - || strcmp(name, IP6TC_LABEL_RETURN) == 0) - name = "standard"; - - for (ptr = ip6tables_targets; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) { - char path[strlen(lib_dir) + sizeof("/libip6t_.so") - + strlen(name)]; - sprintf(path, "%s/libip6t_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) { - /* Found library. If it didn't register itself, - maybe they specified match as a target. */ - ptr = find_target(name, DONT_LOAD); - if (!ptr) - exit_error(PARAMETER_PROBLEM, - "Couldn't load target `%s'\n", - name); - } else if (tryload == LOAD_MUST_SUCCEED) - exit_error(PARAMETER_PROBLEM, - "Couldn't load target `%s':%s\n", - name, dlerror()); - } -#else - if (ptr && !ptr->loaded) { - if (tryload != DONT_LOAD) - ptr->loaded = 1; - else - ptr = NULL; - } - if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { - exit_error(PARAMETER_PROBLEM, - "Couldn't find target `%s'\n", name); - } -#endif - - if (ptr) - ptr->used = 1; - - return ptr; -} - -static struct option * -merge_options(struct option *oldopts, const struct option *newopts, - unsigned int *option_offset) -{ - unsigned int num_old, num_new, i; - struct option *merge; - - for (num_old = 0; oldopts[num_old].name; num_old++); - for (num_new = 0; newopts[num_new].name; num_new++); - - global_option_offset += OPTION_OFFSET; - *option_offset = global_option_offset; - - merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); - memcpy(merge, oldopts, num_old * sizeof(struct option)); - free_opts(0); /* Release previous options merged if any */ - for (i = 0; i < num_new; i++) { - merge[num_old + i] = newopts[i]; - merge[num_old + i].val += *option_offset; - } - memset(merge + num_old + num_new, 0, sizeof(struct option)); - - return merge; -} - -static int compatible_revision(const char *name, u_int8_t revision, int opt) -{ - struct ip6t_get_revision rev; - socklen_t s = sizeof(rev); - int max_rev, sockfd; - - sockfd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW); - if (sockfd < 0) { - fprintf(stderr, "Could not open socket to kernel: %s\n", - strerror(errno)); - exit(1); - } - - strcpy(rev.name, name); - rev.revision = revision; - - load_ip6tables_ko(modprobe); - - max_rev = getsockopt(sockfd, IPPROTO_IPV6, opt, &rev, &s); - if (max_rev < 0) { - /* Definitely don't support this? */ - if (errno == EPROTONOSUPPORT) { - close(sockfd); - return 0; - } else if (errno == ENOPROTOOPT) { - close(sockfd); - /* Assume only revision 0 support (old kernel) */ - return (revision == 0); - } else { - fprintf(stderr, "getsockopt failed strangely: %s\n", - strerror(errno)); - exit(1); - } - } - close(sockfd); - return 1; -} - -static int compatible_match_revision(const char *name, u_int8_t revision) -{ - return compatible_revision(name, revision, IP6T_SO_GET_REVISION_MATCH); -} - -void -register_match6(struct ip6tables_match *me) -{ - struct ip6tables_match **i, *old; - - if (strcmp(me->version, program_version) != 0) { - fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n", - program_name, me->name, me->version, program_version); - exit(1); - } - - /* Revision field stole a char from name. */ - if (strlen(me->name) >= IP6T_FUNCTION_MAXNAMELEN-1) { - fprintf(stderr, "%s: target `%s' has invalid name\n", - program_name, me->name); - exit(1); - } - - old = find_match(me->name, DURING_LOAD, NULL); - if (old) { - if (old->revision == me->revision) { - fprintf(stderr, - "%s: match `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - /* Now we have two (or more) options, check compatibility. */ - if (compatible_match_revision(old->name, old->revision) - && old->revision > me->revision) - return; - - /* Replace if compatible. */ - if (!compatible_match_revision(me->name, me->revision)) - return; - - /* Delete old one. */ - for (i = &ip6tables_matches; *i!=old; i = &(*i)->next); - *i = old->next; - } - - if (me->size != IP6T_ALIGN(me->size)) { - fprintf(stderr, "%s: match `%s' has invalid size %u.\n", - program_name, me->name, (unsigned int)me->size); - exit(1); - } - - /* Append to list. */ - for (i = &ip6tables_matches; *i; i = &(*i)->next); - me->next = NULL; - *i = me; - - me->m = NULL; - me->mflags = 0; -} - -void -register_target6(struct ip6tables_target *me) -{ - if (strcmp(me->version, program_version) != 0) { - fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n", - program_name, me->name, me->version, program_version); - exit(1); - } - - if (find_target(me->name, DURING_LOAD)) { - fprintf(stderr, "%s: target `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IP6T_ALIGN(me->size)) { - fprintf(stderr, "%s: target `%s' has invalid size %u.\n", - program_name, me->name, (unsigned int)me->size); - exit(1); - } - - /* Prepend to list. */ - me->next = ip6tables_targets; - ip6tables_targets = me; - me->t = NULL; - me->tflags = 0; -} - static void print_num(u_int64_t number, unsigned int format) { @@ -1259,7 +516,7 @@ print_num(u_int64_t number, unsigned int format) static void -print_header(unsigned int format, const char *chain, ip6tc_handle_t *handle) +print_header(unsigned int format, const char *chain, struct ip6tc_handle *handle) { struct ip6t_counters counters; const char *pol = ip6tc_get_policy(chain, &counters, handle); @@ -1313,7 +570,8 @@ print_match(const struct ip6t_entry_match *m, const struct ip6t_ip6 *ip, int numeric) { - struct ip6tables_match *match = find_match(m->u.user.name, TRY_LOAD, NULL); + struct xtables_match *match = + xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL); if (match) { if (match->print) @@ -1328,29 +586,30 @@ print_match(const struct ip6t_entry_match *m, return 0; } -/* e is called `fw' here for hysterical raisins */ +/* e is called `fw' here for historical reasons */ static void print_firewall(const struct ip6t_entry *fw, const char *targname, unsigned int num, unsigned int format, - const ip6tc_handle_t handle) + struct ip6tc_handle *const handle) { - struct ip6tables_target *target = NULL; + struct xtables_target *target = NULL; const struct ip6t_entry_target *t; u_int8_t flags; char buf[BUFSIZ]; if (!ip6tc_is_chain(targname, handle)) - target = find_target(targname, TRY_LOAD); + target = xtables_find_target(targname, XTF_TRY_LOAD); else - target = find_target(IP6T_STANDARD_TARGET, LOAD_MUST_SUCCEED); + target = xtables_find_target(IP6T_STANDARD_TARGET, + XTF_LOAD_MUST_SUCCEED); t = ip6t_get_target((struct ip6t_entry *)fw); flags = fw->ipv6.flags; if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num+1); + printf(FMT("%-4u ", "%u "), num); if (!(format & FMT_NOCOUNTS)) { print_num(fw->counters.pcnt, format); @@ -1362,7 +621,7 @@ print_firewall(const struct ip6t_entry *fw, fputc(fw->ipv6.invflags & IP6T_INV_PROTO ? '!' : ' ', stdout); { - char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC); + const char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC); if (pname) printf(FMT("%-5s", "%s "), pname); else @@ -1408,34 +667,39 @@ print_firewall(const struct ip6t_entry *fw, } fputc(fw->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout); - if (!memcmp(&fw->ipv6.smsk, &in6addr_any, sizeof in6addr_any) + if (!memcmp(&fw->ipv6.smsk, &in6addr_any, sizeof in6addr_any) && !(format & FMT_NUMERIC)) printf(FMT("%-19s ","%s "), "anywhere"); else { if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_numeric(&(fw->ipv6.src))); + strcpy(buf, xtables_ip6addr_to_numeric(&fw->ipv6.src)); else - sprintf(buf, "%s", addr_to_anyname(&(fw->ipv6.src))); - strcat(buf, mask_to_numeric(&(fw->ipv6.smsk))); + strcpy(buf, xtables_ip6addr_to_anyname(&fw->ipv6.src)); + strcat(buf, xtables_ip6mask_to_numeric(&fw->ipv6.smsk)); printf(FMT("%-19s ","%s "), buf); } fputc(fw->ipv6.invflags & IP6T_INV_DSTIP ? '!' : ' ', stdout); if (!memcmp(&fw->ipv6.dmsk, &in6addr_any, sizeof in6addr_any) && !(format & FMT_NUMERIC)) - printf(FMT("%-19s","-> %s"), "anywhere"); + printf(FMT("%-19s ","-> %s"), "anywhere"); else { if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_numeric(&(fw->ipv6.dst))); + strcpy(buf, xtables_ip6addr_to_numeric(&fw->ipv6.dst)); else - sprintf(buf, "%s", addr_to_anyname(&(fw->ipv6.dst))); - strcat(buf, mask_to_numeric(&(fw->ipv6.dmsk))); - printf(FMT("%-19s","-> %s"), buf); + strcpy(buf, xtables_ip6addr_to_anyname(&fw->ipv6.dst)); + strcat(buf, xtables_ip6mask_to_numeric(&fw->ipv6.dmsk)); + printf(FMT("%-19s ","-> %s"), buf); } if (format & FMT_NOTABLE) fputs(" ", stdout); +#ifdef IP6T_F_GOTO + if(fw->ipv6.flags & IP6T_F_GOTO) + printf("[goto] "); +#endif + IP6T_MATCH_ITERATE(fw, print_match, &fw->ipv6, format & FMT_NUMERIC); if (target) { @@ -1452,7 +716,7 @@ print_firewall(const struct ip6t_entry *fw, static void print_firewall_line(const struct ip6t_entry *fw, - const ip6tc_handle_t h) + struct ip6tc_handle *const h) { struct ip6t_entry_target *t; @@ -1465,20 +729,24 @@ append_entry(const ip6t_chainlabel chain, struct ip6t_entry *fw, unsigned int nsaddrs, const struct in6_addr saddrs[], + const struct in6_addr smasks[], unsigned int ndaddrs, const struct in6_addr daddrs[], + const struct in6_addr dmasks[], int verbose, - ip6tc_handle_t *handle) + struct ip6tc_handle *handle) { unsigned int i, j; int ret = 1; for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; + fw->ipv6.smsk = smasks[i]; for (j = 0; j < ndaddrs; j++) { fw->ipv6.dst = daddrs[j]; + fw->ipv6.dmsk = dmasks[j]; if (verbose) - print_firewall_line(fw, *handle); + print_firewall_line(fw, handle); ret &= ip6tc_append_entry(chain, fw, handle); } } @@ -1490,16 +758,18 @@ static int replace_entry(const ip6t_chainlabel chain, struct ip6t_entry *fw, unsigned int rulenum, - const struct in6_addr *saddr, - const struct in6_addr *daddr, + const struct in6_addr *saddr, const struct in6_addr *smask, + const struct in6_addr *daddr, const struct in6_addr *dmask, int verbose, - ip6tc_handle_t *handle) + struct ip6tc_handle *handle) { fw->ipv6.src = *saddr; fw->ipv6.dst = *daddr; + fw->ipv6.smsk = *smask; + fw->ipv6.dmsk = *dmask; if (verbose) - print_firewall_line(fw, *handle); + print_firewall_line(fw, handle); return ip6tc_replace_entry(chain, fw, rulenum, handle); } @@ -1509,20 +779,24 @@ insert_entry(const ip6t_chainlabel chain, unsigned int rulenum, unsigned int nsaddrs, const struct in6_addr saddrs[], + const struct in6_addr smasks[], unsigned int ndaddrs, const struct in6_addr daddrs[], + const struct in6_addr dmasks[], int verbose, - ip6tc_handle_t *handle) + struct ip6tc_handle *handle) { unsigned int i, j; int ret = 1; for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; + fw->ipv6.smsk = smasks[i]; for (j = 0; j < ndaddrs; j++) { fw->ipv6.dst = daddrs[j]; + fw->ipv6.dmsk = dmasks[j]; if (verbose) - print_firewall_line(fw, *handle); + print_firewall_line(fw, handle); ret &= ip6tc_insert_entry(chain, fw, rulenum, handle); } } @@ -1531,20 +805,21 @@ insert_entry(const ip6t_chainlabel chain, } static unsigned char * -make_delete_mask(struct ip6t_entry *fw, struct ip6tables_rule_match *matches) +make_delete_mask(struct xtables_rule_match *matches, + const struct xtables_target *target) { /* Establish mask for comparison */ unsigned int size; - struct ip6tables_rule_match *matchp; + struct xtables_rule_match *matchp; unsigned char *mask, *mptr; size = sizeof(struct ip6t_entry); for (matchp = matches; matchp; matchp = matchp->next) size += IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + matchp->match->size; - mask = fw_calloc(1, size + mask = xtables_calloc(1, size + IP6T_ALIGN(sizeof(struct ip6t_entry_target)) - + ip6tables_targets->size); + + target->size); memset(mask, 0xFF, sizeof(struct ip6t_entry)); mptr = mask + sizeof(struct ip6t_entry); @@ -1556,9 +831,9 @@ make_delete_mask(struct ip6t_entry *fw, struct ip6tables_rule_match *matches) mptr += IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + matchp->match->size; } - memset(mptr, 0xFF, + memset(mptr, 0xFF, IP6T_ALIGN(sizeof(struct ip6t_entry_target)) - + ip6tables_targets->userspacesize); + + target->userspacesize); return mask; } @@ -1568,23 +843,28 @@ delete_entry(const ip6t_chainlabel chain, struct ip6t_entry *fw, unsigned int nsaddrs, const struct in6_addr saddrs[], + const struct in6_addr smasks[], unsigned int ndaddrs, const struct in6_addr daddrs[], + const struct in6_addr dmasks[], int verbose, - ip6tc_handle_t *handle, - struct ip6tables_rule_match *matches) + struct ip6tc_handle *handle, + struct xtables_rule_match *matches, + const struct xtables_target *target) { unsigned int i, j; int ret = 1; unsigned char *mask; - mask = make_delete_mask(fw, matches); + mask = make_delete_mask(matches, target); for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; + fw->ipv6.smsk = smasks[i]; for (j = 0; j < ndaddrs; j++) { fw->ipv6.dst = daddrs[j]; + fw->ipv6.dmsk = dmasks[j]; if (verbose) - print_firewall_line(fw, *handle); + print_firewall_line(fw, handle); ret &= ip6tc_delete_entry(chain, fw, mask, handle); } } @@ -1594,10 +874,10 @@ delete_entry(const ip6t_chainlabel chain, } int -for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), - int verbose, int builtinstoo, ip6tc_handle_t *handle) +for_each_chain(int (*fn)(const ip6t_chainlabel, int, struct ip6tc_handle *), + int verbose, int builtinstoo, struct ip6tc_handle *handle) { - int ret = 1; + int ret = 1; const char *chain; char *chains; unsigned int i, chaincount = 0; @@ -1606,32 +886,32 @@ for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), while (chain) { chaincount++; chain = ip6tc_next_chain(handle); - } + } - chains = fw_malloc(sizeof(ip6t_chainlabel) * chaincount); + chains = xtables_malloc(sizeof(ip6t_chainlabel) * chaincount); i = 0; chain = ip6tc_first_chain(handle); while (chain) { strcpy(chains + i*sizeof(ip6t_chainlabel), chain); i++; chain = ip6tc_next_chain(handle); - } + } for (i = 0; i < chaincount; i++) { if (!builtinstoo && ip6tc_builtin(chains + i*sizeof(ip6t_chainlabel), - *handle) == 1) + handle) == 1) continue; - ret &= fn(chains + i*sizeof(ip6t_chainlabel), verbose, handle); + ret &= fn(chains + i*sizeof(ip6t_chainlabel), verbose, handle); } free(chains); - return ret; + return ret; } int flush_entries(const ip6t_chainlabel chain, int verbose, - ip6tc_handle_t *handle) + struct ip6tc_handle *handle) { if (!chain) return for_each_chain(flush_entries, verbose, 1, handle); @@ -1643,7 +923,7 @@ flush_entries(const ip6t_chainlabel chain, int verbose, static int zero_entries(const ip6t_chainlabel chain, int verbose, - ip6tc_handle_t *handle) + struct ip6tc_handle *handle) { if (!chain) return for_each_chain(zero_entries, verbose, 1, handle); @@ -1655,19 +935,19 @@ zero_entries(const ip6t_chainlabel chain, int verbose, int delete_chain(const ip6t_chainlabel chain, int verbose, - ip6tc_handle_t *handle) + struct ip6tc_handle *handle) { if (!chain) return for_each_chain(delete_chain, verbose, 0, handle); if (verbose) - fprintf(stdout, "Deleting chain `%s'\n", chain); + fprintf(stdout, "Deleting chain `%s'\n", chain); return ip6tc_delete_chain(chain, handle); } static int -list_entries(const ip6t_chainlabel chain, int verbose, int numeric, - int expanded, int linenumbers, ip6tc_handle_t *handle) +list_entries(const ip6t_chainlabel chain, int rulenum, int verbose, int numeric, + int expanded, int linenumbers, struct ip6tc_handle *handle) { int found = 0; unsigned int format; @@ -1699,16 +979,19 @@ list_entries(const ip6t_chainlabel chain, int verbose, int numeric, if (found) printf("\n"); - print_header(format, this, handle); + if (!rulenum) + print_header(format, this, handle); i = ip6tc_first_rule(this, handle); num = 0; while (i) { - print_firewall(i, - ip6tc_get_target(i, handle), - num++, - format, - *handle); + num++; + if (!rulenum || num == rulenum) + print_firewall(i, + ip6tc_get_target(i, handle), + num, + format, + handle); i = ip6tc_next_rule(i, handle); } found = 1; @@ -1718,97 +1001,260 @@ list_entries(const ip6t_chainlabel chain, int verbose, int numeric, return found; } -static char *get_modprobe(void) +/* This assumes that mask is contiguous, and byte-bounded. */ +static void +print_iface(char letter, const char *iface, const unsigned char *mask, + int invert) { - int procfile; - char *ret; - -#define PROCFILE_BUFSIZ 1024 - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); - if (procfile < 0) - return NULL; - - ret = malloc(PROCFILE_BUFSIZ); - if (ret) { - memset(ret, 0, PROCFILE_BUFSIZ); - switch (read(procfile, ret, PROCFILE_BUFSIZ)) { - case -1: goto fail; - case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */ + unsigned int i; + + if (mask[0] == 0) + return; + + printf("%s-%c ", invert ? "! " : "", letter); + + for (i = 0; i < IFNAMSIZ; i++) { + if (mask[i] != 0) { + if (iface[i] != '\0') + printf("%c", iface[i]); + } else { + /* we can access iface[i-1] here, because + * a few lines above we make sure that mask[0] != 0 */ + if (iface[i-1] != '\0') + printf("+"); + break; } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; - close(procfile); - return ret; } - fail: - free(ret); - close(procfile); - return NULL; + + printf(" "); } -int ip6tables_insmod(const char *modname, const char *modprobe) +/* The ip6tables looks up the /etc/protocols. */ +static void print_proto(u_int16_t proto, int invert) { - char *buf = NULL; - char *argv[3]; - int status; - - /* If they don't explicitly set it, read out of kernel */ - if (!modprobe) { - buf = get_modprobe(); - if (!buf) - return -1; - modprobe = buf; + if (proto) { + unsigned int i; + const char *invertstr = invert ? "! " : ""; + + struct protoent *pent = getprotobynumber(proto); + if (pent) { + printf("%s-p %s ", + invertstr, pent->p_name); + return; + } + + for (i = 0; xtables_chain_protos[i].name != NULL; ++i) + if (xtables_chain_protos[i].num == proto) { + printf("%s-p %s ", + invertstr, xtables_chain_protos[i].name); + return; + } + + printf("%s-p %u ", invertstr, proto); } +} + +static int print_match_save(const struct ip6t_entry_match *e, + const struct ip6t_ip6 *ip) +{ + struct xtables_match *match = + xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL); + + if (match) { + printf("-m %s ", e->u.user.name); + + /* some matches don't provide a save function */ + if (match->save) + match->save(ip, e); + } else { + if (e->u.match_size) { + fprintf(stderr, + "Can't find library for match `%s'\n", + e->u.user.name); + exit(1); + } + } + return 0; +} - switch (fork()) { - case 0: - argv[0] = (char *)modprobe; - argv[1] = (char *)modname; - argv[2] = NULL; - execv(argv[0], argv); +/* print a given ip including mask if neccessary */ +static void print_ip(char *prefix, const struct in6_addr *ip, const struct in6_addr *mask, int invert) +{ + char buf[51]; + int l = ipv6_prefix_length(mask); + + if (l == 0 && !invert) + return; + + printf("%s%s %s", + invert ? "! " : "", + prefix, + inet_ntop(AF_INET6, ip, buf, sizeof buf)); + + if (l == -1) + printf("/%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf)); + else + printf("/%d ", l); +} + +/* We want this to be readable, so only print out neccessary fields. + * Because that's the kind of world I want to live in. */ +void print_rule(const struct ip6t_entry *e, + struct ip6tc_handle *h, const char *chain, int counters) +{ + struct ip6t_entry_target *t; + const char *target_name; + + /* print counters for iptables-save */ + if (counters > 0) + printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); + + /* print chain name */ + printf("-A %s ", chain); + + /* Print IP part. */ + print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk), + e->ipv6.invflags & IP6T_INV_SRCIP); + + print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), + e->ipv6.invflags & IP6T_INV_DSTIP); - /* not usually reached */ - exit(1); - case -1: - return -1; + print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, + e->ipv6.invflags & IP6T_INV_VIA_IN); - default: /* parent */ - wait(&status); + print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, + e->ipv6.invflags & IP6T_INV_VIA_OUT); + + print_proto(e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO); + +#if 0 + /* not definied in ipv6 + * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */ + if (e->ipv6.flags & IPT_F_FRAG) + printf("%s-f ", + e->ipv6.invflags & IP6T_INV_FRAG ? "! " : ""); +#endif + + if (e->ipv6.flags & IP6T_F_TOS) + printf("%s-? %d ", + e->ipv6.invflags & IP6T_INV_TOS ? "! " : "", + e->ipv6.tos); + + /* Print matchinfo part */ + if (e->target_offset) { + IP6T_MATCH_ITERATE(e, print_match_save, &e->ipv6); } - free(buf); - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - return 0; - return -1; + /* print counters for iptables -R */ + if (counters < 0) + printf("-c %llu %llu ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); + + /* Print target name */ + target_name = ip6tc_get_target(e, h); + if (target_name && (*target_name != '\0')) +#ifdef IP6T_F_GOTO + printf("-%c %s ", e->ipv6.flags & IP6T_F_GOTO ? 'g' : 'j', target_name); +#else + printf("-j %s ", target_name); +#endif + + /* Print targinfo part */ + t = ip6t_get_target((struct ip6t_entry *)e); + if (t->u.user.name[0]) { + struct xtables_target *target = + xtables_find_target(t->u.user.name, XTF_TRY_LOAD); + + if (!target) { + fprintf(stderr, "Can't find library for target `%s'\n", + t->u.user.name); + exit(1); + } + + if (target->save) + target->save(&e->ipv6, t); + else { + /* If the target size is greater than ip6t_entry_target + * there is something to be saved, we just don't know + * how to print it */ + if (t->u.target_size != + sizeof(struct ip6t_entry_target)) { + fprintf(stderr, "Target `%s' is missing " + "save function\n", + t->u.user.name); + exit(1); + } + } + } + printf("\n"); } -int load_ip6tables_ko(const char *modprobe) +static int +list_rules(const ip6t_chainlabel chain, int rulenum, int counters, + struct ip6tc_handle *handle) { - static int loaded = 0; - static int ret = -1; + const char *this = NULL; + int found = 0; + + if (counters) + counters = -1; /* iptables -c format */ + + /* Dump out chain names first, + * thereby preventing dependency conflicts */ + if (!rulenum) for (this = ip6tc_first_chain(handle); + this; + this = ip6tc_next_chain(handle)) { + if (chain && strcmp(this, chain) != 0) + continue; - if (!loaded) { - ret = ip6tables_insmod("ip6_tables", modprobe); - loaded = 1; + if (ip6tc_builtin(this, handle)) { + struct ip6t_counters count; + printf("-P %s %s", this, ip6tc_get_policy(this, &count, handle)); + if (counters) + printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); + printf("\n"); + } else { + printf("-N %s\n", this); + } } - return ret; + for (this = ip6tc_first_chain(handle); + this; + this = ip6tc_next_chain(handle)) { + const struct ip6t_entry *e; + int num = 0; + + if (chain && strcmp(this, chain) != 0) + continue; + + /* Dump out rules */ + e = ip6tc_first_rule(this, handle); + while(e) { + num++; + if (!rulenum || num == rulenum) + print_rule(e, handle, this, counters); + e = ip6tc_next_rule(e, handle); + } + found = 1; + } + + errno = ENOENT; + return found; } static struct ip6t_entry * generate_entry(const struct ip6t_entry *fw, - struct ip6tables_rule_match *matches, + struct xtables_rule_match *matches, struct ip6t_entry_target *target) { unsigned int size; - struct ip6tables_rule_match *matchp; + struct xtables_rule_match *matchp; struct ip6t_entry *e; size = sizeof(struct ip6t_entry); for (matchp = matches; matchp; matchp = matchp->next) size += matchp->match->m->u.match_size; - e = fw_malloc(size + target->u.target_size); + e = xtables_malloc(size + target->u.target_size); *e = *fw; e->target_offset = size; e->next_offset = size + target->u.target_size; @@ -1823,9 +1269,9 @@ generate_entry(const struct ip6t_entry *fw, return e; } -void clear_rule_matches(struct ip6tables_rule_match **matches) +static void clear_rule_matches(struct xtables_rule_match **matches) { - struct ip6tables_rule_match *matchp, *tmp; + struct xtables_rule_match *matchp, *tmp; for (matchp = *matches; matchp;) { tmp = matchp->next; @@ -1844,20 +1290,13 @@ void clear_rule_matches(struct ip6tables_rule_match **matches) *matches = NULL; } -static void set_revision(char *name, u_int8_t revision) -{ - /* Old kernel sources don't have ".revision" field, - but we stole a byte from name. */ - name[IP6T_FUNCTION_MAXNAMELEN - 2] = '\0'; - name[IP6T_FUNCTION_MAXNAMELEN - 1] = revision; -} - -int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) +int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **handle) { struct ip6t_entry fw, *e = NULL; int invert = 0; unsigned int nsaddrs = 0, ndaddrs = 0; struct in6_addr *saddrs = NULL, *daddrs = NULL; + struct in6_addr *smasks = NULL, *dmasks = NULL; int c, verbose = 0; const char *chain = NULL; @@ -1866,14 +1305,15 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) unsigned int rulenum = 0, options = 0, command = 0; const char *pcnt = NULL, *bcnt = NULL; int ret = 1; - struct ip6tables_match *m; - struct ip6tables_rule_match *matches = NULL; - struct ip6tables_rule_match *matchp; - struct ip6tables_target *target = NULL; - struct ip6tables_target *t; + struct xtables_match *m; + struct xtables_rule_match *matches = NULL; + struct xtables_rule_match *matchp; + struct xtables_target *target = NULL; + struct xtables_target *t; const char *jumpto = ""; char *protocol = NULL; int proto_used = 0; + unsigned long long cnt; memset(&fw, 0, sizeof(fw)); @@ -1883,10 +1323,10 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) /* clear mflags in case do_command gets called a second time * (we clear the global list of all matches for security)*/ - for (m = ip6tables_matches; m; m = m->next) + for (m = xtables_matches; m; m = m->next) m->mflags = 0; - for (t = ip6tables_targets; t; t = t->next) { + for (t = xtables_targets; t; t = t->next) { t->tflags = 0; t->used = 0; } @@ -1896,7 +1336,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) opterr = 0; while ((c = getopt_long(argc, argv, - "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:", + "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:g:", opts, NULL)) != -1) { switch (c) { /* @@ -1927,7 +1367,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "-%c requires a rule number", cmd2char(CMD_REPLACE)); break; @@ -1943,12 +1383,27 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) break; case 'L': - add_command(&command, CMD_LIST, CMD_ZERO, - invert); + add_command(&command, CMD_LIST, + CMD_ZERO | CMD_ZERO_NUM, invert); + if (optarg) chain = optarg; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + chain = argv[optind++]; + if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + rulenum = parse_rulenumber(argv[optind++]); + break; + + case 'S': + add_command(&command, CMD_LIST_RULES, + CMD_ZERO | CMD_ZERO_NUM, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; + if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + rulenum = parse_rulenumber(argv[optind++]); break; case 'F': @@ -1961,21 +1416,26 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) break; case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST, + add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; + if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') { + rulenum = parse_rulenumber(argv[optind++]); + command = CMD_ZERO_NUM; + } break; case 'N': if (optarg && (*optarg == '-' || *optarg == '!')) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "chain name not allowed to start " "with `%c'\n", *optarg); - if (find_target(optarg, TRY_LOAD)) - exit_error(PARAMETER_PROBLEM, + if (xtables_find_target(optarg, XTF_TRY_LOAD)) + xtables_error(PARAMETER_PROBLEM, "chain name may not clash " "with target name\n"); add_command(&command, CMD_NEW_CHAIN, CMD_NONE, @@ -2000,8 +1460,8 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) && argv[optind][0] != '!') newname = argv[optind++]; else - exit_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " + xtables_error(PARAMETER_PROBLEM, + "-%c requires old-chain-name and " "new-chain-name", cmd2char(CMD_RENAME_CHAIN)); break; @@ -2014,7 +1474,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) && argv[optind][0] != '!') policy = argv[optind++]; else - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "-%c requires a chain and a policy", cmd2char(CMD_SET_POLICY)); break; @@ -2025,7 +1485,8 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) /* ip6tables -p icmp -h */ if (!matches && protocol) - find_match(protocol, TRY_LOAD, &matches); + xtables_find_match(protocol, XTF_TRY_LOAD, + &matches); exit_printhelp(matches); @@ -2033,49 +1494,60 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) * Option selection */ case 'p': - check_inverse(optarg, &invert, &optind, argc); + xtables_check_inverse(optarg, &invert, &optind, argc, argv); set_option(&options, OPT_PROTOCOL, &fw.ipv6.invflags, invert); /* Canonicalize into lower case */ - for (protocol = argv[optind-1]; *protocol; protocol++) + for (protocol = optarg; *protocol; protocol++) *protocol = tolower(*protocol); - protocol = argv[optind-1]; - fw.ipv6.proto = parse_protocol(protocol); + protocol = optarg; + fw.ipv6.proto = xtables_parse_protocol(protocol); fw.ipv6.flags |= IP6T_F_PROTO; if (fw.ipv6.proto == 0 && (fw.ipv6.invflags & IP6T_INV_PROTO)) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); - - if (fw.ipv6.proto != IPPROTO_ESP && - is_exthdr(fw.ipv6.proto)) - printf("Warning: never matched protocol: %s. " - "use exension match instead.", protocol); + + if (is_exthdr(fw.ipv6.proto) + && (fw.ipv6.invflags & IP6T_INV_PROTO) == 0) + fprintf(stderr, + "Warning: never matched protocol: %s. " + "use extension match instead.\n", + protocol); break; case 's': - check_inverse(optarg, &invert, &optind, argc); + xtables_check_inverse(optarg, &invert, &optind, argc, argv); set_option(&options, OPT_SOURCE, &fw.ipv6.invflags, invert); - shostnetworkmask = argv[optind-1]; + shostnetworkmask = optarg; break; case 'd': - check_inverse(optarg, &invert, &optind, argc); + xtables_check_inverse(optarg, &invert, &optind, argc, argv); set_option(&options, OPT_DESTINATION, &fw.ipv6.invflags, invert); - dhostnetworkmask = argv[optind-1]; + dhostnetworkmask = optarg; break; +#ifdef IP6T_F_GOTO + case 'g': + set_option(&options, OPT_JUMP, &fw.ipv6.invflags, + invert); + fw.ipv6.flags |= IP6T_F_GOTO; + jumpto = parse_target(optarg); + break; +#endif + case 'j': set_option(&options, OPT_JUMP, &fw.ipv6.invflags, invert); jumpto = parse_target(optarg); /* TRY_LOAD (may be chain name) */ - target = find_target(jumpto, TRY_LOAD); + target = xtables_find_target(jumpto, XTF_TRY_LOAD); if (target) { size_t size; @@ -2083,30 +1555,37 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) size = IP6T_ALIGN(sizeof(struct ip6t_entry_target)) + target->size; - target->t = fw_calloc(1, size); + target->t = xtables_calloc(1, size); target->t->u.target_size = size; strcpy(target->t->u.user.name, jumpto); + xtables_set_revision(target->t->u.user.name, + target->revision); if (target->init != NULL) - target->init(target->t, &fw.nfcache); - opts = merge_options(opts, target->extra_opts, &target->option_offset); + target->init(target->t); + opts = xtables_merge_options(opts, + target->extra_opts, + &target->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, + "can't alloc memory!"); } break; case 'i': - check_inverse(optarg, &invert, &optind, argc); + xtables_check_inverse(optarg, &invert, &optind, argc, argv); set_option(&options, OPT_VIANAMEIN, &fw.ipv6.invflags, invert); - parse_interface(argv[optind-1], + xtables_parse_interface(optarg, fw.ipv6.iniface, fw.ipv6.iniface_mask); break; case 'o': - check_inverse(optarg, &invert, &optind, argc); + xtables_check_inverse(optarg, &invert, &optind, argc, argv); set_option(&options, OPT_VIANAMEOUT, &fw.ipv6.invflags, invert); - parse_interface(argv[optind-1], + xtables_parse_interface(optarg, fw.ipv6.outiface, fw.ipv6.outiface_mask); break; @@ -2122,21 +1601,22 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) size_t size; if (invert) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --match"); - m = find_match(optarg, LOAD_MUST_SUCCEED, &matches); + m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, + &matches); size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; - m->m = fw_calloc(1, size); + m->m = xtables_calloc(1, size); m->m->u.match_size = size; strcpy(m->m->u.user.name, m->name); - set_revision(m->m->u.user.name, m->revision); + xtables_set_revision(m->m->u.user.name, m->revision); if (m->init != NULL) - m->init(m->m, &fw.nfcache); + m->init(m->m); if (m != m->next) /* Merge options for non-cloned matches */ - opts = merge_options(opts, m->extra_opts, &m->option_offset); + opts = xtables_merge_options(opts, m->extra_opts, &m->option_offset); } break; @@ -2147,9 +1627,9 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) case 't': if (invert) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); - *table = argv[optind-1]; + *table = optarg; break; case 'x': @@ -2159,10 +1639,10 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) case 'V': if (invert) - printf("Not %s ;-)\n", program_version); + printf("Not %s ;-)\n", prog_vers); else printf("%s v%s\n", - program_name, program_version); + prog_name, prog_vers); exit(0); case '0': @@ -2171,7 +1651,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) break; case 'M': - modprobe = optarg; + xtables_modprobe_program = optarg; break; case 'c': @@ -2179,54 +1659,57 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) set_option(&options, OPT_COUNTERS, &fw.ipv6.invflags, invert); pcnt = optarg; - if (optind < argc && argv[optind][0] != '-' + bcnt = strchr(pcnt + 1, ','); + if (bcnt) + bcnt++; + if (!bcnt && optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') bcnt = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, + if (!bcnt) + xtables_error(PARAMETER_PROBLEM, "-%c requires packet and byte counter", opt2char(OPT_COUNTERS)); - if (sscanf(pcnt, "%llu", (unsigned long long *)&fw.counters.pcnt) != 1) - exit_error(PARAMETER_PROBLEM, + if (sscanf(pcnt, "%llu", &cnt) != 1) + xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); + fw.counters.pcnt = cnt; - if (sscanf(bcnt, "%llu", (unsigned long long *)&fw.counters.bcnt) != 1) - exit_error(PARAMETER_PROBLEM, + if (sscanf(bcnt, "%llu", &cnt) != 1) + xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); - + fw.counters.bcnt = cnt; break; - case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { if (invert) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); invert = TRUE; optarg[0] = '\0'; continue; } - printf("Bad argument `%s'\n", optarg); + fprintf(stderr, "Bad argument `%s'\n", optarg); exit_tryhelp(2); default: - if (!target - || !(target->parse(c - target->option_offset, + if (target == NULL || target->parse == NULL || + !target->parse(c - target->option_offset, argv, invert, &target->tflags, - &fw, &target->t))) { + &fw, &target->t)) { for (matchp = matches; matchp; matchp = matchp->next) { - if (matchp->completed) + if (matchp->completed || + matchp->match->parse == NULL) continue; if (matchp->match->parse(c - matchp->match->option_offset, argv, invert, &matchp->match->mflags, &fw, - &fw.nfcache, &matchp->match->m)) break; } @@ -2257,61 +1740,78 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) */ if (m == NULL && protocol - && (!find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC, NULL) - || (find_proto(protocol, DONT_LOAD, + && (!find_proto(protocol, XTF_DONT_LOAD, + options&OPT_NUMERIC, NULL) + || (find_proto(protocol, XTF_DONT_LOAD, options&OPT_NUMERIC, NULL) && (proto_used == 0)) ) - && (m = find_proto(protocol, TRY_LOAD, + && (m = find_proto(protocol, XTF_TRY_LOAD, options&OPT_NUMERIC, &matches))) { /* Try loading protocol */ size_t size; - + proto_used = 1; size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; - m->m = fw_calloc(1, size); + m->m = xtables_calloc(1, size); m->m->u.match_size = size; strcpy(m->m->u.user.name, m->name); - set_revision(m->m->u.user.name, + xtables_set_revision(m->m->u.user.name, m->revision); if (m->init != NULL) - m->init(m->m, &fw.nfcache); + m->init(m->m); - opts = merge_options(opts, + opts = xtables_merge_options(opts, m->extra_opts, &m->option_offset); optind--; continue; } - if (!m) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind-1]); + if (!m) { + if (c == '?') { + if (optopt) { + xtables_error( + PARAMETER_PROBLEM, + "option `%s' " + "requires an " + "argument", + argv[optind-1]); + } else { + xtables_error( + PARAMETER_PROBLEM, + "unknown option " + "`%s'", + argv[optind-1]); + } + } + xtables_error(PARAMETER_PROBLEM, + "Unknown arg `%s'", optarg); + } } } invert = FALSE; } for (matchp = matches; matchp; matchp = matchp->next) - matchp->match->final_check(matchp->match->mflags); + if (matchp->match->final_check != NULL) + matchp->match->final_check(matchp->match->mflags); - if (target) + if (target != NULL && target->final_check != NULL) target->final_check(target->tflags); /* Fix me: must put inverse options checking here --MN */ if (optind < argc) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "unknown arguments found on commandline"); if (!command) - exit_error(PARAMETER_PROBLEM, "no command specified"); + xtables_error(PARAMETER_PROBLEM, "no command specified"); if (invert) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { @@ -2322,26 +1822,26 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) } if (shostnetworkmask) - parse_hostnetworkmask(shostnetworkmask, &saddrs, - &(fw.ipv6.smsk), &nsaddrs); + xtables_ip6parse_multiple(shostnetworkmask, &saddrs, + &smasks, &nsaddrs); if (dhostnetworkmask) - parse_hostnetworkmask(dhostnetworkmask, &daddrs, - &(fw.ipv6.dmsk), &ndaddrs); + xtables_ip6parse_multiple(dhostnetworkmask, &daddrs, + &dmasks, &ndaddrs); if ((nsaddrs > 1 || ndaddrs > 1) && (fw.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) - exit_error(PARAMETER_PROBLEM, "! not allowed with multiple" + xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) - exit_error(PARAMETER_PROBLEM, "Replacement rule does not " + xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); generic_opt_check(command, options); if (chain && strlen(chain) > IP6T_FUNCTION_MAXNAMELEN) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "chain name `%s' too long (must be under %i chars)", chain, IP6T_FUNCTION_MAXNAMELEN); @@ -2350,11 +1850,11 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) *handle = ip6tc_init(*table); /* try to insmod the module if iptc_init failed */ - if (!*handle && load_ip6tables_ko(modprobe) != -1) + if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1) *handle = ip6tc_init(*table); if (!*handle) - exit_error(VERSION_PROBLEM, + xtables_error(VERSION_PROBLEM, "can't initialize ip6tables table `%s': %s", *table, ip6tc_strerror(errno)); @@ -2366,7 +1866,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) || strcmp(chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ if (options & OPT_VIANAMEOUT) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), chain); @@ -2376,15 +1876,16 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) || strcmp(chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ if (options & OPT_VIANAMEIN) - exit_error(PARAMETER_PROBLEM, + xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), chain); } if (target && ip6tc_is_chain(jumpto, *handle)) { - printf("Warning: using chain %s, not extension\n", - jumpto); + fprintf(stderr, + "Warning: using chain %s, not extension\n", + jumpto); if (target->t) free(target->t); @@ -2399,16 +1900,16 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) || ip6tc_is_chain(jumpto, *handle))) { size_t size; - target = find_target(IP6T_STANDARD_TARGET, - LOAD_MUST_SUCCEED); + target = xtables_find_target(IP6T_STANDARD_TARGET, + XTF_LOAD_MUST_SUCCEED); size = sizeof(struct ip6t_entry_target) + target->size; - target->t = fw_calloc(1, size); + target->t = xtables_calloc(1, size); target->t->u.target_size = size; strcpy(target->t->u.user.name, jumpto); if (target->init != NULL) - target->init(target->t, &fw.nfcache); + target->init(target->t); } if (!target) { @@ -2416,7 +1917,12 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) * We cannot know if the plugin is corrupt, non * existant OR if the user just misspelled a * chain. */ - find_target(jumpto, LOAD_MUST_SUCCEED); +#ifdef IP6T_F_GOTO + if (fw.ipv6.flags & IP6T_F_GOTO) + xtables_error(PARAMETER_PROBLEM, + "goto '%s' is not a chain\n", jumpto); +#endif + xtables_find_target(jumpto, XTF_LOAD_MUST_SUCCEED); } else { e = generate_entry(&fw, matches, target->t); free(target->t); @@ -2426,66 +1932,82 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) switch (command) { case CMD_APPEND: ret = append_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, + nsaddrs, saddrs, smasks, + ndaddrs, daddrs, dmasks, options&OPT_VERBOSE, - handle); + *handle); break; case CMD_DELETE: ret = delete_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, + nsaddrs, saddrs, smasks, + ndaddrs, daddrs, dmasks, options&OPT_VERBOSE, - handle, matches); + *handle, matches, target); break; case CMD_DELETE_NUM: - ret = ip6tc_delete_num_entry(chain, rulenum - 1, handle); + ret = ip6tc_delete_num_entry(chain, rulenum - 1, *handle); break; case CMD_REPLACE: ret = replace_entry(chain, e, rulenum - 1, - saddrs, daddrs, options&OPT_VERBOSE, - handle); + saddrs, smasks, daddrs, dmasks, + options&OPT_VERBOSE, *handle); break; case CMD_INSERT: ret = insert_entry(chain, e, rulenum - 1, - nsaddrs, saddrs, ndaddrs, daddrs, + nsaddrs, saddrs, smasks, + ndaddrs, daddrs, dmasks, options&OPT_VERBOSE, - handle); - break; - case CMD_LIST: - ret = list_entries(chain, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, - handle); + *handle); break; case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, handle); + ret = flush_entries(chain, options&OPT_VERBOSE, *handle); break; case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, handle); + ret = zero_entries(chain, options&OPT_VERBOSE, *handle); + break; + case CMD_ZERO_NUM: + ret = ip6tc_zero_counter(chain, rulenum, *handle); break; + case CMD_LIST: case CMD_LIST|CMD_ZERO: + case CMD_LIST|CMD_ZERO_NUM: ret = list_entries(chain, + rulenum, options&OPT_VERBOSE, options&OPT_NUMERIC, options&OPT_EXPANDED, options&OPT_LINENUMBERS, - handle); - if (ret) + *handle); + if (ret && (command & CMD_ZERO)) + ret = zero_entries(chain, + options&OPT_VERBOSE, *handle); + if (ret && (command & CMD_ZERO_NUM)) + ret = ip6tc_zero_counter(chain, rulenum, *handle); + break; + case CMD_LIST_RULES: + case CMD_LIST_RULES|CMD_ZERO: + case CMD_LIST_RULES|CMD_ZERO_NUM: + ret = list_rules(chain, + rulenum, + options&OPT_VERBOSE, + *handle); + if (ret && (command & CMD_ZERO)) ret = zero_entries(chain, - options&OPT_VERBOSE, handle); + options&OPT_VERBOSE, *handle); + if (ret && (command & CMD_ZERO_NUM)) + ret = ip6tc_zero_counter(chain, rulenum, *handle); break; case CMD_NEW_CHAIN: - ret = ip6tc_create_chain(chain, handle); + ret = ip6tc_create_chain(chain, *handle); break; case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, handle); + ret = delete_chain(chain, options&OPT_VERBOSE, *handle); break; case CMD_RENAME_CHAIN: - ret = ip6tc_rename_chain(chain, newname, handle); + ret = ip6tc_rename_chain(chain, newname, *handle); break; case CMD_SET_POLICY: - ret = ip6tc_set_policy(chain, policy, NULL, handle); + ret = ip6tc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, *handle); break; default: /* We should never reach this... */ @@ -2502,13 +2024,11 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) e = NULL; } - for (c = 0; c < nsaddrs; c++) - free(&saddrs[c]); - - for (c = 0; c < ndaddrs; c++) - free(&daddrs[c]); - - free_opts(1); + free(saddrs); + free(smasks); + free(daddrs); + free(dmasks); + xtables_free_opts(1); return ret; } |