From: Mark Huang Date: Mon, 1 Nov 2004 19:25:42 +0000 (+0000) Subject: cleanup junk, add spec file X-Git-Tag: iptables-1.3.8-0~29 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=f53efc600ef842c8e60617ea1bbe21b308cb2c59;p=iptables.git cleanup junk, add spec file --- diff --git a/.#iptables.c.1.54 b/.#iptables.c.1.54 deleted file mode 100644 index a838e56..0000000 --- a/.#iptables.c.1.54 +++ /dev/null @@ -1,2298 +0,0 @@ -/* Code to take an iptables-style command line and do it. */ - -/* - * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au - * - * (C) 2000-2002 by the netfilter coreteam : - * Paul 'Rusty' Russell - * Marc Boucher - * James Morris - * Harald Welte - * Jozsef Kadlecsik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef IPT_LIB_DIR -#define IPT_LIB_DIR "/usr/lib/iptables" -#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 -#define FMT_OPTIONS 0x0008 -#define FMT_NOTABLE 0x0010 -#define FMT_NOTARGET 0x0020 -#define FMT_VIA 0x0040 -#define FMT_NONEWLINE 0x0080 -#define FMT_LINENUMBERS 0x0100 - -#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ - | FMT_NUMERIC | FMT_NOTABLE) -#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) - - -#define CMD_NONE 0x0000U -#define CMD_INSERT 0x0001U -#define CMD_DELETE 0x0002U -#define CMD_DELETE_NUM 0x0004U -#define CMD_REPLACE 0x0008U -#define CMD_APPEND 0x0010U -#define CMD_LIST 0x0020U -#define CMD_FLUSH 0x0040U -#define CMD_ZERO 0x0080U -#define CMD_NEW_CHAIN 0x0100U -#define CMD_DELETE_CHAIN 0x0200U -#define CMD_SET_POLICY 0x0400U -#define CMD_CHECK 0x0800U -#define CMD_RENAME_CHAIN 0x1000U -#define NUMBER_OF_CMD 13 -static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', - 'N', 'X', 'P', 'E' }; - -#define OPTION_OFFSET 256 - -#define OPT_NONE 0x00000U -#define OPT_NUMERIC 0x00001U -#define OPT_SOURCE 0x00002U -#define OPT_DESTINATION 0x00004U -#define OPT_PROTOCOL 0x00008U -#define OPT_JUMP 0x00010U -#define OPT_VERBOSE 0x00020U -#define OPT_EXPANDED 0x00040U -#define OPT_VIANAMEIN 0x00080U -#define OPT_VIANAMEOUT 0x00100U -#define OPT_FRAGMENT 0x00200U -#define OPT_LINENUMBERS 0x00400U -#define OPT_COUNTERS 0x00800U -#define NUMBER_OF_OPT 12 -static const char optflags[NUMBER_OF_OPT] -= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '3', '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' }, - { "fragments", 0, 0, 'f' }, - { "version", 0, 0, 'V' }, - { "help", 2, 0, 'h' }, - { "line-numbers", 0, 0, '0' }, - { "modprobe", 1, 0, 'M' }, - { "set-counters", 1, 0, 'c' }, - { 0 } -}; - -/* we need this for iptables-restore. iptables-restore.c sets line to the - * current line of the input file, in order to give a more precise error - * message. iptables itself doesn't need this, so it is initialized to the - * magic number of -1 */ -int line = -1; - -#ifndef __OPTIMIZE__ -struct ipt_entry_target * -ipt_get_target(struct ipt_entry *e) -{ - return (void *)e + e->target_offset; -} -#endif - -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to - * CMD_LIST and CMD_ZERO only). - * Key: - * + compulsory - * x illegal - * optional - */ - -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 -f --line */ -/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, -/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*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'}, -/*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'}, -/*CHECK*/ {'x','+','+','+','x',' ','x',' ',' ',' ','x'}, -/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'} -}; - -static int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IPT_INV_SRCIP, -/* -d */ IPT_INV_DSTIP, -/* -p */ IPT_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IPT_INV_VIA_IN, -/* -o */ IPT_INV_VIA_OUT, -/* -f */ IPT_INV_FRAG, -/*--line*/ 0 -}; - -const char *program_version; -const char *program_name; - -/* Keeping track of external matches and targets: linked lists. */ -struct iptables_match *iptables_matches = NULL; -struct iptables_target *iptables_targets = NULL; - -/* Extra debugging from libiptc */ -extern void dump_entries(const iptc_handle_t handle); - -/* A few hardcoded protocols for 'all' and in case the user has no - /etc/protocols */ -struct pprot { - char *name; - 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 }, - { "icmp", IPPROTO_ICMP }, - { "esp", IPPROTO_ESP }, - { "ah", IPPROTO_AH }, - { "all", 0 }, -}; - -static char * -proto_to_name(u_int8_t proto, int nolookup) -{ - unsigned int i; - - if (proto && !nolookup) { - struct protoent *pent = getprotobynumber(proto); - if (pent) - 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; - - return NULL; -} - -struct in_addr * -dotted_to_addr(const char *dotted) -{ - static struct in_addr addr; - unsigned char *addrp; - char *p, *q; - unsigned int onebyte; - int i; - char buf[20]; - - /* copy dotted string, because we need to modify it */ - strncpy(buf, dotted, sizeof(buf) - 1); - addrp = (unsigned char *) &(addr.s_addr); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return (struct in_addr *) NULL; - - *q = '\0'; - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[i] = (unsigned char) onebyte; - p = q + 1; - } - - /* we've checked 3 bytes, now we check the last one */ - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[3] = (unsigned char) onebyte; - - return &addr; -} - -static struct in_addr * -network_to_addr(const char *name) -{ - struct netent *net; - static struct in_addr addr; - - if ((net = getnetbyname(name)) != NULL) { - if (net->n_addrtype != AF_INET) - return (struct in_addr *) NULL; - addr.s_addr = htonl((unsigned long) net->n_net); - return &addr; - } - - return (struct in_addr *) NULL; -} - -static void -inaddrcpy(struct in_addr *dst, struct in_addr *src) -{ - /* memcpy(dst, src, sizeof(struct in_addr)); */ - dst->s_addr = src->s_addr; -} - -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 iptables or your kernel needs to be upgraded.\n"); - 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 ); - exit(status); -} - -void -exit_printhelp(void) -{ - struct iptables_match *m = NULL; - struct iptables_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 -D chain rulenum [options]\n" -" %s -[LFZ] [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); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" 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" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain] 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" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" 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" -" source specification\n" -" --destination -d [!] address[/mask]\n" -" destination specification\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" -" --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" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -"[!] --fragment -f match second or further fragments only\n" -" --modprobe= try to insert modules using this command\n" -" --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 matches & targets */ - for (t=iptables_targets;t;t=t->next) { - printf("\n"); - t->help(); - } - for (m=iptables_matches;m;m=m->next) { - printf("\n"); - m->help(); - } - exit(0); -} - -static void -generic_opt_check(int command, int options) -{ - int i, j, legal = 0; - - /* Check that commands are valid with options. Complicated by the - * fact that if an option is legal with *any* command given, it is - * legal overall (ie. -z and -l). - */ - for (i = 0; i < NUMBER_OF_OPT; i++) { - legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ - - for (j = 0; j < NUMBER_OF_CMD; j++) { - if (!(command & (1< 1; option >>= 1, ptr++); - - return *ptr; -} - -static char -cmd2char(int option) -{ - const char *ptr; - for (ptr = cmdflags; option > 1; option >>= 1, ptr++); - - return *ptr; -} - -static void -add_command(int *cmd, const int newcmd, const int othercmds, int invert) -{ - if (invert) - exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); - if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Can't 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("iptables: calloc failed"); - exit(1); - } - return p; -} - -static void * -fw_malloc(size_t size) -{ - void *p; - - if ((p = malloc(size)) == NULL) { - perror("iptables: malloc failed"); - exit(1); - } - return p; -} - -static struct in_addr * -host_to_addr(const char *name, unsigned int *naddr) -{ - struct hostent *host; - struct in_addr *addr; - unsigned int i; - - *naddr = 0; - if ((host = gethostbyname(name)) != NULL) { - if (host->h_addrtype != AF_INET || - host->h_length != sizeof(struct in_addr)) - return (struct in_addr *) NULL; - - while (host->h_addr_list[*naddr] != (char *) NULL) - (*naddr)++; - addr = fw_calloc(*naddr, sizeof(struct in_addr)); - for (i = 0; i < *naddr; i++) - inaddrcpy(&(addr[i]), - (struct in_addr *) host->h_addr_list[i]); - return addr; - } - - return (struct in_addr *) NULL; -} - -static char * -addr_to_host(const struct in_addr *addr) -{ - struct hostent *host; - - if ((host = gethostbyaddr((char *) addr, - sizeof(struct in_addr), AF_INET)) != NULL) - return (char *) host->h_name; - - return (char *) NULL; -} - -/* - * All functions starting with "parse" should succeed, otherwise - * the program fails. - * Most routines return pointers to static data that may change - * between calls to the same or other routines with a few exceptions: - * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" - * return global static data. -*/ - -static struct in_addr * -parse_hostnetwork(const char *name, unsigned int *naddrs) -{ - struct in_addr *addrp, *addrptmp; - - if ((addrptmp = dotted_to_addr(name)) != NULL || - (addrptmp = network_to_addr(name)) != NULL) { - addrp = fw_malloc(sizeof(struct in_addr)); - inaddrcpy(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 in_addr * -parse_mask(char *mask) -{ - static struct in_addr maskaddr; - struct in_addr *addrp; - unsigned int bits; - - if (mask == NULL) { - /* no mask at all defaults to 32 bits */ - maskaddr.s_addr = 0xFFFFFFFF; - return &maskaddr; - } - if ((addrp = dotted_to_addr(mask)) != NULL) - /* dotted_to_addr already returns a network byte order addr */ - return addrp; - if (string_to_number(mask, 0, 32, &bits) == -1) - exit_error(PARAMETER_PROBLEM, - "invalid mask `%s' specified", mask); - if (bits != 0) { - maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); - return &maskaddr; - } - - maskaddr.s_addr = 0L; - return &maskaddr; -} - -void -parse_hostnetworkmask(const char *name, struct in_addr **addrpp, - struct in_addr *maskp, unsigned int *naddrs) -{ - struct in_addr *addrp; - char buf[256]; - char *p; - int i, j, k, n; - - strncpy(buf, name, sizeof(buf) - 1); - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - addrp = parse_mask(p + 1); - } else - addrp = parse_mask(NULL); - inaddrcpy(maskp, addrp); - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (maskp->s_addr == 0L) - strcpy(buf, "0.0.0.0"); - - addrp = *addrpp = parse_hostnetwork(buf, naddrs); - n = *naddrs; - for (i = 0, j = 0; i < n; i++) { - addrp[j++].s_addr &= maskp->s_addr; - for (k = 0; k < j - 1; k++) { - if (addrp[k].s_addr == addrp[j - 1].s_addr) { - (*naddrs)--; - j--; - break; - } - } - } -} - -struct iptables_match * -find_match(const char *name, enum ipt_tryload tryload) -{ - struct iptables_match *ptr; - - for (ptr = iptables_matches; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", 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); - - 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) - ptr->used = 1; - - return ptr; -} - -/* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static struct iptables_match * -find_proto(const char *pname, enum ipt_tryload tryload, int nolookup) -{ - unsigned int proto; - - if (string_to_number(pname, 0, 255, &proto) != -1) { - char *protoname = proto_to_name(proto, nolookup); - - if (protoname) - return find_match(protoname, tryload); - } else - return find_match(pname, tryload); - - 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; - - 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; -} - -static 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) - 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 (!isalnum(vianame[i]) - && vianame[i] != '_' - && vianame[i] != '.') { - printf("Warning: wierd 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, - "Invalid rule number `%s'", rule); - - return rulenum; -} - -static const char * -parse_target(const char *targetname) -{ - const char *ptr; - - if (strlen(targetname) < 1) - exit_error(PARAMETER_PROBLEM, - "Invalid target name (too short)"); - - if (strlen(targetname)+1 > sizeof(ipt_chainlabel)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s' (%i chars max)", - targetname, sizeof(ipt_chainlabel)-1); - - for (ptr = targetname; *ptr; ptr++) - if (isspace(*ptr)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s'", targetname); - return targetname; -} - -static char * -addr_to_network(const struct in_addr *addr) -{ - struct netent *net; - - if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL) - return (char *) net->n_name; - - return (char *) NULL; -} - -char * -addr_to_dotted(const struct in_addr *addrp) -{ - static char buf[20]; - const unsigned char *bytep; - - bytep = (const unsigned char *) &(addrp->s_addr); - sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); - return buf; -} - -char * -addr_to_anyname(const struct in_addr *addr) -{ - char *name; - - if ((name = addr_to_host(addr)) != NULL || - (name = addr_to_network(addr)) != NULL) - return name; - - return addr_to_dotted(addr); -} - -char * -mask_to_dotted(const struct in_addr *mask) -{ - int i; - static char buf[20]; - u_int32_t maskaddr, bits; - - maskaddr = ntohl(mask->s_addr); - - if (maskaddr == 0xFFFFFFFFL) - /* we don't want to see "/32" */ - return ""; - - i = 32; - bits = 0xFFFFFFFEL; - while (--i >= 0 && maskaddr != bits) - bits <<= 1; - if (i >= 0) - sprintf(buf, "/%d", i); - else - /* mask was not a decent combination of 1's and 0's */ - sprintf(buf, "/%s", addr_to_dotted(mask)); - - return buf; -} - -int -string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtol(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && number <= max) { - *ret = number; - return 0; - } - } - return -1; -} - -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", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - exit_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - -struct iptables_target * -find_target(const char *name, enum ipt_tryload tryload) -{ - struct iptables_target *ptr; - - /* Standard target? */ - if (strcmp(name, "") == 0 - || strcmp(name, IPTC_LABEL_ACCEPT) == 0 - || strcmp(name, IPTC_LABEL_DROP) == 0 - || strcmp(name, IPTC_LABEL_QUEUE) == 0 - || strcmp(name, IPTC_LABEL_RETURN) == 0) - name = "standard"; - - for (ptr = iptables_targets; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", 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)); - 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; -} - -void -register_match(struct iptables_match *me) -{ - struct iptables_match **i; - - 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); - } - - if (find_match(me->name, DONT_LOAD)) { - fprintf(stderr, "%s: match `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: match `%s' has invalid size %u.\n", - program_name, me->name, me->size); - exit(1); - } - - /* Append to list. */ - for (i = &iptables_matches; *i; i = &(*i)->next); - me->next = NULL; - *i = me; - - me->m = NULL; - me->mflags = 0; -} - -void -register_target(struct iptables_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, DONT_LOAD)) { - fprintf(stderr, "%s: target `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: target `%s' has invalid size %u.\n", - program_name, me->name, me->size); - exit(1); - } - - /* Prepend to list. */ - me->next = iptables_targets; - iptables_targets = me; - me->t = NULL; - me->tflags = 0; -} - -static void -print_num(u_int64_t number, unsigned int format) -{ - if (format & FMT_KILOMEGAGIGA) { - if (number > 99999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - printf(FMT("%4lluT ","%lluT "), number); - } - else printf(FMT("%4lluG ","%lluG "), number); - } - else printf(FMT("%4lluM ","%lluM "), number); - } else - printf(FMT("%4lluK ","%lluK "), number); - } else - printf(FMT("%5llu ","%llu "), number); - } else - printf(FMT("%8llu ","%llu "), number); -} - - -static void -print_header(unsigned int format, const char *chain, iptc_handle_t *handle) -{ - struct ipt_counters counters; - const char *pol = iptc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!iptc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - -static int -print_match(const struct ipt_entry_match *m, - const struct ipt_ip *ip, - int numeric) -{ - struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD); - - if (match) { - if (match->print) - match->print(ip, m, numeric); - else - printf("%s ", match->name); - } else { - if (m->u.user.name[0]) - printf("UNKNOWN match `%s' ", m->u.user.name); - } - /* Don't stop iterating. */ - return 0; -} - -/* e is called `fw' here for hysterical raisins */ -static void -print_firewall(const struct ipt_entry *fw, - const char *targname, - unsigned int num, - unsigned int format, - const iptc_handle_t handle) -{ - struct iptables_target *target = NULL; - const struct ipt_entry_target *t; - u_int8_t flags; - char buf[BUFSIZ]; - - if (!iptc_is_chain(targname, handle)) - target = find_target(targname, TRY_LOAD); - else - target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED); - - t = ipt_get_target((struct ipt_entry *)fw); - flags = fw->ip.flags; - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num+1); - - if (!(format & FMT_NOCOUNTS)) { - print_num(fw->counters.pcnt, format); - print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); - - fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout); - { - char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ip.proto); - } - - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); - fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); - fputc(' ', stdout); - } - - if (format & FMT_VIA) { - char iface[IFNAMSIZ+2]; - - if (fw->ip.invflags & IPT_INV_VIA_IN) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ip.iniface[0] != '\0') { - strcat(iface, fw->ip.iniface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT(" %-6s ","in %s "), iface); - - if (fw->ip.invflags & IPT_INV_VIA_OUT) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ip.outiface[0] != '\0') { - strcat(iface, fw->ip.outiface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT("%-6s ","out %s "), iface); - } - - fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout); - if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC)) - printf(FMT("%-19s ","%s "), "anywhere"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src))); - strcat(buf, mask_to_dotted(&(fw->ip.smsk))); - printf(FMT("%-19s ","%s "), buf); - } - - fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout); - if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC)) - printf(FMT("%-19s","-> %s"), "anywhere"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst))); - strcat(buf, mask_to_dotted(&(fw->ip.dmsk))); - printf(FMT("%-19s","-> %s"), buf); - } - - if (format & FMT_NOTABLE) - fputs(" ", stdout); - - IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); - - if (target) { - if (target->print) - /* Print the target information. */ - target->print(&fw->ip, t, format & FMT_NUMERIC); - } else if (t->u.target_size != sizeof(*t)) - printf("[%u bytes of unknown target data] ", - t->u.target_size - sizeof(*t)); - - if (!(format & FMT_NONEWLINE)) - fputc('\n', stdout); -} - -static void -print_firewall_line(const struct ipt_entry *fw, - const iptc_handle_t h) -{ - struct ipt_entry_target *t; - - t = ipt_get_target((struct ipt_entry *)fw); - print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); -} - -static int -append_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_append_entry(chain, fw, handle); - } - } - - return ret; -} - -static int -replace_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int rulenum, - const struct in_addr *saddr, - const struct in_addr *daddr, - int verbose, - iptc_handle_t *handle) -{ - fw->ip.src.s_addr = saddr->s_addr; - fw->ip.dst.s_addr = daddr->s_addr; - - if (verbose) - print_firewall_line(fw, *handle); - return iptc_replace_entry(chain, fw, rulenum, handle); -} - -static int -insert_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int rulenum, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_insert_entry(chain, fw, rulenum, handle); - } - } - - return ret; -} - -static unsigned char * -make_delete_mask(struct ipt_entry *fw) -{ - /* Establish mask for comparison */ - unsigned int size; - struct iptables_match *m; - unsigned char *mask, *mptr; - - size = sizeof(struct ipt_entry); - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; - } - - mask = fw_calloc(1, size - + IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->size); - - memset(mask, 0xFF, sizeof(struct ipt_entry)); - mptr = mask + sizeof(struct ipt_entry); - - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - memset(mptr, 0xFF, - IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->userspacesize); - mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; - } - - memset(mptr, 0xFF, - IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->userspacesize); - - return mask; -} - -static int -delete_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - unsigned char *mask; - - mask = make_delete_mask(fw); - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_delete_entry(chain, fw, mask, handle); - } - } - return ret; -} - -int -for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *), - int verbose, int builtinstoo, iptc_handle_t *handle) -{ - int ret = 1; - const char *chain; - char *chains; - unsigned int i, chaincount = 0; - - chain = iptc_first_chain(handle); - while (chain) { - chaincount++; - chain = iptc_next_chain(handle); - } - - chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount); - i = 0; - chain = iptc_first_chain(handle); - while (chain) { - strcpy(chains + i*sizeof(ipt_chainlabel), chain); - i++; - chain = iptc_next_chain(handle); - } - - for (i = 0; i < chaincount; i++) { - if (!builtinstoo - && iptc_builtin(chains + i*sizeof(ipt_chainlabel), - *handle)) - continue; - ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle); - } - - free(chains); - return ret; -} - -int -flush_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(flush_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Flushing chain `%s'\n", chain); - return iptc_flush_entries(chain, handle); -} - -static int -zero_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(zero_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Zeroing chain `%s'\n", chain); - return iptc_zero_entries(chain, handle); -} - -int -delete_chain(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(delete_chain, verbose, 0, handle); - - if (verbose) - fprintf(stdout, "Deleting chain `%s'\n", chain); - return iptc_delete_chain(chain, handle); -} - -static int -list_entries(const ipt_chainlabel chain, int verbose, int numeric, - int expanded, int linenumbers, iptc_handle_t *handle) -{ - int found = 0; - unsigned int format; - const char *this; - - format = FMT_OPTIONS; - if (!verbose) - format |= FMT_NOCOUNTS; - else - format |= FMT_VIA; - - if (numeric) - format |= FMT_NUMERIC; - - if (!expanded) - format |= FMT_KILOMEGAGIGA; - - if (linenumbers) - format |= FMT_LINENUMBERS; - - for (this = iptc_first_chain(handle); - this; - this = iptc_next_chain(handle)) { - const struct ipt_entry *i; - unsigned int num; - - if (chain && strcmp(chain, this) != 0) - continue; - - if (found) printf("\n"); - - print_header(format, this, handle); - i = iptc_first_rule(this, handle); - - num = 0; - while (i) { - print_firewall(i, - iptc_get_target(i, handle), - num++, - format, - *handle); - i = iptc_next_rule(i, handle); - } - found = 1; - } - - errno = ENOENT; - return found; -} - -static char *get_modprobe(void) -{ - int procfile; - char *ret; - - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); - if (procfile < 0) - return NULL; - - ret = malloc(1024); - if (ret) { - switch (read(procfile, ret, 1024)) { - case -1: goto fail; - case 1024: goto fail; /* Partial read. Wierd */ - } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; - close(procfile); - return ret; - } - fail: - free(ret); - close(procfile); - return NULL; -} - -int iptables_insmod(const char *modname, const char *modprobe) -{ - char *buf = NULL; - char *argv[3]; - - /* If they don't explicitly set it, read out of kernel */ - if (!modprobe) { - buf = get_modprobe(); - if (!buf) - return -1; - modprobe = buf; - } - - switch (fork()) { - case 0: - argv[0] = (char *)modprobe; - argv[1] = (char *)modname; - argv[2] = NULL; - execv(argv[0], argv); - - /* not usually reached */ - exit(0); - case -1: - return -1; - - default: /* parent */ - wait(NULL); - } - - free(buf); - return 0; -} - -static struct ipt_entry * -generate_entry(const struct ipt_entry *fw, - struct iptables_match *matches, - struct ipt_entry_target *target) -{ - unsigned int size; - struct iptables_match *m; - struct ipt_entry *e; - - size = sizeof(struct ipt_entry); - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - size += m->m->u.match_size; - } - - e = fw_malloc(size + target->u.target_size); - *e = *fw; - e->target_offset = size; - e->next_offset = size + target->u.target_size; - - size = 0; - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - memcpy(e->elems + size, m->m, m->m->u.match_size); - size += m->m->u.match_size; - } - memcpy(e->elems + size, target, target->u.target_size); - - return e; -} - -int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) -{ - struct ipt_entry fw, *e = NULL; - int invert = 0; - unsigned int nsaddrs = 0, ndaddrs = 0; - struct in_addr *saddrs = NULL, *daddrs = NULL; - - int c, verbose = 0; - const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; - const char *policy = NULL, *newname = NULL; - unsigned int rulenum = 0, options = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; - int ret = 1; - struct iptables_match *m; - struct iptables_target *target = NULL; - struct iptables_target *t; - const char *jumpto = ""; - char *protocol = NULL; - const char *modprobe = NULL; - int proto_used = 0; - - memset(&fw, 0, sizeof(fw)); - - opts = original_opts; - global_option_offset = 0; - - /* re-set optind to 0 in case do_command gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = iptables_matches; m; m = m->next) { - m->mflags = 0; - m->used = 0; - } - - for (t = iptables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - 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:fbvnt:m:xc:", - opts, NULL)) != -1) { - switch (c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, - invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, CMD_ZERO, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'N': - if (optarg && *optarg == '-') - exit_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `-'\n"); - if (find_target(optarg, TRY_LOAD)) - exit_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - newname = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - policy = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!iptables_matches && protocol) - find_match(protocol, TRY_LOAD); - - exit_printhelp(); - - /* - * Option selection - */ - case 'p': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_PROTOCOL, &fw.ip.invflags, - invert); - - /* Canonicalize into lower case */ - for (protocol = argv[optind-1]; *protocol; protocol++) - *protocol = tolower(*protocol); - - protocol = argv[optind-1]; - fw.ip.proto = parse_protocol(protocol); - - if (fw.ip.proto == 0 - && (fw.ip.invflags & IPT_INV_PROTO)) - exit_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - fw.nfcache |= NFC_IP_PROTO; - break; - - case 's': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_SOURCE, &fw.ip.invflags, - invert); - shostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP_SRC; - break; - - case 'd': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_DESTINATION, &fw.ip.invflags, - invert); - dhostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP_DST; - break; - - case 'j': - set_option(&options, OPT_JUMP, &fw.ip.invflags, - invert); - jumpto = parse_target(optarg); - /* TRY_LOAD (may be chain name) */ - target = find_target(jumpto, TRY_LOAD); - - if (target) { - size_t size; - - size = IPT_ALIGN(sizeof(struct ipt_entry_target)) - + target->size; - - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - opts = merge_options(opts, target->extra_opts, &target->option_offset); - } - break; - - - case 'i': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags, - invert); - parse_interface(argv[optind-1], - fw.ip.iniface, - fw.ip.iniface_mask); - fw.nfcache |= NFC_IP_IF_IN; - break; - - case 'o': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags, - invert); - parse_interface(argv[optind-1], - fw.ip.outiface, - fw.ip.outiface_mask); - fw.nfcache |= NFC_IP_IF_OUT; - break; - - case 'f': - set_option(&options, OPT_FRAGMENT, &fw.ip.invflags, - invert); - fw.ip.flags |= IPT_F_FRAG; - fw.nfcache |= NFC_IP_FRAG; - break; - - case 'v': - if (!verbose) - set_option(&options, OPT_VERBOSE, - &fw.ip.invflags, invert); - verbose++; - break; - - case 'm': { - size_t size; - - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --match"); - - m = find_match(optarg, LOAD_MUST_SUCCEED); - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - opts = merge_options(opts, m->extra_opts, &m->option_offset); - } - break; - - case 'n': - set_option(&options, OPT_NUMERIC, &fw.ip.invflags, - invert); - break; - - case 't': - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - *table = argv[optind-1]; - break; - - case 'x': - set_option(&options, OPT_EXPANDED, &fw.ip.invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", program_version); - else - printf("%s v%s\n", - program_name, program_version); - exit(0); - - case '0': - set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags, - invert); - break; - - case 'M': - modprobe = optarg; - break; - - case 'c': - - set_option(&options, OPT_COUNTERS, &fw.ip.invflags, - invert); - pcnt = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - bcnt = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - - if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - - break; - - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - exit_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = TRUE; - optarg[0] = '\0'; - continue; - } - printf("Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - /* FIXME: This scheme doesn't allow two of the same - matches --RR */ - if (!target - || !(target->parse(c - target->option_offset, - argv, invert, - &target->tflags, - &fw, &target->t))) { - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - if (m->parse(c - m->option_offset, - argv, invert, - &m->mflags, - &fw, - &fw.nfcache, - &m->m)) - break; - } - - /* If you listen carefully, you can - actually hear this code suck. */ - - /* some explanations (after four different bugs - * in 3 different releases): If we encountere a - * parameter, that has not been parsed yet, - * it's not an option of an explicitly loaded - * match or a target. However, we support - * implicit loading of the protocol match - * extension. '-p tcp' means 'l4 proto 6' and - * at the same time 'load tcp protocol match on - * demand if we specify --dport'. - * - * To make this work, we need to make sure: - * - the parameter has not been parsed by - * a match (m above) - * - a protocol has been specified - * - the protocol extension has not been - * loaded yet, or is loaded and unused - * [think of iptables-restore!] - * - the protocol extension can be successively - * loaded - */ - if (m == NULL - && protocol - && (!find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - || (find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - && (proto_used == 0)) - ) - && (m = find_proto(protocol, TRY_LOAD, - options&OPT_NUMERIC))) { - /* Try loading protocol */ - size_t size; - - proto_used = 1; - - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - - opts = merge_options(opts, - m->extra_opts, &m->option_offset); - - optind--; - continue; - } - if (!m) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind-1]); - } - } - invert = FALSE; - } - - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - m->final_check(m->mflags); - } - - if (target) - target->final_check(target->tflags); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - exit_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - exit_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - exit_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) - dhostnetworkmask = "0.0.0.0/0"; - if (!(options & OPT_SOURCE)) - shostnetworkmask = "0.0.0.0/0"; - } - - if (shostnetworkmask) - parse_hostnetworkmask(shostnetworkmask, &saddrs, - &(fw.ip.smsk), &nsaddrs); - - if (dhostnetworkmask) - parse_hostnetworkmask(dhostnetworkmask, &daddrs, - &(fw.ip.dmsk), &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - exit_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 " - "specify a unique address"); - - generic_opt_check(command, options); - - if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN) - exit_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %i chars)", - chain, IPT_FUNCTION_MAXNAMELEN); - - /* only allocate handle if we weren't called with a handle */ - if (!*handle) - *handle = iptc_init(*table); - - if (!*handle) { - /* try to insmod the module if iptc_init failed */ - iptables_insmod("ip_tables", modprobe); - *handle = iptc_init(*table); - } - - if (!*handle) - exit_error(VERSION_PROBLEM, - "can't initialize iptables table `%s': %s", - *table, iptc_strerror(errno)); - - if (command == CMD_APPEND - || command == CMD_DELETE - || command == CMD_INSERT - || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - - if (target && iptc_is_chain(jumpto, *handle)) { - printf("Warning: using chain %s, not extension\n", - jumpto); - - target = NULL; - } - - /* If they didn't specify a target, or it's a chain - name, use standard. */ - if (!target - && (strlen(jumpto) == 0 - || iptc_is_chain(jumpto, *handle))) { - size_t size; - - target = find_target(IPT_STANDARD_TARGET, - LOAD_MUST_SUCCEED); - - size = sizeof(struct ipt_entry_target) - + target->size; - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - } - - if (!target) { - /* it is no chain, and we can't load a plugin. - * We cannot know if the plugin is corrupt, non - * existant OR if the user just misspelled a - * chain. */ - find_target(jumpto, LOAD_MUST_SUCCEED); - } else { - e = generate_entry(&fw, iptables_matches, target->t); - } - } - - switch (command) { - case CMD_APPEND: - ret = append_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE: - ret = delete_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE_NUM: - ret = iptc_delete_num_entry(chain, rulenum - 1, handle); - break; - case CMD_REPLACE: - ret = replace_entry(chain, e, rulenum - 1, - saddrs, daddrs, options&OPT_VERBOSE, - handle); - break; - case CMD_INSERT: - ret = insert_entry(chain, e, rulenum - 1, - nsaddrs, saddrs, ndaddrs, daddrs, - 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); - break; - case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_LIST|CMD_ZERO: - ret = list_entries(chain, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, - handle); - if (ret) - ret = zero_entries(chain, - options&OPT_VERBOSE, handle); - break; - case CMD_NEW_CHAIN: - ret = iptc_create_chain(chain, handle); - break; - case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, handle); - break; - case CMD_RENAME_CHAIN: - ret = iptc_rename_chain(chain, newname, handle); - break; - case CMD_SET_POLICY: - ret = iptc_set_policy(chain, policy, NULL, handle); - break; - default: - /* We should never reach this... */ - exit_tryhelp(2); - } - - if (verbose > 1) - dump_entries(*handle); - - return ret; -} diff --git a/.#iptables.c.1.55 b/.#iptables.c.1.55 deleted file mode 100644 index b8087f1..0000000 --- a/.#iptables.c.1.55 +++ /dev/null @@ -1,2303 +0,0 @@ -/* Code to take an iptables-style command line and do it. */ - -/* - * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au - * - * (C) 2000-2002 by the netfilter coreteam : - * Paul 'Rusty' Russell - * Marc Boucher - * James Morris - * Harald Welte - * Jozsef Kadlecsik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef IPT_LIB_DIR -#define IPT_LIB_DIR "/usr/lib/iptables" -#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 -#define FMT_OPTIONS 0x0008 -#define FMT_NOTABLE 0x0010 -#define FMT_NOTARGET 0x0020 -#define FMT_VIA 0x0040 -#define FMT_NONEWLINE 0x0080 -#define FMT_LINENUMBERS 0x0100 - -#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ - | FMT_NUMERIC | FMT_NOTABLE) -#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) - - -#define CMD_NONE 0x0000U -#define CMD_INSERT 0x0001U -#define CMD_DELETE 0x0002U -#define CMD_DELETE_NUM 0x0004U -#define CMD_REPLACE 0x0008U -#define CMD_APPEND 0x0010U -#define CMD_LIST 0x0020U -#define CMD_FLUSH 0x0040U -#define CMD_ZERO 0x0080U -#define CMD_NEW_CHAIN 0x0100U -#define CMD_DELETE_CHAIN 0x0200U -#define CMD_SET_POLICY 0x0400U -#define CMD_CHECK 0x0800U -#define CMD_RENAME_CHAIN 0x1000U -#define NUMBER_OF_CMD 13 -static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', - 'N', 'X', 'P', 'E' }; - -#define OPTION_OFFSET 256 - -#define OPT_NONE 0x00000U -#define OPT_NUMERIC 0x00001U -#define OPT_SOURCE 0x00002U -#define OPT_DESTINATION 0x00004U -#define OPT_PROTOCOL 0x00008U -#define OPT_JUMP 0x00010U -#define OPT_VERBOSE 0x00020U -#define OPT_EXPANDED 0x00040U -#define OPT_VIANAMEIN 0x00080U -#define OPT_VIANAMEOUT 0x00100U -#define OPT_FRAGMENT 0x00200U -#define OPT_LINENUMBERS 0x00400U -#define OPT_COUNTERS 0x00800U -#define NUMBER_OF_OPT 12 -static const char optflags[NUMBER_OF_OPT] -= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '3', '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' }, - { "fragments", 0, 0, 'f' }, - { "version", 0, 0, 'V' }, - { "help", 2, 0, 'h' }, - { "line-numbers", 0, 0, '0' }, - { "modprobe", 1, 0, 'M' }, - { "set-counters", 1, 0, 'c' }, - { 0 } -}; - -/* we need this for iptables-restore. iptables-restore.c sets line to the - * current line of the input file, in order to give a more precise error - * message. iptables itself doesn't need this, so it is initialized to the - * magic number of -1 */ -int line = -1; - -#ifndef __OPTIMIZE__ -struct ipt_entry_target * -ipt_get_target(struct ipt_entry *e) -{ - return (void *)e + e->target_offset; -} -#endif - -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to - * CMD_LIST and CMD_ZERO only). - * Key: - * + compulsory - * x illegal - * optional - */ - -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 -f --line */ -/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, -/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*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'}, -/*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'}, -/*CHECK*/ {'x','+','+','+','x',' ','x',' ',' ',' ','x'}, -/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'} -}; - -static int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IPT_INV_SRCIP, -/* -d */ IPT_INV_DSTIP, -/* -p */ IPT_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IPT_INV_VIA_IN, -/* -o */ IPT_INV_VIA_OUT, -/* -f */ IPT_INV_FRAG, -/*--line*/ 0 -}; - -const char *program_version; -const char *program_name; - -/* Keeping track of external matches and targets: linked lists. */ -struct iptables_match *iptables_matches = NULL; -struct iptables_target *iptables_targets = NULL; - -/* Extra debugging from libiptc */ -extern void dump_entries(const iptc_handle_t handle); - -/* A few hardcoded protocols for 'all' and in case the user has no - /etc/protocols */ -struct pprot { - char *name; - 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 }, - { "icmp", IPPROTO_ICMP }, - { "esp", IPPROTO_ESP }, - { "ah", IPPROTO_AH }, - { "all", 0 }, -}; - -static char * -proto_to_name(u_int8_t proto, int nolookup) -{ - unsigned int i; - - if (proto && !nolookup) { - struct protoent *pent = getprotobynumber(proto); - if (pent) - 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; - - return NULL; -} - -struct in_addr * -dotted_to_addr(const char *dotted) -{ - static struct in_addr addr; - unsigned char *addrp; - char *p, *q; - unsigned int onebyte; - int i; - char buf[20]; - - /* copy dotted string, because we need to modify it */ - strncpy(buf, dotted, sizeof(buf) - 1); - addrp = (unsigned char *) &(addr.s_addr); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return (struct in_addr *) NULL; - - *q = '\0'; - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[i] = (unsigned char) onebyte; - p = q + 1; - } - - /* we've checked 3 bytes, now we check the last one */ - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[3] = (unsigned char) onebyte; - - return &addr; -} - -static struct in_addr * -network_to_addr(const char *name) -{ - struct netent *net; - static struct in_addr addr; - - if ((net = getnetbyname(name)) != NULL) { - if (net->n_addrtype != AF_INET) - return (struct in_addr *) NULL; - addr.s_addr = htonl((unsigned long) net->n_net); - return &addr; - } - - return (struct in_addr *) NULL; -} - -static void -inaddrcpy(struct in_addr *dst, struct in_addr *src) -{ - /* memcpy(dst, src, sizeof(struct in_addr)); */ - dst->s_addr = src->s_addr; -} - -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 iptables or your kernel needs to be upgraded.\n"); - exit(status); -} - -void -exit_tryhelp(int status) -{ -<<<<<<< iptables.c - if (line != -1) - fprintf(stderr, "Error occurred at line: %d\n", line); -======= - if (line != -1) - fprintf(stderr, "Error occured at line: %d\n", line); ->>>>>>> 1.55 - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - program_name, program_name ); - exit(status); -} - -void -exit_printhelp(void) -{ - struct iptables_match *m = NULL; - struct iptables_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 -D chain rulenum [options]\n" -" %s -[LFZ] [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); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" 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" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain] 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" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" 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" -" source specification\n" -" --destination -d [!] address[/mask]\n" -" destination specification\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" -" --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" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -"[!] --fragment -f match second or further fragments only\n" -" --modprobe= try to insert modules using this command\n" -" --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 matches & targets */ - for (t=iptables_targets;t;t=t->next) { - printf("\n"); - t->help(); - } - for (m=iptables_matches;m;m=m->next) { - printf("\n"); - m->help(); - } - exit(0); -} - -static void -generic_opt_check(int command, int options) -{ - int i, j, legal = 0; - - /* Check that commands are valid with options. Complicated by the - * fact that if an option is legal with *any* command given, it is - * legal overall (ie. -z and -l). - */ - for (i = 0; i < NUMBER_OF_OPT; i++) { - legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ - - for (j = 0; j < NUMBER_OF_CMD; j++) { - if (!(command & (1< 1; option >>= 1, ptr++); - - return *ptr; -} - -static char -cmd2char(int option) -{ - const char *ptr; - for (ptr = cmdflags; option > 1; option >>= 1, ptr++); - - return *ptr; -} - -static void -add_command(int *cmd, const int newcmd, const int othercmds, int invert) -{ - if (invert) - exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); - if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Can't 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("iptables: calloc failed"); - exit(1); - } - return p; -} - -static void * -fw_malloc(size_t size) -{ - void *p; - - if ((p = malloc(size)) == NULL) { - perror("iptables: malloc failed"); - exit(1); - } - return p; -} - -static struct in_addr * -host_to_addr(const char *name, unsigned int *naddr) -{ - struct hostent *host; - struct in_addr *addr; - unsigned int i; - - *naddr = 0; - if ((host = gethostbyname(name)) != NULL) { - if (host->h_addrtype != AF_INET || - host->h_length != sizeof(struct in_addr)) - return (struct in_addr *) NULL; - - while (host->h_addr_list[*naddr] != (char *) NULL) - (*naddr)++; - addr = fw_calloc(*naddr, sizeof(struct in_addr)); - for (i = 0; i < *naddr; i++) - inaddrcpy(&(addr[i]), - (struct in_addr *) host->h_addr_list[i]); - return addr; - } - - return (struct in_addr *) NULL; -} - -static char * -addr_to_host(const struct in_addr *addr) -{ - struct hostent *host; - - if ((host = gethostbyaddr((char *) addr, - sizeof(struct in_addr), AF_INET)) != NULL) - return (char *) host->h_name; - - return (char *) NULL; -} - -/* - * All functions starting with "parse" should succeed, otherwise - * the program fails. - * Most routines return pointers to static data that may change - * between calls to the same or other routines with a few exceptions: - * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" - * return global static data. -*/ - -static struct in_addr * -parse_hostnetwork(const char *name, unsigned int *naddrs) -{ - struct in_addr *addrp, *addrptmp; - - if ((addrptmp = dotted_to_addr(name)) != NULL || - (addrptmp = network_to_addr(name)) != NULL) { - addrp = fw_malloc(sizeof(struct in_addr)); - inaddrcpy(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 in_addr * -parse_mask(char *mask) -{ - static struct in_addr maskaddr; - struct in_addr *addrp; - unsigned int bits; - - if (mask == NULL) { - /* no mask at all defaults to 32 bits */ - maskaddr.s_addr = 0xFFFFFFFF; - return &maskaddr; - } - if ((addrp = dotted_to_addr(mask)) != NULL) - /* dotted_to_addr already returns a network byte order addr */ - return addrp; - if (string_to_number(mask, 0, 32, &bits) == -1) - exit_error(PARAMETER_PROBLEM, - "invalid mask `%s' specified", mask); - if (bits != 0) { - maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); - return &maskaddr; - } - - maskaddr.s_addr = 0L; - return &maskaddr; -} - -void -parse_hostnetworkmask(const char *name, struct in_addr **addrpp, - struct in_addr *maskp, unsigned int *naddrs) -{ - struct in_addr *addrp; - char buf[256]; - char *p; - int i, j, k, n; - - strncpy(buf, name, sizeof(buf) - 1); - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - addrp = parse_mask(p + 1); - } else - addrp = parse_mask(NULL); - inaddrcpy(maskp, addrp); - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (maskp->s_addr == 0L) - strcpy(buf, "0.0.0.0"); - - addrp = *addrpp = parse_hostnetwork(buf, naddrs); - n = *naddrs; - for (i = 0, j = 0; i < n; i++) { - addrp[j++].s_addr &= maskp->s_addr; - for (k = 0; k < j - 1; k++) { - if (addrp[k].s_addr == addrp[j - 1].s_addr) { - (*naddrs)--; - j--; - break; - } - } - } -} - -struct iptables_match * -find_match(const char *name, enum ipt_tryload tryload) -{ - struct iptables_match *ptr; - - for (ptr = iptables_matches; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", 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); - - 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) - ptr->used = 1; - - return ptr; -} - -/* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static struct iptables_match * -find_proto(const char *pname, enum ipt_tryload tryload, int nolookup) -{ - unsigned int proto; - - if (string_to_number(pname, 0, 255, &proto) != -1) { - char *protoname = proto_to_name(proto, nolookup); - - if (protoname) - return find_match(protoname, tryload); - } else - return find_match(pname, tryload); - - 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; - - 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; -} - -static 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) - 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 (!isalnum(vianame[i]) - && vianame[i] != '_' - && vianame[i] != '.') { - printf("Warning: wierd 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, - "Invalid rule number `%s'", rule); - - return rulenum; -} - -static const char * -parse_target(const char *targetname) -{ - const char *ptr; - - if (strlen(targetname) < 1) - exit_error(PARAMETER_PROBLEM, - "Invalid target name (too short)"); - - if (strlen(targetname)+1 > sizeof(ipt_chainlabel)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s' (%i chars max)", - targetname, sizeof(ipt_chainlabel)-1); - - for (ptr = targetname; *ptr; ptr++) - if (isspace(*ptr)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s'", targetname); - return targetname; -} - -static char * -addr_to_network(const struct in_addr *addr) -{ - struct netent *net; - - if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL) - return (char *) net->n_name; - - return (char *) NULL; -} - -char * -addr_to_dotted(const struct in_addr *addrp) -{ - static char buf[20]; - const unsigned char *bytep; - - bytep = (const unsigned char *) &(addrp->s_addr); - sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); - return buf; -} - -char * -addr_to_anyname(const struct in_addr *addr) -{ - char *name; - - if ((name = addr_to_host(addr)) != NULL || - (name = addr_to_network(addr)) != NULL) - return name; - - return addr_to_dotted(addr); -} - -char * -mask_to_dotted(const struct in_addr *mask) -{ - int i; - static char buf[20]; - u_int32_t maskaddr, bits; - - maskaddr = ntohl(mask->s_addr); - - if (maskaddr == 0xFFFFFFFFL) - /* we don't want to see "/32" */ - return ""; - - i = 32; - bits = 0xFFFFFFFEL; - while (--i >= 0 && maskaddr != bits) - bits <<= 1; - if (i >= 0) - sprintf(buf, "/%d", i); - else - /* mask was not a decent combination of 1's and 0's */ - sprintf(buf, "/%s", addr_to_dotted(mask)); - - return buf; -} - -int -string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtol(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && number <= max) { - *ret = number; - return 0; - } - } - return -1; -} - -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", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - exit_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - -struct iptables_target * -find_target(const char *name, enum ipt_tryload tryload) -{ - struct iptables_target *ptr; - - /* Standard target? */ - if (strcmp(name, "") == 0 - || strcmp(name, IPTC_LABEL_ACCEPT) == 0 - || strcmp(name, IPTC_LABEL_DROP) == 0 - || strcmp(name, IPTC_LABEL_QUEUE) == 0 - || strcmp(name, IPTC_LABEL_RETURN) == 0) - name = "standard"; - - for (ptr = iptables_targets; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", 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)); - 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; -} - -void -register_match(struct iptables_match *me) -{ - struct iptables_match **i; - - 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); - } - - if (find_match(me->name, DONT_LOAD)) { - fprintf(stderr, "%s: match `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: match `%s' has invalid size %u.\n", - program_name, me->name, me->size); - exit(1); - } - - /* Append to list. */ - for (i = &iptables_matches; *i; i = &(*i)->next); - me->next = NULL; - *i = me; - - me->m = NULL; - me->mflags = 0; -} - -void -register_target(struct iptables_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, DONT_LOAD)) { - fprintf(stderr, "%s: target `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: target `%s' has invalid size %u.\n", - program_name, me->name, me->size); - exit(1); - } - - /* Prepend to list. */ - me->next = iptables_targets; - iptables_targets = me; - me->t = NULL; - me->tflags = 0; -} - -static void -print_num(u_int64_t number, unsigned int format) -{ - if (format & FMT_KILOMEGAGIGA) { - if (number > 99999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - printf(FMT("%4lluT ","%lluT "), number); - } - else printf(FMT("%4lluG ","%lluG "), number); - } - else printf(FMT("%4lluM ","%lluM "), number); - } else - printf(FMT("%4lluK ","%lluK "), number); - } else - printf(FMT("%5llu ","%llu "), number); - } else - printf(FMT("%8llu ","%llu "), number); -} - - -static void -print_header(unsigned int format, const char *chain, iptc_handle_t *handle) -{ - struct ipt_counters counters; - const char *pol = iptc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!iptc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - -static int -print_match(const struct ipt_entry_match *m, - const struct ipt_ip *ip, - int numeric) -{ - struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD); - - if (match) { - if (match->print) - match->print(ip, m, numeric); - else - printf("%s ", match->name); - } else { - if (m->u.user.name[0]) - printf("UNKNOWN match `%s' ", m->u.user.name); - } - /* Don't stop iterating. */ - return 0; -} - -/* e is called `fw' here for hysterical raisins */ -static void -print_firewall(const struct ipt_entry *fw, - const char *targname, - unsigned int num, - unsigned int format, - const iptc_handle_t handle) -{ - struct iptables_target *target = NULL; - const struct ipt_entry_target *t; - u_int8_t flags; - char buf[BUFSIZ]; - - if (!iptc_is_chain(targname, handle)) - target = find_target(targname, TRY_LOAD); - else - target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED); - - t = ipt_get_target((struct ipt_entry *)fw); - flags = fw->ip.flags; - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num+1); - - if (!(format & FMT_NOCOUNTS)) { - print_num(fw->counters.pcnt, format); - print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); - - fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout); - { - char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ip.proto); - } - - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); - fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); - fputc(' ', stdout); - } - - if (format & FMT_VIA) { - char iface[IFNAMSIZ+2]; - - if (fw->ip.invflags & IPT_INV_VIA_IN) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ip.iniface[0] != '\0') { - strcat(iface, fw->ip.iniface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT(" %-6s ","in %s "), iface); - - if (fw->ip.invflags & IPT_INV_VIA_OUT) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ip.outiface[0] != '\0') { - strcat(iface, fw->ip.outiface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT("%-6s ","out %s "), iface); - } - - fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout); - if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC)) - printf(FMT("%-19s ","%s "), "anywhere"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src))); - strcat(buf, mask_to_dotted(&(fw->ip.smsk))); - printf(FMT("%-19s ","%s "), buf); - } - - fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout); - if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC)) - printf(FMT("%-19s","-> %s"), "anywhere"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst))); - strcat(buf, mask_to_dotted(&(fw->ip.dmsk))); - printf(FMT("%-19s","-> %s"), buf); - } - - if (format & FMT_NOTABLE) - fputs(" ", stdout); - - IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); - - if (target) { - if (target->print) - /* Print the target information. */ - target->print(&fw->ip, t, format & FMT_NUMERIC); - } else if (t->u.target_size != sizeof(*t)) - printf("[%u bytes of unknown target data] ", - t->u.target_size - sizeof(*t)); - - if (!(format & FMT_NONEWLINE)) - fputc('\n', stdout); -} - -static void -print_firewall_line(const struct ipt_entry *fw, - const iptc_handle_t h) -{ - struct ipt_entry_target *t; - - t = ipt_get_target((struct ipt_entry *)fw); - print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); -} - -static int -append_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_append_entry(chain, fw, handle); - } - } - - return ret; -} - -static int -replace_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int rulenum, - const struct in_addr *saddr, - const struct in_addr *daddr, - int verbose, - iptc_handle_t *handle) -{ - fw->ip.src.s_addr = saddr->s_addr; - fw->ip.dst.s_addr = daddr->s_addr; - - if (verbose) - print_firewall_line(fw, *handle); - return iptc_replace_entry(chain, fw, rulenum, handle); -} - -static int -insert_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int rulenum, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_insert_entry(chain, fw, rulenum, handle); - } - } - - return ret; -} - -static unsigned char * -make_delete_mask(struct ipt_entry *fw) -{ - /* Establish mask for comparison */ - unsigned int size; - struct iptables_match *m; - unsigned char *mask, *mptr; - - size = sizeof(struct ipt_entry); - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; - } - - mask = fw_calloc(1, size - + IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->size); - - memset(mask, 0xFF, sizeof(struct ipt_entry)); - mptr = mask + sizeof(struct ipt_entry); - - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - memset(mptr, 0xFF, - IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->userspacesize); - mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; - } - - memset(mptr, 0xFF, - IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->userspacesize); - - return mask; -} - -static int -delete_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - unsigned char *mask; - - mask = make_delete_mask(fw); - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_delete_entry(chain, fw, mask, handle); - } - } - return ret; -} - -int -for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *), - int verbose, int builtinstoo, iptc_handle_t *handle) -{ - int ret = 1; - const char *chain; - char *chains; - unsigned int i, chaincount = 0; - - chain = iptc_first_chain(handle); - while (chain) { - chaincount++; - chain = iptc_next_chain(handle); - } - - chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount); - i = 0; - chain = iptc_first_chain(handle); - while (chain) { - strcpy(chains + i*sizeof(ipt_chainlabel), chain); - i++; - chain = iptc_next_chain(handle); - } - - for (i = 0; i < chaincount; i++) { - if (!builtinstoo - && iptc_builtin(chains + i*sizeof(ipt_chainlabel), - *handle)) - continue; - ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle); - } - - free(chains); - return ret; -} - -int -flush_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(flush_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Flushing chain `%s'\n", chain); - return iptc_flush_entries(chain, handle); -} - -static int -zero_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(zero_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Zeroing chain `%s'\n", chain); - return iptc_zero_entries(chain, handle); -} - -int -delete_chain(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(delete_chain, verbose, 0, handle); - - if (verbose) - fprintf(stdout, "Deleting chain `%s'\n", chain); - return iptc_delete_chain(chain, handle); -} - -static int -list_entries(const ipt_chainlabel chain, int verbose, int numeric, - int expanded, int linenumbers, iptc_handle_t *handle) -{ - int found = 0; - unsigned int format; - const char *this; - - format = FMT_OPTIONS; - if (!verbose) - format |= FMT_NOCOUNTS; - else - format |= FMT_VIA; - - if (numeric) - format |= FMT_NUMERIC; - - if (!expanded) - format |= FMT_KILOMEGAGIGA; - - if (linenumbers) - format |= FMT_LINENUMBERS; - - for (this = iptc_first_chain(handle); - this; - this = iptc_next_chain(handle)) { - const struct ipt_entry *i; - unsigned int num; - - if (chain && strcmp(chain, this) != 0) - continue; - - if (found) printf("\n"); - - print_header(format, this, handle); - i = iptc_first_rule(this, handle); - - num = 0; - while (i) { - print_firewall(i, - iptc_get_target(i, handle), - num++, - format, - *handle); - i = iptc_next_rule(i, handle); - } - found = 1; - } - - errno = ENOENT; - return found; -} - -static char *get_modprobe(void) -{ - int procfile; - char *ret; - - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); - if (procfile < 0) - return NULL; - - ret = malloc(1024); - if (ret) { - switch (read(procfile, ret, 1024)) { - case -1: goto fail; - case 1024: goto fail; /* Partial read. Wierd */ - } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; - close(procfile); - return ret; - } - fail: - free(ret); - close(procfile); - return NULL; -} - -int iptables_insmod(const char *modname, const char *modprobe) -{ - char *buf = NULL; - char *argv[3]; - - /* If they don't explicitly set it, read out of kernel */ - if (!modprobe) { - buf = get_modprobe(); - if (!buf) - return -1; - modprobe = buf; - } - - switch (fork()) { - case 0: - argv[0] = (char *)modprobe; - argv[1] = (char *)modname; - argv[2] = NULL; - execv(argv[0], argv); - - /* not usually reached */ - exit(0); - case -1: - return -1; - - default: /* parent */ - wait(NULL); - } - - free(buf); - return 0; -} - -static struct ipt_entry * -generate_entry(const struct ipt_entry *fw, - struct iptables_match *matches, - struct ipt_entry_target *target) -{ - unsigned int size; - struct iptables_match *m; - struct ipt_entry *e; - - size = sizeof(struct ipt_entry); - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - size += m->m->u.match_size; - } - - e = fw_malloc(size + target->u.target_size); - *e = *fw; - e->target_offset = size; - e->next_offset = size + target->u.target_size; - - size = 0; - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - memcpy(e->elems + size, m->m, m->m->u.match_size); - size += m->m->u.match_size; - } - memcpy(e->elems + size, target, target->u.target_size); - - return e; -} - -int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) -{ - struct ipt_entry fw, *e = NULL; - int invert = 0; - unsigned int nsaddrs = 0, ndaddrs = 0; - struct in_addr *saddrs = NULL, *daddrs = NULL; - - int c, verbose = 0; - const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; - const char *policy = NULL, *newname = NULL; - unsigned int rulenum = 0, options = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; - int ret = 1; - struct iptables_match *m; - struct iptables_target *target = NULL; - struct iptables_target *t; - const char *jumpto = ""; - char *protocol = NULL; - const char *modprobe = NULL; - int proto_used = 0; - - memset(&fw, 0, sizeof(fw)); - - opts = original_opts; - global_option_offset = 0; - - /* re-set optind to 0 in case do_command gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = iptables_matches; m; m = m->next) { - m->mflags = 0; - m->used = 0; - } - - for (t = iptables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - 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:fbvnt:m:xc:", - opts, NULL)) != -1) { - switch (c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, - invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, CMD_ZERO, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'N': - if (optarg && *optarg == '-') - exit_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `-'\n"); - if (find_target(optarg, TRY_LOAD)) - exit_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - newname = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - policy = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!iptables_matches && protocol) - find_match(protocol, TRY_LOAD); - - exit_printhelp(); - - /* - * Option selection - */ - case 'p': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_PROTOCOL, &fw.ip.invflags, - invert); - - /* Canonicalize into lower case */ - for (protocol = argv[optind-1]; *protocol; protocol++) - *protocol = tolower(*protocol); - - protocol = argv[optind-1]; - fw.ip.proto = parse_protocol(protocol); - - if (fw.ip.proto == 0 - && (fw.ip.invflags & IPT_INV_PROTO)) - exit_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - fw.nfcache |= NFC_IP_PROTO; - break; - - case 's': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_SOURCE, &fw.ip.invflags, - invert); - shostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP_SRC; - break; - - case 'd': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_DESTINATION, &fw.ip.invflags, - invert); - dhostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP_DST; - break; - - case 'j': - set_option(&options, OPT_JUMP, &fw.ip.invflags, - invert); - jumpto = parse_target(optarg); - /* TRY_LOAD (may be chain name) */ - target = find_target(jumpto, TRY_LOAD); - - if (target) { - size_t size; - - size = IPT_ALIGN(sizeof(struct ipt_entry_target)) - + target->size; - - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - opts = merge_options(opts, target->extra_opts, &target->option_offset); - } - break; - - - case 'i': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags, - invert); - parse_interface(argv[optind-1], - fw.ip.iniface, - fw.ip.iniface_mask); - fw.nfcache |= NFC_IP_IF_IN; - break; - - case 'o': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags, - invert); - parse_interface(argv[optind-1], - fw.ip.outiface, - fw.ip.outiface_mask); - fw.nfcache |= NFC_IP_IF_OUT; - break; - - case 'f': - set_option(&options, OPT_FRAGMENT, &fw.ip.invflags, - invert); - fw.ip.flags |= IPT_F_FRAG; - fw.nfcache |= NFC_IP_FRAG; - break; - - case 'v': - if (!verbose) - set_option(&options, OPT_VERBOSE, - &fw.ip.invflags, invert); - verbose++; - break; - - case 'm': { - size_t size; - - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --match"); - - m = find_match(optarg, LOAD_MUST_SUCCEED); - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - opts = merge_options(opts, m->extra_opts, &m->option_offset); - } - break; - - case 'n': - set_option(&options, OPT_NUMERIC, &fw.ip.invflags, - invert); - break; - - case 't': - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - *table = argv[optind-1]; - break; - - case 'x': - set_option(&options, OPT_EXPANDED, &fw.ip.invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", program_version); - else - printf("%s v%s\n", - program_name, program_version); - exit(0); - - case '0': - set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags, - invert); - break; - - case 'M': - modprobe = optarg; - break; - - case 'c': - - set_option(&options, OPT_COUNTERS, &fw.ip.invflags, - invert); - pcnt = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - bcnt = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - - if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - - break; - - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - exit_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = TRUE; - optarg[0] = '\0'; - continue; - } - printf("Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - /* FIXME: This scheme doesn't allow two of the same - matches --RR */ - if (!target - || !(target->parse(c - target->option_offset, - argv, invert, - &target->tflags, - &fw, &target->t))) { - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - if (m->parse(c - m->option_offset, - argv, invert, - &m->mflags, - &fw, - &fw.nfcache, - &m->m)) - break; - } - - /* If you listen carefully, you can - actually hear this code suck. */ - - /* some explanations (after four different bugs - * in 3 different releases): If we encountere a - * parameter, that has not been parsed yet, - * it's not an option of an explicitly loaded - * match or a target. However, we support - * implicit loading of the protocol match - * extension. '-p tcp' means 'l4 proto 6' and - * at the same time 'load tcp protocol match on - * demand if we specify --dport'. - * - * To make this work, we need to make sure: - * - the parameter has not been parsed by - * a match (m above) - * - a protocol has been specified - * - the protocol extension has not been - * loaded yet, or is loaded and unused - * [think of iptables-restore!] - * - the protocol extension can be successively - * loaded - */ - if (m == NULL - && protocol - && (!find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - || (find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - && (proto_used == 0)) - ) - && (m = find_proto(protocol, TRY_LOAD, - options&OPT_NUMERIC))) { - /* Try loading protocol */ - size_t size; - - proto_used = 1; - - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - - opts = merge_options(opts, - m->extra_opts, &m->option_offset); - - optind--; - continue; - } - if (!m) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind-1]); - } - } - invert = FALSE; - } - - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - m->final_check(m->mflags); - } - - if (target) - target->final_check(target->tflags); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - exit_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - exit_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - exit_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) - dhostnetworkmask = "0.0.0.0/0"; - if (!(options & OPT_SOURCE)) - shostnetworkmask = "0.0.0.0/0"; - } - - if (shostnetworkmask) - parse_hostnetworkmask(shostnetworkmask, &saddrs, - &(fw.ip.smsk), &nsaddrs); - - if (dhostnetworkmask) - parse_hostnetworkmask(dhostnetworkmask, &daddrs, - &(fw.ip.dmsk), &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - exit_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 " - "specify a unique address"); - - generic_opt_check(command, options); - - if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN) - exit_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %i chars)", - chain, IPT_FUNCTION_MAXNAMELEN); - - /* only allocate handle if we weren't called with a handle */ - if (!*handle) - *handle = iptc_init(*table); - - if (!*handle) { - /* try to insmod the module if iptc_init failed */ - iptables_insmod("ip_tables", modprobe); - *handle = iptc_init(*table); - } - - if (!*handle) - exit_error(VERSION_PROBLEM, - "can't initialize iptables table `%s': %s", - *table, iptc_strerror(errno)); - - if (command == CMD_APPEND - || command == CMD_DELETE - || command == CMD_INSERT - || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - - if (target && iptc_is_chain(jumpto, *handle)) { - printf("Warning: using chain %s, not extension\n", - jumpto); - - target = NULL; - } - - /* If they didn't specify a target, or it's a chain - name, use standard. */ - if (!target - && (strlen(jumpto) == 0 - || iptc_is_chain(jumpto, *handle))) { - size_t size; - - target = find_target(IPT_STANDARD_TARGET, - LOAD_MUST_SUCCEED); - - size = sizeof(struct ipt_entry_target) - + target->size; - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - } - - if (!target) { - /* it is no chain, and we can't load a plugin. - * We cannot know if the plugin is corrupt, non - * existant OR if the user just misspelled a - * chain. */ - find_target(jumpto, LOAD_MUST_SUCCEED); - } else { - e = generate_entry(&fw, iptables_matches, target->t); - } - } - - switch (command) { - case CMD_APPEND: - ret = append_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE: - ret = delete_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE_NUM: - ret = iptc_delete_num_entry(chain, rulenum - 1, handle); - break; - case CMD_REPLACE: - ret = replace_entry(chain, e, rulenum - 1, - saddrs, daddrs, options&OPT_VERBOSE, - handle); - break; - case CMD_INSERT: - ret = insert_entry(chain, e, rulenum - 1, - nsaddrs, saddrs, ndaddrs, daddrs, - 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); - break; - case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_LIST|CMD_ZERO: - ret = list_entries(chain, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, - handle); - if (ret) - ret = zero_entries(chain, - options&OPT_VERBOSE, handle); - break; - case CMD_NEW_CHAIN: - ret = iptc_create_chain(chain, handle); - break; - case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, handle); - break; - case CMD_RENAME_CHAIN: - ret = iptc_rename_chain(chain, newname, handle); - break; - case CMD_SET_POLICY: - ret = iptc_set_policy(chain, policy, NULL, handle); - break; - default: - /* We should never reach this... */ - exit_tryhelp(2); - } - - if (verbose > 1) - dump_entries(*handle); - - return ret; -} diff --git a/Makefile.nolibnsl b/Makefile.nolibnsl deleted file mode 100644 index 622a680..0000000 --- a/Makefile.nolibnsl +++ /dev/null @@ -1,208 +0,0 @@ -# uncomment this to get a fully statically linked version -# NO_SHARED_LIBS = 1 - -# uncomment this to disable IPv6 support -# DO_IPV6 = 0 - -###################################################################### -# YOU SHOULD NOT NEED TO TOUCH ANYTHING BELOW THIS LINE -###################################################################### - -# Standard part of Makefile for topdir. -TOPLEVEL_INCLUDED=YES - -ifndef KERNEL_DIR -KERNEL_DIR=/usr/src/linux -endif -IPTABLES_VERSION:=1.2.9 -OLD_IPTABLES_VERSION:=1.2.8 - -PREFIX:=/usr -LIBDIR:=$(PREFIX)/lib -BINDIR:=$(PREFIX)/sbin -MANDIR:=$(PREFIX)/man -INCDIR:=$(PREFIX)/include - -# directory for new iptables releases -RELEASE_DIR:=/tmp - -# Need libc6 for this. FIXME: Should covert to autoconf. -ifeq ($(shell [ -f /usr/include/netinet/ip6.h ] && echo YES), YES) -DO_IPV6:=1 -endif - -COPT_FLAGS:=-O2 -CFLAGS:=$(COPT_FLAGS) -Wall -Wunused -I$(KERNEL_DIR)/include -Iinclude/ -DIPTABLES_VERSION=\"$(IPTABLES_VERSION)\" #-g -DDEBUG #-pg # -DIPTC_DEBUG - -ifdef NO_SHARED_LIBS -CFLAGS += -DNO_SHARED_LIBS=1 -endif - -ifndef NO_SHARED_LIBS -DEPFILES = $(SHARED_LIBS:%.so=%.d) -SH_CFLAGS:=$(CFLAGS) -fPIC -STATIC_LIBS = -STATIC6_LIBS = -LDFLAGS = -rdynamic -LDLIBS = -ldl -lnsl -else -DEPFILES = $(EXT_OBJS:%.o=%.d) -STATIC_LIBS = extensions/libext.a -STATIC6_LIBS = extensions/libext6.a -LDFLAGS = -static -LDLIBS = -endif - -EXTRAS+=iptables iptables.o -EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(MANDIR)/man8/iptables.8 - -# No longer experimental. -EXTRAS+=iptables-save iptables-restore -EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore $(DESTDIR)$(MANDIR)/man8/iptables-restore.8 $(DESTDIR)$(MANDIR)/man8/iptables-save.8 - -ifeq ($(DO_IPV6), 1) -EXTRAS+=ip6tables ip6tables.o -EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/ip6tables $(DESTDIR)$(MANDIR)/man8/ip6tables.8 -EXTRAS_EXP+=ip6tables-save ip6tables-restore -EXTRA_INSTALLS_EXP+=$(DESTDIR)$(BINDIR)/ip6tables-save $(DESTDIR)$(BINDIR)/ip6tables-restore # $(DESTDIR)$(MANDIR)/man8/iptables-restore.8 $(DESTDIR)$(MANDIR)/man8/iptables-save.8 $(DESTDIR)$(MANDIR)/man8/ip6tables-save.8 $(DESTDIR)$(MANDIR)/man8/ip6tables-restore.8 -endif - -# Sparc64 hack -ifeq ($(shell uname -m),sparc64) -# The kernel is 64-bit, even though userspace is 32. -CFLAGS+=-DIPT_MIN_ALIGN=8 -DKERNEL_64_USERSPACE_32 -endif - -# HPPA hack -ifeq ($(shell uname -m),parisc64) -# The kernel is 64-bit, even though userspace is 32. -CFLAGS+=-DIPT_MIN_ALIGN=8 -DKERNEL_64_USERSPACE_32 -endif - -ifndef IPT_LIBDIR -IPT_LIBDIR:=$(LIBDIR)/iptables -endif - -.PHONY: default -default: print-extensions all - -.PHONY: print-extensions -print-extensions: - @[ -n "$(OPTIONALS)" ] && echo Extensions found: $(OPTIONALS) - -iptables.o: iptables.c - $(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $< - -iptables: iptables-standalone.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a - $(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(DESTDIR)$(BINDIR)/iptables: iptables - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -iptables-save: iptables-save.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a - $(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(DESTDIR)$(BINDIR)/iptables-save: iptables-save - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -iptables-restore: iptables-restore.c iptables.o $(STATIC_LIBS) libiptc/libiptc.a - $(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(DESTDIR)$(BINDIR)/iptables-restore: iptables-restore - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -ip6tables.o: ip6tables.c - $(CC) $(CFLAGS) -DIP6T_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $< - -ip6tables: ip6tables-standalone.c ip6tables.o $(STATIC6_LIBS) libiptc/libiptc.a - $(CC) $(CFLAGS) -DIP6T_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(DESTDIR)$(BINDIR)/ip6tables: ip6tables - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -ip6tables-save: ip6tables-save.c ip6tables.o $(STATIC6_LIBS) libiptc/libiptc.a - $(CC) $(CFLAGS) -DIP6T_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(DESTDIR)$(BINDIR)/ip6tables-save: ip6tables-save - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -ip6tables-restore: ip6tables-restore.c ip6tables.o $(STATIC6_LIBS) libiptc/libiptc.a - $(CC) $(CFLAGS) -DIP6T_LIB_DIR=\"$(IPT_LIBDIR)\" $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(DESTDIR)$(BINDIR)/ip6tables-restore: ip6tables-restore - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -$(DESTDIR)$(MANDIR)/man8/%.8: %.8 - @[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8 - cp $< $@ - -EXTRA_DEPENDS+=iptables-standalone.d iptables.d - -iptables-standalone.d iptables.d: %.d: %.c - @-$(CC) -M -MG $(CFLAGS) $< | sed -e 's@^.*\.o:@$*.d $*.o:@' > $@ - - -# Development Targets -.PHONY: install-devel-man3 -install-devel-man3: $(DEVEL_MAN3) - @[ -d $(DESTDIR)$(MANDIR)/man3 ] || mkdir -p $(DESTDIR)$(MANDIR)/man3 - @cp -v $(DEVEL_MAN3) $(DESTDIR)$(MANDIR)/man3 - -.PHONY: install-devel-headers -install-devel-headers: $(DEVEL_HEADERS) - @[ -d $(DESTDIR)$(INCDIR) ] || mkdir -p $(DESTDIR)$(INCDIR) - @cp -v $(DEVEL_HEADERS) $(DESTDIR)$(INCDIR) - -.PHONY: install-devel-libs -install-devel-libs: $(DEVEL_LIBS) - @[ -d $(DESTDIR)$(LIBDIR) ] || mkdir -p $(DESTDIR)$(LIBDIR) - @cp -v $(DEVEL_LIBS) $(DESTDIR)$(LIBDIR) - -.PHONY: install-devel -install-devel: all install-devel-man3 install-devel-headers install-devel-libs - -.PHONY: distclean -distclean: clean - @rm -f TAGS `find . -name '*~' -o -name '.*~'` `find . -name '*.rej'` `find . -name '*.d'` .makefirst - -# Rusty's distro magic. -.PHONY: distrib -distrib: check distclean delrelease $(RELEASE_DIR)/iptables-$(IPTABLES_VERSION).tar.bz2 diff md5sums # nowhitespace - -# Makefile must not define: -# -g -pg -DIPTC_DEBUG -.PHONY: check -check: - @if echo $(CFLAGS) | egrep -e '-g|-pg|IPTC_DEBUG' >/dev/null; then echo Remove debugging flags; exit 1; else exit 0; fi - -.PHONY: nowhitespace -nowhitespace: - @if grep -n '[ ]$$' `find . -name 'Makefile' -o -name '*.[ch]'`; then exit 1; else exit 0; fi - -.PHONY: delrelease -delrelease: - rm -f $(RELEASE_DIR)/iptables-$(IPTABLES_VERSION).tar.bz2 - -$(RELEASE_DIR)/iptables-$(IPTABLES_VERSION).tar.bz2: - cd .. && ln -sf userspace iptables-$(IPTABLES_VERSION) && tar cvf - --exclude CVS iptables-$(IPTABLES_VERSION)/. | bzip2 -9 > $@ && rm iptables-$(IPTABLES_VERSION) - -.PHONY: diff -diff: $(RELEASE_DIR)/iptables-$(IPTABLES_VERSION).tar.bz2 - @mkdir /tmp/diffdir - @cd /tmp/diffdir && tar -x --bzip2 -f $(RELEASE_DIR)/iptables-$(IPTABLES_VERSION).tar.bz2 - @set -e; cd /tmp/diffdir; tar -x --bzip2 -f $(RELEASE_DIR)/iptables-$(OLD_IPTABLES_VERSION).tar.bz2; echo Creating patch-iptables-$(OLD_IPTABLES_VERSION)-$(IPTABLES_VERSION).bz2; diff -urN iptables-$(OLD_IPTABLES_VERSION) iptables-$(IPTABLES_VERSION) | bzip2 -9 > $(RELEASE_DIR)/patch-iptables-$(OLD_IPTABLES_VERSION)-$(IPTABLES_VERSION).bz2 - @rm -rf /tmp/diffdir - -.PHONY: md5sums -md5sums: - cd $(RELEASE_DIR)/ && md5sum patch-iptables-*-$(IPTABLES_VERSION).bz2 iptables-$(IPTABLES_VERSION).tar.bz2 - -# $(wildcard) fails wierdly with make v.3.78.1. -include $(shell echo */Makefile) -include Rules.make diff --git a/extensions/.#libipt_ECN.c.1.7 b/extensions/.#libipt_ECN.c.1.7 deleted file mode 100644 index 7bb0044..0000000 --- a/extensions/.#libipt_ECN.c.1.7 +++ /dev/null @@ -1,180 +0,0 @@ -/* Shared library add-on to iptables for ECN, $Version$ - * - * (C) 2002 by Harald Welte - * - * This program is distributed under the terms of GNU GPL v2, 1991 - * - * libipt_ECN.c borrowed heavily from libipt_DSCP.c - * - * $Id: libipt_ECN.c,v 1.7 2002/05/29 15:11:36 laforge Exp $ - */ -#include -#include -#include -#include - -#include -#include -#include - -static void init(struct ipt_entry_target *t, unsigned int *nfcache) -{ -} - -static void help(void) -{ - printf( -"ECN target v%s options\n" -" --ecn-tcp-remove Remove all ECN bits from TCP header\n" -"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n" -" --ecn-ip-ect Set the IPv4 ECT codepoint (0 to 3)\n" -" --ecn-tcp-cwr Set the IPv4 CWR bit (0 or 1)\n" -" --ecn-tcp-ece Set the IPv4 CWR bit (0 or 1)\n", - IPTABLES_VERSION, IPTABLES_VERSION -); -} - -static struct option opts[] = { - { "ecn-tcp-remove", 0, 0, 'F' }, - { "ecn-tcp-cwr", 1, 0, 'G' }, - { "ecn-tcp-ece", 1, 0, 'H' }, - { "ecn-ip-ect", 1, 0, '9' }, - { 0 } -}; - -static int -parse(int c, char **argv, int invert, unsigned int *flags, - const struct ipt_entry *entry, - struct ipt_entry_target **target) -{ - unsigned int result; - struct ipt_ECN_info *einfo - = (struct ipt_ECN_info *)(*target)->data; - - switch (c) { - case 'F': - if (*flags) - exit_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-tcp-remove ONCE!"); - einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR; - einfo->proto.tcp.ece = 0; - einfo->proto.tcp.cwr = 0; - *flags = 1; - break; - case 'G': - if (*flags & IPT_ECN_OP_SET_CWR) - exit_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-tcp-cwr ONCE!"); - if (string_to_number(optarg, 0, 1, &result)) - exit_error(PARAMETER_PROBLEM, - "ECN target: Value out of range"); - einfo->operation |= IPT_ECN_OP_SET_CWR; - einfo->proto.tcp.cwr = result; - *flags |= IPT_ECN_OP_SET_CWR; - break; - case 'H': - if (*flags & IPT_ECN_OP_SET_ECE) - exit_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-tcp-ece ONCE!"); - if (string_to_number(optarg, 0, 1, &result)) - exit_error(PARAMETER_PROBLEM, - "ECN target: Value out of range"); - einfo->operation |= IPT_ECN_OP_SET_ECE; - einfo->proto.tcp.ece = result; - *flags |= IPT_ECN_OP_SET_ECE; - break; - case '9': - if (*flags & IPT_ECN_OP_SET_IP) - exit_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-ip-ect ONCE!"); - if (string_to_number(optarg, 0, 3, &result)) - exit_error(PARAMETER_PROBLEM, - "ECN target: Value out of range"); - einfo->operation |= IPT_ECN_OP_SET_IP; - einfo->ip_ect = (result << IPT_ECN_SHIFT); - default: - return 0; - } - - return 1; -} - -static void -final_check(unsigned int flags) -{ - if (!flags) - exit_error(PARAMETER_PROBLEM, - "ECN target: Parameter --ecn-remove is required"); -} - -/* Prints out the targinfo. */ -static void -print(const struct ipt_ip *ip, - const struct ipt_entry_target *target, - int numeric) -{ - const struct ipt_ECN_info *einfo = - (const struct ipt_ECN_info *)target->data; - - printf("ECN "); - - if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) - && einfo->proto.tcp.ece == 0 - && einfo->proto.tcp.cwr == 0) - printf("TCP remove "); - else { - if (einfo->operation & IPT_ECN_OP_SET_ECE) - printf("ECE=%u ", einfo->proto.tcp.ece); - - if (einfo->operation & IPT_ECN_OP_SET_CWR) - printf("CWR=%u ", einfo->proto.tcp.cwr); - - if (einfo->operation & IPT_ECN_OP_SET_IP) - printf("ECT codepoint=%u ", einfo->ip_ect); - } -} - -/* Saves the union ipt_targinfo in parsable form to stdout. */ -static void -save(const struct ipt_ip *ip, const struct ipt_entry_target *target) -{ - const struct ipt_ECN_info *einfo = - (const struct ipt_ECN_info *)target->data; - - if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) - && einfo->proto.tcp.ece == 0 - && einfo->proto.tcp.cwr == 0) - printf("--ecn-tcp-remove "); - else { - - if (einfo->operation & IPT_ECN_OP_SET_ECE) - printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece); - - if (einfo->operation & IPT_ECN_OP_SET_CWR) - printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr); - - if (einfo->operation & IPT_ECN_OP_SET_IP) - printf("--ecn-ip-ect %d ", einfo->ip_ect); - } -} - -static -struct iptables_target ecn -= { NULL, - "ECN", - IPTABLES_VERSION, - IPT_ALIGN(sizeof(struct ipt_ECN_info)), - IPT_ALIGN(sizeof(struct ipt_ECN_info)), - &help, - &init, - &parse, - &final_check, - &print, - &save, - opts -}; - -void _init(void) -{ - register_target(&ecn); -} diff --git a/extensions/.#libipt_recent.c.1.6 b/extensions/.#libipt_recent.c.1.6 deleted file mode 100644 index cb86597..0000000 --- a/extensions/.#libipt_recent.c.1.6 +++ /dev/null @@ -1,229 +0,0 @@ -/* Shared library add-on to iptables to add recent matching support. */ -#include -#include -#include -#include -#include - -#include -#include - -/* Function which prints out usage message. */ -static void -help(void) -{ - printf( -"recent v%s options:\n" -"[!] --set Add source address to list, always matches.\n" -"[!] --rcheck Match if source address in list.\n" -"[!] --update Match if source address in list, also update last-seen time.\n" -"[!] --remove Match if source address in list, also removes that address from list.\n" -" --seconds seconds For check and update commands above.\n" -" Specifies that the match will only occur if source address last seen within\n" -" the last 'seconds' seconds.\n" -" --hitcount hits For check and update commands above.\n" -" Specifies that the match will only occur if source address seen hits times.\n" -" May be used in conjunction with the seconds option.\n" -" --rttl For check and update commands above.\n" -" Specifies that the match will only occur if the source address and the TTL\n" -" match between this packet and the one which was set.\n" -" Useful if you have problems with people spoofing their source address in order\n" -" to DoS you via this module.\n" -" --name name Name of the recent list to be used. DEFAULT used if none given.\n" -" --rsource Save the source address of each packet in the recent list table (default).\n" -" --rdest Save the destination address of each packet in the recent list table.\n" -, -IPTABLES_VERSION); - -} - -static struct option opts[] = { - { "set", 0, 0, 201 }, - { "rcheck", 0, 0, 202 }, - { "update", 0, 0, 203 }, - { "seconds", 1, 0, 204 }, - { "hitcount", 1, 0, 205 }, - { "remove",0, 0, 206 }, - { "rttl",0, 0, 207 }, - { "name", 1, 0, 208 }, - { "rsource", 0, 0, 209 }, - { "rdest", 0, 0, 210 }, - {0} -}; - -/* Initialize the match. */ -static void -init(struct ipt_entry_match *match, unsigned int *nfcache) -{ - struct ipt_recent_info *info = (struct ipt_recent_info *)(match)->data; - - *nfcache |= NFC_UNKNOWN; - - strncpy(info->name, "DEFAULT", 200); - info->side = IPT_RECENT_SOURCE; -} - -/* Function which parses command options; returns true if it - ate an option */ -static int -parse(int c, char **argv, int invert, unsigned int *flags, - const struct ipt_entry *entry, - unsigned int *nfcache, - struct ipt_entry_match **match) -{ - struct ipt_recent_info *info = (struct ipt_recent_info *)(*match)->data; - switch (c) { - case 201: - if (*flags) - exit_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--check' " - "`--update' or `--remove' may be set"); - check_inverse(optarg, &invert, &optind, 0); - info->check_set |= IPT_RECENT_SET; - if (invert) - info->invert = 1; - *flags = 1; - break; - - case 202: - if (*flags) - exit_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--check' " - "`--update' or `--remove' may be set"); - check_inverse(optarg, &invert, &optind, 0); - info->check_set |= IPT_RECENT_CHECK; - if (invert) - info->invert = 1; - *flags = 1; - break; - - case 203: - if (*flags) - exit_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--check' " - "`--update' or `--remove' may be set"); - check_inverse(optarg, &invert, &optind, 0); - info->check_set |= IPT_RECENT_UPDATE; - if (invert) - info->invert = 1; - *flags = 1; - break; - - case 206: - if (*flags) - exit_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--check' " - "`--update' or `--remove' may be set"); - check_inverse(optarg, &invert, &optind, 0); - info->check_set |= IPT_RECENT_REMOVE; - if (invert) - info->invert = 1; - *flags = 1; - break; - - case 204: - info->seconds = atoi(optarg); - break; - - case 205: - info->hit_count = atoi(optarg); - break; - - case 207: - info->check_set |= IPT_RECENT_TTL; - break; - - case 208: - strncpy(info->name, optarg, 200); - break; - - case 209: - info->side = IPT_RECENT_SOURCE; - break; - - case 210: - info->side = IPT_RECENT_DEST; - break; - - default: - return 0; - } - - return 1; -} - -/* Final check; must have specified a specific option. */ -static void -final_check(unsigned int flags) -{ - - if (!flags) - exit_error(PARAMETER_PROBLEM, - "recent: you must specify one of `--set', `--check' " - "`--update' or `--remove'"); -} - -/* Prints out the matchinfo. */ -static void -print(const struct ipt_ip *ip, - const struct ipt_entry_match *match, - int numeric) -{ - struct ipt_recent_info *info = (struct ipt_recent_info *)match->data; - - if (info->invert) fputc('!', stdout); - - printf("recent: "); - if(info->check_set & IPT_RECENT_SET) printf("SET "); - if(info->check_set & IPT_RECENT_CHECK) printf("CHECK "); - if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE "); - if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE "); - if(info->seconds) printf("seconds: %d ", info->seconds); - if(info->hit_count) printf("hit_count: %d ", info->hit_count); - if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match "); - if(info->name) printf("name: %s ", info->name); - if(info->side == IPT_RECENT_SOURCE) printf("side: source "); - if(info->side == IPT_RECENT_DEST) printf("side: dest"); -} - -/* Saves the union ipt_matchinfo in parsable form to stdout. */ -static void -save(const struct ipt_ip *ip, const struct ipt_entry_match *match) -{ - struct ipt_recent_info *info = (struct ipt_recent_info *)match; - - if (info->invert) fputc('!', stdout); - - printf("recent: "); - if(info->check_set & IPT_RECENT_SET) printf("SET "); - if(info->check_set & IPT_RECENT_CHECK) printf("CHECK "); - if(info->check_set & IPT_RECENT_UPDATE) printf("UPDATE "); - if(info->check_set & IPT_RECENT_REMOVE) printf("REMOVE "); - if(info->seconds) printf("seconds: %d ",info->seconds); - if(info->hit_count) printf("hit_count: %d ",info->hit_count); - if(info->check_set & IPT_RECENT_TTL) printf("TTL-Match "); - if(info->name) printf("name: %s ",info->name); - if(info->side == IPT_RECENT_SOURCE) printf("side: source "); - if(info->side == IPT_RECENT_DEST) printf("side: dest"); -} - -static -struct iptables_match recent -= { NULL, - "recent", - IPTABLES_VERSION, - IPT_ALIGN(sizeof(struct ipt_recent_info)), - IPT_ALIGN(sizeof(struct ipt_recent_info)), - &help, - &init, - &parse, - &final_check, - &print, - &save, - opts -}; - -void _init(void) -{ - register_match(&recent); -} diff --git a/extensions/libipt_icmp.c.print_type b/extensions/libipt_icmp.c.print_type deleted file mode 100644 index 6c7b1c3..0000000 --- a/extensions/libipt_icmp.c.print_type +++ /dev/null @@ -1,310 +0,0 @@ -/* Shared library add-on to iptables to add ICMP support. */ -#include -#include -#include -#include -#include -#include -#include - -/* special hack for icmp-type 'any': - * Up to kernel <=2.4.20 the problem was: - * '-p icmp ' matches all icmp packets - * '-p icmp -m icmp' matches _only_ ICMP type 0 :( - * This is now fixed by initializing the field * to icmp type 0xFF - * See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37 - */ - -struct icmp_names { - const char *name; - u_int8_t type; - u_int8_t code_min, code_max; -}; - -static const struct icmp_names icmp_codes[] = { - { "any", 0xFF, 0, 0xFF }, - { "echo-reply", 0, 0, 0xFF }, - /* Alias */ { "pong", 0, 0, 0xFF }, - - { "destination-unreachable", 3, 0, 0xFF }, - { "network-unreachable", 3, 0, 0 }, - { "host-unreachable", 3, 1, 1 }, - { "protocol-unreachable", 3, 2, 2 }, - { "port-unreachable", 3, 3, 3 }, - { "fragmentation-needed", 3, 4, 4 }, - { "source-route-failed", 3, 5, 5 }, - { "network-unknown", 3, 6, 6 }, - { "host-unknown", 3, 7, 7 }, - { "network-prohibited", 3, 9, 9 }, - { "host-prohibited", 3, 10, 10 }, - { "TOS-network-unreachable", 3, 11, 11 }, - { "TOS-host-unreachable", 3, 12, 12 }, - { "communication-prohibited", 3, 13, 13 }, - { "host-precedence-violation", 3, 14, 14 }, - { "precedence-cutoff", 3, 15, 15 }, - - { "source-quench", 4, 0, 0xFF }, - - { "redirect", 5, 0, 0xFF }, - { "network-redirect", 5, 0, 0 }, - { "host-redirect", 5, 1, 1 }, - { "TOS-network-redirect", 5, 2, 2 }, - { "TOS-host-redirect", 5, 3, 3 }, - - { "echo-request", 8, 0, 0xFF }, - /* Alias */ { "ping", 8, 0, 0xFF }, - - { "router-advertisement", 9, 0, 0xFF }, - - { "router-solicitation", 10, 0, 0xFF }, - - { "time-exceeded", 11, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, - { "ttl-zero-during-transit", 11, 0, 0 }, - { "ttl-zero-during-reassembly", 11, 1, 1 }, - - { "parameter-problem", 12, 0, 0xFF }, - { "ip-header-bad", 12, 0, 0 }, - { "required-option-missing", 12, 1, 1 }, - - { "timestamp-request", 13, 0, 0xFF }, - - { "timestamp-reply", 14, 0, 0xFF }, - - { "address-mask-request", 17, 0, 0xFF }, - - { "address-mask-reply", 18, 0, 0xFF } -}; - -static void -print_icmptypes() -{ - unsigned int i; - printf("Valid ICMP Types:"); - - for (i = 0; i < sizeof(icmp_codes)/sizeof(struct icmp_names); i++) { - if (i && icmp_codes[i].type == icmp_codes[i-1].type) { - if (icmp_codes[i].code_min == icmp_codes[i-1].code_min - && (icmp_codes[i].code_max - == icmp_codes[i-1].code_max)) - printf(" (%s)", icmp_codes[i].name); - else - printf("\n %s", icmp_codes[i].name); - } - else - printf("\n%s", icmp_codes[i].name); - } - printf("\n"); -} - -/* Function which prints out usage message. */ -static void -help(void) -{ - printf( -"ICMP v%s options:\n" -" --icmp-type [!] typename match icmp type\n" -" (or numeric type or type/code)\n" -"\n", IPTABLES_VERSION); - print_icmptypes(); -} - -static struct option opts[] = { - { "icmp-type", 1, 0, '1' }, - {0} -}; - -static unsigned int -parse_icmp(const char *icmptype, u_int8_t *type, u_int8_t code[]) -{ - unsigned int limit = sizeof(icmp_codes)/sizeof(struct icmp_names); - unsigned int match = limit; - unsigned int i; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)) - == 0) { - if (match != limit) - exit_error(PARAMETER_PROBLEM, - "Ambiguous ICMP type `%s':" - " `%s' or `%s'?", - icmptype, - icmp_codes[match].name, - icmp_codes[i].name); - match = i; - } - } - - if (match != limit) { - *type = icmp_codes[match].type; - code[0] = icmp_codes[match].code_min; - code[1] = icmp_codes[match].code_max; - } else { - char *slash; - char buffer[strlen(icmptype) + 1]; - unsigned int number; - - strcpy(buffer, icmptype); - slash = strchr(buffer, '/'); - - if (slash) - *slash = '\0'; - - if (string_to_number(buffer, 0, 255, &number) == -1) - exit_error(PARAMETER_PROBLEM, - "Invalid ICMP type `%s'\n", buffer); - *type = number; - if (slash) { - if (string_to_number(slash+1, 0, 255, &number) == -1) - exit_error(PARAMETER_PROBLEM, - "Invalid ICMP code `%s'\n", - slash+1); - code[0] = code[1] = number; - } else { - code[0] = 0; - code[1] = 0xFF; - } - } - - if (code[0] == 0 && code[1] == 0xFF) - return NFC_IP_SRC_PT; - else return NFC_IP_SRC_PT | NFC_IP_DST_PT; -} - -/* Initialize the match. */ -static void -init(struct ipt_entry_match *m, unsigned int *nfcache) -{ - struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; - - icmpinfo->type = 0xFF; - icmpinfo->code[1] = 0xFF; -} - -/* Function which parses command options; returns true if it - ate an option */ -static int -parse(int c, char **argv, int invert, unsigned int *flags, - const struct ipt_entry *entry, - unsigned int *nfcache, - struct ipt_entry_match **match) -{ - struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data; - - switch (c) { - case '1': - check_inverse(optarg, &invert, &optind, 0); - *nfcache |= parse_icmp(argv[optind-1], - &icmpinfo->type, - icmpinfo->code); - if (invert) - icmpinfo->invflags |= IPT_ICMP_INV; - break; - - default: - return 0; - } - - return 1; -} - -static void print_icmptype(u_int8_t type, - u_int8_t code_min, u_int8_t code_max, - int invert, - int numeric) -{ - if (!numeric) { - unsigned int i; - - for (i = 0; - i < sizeof(icmp_codes)/sizeof(struct icmp_names); - i++) { - if (icmp_codes[i].type == type - && icmp_codes[i].code_min == code_min - && icmp_codes[i].code_max == code_max) - break; - } - - if (i != sizeof(icmp_codes)/sizeof(struct icmp_names)) { - printf("%s%s ", - invert ? "!" : "", - icmp_codes[i].name); - return; - } - } - - if (invert) - printf("!"); - - printf("type %u", type); - if (code_min == 0 && code_max == 0xFF) - printf(" "); - else if (code_min == code_max) - printf(" code %u ", code_min); - else - printf(" codes %u-%u ", code_min, code_max); -} - -/* Prints out the union ipt_matchinfo. */ -static void -print(const struct ipt_ip *ip, - const struct ipt_entry_match *match, - int numeric) -{ - const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; - - printf("icmp "); - print_icmptype(icmp->type, icmp->code[0], icmp->code[1], - icmp->invflags & IPT_ICMP_INV, - numeric); - - if (icmp->invflags & ~IPT_ICMP_INV) - printf("Unknown invflags: 0x%X ", - icmp->invflags & ~IPT_ICMP_INV); -} - -/* Saves the match in parsable form to stdout. */ -static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) -{ - const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; - - if (icmp->invflags & IPT_ICMP_INV) - printf("! "); - - /* special hack for 'any' case */ - if (icmp->type == 0xFF) { - print_icmptype(icmp->type, icmp->code[0], icmp->code[1], - icmp->invflags & IPT_ICMP_INV, 0); - } else { - printf("--icmp-type %u", icmp->type); - if (icmp->code[0] != 0 || icmp->code[1] != 0xFF) - printf("/%u", icmp->code[0]); - printf(" "); - } -} - -/* Final check; we don't care. */ -static void final_check(unsigned int flags) -{ -} - -static -struct iptables_match icmp -= { NULL, - "icmp", - IPTABLES_VERSION, - IPT_ALIGN(sizeof(struct ipt_icmp)), - IPT_ALIGN(sizeof(struct ipt_icmp)), - &help, - &init, - &parse, - &final_check, - &print, - &save, - opts -}; - -void _init(void) -{ - register_match(&icmp); -} diff --git a/ip6tables.c.selinux b/ip6tables.c.selinux deleted file mode 100644 index fc4e284..0000000 --- a/ip6tables.c.selinux +++ /dev/null @@ -1,2300 +0,0 @@ -/* Code to take an iptables-style command line and do it. */ - -/* - * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au - * - * (C) 2000-2002 by the netfilter coreteam : - * Paul 'Rusty' Russell - * Marc Boucher - * James Morris - * Harald Welte - * Jozsef Kadlecsik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef IP6T_LIB_DIR -#define IP6T_LIB_DIR "/usr/lib/iptables" -#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 -#define FMT_OPTIONS 0x0008 -#define FMT_NOTABLE 0x0010 -#define FMT_NOTARGET 0x0020 -#define FMT_VIA 0x0040 -#define FMT_NONEWLINE 0x0080 -#define FMT_LINENUMBERS 0x0100 - -#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ - | FMT_NUMERIC | FMT_NOTABLE) -#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) - - -#define CMD_NONE 0x0000U -#define CMD_INSERT 0x0001U -#define CMD_DELETE 0x0002U -#define CMD_DELETE_NUM 0x0004U -#define CMD_REPLACE 0x0008U -#define CMD_APPEND 0x0010U -#define CMD_LIST 0x0020U -#define CMD_FLUSH 0x0040U -#define CMD_ZERO 0x0080U -#define CMD_NEW_CHAIN 0x0100U -#define CMD_DELETE_CHAIN 0x0200U -#define CMD_SET_POLICY 0x0400U -#define CMD_CHECK 0x0800U -#define CMD_RENAME_CHAIN 0x1000U -#define NUMBER_OF_CMD 13 -static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', - 'N', 'X', 'P', 'E' }; - -#define OPTION_OFFSET 256 - -#define OPT_NONE 0x00000U -#define OPT_NUMERIC 0x00001U -#define OPT_SOURCE 0x00002U -#define OPT_DESTINATION 0x00004U -#define OPT_PROTOCOL 0x00008U -#define OPT_JUMP 0x00010U -#define OPT_VERBOSE 0x00020U -#define OPT_EXPANDED 0x00040U -#define OPT_VIANAMEIN 0x00080U -#define OPT_VIANAMEOUT 0x00100U -#define OPT_LINENUMBERS 0x00200U -#define OPT_COUNTERS 0x00400U -#define NUMBER_OF_OPT 11 -static const char optflags[NUMBER_OF_OPT] -= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '3', '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 } -}; - -/* we need this for ip6tables-restore. ip6tables-restore.c sets line to the - * current line of the input file, in order to give a more precise error - * message. ip6tables itself doesn't need this, so it is initialized to the - * magic number of -1 */ -int line = -1; - -#ifndef __OPTIMIZE__ -struct ip6t_entry_target * -ip6t_get_target(struct ip6t_entry *e) -{ - return (void *)e + e->target_offset; -} -#endif - -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to - * CMD_LIST and CMD_ZERO only). - * Key: - * + compulsory - * x illegal - * optional - */ - -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 */ -/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x'}, -/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x'}, -/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x'}, -/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x'}, -/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x'}, -/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' '}, -/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x'}, -/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x'}, -/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x'}, -/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x'}, -/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x'}, -/*CHECK*/ {'x','+','+','+','x',' ','x',' ',' ','x'}, -/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x'} -}; - -static int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IP6T_INV_SRCIP, -/* -d */ IP6T_INV_DSTIP, -/* -p */ IP6T_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IP6T_INV_VIA_IN, -/* -o */ IP6T_INV_VIA_OUT, -/*--line*/ 0 -}; - -const char *program_version; -const char *program_name; - -/* 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); - -/* A few hardcoded protocols for 'all' and in case the user has no - /etc/protocols */ -struct pprot { - char *name; - 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 }, - { "icmpv6", IPPROTO_ICMPV6 }, - { "esp", IPPROTO_ESP }, - { "ah", IPPROTO_AH }, - { "all", 0 }, -}; - -static char * -proto_to_name(u_int8_t proto, int nolookup) -{ - unsigned int i; - - if (proto && !nolookup) { - struct protoent *pent = getprotobynumber(proto); - if (pent) - 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; - - return NULL; -} - -static void -in6addrcpy(struct in6_addr *dst, struct in6_addr *src) -{ - memcpy(dst, src, sizeof(struct in6_addr)); - /* dst->s6_addr = src->s6_addr; */ -} - -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 iptables or your kernel needs to be upgraded.\n"); - 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 ); - exit(status); -} - -void -exit_printhelp(void) -{ - struct ip6tables_match *m = 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 -D chain rulenum [options]\n" -" %s -[LFZ] [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); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" 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" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain] 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" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" 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" -" source specification\n" -" --destination -d [!] address[/mask]\n" -" destination specification\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" -" --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" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -/*"[!] --fragment -f match second or further fragments only\n"*/ -" --modprobe= try to insert modules using this command\n" -" --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 - matches & targets */ - for (t=ip6tables_targets;t;t=t->next) { - printf("\n"); - t->help(); - } - for (m=ip6tables_matches;m;m=m->next) { - printf("\n"); - m->help(); - } - exit(0); -} - -static void -generic_opt_check(int command, int options) -{ - int i, j, legal = 0; - - /* Check that commands are valid with options. Complicated by the - * fact that if an option is legal with *any* command given, it is - * legal overall (ie. -z and -l). - */ - for (i = 0; i < NUMBER_OF_OPT; i++) { - legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ - - for (j = 0; j < NUMBER_OF_CMD; j++) { - if (!(command & (1< 1; option >>= 1, ptr++); - - return *ptr; -} - -static char -cmd2char(int option) -{ - const char *ptr; - for (ptr = cmdflags; option > 1; option >>= 1, ptr++); - - return *ptr; -} - -static void -add_command(int *cmd, const int newcmd, const int othercmds, int invert) -{ - if (invert) - exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); - if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Can't 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. - * Most routines return pointers to static data that may change - * between calls to the same or other routines with a few exceptions: - * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" - * 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); - 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 *name, enum ip6t_tryload tryload) -{ - struct ip6tables_match *ptr; - int icmphack = 0; - - /* This is ugly as hell. Nonetheless, there is no way of changing - * this without hurting backwards compatibility */ - if ( (strcmp(name,"icmpv6") == 0) || - (strcmp(name,"ipv6-icmp") == 0) || - (strcmp(name,"icmp6") == 0) ) icmphack = 1; - - if (!icmphack) { - for (ptr = ip6tables_matches; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - } else { - for (ptr = ip6tables_matches; ptr; ptr = ptr->next) { - if (strcmp("icmp6", ptr->name) == 0) - break; - } - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IP6T_LIB_DIR) + sizeof("/libip6t_.so") - + strlen(name)]; - if (!icmphack) - sprintf(path, IP6T_LIB_DIR "/libip6t_%s.so", name); - else - sprintf(path, IP6T_LIB_DIR "/libip6t_%s.so", "icmpv6"); - 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); - - 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) - ptr->used = 1; - - 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) -{ - unsigned int proto; - - if (string_to_number(pname, 0, 255, &proto) != -1) { - char *protoname = proto_to_name(proto, nolookup); - - if (protoname) - return find_match(protoname, tryload); - } else - return find_match(pname, tryload); - - 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; - - 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; -} - -static 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) - 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 (!isalnum(vianame[i]) - && vianame[i] != '_' - && vianame[i] != '.') { - printf("Warning: wierd 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, - "Invalid rule number `%s'", rule); - - return rulenum; -} - -static const char * -parse_target(const char *targetname) -{ - const char *ptr; - - if (strlen(targetname) < 1) - exit_error(PARAMETER_PROBLEM, - "Invalid target name (too short)"); - - if (strlen(targetname)+1 > sizeof(ip6t_chainlabel)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s' (%i chars max)", - targetname, sizeof(ip6t_chainlabel)-1); - - for (ptr = targetname; *ptr; ptr++) - if (isspace(*ptr)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s'", targetname); - return targetname; -} - -int -string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtol(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && number <= max) { - *ret = number; - return 0; - } - } - return -1; -} - -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", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - exit_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) { - char path[sizeof(IP6T_LIB_DIR) + sizeof("/libip6t_.so") - + strlen(name)]; - sprintf(path, IP6T_LIB_DIR "/libip6t_%s.so", 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)); - 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; -} - -void -register_match6(struct ip6tables_match *me) -{ - struct ip6tables_match **i; - - 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); - } - - if (find_match(me->name, DONT_LOAD)) { - fprintf(stderr, "%s: match `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IP6T_ALIGN(me->size)) { - fprintf(stderr, "%s: match `%s' has invalid size %u.\n", - program_name, me->name, 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, DONT_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, 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) -{ - if (format & FMT_KILOMEGAGIGA) { - if (number > 99999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - printf(FMT("%4lluT ","%lluT "), number); - } - else printf(FMT("%4lluG ","%lluG "), number); - } - else printf(FMT("%4lluM ","%lluM "), number); - } else - printf(FMT("%4lluK ","%lluK "), number); - } else - printf(FMT("%5llu ","%llu "), number); - } else - printf(FMT("%8llu ","%llu "), number); -} - - -static void -print_header(unsigned int format, const char *chain, ip6tc_handle_t *handle) -{ - struct ip6t_counters counters; - const char *pol = ip6tc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!ip6tc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - -static int -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); - - if (match) { - if (match->print) - match->print(ip, m, numeric); - else - printf("%s ", match->name); - } else { - if (m->u.user.name[0]) - printf("UNKNOWN match `%s' ", m->u.user.name); - } - /* Don't stop iterating. */ - return 0; -} - -/* e is called `fw' here for hysterical raisins */ -static void -print_firewall(const struct ip6t_entry *fw, - const char *targname, - unsigned int num, - unsigned int format, - const ip6tc_handle_t handle) -{ - struct ip6tables_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); - else - target = find_target(IP6T_STANDARD_TARGET, 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); - - if (!(format & FMT_NOCOUNTS)) { - print_num(fw->counters.pcnt, format); - print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); - - fputc(fw->ipv6.invflags & IP6T_INV_PROTO ? '!' : ' ', stdout); - { - char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ipv6.proto); - } - - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(' ', stdout); /* Invert flag of FRAG */ - fputc(' ', stdout); /* -f */ - fputc(' ', stdout); - } - - if (format & FMT_VIA) { - char iface[IFNAMSIZ+2]; - - if (fw->ipv6.invflags & IP6T_INV_VIA_IN) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ipv6.iniface[0] != '\0') { - strcat(iface, fw->ipv6.iniface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT(" %-6s ","in %s "), iface); - - if (fw->ipv6.invflags & IP6T_INV_VIA_OUT) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ipv6.outiface[0] != '\0') { - strcat(iface, fw->ipv6.outiface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT("%-6s ","out %s "), iface); - } - - fputc(fw->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout); - 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))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ipv6.src))); - strcat(buf, mask_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"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_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); - } - - if (format & FMT_NOTABLE) - fputs(" ", stdout); - - IP6T_MATCH_ITERATE(fw, print_match, &fw->ipv6, format & FMT_NUMERIC); - - if (target) { - if (target->print) - /* Print the target information. */ - target->print(&fw->ipv6, t, format & FMT_NUMERIC); - } else if (t->u.target_size != sizeof(*t)) - printf("[%u bytes of unknown target data] ", - t->u.target_size - sizeof(*t)); - - if (!(format & FMT_NONEWLINE)) - fputc('\n', stdout); -} - -static void -print_firewall_line(const struct ip6t_entry *fw, - const ip6tc_handle_t h) -{ - struct ip6t_entry_target *t; - - t = ip6t_get_target((struct ip6t_entry *)fw); - print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); -} - -static int -append_entry(const ip6t_chainlabel chain, - struct ip6t_entry *fw, - unsigned int nsaddrs, - const struct in6_addr saddrs[], - unsigned int ndaddrs, - const struct in6_addr daddrs[], - int verbose, - ip6tc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ipv6.src = saddrs[i]; - for (j = 0; j < ndaddrs; j++) { - fw->ipv6.dst = daddrs[j]; - if (verbose) - print_firewall_line(fw, *handle); - ret &= ip6tc_append_entry(chain, fw, handle); - } - } - - return ret; -} - -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, - int verbose, - ip6tc_handle_t *handle) -{ - fw->ipv6.src = *saddr; - fw->ipv6.dst = *daddr; - - if (verbose) - print_firewall_line(fw, *handle); - return ip6tc_replace_entry(chain, fw, rulenum, handle); -} - -static int -insert_entry(const ip6t_chainlabel chain, - struct ip6t_entry *fw, - unsigned int rulenum, - unsigned int nsaddrs, - const struct in6_addr saddrs[], - unsigned int ndaddrs, - const struct in6_addr daddrs[], - int verbose, - ip6tc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ipv6.src = saddrs[i]; - for (j = 0; j < ndaddrs; j++) { - fw->ipv6.dst = daddrs[j]; - if (verbose) - print_firewall_line(fw, *handle); - ret &= ip6tc_insert_entry(chain, fw, rulenum, handle); - } - } - - return ret; -} - -static unsigned char * -make_delete_mask(struct ip6t_entry *fw) -{ - /* Establish mask for comparison */ - unsigned int size; - struct ip6tables_match *m; - unsigned char *mask, *mptr; - - size = sizeof(struct ip6t_entry); - for (m = ip6tables_matches; m; m = m->next) { - if (!m->used) - continue; - - size += IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; - } - - mask = fw_calloc(1, size - + IP6T_ALIGN(sizeof(struct ip6t_entry_target)) - + ip6tables_targets->size); - - memset(mask, 0xFF, sizeof(struct ip6t_entry)); - mptr = mask + sizeof(struct ip6t_entry); - - for (m = ip6tables_matches; m; m = m->next) { - if (!m->used) - continue; - - memset(mptr, 0xFF, - IP6T_ALIGN(sizeof(struct ip6t_entry_match)) - + m->userspacesize); - mptr += IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; - } - - memset(mptr, 0xFF, - IP6T_ALIGN(sizeof(struct ip6t_entry_target)) - + ip6tables_targets->userspacesize); - - return mask; -} - -static int -delete_entry(const ip6t_chainlabel chain, - struct ip6t_entry *fw, - unsigned int nsaddrs, - const struct in6_addr saddrs[], - unsigned int ndaddrs, - const struct in6_addr daddrs[], - int verbose, - ip6tc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - unsigned char *mask; - - mask = make_delete_mask(fw); - for (i = 0; i < nsaddrs; i++) { - fw->ipv6.src = saddrs[i]; - for (j = 0; j < ndaddrs; j++) { - fw->ipv6.dst = daddrs[j]; - if (verbose) - print_firewall_line(fw, *handle); - ret &= ip6tc_delete_entry(chain, fw, mask, handle); - } - } - return ret; -} - -int -for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), - int verbose, int builtinstoo, ip6tc_handle_t *handle) -{ - int ret = 1; - const char *chain; - char *chains; - unsigned int i, chaincount = 0; - - chain = ip6tc_first_chain(handle); - while (chain) { - chaincount++; - chain = ip6tc_next_chain(handle); - } - - chains = fw_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)) - continue; - ret &= fn(chains + i*sizeof(ip6t_chainlabel), verbose, handle); - } - - free(chains); - return ret; -} - -int -flush_entries(const ip6t_chainlabel chain, int verbose, - ip6tc_handle_t *handle) -{ - if (!chain) - return for_each_chain(flush_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Flushing chain `%s'\n", chain); - return ip6tc_flush_entries(chain, handle); -} - -static int -zero_entries(const ip6t_chainlabel chain, int verbose, - ip6tc_handle_t *handle) -{ - if (!chain) - return for_each_chain(zero_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Zeroing chain `%s'\n", chain); - return ip6tc_zero_entries(chain, handle); -} - -int -delete_chain(const ip6t_chainlabel chain, int verbose, - ip6tc_handle_t *handle) -{ - if (!chain) - return for_each_chain(delete_chain, verbose, 0, handle); - - if (verbose) - 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) -{ - int found = 0; - unsigned int format; - const char *this; - - format = FMT_OPTIONS; - if (!verbose) - format |= FMT_NOCOUNTS; - else - format |= FMT_VIA; - - if (numeric) - format |= FMT_NUMERIC; - - if (!expanded) - format |= FMT_KILOMEGAGIGA; - - if (linenumbers) - format |= FMT_LINENUMBERS; - - for (this = ip6tc_first_chain(handle); - this; - this = ip6tc_next_chain(handle)) { - const struct ip6t_entry *i; - unsigned int num; - - if (chain && strcmp(chain, this) != 0) - continue; - - if (found) printf("\n"); - - 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); - i = ip6tc_next_rule(i, handle); - } - found = 1; - } - - errno = ENOENT; - return found; -} - -static char *get_modprobe(void) -{ - int procfile; - char *ret; - - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); - if (procfile < 0) - return NULL; - - ret = malloc(1024); - if (ret) { - switch (read(procfile, ret, 1024)) { - case -1: goto fail; - case 1024: goto fail; /* Partial read. Wierd */ - } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; - close(procfile); - return ret; - } - fail: - free(ret); - close(procfile); - return NULL; -} - -int ip6tables_insmod(const char *modname, const char *modprobe) -{ - char *buf = NULL; - char *argv[3]; - - /* If they don't explicitly set it, read out of kernel */ - if (!modprobe) { - buf = get_modprobe(); - if (!buf) - return -1; - modprobe = buf; - } - - switch (fork()) { - case 0: - argv[0] = (char *)modprobe; - argv[1] = (char *)modname; - argv[2] = NULL; - execv(argv[0], argv); - - /* not usually reached */ - exit(0); - case -1: - return -1; - - default: /* parent */ - wait(NULL); - } - - free(buf); - return 0; -} - -static struct ip6t_entry * -generate_entry(const struct ip6t_entry *fw, - struct ip6tables_match *matches, - struct ip6t_entry_target *target) -{ - unsigned int size; - struct ip6tables_match *m; - struct ip6t_entry *e; - - size = sizeof(struct ip6t_entry); - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - size += m->m->u.match_size; - } - - e = fw_malloc(size + target->u.target_size); - *e = *fw; - e->target_offset = size; - e->next_offset = size + target->u.target_size; - - size = 0; - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - memcpy(e->elems + size, m->m, m->m->u.match_size); - size += m->m->u.match_size; - } - memcpy(e->elems + size, target, target->u.target_size); - - return e; -} - -int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) -{ - struct ip6t_entry fw, *e = NULL; - int invert = 0; - unsigned int nsaddrs = 0, ndaddrs = 0; - struct in6_addr *saddrs = NULL, *daddrs = NULL; - - int c, verbose = 0; - const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; - const char *policy = NULL, *newname = NULL; - unsigned int rulenum = 0, options = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; - int ret = 1; - struct ip6tables_match *m; - struct ip6tables_target *target = NULL; - struct ip6tables_target *t; - const char *jumpto = ""; - char *protocol = NULL; - const char *modprobe = NULL; - int proto_used = 0; - char icmp6p[] = "icmpv6"; - - memset(&fw, 0, sizeof(fw)); - - opts = original_opts; - global_option_offset = 0; - - /* re-set optind to 0 in case do_command gets called - * a second time */ - optind = 0; - - /* 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) { - m->mflags = 0; - m->used = 0; - } - - for (t = ip6tables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - 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:", - opts, NULL)) != -1) { - switch (c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, - invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, CMD_ZERO, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'N': - if (optarg && *optarg == '-') - exit_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `-'\n"); - if (find_target(optarg, TRY_LOAD)) - exit_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - newname = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - policy = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!ip6tables_matches && protocol) - find_match(protocol, TRY_LOAD); - - exit_printhelp(); - - /* - * Option selection - */ - case 'p': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_PROTOCOL, &fw.ipv6.invflags, - invert); - - /* Canonicalize into lower case */ - for (protocol = argv[optind-1]; *protocol; protocol++) - *protocol = tolower(*protocol); - - protocol = argv[optind-1]; - if ( strcmp(protocol,"ipv6-icmp") == 0) - protocol = icmp6p; - fw.ipv6.proto = parse_protocol(protocol); - fw.ipv6.flags |= IP6T_F_PROTO; - - if (fw.ipv6.proto == 0 - && (fw.ipv6.invflags & IP6T_INV_PROTO)) - exit_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - fw.nfcache |= NFC_IP6_PROTO; - break; - - case 's': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_SOURCE, &fw.ipv6.invflags, - invert); - shostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP6_SRC; - break; - - case 'd': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_DESTINATION, &fw.ipv6.invflags, - invert); - dhostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP6_DST; - break; - - 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); - - if (target) { - size_t size; - - size = IP6T_ALIGN(sizeof(struct ip6t_entry_target)) - + target->size; - - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - opts = merge_options(opts, target->extra_opts, &target->option_offset); - } - break; - - - case 'i': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEIN, &fw.ipv6.invflags, - invert); - parse_interface(argv[optind-1], - fw.ipv6.iniface, - fw.ipv6.iniface_mask); - fw.nfcache |= NFC_IP6_IF_IN; - break; - - case 'o': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEOUT, &fw.ipv6.invflags, - invert); - parse_interface(argv[optind-1], - fw.ipv6.outiface, - fw.ipv6.outiface_mask); - fw.nfcache |= NFC_IP6_IF_OUT; - break; - - case 'v': - if (!verbose) - set_option(&options, OPT_VERBOSE, - &fw.ipv6.invflags, invert); - verbose++; - break; - - case 'm': { - size_t size; - - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --match"); - - m = find_match(optarg, LOAD_MUST_SUCCEED); - size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) - + m->size; - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - opts = merge_options(opts, m->extra_opts, &m->option_offset); - } - break; - - case 'n': - set_option(&options, OPT_NUMERIC, &fw.ipv6.invflags, - invert); - break; - - case 't': - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - *table = argv[optind-1]; - break; - - case 'x': - set_option(&options, OPT_EXPANDED, &fw.ipv6.invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", program_version); - else - printf("%s v%s\n", - program_name, program_version); - exit(0); - - case '0': - set_option(&options, OPT_LINENUMBERS, &fw.ipv6.invflags, - invert); - break; - - case 'M': - modprobe = optarg; - break; - - case 'c': - - set_option(&options, OPT_COUNTERS, &fw.ipv6.invflags, - invert); - pcnt = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - bcnt = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - - if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - - break; - - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - exit_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = TRUE; - optarg[0] = '\0'; - continue; - } - printf("Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - /* FIXME: This scheme doesn't allow two of the same - matches --RR */ - if (!target - || !(target->parse(c - target->option_offset, - argv, invert, - &target->tflags, - &fw, &target->t))) { - for (m = ip6tables_matches; m; m = m->next) { - if (!m->used) - continue; - - if (m->parse(c - m->option_offset, - argv, invert, - &m->mflags, - &fw, - &fw.nfcache, - &m->m)) - break; - } - - /* If you listen carefully, you can - actually hear this code suck. */ - - /* some explanations (after four different bugs - * in 3 different releases): If we encountere a - * parameter, that has not been parsed yet, - * it's not an option of an explicitly loaded - * match or a target. However, we support - * implicit loading of the protocol match - * extension. '-p tcp' means 'l4 proto 6' and - * at the same time 'load tcp protocol match on - * demand if we specify --dport'. - * - * To make this work, we need to make sure: - * - the parameter has not been parsed by - * a match (m above) - * - a protocol has been specified - * - the protocol extension has not been - * loaded yet, or is loaded and unused - * [think of iptables-restore!] - * - the protocol extension can be successively - * loaded - */ - if (m == NULL - && protocol - && (!find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - || (find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - && (proto_used == 0)) - ) - && (m = find_proto(protocol, TRY_LOAD, - options&OPT_NUMERIC))) { - /* 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->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - - opts = merge_options(opts, - m->extra_opts, &m->option_offset); - - optind--; - continue; - } - - if (!m) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind-1]); - } - } - invert = FALSE; - } - - for (m = ip6tables_matches; m; m = m->next) { - if (!m->used) - continue; - - m->final_check(m->mflags); - } - - if (target) - target->final_check(target->tflags); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - exit_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - exit_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - exit_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) - dhostnetworkmask = "::0/0"; - if (!(options & OPT_SOURCE)) - shostnetworkmask = "::0/0"; - } - - if (shostnetworkmask) - parse_hostnetworkmask(shostnetworkmask, &saddrs, - &(fw.ipv6.smsk), &nsaddrs); - - if (dhostnetworkmask) - parse_hostnetworkmask(dhostnetworkmask, &daddrs, - &(fw.ipv6.dmsk), &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) - exit_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 " - "specify a unique address"); - - generic_opt_check(command, options); - - if (chain && strlen(chain) > IP6T_FUNCTION_MAXNAMELEN) - exit_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %i chars)", - chain, IP6T_FUNCTION_MAXNAMELEN); - - /* only allocate handle if we weren't called with a handle */ - if (!*handle) - *handle = ip6tc_init(*table); - - if (!*handle) { - /* try to insmod the module if iptc_init failed */ - ip6tables_insmod("ip6_tables", modprobe); - *handle = ip6tc_init(*table); - } - - if (!*handle) - exit_error(VERSION_PROBLEM, - "can't initialize ip6tables table `%s': %s", - *table, ip6tc_strerror(errno)); - - if (command == CMD_APPEND - || command == CMD_DELETE - || command == CMD_INSERT - || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) - exit_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); - - target = NULL; - } - - /* If they didn't specify a target, or it's a chain - name, use standard. */ - if (!target - && (strlen(jumpto) == 0 - || ip6tc_is_chain(jumpto, *handle))) { - size_t size; - - target = find_target(IP6T_STANDARD_TARGET, - LOAD_MUST_SUCCEED); - - size = sizeof(struct ip6t_entry_target) - + target->size; - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - } - - if (!target) { - /* it is no chain, and we can't load a plugin. - * We cannot know if the plugin is corrupt, non - * existant OR if the user just misspelled a - * chain. */ - find_target(jumpto, LOAD_MUST_SUCCEED); - } else { - e = generate_entry(&fw, ip6tables_matches, target->t); - } - } - - switch (command) { - case CMD_APPEND: - ret = append_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE: - ret = delete_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE_NUM: - 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); - break; - case CMD_INSERT: - ret = insert_entry(chain, e, rulenum - 1, - nsaddrs, saddrs, ndaddrs, daddrs, - 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); - break; - case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_LIST|CMD_ZERO: - ret = list_entries(chain, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, - handle); - if (ret) - ret = zero_entries(chain, - options&OPT_VERBOSE, handle); - break; - case CMD_NEW_CHAIN: - ret = ip6tc_create_chain(chain, handle); - break; - case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, handle); - break; - case CMD_RENAME_CHAIN: - ret = ip6tc_rename_chain(chain, newname, handle); - break; - case CMD_SET_POLICY: - ret = ip6tc_set_policy(chain, policy, NULL, handle); - break; - default: - /* We should never reach this... */ - exit_tryhelp(2); - } - - if (verbose > 1) - dump_entries6(*handle); - - return ret; -} diff --git a/iptables-restore.c.counters b/iptables-restore.c.counters deleted file mode 100644 index b40630c..0000000 --- a/iptables-restore.c.counters +++ /dev/null @@ -1,384 +0,0 @@ -/* Code to restore the iptables state, from file by iptables-save. - * (C) 2000-2002 by Harald Welte - * based on previous code from Rusty Russell - * - * This code is distributed under the terms of GNU GPL v2 - * - * $Id: iptables-restore.c,v 1.26 2003/05/02 15:30:11 laforge Exp $ - */ - -#include -#include -#include -#include -#include -#include "iptables.h" -#include "libiptc/libiptc.h" - -#ifdef DEBUG -#define DEBUGP(x, args...) fprintf(stderr, x, ## args) -#else -#define DEBUGP(x, args...) -#endif - -static int binary = 0, counters = 0, verbose = 0, noflush = 0; - -/* Keeping track of external matches and targets. */ -static struct option options[] = { - { "binary", 0, 0, 'b' }, - { "counters", 0, 0, 'c' }, - { "verbose", 1, 0, 'v' }, - { "help", 0, 0, 'h' }, - { "noflush", 0, 0, 'n'}, - { "modprobe", 1, 0, 'M'}, - { 0 } -}; - -static void print_usage(const char *name, const char *version) __attribute__((noreturn)); - -static void print_usage(const char *name, const char *version) -{ - fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-h]\n" - " [ --binary ]\n" - " [ --counters ]\n" - " [ --verbose ]\n" - " [ --help ]\n" - " [ --noflush ]\n" - " [ --modprobe=]\n", name); - - exit(1); -} - -iptc_handle_t create_handle(const char *tablename, const char* modprobe ) -{ - iptc_handle_t handle; - - handle = iptc_init(tablename); - - if (!handle) { - /* try to insmod the module if iptc_init failed */ - iptables_insmod("ip_tables", modprobe); - handle = iptc_init(tablename); - } - - if (!handle) { - exit_error(PARAMETER_PROBLEM, "%s: unable to initialize" - "table '%s'\n", program_name, tablename); - exit(1); - } - return handle; -} - -int parse_counters(char *string, struct ipt_counters *ctr) -{ - return (sscanf(string, "[%llu:%llu]", &ctr->pcnt, &ctr->bcnt) == 2); -} - -/* global new argv and argc */ -static char *newargv[255]; -static int newargc; - -/* function adding one argument to newargv, updating newargc - * returns true if argument added, false otherwise */ -static int add_argv(char *what) { - DEBUGP("add_argv: %s\n", what); - if (what && ((newargc + 1) < sizeof(newargv)/sizeof(char *))) { - newargv[newargc] = strdup(what); - newargc++; - return 1; - } else - return 0; -} - -static void free_argv(void) { - int i; - - for (i = 0; i < newargc; i++) - free(newargv[i]); -} - -int main(int argc, char *argv[]) -{ - iptc_handle_t handle = NULL; - char buffer[10240]; - int c; - char curtable[IPT_TABLE_MAXNAMELEN + 1]; - FILE *in; - const char *modprobe = 0; - int in_table = 0; - - program_name = "iptables-restore"; - program_version = IPTABLES_VERSION; - line = 0; - -#ifdef NO_SHARED_LIBS - init_extensions(); -#endif - - while ((c = getopt_long(argc, argv, "bcvhnM:", options, NULL)) != -1) { - switch (c) { - case 'b': - binary = 1; - break; - case 'c': - counters = 1; - break; - case 'v': - verbose = 1; - break; - case 'h': - print_usage("iptables-restore", - IPTABLES_VERSION); - break; - case 'n': - noflush = 1; - break; - case 'M': - modprobe = optarg; - break; - } - } - - if (optind == argc - 1) { - in = fopen(argv[optind], "r"); - if (!in) { - fprintf(stderr, "Can't open %s: %s", argv[optind], - strerror(errno)); - exit(1); - } - } - else if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline"); - exit(1); - } - else in = stdin; - - /* Grab standard input. */ - while (fgets(buffer, sizeof(buffer), in)) { - int ret = 0; - - line++; - if (buffer[0] == '\n') continue; - else if (buffer[0] == '#') { - if (verbose) fputs(buffer, stdout); - continue; - } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { - DEBUGP("Calling commit\n"); - ret = iptc_commit(&handle); - in_table = 0; - } else if ((buffer[0] == '*') && (!in_table)) { - /* New table */ - char *table; - - table = strtok(buffer+1, " \t\n"); - DEBUGP("line %u, table '%s'\n", line, table); - if (!table) { - exit_error(PARAMETER_PROBLEM, - "%s: line %u table name invalid\n", - program_name, line); - exit(1); - } - strncpy(curtable, table, IPT_TABLE_MAXNAMELEN); - - if (handle) - iptc_free(&handle); - - handle = create_handle(table, modprobe); - if (noflush == 0) { - DEBUGP("Cleaning all chains of table '%s'\n", - table); - for_each_chain(flush_entries, verbose, 1, - &handle); - - DEBUGP("Deleting all user-defined chains " - "of table '%s'\n", table); - for_each_chain(delete_chain, verbose, 0, - &handle) ; - } - - ret = 1; - in_table = 1; - - } else if ((buffer[0] == ':') && (in_table)) { - /* New chain. */ - char *policy, *chain; - - chain = strtok(buffer+1, " \t\n"); - DEBUGP("line %u, chain '%s'\n", line, chain); - if (!chain) { - exit_error(PARAMETER_PROBLEM, - "%s: line %u chain name invalid\n", - program_name, line); - exit(1); - } - - if (!iptc_builtin(chain, handle)) { - DEBUGP("Creating new chain '%s'\n", chain); - if (!iptc_create_chain(chain, &handle)) - exit_error(PARAMETER_PROBLEM, - "error creating chain " - "'%s':%s\n", chain, - strerror(errno)); - } - - policy = strtok(NULL, " \t\n"); - DEBUGP("line %u, policy '%s'\n", line, policy); - if (!policy) { - exit_error(PARAMETER_PROBLEM, - "%s: line %u policy invalid\n", - program_name, line); - exit(1); - } - - if (strcmp(policy, "-") != 0) { - struct ipt_counters count; - - if (counters) { - char *ctrs; - ctrs = strtok(NULL, " \t\n"); - - parse_counters(ctrs, &count); - - } else { - memset(&count, 0, - sizeof(struct ipt_counters)); - } - - DEBUGP("Setting policy of chain %s to %s\n", - chain, policy); - - if (!iptc_set_policy(chain, policy, &count, - &handle)) - exit_error(OTHER_PROBLEM, - "Can't set policy `%s'" - " on `%s' line %u: %s\n", - chain, policy, line, - iptc_strerror(errno)); - } - - ret = 1; - - } else if (in_table) { - int a; - char *ptr = buffer; - char *pcnt = NULL; - char *bcnt = NULL; - char *parsestart; - - /* the parser */ - char *param_start, *curchar; - int quote_open; - - /* reset the newargv */ - newargc = 0; - - if (buffer[0] == '[') { - /* we have counters in our input */ - ptr = strchr(buffer, ']'); - if (!ptr) - exit_error(PARAMETER_PROBLEM, - "Bad line %u: need ]\n", - line); - - pcnt = strtok(buffer+1, ":"); - if (!pcnt) - exit_error(PARAMETER_PROBLEM, - "Bad line %u: need :\n", - line); - - bcnt = strtok(NULL, "]"); - if (!bcnt) - exit_error(PARAMETER_PROBLEM, - "Bad line %u: need ]\n", - line); - - /* start command parsing after counter */ - parsestart = ptr + 1; - } else { - /* start command parsing at start of line */ - parsestart = buffer; - } - - add_argv(argv[0]); - add_argv("-t"); - add_argv((char *) &curtable); - - if (counters && pcnt && bcnt) { - add_argv("--set-counters"); - add_argv((char *) pcnt); - add_argv((char *) bcnt); - } - - /* After fighting with strtok enough, here's now - * a 'real' parser. According to Rusty I'm now no - * longer a real hacker, but I can live with that */ - - quote_open = 0; - param_start = parsestart; - - for (curchar = parsestart; *curchar; curchar++) { - if (*curchar == '"') { - if (quote_open) { - quote_open = 0; - *curchar = ' '; - } else { - quote_open = 1; - param_start++; - } - } - if (*curchar == ' ' - || *curchar == '\t' - || * curchar == '\n') { - char param_buffer[1024]; - int param_len = curchar-param_start; - - if (quote_open) - continue; - - if (!param_len) { - /* two spaces? */ - param_start++; - continue; - } - - /* end of one parameter */ - strncpy(param_buffer, param_start, - param_len); - *(param_buffer+param_len) = '\0'; - - /* check if table name specified */ - if (!strncmp(param_buffer, "-t", 3) - || !strncmp(param_buffer, "--table", 8)) { - exit_error(PARAMETER_PROBLEM, - "Line %u seems to have a " - "-t table option.\n", line); - exit(1); - } - - add_argv(param_buffer); - param_start += param_len + 1; - } else { - /* regular character, skip */ - } - } - - DEBUGP("calling do_command(%u, argv, &%s, handle):\n", - newargc, curtable); - - for (a = 0; a < newargc; a++) - DEBUGP("argv[%u]: %s\n", a, newargv[a]); - - ret = do_command(newargc, newargv, - &newargv[2], &handle); - - free_argv(); - } - if (!ret) { - fprintf(stderr, "%s: line %u failed\n", - program_name, line); - exit(1); - } - } - - return 0; -} diff --git a/iptables.c.selinux b/iptables.c.selinux deleted file mode 100644 index 187fd86..0000000 --- a/iptables.c.selinux +++ /dev/null @@ -1,2298 +0,0 @@ -/* Code to take an iptables-style command line and do it. */ - -/* - * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au - * - * (C) 2000-2002 by the netfilter coreteam : - * Paul 'Rusty' Russell - * Marc Boucher - * James Morris - * Harald Welte - * Jozsef Kadlecsik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef IPT_LIB_DIR -#define IPT_LIB_DIR "/usr/lib/iptables" -#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 -#define FMT_OPTIONS 0x0008 -#define FMT_NOTABLE 0x0010 -#define FMT_NOTARGET 0x0020 -#define FMT_VIA 0x0040 -#define FMT_NONEWLINE 0x0080 -#define FMT_LINENUMBERS 0x0100 - -#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ - | FMT_NUMERIC | FMT_NOTABLE) -#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) - - -#define CMD_NONE 0x0000U -#define CMD_INSERT 0x0001U -#define CMD_DELETE 0x0002U -#define CMD_DELETE_NUM 0x0004U -#define CMD_REPLACE 0x0008U -#define CMD_APPEND 0x0010U -#define CMD_LIST 0x0020U -#define CMD_FLUSH 0x0040U -#define CMD_ZERO 0x0080U -#define CMD_NEW_CHAIN 0x0100U -#define CMD_DELETE_CHAIN 0x0200U -#define CMD_SET_POLICY 0x0400U -#define CMD_CHECK 0x0800U -#define CMD_RENAME_CHAIN 0x1000U -#define NUMBER_OF_CMD 13 -static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', - 'N', 'X', 'P', 'E' }; - -#define OPTION_OFFSET 256 - -#define OPT_NONE 0x00000U -#define OPT_NUMERIC 0x00001U -#define OPT_SOURCE 0x00002U -#define OPT_DESTINATION 0x00004U -#define OPT_PROTOCOL 0x00008U -#define OPT_JUMP 0x00010U -#define OPT_VERBOSE 0x00020U -#define OPT_EXPANDED 0x00040U -#define OPT_VIANAMEIN 0x00080U -#define OPT_VIANAMEOUT 0x00100U -#define OPT_FRAGMENT 0x00200U -#define OPT_LINENUMBERS 0x00400U -#define OPT_COUNTERS 0x00800U -#define NUMBER_OF_OPT 12 -static const char optflags[NUMBER_OF_OPT] -= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '3', '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' }, - { "fragments", 0, 0, 'f' }, - { "version", 0, 0, 'V' }, - { "help", 2, 0, 'h' }, - { "line-numbers", 0, 0, '0' }, - { "modprobe", 1, 0, 'M' }, - { "set-counters", 1, 0, 'c' }, - { 0 } -}; - -/* we need this for iptables-restore. iptables-restore.c sets line to the - * current line of the input file, in order to give a more precise error - * message. iptables itself doesn't need this, so it is initialized to the - * magic number of -1 */ -int line = -1; - -#ifndef __OPTIMIZE__ -struct ipt_entry_target * -ipt_get_target(struct ipt_entry *e) -{ - return (void *)e + e->target_offset; -} -#endif - -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to - * CMD_LIST and CMD_ZERO only). - * Key: - * + compulsory - * x illegal - * optional - */ - -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 -f --line */ -/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, -/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, -/*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'}, -/*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'}, -/*CHECK*/ {'x','+','+','+','x',' ','x',' ',' ',' ','x'}, -/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'} -}; - -static int inverse_for_options[NUMBER_OF_OPT] = -{ -/* -n */ 0, -/* -s */ IPT_INV_SRCIP, -/* -d */ IPT_INV_DSTIP, -/* -p */ IPT_INV_PROTO, -/* -j */ 0, -/* -v */ 0, -/* -x */ 0, -/* -i */ IPT_INV_VIA_IN, -/* -o */ IPT_INV_VIA_OUT, -/* -f */ IPT_INV_FRAG, -/*--line*/ 0 -}; - -const char *program_version; -const char *program_name; - -/* Keeping track of external matches and targets: linked lists. */ -struct iptables_match *iptables_matches = NULL; -struct iptables_target *iptables_targets = NULL; - -/* Extra debugging from libiptc */ -extern void dump_entries(const iptc_handle_t handle); - -/* A few hardcoded protocols for 'all' and in case the user has no - /etc/protocols */ -struct pprot { - char *name; - 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 }, - { "icmp", IPPROTO_ICMP }, - { "esp", IPPROTO_ESP }, - { "ah", IPPROTO_AH }, - { "all", 0 }, -}; - -static char * -proto_to_name(u_int8_t proto, int nolookup) -{ - unsigned int i; - - if (proto && !nolookup) { - struct protoent *pent = getprotobynumber(proto); - if (pent) - 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; - - return NULL; -} - -struct in_addr * -dotted_to_addr(const char *dotted) -{ - static struct in_addr addr; - unsigned char *addrp; - char *p, *q; - unsigned int onebyte; - int i; - char buf[20]; - - /* copy dotted string, because we need to modify it */ - strncpy(buf, dotted, sizeof(buf) - 1); - addrp = (unsigned char *) &(addr.s_addr); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return (struct in_addr *) NULL; - - *q = '\0'; - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[i] = (unsigned char) onebyte; - p = q + 1; - } - - /* we've checked 3 bytes, now we check the last one */ - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[3] = (unsigned char) onebyte; - - return &addr; -} - -static struct in_addr * -network_to_addr(const char *name) -{ - struct netent *net; - static struct in_addr addr; - - if ((net = getnetbyname(name)) != NULL) { - if (net->n_addrtype != AF_INET) - return (struct in_addr *) NULL; - addr.s_addr = htonl((unsigned long) net->n_net); - return &addr; - } - - return (struct in_addr *) NULL; -} - -static void -inaddrcpy(struct in_addr *dst, struct in_addr *src) -{ - /* memcpy(dst, src, sizeof(struct in_addr)); */ - dst->s_addr = src->s_addr; -} - -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 iptables or your kernel needs to be upgraded.\n"); - 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 ); - exit(status); -} - -void -exit_printhelp(void) -{ - struct iptables_match *m = NULL; - struct iptables_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 -D chain rulenum [options]\n" -" %s -[LFZ] [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); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" 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" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain] 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" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" 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" -" source specification\n" -" --destination -d [!] address[/mask]\n" -" destination specification\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" -" --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" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -"[!] --fragment -f match second or further fragments only\n" -" --modprobe= try to insert modules using this command\n" -" --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 matches & targets */ - for (t=iptables_targets;t;t=t->next) { - printf("\n"); - t->help(); - } - for (m=iptables_matches;m;m=m->next) { - printf("\n"); - m->help(); - } - exit(0); -} - -static void -generic_opt_check(int command, int options) -{ - int i, j, legal = 0; - - /* Check that commands are valid with options. Complicated by the - * fact that if an option is legal with *any* command given, it is - * legal overall (ie. -z and -l). - */ - for (i = 0; i < NUMBER_OF_OPT; i++) { - legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ - - for (j = 0; j < NUMBER_OF_CMD; j++) { - if (!(command & (1< 1; option >>= 1, ptr++); - - return *ptr; -} - -static char -cmd2char(int option) -{ - const char *ptr; - for (ptr = cmdflags; option > 1; option >>= 1, ptr++); - - return *ptr; -} - -static void -add_command(int *cmd, const int newcmd, const int othercmds, int invert) -{ - if (invert) - exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); - if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Can't 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("iptables: calloc failed"); - exit(1); - } - return p; -} - -static void * -fw_malloc(size_t size) -{ - void *p; - - if ((p = malloc(size)) == NULL) { - perror("iptables: malloc failed"); - exit(1); - } - return p; -} - -static struct in_addr * -host_to_addr(const char *name, unsigned int *naddr) -{ - struct hostent *host; - struct in_addr *addr; - unsigned int i; - - *naddr = 0; - if ((host = gethostbyname(name)) != NULL) { - if (host->h_addrtype != AF_INET || - host->h_length != sizeof(struct in_addr)) - return (struct in_addr *) NULL; - - while (host->h_addr_list[*naddr] != (char *) NULL) - (*naddr)++; - addr = fw_calloc(*naddr, sizeof(struct in_addr)); - for (i = 0; i < *naddr; i++) - inaddrcpy(&(addr[i]), - (struct in_addr *) host->h_addr_list[i]); - return addr; - } - - return (struct in_addr *) NULL; -} - -static char * -addr_to_host(const struct in_addr *addr) -{ - struct hostent *host; - - if ((host = gethostbyaddr((char *) addr, - sizeof(struct in_addr), AF_INET)) != NULL) - return (char *) host->h_name; - - return (char *) NULL; -} - -/* - * All functions starting with "parse" should succeed, otherwise - * the program fails. - * Most routines return pointers to static data that may change - * between calls to the same or other routines with a few exceptions: - * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" - * return global static data. -*/ - -static struct in_addr * -parse_hostnetwork(const char *name, unsigned int *naddrs) -{ - struct in_addr *addrp, *addrptmp; - - if ((addrptmp = dotted_to_addr(name)) != NULL || - (addrptmp = network_to_addr(name)) != NULL) { - addrp = fw_malloc(sizeof(struct in_addr)); - inaddrcpy(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 in_addr * -parse_mask(char *mask) -{ - static struct in_addr maskaddr; - struct in_addr *addrp; - unsigned int bits; - - if (mask == NULL) { - /* no mask at all defaults to 32 bits */ - maskaddr.s_addr = 0xFFFFFFFF; - return &maskaddr; - } - if ((addrp = dotted_to_addr(mask)) != NULL) - /* dotted_to_addr already returns a network byte order addr */ - return addrp; - if (string_to_number(mask, 0, 32, &bits) == -1) - exit_error(PARAMETER_PROBLEM, - "invalid mask `%s' specified", mask); - if (bits != 0) { - maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); - return &maskaddr; - } - - maskaddr.s_addr = 0L; - return &maskaddr; -} - -void -parse_hostnetworkmask(const char *name, struct in_addr **addrpp, - struct in_addr *maskp, unsigned int *naddrs) -{ - struct in_addr *addrp; - char buf[256]; - char *p; - int i, j, k, n; - - strncpy(buf, name, sizeof(buf) - 1); - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - addrp = parse_mask(p + 1); - } else - addrp = parse_mask(NULL); - inaddrcpy(maskp, addrp); - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (maskp->s_addr == 0L) - strcpy(buf, "0.0.0.0"); - - addrp = *addrpp = parse_hostnetwork(buf, naddrs); - n = *naddrs; - for (i = 0, j = 0; i < n; i++) { - addrp[j++].s_addr &= maskp->s_addr; - for (k = 0; k < j - 1; k++) { - if (addrp[k].s_addr == addrp[j - 1].s_addr) { - (*naddrs)--; - j--; - break; - } - } - } -} - -struct iptables_match * -find_match(const char *name, enum ipt_tryload tryload) -{ - struct iptables_match *ptr; - - for (ptr = iptables_matches; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", 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); - - 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) - ptr->used = 1; - - return ptr; -} - -/* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static struct iptables_match * -find_proto(const char *pname, enum ipt_tryload tryload, int nolookup) -{ - unsigned int proto; - - if (string_to_number(pname, 0, 255, &proto) != -1) { - char *protoname = proto_to_name(proto, nolookup); - - if (protoname) - return find_match(protoname, tryload); - } else - return find_match(pname, tryload); - - 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; - - 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; -} - -static 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) - 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 (!isalnum(vianame[i]) - && vianame[i] != '_' - && vianame[i] != '.') { - printf("Warning: wierd 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, - "Invalid rule number `%s'", rule); - - return rulenum; -} - -static const char * -parse_target(const char *targetname) -{ - const char *ptr; - - if (strlen(targetname) < 1) - exit_error(PARAMETER_PROBLEM, - "Invalid target name (too short)"); - - if (strlen(targetname)+1 > sizeof(ipt_chainlabel)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s' (%i chars max)", - targetname, sizeof(ipt_chainlabel)-1); - - for (ptr = targetname; *ptr; ptr++) - if (isspace(*ptr)) - exit_error(PARAMETER_PROBLEM, - "Invalid target name `%s'", targetname); - return targetname; -} - -static char * -addr_to_network(const struct in_addr *addr) -{ - struct netent *net; - - if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL) - return (char *) net->n_name; - - return (char *) NULL; -} - -char * -addr_to_dotted(const struct in_addr *addrp) -{ - static char buf[20]; - const unsigned char *bytep; - - bytep = (const unsigned char *) &(addrp->s_addr); - sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); - return buf; -} - -char * -addr_to_anyname(const struct in_addr *addr) -{ - char *name; - - if ((name = addr_to_host(addr)) != NULL || - (name = addr_to_network(addr)) != NULL) - return name; - - return addr_to_dotted(addr); -} - -char * -mask_to_dotted(const struct in_addr *mask) -{ - int i; - static char buf[20]; - u_int32_t maskaddr, bits; - - maskaddr = ntohl(mask->s_addr); - - if (maskaddr == 0xFFFFFFFFL) - /* we don't want to see "/32" */ - return ""; - - i = 32; - bits = 0xFFFFFFFEL; - while (--i >= 0 && maskaddr != bits) - bits <<= 1; - if (i >= 0) - sprintf(buf, "/%d", i); - else - /* mask was not a decent combination of 1's and 0's */ - sprintf(buf, "/%s", addr_to_dotted(mask)); - - return buf; -} - -int -string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtol(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && number <= max) { - *ret = number; - return 0; - } - } - return -1; -} - -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", - opt2char(option)); - *options |= option; - - if (invert) { - unsigned int i; - for (i = 0; 1 << i != option; i++); - - if (!inverse_for_options[i]) - exit_error(PARAMETER_PROBLEM, - "cannot have ! before -%c", - opt2char(option)); - *invflg |= inverse_for_options[i]; - } -} - -struct iptables_target * -find_target(const char *name, enum ipt_tryload tryload) -{ - struct iptables_target *ptr; - - /* Standard target? */ - if (strcmp(name, "") == 0 - || strcmp(name, IPTC_LABEL_ACCEPT) == 0 - || strcmp(name, IPTC_LABEL_DROP) == 0 - || strcmp(name, IPTC_LABEL_QUEUE) == 0 - || strcmp(name, IPTC_LABEL_RETURN) == 0) - name = "standard"; - - for (ptr = iptables_targets; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) - break; - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD) { - char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, IPT_LIB_DIR "/libipt_%s.so", 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)); - 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; -} - -void -register_match(struct iptables_match *me) -{ - struct iptables_match **i; - - 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); - } - - if (find_match(me->name, DONT_LOAD)) { - fprintf(stderr, "%s: match `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: match `%s' has invalid size %u.\n", - program_name, me->name, me->size); - exit(1); - } - - /* Append to list. */ - for (i = &iptables_matches; *i; i = &(*i)->next); - me->next = NULL; - *i = me; - - me->m = NULL; - me->mflags = 0; -} - -void -register_target(struct iptables_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, DONT_LOAD)) { - fprintf(stderr, "%s: target `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: target `%s' has invalid size %u.\n", - program_name, me->name, me->size); - exit(1); - } - - /* Prepend to list. */ - me->next = iptables_targets; - iptables_targets = me; - me->t = NULL; - me->tflags = 0; -} - -static void -print_num(u_int64_t number, unsigned int format) -{ - if (format & FMT_KILOMEGAGIGA) { - if (number > 99999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - if (number > 9999) { - number = (number + 500) / 1000; - printf(FMT("%4lluT ","%lluT "), number); - } - else printf(FMT("%4lluG ","%lluG "), number); - } - else printf(FMT("%4lluM ","%lluM "), number); - } else - printf(FMT("%4lluK ","%lluK "), number); - } else - printf(FMT("%5llu ","%llu "), number); - } else - printf(FMT("%8llu ","%llu "), number); -} - - -static void -print_header(unsigned int format, const char *chain, iptc_handle_t *handle) -{ - struct ipt_counters counters; - const char *pol = iptc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!iptc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - -static int -print_match(const struct ipt_entry_match *m, - const struct ipt_ip *ip, - int numeric) -{ - struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD); - - if (match) { - if (match->print) - match->print(ip, m, numeric); - else - printf("%s ", match->name); - } else { - if (m->u.user.name[0]) - printf("UNKNOWN match `%s' ", m->u.user.name); - } - /* Don't stop iterating. */ - return 0; -} - -/* e is called `fw' here for hysterical raisins */ -static void -print_firewall(const struct ipt_entry *fw, - const char *targname, - unsigned int num, - unsigned int format, - const iptc_handle_t handle) -{ - struct iptables_target *target = NULL; - const struct ipt_entry_target *t; - u_int8_t flags; - char buf[BUFSIZ]; - - if (!iptc_is_chain(targname, handle)) - target = find_target(targname, TRY_LOAD); - else - target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED); - - t = ipt_get_target((struct ipt_entry *)fw); - flags = fw->ip.flags; - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num+1); - - if (!(format & FMT_NOCOUNTS)) { - print_num(fw->counters.pcnt, format); - print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); - - fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout); - { - char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ip.proto); - } - - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); - fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); - fputc(' ', stdout); - } - - if (format & FMT_VIA) { - char iface[IFNAMSIZ+2]; - - if (fw->ip.invflags & IPT_INV_VIA_IN) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ip.iniface[0] != '\0') { - strcat(iface, fw->ip.iniface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT(" %-6s ","in %s "), iface); - - if (fw->ip.invflags & IPT_INV_VIA_OUT) { - iface[0] = '!'; - iface[1] = '\0'; - } - else iface[0] = '\0'; - - if (fw->ip.outiface[0] != '\0') { - strcat(iface, fw->ip.outiface); - } - else if (format & FMT_NUMERIC) strcat(iface, "*"); - else strcat(iface, "any"); - printf(FMT("%-6s ","out %s "), iface); - } - - fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout); - if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC)) - printf(FMT("%-19s ","%s "), "anywhere"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src))); - strcat(buf, mask_to_dotted(&(fw->ip.smsk))); - printf(FMT("%-19s ","%s "), buf); - } - - fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout); - if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC)) - printf(FMT("%-19s ","-> %s"), "anywhere"); - else { - if (format & FMT_NUMERIC) - sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst))); - else - sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst))); - strcat(buf, mask_to_dotted(&(fw->ip.dmsk))); - printf(FMT("%-19s ","-> %s"), buf); - } - - if (format & FMT_NOTABLE) - fputs(" ", stdout); - - IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); - - if (target) { - if (target->print) - /* Print the target information. */ - target->print(&fw->ip, t, format & FMT_NUMERIC); - } else if (t->u.target_size != sizeof(*t)) - printf("[%u bytes of unknown target data] ", - t->u.target_size - sizeof(*t)); - - if (!(format & FMT_NONEWLINE)) - fputc('\n', stdout); -} - -static void -print_firewall_line(const struct ipt_entry *fw, - const iptc_handle_t h) -{ - struct ipt_entry_target *t; - - t = ipt_get_target((struct ipt_entry *)fw); - print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); -} - -static int -append_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_append_entry(chain, fw, handle); - } - } - - return ret; -} - -static int -replace_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int rulenum, - const struct in_addr *saddr, - const struct in_addr *daddr, - int verbose, - iptc_handle_t *handle) -{ - fw->ip.src.s_addr = saddr->s_addr; - fw->ip.dst.s_addr = daddr->s_addr; - - if (verbose) - print_firewall_line(fw, *handle); - return iptc_replace_entry(chain, fw, rulenum, handle); -} - -static int -insert_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int rulenum, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_insert_entry(chain, fw, rulenum, handle); - } - } - - return ret; -} - -static unsigned char * -make_delete_mask(struct ipt_entry *fw) -{ - /* Establish mask for comparison */ - unsigned int size; - struct iptables_match *m; - unsigned char *mask, *mptr; - - size = sizeof(struct ipt_entry); - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; - } - - mask = fw_calloc(1, size - + IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->size); - - memset(mask, 0xFF, sizeof(struct ipt_entry)); - mptr = mask + sizeof(struct ipt_entry); - - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - memset(mptr, 0xFF, - IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->userspacesize); - mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; - } - - memset(mptr, 0xFF, - IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->userspacesize); - - return mask; -} - -static int -delete_entry(const ipt_chainlabel chain, - struct ipt_entry *fw, - unsigned int nsaddrs, - const struct in_addr saddrs[], - unsigned int ndaddrs, - const struct in_addr daddrs[], - int verbose, - iptc_handle_t *handle) -{ - unsigned int i, j; - int ret = 1; - unsigned char *mask; - - mask = make_delete_mask(fw); - for (i = 0; i < nsaddrs; i++) { - fw->ip.src.s_addr = saddrs[i].s_addr; - for (j = 0; j < ndaddrs; j++) { - fw->ip.dst.s_addr = daddrs[j].s_addr; - if (verbose) - print_firewall_line(fw, *handle); - ret &= iptc_delete_entry(chain, fw, mask, handle); - } - } - return ret; -} - -int -for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *), - int verbose, int builtinstoo, iptc_handle_t *handle) -{ - int ret = 1; - const char *chain; - char *chains; - unsigned int i, chaincount = 0; - - chain = iptc_first_chain(handle); - while (chain) { - chaincount++; - chain = iptc_next_chain(handle); - } - - chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount); - i = 0; - chain = iptc_first_chain(handle); - while (chain) { - strcpy(chains + i*sizeof(ipt_chainlabel), chain); - i++; - chain = iptc_next_chain(handle); - } - - for (i = 0; i < chaincount; i++) { - if (!builtinstoo - && iptc_builtin(chains + i*sizeof(ipt_chainlabel), - *handle)) - continue; - ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle); - } - - free(chains); - return ret; -} - -int -flush_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(flush_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Flushing chain `%s'\n", chain); - return iptc_flush_entries(chain, handle); -} - -static int -zero_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(zero_entries, verbose, 1, handle); - - if (verbose) - fprintf(stdout, "Zeroing chain `%s'\n", chain); - return iptc_zero_entries(chain, handle); -} - -int -delete_chain(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle) -{ - if (!chain) - return for_each_chain(delete_chain, verbose, 0, handle); - - if (verbose) - fprintf(stdout, "Deleting chain `%s'\n", chain); - return iptc_delete_chain(chain, handle); -} - -static int -list_entries(const ipt_chainlabel chain, int verbose, int numeric, - int expanded, int linenumbers, iptc_handle_t *handle) -{ - int found = 0; - unsigned int format; - const char *this; - - format = FMT_OPTIONS; - if (!verbose) - format |= FMT_NOCOUNTS; - else - format |= FMT_VIA; - - if (numeric) - format |= FMT_NUMERIC; - - if (!expanded) - format |= FMT_KILOMEGAGIGA; - - if (linenumbers) - format |= FMT_LINENUMBERS; - - for (this = iptc_first_chain(handle); - this; - this = iptc_next_chain(handle)) { - const struct ipt_entry *i; - unsigned int num; - - if (chain && strcmp(chain, this) != 0) - continue; - - if (found) printf("\n"); - - print_header(format, this, handle); - i = iptc_first_rule(this, handle); - - num = 0; - while (i) { - print_firewall(i, - iptc_get_target(i, handle), - num++, - format, - *handle); - i = iptc_next_rule(i, handle); - } - found = 1; - } - - errno = ENOENT; - return found; -} - -static char *get_modprobe(void) -{ - int procfile; - char *ret; - - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); - if (procfile < 0) - return NULL; - - ret = malloc(1024); - if (ret) { - switch (read(procfile, ret, 1024)) { - case -1: goto fail; - case 1024: goto fail; /* Partial read. Wierd */ - } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; - close(procfile); - return ret; - } - fail: - free(ret); - close(procfile); - return NULL; -} - -int iptables_insmod(const char *modname, const char *modprobe) -{ - char *buf = NULL; - char *argv[3]; - - /* If they don't explicitly set it, read out of kernel */ - if (!modprobe) { - buf = get_modprobe(); - if (!buf) - return -1; - modprobe = buf; - } - - switch (fork()) { - case 0: - argv[0] = (char *)modprobe; - argv[1] = (char *)modname; - argv[2] = NULL; - execv(argv[0], argv); - - /* not usually reached */ - exit(0); - case -1: - return -1; - - default: /* parent */ - wait(NULL); - } - - free(buf); - return 0; -} - -static struct ipt_entry * -generate_entry(const struct ipt_entry *fw, - struct iptables_match *matches, - struct ipt_entry_target *target) -{ - unsigned int size; - struct iptables_match *m; - struct ipt_entry *e; - - size = sizeof(struct ipt_entry); - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - size += m->m->u.match_size; - } - - e = fw_malloc(size + target->u.target_size); - *e = *fw; - e->target_offset = size; - e->next_offset = size + target->u.target_size; - - size = 0; - for (m = matches; m; m = m->next) { - if (!m->used) - continue; - - memcpy(e->elems + size, m->m, m->m->u.match_size); - size += m->m->u.match_size; - } - memcpy(e->elems + size, target, target->u.target_size); - - return e; -} - -int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) -{ - struct ipt_entry fw, *e = NULL; - int invert = 0; - unsigned int nsaddrs = 0, ndaddrs = 0; - struct in_addr *saddrs = NULL, *daddrs = NULL; - - int c, verbose = 0; - const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; - const char *policy = NULL, *newname = NULL; - unsigned int rulenum = 0, options = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; - int ret = 1; - struct iptables_match *m; - struct iptables_target *target = NULL; - struct iptables_target *t; - const char *jumpto = ""; - char *protocol = NULL; - const char *modprobe = NULL; - int proto_used = 0; - - memset(&fw, 0, sizeof(fw)); - - opts = original_opts; - global_option_offset = 0; - - /* re-set optind to 0 in case do_command gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = iptables_matches; m; m = m->next) { - m->mflags = 0; - m->used = 0; - } - - for (t = iptables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - 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:fbvnt:m:xc:", - opts, NULL)) != -1) { - switch (c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, - invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, CMD_ZERO, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'N': - if (optarg && *optarg == '-') - exit_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `-'\n"); - if (find_target(optarg, TRY_LOAD)) - exit_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - newname = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - policy = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!iptables_matches && protocol) - find_match(protocol, TRY_LOAD); - - exit_printhelp(); - - /* - * Option selection - */ - case 'p': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_PROTOCOL, &fw.ip.invflags, - invert); - - /* Canonicalize into lower case */ - for (protocol = argv[optind-1]; *protocol; protocol++) - *protocol = tolower(*protocol); - - protocol = argv[optind-1]; - fw.ip.proto = parse_protocol(protocol); - - if (fw.ip.proto == 0 - && (fw.ip.invflags & IPT_INV_PROTO)) - exit_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - fw.nfcache |= NFC_IP_PROTO; - break; - - case 's': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_SOURCE, &fw.ip.invflags, - invert); - shostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP_SRC; - break; - - case 'd': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_DESTINATION, &fw.ip.invflags, - invert); - dhostnetworkmask = argv[optind-1]; - fw.nfcache |= NFC_IP_DST; - break; - - case 'j': - set_option(&options, OPT_JUMP, &fw.ip.invflags, - invert); - jumpto = parse_target(optarg); - /* TRY_LOAD (may be chain name) */ - target = find_target(jumpto, TRY_LOAD); - - if (target) { - size_t size; - - size = IPT_ALIGN(sizeof(struct ipt_entry_target)) - + target->size; - - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - opts = merge_options(opts, target->extra_opts, &target->option_offset); - } - break; - - - case 'i': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags, - invert); - parse_interface(argv[optind-1], - fw.ip.iniface, - fw.ip.iniface_mask); - fw.nfcache |= NFC_IP_IF_IN; - break; - - case 'o': - check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags, - invert); - parse_interface(argv[optind-1], - fw.ip.outiface, - fw.ip.outiface_mask); - fw.nfcache |= NFC_IP_IF_OUT; - break; - - case 'f': - set_option(&options, OPT_FRAGMENT, &fw.ip.invflags, - invert); - fw.ip.flags |= IPT_F_FRAG; - fw.nfcache |= NFC_IP_FRAG; - break; - - case 'v': - if (!verbose) - set_option(&options, OPT_VERBOSE, - &fw.ip.invflags, invert); - verbose++; - break; - - case 'm': { - size_t size; - - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --match"); - - m = find_match(optarg, LOAD_MUST_SUCCEED); - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - opts = merge_options(opts, m->extra_opts, &m->option_offset); - } - break; - - case 'n': - set_option(&options, OPT_NUMERIC, &fw.ip.invflags, - invert); - break; - - case 't': - if (invert) - exit_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - *table = argv[optind-1]; - break; - - case 'x': - set_option(&options, OPT_EXPANDED, &fw.ip.invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", program_version); - else - printf("%s v%s\n", - program_name, program_version); - exit(0); - - case '0': - set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags, - invert); - break; - - case 'M': - modprobe = optarg; - break; - - case 'c': - - set_option(&options, OPT_COUNTERS, &fw.ip.invflags, - invert); - pcnt = optarg; - if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - bcnt = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - - if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1) - exit_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - - break; - - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - exit_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = TRUE; - optarg[0] = '\0'; - continue; - } - printf("Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - /* FIXME: This scheme doesn't allow two of the same - matches --RR */ - if (!target - || !(target->parse(c - target->option_offset, - argv, invert, - &target->tflags, - &fw, &target->t))) { - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - if (m->parse(c - m->option_offset, - argv, invert, - &m->mflags, - &fw, - &fw.nfcache, - &m->m)) - break; - } - - /* If you listen carefully, you can - actually hear this code suck. */ - - /* some explanations (after four different bugs - * in 3 different releases): If we encountere a - * parameter, that has not been parsed yet, - * it's not an option of an explicitly loaded - * match or a target. However, we support - * implicit loading of the protocol match - * extension. '-p tcp' means 'l4 proto 6' and - * at the same time 'load tcp protocol match on - * demand if we specify --dport'. - * - * To make this work, we need to make sure: - * - the parameter has not been parsed by - * a match (m above) - * - a protocol has been specified - * - the protocol extension has not been - * loaded yet, or is loaded and unused - * [think of iptables-restore!] - * - the protocol extension can be successively - * loaded - */ - if (m == NULL - && protocol - && (!find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - || (find_proto(protocol, DONT_LOAD, - options&OPT_NUMERIC) - && (proto_used == 0)) - ) - && (m = find_proto(protocol, TRY_LOAD, - options&OPT_NUMERIC))) { - /* Try loading protocol */ - size_t size; - - proto_used = 1; - - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - - m->m = fw_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->init(m->m, &fw.nfcache); - - opts = merge_options(opts, - m->extra_opts, &m->option_offset); - - optind--; - continue; - } - if (!m) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind-1]); - } - } - invert = FALSE; - } - - for (m = iptables_matches; m; m = m->next) { - if (!m->used) - continue; - - m->final_check(m->mflags); - } - - if (target) - target->final_check(target->tflags); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - exit_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - exit_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - exit_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) - dhostnetworkmask = "0.0.0.0/0"; - if (!(options & OPT_SOURCE)) - shostnetworkmask = "0.0.0.0/0"; - } - - if (shostnetworkmask) - parse_hostnetworkmask(shostnetworkmask, &saddrs, - &(fw.ip.smsk), &nsaddrs); - - if (dhostnetworkmask) - parse_hostnetworkmask(dhostnetworkmask, &daddrs, - &(fw.ip.dmsk), &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - exit_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 " - "specify a unique address"); - - generic_opt_check(command, options); - - if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN) - exit_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %i chars)", - chain, IPT_FUNCTION_MAXNAMELEN); - - /* only allocate handle if we weren't called with a handle */ - if (!*handle) - *handle = iptc_init(*table); - - if (!*handle) { - /* try to insmod the module if iptc_init failed */ - iptables_insmod("ip_tables", modprobe); - *handle = iptc_init(*table); - } - - if (!*handle) - exit_error(VERSION_PROBLEM, - "can't initialize iptables table `%s': %s", - *table, iptc_strerror(errno)); - - if (command == CMD_APPEND - || command == CMD_DELETE - || command == CMD_INSERT - || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) - exit_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - - if (target && iptc_is_chain(jumpto, *handle)) { - printf("Warning: using chain %s, not extension\n", - jumpto); - - target = NULL; - } - - /* If they didn't specify a target, or it's a chain - name, use standard. */ - if (!target - && (strlen(jumpto) == 0 - || iptc_is_chain(jumpto, *handle))) { - size_t size; - - target = find_target(IPT_STANDARD_TARGET, - LOAD_MUST_SUCCEED); - - size = sizeof(struct ipt_entry_target) - + target->size; - target->t = fw_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->init(target->t, &fw.nfcache); - } - - if (!target) { - /* it is no chain, and we can't load a plugin. - * We cannot know if the plugin is corrupt, non - * existant OR if the user just misspelled a - * chain. */ - find_target(jumpto, LOAD_MUST_SUCCEED); - } else { - e = generate_entry(&fw, iptables_matches, target->t); - } - } - - switch (command) { - case CMD_APPEND: - ret = append_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE: - ret = delete_entry(chain, e, - nsaddrs, saddrs, ndaddrs, daddrs, - options&OPT_VERBOSE, - handle); - break; - case CMD_DELETE_NUM: - ret = iptc_delete_num_entry(chain, rulenum - 1, handle); - break; - case CMD_REPLACE: - ret = replace_entry(chain, e, rulenum - 1, - saddrs, daddrs, options&OPT_VERBOSE, - handle); - break; - case CMD_INSERT: - ret = insert_entry(chain, e, rulenum - 1, - nsaddrs, saddrs, ndaddrs, daddrs, - 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); - break; - case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, handle); - break; - case CMD_LIST|CMD_ZERO: - ret = list_entries(chain, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, - handle); - if (ret) - ret = zero_entries(chain, - options&OPT_VERBOSE, handle); - break; - case CMD_NEW_CHAIN: - ret = iptc_create_chain(chain, handle); - break; - case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, handle); - break; - case CMD_RENAME_CHAIN: - ret = iptc_rename_chain(chain, newname, handle); - break; - case CMD_SET_POLICY: - ret = iptc_set_policy(chain, policy, NULL, handle); - break; - default: - /* We should never reach this... */ - exit_tryhelp(2); - } - - if (verbose > 1) - dump_entries(*handle); - - return ret; -} diff --git a/iptables.spec b/iptables.spec new file mode 100644 index 0000000..695c2ae --- /dev/null +++ b/iptables.spec @@ -0,0 +1,360 @@ +%define build_devel 1 +%define linux_header 0 + +Name: iptables +Summary: Tools for managing Linux kernel packet filtering capabilities. +Version: 1.2.9 +Release: 2.3.1 +Source: http://www.netfilter.org/%{name}-%{version}.tar.bz2 +Source1: iptables.init +Source2: iptables-config +%if %{linux_header} +Source3: netfilter-2.4.20.tar.gz +%endif +Patch2: iptables-1.2.8-nolibnsl.patch +Patch3: iptables-1.2.8-print_type.patch +Patch4: iptables-1.2.9-netlink.patch +Patch5: iptables-1.2.9-selinux.patch +Patch6: iptables-1.2.9-counters.patch +Group: System Environment/Base +URL: http://www.netfilter.org/ +BuildRoot: %{_tmppath}/%{name}-buildroot +License: GPL +BuildPrereq: /usr/bin/perl +Requires: kernel >= 2.4.20 +Requires(post,postun): chkconfig +Prefix: %{_prefix} + +%package ipv6 +Summary: IPv6 support for iptables. +Group: System Environment/Base +Requires: %{name} = %{version} + +%if %{build_devel} +%package devel +Summary: Development package for iptables. +Group: System Environment/Base +Requires: %{name} = %{version} +%endif + +%description +The iptables utility controls the network packet filtering code in the +Linux kernel. If you need to set up firewalls and/or IP masquerading, +you should install this package. + +%description ipv6 +The iptables package contains IPv6 (the next version of the IP +protocol) support for iptables. Iptables controls the Linux kernel +network packet filtering code, allowing you to set up firewalls and IP +masquerading. + +Install iptables-ipv6 if you need to set up firewalling for your +network and you are using ipv6. + +%if %{build_devel} +%description devel +The iptables utility controls the network packet filtering code in the +Linux kernel. If you need to set up firewalls and/or IP masquerading, +you should install this package. +%endif + +%prep +rm -rf %{buildroot} + +%setup -q +%if %{linux_header} +cd include +tar -zxf %{SOURCE3} +cd .. +%endif +%patch2 -p1 -b .nolibnsl +%patch3 -p1 -b .print_type +%patch4 -p1 -b .netlink +%patch5 -p1 -b .selinux +%patch6 -p1 -b .counters + +# Put it to a reasonable place +find . -type f -exec perl -pi -e "s,/usr/local,%{prefix},g" {} \; + +%build +TOPDIR=`pwd` +OPT="$RPM_OPT_FLAGS -I$TOPDIR/include" +make COPT_FLAGS="$OPT" KERNEL_DIR=/usr LIBDIR=/%{_lib} +make COPT_FLAGS="$OPT" KERNEL_DIR=/usr LIBDIR=/%{_lib} iptables-save iptables-restore +make COPT_FLAGS="$OPT" KERNEL_DIR=/usr LIBDIR=/%{_lib} ip6tables-save ip6tables-restore + +%install +make install DESTDIR=%{buildroot} KERNEL_DIR=/usr BINDIR=/sbin LIBDIR=/%{_lib} MANDIR=%{_mandir} +%if %{build_devel} +make install-devel DESTDIR=%{buildroot} KERNEL_DIR=/usr BINDIR=/sbin LIBDIR=%{_libdir} MANDIR=%{_mandir} +%endif +cp ip{6,}tables-{save,restore} $RPM_BUILD_ROOT/sbin +cp iptables-*.8 $RPM_BUILD_ROOT%{_mandir}/man8 +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d +install -c -m755 %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/iptables +sed -e 's;iptables;ip6tables;g' -e 's;IPTABLES;IP6TABLES;g' < %{SOURCE1} > ip6tables.init +install -c -m755 ip6tables.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ip6tables +mkdir -p $RPM_BUILD_ROOT/etc/sysconfig +install -c -m755 %{SOURCE2} $RPM_BUILD_ROOT/etc/sysconfig/iptables-config +sed -e 's;iptables;ip6tables;g' -e 's;IPTABLES;IP6TABLES;g' < %{SOURCE2} > ip6tables-config +install -c -m755 ip6tables-config $RPM_BUILD_ROOT/etc/sysconfig/ip6tables-config + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +/sbin/chkconfig --add iptables + +%preun +if [ "$1" = 0 ]; then + /sbin/chkconfig --del iptables +fi + +%post ipv6 +/sbin/chkconfig --add ip6tables + +%preun ipv6 +if [ "$1" = 0 ]; then + /sbin/chkconfig --del ip6tables +fi + +%files +%defattr(-,root,root,0755) +%doc COPYING INSTALL INCOMPATIBILITIES +%config %attr(0755,root,root) /etc/rc.d/init.d/iptables +%config(noreplace) %attr(0600,root,root) /etc/sysconfig/iptables-config +/sbin/iptables* +%{_mandir}/man8/iptables* +%dir /%{_lib}/iptables +/%{_lib}/iptables/libipt* + +%files ipv6 +%defattr(-,root,root,0755) +%config %attr(0755,root,root) /etc/rc.d/init.d/ip6tables +%config(noreplace) %attr(0600,root,root) /etc/sysconfig/ip6tables-config +/sbin/ip6tables* +%{_mandir}/man8/ip6tables* +/%{_lib}/iptables/libip6t* + +%if %{build_devel} +%files devel +%defattr(-,root,root,0755) +%{_includedir}/libipq.h +%{_libdir}/libipq.a +%{_libdir}/libiptc.a +%{_mandir}/man3/* +%endif + +%changelog +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Thu Feb 26 2004 Thomas Woerner 1.2.9-2.3 +- fixed iptables-restore -c fault if there are no counters (#116421) + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Sun Jan 25 2004 Dan Walsh 1.2.9-1.2 +- Close File descriptors to prevent SELinux error message + +* Wed Jan 7 2004 Thomas Woerner 1.2.9-1.1 +- rebuild + +* Wed Dec 17 2003 Thomas Woerner 1.2.9-1 +- vew version 1.2.9 +- new config options in ipXtables-config: + IPTABLES_MODULES_UNLOAD +- more documentation in ipXtables-config +- fix for netlink security issue in libipq (devel package) +- print fix for libipt_icmp (#109546) + +* Thu Oct 23 2003 Thomas Woerner 1.2.8-13 +- marked all messages in iptables init script for translation (#107462) +- enabled devel package (#105884, #106101) +- bumped build for fedora for libipt_recent.so (#106002) + +* Tue Sep 23 2003 Thomas Woerner 1.2.8-12.1 +- fixed lost udp port range in ip6tables-save (#104484) +- fixed non numeric multiport port output in ipXtables-savs + +* Mon Sep 22 2003 Florian La Roche 1.2.8-11 +- do not link against -lnsl + +* Wed Sep 17 2003 Thomas Woerner 1.2.8-10 +- made variables in rmmod_r local + +* Tue Jul 22 2003 Thomas Woerner 1.2.8-9 +- fixed permission for init script + +* Sat Jul 19 2003 Thomas Woerner 1.2.8-8 +- fixed save when iptables file is missing and iptables-config permissions + +* Tue Jul 8 2003 Thomas Woerner 1.2.8-7 +- fixes for ip6tables: module unloading, setting policy only for existing + tables + +* Thu Jul 3 2003 Thomas Woerner 1.2.8-6 +- IPTABLES_SAVE_COUNTER defaults to no, now +- install config file in /etc/sysconfig +- exchange unload of ip_tables and ip_conntrack +- fixed start function + +* Wed Jul 2 2003 Thomas Woerner 1.2.8-5 +- new config option IPTABLES_SAVE_ON_RESTART +- init script: new status, save and restart +- fixes #44905, #65389, #80785, #82860, #91040, #91560 and #91374 + +* Mon Jun 30 2003 Thomas Woerner 1.2.8-4 +- new config option IPTABLES_STATUS_NUMERIC +- cleared IPTABLES_MODULES in iptables-config + +* Mon Jun 30 2003 Thomas Woerner 1.2.8-3 +- new init scripts + +* Sat Jun 28 2003 Florian La Roche +- remove check for very old kernel versions in init scripts +- sync up both init scripts and remove some further ugly things +- add some docu into rpm + +* Thu Jun 26 2003 Thomas Woerner 1.2.8-2 +- rebuild + +* Mon Jun 16 2003 Thomas Woerner 1.2.8-1 +- update to 1.2.8 + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Mon Jan 13 2003 Bill Nottingham 1.2.7a-1 +- update to 1.2.7a +- add a plethora of bugfixes courtesy Michael Schwendt + +* Fri Dec 13 2002 Elliot Lee 1.2.6a-3 +- Fix multilib + +* Wed Aug 07 2002 Karsten Hopp +- fixed iptables and ip6tables initscript output, based on #70511 +- check return status of all iptables calls, not just the last one + in a 'for' loop. + +* Mon Jul 29 2002 Bernhard Rosenkraenzer 1.2.6a-1 +- 1.2.6a (bugfix release, #69747) + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Mon Mar 4 2002 Bernhard Rosenkraenzer 1.2.5-3 +- Add some fixes from CVS, fixing bug #60465 + +* Tue Feb 12 2002 Bernhard Rosenkraenzer 1.2.5-2 +- Merge ip6tables improvements from Ian Prowell + #59402 +- Update URL (#59354) +- Use /sbin/chkconfig rather than chkconfig in %postun script + +* Fri Jan 11 2002 Bernhard Rosenkraenzer 1.2.5-1 +- 1.2.5 + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Mon Nov 5 2001 Bernhard Rosenkraenzer 1.2.4-2 +- Fix %preun script + +* Tue Oct 30 2001 Bernhard Rosenkraenzer 1.2.4-1 +- Update to 1.2.4 (various fixes, including security fixes; among others: + #42990, #50500, #53325, #54280) +- Fix init script (#31133) + +* Mon Sep 3 2001 Bernhard Rosenkraenzer 1.2.3-1 +- 1.2.3 (5 security fixes, some other fixes) +- Fix updating (#53032) + +* Mon Aug 27 2001 Bernhard Rosenkraenzer 1.2.2-4 +- Fix #50990 +- Add some fixes from current CVS; should fix #52620 + +* Mon Jul 16 2001 Bernhard Rosenkraenzer 1.2.2-3 +- Add some fixes from the current CVS tree; fixes #49154 and some IPv6 + issues + +* Tue Jun 26 2001 Bernhard Rosenkraenzer 1.2.2-2 +- Fix iptables-save reject-with (#45632), Patch from Michael Schwendt + + +* Tue May 8 2001 Bernhard Rosenkraenzer 1.2.2-1 +- 1.2.2 + +* Wed Mar 21 2001 Bernhard Rosenkraenzer +- 1.2.1a, fixes #28412, #31136, #31460, #31133 + +* Thu Mar 1 2001 Bernhard Rosenkraenzer +- Yet another initscript fix (#30173) +- Fix the fixes; they fixed some issues but broke more important + stuff :/ (#30176) + +* Tue Feb 27 2001 Bernhard Rosenkraenzer +- Fix up initscript (#27962) +- Add fixes from CVS to iptables-{restore,save}, fixing #28412 + +* Fri Feb 09 2001 Karsten Hopp +- create /etc/sysconfig/iptables mode 600 (same problem as #24245) + +* Mon Feb 05 2001 Karsten Hopp +- fix bugzilla #25986 (initscript not marked as config file) +- fix bugzilla #25962 (iptables-restore) +- mv chkconfig --del from postun to preun + +* Thu Feb 1 2001 Trond Eivind Glomsrød +- Fix check for ipchains + +* Mon Jan 29 2001 Bernhard Rosenkraenzer +- Some fixes to init scripts + +* Wed Jan 24 2001 Bernhard Rosenkraenzer +- Add some fixes from CVS, fixes among other things Bug #24732 + +* Wed Jan 17 2001 Bernhard Rosenkraenzer +- Add missing man pages, fix up init script (Bug #17676) + +* Mon Jan 15 2001 Bill Nottingham +- add init script + +* Mon Jan 15 2001 Bernhard Rosenkraenzer +- 1.2 +- fix up ipv6 split +- add init script +- Move the plugins from /usr/lib/iptables to /lib/iptables. + This needs to work before /usr is mounted... +- Use -O1 on alpha (compiler bug) + +* Sat Jan 6 2001 Bernhard Rosenkraenzer +- 1.1.2 +- Add IPv6 support (in separate package) + +* Thu Aug 17 2000 Bill Nottingham +- build everywhere + +* Tue Jul 25 2000 Bernhard Rosenkraenzer +- 1.1.1 + +* Thu Jul 13 2000 Prospector +- automatic rebuild + +* Tue Jun 27 2000 Preston Brown +- move iptables to /sbin. +- excludearch alpha for now, not building there because of compiler bug(?) + +* Fri Jun 9 2000 Bill Nottingham +- don't obsolete ipchains either +- update to 1.1.0 + +* Mon Jun 4 2000 Bill Nottingham +- remove explicit kernel requirement + +* Tue May 2 2000 Bernhard Rosenkränzer +- initial package diff --git a/libipq/libipq.c.netlink b/libipq/libipq.c.netlink deleted file mode 100644 index 709c8a2..0000000 --- a/libipq/libipq.c.netlink +++ /dev/null @@ -1,373 +0,0 @@ -/* - * libipq.c - * - * IPQ userspace library. - * - * Please note that this library is still developmental, and there may - * be some API changes. - * - * Author: James Morris - * - * 07-11-2001 Modified by Fernando Anton to add support for IPv6. - * - * Copyright (c) 2000-2001 Netfilter Core Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -/**************************************************************************** - * - * Private interface - * - ****************************************************************************/ - -enum { - IPQ_ERR_NONE = 0, - IPQ_ERR_IMPL, - IPQ_ERR_HANDLE, - IPQ_ERR_SOCKET, - IPQ_ERR_BIND, - IPQ_ERR_BUFFER, - IPQ_ERR_RECV, - IPQ_ERR_NLEOF, - IPQ_ERR_ADDRLEN, - IPQ_ERR_STRUNC, - IPQ_ERR_RTRUNC, - IPQ_ERR_NLRECV, - IPQ_ERR_SEND, - IPQ_ERR_SUPP, - IPQ_ERR_RECVBUF, - IPQ_ERR_TIMEOUT, - IPQ_ERR_PROTOCOL -}; -#define IPQ_MAXERR IPQ_ERR_PROTOCOL - -struct ipq_errmap_t { - int errcode; - char *message; -} ipq_errmap[] = { - { IPQ_ERR_NONE, "Unknown error" }, - { IPQ_ERR_IMPL, "Implementation error" }, - { IPQ_ERR_HANDLE, "Unable to create netlink handle" }, - { IPQ_ERR_SOCKET, "Unable to create netlink socket" }, - { IPQ_ERR_BIND, "Unable to bind netlink socket" }, - { IPQ_ERR_BUFFER, "Unable to allocate buffer" }, - { IPQ_ERR_RECV, "Failed to receive netlink message" }, - { IPQ_ERR_NLEOF, "Received EOF on netlink socket" }, - { IPQ_ERR_ADDRLEN, "Invalid peer address length" }, - { IPQ_ERR_STRUNC, "Sent message truncated" }, - { IPQ_ERR_RTRUNC, "Received message truncated" }, - { IPQ_ERR_NLRECV, "Received error from netlink" }, - { IPQ_ERR_SEND, "Failed to send netlink message" }, - { IPQ_ERR_SUPP, "Operation not supported" }, - { IPQ_ERR_RECVBUF, "Receive buffer size invalid" }, - { IPQ_ERR_TIMEOUT, "Timeout"}, - { IPQ_ERR_PROTOCOL, "Invalid protocol specified" } -}; - -static int ipq_errno = IPQ_ERR_NONE; - -static ssize_t ipq_netlink_sendto(const struct ipq_handle *h, - const void *msg, size_t len); - -static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h, - unsigned char *buf, size_t len, - int timeout); - -static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h, - const struct msghdr *msg, - unsigned int flags); - -static char *ipq_strerror(int errcode); - -static ssize_t ipq_netlink_sendto(const struct ipq_handle *h, - const void *msg, size_t len) -{ - int status = sendto(h->fd, msg, len, 0, - (struct sockaddr *)&h->peer, sizeof(h->peer)); - if (status < 0) - ipq_errno = IPQ_ERR_SEND; - return status; -} - -static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h, - const struct msghdr *msg, - unsigned int flags) -{ - int status = sendmsg(h->fd, msg, flags); - if (status < 0) - ipq_errno = IPQ_ERR_SEND; - return status; -} - -static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h, - unsigned char *buf, size_t len, - int timeout) -{ - int addrlen, status; - struct nlmsghdr *nlh; - - if (len < sizeof(struct nlmsgerr)) { - ipq_errno = IPQ_ERR_RECVBUF; - return -1; - } - addrlen = sizeof(h->peer); - - if (timeout != 0) { - int ret; - struct timeval tv; - fd_set read_fds; - - if (timeout < 0) { - /* non-block non-timeout */ - tv.tv_sec = 0; - tv.tv_usec = 0; - } else { - tv.tv_sec = timeout / 1000000; - tv.tv_usec = timeout % 1000000; - } - - FD_ZERO(&read_fds); - FD_SET(h->fd, &read_fds); - ret = select(h->fd+1, &read_fds, NULL, NULL, &tv); - if (ret < 0) { - if (errno == EINTR) { - return 0; - } else { - ipq_errno = IPQ_ERR_RECV; - return -1; - } - } - if (!FD_ISSET(h->fd, &read_fds)) { - ipq_errno = IPQ_ERR_TIMEOUT; - return 0; - } - } - status = recvfrom(h->fd, buf, len, 0, - (struct sockaddr *)&h->peer, &addrlen); - if (status < 0) { - ipq_errno = IPQ_ERR_RECV; - return status; - } - if (addrlen != sizeof(h->peer)) { - ipq_errno = IPQ_ERR_RECV; - return -1; - } - if (status == 0) { - ipq_errno = IPQ_ERR_NLEOF; - return -1; - } - nlh = (struct nlmsghdr *)buf; - if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) { - ipq_errno = IPQ_ERR_RTRUNC; - return -1; - } - return status; -} - -static char *ipq_strerror(int errcode) -{ - if (errcode < 0 || errcode > IPQ_MAXERR) - errcode = IPQ_ERR_IMPL; - return ipq_errmap[errcode].message; -} - -/**************************************************************************** - * - * Public interface - * - ****************************************************************************/ - -/* - * Create and initialise an ipq handle. - */ -struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol) -{ - int status; - struct ipq_handle *h; - - h = (struct ipq_handle *)malloc(sizeof(struct ipq_handle)); - if (h == NULL) { - ipq_errno = IPQ_ERR_HANDLE; - return NULL; - } - - memset(h, 0, sizeof(struct ipq_handle)); - - if (protocol == PF_INET) - h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL); - else if (protocol == PF_INET6) - h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP6_FW); - else { - ipq_errno = IPQ_ERR_PROTOCOL; - free(h); - return NULL; - } - - if (h->fd == -1) { - ipq_errno = IPQ_ERR_SOCKET; - close(h->fd); - free(h); - return NULL; - } - memset(&h->local, 0, sizeof(struct sockaddr_nl)); - h->local.nl_family = AF_NETLINK; - h->local.nl_pid = getpid(); - h->local.nl_groups = 0; - status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local)); - if (status == -1) { - ipq_errno = IPQ_ERR_BIND; - close(h->fd); - free(h); - return NULL; - } - memset(&h->peer, 0, sizeof(struct sockaddr_nl)); - h->peer.nl_family = AF_NETLINK; - h->peer.nl_pid = 0; - h->peer.nl_groups = 0; - return h; -} - -/* - * No error condition is checked here at this stage, but it may happen - * if/when reliable messaging is implemented. - */ -int ipq_destroy_handle(struct ipq_handle *h) -{ - if (h) { - close(h->fd); - free(h); - } - return 0; -} - -int ipq_set_mode(const struct ipq_handle *h, - u_int8_t mode, size_t range) -{ - struct { - struct nlmsghdr nlh; - ipq_peer_msg_t pm; - } req; - - memset(&req, 0, sizeof(req)); - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req)); - req.nlh.nlmsg_flags = NLM_F_REQUEST; - req.nlh.nlmsg_type = IPQM_MODE; - req.nlh.nlmsg_pid = h->local.nl_pid; - req.pm.msg.mode.value = mode; - req.pm.msg.mode.range = range; - return ipq_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len); -} - -/* - * timeout is in microseconds (1 second is 1000000 (1 million) microseconds) - * - */ -ssize_t ipq_read(const struct ipq_handle *h, - unsigned char *buf, size_t len, int timeout) -{ - return ipq_netlink_recvfrom(h, buf, len, timeout); -} - -int ipq_message_type(const unsigned char *buf) -{ - return ((struct nlmsghdr*)buf)->nlmsg_type; -} - -int ipq_get_msgerr(const unsigned char *buf) -{ - struct nlmsghdr *h = (struct nlmsghdr *)buf; - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); - return -err->error; -} - -ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf) -{ - return NLMSG_DATA((struct nlmsghdr *)(buf)); -} - -int ipq_set_verdict(const struct ipq_handle *h, - ipq_id_t id, - unsigned int verdict, - size_t data_len, - unsigned char *buf) -{ - unsigned char nvecs; - size_t tlen; - struct nlmsghdr nlh; - ipq_peer_msg_t pm; - struct iovec iov[3]; - struct msghdr msg; - - memset(&nlh, 0, sizeof(nlh)); - nlh.nlmsg_flags = NLM_F_REQUEST; - nlh.nlmsg_type = IPQM_VERDICT; - nlh.nlmsg_pid = h->local.nl_pid; - memset(&pm, 0, sizeof(pm)); - pm.msg.verdict.value = verdict; - pm.msg.verdict.id = id; - pm.msg.verdict.data_len = data_len; - iov[0].iov_base = &nlh; - iov[0].iov_len = sizeof(nlh); - iov[1].iov_base = ± - iov[1].iov_len = sizeof(pm); - tlen = sizeof(nlh) + sizeof(pm); - nvecs = 2; - if (data_len && buf) { - iov[2].iov_base = buf; - iov[2].iov_len = data_len; - tlen += data_len; - nvecs++; - } - msg.msg_name = (void *)&h->peer; - msg.msg_namelen = sizeof(h->peer); - msg.msg_iov = iov; - msg.msg_iovlen = nvecs; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - nlh.nlmsg_len = tlen; - return ipq_netlink_sendmsg(h, &msg, 0); -} - -/* Not implemented yet */ -int ipq_ctl(const struct ipq_handle *h, int request, ...) -{ - return 1; -} - -char *ipq_errstr(void) -{ - return ipq_strerror(ipq_errno); -} - -void ipq_perror(const char *s) -{ - if (s) - fputs(s, stderr); - else - fputs("ERROR", stderr); - if (ipq_errno) - fprintf(stderr, ": %s", ipq_errstr()); - if (errno) - fprintf(stderr, ": %s", strerror(errno)); - fputc('\n', stderr); -} diff --git a/libiptc2/.#libiptc.c.1.40 b/libiptc2/.#libiptc.c.1.40 deleted file mode 100644 index ce4af9b..0000000 --- a/libiptc2/.#libiptc.c.1.40 +++ /dev/null @@ -1,1972 +0,0 @@ -/* Library which manipulates firewall rules. Version $Revision: 1.40 $ */ - -/* Architecture of firewall rules is as follows: - * - * Chains go INPUT, FORWARD, OUTPUT then user chains. - * Each user chain starts with an ERROR node. - * Every chain ends with an unconditional jump: a RETURN for user chains, - * and a POLICY for built-ins. - */ - -/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See - * COPYING for details). - * (C) 2000-2003 by the Netfilter Core Team - * - * 2003-Jun-20: Harald Welte : - * - Reimplementation of chain cache to use offsets instead of entries - * 2003-Jun-23: Harald Welte : - * - speed optimization, sponsored by Astaro AG (http://www.astaro.com/) - * don't rebuild the chain cache after every operation, instead fix it - * up after a ruleset change. - * 2003-Jun-30: Harald Welte : - * - total reimplementation - */ -#include "linux_listhelp.h" - -#ifndef IPT_LIB_DIR -#define IPT_LIB_DIR "/usr/lib/iptables" -#endif - -static int sockfd = -1; -static void *iptc_fn = NULL; - -static const char *hooknames[] -= { [HOOK_PRE_ROUTING] "PREROUTING", - [HOOK_LOCAL_IN] "INPUT", - [HOOK_FORWARD] "FORWARD", - [HOOK_LOCAL_OUT] "OUTPUT", - [HOOK_POST_ROUTING] "POSTROUTING", -#ifdef HOOK_DROPPING - [HOOK_DROPPING] "DROPPING" -#endif -}; - -struct counter_map -{ - enum { - COUNTER_MAP_NOMAP, - COUNTER_MAP_NORMAL_MAP, - COUNTER_MAP_ZEROED, - COUNTER_MAP_SET - } maptype; - unsigned int mappos; -}; - -/* Convenience structures */ -struct ipt_error_target -{ - STRUCT_ENTRY_TARGET t; - char error[TABLE_MAXNAMELEN]; -}; - -struct rule_head -{ - struct list_head list; /* list of rules in chain */ - - struct chain_head *chain; /* we're part of this chain */ - struct rule_head *target; /* target of this rule, in case - it is a jump rule */ - - - unsigned int size; /* size of rule */ - STRUCT_ENTRY *entry_blob; /* pointer to entry in blob */ - STRUCT_ENTRY entry[0]; -}; - -struct chain_head -{ - struct list_head list; - - char name[TABLE_MAXNAMELEN]; - unsigned int hooknum; - struct list_head rules; -}; - -STRUCT_TC_HANDLE -{ - /* Have changes been made? */ - int changed; - - /* linked list of chains in this table */ - struct list_head chains; - - /* current position of first_chain() / next_chain() */ - struct chain_head *chain_iterator_cur; - - /* current position of first_rule() / next_rule() */ - struct rule_head *rule_iterator_cur; - - struct counter_map *counter_map; - - /* the structure we receive from getsockopt() */ - STRUCT_GETINFO info; - - /* Array of hook names */ - const char **hooknames; -#if 0 - /* Size in here reflects original state. */ - - - /* Cached position of chain heads (NULL = no cache). */ - unsigned int cache_num_chains; - unsigned int cache_num_builtins; - struct chain_cache *cache_chain_heads; - - /* Chain iterator: current chain cache entry. */ - struct chain_cache *cache_chain_iteration; - - /* Rule iterator: terminal rule */ - STRUCT_ENTRY *cache_rule_end; - - /* Number in here reflects current state. */ - unsigned int new_number; -#endif - STRUCT_GET_ENTRIES entries; -}; - -static void -set_changed(TC_HANDLE_T h) -{ - h->changed = 1; -} - -#ifdef IPTC_DEBUG -static void do_check(TC_HANDLE_T h, unsigned int line); -#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) -#else -#define CHECK(h) -#endif - -static struct rule_head *ruleh_alloc(unsigned int size) -{ - struct rule_head *ruleh = malloc(sizeof(*ruleh)+size); - if (!ruleh) - return NULL; - - memset(ruleh, 0, sizeof(*ruleh)+size); - ruleh->size = size; - - return ruleh; -} - -static void ruleh_free(struct rule_head *ruleh) -{ - list_del(&ruleh->list); - free(ruleh); -} - -static struct rule_head *ruleh_get_n(struct chain_head *chain, int num) -{ - return NULL; -} - -static struct chain_head *chainh_alloc(TC_HANDLE_T h, const char *name) -{ - struct chain_head *chainh = malloc(sizeof(*chainh)); - if (!chainh) - return NULL; - - memset(chainh, 0, sizeof(*chainh)); - strncpy(chainh->name, name, sizeof(&chainh->name)); - list_append(&chainh->list, &h->chains); - - return chainh; -} - -static void -chainh_free(struct chain_head *chainh) -{ - /* FIXME */ - struct list_head *cur_item, *item2; - - list_for_each_safe(cur_item, item2, &chainh->rules) { - struct rule_head *ruleh = list_entry(cur_item, - struct rule_head, - list); - ruleh_free(ruleh); - } - - list_del(&chainh->list); -} - -#if 0 -static inline int -get_number(const STRUCT_ENTRY *i, - const STRUCT_ENTRY *seek, - unsigned int *pos) -{ - if (i == seek) - return 1; - (*pos)++; - return 0; -} -#endif - -static struct chain_head * -chainh_find(TC_HANDLE_T h, const IPT_CHAINLABEL name) -{ - struct list_head *cur; - - list_for_each(cur, &h->chains) { - struct chain_head *ch = list_entry(cur, struct chain_head, - list); - if (!strcmp(name, ch->name)) - return ch; - } - return NULL; -} - -static inline unsigned long -entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) -{ - return (void *)e - (void *)h->entries.entrytable; -} - -#if 0 -static unsigned int -entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek) -{ - unsigned int pos = 0; - - if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size, - get_number, seek, &pos) == 0) { - fprintf(stderr, "ERROR: offset %i not an entry!\n", - (char *)seek - (char *)h->entries.entrytable); - abort(); - } - return pos; -} - -static inline int -get_entry_n(STRUCT_ENTRY *i, - unsigned int number, - unsigned int *pos, - STRUCT_ENTRY **pe) -{ - if (*pos == number) { - *pe = i; - return 1; - } - (*pos)++; - return 0; -} - -static STRUCT_ENTRY * -index2entry(TC_HANDLE_T h, unsigned int index) -{ - unsigned int pos = 0; - STRUCT_ENTRY *ret = NULL; - - ENTRY_ITERATE(h->entries.entrytable, h->entries.size, - get_entry_n, index, &pos, &ret); - - return ret; -} - -static inline STRUCT_ENTRY * -get_entry(TC_HANDLE_T h, unsigned int offset) -{ - return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset); -} - - -static inline unsigned long -index2offset(TC_HANDLE_T h, unsigned int index) -{ - return entry2offset(h, index2entry(h, index)); -} - -static inline STRUCT_ENTRY * -offset2entry(TC_HANDLE_T h, unsigned int offset) -{ - return (STRUCT_ENTRY *) ((void *)h->entries.entrytable+offset); -} - -static inline unsigned int -offset2index(const TC_HANDLE_T h, unsigned int offset) -{ - return entry2index(h, offset2entry(h, offset)); -} - - -static const char * -get_errorlabel(TC_HANDLE_T h, unsigned int offset) -{ - STRUCT_ENTRY *e; - - e = get_entry(h, offset); - if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) { - fprintf(stderr, "ERROR: offset %u not an error node!\n", - offset); - abort(); - } - - return (const char *)GET_TARGET(e)->data; -} -#endif - -/* Allocate handle of given size */ -static TC_HANDLE_T -alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) -{ - size_t len; - TC_HANDLE_T h; - - len = sizeof(STRUCT_TC_HANDLE) - + size - + num_rules * sizeof(struct counter_map); - - if ((h = malloc(len)) == NULL) { - errno = ENOMEM; - return NULL; - } - - h->changed = 0; - - h->counter_map = (void *)h - + sizeof(STRUCT_TC_HANDLE) - + size; - strcpy(h->info.name, tablename); - strcpy(h->entries.name, tablename); - INIT_LIST_HEAD(&h->chains); - - return h; -} - -struct rule_head * -append_entrycopy(STRUCT_ENTRY *e, struct chain_head *chain) -{ - struct rule_head *ruleh = ruleh_alloc(e->next_offset); - if (!ruleh) - return NULL; - - memcpy(&ruleh->entry, e, e->next_offset); - ruleh->chain = chain; - ruleh->entry_blob = e; - list_append(&ruleh->list, &chain->rules); - - return ruleh; -} - - -/* have to return 0 on success, bcf ENTRY_ITERATE */ -static inline int -parse_entry(STRUCT_ENTRY *e, TC_HANDLE_T h, struct chain_head **curchain) -{ - int i; - union tgt_u { - STRUCT_ENTRY_TARGET ent; - STRUCT_STANDARD_TARGET std; - struct ipt_error_target err; - } *tgt; - - tgt = (union tgt_u *) GET_TARGET(e); - - if (e->target_offset == sizeof(STRUCT_ENTRY) - && (strcmp(tgt->ent.u.user.name, IPT_STANDARD_TARGET) == 0)) { - /* jump to somewhere else */ - append_entrycopy(e, *curchain); - /* FIXME: */ - } else if (e->target_offset == sizeof(STRUCT_ENTRY) - && e->next_offset == sizeof(STRUCT_ENTRY) - + ALIGN(sizeof(struct ipt_error_target)) - && !strcmp(tgt->ent.u.user.name, ERROR_TARGET)) { - /* chain head */ - *curchain = chainh_find(h, tgt->err.error); - if (*curchain) { - /* FIXME: error handling */ - return 1; - } - - *curchain = chainh_alloc(h, tgt->err.error); - /* FIXME: error handling */ - append_entrycopy(e, *curchain); - } else if (e->target_offset == sizeof(STRUCT_ENTRY) - && e->next_offset == sizeof(STRUCT_ENTRY) - + ALIGN(sizeof(STRUCT_STANDARD_TARGET)) - && tgt->std.verdict == RETURN) { - /* chain end */ - append_entrycopy(e, *curchain); - *curchain = NULL; - } else { - /* normal rule */ - append_entrycopy(e, *curchain); - } - - /* iterate over hook_entries, needed to connect builtin - * chains with hook numbers */ - for (i = 0; i < NUMHOOKS; i++) { - if (!(h->info.valid_hooks & (1 << i))) - continue; - if (h->info.hook_entry[i] == entry2offset(h, e)) { - /* found hook entry point */ - if (*curchain) - (*curchain)->hooknum = i; - } - if (h->info.underflow[i] == entry2offset(h, e)) { - /* found underflow point */ - } - } - - return 0; -} - -static int parse_ruleset(TC_HANDLE_T h) -{ - struct chain_head *curchain; - - /* iterate over ruleset; create linked list of rule_head/chain_head */ - if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size, - parse_entry, h, &curchain)) { - /* some error happened while iterating */ - return 0; - } - - return 1; -} - -TC_HANDLE_T -TC_INIT(const char *tablename) -{ - TC_HANDLE_T h; - STRUCT_GETINFO info; - unsigned int i; - int tmp; - socklen_t s; - - iptc_fn = TC_INIT; - - if (sockfd != -1) { - close(sockfd); - sockfd = -1; - } - - if (strlen(tablename) >= TABLE_MAXNAMELEN) { - errno = EINVAL; - return NULL; - } - - sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); - if (sockfd < 0) - return NULL; - - s = sizeof(info); - - strcpy(info.name, tablename); - if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) - return NULL; - - if ((h = alloc_handle(info.name, info.size, info.num_entries)) - == NULL) { - close(sockfd); - sockfd = -1; - return NULL; - } - -/* Too hard --RR */ -#if 0 - sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name); - dynlib = dlopen(pathname, RTLD_NOW); - if (!dynlib) { - errno = ENOENT; - return NULL; - } - h->hooknames = dlsym(dynlib, "hooknames"); - if (!h->hooknames) { - errno = ENOENT; - return NULL; - } -#else - h->hooknames = hooknames; -#endif - - /* Initialize current state */ - h->info = info; - //h->new_number = h->info.num_entries; - for (i = 0; i < h->info.num_entries; i++) - h->counter_map[i] - = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i}); - - h->entries.size = h->info.size; - - tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; - - if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries, - &tmp) < 0) { - close(sockfd); - sockfd = -1; - free(h); - return NULL; - } - - CHECK(h); - parse_ruleset(h); - - return h; -} - -void -TC_FREE(TC_HANDLE_T *h) -{ - struct list_head *cur_item, *item2; - - close(sockfd); - sockfd = -1; - - /* free all chains */ - list_for_each_safe(cur_item, item2, (*h)->chains.next) { - struct chain_head *chead = list_entry(cur_item, - struct chain_head, - list); - chainh_free(chead); - } - - /* FIXME: free all other ressources we might be using */ - - free(*h); - *h = NULL; -} - -static inline int -print_match(const STRUCT_ENTRY_MATCH *m) -{ - printf("Match name: `%s'\n", m->u.user.name); - return 0; -} - -static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle); - -#if 0 -void -TC_DUMP_ENTRIES(const TC_HANDLE_T handle) -{ - CHECK(handle); - - printf("libiptc v%s. %u entries, %u bytes.\n", - IPTABLES_VERSION, - handle->new_number, handle->entries.size); - printf("Table `%s'\n", handle->info.name); - printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", - handle->info.hook_entry[HOOK_PRE_ROUTING], - handle->info.hook_entry[HOOK_LOCAL_IN], - handle->info.hook_entry[HOOK_FORWARD], - handle->info.hook_entry[HOOK_LOCAL_OUT], - handle->info.hook_entry[HOOK_POST_ROUTING]); - printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", - handle->info.underflow[HOOK_PRE_ROUTING], - handle->info.underflow[HOOK_LOCAL_IN], - handle->info.underflow[HOOK_FORWARD], - handle->info.underflow[HOOK_LOCAL_OUT], - handle->info.underflow[HOOK_POST_ROUTING]); - - ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size, - dump_entry, handle); -} - -/* Returns 0 if not hook entry, else hooknumber + 1 */ -static inline unsigned int -is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) -{ - unsigned int i; - - for (i = 0; i < NUMHOOKS; i++) { - if ((h->info.valid_hooks & (1 << i)) - && get_entry(h, h->info.hook_entry[i]) == e) - return i+1; - } - return 0; -} - - -static int alphasort(const void *a, const void *b) -{ - return strcmp(((struct chain_cache *)a)->name, - ((struct chain_cache *)b)->name); -} -#endif - -/* Returns chain head if found, otherwise NULL. */ -static struct chain_head * -find_label(const char *name, TC_HANDLE_T handle) -{ - struct list_head *pos; - - if (list_empty(&handle->chains)) - return NULL; - - list_for_each(pos, &handle->chains) { - struct chain_head *c = list_entry(pos, struct chain_head, list); - if (!strcmp(c->name, name)) - return c; - } - - return NULL; -} - -/* Does this chain exist? */ -int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) -{ - return find_label(chain, handle) != NULL; -} - -#if 0 -/* Returns the position of the final (ie. unconditional) element. */ -static unsigned int -get_chain_end(const TC_HANDLE_T handle, unsigned int start) -{ - unsigned int last_off, off; - STRUCT_ENTRY *e; - - last_off = start; - e = get_entry(handle, start); - - /* Terminate when we meet a error label or a hook entry. */ - for (off = start + e->next_offset; - off < handle->entries.size; - last_off = off, off += e->next_offset) { - STRUCT_ENTRY_TARGET *t; - unsigned int i; - - e = get_entry(handle, off); - - /* We hit an entry point. */ - for (i = 0; i < NUMHOOKS; i++) { - if ((handle->info.valid_hooks & (1 << i)) - && off == handle->info.hook_entry[i]) - return last_off; - } - - /* We hit a user chain label */ - t = GET_TARGET(e); - if (strcmp(t->u.user.name, ERROR_TARGET) == 0) - return last_off; - } - /* SHOULD NEVER HAPPEN */ - fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n", - handle->entries.size, off); - abort(); -} -#endif - -/* Iterator functions to run through the chains. */ -const char * -TC_FIRST_CHAIN(TC_HANDLE_T *handle) -{ - struct chain_head *firsthead = list_entry((*handle)->chains.next, - struct chain_head, list); - (*handle)->chain_iterator_cur = firsthead; - - return firsthead->name; -} - -/* Iterator functions to run through the chains. Returns NULL at end. */ -const char * -TC_NEXT_CHAIN(TC_HANDLE_T *handle) -{ - struct chain_head *next = list_entry(&(*handle)->chain_iterator_cur->list.next, struct chain_head, list); - (*handle)->chain_iterator_cur = next; - - if (&next->list == &(*handle)->chains) - return NULL; - - return next->name; -} - -/* Get first rule in the given chain: NULL for empty chain. */ -const STRUCT_ENTRY * -TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle) -{ - struct chain_head *c; - struct rule_head *r; - - c = find_label(chain, *handle); - if (!c) { - errno = ENOENT; - return NULL; - } - - /* Empty chain: single return/policy rule */ - if (list_empty(&c->rules)) - return NULL; - - r = list_entry(c->rules.next, struct rule_head, list); - (*handle)->rule_iterator_cur = r; - - return r->entry; -} - -/* Returns NULL when rules run out. */ -const STRUCT_ENTRY * -TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) -{ - struct rule_head *r = list_entry((*handle)->rule_iterator_cur->list.next, struct rule_head, list); - - if (&r->list == &r->chain->rules) - return NULL; - - /* NOTE: prev is without any influence ! */ - return r->entry; -} - -#if 0 -/* How many rules in this chain? */ -unsigned int -TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle) -{ - unsigned int off = 0; - STRUCT_ENTRY *start, *end; - - CHECK(*handle); - if (!find_label(&off, chain, *handle)) { - errno = ENOENT; - return (unsigned int)-1; - } - - start = get_entry(*handle, off); - end = get_entry(*handle, get_chain_end(*handle, off)); - - return entry2index(*handle, end) - entry2index(*handle, start); -} - -/* Get n'th rule in this chain. */ -const STRUCT_ENTRY *TC_GET_RULE(const char *chain, - unsigned int n, - TC_HANDLE_T *handle) -{ - unsigned int pos = 0, chainindex; - - CHECK(*handle); - if (!find_label(&pos, chain, *handle)) { - errno = ENOENT; - return NULL; - } - - chainindex = entry2index(*handle, get_entry(*handle, pos)); - - return index2entry(*handle, chainindex + n); -} -#endif - -static const char * -target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce) -{ - int spos; - unsigned int labelidx; - STRUCT_ENTRY *jumpto; - - /* To avoid const warnings */ - STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; - - if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0) - return GET_TARGET(e)->u.user.name; - - /* Standard target: evaluate */ - spos = *(int *)GET_TARGET(e)->data; - if (spos < 0) { - if (spos == RETURN) - return LABEL_RETURN; - else if (spos == -NF_ACCEPT-1) - return LABEL_ACCEPT; - else if (spos == -NF_DROP-1) - return LABEL_DROP; - else if (spos == -NF_QUEUE-1) - return LABEL_QUEUE; - - fprintf(stderr, "ERROR: off %lu/%u not a valid target (%d)\n", - entry2offset(handle, e), handle->entries.size, - spos); - abort(); - } - - jumpto = get_entry(handle, spos); - - /* Fall through rule */ - if (jumpto == (void *)e + e->next_offset) - return ""; - - /* Must point to head of a chain: ie. after error rule */ - /* FIXME: this needs to deal with internal jump targets */ - labelidx = entry2index(handle, jumpto) - 1; - return get_errorlabel(handle, index2offset(handle, labelidx)); -} - -/* Returns a pointer to the target name of this position. */ -const char *TC_GET_TARGET(const STRUCT_ENTRY *e, - TC_HANDLE_T *handle) -{ - return target_name(*handle, e); -} - -/* Is this a built-in chain? Actually returns hook + 1. */ -int -TC_BUILTIN(const char *chain, const TC_HANDLE_T handle) -{ - unsigned int i; - - for (i = 0; i < NUMHOOKS; i++) { - if ((handle->info.valid_hooks & (1 << i)) - && handle->hooknames[i] - && strcmp(handle->hooknames[i], chain) == 0) - return i+1; - } - return 0; -} - -/* Get the policy of a given built-in chain */ -const char * -TC_GET_POLICY(const char *chain, - STRUCT_COUNTERS *counters, - TC_HANDLE_T *handle) -{ - unsigned int start; - STRUCT_ENTRY *e; - int hook; - - hook = TC_BUILTIN(chain, *handle); - if (hook != 0) - start = (*handle)->info.hook_entry[hook-1]; - else - return NULL; - - e = get_entry(*handle, get_chain_end(*handle, start)); - *counters = e->counters; - - return target_name(*handle, e); -} - -static int -correct_verdict(STRUCT_ENTRY *e, - char *base, - unsigned int offset, int delta_offset) -{ - STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e); - unsigned int curr = (char *)e - base; - - /* Trap: insert of fall-through rule. Don't change fall-through - verdict to jump-over-next-rule. */ - if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0 - && t->verdict > (int)offset - && !(curr == offset && - t->verdict == curr + e->next_offset)) { - t->verdict += delta_offset; - } - - return 0; -} - -/* Adjusts standard verdict jump positions after an insertion/deletion. */ -static int -set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle) -{ - ENTRY_ITERATE((*handle)->entries.entrytable, - (*handle)->entries.size, - correct_verdict, (char *)(*handle)->entries.entrytable, - offset, delta_offset); - - set_changed(*handle); - return 1; -} - -/* If prepend is set, then we are prepending to a chain: if the - * insertion position is an entry point, keep the entry point. */ -static int -insert_rules(unsigned int num_rules, unsigned int rules_size, - const STRUCT_ENTRY *insert, - unsigned int offset, unsigned int num_rules_offset, - int prepend, - TC_HANDLE_T *handle) -{ - TC_HANDLE_T newh; - STRUCT_GETINFO newinfo; - unsigned int i; - - if (offset >= (*handle)->entries.size) { - errno = EINVAL; - return 0; - } - - newinfo = (*handle)->info; - - /* Fix up entry points. */ - for (i = 0; i < NUMHOOKS; i++) { - /* Entry points to START of chain, so keep same if - inserting on at that point. */ - if ((*handle)->info.hook_entry[i] > offset) - newinfo.hook_entry[i] += rules_size; - - /* Underflow always points to END of chain (policy), - so if something is inserted at same point, it - should be advanced. */ - if ((*handle)->info.underflow[i] >= offset) - newinfo.underflow[i] += rules_size; - } - - newh = alloc_handle((*handle)->info.name, - (*handle)->entries.size + rules_size, - (*handle)->new_number + num_rules); - if (!newh) - return 0; - newh->info = newinfo; - - /* Copy pre... */ - memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset); - /* ... Insert new ... */ - memcpy((char *)newh->entries.entrytable + offset, insert, rules_size); - /* ... copy post */ - memcpy((char *)newh->entries.entrytable + offset + rules_size, - (char *)(*handle)->entries.entrytable + offset, - (*handle)->entries.size - offset); - - /* Move counter map. */ - /* Copy pre... */ - memcpy(newh->counter_map, (*handle)->counter_map, - sizeof(struct counter_map) * num_rules_offset); - /* ... copy post */ - memcpy(newh->counter_map + num_rules_offset + num_rules, - (*handle)->counter_map + num_rules_offset, - sizeof(struct counter_map) * ((*handle)->new_number - - num_rules_offset)); - /* Set intermediates to no counter copy */ - for (i = 0; i < num_rules; i++) - newh->counter_map[num_rules_offset+i] - = ((struct counter_map){ COUNTER_MAP_SET, 0 }); - - newh->new_number = (*handle)->new_number + num_rules; - newh->entries.size = (*handle)->entries.size + rules_size; - newh->hooknames = (*handle)->hooknames; - - if ((*handle)->cache_chain_heads) - free((*handle)->cache_chain_heads); - free(*handle); - *handle = newh; - - return set_verdict(offset, rules_size, handle); -} - -static int -delete_rules(unsigned int num_rules, unsigned int rules_size, - unsigned int offset, unsigned int num_rules_offset, - TC_HANDLE_T *handle) -{ - unsigned int i; - - if (offset + rules_size > (*handle)->entries.size) { - errno = EINVAL; - return 0; - } - - /* Fix up entry points. */ - for (i = 0; i < NUMHOOKS; i++) { - /* In practice, we never delete up to a hook entry, - since the built-in chains are always first, - so these two are never equal */ - if ((*handle)->info.hook_entry[i] >= offset + rules_size) - (*handle)->info.hook_entry[i] -= rules_size; - else if ((*handle)->info.hook_entry[i] > offset) { - fprintf(stderr, "ERROR: Deleting entry %u %u %u\n", - i, (*handle)->info.hook_entry[i], offset); - abort(); - } - - /* Underflow points to policy (terminal) rule in - built-in, so sequality is valid here (when deleting - the last rule). */ - if ((*handle)->info.underflow[i] >= offset + rules_size) - (*handle)->info.underflow[i] -= rules_size; - else if ((*handle)->info.underflow[i] > offset) { - fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n", - i, (*handle)->info.underflow[i], offset); - abort(); - } - } - - /* Move the rules down. */ - memmove((char *)(*handle)->entries.entrytable + offset, - (char *)(*handle)->entries.entrytable + offset + rules_size, - (*handle)->entries.size - (offset + rules_size)); - - /* Move the counter map down. */ - memmove(&(*handle)->counter_map[num_rules_offset], - &(*handle)->counter_map[num_rules_offset + num_rules], - sizeof(struct counter_map) - * ((*handle)->new_number - (num_rules + num_rules_offset))); - - /* Fix numbers */ - (*handle)->new_number -= num_rules; - (*handle)->entries.size -= rules_size; - - return set_verdict(offset, -(int)rules_size, handle); -} - -static int -standard_map(STRUCT_ENTRY *e, int verdict) -{ - STRUCT_STANDARD_TARGET *t; - - t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); - - if (t->target.u.target_size - != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { - errno = EINVAL; - return 0; - } - /* memset for memcmp convenience on delete/replace */ - memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); - strcpy(t->target.u.user.name, STANDARD_TARGET); - t->verdict = verdict; - - return 1; -} - -static int -map_target(const TC_HANDLE_T handle, - STRUCT_ENTRY *e, - unsigned int offset, - STRUCT_ENTRY_TARGET *old) -{ - STRUCT_ENTRY_TARGET *t = GET_TARGET(e); - - /* Save old target (except data, which we don't change, except for - standard case, where we don't care). */ - *old = *t; - - /* Maybe it's empty (=> fall through) */ - if (strcmp(t->u.user.name, "") == 0) - return standard_map(e, offset + e->next_offset); - /* Maybe it's a standard target name... */ - else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0) - return standard_map(e, -NF_ACCEPT - 1); - else if (strcmp(t->u.user.name, LABEL_DROP) == 0) - return standard_map(e, -NF_DROP - 1); - else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0) - return standard_map(e, -NF_QUEUE - 1); - else if (strcmp(t->u.user.name, LABEL_RETURN) == 0) - return standard_map(e, RETURN); - else if (TC_BUILTIN(t->u.user.name, handle)) { - /* Can't jump to builtins. */ - errno = EINVAL; - return 0; - } else { - /* Maybe it's an existing chain name. */ - struct chain_cache *c; - - c = find_label(t->u.user.name, handle); - if (c) - return standard_map(e, c->start_off); - } - - /* Must be a module? If not, kernel will reject... */ - /* memset to all 0 for your memcmp convenience. */ - memset(t->u.user.name + strlen(t->u.user.name), - 0, - FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); - return 1; -} - -static void -unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old) -{ - STRUCT_ENTRY_TARGET *t = GET_TARGET(e); - - /* Save old target (except data, which we don't change, except for - standard case, where we don't care). */ - *t = *old; -} - -/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ -int -TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, - const STRUCT_ENTRY *e, - unsigned int rulenum, - TC_HANDLE_T *handle) -{ - unsigned int chainindex, offset; - STRUCT_ENTRY_TARGET old; - struct chain_cache *c; - STRUCT_ENTRY *tmp; - int ret; - - iptc_fn = TC_INSERT_ENTRY; - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - chainindex = offset2index(*handle, c->start_off); - - tmp = index2entry(*handle, chainindex + rulenum); - if (!tmp || tmp > offset2entry(*handle, c->end_off)) { - errno = E2BIG; - return 0; - } - offset = index2offset(*handle, chainindex + rulenum); - - /* Mapping target actually alters entry, but that's - transparent to the caller. */ - if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) - return 0; - - ret = insert_rules(1, e->next_offset, e, offset, - chainindex + rulenum, rulenum == 0, handle); - unmap_target((STRUCT_ENTRY *)e, &old); - return ret; -} - -/* Atomically replace rule `rulenum' in `chain' with `fw'. */ -int -TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, - const STRUCT_ENTRY *e, - unsigned int rulenum, - TC_HANDLE_T *handle) -{ - unsigned int chainindex, offset; - STRUCT_ENTRY_TARGET old; - struct chain_cache *c; - STRUCT_ENTRY *tmp; - int ret; - - iptc_fn = TC_REPLACE_ENTRY; - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - chainindex = offset2index(*handle, c->start_off); - - tmp = index2entry(*handle, chainindex + rulenum); - if (!tmp || tmp >= offset2entry(*handle, c->end_off)) { - errno = E2BIG; - return 0; - } - - offset = index2offset(*handle, chainindex + rulenum); - /* Replace = delete and insert. */ - if (!delete_rules(1, get_entry(*handle, offset)->next_offset, - offset, chainindex + rulenum, handle)) - return 0; - - if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) - return 0; - - ret = insert_rules(1, e->next_offset, e, offset, - chainindex + rulenum, 1, handle); - unmap_target((STRUCT_ENTRY *)e, &old); - return ret; -} - -/* Append entry `fw' to chain `chain'. Equivalent to insert with - rulenum = length of chain. */ -int -TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, - const STRUCT_ENTRY *e, - TC_HANDLE_T *handle) -{ - struct chain_cache *c; - STRUCT_ENTRY_TARGET old; - int ret; - - iptc_fn = TC_APPEND_ENTRY; - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - if (!map_target(*handle, (STRUCT_ENTRY *)e, - c->end_off, &old)) - return 0; - - ret = insert_rules(1, e->next_offset, e, c->end_off, - offset2index(*handle, c->end_off), 0, handle); - unmap_target((STRUCT_ENTRY *)e, &old); - return ret; -} - -static inline int -match_different(const STRUCT_ENTRY_MATCH *a, - const unsigned char *a_elems, - const unsigned char *b_elems, - unsigned char **maskptr) -{ - const STRUCT_ENTRY_MATCH *b; - unsigned int i; - - /* Offset of b is the same as a. */ - b = (void *)b_elems + ((unsigned char *)a - a_elems); - - if (a->u.match_size != b->u.match_size) - return 1; - - if (strcmp(a->u.user.name, b->u.user.name) != 0) - return 1; - - *maskptr += ALIGN(sizeof(*a)); - - for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++) - if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) - return 1; - *maskptr += i; - return 0; -} - -static inline int -target_different(const unsigned char *a_targdata, - const unsigned char *b_targdata, - unsigned int tdatasize, - const unsigned char *mask) -{ - unsigned int i; - for (i = 0; i < tdatasize; i++) - if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0) - return 1; - - return 0; -} - -static int -is_same(const STRUCT_ENTRY *a, - const STRUCT_ENTRY *b, - unsigned char *matchmask); - -/* Delete the first rule in `chain' which matches `fw'. */ -int -TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, - const STRUCT_ENTRY *origfw, - unsigned char *matchmask, - TC_HANDLE_T *handle) -{ - unsigned int offset; - struct chain_cache *c; - STRUCT_ENTRY *e, *fw; - - iptc_fn = TC_DELETE_ENTRY; - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - fw = malloc(origfw->next_offset); - if (fw == NULL) { - errno = ENOMEM; - return 0; - } - - for (offset = c->start_off; offset < c->end_off; - offset += e->next_offset) { - STRUCT_ENTRY_TARGET discard; - - memcpy(fw, origfw, origfw->next_offset); - - /* FIXME: handle this in is_same --RR */ - if (!map_target(*handle, fw, offset, &discard)) { - free(fw); - return 0; - } - e = get_entry(*handle, offset); - -#if 0 - printf("Deleting:\n"); - dump_entry(newe); -#endif - if (is_same(e, fw, matchmask)) { - int ret; - ret = delete_rules(1, e->next_offset, - offset, entry2index(*handle, e), - handle); - free(fw); - return ret; - } - } - - free(fw); - errno = ENOENT; - return 0; -} - -/* Delete the rule in position `rulenum' in `chain'. */ -int -TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, - unsigned int rulenum, - TC_HANDLE_T *handle) -{ - unsigned int index; - int ret; - STRUCT_ENTRY *e; - struct chain_cache *c; - - iptc_fn = TC_DELETE_NUM_ENTRY; - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - index = offset2index(*handle, c->start_off) + rulenum; - - if (index >= offset2index(*handle, c->end_off)) { - errno = E2BIG; - return 0; - } - - e = index2entry(*handle, index); - if (e == NULL) { - errno = EINVAL; - return 0; - } - - ret = delete_rules(1, e->next_offset, entry2offset(*handle, e), - index, handle); - return ret; -} - -/* Check the packet `fw' on chain `chain'. Returns the verdict, or - NULL and sets errno. */ -const char * -TC_CHECK_PACKET(const IPT_CHAINLABEL chain, - STRUCT_ENTRY *entry, - TC_HANDLE_T *handle) -{ - errno = ENOSYS; - return NULL; -} - -/* Flushes the entries in the given chain (ie. empties chain). */ -int -TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) -{ - unsigned int startindex, endindex; - STRUCT_ENTRY *startentry, *endentry; - struct chain_cache *c; - int ret; - - iptc_fn = TC_FLUSH_ENTRIES; - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - startindex = offset2index(*handle, c->start_off); - endindex = offset2index(*handle, c->end_off); - startentry = offset2entry(*handle, c->start_off); - endentry = offset2entry(*handle, c->end_off); - - ret = delete_rules(endindex - startindex, - (char *)endentry - (char *)startentry, - c->start_off, startindex, - handle); - return ret; -} - -/* Zeroes the counters in a chain. */ -int -TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) -{ - unsigned int i, end; - struct chain_cache *c; - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - i = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - for (; i <= end; i++) { - if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP) - (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED; - } - set_changed(*handle); - - return 1; -} - -STRUCT_COUNTERS * -TC_READ_COUNTER(const IPT_CHAINLABEL chain, - unsigned int rulenum, - TC_HANDLE_T *handle) -{ - STRUCT_ENTRY *e; - struct chain_cache *c; - unsigned int chainindex, end; - - iptc_fn = TC_READ_COUNTER; - CHECK(*handle); - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return NULL; - } - - chainindex = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - if (chainindex + rulenum > end) { - errno = E2BIG; - return NULL; - } - - e = index2entry(*handle, chainindex + rulenum); - - return &e->counters; -} - -int -TC_ZERO_COUNTER(const IPT_CHAINLABEL chain, - unsigned int rulenum, - TC_HANDLE_T *handle) -{ - STRUCT_ENTRY *e; - struct chain_cache *c; - unsigned int chainindex, end; - - iptc_fn = TC_ZERO_COUNTER; - CHECK(*handle); - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - chainindex = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - if (chainindex + rulenum > end) { - errno = E2BIG; - return 0; - } - - e = index2entry(*handle, chainindex + rulenum); - - if ((*handle)->counter_map[chainindex + rulenum].maptype - == COUNTER_MAP_NORMAL_MAP) { - (*handle)->counter_map[chainindex + rulenum].maptype - = COUNTER_MAP_ZEROED; - } - - set_changed(*handle); - - return 1; -} - -int -TC_SET_COUNTER(const IPT_CHAINLABEL chain, - unsigned int rulenum, - STRUCT_COUNTERS *counters, - TC_HANDLE_T *handle) -{ - STRUCT_ENTRY *e; - struct chain_cache *c; - unsigned int chainindex, end; - - iptc_fn = TC_SET_COUNTER; - CHECK(*handle); - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - chainindex = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - if (chainindex + rulenum > end) { - errno = E2BIG; - return 0; - } - - e = index2entry(*handle, chainindex + rulenum); - - (*handle)->counter_map[chainindex + rulenum].maptype - = COUNTER_MAP_SET; - - memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); - - set_changed(*handle); - - return 1; -} - -/* Creates a new chain. */ -/* To create a chain, create two rules: error node and unconditional - * return. */ -int -TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) -{ - int ret; - struct chainstart { - STRUCT_ENTRY head; - struct ipt_error_target name; - } *newc1; - struct chainend { - STRUCT_ENTRY ret; - STRUCT_STANDARD_TARGET target; - } *newc2; - struct chain_head *chead; - - iptc_fn = TC_CREATE_CHAIN; - - /* find_label doesn't cover built-in targets: DROP, ACCEPT, - QUEUE, RETURN. */ - if (find_label(chain, *handle) - || strcmp(chain, LABEL_DROP) == 0 - || strcmp(chain, LABEL_ACCEPT) == 0 - || strcmp(chain, LABEL_QUEUE) == 0 - || strcmp(chain, LABEL_RETURN) == 0) { - errno = EEXIST; - return 0; - } - - if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { - errno = EINVAL; - return 0; - } - - chead = chainh_alloc(*handle, chain); - if (!chead) { - errno = ENOMEM; - return 0; - } - - newc1 = ruleh_alloc(sizeof(*newc1)); - if (!newc1) { - chainh_free(chead); - return 0; - } - - newc2 = ruleh_alloc(sizeof(*newc2)); - if (!newc2) { - chainh_free(chead); - ruleh_free(newc1); - return 0; - } - - newc1->head.target_offset = sizeof(STRUCT_ENTRY); - newc1->head.next_offset - = sizeof(STRUCT_ENTRY) - + ALIGN(sizeof(struct ipt_error_target)); - strcpy(newc1->name.t.u.user.name, ERROR_TARGET); - newc1->name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target)); - strcpy(newc1->name.error, chain); - - newc2->ret.target_offset = sizeof(STRUCT_ENTRY); - newc2->ret.next_offset - = sizeof(STRUCT_ENTRY) - + ALIGN(sizeof(STRUCT_STANDARD_TARGET)); - strcpy(newc2->target.target.u.user.name, STANDARD_TARGET); - newc->target.target.u.target_size - = ALIGN(sizeof(STRUCT_STANDARD_TARGET)); - newc->target.verdict = RETURN; - - list_prepend(newc1, &chead->rules); - list_append(newc2, &chead->rules); - - return 1; -} - -static int -count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref) -{ - STRUCT_STANDARD_TARGET *t; - - if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) { - t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); - - if (t->verdict == offset) - (*ref)++; - } - - return 0; -} - -/* Get the number of references to this chain. */ -int -TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, - TC_HANDLE_T *handle) -{ - struct chain_cache *c; - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - *ref = 0; - ENTRY_ITERATE((*handle)->entries.entrytable, - (*handle)->entries.size, - count_ref, c->start_off, ref); - return 1; -} - -/* Deletes a chain. */ -int -TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) -{ - unsigned int labelidx, labeloff; - unsigned int references; - struct chain_cache *c; - int ret; - STRUCT_ENTRY *start; - - if (!TC_GET_REFERENCES(&references, chain, handle)) - return 0; - - iptc_fn = TC_DELETE_CHAIN; - - if (TC_BUILTIN(chain, *handle)) { - errno = EINVAL; - return 0; - } - - if (references > 0) { - errno = EMLINK; - return 0; - } - - if (!(c = find_label(chain, *handle))) { - errno = ENOENT; - return 0; - } - - if (c->start_off != c->end_off) { - errno = ENOTEMPTY; - return 0; - } - - /* Need label index: preceeds chain start */ - labelidx = offset2index(*handle, c->start_off) - 1; - labeloff = index2offset(*handle, labelidx); - - start = offset2entry(*handle, c->start_off); - - ret = delete_rules(2, - get_entry(*handle, labeloff)->next_offset - + start->next_offset, - labeloff, labelidx, handle); - return ret; -} - -/* Renames a chain. */ -int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, - const IPT_CHAINLABEL newname, - TC_HANDLE_T *handle) -{ - unsigned int labeloff, labelidx; - struct chain_cache *c; - struct ipt_error_target *t; - - iptc_fn = TC_RENAME_CHAIN; - - /* find_label doesn't cover built-in targets: DROP, ACCEPT, - QUEUE, RETURN. */ - if (find_label(newname, *handle) - || strcmp(newname, LABEL_DROP) == 0 - || strcmp(newname, LABEL_ACCEPT) == 0 - || strcmp(newname, LABEL_QUEUE) == 0 - || strcmp(newname, LABEL_RETURN) == 0) { - errno = EEXIST; - return 0; - } - - if (!(c = find_label(oldname, *handle)) - || TC_BUILTIN(oldname, *handle)) { - errno = ENOENT; - return 0; - } - - if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) { - errno = EINVAL; - return 0; - } - - /* Need label index: preceeds chain start */ - labelidx = offset2index(*handle, c->start_off) - 1; - labeloff = index2offset(*handle, labelidx); - - t = (struct ipt_error_target *) - GET_TARGET(get_entry(*handle, labeloff)); - - memset(t->error, 0, sizeof(t->error)); - strcpy(t->error, newname); - set_changed(*handle); - - return 1; -} - -/* Sets the policy on a built-in chain. */ -int -TC_SET_POLICY(const IPT_CHAINLABEL chain, - const IPT_CHAINLABEL policy, - STRUCT_COUNTERS *counters, - TC_HANDLE_T *handle) -{ - unsigned int hook; - unsigned int policyoff, ctrindex; - STRUCT_ENTRY *e; - STRUCT_STANDARD_TARGET *t; - - iptc_fn = TC_SET_POLICY; - /* Figure out which chain. */ - hook = TC_BUILTIN(chain, *handle); - if (hook == 0) { - errno = ENOENT; - return 0; - } else - hook--; - - policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]); - if (policyoff != (*handle)->info.underflow[hook]) { - printf("ERROR: Policy for `%s' offset %u != underflow %u\n", - chain, policyoff, (*handle)->info.underflow[hook]); - return 0; - } - - e = get_entry(*handle, policyoff); - t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); - - if (strcmp(policy, LABEL_ACCEPT) == 0) - t->verdict = -NF_ACCEPT - 1; - else if (strcmp(policy, LABEL_DROP) == 0) - t->verdict = -NF_DROP - 1; - else { - errno = EINVAL; - return 0; - } - - ctrindex = entry2index(*handle, e); - - if (counters) { - /* set byte and packet counters */ - memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); - - (*handle)->counter_map[ctrindex].maptype - = COUNTER_MAP_SET; - - } else { - (*handle)->counter_map[ctrindex] - = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); - } - - set_changed(*handle); - - return 1; -} - -/* Without this, on gcc 2.7.2.3, we get: - libiptc.c: In function `TC_COMMIT': - libiptc.c:833: fixed or forbidden register was spilled. - This may be due to a compiler bug or to impossible asm - statements or clauses. -*/ -static void -subtract_counters(STRUCT_COUNTERS *answer, - const STRUCT_COUNTERS *a, - const STRUCT_COUNTERS *b) -{ - answer->pcnt = a->pcnt - b->pcnt; - answer->bcnt = a->bcnt - b->bcnt; -} - -int -TC_COMMIT(TC_HANDLE_T *handle) -{ - /* Replace, then map back the counters. */ - STRUCT_REPLACE *repl; - STRUCT_COUNTERS_INFO *newcounters; - unsigned int i; - size_t counterlen; - - CHECK(*handle); - - counterlen = sizeof(STRUCT_COUNTERS_INFO) - + sizeof(STRUCT_COUNTERS) * (*handle)->new_number; - -#if 0 - TC_DUMP_ENTRIES(*handle); -#endif - - /* Don't commit if nothing changed. */ - if (!(*handle)->changed) - goto finished; - - repl = malloc(sizeof(*repl) + (*handle)->entries.size); - if (!repl) { - errno = ENOMEM; - return 0; - } - - /* These are the old counters we will get from kernel */ - repl->counters = malloc(sizeof(STRUCT_COUNTERS) - * (*handle)->info.num_entries); - if (!repl->counters) { - free(repl); - errno = ENOMEM; - return 0; - } - - /* These are the counters we're going to put back, later. */ - newcounters = malloc(counterlen); - if (!newcounters) { - free(repl->counters); - free(repl); - errno = ENOMEM; - return 0; - } - - strcpy(repl->name, (*handle)->info.name); - repl->num_entries = (*handle)->new_number; - repl->size = (*handle)->entries.size; - memcpy(repl->hook_entry, (*handle)->info.hook_entry, - sizeof(repl->hook_entry)); - memcpy(repl->underflow, (*handle)->info.underflow, - sizeof(repl->underflow)); - repl->num_counters = (*handle)->info.num_entries; - repl->valid_hooks = (*handle)->info.valid_hooks; - memcpy(repl->entries, (*handle)->entries.entrytable, - (*handle)->entries.size); - - if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, - sizeof(*repl) + (*handle)->entries.size) < 0) { - free(repl->counters); - free(repl); - free(newcounters); - return 0; - } - - /* Put counters back. */ - strcpy(newcounters->name, (*handle)->info.name); - newcounters->num_counters = (*handle)->new_number; - for (i = 0; i < (*handle)->new_number; i++) { - unsigned int mappos = (*handle)->counter_map[i].mappos; - switch ((*handle)->counter_map[i].maptype) { - case COUNTER_MAP_NOMAP: - newcounters->counters[i] - = ((STRUCT_COUNTERS){ 0, 0 }); - break; - - case COUNTER_MAP_NORMAL_MAP: - /* Original read: X. - * Atomic read on replacement: X + Y. - * Currently in kernel: Z. - * Want in kernel: X + Y + Z. - * => Add in X + Y - * => Add in replacement read. - */ - newcounters->counters[i] = repl->counters[mappos]; - break; - - case COUNTER_MAP_ZEROED: - /* Original read: X. - * Atomic read on replacement: X + Y. - * Currently in kernel: Z. - * Want in kernel: Y + Z. - * => Add in Y. - * => Add in (replacement read - original read). - */ - subtract_counters(&newcounters->counters[i], - &repl->counters[mappos], - &index2entry(*handle, i)->counters); - break; - - case COUNTER_MAP_SET: - /* Want to set counter (iptables-restore) */ - - memcpy(&newcounters->counters[i], - &index2entry(*handle, i)->counters, - sizeof(STRUCT_COUNTERS)); - - break; - } - } - -#ifdef KERNEL_64_USERSPACE_32 - { - /* Kernel will think that pointer should be 64-bits, and get - padding. So we accomodate here (assumption: alignment of - `counters' is on 64-bit boundary). */ - u_int64_t *kernptr = (u_int64_t *)&newcounters->counters; - if ((unsigned long)&newcounters->counters % 8 != 0) { - fprintf(stderr, - "counters alignment incorrect! Mail rusty!\n"); - abort(); - } - *kernptr = newcounters->counters; - } -#endif /* KERNEL_64_USERSPACE_32 */ - - if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, - newcounters, counterlen) < 0) { - free(repl->counters); - free(repl); - free(newcounters); - return 0; - } - - free(repl->counters); - free(repl); - free(newcounters); - - finished: - TC_FREE(handle); - return 1; -} - -/* Get raw socket. */ -int -TC_GET_RAW_SOCKET() -{ - return sockfd; -} - -/* Translates errno numbers into more human-readable form than strerror. */ -const char * -TC_STRERROR(int err) -{ - unsigned int i; - struct table_struct { - void *fn; - int err; - const char *message; - } table [] = - { { TC_INIT, EPERM, "Permission denied (you must be root)" }, - { TC_INIT, EINVAL, "Module is wrong version" }, - { TC_INIT, ENOENT, - "Table does not exist (do you need to insmod?)" }, - { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" }, - { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" }, - { TC_DELETE_CHAIN, EMLINK, - "Can't delete chain with references left" }, - { TC_CREATE_CHAIN, EEXIST, "Chain already exists" }, - { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" }, - { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" }, - { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" }, - { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, - { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, - { TC_INSERT_ENTRY, ELOOP, "Loop found in table" }, - { TC_INSERT_ENTRY, EINVAL, "Target problem" }, - /* EINVAL for CHECK probably means bad interface. */ - { TC_CHECK_PACKET, EINVAL, - "Bad arguments (does that interface exist?)" }, - { TC_CHECK_PACKET, ENOSYS, - "Checking will most likely never get implemented" }, - /* ENOENT for DELETE probably means no matching rule */ - { TC_DELETE_ENTRY, ENOENT, - "Bad rule (does a matching rule exist in that chain?)" }, - { TC_SET_POLICY, ENOENT, - "Bad built-in chain name" }, - { TC_SET_POLICY, EINVAL, - "Bad policy name" }, - - { NULL, 0, "Incompatible with this kernel" }, - { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, - { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" }, - { NULL, ENOMEM, "Memory allocation problem" }, - { NULL, ENOENT, "No chain/target/match by that name" }, - }; - - for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { - if ((!table[i].fn || table[i].fn == iptc_fn) - && table[i].err == err) - return table[i].message; - } - - return strerror(err); -}