From 79dee0702b18c8ea1d1f7a2b1f6b29349466986b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 2 May 2000 16:45:16 +0000 Subject: IPv6 enhancements. --- include/ip6tables.h | 107 ++++++ include/iptables.h | 28 +- include/iptables_common.h | 18 + include/libiptc/libip6tc.h | 133 +++++++ libiptc/Makefile | 3 +- libiptc/libip4tc.c | 444 +++++++++++++++++++++++ libiptc/libip6tc.c | 264 ++++++++++++++ libiptc/libiptc.c | 883 ++++++++++++++------------------------------- 8 files changed, 1246 insertions(+), 634 deletions(-) create mode 100644 include/ip6tables.h create mode 100644 include/iptables_common.h create mode 100644 include/libiptc/libip6tc.h create mode 100644 libiptc/libip4tc.c create mode 100644 libiptc/libip6tc.c diff --git a/include/ip6tables.h b/include/ip6tables.h new file mode 100644 index 00000000..7acf800b --- /dev/null +++ b/include/ip6tables.h @@ -0,0 +1,107 @@ +#ifndef _IP6TABLES_USER_H +#define _IP6TABLES_USER_H + +#include "iptables_common.h" +#include "libiptc/libip6tc.h" + +/* Include file for additions: new matches and targets. */ +struct ip6tables_match +{ + struct ip6tables_match *next; + + ip6t_chainlabel name; + + const char *version; + + /* Size of match data. */ + size_t size; + + /* Function which prints out usage message. */ + void (*help)(void); + + /* Initialize the match. */ + void (*init)(struct ip6t_entry_match *m, unsigned int *nfcache); + + /* Function which parses command options; returns true if it + ate an option */ + int (*parse)(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match); + + /* Final check; exit if not ok. */ + void (*final_check)(unsigned int flags); + + /* Prints out the match iff non-NULL: put space at end */ + void (*print)(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, int numeric); + + /* Saves the union ipt_matchinfo in parsable form to stdout. */ + void (*save)(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match); + + /* Pointer to list of extra command-line options */ + struct option *extra_opts; + + /* Ignore these men behind the curtain: */ + unsigned int option_offset; + struct ip6t_entry_match *m; + unsigned int mflags; +}; + +struct ip6tables_target +{ + struct ip6tables_target *next; + + ip6t_chainlabel name; + + const char *version; + + /* Size of target data. */ + size_t size; + + /* Function which prints out usage message. */ + void (*help)(void); + + /* Initialize the target. */ + void (*init)(struct ip6t_entry_target *t, unsigned int *nfcache); + + /* Function which parses command options; returns true if it + ate an option */ + int (*parse)(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + struct ip6t_entry_target **target); + + /* Final check; exit if not ok. */ + void (*final_check)(unsigned int flags); + + /* Prints out the target iff non-NULL: put space at end */ + void (*print)(const struct ip6t_ip6 *ip, + const struct ip6t_entry_target *target, int numeric); + + /* Saves the targinfo in parsable form to stdout. */ + void (*save)(const struct ip6t_ip6 *ip, + const struct ip6t_entry_target *target); + + /* Pointer to list of extra command-line options */ + struct option *extra_opts; + + /* Ignore these men behind the curtain: */ + unsigned int option_offset; + struct ip6t_entry_target *t; + unsigned int tflags; +}; + +/* Your shared library should call one of these. */ +extern void register_match6(struct ip6tables_match *me); +extern void register_target6(struct ip6tables_target *me); + +extern int do_command6(int argc, char *argv[], char **table, + ip6tc_handle_t *handle); +/* Keeping track of external matches and targets: linked lists. */ +extern struct ip6tables_match *ip6tables_matches; +extern struct ip6tables_target *ip6tables_targets; + +extern struct ip6tables_target *find_target6(const char *name, int tryload); +extern struct ip6tables_match *find_match6(const char *name, int tryload); +#endif /*_IP6TABLES_USER_H*/ diff --git a/include/iptables.h b/include/iptables.h index 1ddd8712..886d576b 100644 --- a/include/iptables.h +++ b/include/iptables.h @@ -1,6 +1,7 @@ #ifndef _IPTABLES_USER_H #define _IPTABLES_USER_H +#include "iptables_common.h" #include "libiptc/libiptc.h" /* Include file for additions: new matches and targets. */ @@ -38,7 +39,7 @@ struct iptables_match void (*print)(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric); - /* Saves the union ipt_matchinfo in parsable form to stdout. */ + /* Saves the match info in parsable form to stdout. */ void (*save)(const struct ipt_ip *ip, const struct ipt_entry_match *match); @@ -101,21 +102,8 @@ struct iptables_target extern void register_match(struct iptables_match *me); extern void register_target(struct iptables_target *me); -/* Functions we share */ -enum exittype { - OTHER_PROBLEM = 1, - PARAMETER_PROBLEM, - VERSION_PROBLEM -}; -extern void exit_printhelp() __attribute__((noreturn)); -extern void exit_tryhelp(int) __attribute__((noreturn)); -int check_inverse(const char option[], int *invert); -extern int string_to_number(const char *, int, int); -void exit_error(enum exittype, char *, ...)__attribute__((noreturn, - format(printf,2,3))); +extern struct in_addr *dotted_to_addr(const char *dotted); extern char *addr_to_dotted(const struct in_addr *addrp); -struct in_addr *dotted_to_addr(const char *dotted); -extern const char *program_name, *program_version; extern int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle); @@ -123,6 +111,12 @@ extern int do_command(int argc, char *argv[], char **table, extern struct iptables_match *iptables_matches; extern struct iptables_target *iptables_targets; -extern struct iptables_target *find_target(const char *name, int tryload); -extern struct iptables_match *find_match(const char *name, int tryload); +enum ipt_tryload { + DONT_LOAD, + TRY_LOAD, + LOAD_MUST_SUCCEED +}; + +extern struct iptables_target *find_target(const char *name, enum ipt_tryload); +extern struct iptables_match *find_match(const char *name, enum ipt_tryload); #endif /*_IPTABLES_USER_H*/ diff --git a/include/iptables_common.h b/include/iptables_common.h new file mode 100644 index 00000000..90ca74d7 --- /dev/null +++ b/include/iptables_common.h @@ -0,0 +1,18 @@ +#ifndef _IPTABLES_COMMON_H +#define _IPTABLES_COMMON_H +/* Shared definitions between ipv4 and ipv6. */ + +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; +extern void exit_printhelp() __attribute__((noreturn)); +extern void exit_tryhelp(int) __attribute__((noreturn)); +int check_inverse(const char option[], int *invert); +extern int string_to_number(const char *, int, int); +void exit_error(enum exittype, char *, ...)__attribute__((noreturn, + format(printf,2,3))); +extern const char *program_name, *program_version; + +#endif /*_IPTABLES_COMMON_H*/ diff --git a/include/libiptc/libip6tc.h b/include/libiptc/libip6tc.h new file mode 100644 index 00000000..d0b87bdf --- /dev/null +++ b/include/libiptc/libip6tc.h @@ -0,0 +1,133 @@ +#ifndef _LIBIP6TC_H +#define _LIBIP6TC_H +/* Library which manipulates firewall rules. Version 0.2. */ + +#include +#include + +#ifndef IP6T_MIN_ALIGN +#define IP6T_MIN_ALIGN (__alignof__(struct ip6t_entry_match)) +#endif +#define IP6T_ALIGN(s) (((s) + (IP6T_MIN_ALIGN-1)) & ~(IP6T_MIN_ALIGN-1)) + +typedef char ip6t_chainlabel[32]; + +#define IP6TC_LABEL_ACCEPT "ACCEPT" +#define IP6TC_LABEL_DROP "DROP" +#define IP6TC_LABEL_RETURN "RETURN" + +/* Transparent handle type. */ +typedef struct ip6tc_handle *ip6tc_handle_t; + +/* Does this chain exist? */ +int ip6tc_is_chain(const char *chain, const ip6tc_handle_t handle); + +/* Take a snapshot of the rules. Returns NULL on error. */ +ip6tc_handle_t ip6tc_init(const char *tablename); + +/* Iterator functions to run through the chains; prev = NULL means + first chain. Returns NULL at end. */ +const char *ip6tc_next_chain(const char *prev, ip6tc_handle_t *handle); + +/* How many rules in this chain? */ +unsigned int ip6tc_num_rules(const char *chain, ip6tc_handle_t *handle); + +/* Get n'th rule in this chain. */ +const struct ip6t_entry *ip6tc_get_rule(const char *chain, + unsigned int n, + ip6tc_handle_t *handle); + +/* Returns a pointer to the target name of this position. */ +const char *ip6tc_get_target(const char *chain, + unsigned int n, + ip6tc_handle_t *handle); + +/* Is this a built-in chain? */ +int ip6tc_builtin(const char *chain, const ip6tc_handle_t handle); + +/* Get the policy of a given built-in chain */ +const char *ip6tc_get_policy(const char *chain, + struct ip6t_counters *counters, + ip6tc_handle_t *handle); + +/* These functions return TRUE for OK or 0 and set errno. If errno == + 0, it means there was a version error (ie. upgrade libiptc). */ +/* Rule numbers start at 1 for the first rule. */ + +/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ +int ip6tc_insert_entry(const ip6t_chainlabel chain, + const struct ip6t_entry *e, + unsigned int rulenum, + ip6tc_handle_t *handle); + +/* Atomically replace rule `rulenum' in `chain' with `fw'. */ +int ip6tc_replace_entry(const ip6t_chainlabel chain, + const struct ip6t_entry *e, + unsigned int rulenum, + ip6tc_handle_t *handle); + +/* Append entry `fw' to chain `chain'. Equivalent to insert with + rulenum = length of chain. */ +int ip6tc_append_entry(const ip6t_chainlabel chain, + const struct ip6t_entry *e, + ip6tc_handle_t *handle); + +/* Delete the first rule in `chain' which matches `fw'. */ +int ip6tc_delete_entry(const ip6t_chainlabel chain, + const struct ip6t_entry *origfw, + ip6tc_handle_t *handle); + +/* Delete the rule in position `rulenum' in `chain'. */ +int ip6tc_delete_num_entry(const ip6t_chainlabel chain, + unsigned int rulenum, + ip6tc_handle_t *handle); + +/* Check the packet `fw' on chain `chain'. Returns the verdict, or + NULL and sets errno. */ +const char *ip6tc_check_packet(const ip6t_chainlabel chain, + struct ip6t_entry *, + ip6tc_handle_t *handle); + +/* Flushes the entries in the given chain (ie. empties chain). */ +int ip6tc_flush_entries(const ip6t_chainlabel chain, + ip6tc_handle_t *handle); + +/* Zeroes the counters in a chain. */ +int ip6tc_zero_entries(const ip6t_chainlabel chain, + ip6tc_handle_t *handle); + +/* Creates a new chain. */ +int ip6tc_create_chain(const ip6t_chainlabel chain, + ip6tc_handle_t *handle); + +/* Deletes a chain. */ +int ip6tc_delete_chain(const ip6t_chainlabel chain, + ip6tc_handle_t *handle); + +/* Renames a chain. */ +int ip6tc_rename_chain(const ip6t_chainlabel oldname, + const ip6t_chainlabel newname, + ip6tc_handle_t *handle); + +/* Sets the policy on a built-in chain. */ +int ip6tc_set_policy(const ip6t_chainlabel chain, + const ip6t_chainlabel policy, + ip6tc_handle_t *handle); + +/* Get the number of references to this chain */ +int ip6tc_get_references(unsigned int *ref, const ip6t_chainlabel chain, + ip6tc_handle_t *handle); + +/* Makes the actual changes. */ +int ip6tc_commit(ip6tc_handle_t *handle); + +/* Get raw socket. */ +int ip6tc_get_raw_socket(); + +/* Translates errno numbers into more human-readable form than strerror. */ +const char *ip6tc_strerror(int err); + +/* Return prefix length, or -1 if not contiguous */ +int ipv6_prefix_length(const struct in6_addr *a); + +#endif /* _LIBIP6TC_H */ diff --git a/libiptc/Makefile b/libiptc/Makefile index c47669f5..7c0ff5e5 100644 --- a/libiptc/Makefile +++ b/libiptc/Makefile @@ -9,7 +9,8 @@ local: else EXTRA_DEPENDS+=libiptc/libiptc.d -libiptc/libiptc.a: libiptc/libiptc.a(libiptc/libiptc.o) +#libiptc/libiptc.a: libiptc/libiptc.a(libiptc/libip4tc.o libiptc/libip6tc.o) +libiptc/libiptc.a: libiptc/libiptc.a(libiptc/libip4tc.o) libiptc/libiptc.d: %.d: %.c @-$(CC) -M -MG $(CFLAGS) $< | sed -e 's@^.*\.o:@$*.d $*.a($*.o):@' > $@ diff --git a/libiptc/libip4tc.c b/libiptc/libip4tc.c new file mode 100644 index 00000000..10ea1be2 --- /dev/null +++ b/libiptc/libip4tc.c @@ -0,0 +1,444 @@ +/* Library which manipulates firewall rules. Version 0.1. */ + +/* 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). */ + +#include +#include +#include +#include +#include + +#ifdef DEBUG_CONNTRACK +#define inline +#endif + +#if !defined(__GLIBC__) || (__GLIBC__ < 2) +typedef unsigned int socklen_t; +#endif + +#include "libiptc/libiptc.h" + +#define IP_VERSION 4 +#define IP_OFFSET 0x1FFF + +#define HOOK_PRE_ROUTING NF_IP_PRE_ROUTING +#define HOOK_LOCAL_IN NF_IP_LOCAL_IN +#define HOOK_FORWARD NF_IP_FORWARD +#define HOOK_LOCAL_OUT NF_IP_LOCAL_OUT +#define HOOK_POST_ROUTING NF_IP_POST_ROUTING + +#define STRUCT_ENTRY_TARGET struct ipt_entry_target +#define STRUCT_ENTRY struct ipt_entry +#define STRUCT_ENTRY_MATCH struct ipt_entry_match +#define STRUCT_GETINFO struct ipt_getinfo +#define STRUCT_GET_ENTRIES struct ipt_get_entries +#define STRUCT_COUNTERS struct ipt_counters +#define STRUCT_COUNTERS_INFO struct ipt_counters_info +#define STRUCT_STANDARD_TARGET struct ipt_standard_target +#define STRUCT_REPLACE struct ipt_replace + +#define STRUCT_TC_HANDLE struct iptc_handle +#define TC_HANDLE_T iptc_handle_t + +#define ENTRY_ITERATE IPT_ENTRY_ITERATE +#define TABLE_MAXNAMELEN IPT_TABLE_MAXNAMELEN +#define FUNCTION_MAXNAMELEN IPT_FUNCTION_MAXNAMELEN + +#define GET_TARGET ipt_get_target + +#define ERROR_TARGET IPT_ERROR_TARGET +#define NUMHOOKS NF_IP_NUMHOOKS + +#define IPT_CHAINLABEL ipt_chainlabel + +#define TC_DUMP_ENTRIES dump_entries +#define TC_IS_CHAIN iptc_is_chain +#define TC_NEXT_CHAIN iptc_next_chain +#define TC_NUM_RULES iptc_num_rules +#define TC_GET_RULE iptc_get_rule +#define TC_GET_TARGET iptc_get_target +#define TC_BUILTIN iptc_builtin +#define TC_GET_POLICY iptc_get_policy +#define TC_INSERT_ENTRY iptc_insert_entry +#define TC_REPLACE_ENTRY iptc_replace_entry +#define TC_APPEND_ENTRY iptc_append_entry +#define TC_DELETE_ENTRY iptc_delete_entry +#define TC_DELETE_NUM_ENTRY iptc_delete_num_entry +#define TC_CHECK_PACKET iptc_check_packet +#define TC_FLUSH_ENTRIES iptc_flush_entries +#define TC_ZERO_ENTRIES iptc_zero_entries +#define TC_CREATE_CHAIN iptc_create_chain +#define TC_GET_REFERENCES iptc_get_references +#define TC_DELETE_CHAIN iptc_delete_chain +#define TC_RENAME_CHAIN iptc_rename_chain +#define TC_SET_POLICY iptc_set_policy +#define TC_GET_RAW_SOCKET iptc_get_raw_socket +#define TC_INIT iptc_init +#define TC_COMMIT iptc_commit +#define TC_STRERROR iptc_strerror + +#define TC_AF AF_INET +#define TC_IPPROTO IPPROTO_IP + +#define SO_SET_REPLACE IPT_SO_SET_REPLACE +#define SO_SET_ADD_COUNTERS IPT_SO_SET_ADD_COUNTERS +#define SO_GET_INFO IPT_SO_GET_INFO +#define SO_GET_ENTRIES IPT_SO_GET_ENTRIES +#define SO_GET_VERSION IPT_SO_GET_VERSION + +#define STANDARD_TARGET IPT_STANDARD_TARGET +#define LABEL_RETURN IPTC_LABEL_RETURN +#define LABEL_ACCEPT IPTC_LABEL_ACCEPT +#define LABEL_DROP IPTC_LABEL_DROP + +#define ALIGN IPT_ALIGN +#define RETURN IPT_RETURN + +#include "libiptc.c" + +#define IP_PARTS_NATIVE(n) \ +(unsigned int)((n)>>24)&0xFF, \ +(unsigned int)((n)>>16)&0xFF, \ +(unsigned int)((n)>>8)&0xFF, \ +(unsigned int)((n)&0xFF) + +#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) + +int +dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle) +{ + size_t i; + STRUCT_ENTRY_TARGET *t; + + printf("Entry %u (%lu):\n", entry2index(handle, e), + entry2offset(handle, e)); + printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n", + IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr)); + printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n", + IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr)); + printf("Interface: `%s'/", e->ip.iniface); + for (i = 0; i < IFNAMSIZ; i++) + printf("%c", e->ip.iniface_mask[i] ? 'X' : '.'); + printf("to `%s'/", e->ip.outiface); + for (i = 0; i < IFNAMSIZ; i++) + printf("%c", e->ip.outiface_mask[i] ? 'X' : '.'); + printf("\nProtocol: %u\n", e->ip.proto); + printf("Flags: %02X\n", e->ip.flags); + printf("Invflags: %02X\n", e->ip.invflags); + printf("Counters: %llu packets, %llu bytes\n", + e->counters.pcnt, e->counters.bcnt); + printf("Cache: %08X ", e->nfcache); + if (e->nfcache & NFC_ALTERED) printf("ALTERED "); + if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN "); + if (e->nfcache & NFC_IP_SRC) printf("IP_SRC "); + if (e->nfcache & NFC_IP_DST) printf("IP_DST "); + if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN "); + if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT "); + if (e->nfcache & NFC_IP_TOS) printf("IP_TOS "); + if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO "); + if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS "); + if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS "); + if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT "); + if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT "); + if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN "); + printf("\n"); + + IPT_MATCH_ITERATE(e, print_match); + + t = GET_TARGET(e); + printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size); + if (strcmp(t->u.user.name, STANDARD_TARGET) == 0) { + int pos = *(int *)t->data; + if (pos < 0) + printf("verdict=%s\n", + pos == -NF_ACCEPT-1 ? "NF_ACCEPT" + : pos == -NF_DROP-1 ? "NF_DROP" + : pos == -NF_QUEUE-1 ? "NF_QUEUE" + : pos == RETURN ? "RETURN" + : "UNKNOWN"); + else + printf("verdict=%u\n", pos); + } else if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) + printf("error=`%s'\n", t->data); + + printf("\n"); + return 0; +} + +static int +is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask) +{ + unsigned int i; + STRUCT_ENTRY_TARGET *ta, *tb; + unsigned char *mptr; + + /* Always compare head structures: ignore mask here. */ + if (a->ip.src.s_addr != b->ip.src.s_addr + || a->ip.dst.s_addr != b->ip.dst.s_addr + || a->ip.smsk.s_addr != b->ip.smsk.s_addr + || a->ip.smsk.s_addr != b->ip.smsk.s_addr + || a->ip.proto != b->ip.proto + || a->ip.flags != b->ip.flags + || a->ip.invflags != b->ip.invflags) + return 0; + + for (i = 0; i < IFNAMSIZ; i++) { + if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i]) + return 0; + if ((a->ip.iniface[i] & a->ip.iniface_mask[i]) + != (b->ip.iniface[i] & b->ip.iniface_mask[i])) + return 0; + if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i]) + return 0; + if ((a->ip.outiface[i] & a->ip.outiface_mask[i]) + != (b->ip.outiface[i] & b->ip.outiface_mask[i])) + return 0; + } + + if (a->nfcache != b->nfcache + || a->target_offset != b->target_offset + || a->next_offset != b->next_offset) + return 0; + + mptr = matchmask + sizeof(STRUCT_ENTRY); + if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr)) + return 0; + + ta = GET_TARGET((STRUCT_ENTRY *)a); + tb = GET_TARGET((STRUCT_ENTRY *)b); + if (ta->u.target_size != tb->u.target_size) + return 0; + if (strcmp(ta->u.user.name, tb->u.user.name) != 0) + return 0; + + mptr += sizeof(*ta); + if (target_different(ta->data, tb->data, + ta->u.target_size - sizeof(*ta), mptr)) + return 0; + + return 1; +} + +/***************************** DEBUGGING ********************************/ +static inline int +unconditional(const struct ipt_ip *ip) +{ + unsigned int i; + + for (i = 0; i < sizeof(*ip)/sizeof(u_int32_t); i++) + if (((u_int32_t *)ip)[i]) + return 0; + + return 1; +} + +static inline int +check_match(const STRUCT_ENTRY_MATCH *m, unsigned int *off) +{ + assert(m->u.match_size >= sizeof(STRUCT_ENTRY_MATCH)); + assert(ALIGN(m->u.match_size) == m->u.match_size); + + (*off) += m->u.match_size; + return 0; +} + +static inline int +check_entry(const STRUCT_ENTRY *e, unsigned int *i, unsigned int *off, + unsigned int user_offset, int *was_return, + TC_HANDLE_T h) +{ + unsigned int toff; + STRUCT_STANDARD_TARGET *t; + + assert(e->target_offset >= sizeof(STRUCT_ENTRY)); + assert(e->next_offset >= e->target_offset + + sizeof(STRUCT_ENTRY_TARGET)); + toff = sizeof(STRUCT_ENTRY); + IPT_MATCH_ITERATE(e, check_match, &toff); + + assert(toff == e->target_offset); + + t = (STRUCT_STANDARD_TARGET *) + GET_TARGET((STRUCT_ENTRY *)e); + /* next_offset will have to be multiple of entry alignment. */ + assert(e->next_offset == ALIGN(e->next_offset)); + assert(e->target_offset == ALIGN(e->target_offset)); + assert(t->target.u.target_size == ALIGN(t->target.u.target_size)); + assert(!TC_IS_CHAIN(t->target.u.user.name, h)); + + if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0) { + assert(t->target.u.target_size + == ALIGN(sizeof(STRUCT_STANDARD_TARGET))); + + assert(t->verdict == -NF_DROP-1 + || t->verdict == -NF_ACCEPT-1 + || t->verdict == RETURN + || t->verdict < (int)h->entries.size); + + if (t->verdict >= 0) { + STRUCT_ENTRY *te = get_entry(h, t->verdict); + int idx; + + idx = entry2index(h, te); + assert(strcmp(GET_TARGET(te)->u.user.name, + IPT_ERROR_TARGET) + != 0); + assert(te != e); + + /* Prior node must be error node, or this node. */ + assert(t->verdict == entry2offset(h, e)+e->next_offset + || strcmp(GET_TARGET(index2entry(h, idx-1)) + ->u.user.name, IPT_ERROR_TARGET) + == 0); + } + + if (t->verdict == RETURN + && unconditional(&e->ip) + && e->target_offset == sizeof(*e)) + *was_return = 1; + else + *was_return = 0; + } else if (strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0) { + assert(t->target.u.target_size + == ALIGN(sizeof(struct ipt_error_target))); + + /* If this is in user area, previous must have been return */ + if (*off > user_offset) + assert(*was_return); + + *was_return = 0; + } + else *was_return = 0; + + if (*off == user_offset) + assert(strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0); + + (*off) += e->next_offset; + (*i)++; + return 0; +} + +#ifndef NDEBUG +/* Do every conceivable sanity check on the handle */ +static void +do_check(TC_HANDLE_T h, unsigned int line) +{ + unsigned int i, n; + unsigned int user_offset; /* Offset of first user chain */ + int was_return; + + assert(h->changed == 0 || h->changed == 1); + if (strcmp(h->info.name, "filter") == 0) { + assert(h->info.valid_hooks + == (1 << NF_IP_LOCAL_IN + | 1 << NF_IP_FORWARD + | 1 << NF_IP_LOCAL_OUT)); + + /* Hooks should be first three */ + assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0); + + n = get_chain_end(h, 0); + n += get_entry(h, n)->next_offset; + assert(h->info.hook_entry[NF_IP_FORWARD] == n); + + n = get_chain_end(h, n); + n += get_entry(h, n)->next_offset; + assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); + + user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; + } else if (strcmp(h->info.name, "nat") == 0) { + assert(h->info.valid_hooks + == (1 << NF_IP_PRE_ROUTING + | 1 << NF_IP_POST_ROUTING + | 1 << NF_IP_LOCAL_OUT)); + + assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); + + n = get_chain_end(h, 0); + n += get_entry(h, n)->next_offset; + assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n); + + n = get_chain_end(h, n); + n += get_entry(h, n)->next_offset; + assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); + + user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; + } else if (strcmp(h->info.name, "mangle") == 0) { + assert(h->info.valid_hooks + == (1 << NF_IP_PRE_ROUTING + | 1 << NF_IP_LOCAL_OUT)); + + /* Hooks should be first three */ + assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); + + n = get_chain_end(h, 0); + n += get_entry(h, n)->next_offset; + assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); + + user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; + } else + abort(); + + /* User chain == end of last builtin + policy entry */ + user_offset = get_chain_end(h, user_offset); + user_offset += get_entry(h, user_offset)->next_offset; + + /* Overflows should be end of entry chains, and unconditional + policy nodes. */ + for (i = 0; i < NUMHOOKS; i++) { + STRUCT_ENTRY *e; + STRUCT_STANDARD_TARGET *t; + + if (!(h->info.valid_hooks & (1 << i))) + continue; + assert(h->info.underflow[i] + == get_chain_end(h, h->info.hook_entry[i])); + + e = get_entry(h, get_chain_end(h, h->info.hook_entry[i])); + assert(unconditional(&e->ip)); + assert(e->target_offset == sizeof(*e)); + assert(e->next_offset == sizeof(*e) + sizeof(*t)); + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); + + assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0); + assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1); + + /* Hooks and underflows must be valid entries */ + entry2index(h, get_entry(h, h->info.hook_entry[i])); + entry2index(h, get_entry(h, h->info.underflow[i])); + } + + assert(h->info.size + >= h->info.num_entries * (sizeof(STRUCT_ENTRY) + +sizeof(STRUCT_STANDARD_TARGET))); + + assert(h->entries.size + >= (h->new_number + * (sizeof(STRUCT_ENTRY) + + sizeof(STRUCT_STANDARD_TARGET)))); + assert(strcmp(h->info.name, h->entries.name) == 0); + + i = 0; n = 0; + was_return = 0; + /* Check all the entries. */ + ENTRY_ITERATE(h->entries.entries, h->entries.size, + check_entry, &i, &n, user_offset, &was_return, h); + + assert(i == h->new_number); + assert(n == h->entries.size); + + /* Final entry must be error node */ + assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1)) + ->u.user.name, + IPT_ERROR_TARGET) == 0); +} +#endif /*NDEBUG*/ diff --git a/libiptc/libip6tc.c b/libiptc/libip6tc.c new file mode 100644 index 00000000..033693ff --- /dev/null +++ b/libiptc/libip6tc.c @@ -0,0 +1,264 @@ +/* Library which manipulates firewall rules. Version 0.1. */ + +/* 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). */ + +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_CONNTRACK +#define inline +#endif + +#if !defined(__GLIBC__) || (__GLIBC__ < 2) +typedef unsigned int socklen_t; +#endif + +#include "libiptc/libip6tc.h" + +#define HOOK_PRE_ROUTING NF_IP6_PRE_ROUTING +#define HOOK_LOCAL_IN NF_IP6_LOCAL_IN +#define HOOK_FORWARD NF_IP6_FORWARD +#define HOOK_LOCAL_OUT NF_IP6_LOCAL_OUT +#define HOOK_POST_ROUTING NF_IP6_POST_ROUTING + +#define STRUCT_ENTRY_TARGET struct ip6t_entry_target +#define STRUCT_ENTRY struct ip6t_entry +#define STRUCT_ENTRY_MATCH struct ip6t_entry_match +#define STRUCT_GETINFO struct ip6t_getinfo +#define STRUCT_GET_ENTRIES struct ip6t_get_entries +#define STRUCT_COUNTERS struct ip6t_counters +#define STRUCT_COUNTERS_INFO struct ip6t_counters_info +#define STRUCT_STANDARD_TARGET struct ip6t_standard_target +#define STRUCT_REPLACE struct ip6t_replace + +#define STRUCT_TC_HANDLE struct ip6tc_handle +#define TC_HANDLE_T ip6tc_handle_t + +#define ENTRY_ITERATE IP6T_ENTRY_ITERATE +#define TABLE_MAXNAMELEN IP6T_TABLE_MAXNAMELEN +#define FUNCTION_MAXNAMELEN IP6T_FUNCTION_MAXNAMELEN + +#define GET_TARGET ip6t_get_target + +#define ERROR_TARGET IP6T_ERROR_TARGET +#define NUMHOOKS NF_IP6_NUMHOOKS + +#define IPT_CHAINLABEL ip6t_chainlabel + +#define TC_DUMP_ENTRIES dump_entries6 +#define TC_IS_CHAIN ip6tc_is_chain +#define TC_NEXT_CHAIN ip6tc_next_chain +#define TC_NUM_RULES ip6tc_num_rules +#define TC_GET_RULE ip6tc_get_rule +#define TC_GET_TARGET ip6tc_get_target +#define TC_BUILTIN ip6tc_builtin +#define TC_GET_POLICY ip6tc_get_policy +#define TC_INSERT_ENTRY ip6tc_insert_entry +#define TC_REPLACE_ENTRY ip6tc_replace_entry +#define TC_APPEND_ENTRY ip6tc_append_entry +#define TC_DELETE_ENTRY ip6tc_delete_entry +#define TC_DELETE_NUM_ENTRY ip6tc_delete_num_entry +#define TC_CHECK_PACKET ip6tc_check_packet +#define TC_FLUSH_ENTRIES ip6tc_flush_entries +#define TC_ZERO_ENTRIES ip6tc_zero_entries +#define TC_CREATE_CHAIN ip6tc_create_chain +#define TC_GET_REFERENCES ip6tc_get_references +#define TC_DELETE_CHAIN ip6tc_delete_chain +#define TC_RENAME_CHAIN ip6tc_rename_chain +#define TC_SET_POLICY ip6tc_set_policy +#define TC_GET_RAW_SOCKET ip6tc_get_raw_socket +#define TC_INIT ip6tc_init +#define TC_COMMIT ip6tc_commit +#define TC_STRERROR ip6tc_strerror + +#define TC_AF AF_INET6 +#define TC_IPPROTO IPPROTO_IPV6 + +#define SO_SET_REPLACE IP6T_SO_SET_REPLACE +#define SO_SET_ADD_COUNTERS IP6T_SO_SET_ADD_COUNTERS +#define SO_GET_INFO IP6T_SO_GET_INFO +#define SO_GET_ENTRIES IP6T_SO_GET_ENTRIES +#define SO_GET_VERSION IP6T_SO_GET_VERSION + +#define STANDARD_TARGET IP6T_STANDARD_TARGET +#define LABEL_RETURN IP6TC_LABEL_RETURN +#define LABEL_ACCEPT IP6TC_LABEL_ACCEPT +#define LABEL_DROP IP6TC_LABEL_DROP + +#define ALIGN IP6T_ALIGN +#define RETURN IP6T_RETURN + +#include "libiptc.c" + +#define BIT6(a, l) \ + (((a->in6_u.u6_addr32[(l) / 32]) >> ((l) & 31)) & 1) + +int +ipv6_prefix_length(const struct in6_addr *a) +{ + int l, i; + for (l = 0; l < 128; l++) { + if (BIT6(a, l) == 0) + break; + } + for (i = l + 1; i < 128; i++) { + if (BIT6(a, i) == 1) + return -1; + } + return l; +} + +static int +dump_entry(struct ip6t_entry *e, const ip6tc_handle_t handle) +{ + size_t i; + char buf[40]; + int len; + struct ip6t_entry_target *t; + + printf("Entry %u (%lu):\n", entry2index(handle, e), + entry2offset(handle, e)); + puts("SRC IP: "); + inet_ntop(AF_INET6, &e->ipv6.src, buf, sizeof buf); + puts(buf); + putchar('/'); + len = ipv6_prefix_length(&e->ipv6.smsk); + if (len != -1) + printf("%d", len); + else { + inet_ntop(AF_INET6, &e->ipv6.smsk, buf, sizeof buf); + puts(buf); + } + putchar('\n'); + + puts("DST IP: "); + inet_ntop(AF_INET6, &e->ipv6.dst, buf, sizeof buf); + puts(buf); + putchar('/'); + len = ipv6_prefix_length(&e->ipv6.dmsk); + if (len != -1) + printf("%d", len); + else { + inet_ntop(AF_INET6, &e->ipv6.dmsk, buf, sizeof buf); + puts(buf); + } + putchar('\n'); + + printf("Interface: `%s'/", e->ipv6.iniface); + for (i = 0; i < IFNAMSIZ; i++) + printf("%c", e->ipv6.iniface_mask[i] ? 'X' : '.'); + printf("to `%s'/", e->ipv6.outiface); + for (i = 0; i < IFNAMSIZ; i++) + printf("%c", e->ipv6.outiface_mask[i] ? 'X' : '.'); + printf("\nProtocol: %u\n", e->ipv6.proto); + if (e->ipv6.flags & IP6T_F_TOS) + printf("TOS: %u\n", e->ipv6.tos); + printf("Flags: %02X\n", e->ipv6.flags); + printf("Invflags: %02X\n", e->ipv6.invflags); + printf("Counters: %llu packets, %llu bytes\n", + e->counters.pcnt, e->counters.bcnt); + printf("Cache: %08X ", e->nfcache); + if (e->nfcache & NFC_ALTERED) printf("ALTERED "); + if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN "); + if (e->nfcache & NFC_IP6_SRC) printf("IP6_SRC "); + if (e->nfcache & NFC_IP6_DST) printf("IP6_DST "); + if (e->nfcache & NFC_IP6_IF_IN) printf("IP6_IF_IN "); + if (e->nfcache & NFC_IP6_IF_OUT) printf("IP6_IF_OUT "); + if (e->nfcache & NFC_IP6_TOS) printf("IP6_TOS "); + if (e->nfcache & NFC_IP6_PROTO) printf("IP6_PROTO "); + if (e->nfcache & NFC_IP6_OPTIONS) printf("IP6_OPTIONS "); + if (e->nfcache & NFC_IP6_TCPFLAGS) printf("IP6_TCPFLAGS "); + if (e->nfcache & NFC_IP6_SRC_PT) printf("IP6_SRC_PT "); + if (e->nfcache & NFC_IP6_DST_PT) printf("IP6_DST_PT "); + if (e->nfcache & NFC_IP6_PROTO_UNKNOWN) printf("IP6_PROTO_UNKNOWN "); + printf("\n"); + + IP6T_MATCH_ITERATE(e, print_match); + + t = ip6t_get_target(e); + printf("Target name: `%s' [%u]\n", t->u.name, t->target_size); + if (strcmp(t->u.name, IP6T_STANDARD_TARGET) == 0) { + int pos = *(int *)t->data; + if (pos < 0) + printf("verdict=%s\n", + pos == -NF_ACCEPT-1 ? "NF_ACCEPT" + : pos == -NF_DROP-1 ? "NF_DROP" + : pos == IP6T_RETURN ? "RETURN" + : "UNKNOWN"); + else + printf("verdict=%u\n", pos); + } else if (strcmp(t->u.name, IP6T_ERROR_TARGET) == 0) + printf("error=`%s'\n", t->data); + + printf("\n"); + return 0; +} + +static inline int +is_same(const struct STRUCT_ENTRY *a, const struct STRUCT_ENTRY *b, + unsigned char *matchmask) +{ + unsigned int i; + struct STRUCT_ENTRY_TARGET *ta, *tb; + unsigned char *mptr; + + /* Always compare head structures: ignore mask here. */ + if (memcmp(&a->ipv6.src, &b->ipv6.src, sizeof(struct in6_addr)) + || memcmp(&a->ipv6.dst, &b->ipv6.dst, sizeof(struct in6_addr)) + || memcmp(&a->ipv6.smsk, &b->ipv6.smsk, sizeof(struct in6_addr)) + || memcmp(&a->ipv6.dmsk, &b->ipv6.dmsk, sizeof(struct in6_addr)) + || a->ipv6.proto != b->ipv6.proto + || a->ipv6.tos != b->ipv6.tos + || a->ipv6.flags != b->ipv6.flags + || a->ipv6.invflags != b->ipv6.invflags) + return 0; + + for (i = 0; i < IFNAMSIZ; i++) { + if (a->ipv6.iniface_mask[i] != b->ipv6.iniface_mask[i]) + return 0; + if ((a->ipv6.iniface[i] & a->ipv6.iniface_mask[i]) + != (b->ipv6.iniface[i] & b->ipv6.iniface_mask[i])) + return 0; + if (a->ipv6.outiface_mask[i] != b->ipv6.outiface_mask[i]) + return 0; + if ((a->ipv6.outiface[i] & a->ipv6.outiface_mask[i]) + != (b->ipv6.outiface[i] & b->ipv6.outiface_mask[i])) + return 0; + } + + if (a->nfcache != b->nfcache + || a->target_offset != b->target_offset + || a->next_offset != b->next_offset) + return 0; + + mptr = matchmask + sizeof(struct STRUCT_ENTRY); + if (IP6T_MATCH_ITERATE(a, match_different, a->elems, b->elems)) + return 0; + + ta = GET_TARGET((struct STRUCT_ENTRY *)a); + tb = GET_TARGET((struct STRUCT_ENTRY *)b); + if (ta->target_size != tb->target_size) + return 0; + if (strcmp(ta->u.name, tb->u.name) != 0) + return 0; + mptr += sizeof(*ta); + + if (target_different(ta->data, tb->data, + ta->u.target_size - sizeof(*ta), mptr)) + return 0; + + return 1; +} diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 019de66f..56c33049 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -11,30 +11,13 @@ /* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See COPYING for details). */ -#include -#include -#include -#include -#include -#include - -#if !defined(__GLIBC__) || (__GLIBC__ < 2) -typedef unsigned int socklen_t; -#endif - -#include -#include - -#define IP_VERSION 4 -#define IP_OFFSET 0x1FFF - #ifndef IPT_LIB_DIR #define IPT_LIB_DIR "/usr/local/lib/iptables" #endif #if 0 -static struct ipt_entry_target * -ipt_get_target(struct ipt_entry *e) +static STRUCT_ENTRY_TARGET * +GET_TARGET(STRUCT_ENTRY *e) { return (void *)e + e->target_offset; } @@ -44,11 +27,11 @@ static int sockfd = -1; static void *iptc_fn = NULL; static const char *hooknames[] -= { [NF_IP_PRE_ROUTING] "PREROUTING", - [NF_IP_LOCAL_IN] "INPUT", - [NF_IP_FORWARD] "FORWARD", - [NF_IP_LOCAL_OUT] "OUTPUT", - [NF_IP_POST_ROUTING] "POSTROUTING" += { [HOOK_PRE_ROUTING] "PREROUTING", + [HOOK_LOCAL_IN] "INPUT", + [HOOK_FORWARD] "FORWARD", + [HOOK_LOCAL_OUT] "OUTPUT", + [HOOK_POST_ROUTING] "POSTROUTING" }; struct counter_map @@ -64,25 +47,25 @@ struct counter_map /* Convenience structures */ struct ipt_error_target { - struct ipt_entry_target t; - char error[IPT_TABLE_MAXNAMELEN]; + STRUCT_ENTRY_TARGET t; + char error[TABLE_MAXNAMELEN]; }; struct chain_cache { - char name[IPT_TABLE_MAXNAMELEN]; + char name[TABLE_MAXNAMELEN]; /* This is the first rule in chain. */ - struct ipt_entry *start; + STRUCT_ENTRY *start; /* Last rule in chain */ - struct ipt_entry *end; + STRUCT_ENTRY *end; }; -struct iptc_handle +STRUCT_TC_HANDLE { /* Have changes been made? */ int changed; /* Size in here reflects original state. */ - struct ipt_getinfo info; + STRUCT_GETINFO info; struct counter_map *counter_map; /* Array of hook names */ @@ -97,15 +80,15 @@ struct iptc_handle struct chain_cache *cache_chain_iteration; /* Rule iterator: terminal rule */ - struct ipt_entry *cache_rule_end; + STRUCT_ENTRY *cache_rule_end; /* Number in here reflects current state. */ unsigned int new_number; - struct ipt_get_entries entries; + STRUCT_GET_ENTRIES entries; }; static void -set_changed(iptc_handle_t h) +set_changed(TC_HANDLE_T h) { if (h->cache_chain_heads) { free(h->cache_chain_heads); @@ -118,15 +101,15 @@ set_changed(iptc_handle_t h) } #ifndef NDEBUG -static void do_check(iptc_handle_t h, unsigned int line); +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 inline int -get_number(const struct ipt_entry *i, - const struct ipt_entry *seek, +get_number(const STRUCT_ENTRY *i, + const STRUCT_ENTRY *seek, unsigned int *pos) { if (i == seek) @@ -136,12 +119,12 @@ get_number(const struct ipt_entry *i, } static unsigned int -entry2index(const iptc_handle_t h, const struct ipt_entry *seek) +entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek) { unsigned int pos = 0; - if (IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, - get_number, seek, &pos) == 0) { + if (ENTRY_ITERATE(h->entries.entries, h->entries.size, + get_number, seek, &pos) == 0) { fprintf(stderr, "ERROR: offset %i not an entry!\n", (unsigned char *)seek - h->entries.entries); abort(); @@ -150,10 +133,10 @@ entry2index(const iptc_handle_t h, const struct ipt_entry *seek) } static inline int -get_entry_n(struct ipt_entry *i, +get_entry_n(STRUCT_ENTRY *i, unsigned int number, unsigned int *pos, - struct ipt_entry **pe) + STRUCT_ENTRY **pe) { if (*pos == number) { *pe = i; @@ -163,59 +146,59 @@ get_entry_n(struct ipt_entry *i, return 0; } -static struct ipt_entry * -index2entry(iptc_handle_t h, unsigned int index) +static STRUCT_ENTRY * +index2entry(TC_HANDLE_T h, unsigned int index) { unsigned int pos = 0; - struct ipt_entry *ret = NULL; + STRUCT_ENTRY *ret = NULL; - IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, - get_entry_n, index, &pos, &ret); + ENTRY_ITERATE(h->entries.entries, h->entries.size, + get_entry_n, index, &pos, &ret); return ret; } -static inline struct ipt_entry * -get_entry(iptc_handle_t h, unsigned int offset) +static inline STRUCT_ENTRY * +get_entry(TC_HANDLE_T h, unsigned int offset) { - return (struct ipt_entry *)(h->entries.entries + offset); + return (STRUCT_ENTRY *)(h->entries.entries + offset); } static inline unsigned long -entry2offset(const iptc_handle_t h, const struct ipt_entry *e) +entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) { return (unsigned char *)e - h->entries.entries; } static unsigned long -index2offset(iptc_handle_t h, unsigned int index) +index2offset(TC_HANDLE_T h, unsigned int index) { return entry2offset(h, index2entry(h, index)); } static const char * -get_errorlabel(iptc_handle_t h, unsigned int offset) +get_errorlabel(TC_HANDLE_T h, unsigned int offset) { - struct ipt_entry *e; + STRUCT_ENTRY *e; e = get_entry(h, offset); - if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) != 0) { + if (strcmp(GET_TARGET(e)->u.user.name, IPT_ERROR_TARGET) != 0) { fprintf(stderr, "ERROR: offset %u not an error node!\n", offset); abort(); } - return (const char *)ipt_get_target(e)->data; + return (const char *)GET_TARGET(e)->data; } /* Allocate handle of given size */ -static iptc_handle_t +static TC_HANDLE_T alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) { size_t len; - iptc_handle_t h; + TC_HANDLE_T h; - len = sizeof(struct iptc_handle) + len = sizeof(STRUCT_TC_HANDLE) + size + num_rules * sizeof(struct counter_map); @@ -228,7 +211,7 @@ alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) h->cache_num_chains = 0; h->cache_chain_heads = NULL; h->counter_map = (void *)h - + sizeof(struct iptc_handle) + + sizeof(STRUCT_TC_HANDLE) + size; strcpy(h->info.name, tablename); strcpy(h->entries.name, tablename); @@ -236,28 +219,28 @@ alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) return h; } -iptc_handle_t -iptc_init(const char *tablename) +TC_HANDLE_T +TC_INIT(const char *tablename) { - iptc_handle_t h; - struct ipt_getinfo info; + TC_HANDLE_T h; + STRUCT_GETINFO info; unsigned int i; int tmp; socklen_t s; - iptc_fn = iptc_init; + iptc_fn = TC_INIT; - sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) return NULL; s = sizeof(info); - if (strlen(tablename) >= IPT_TABLE_MAXNAMELEN) { + if (strlen(tablename) >= TABLE_MAXNAMELEN) { errno = EINVAL; return NULL; } strcpy(info.name, tablename); - if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_INFO, &info, &s) < 0) + if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) return NULL; if ((h = alloc_handle(info.name, info.size, info.num_entries)) @@ -290,9 +273,9 @@ iptc_init(const char *tablename) h->entries.size = h->info.size; - tmp = sizeof(struct ipt_get_entries) + h->info.size; + tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; - if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_ENTRIES, &h->entries, + if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries, &tmp) < 0) { free(h); return NULL; @@ -302,84 +285,17 @@ iptc_init(const char *tablename) return h; } -#define IP_PARTS_NATIVE(n) \ -(unsigned int)((n)>>24)&0xFF, \ -(unsigned int)((n)>>16)&0xFF, \ -(unsigned int)((n)>>8)&0xFF, \ -(unsigned int)((n)&0xFF) - -#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) - static inline int -print_match(const struct ipt_entry_match *m) +print_match(const STRUCT_ENTRY_MATCH *m) { printf("Match name: `%s'\n", m->u.user.name); return 0; } -int -dump_entry(struct ipt_entry *e, const iptc_handle_t handle) -{ - size_t i; - struct ipt_entry_target *t; - - printf("Entry %u (%lu):\n", entry2index(handle, e), - entry2offset(handle, e)); - printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n", - IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr)); - printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n", - IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr)); - printf("Interface: `%s'/", e->ip.iniface); - for (i = 0; i < IFNAMSIZ; i++) - printf("%c", e->ip.iniface_mask[i] ? 'X' : '.'); - printf("to `%s'/", e->ip.outiface); - for (i = 0; i < IFNAMSIZ; i++) - printf("%c", e->ip.outiface_mask[i] ? 'X' : '.'); - printf("\nProtocol: %u\n", e->ip.proto); - printf("Flags: %02X\n", e->ip.flags); - printf("Invflags: %02X\n", e->ip.invflags); - printf("Counters: %llu packets, %llu bytes\n", - e->counters.pcnt, e->counters.bcnt); - printf("Cache: %08X ", e->nfcache); - if (e->nfcache & NFC_ALTERED) printf("ALTERED "); - if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN "); - if (e->nfcache & NFC_IP_SRC) printf("IP_SRC "); - if (e->nfcache & NFC_IP_DST) printf("IP_DST "); - if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN "); - if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT "); - if (e->nfcache & NFC_IP_TOS) printf("IP_TOS "); - if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO "); - if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS "); - if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS "); - if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT "); - if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT "); - if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN "); - printf("\n"); - - IPT_MATCH_ITERATE(e, print_match); - - t = ipt_get_target(e); - printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size); - if (strcmp(t->u.user.name, IPT_STANDARD_TARGET) == 0) { - int pos = *(int *)t->data; - if (pos < 0) - printf("verdict=%s\n", - pos == -NF_ACCEPT-1 ? "NF_ACCEPT" - : pos == -NF_DROP-1 ? "NF_DROP" - : pos == -NF_QUEUE-1 ? "NF_QUEUE" - : pos == IPT_RETURN ? "RETURN" - : "UNKNOWN"); - else - printf("verdict=%u\n", pos); - } else if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) - printf("error=`%s'\n", t->data); - - printf("\n"); - return 0; -} - +static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle); + void -dump_entries(const iptc_handle_t handle) +TC_DUMP_ENTRIES(const TC_HANDLE_T handle) { CHECK(handle); @@ -400,17 +316,17 @@ dump_entries(const iptc_handle_t handle) handle->info.underflow[NF_IP_LOCAL_OUT], handle->info.underflow[NF_IP_POST_ROUTING]); - IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size, - dump_entry, handle); + ENTRY_ITERATE(handle->entries.entries, handle->entries.size, + dump_entry, handle); } /* Returns 0 if not hook entry, else hooknumber + 1 */ static inline unsigned int -is_hook_entry(struct ipt_entry *e, iptc_handle_t h) +is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) { unsigned int i; - for (i = 0; i < NF_IP_NUMHOOKS; 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; @@ -419,7 +335,7 @@ is_hook_entry(struct ipt_entry *e, iptc_handle_t h) } static inline int -add_chain(struct ipt_entry *e, iptc_handle_t h, struct ipt_entry **prev) +add_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev) { unsigned int builtin; @@ -432,13 +348,13 @@ add_chain(struct ipt_entry *e, iptc_handle_t h, struct ipt_entry **prev) /* We know this is the start of a new chain if it's an ERROR target, or a hook entry point */ - if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) == 0) { + if (strcmp(GET_TARGET(e)->u.user.name, IPT_ERROR_TARGET) == 0) { /* prev was last entry in previous chain */ h->cache_chain_heads[h->cache_num_chains-1].end = *prev; strcpy(h->cache_chain_heads[h->cache_num_chains].name, - (const char *)ipt_get_target(e)->data); + (const char *)GET_TARGET(e)->data); h->cache_chain_heads[h->cache_num_chains].start = (void *)e + e->next_offset; h->cache_num_chains++; @@ -465,10 +381,10 @@ static int alphasort(const void *a, const void *b) ((struct chain_cache *)b)->name); } -static int populate_cache(iptc_handle_t h) +static int populate_cache(TC_HANDLE_T h) { unsigned int i; - struct ipt_entry *prev; + STRUCT_ENTRY *prev; /* # chains < # rules / 2 + num builtins - 1 */ h->cache_chain_heads = malloc((h->new_number / 2 + 4) @@ -482,14 +398,14 @@ static int populate_cache(iptc_handle_t h) h->cache_num_builtins = 0; /* Count builtins */ - for (i = 0; i < NF_IP_NUMHOOKS; i++) { + for (i = 0; i < NUMHOOKS; i++) { if (h->info.valid_hooks & (1 << i)) h->cache_num_builtins++; } prev = NULL; - IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, - add_chain, h, &prev); + ENTRY_ITERATE(h->entries.entries, h->entries.size, + add_chain, h, &prev); qsort(h->cache_chain_heads + h->cache_num_builtins, h->cache_num_chains - h->cache_num_builtins, @@ -500,7 +416,7 @@ static int populate_cache(iptc_handle_t h) /* Returns cache ptr if found, otherwise NULL. */ static struct chain_cache * -find_label(const char *name, iptc_handle_t handle) +find_label(const char *name, TC_HANDLE_T handle) { unsigned int i; @@ -518,17 +434,17 @@ find_label(const char *name, iptc_handle_t handle) } /* Does this chain exist? */ -int iptc_is_chain(const char *chain, const iptc_handle_t handle) +int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) { return find_label(chain, handle) != NULL; } /* Returns the position of the final (ie. unconditional) element. */ static unsigned int -get_chain_end(const iptc_handle_t handle, unsigned int start) +get_chain_end(const TC_HANDLE_T handle, unsigned int start) { unsigned int last_off, off; - struct ipt_entry *e; + STRUCT_ENTRY *e; last_off = start; e = get_entry(handle, start); @@ -537,20 +453,20 @@ get_chain_end(const iptc_handle_t handle, unsigned int start) for (off = start + e->next_offset; off < handle->entries.size; last_off = off, off += e->next_offset) { - struct ipt_entry_target *t; + STRUCT_ENTRY_TARGET *t; unsigned int i; e = get_entry(handle, off); /* We hit an entry point. */ - for (i = 0; i < NF_IP_NUMHOOKS; i++) { + 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 = ipt_get_target(e); + t = GET_TARGET(e); if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) return last_off; } @@ -562,7 +478,7 @@ get_chain_end(const iptc_handle_t handle, unsigned int start) /* Iterator functions to run through the chains. */ const char * -iptc_first_chain(iptc_handle_t *handle) +iptc_first_chain(TC_HANDLE_T *handle) { if ((*handle)->cache_chain_heads == NULL && !populate_cache(*handle)) @@ -576,7 +492,7 @@ iptc_first_chain(iptc_handle_t *handle) /* Iterator functions to run through the chains. Returns NULL at end. */ const char * -iptc_next_chain(iptc_handle_t *handle) +TC_NEXT_CHAIN(TC_HANDLE_T *handle) { (*handle)->cache_chain_iteration++; @@ -588,8 +504,8 @@ iptc_next_chain(iptc_handle_t *handle) } /* Get first rule in the given chain: NULL for empty chain. */ -const struct ipt_entry * -iptc_first_rule(const char *chain, iptc_handle_t *handle) +const STRUCT_ENTRY * +iptc_first_rule(const char *chain, TC_HANDLE_T *handle) { struct chain_cache *c; @@ -608,8 +524,8 @@ iptc_first_rule(const char *chain, iptc_handle_t *handle) } /* Returns NULL when rules run out. */ -const struct ipt_entry * -iptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle) +const STRUCT_ENTRY * +iptc_next_rule(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) { if ((void *)prev + prev->next_offset == (void *)(*handle)->cache_rule_end) @@ -621,10 +537,10 @@ iptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle) #if 0 /* How many rules in this chain? */ unsigned int -iptc_num_rules(const char *chain, iptc_handle_t *handle) +TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle) { unsigned int off = 0; - struct ipt_entry *start, *end; + STRUCT_ENTRY *start, *end; CHECK(*handle); if (!find_label(&off, chain, *handle)) { @@ -639,9 +555,9 @@ iptc_num_rules(const char *chain, iptc_handle_t *handle) } /* Get n'th rule in this chain. */ -const struct ipt_entry *iptc_get_rule(const char *chain, - unsigned int n, - iptc_handle_t *handle) +const STRUCT_ENTRY *TC_GET_RULE(const char *chain, + unsigned int n, + TC_HANDLE_T *handle) { unsigned int pos = 0, chainindex; @@ -658,27 +574,27 @@ const struct ipt_entry *iptc_get_rule(const char *chain, #endif static const char * -target_name(iptc_handle_t handle, const struct ipt_entry *ce) +target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce) { int spos; unsigned int labelidx; - struct ipt_entry *jumpto; + STRUCT_ENTRY *jumpto; /* To avoid const warnings */ - struct ipt_entry *e = (struct ipt_entry *)ce; + STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; - if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) != 0) - return ipt_get_target(e)->u.user.name; + if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0) + return GET_TARGET(e)->u.user.name; /* Standard target: evaluate */ - spos = *(int *)ipt_get_target(e)->data; + spos = *(int *)GET_TARGET(e)->data; if (spos < 0) { - if (spos == IPT_RETURN) - return IPTC_LABEL_RETURN; + if (spos == RETURN) + return LABEL_RETURN; else if (spos == -NF_ACCEPT-1) - return IPTC_LABEL_ACCEPT; + return LABEL_ACCEPT; else if (spos == -NF_DROP-1) - return IPTC_LABEL_DROP; + return LABEL_DROP; else if (spos == -NF_QUEUE-1) return IPTC_LABEL_QUEUE; @@ -700,19 +616,19 @@ target_name(iptc_handle_t handle, const struct ipt_entry *ce) } /* Returns a pointer to the target name of this position. */ -const char *iptc_get_target(const struct ipt_entry *e, - iptc_handle_t *handle) +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 -iptc_builtin(const char *chain, const iptc_handle_t handle) +TC_BUILTIN(const char *chain, const TC_HANDLE_T handle) { unsigned int i; - for (i = 0; i < NF_IP_NUMHOOKS; i++) { + for (i = 0; i < NUMHOOKS; i++) { if ((handle->info.valid_hooks & (1 << i)) && handle->hooknames[i] && strcmp(handle->hooknames[i], chain) == 0) @@ -723,15 +639,15 @@ iptc_builtin(const char *chain, const iptc_handle_t handle) /* Get the policy of a given built-in chain */ const char * -iptc_get_policy(const char *chain, - struct ipt_counters *counters, - iptc_handle_t *handle) +TC_GET_POLICY(const char *chain, + STRUCT_COUNTERS *counters, + TC_HANDLE_T *handle) { unsigned int start; - struct ipt_entry *e; + STRUCT_ENTRY *e; int hook; - hook = iptc_builtin(chain, *handle); + hook = TC_BUILTIN(chain, *handle); if (hook != 0) start = (*handle)->info.hook_entry[hook-1]; else @@ -744,16 +660,16 @@ iptc_get_policy(const char *chain, } static int -correct_verdict(struct ipt_entry *e, +correct_verdict(STRUCT_ENTRY *e, unsigned char *base, unsigned int offset, int delta_offset) { - struct ipt_standard_target *t = (void *)ipt_get_target(e); + STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e); unsigned int curr = (unsigned 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, IPT_STANDARD_TARGET) == 0 + if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0 && t->verdict > (int)offset && !(curr == offset && t->verdict == curr + e->next_offset)) { @@ -765,12 +681,12 @@ correct_verdict(struct ipt_entry *e, /* Adjusts standard verdict jump positions after an insertion/deletion. */ static int -set_verdict(unsigned int offset, int delta_offset, iptc_handle_t *handle) +set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle) { - IPT_ENTRY_ITERATE((*handle)->entries.entries, - (*handle)->entries.size, - correct_verdict, (*handle)->entries.entries, - offset, delta_offset); + ENTRY_ITERATE((*handle)->entries.entries, + (*handle)->entries.size, + correct_verdict, (*handle)->entries.entries, + offset, delta_offset); set_changed(*handle); return 1; @@ -780,13 +696,13 @@ set_verdict(unsigned int offset, int delta_offset, iptc_handle_t *handle) * insertion position is an entry point, keep the entry point. */ static int insert_rules(unsigned int num_rules, unsigned int rules_size, - const struct ipt_entry *insert, + const STRUCT_ENTRY *insert, unsigned int offset, unsigned int num_rules_offset, int prepend, - iptc_handle_t *handle) + TC_HANDLE_T *handle) { - iptc_handle_t newh; - struct ipt_getinfo newinfo; + TC_HANDLE_T newh; + STRUCT_GETINFO newinfo; unsigned int i; if (offset >= (*handle)->entries.size) { @@ -797,7 +713,7 @@ insert_rules(unsigned int num_rules, unsigned int rules_size, newinfo = (*handle)->info; /* Fix up entry points. */ - for (i = 0; i < NF_IP_NUMHOOKS; i++) { + 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) @@ -855,7 +771,7 @@ insert_rules(unsigned int num_rules, unsigned int rules_size, static int delete_rules(unsigned int num_rules, unsigned int rules_size, unsigned int offset, unsigned int num_rules_offset, - iptc_handle_t *handle) + TC_HANDLE_T *handle) { unsigned int i; @@ -865,7 +781,7 @@ delete_rules(unsigned int num_rules, unsigned int rules_size, } /* Fix up entry points. */ - for (i = 0; i < NF_IP_NUMHOOKS; i++) { + 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 */ @@ -908,31 +824,31 @@ delete_rules(unsigned int num_rules, unsigned int rules_size, } static int -standard_map(struct ipt_entry *e, int verdict) +standard_map(STRUCT_ENTRY *e, int verdict) { - struct ipt_standard_target *t; + STRUCT_STANDARD_TARGET *t; - t = (struct ipt_standard_target *)ipt_get_target(e); + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); - if (t->target.u.target_size != sizeof(struct ipt_standard_target)) { + if (t->target.u.target_size != sizeof(STRUCT_STANDARD_TARGET)) { errno = EINVAL; return 0; } /* memset for memcmp convenience on delete/replace */ - memset(t->target.u.user.name, 0, IPT_FUNCTION_MAXNAMELEN); - strcpy(t->target.u.user.name, IPT_STANDARD_TARGET); + 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 iptc_handle_t handle, - struct ipt_entry *e, +map_target(const TC_HANDLE_T handle, + STRUCT_ENTRY *e, unsigned int offset, - struct ipt_entry_target *old) + STRUCT_ENTRY_TARGET *old) { - struct ipt_entry_target *t = ipt_get_target(e); + 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). */ @@ -942,15 +858,15 @@ map_target(const iptc_handle_t handle, 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, IPTC_LABEL_ACCEPT) == 0) + else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0) return standard_map(e, -NF_ACCEPT - 1); - else if (strcmp(t->u.user.name, IPTC_LABEL_DROP) == 0) + else if (strcmp(t->u.user.name, LABEL_DROP) == 0) return standard_map(e, -NF_DROP - 1); else if (strcmp(t->u.user.name, IPTC_LABEL_QUEUE) == 0) return standard_map(e, -NF_QUEUE - 1); - else if (strcmp(t->u.user.name, IPTC_LABEL_RETURN) == 0) - return standard_map(e, IPT_RETURN); - else if (iptc_builtin(t->u.user.name, handle)) { + 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; @@ -967,14 +883,14 @@ map_target(const iptc_handle_t handle, /* memset to all 0 for your memcmp convenience. */ memset(t->u.user.name + strlen(t->u.user.name), 0, - IPT_FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); + FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); return 1; } static void -unmap_target(struct ipt_entry *e, struct ipt_entry_target *old) +unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old) { - struct ipt_entry_target *t = ipt_get_target(e); + 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). */ @@ -983,17 +899,17 @@ unmap_target(struct ipt_entry *e, struct ipt_entry_target *old) /* Insert the entry `fw' in chain `chain' into position `rulenum'. */ int -iptc_insert_entry(const ipt_chainlabel chain, - const struct ipt_entry *e, - unsigned int rulenum, - iptc_handle_t *handle) +TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, + const STRUCT_ENTRY *e, + unsigned int rulenum, + TC_HANDLE_T *handle) { unsigned int chainindex, offset; - struct ipt_entry_target old; + STRUCT_ENTRY_TARGET old; struct chain_cache *c; int ret; - iptc_fn = iptc_insert_entry; + iptc_fn = TC_INSERT_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; @@ -1009,28 +925,28 @@ iptc_insert_entry(const ipt_chainlabel chain, /* Mapping target actually alters entry, but that's transparent to the caller. */ - if (!map_target(*handle, (struct ipt_entry *)e, offset, &old)) + 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 ipt_entry *)e, &old); + unmap_target((STRUCT_ENTRY *)e, &old); return ret; } /* Atomically replace rule `rulenum' in `chain' with `fw'. */ int -iptc_replace_entry(const ipt_chainlabel chain, - const struct ipt_entry *e, - unsigned int rulenum, - iptc_handle_t *handle) +TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, + const STRUCT_ENTRY *e, + unsigned int rulenum, + TC_HANDLE_T *handle) { unsigned int chainindex, offset; - struct ipt_entry_target old; + STRUCT_ENTRY_TARGET old; struct chain_cache *c; int ret; - iptc_fn = iptc_replace_entry; + iptc_fn = TC_REPLACE_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; @@ -1050,33 +966,33 @@ iptc_replace_entry(const ipt_chainlabel chain, offset, chainindex + rulenum, handle)) return 0; - if (!map_target(*handle, (struct ipt_entry *)e, offset, &old)) + 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 ipt_entry *)e, &old); + unmap_target((STRUCT_ENTRY *)e, &old); return ret; } /* Append entry `fw' to chain `chain'. Equivalent to insert with rulenum = length of chain. */ int -iptc_append_entry(const ipt_chainlabel chain, - const struct ipt_entry *e, - iptc_handle_t *handle) +TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, + const STRUCT_ENTRY *e, + TC_HANDLE_T *handle) { struct chain_cache *c; - struct ipt_entry_target old; + STRUCT_ENTRY_TARGET old; int ret; - iptc_fn = iptc_append_entry; + iptc_fn = TC_APPEND_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } - if (!map_target(*handle, (struct ipt_entry *)e, + if (!map_target(*handle, (STRUCT_ENTRY *)e, entry2offset(*handle, c->end), &old)) return 0; @@ -1084,17 +1000,17 @@ iptc_append_entry(const ipt_chainlabel chain, entry2offset(*handle, c->end), entry2index(*handle, c->end), 0, handle); - unmap_target((struct ipt_entry *)e, &old); + unmap_target((STRUCT_ENTRY *)e, &old); return ret; } static inline int -match_different(const struct ipt_entry_match *a, +match_different(const STRUCT_ENTRY_MATCH *a, const unsigned char *a_elems, const unsigned char *b_elems, unsigned char **maskptr) { - const struct ipt_entry_match *b; + const STRUCT_ENTRY_MATCH *b; unsigned int i; /* Offset of b is the same as a. */ @@ -1129,73 +1045,23 @@ target_different(const unsigned char *a_targdata, return 0; } -static inline int -is_same(const struct ipt_entry *a, const struct ipt_entry *b, - unsigned char *matchmask) -{ - unsigned int i; - struct ipt_entry_target *ta, *tb; - unsigned char *mptr; - - /* Always compare head structures: ignore mask here. */ - if (a->ip.src.s_addr != b->ip.src.s_addr - || a->ip.dst.s_addr != b->ip.dst.s_addr - || a->ip.smsk.s_addr != b->ip.smsk.s_addr - || a->ip.smsk.s_addr != b->ip.smsk.s_addr - || a->ip.proto != b->ip.proto - || a->ip.flags != b->ip.flags - || a->ip.invflags != b->ip.invflags) - return 0; - - for (i = 0; i < IFNAMSIZ; i++) { - if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i]) - return 0; - if ((a->ip.iniface[i] & a->ip.iniface_mask[i]) - != (b->ip.iniface[i] & b->ip.iniface_mask[i])) - return 0; - if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i]) - return 0; - if ((a->ip.outiface[i] & a->ip.outiface_mask[i]) - != (b->ip.outiface[i] & b->ip.outiface_mask[i])) - return 0; - } - - if (a->nfcache != b->nfcache - || a->target_offset != b->target_offset - || a->next_offset != b->next_offset) - return 0; - - mptr = matchmask + sizeof(struct ipt_entry); - if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr)) - return 0; - - ta = ipt_get_target((struct ipt_entry *)a); - tb = ipt_get_target((struct ipt_entry *)b); - if (ta->u.target_size != tb->u.target_size) - return 0; - if (strcmp(ta->u.user.name, tb->u.user.name) != 0) - return 0; - - mptr += sizeof(*ta); - if (target_different(ta->data, tb->data, - ta->u.target_size - sizeof(*ta), mptr)) - return 0; - - return 1; -} +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 -iptc_delete_entry(const ipt_chainlabel chain, - const struct ipt_entry *origfw, - unsigned char *matchmask, - iptc_handle_t *handle) +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 ipt_entry *e, *fw; + STRUCT_ENTRY *e, *fw; - iptc_fn = iptc_delete_entry; + iptc_fn = TC_DELETE_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; @@ -1210,7 +1076,7 @@ iptc_delete_entry(const ipt_chainlabel chain, for (offset = entry2offset(*handle, c->start); offset < entry2offset(*handle, c->end); offset += e->next_offset) { - struct ipt_entry_target discard; + STRUCT_ENTRY_TARGET discard; memcpy(fw, origfw, origfw->next_offset); @@ -1242,16 +1108,16 @@ iptc_delete_entry(const ipt_chainlabel chain, /* Delete the rule in position `rulenum' in `chain'. */ int -iptc_delete_num_entry(const ipt_chainlabel chain, - unsigned int rulenum, - iptc_handle_t *handle) +TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, + unsigned int rulenum, + TC_HANDLE_T *handle) { unsigned int index; int ret; - struct ipt_entry *e; + STRUCT_ENTRY *e; struct chain_cache *c; - iptc_fn = iptc_delete_num_entry; + iptc_fn = TC_DELETE_NUM_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; @@ -1278,9 +1144,9 @@ iptc_delete_num_entry(const ipt_chainlabel chain, /* Check the packet `fw' on chain `chain'. Returns the verdict, or NULL and sets errno. */ const char * -iptc_check_packet(const ipt_chainlabel chain, - struct ipt_entry *entry, - iptc_handle_t *handle) +TC_CHECK_PACKET(const IPT_CHAINLABEL chain, + STRUCT_ENTRY *entry, + TC_HANDLE_T *handle) { errno = ENOSYS; return NULL; @@ -1288,13 +1154,13 @@ iptc_check_packet(const ipt_chainlabel chain, /* Flushes the entries in the given chain (ie. empties chain). */ int -iptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle) +TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { unsigned int startindex, endindex; struct chain_cache *c; int ret; - iptc_fn = iptc_flush_entries; + iptc_fn = TC_FLUSH_ENTRIES; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; @@ -1311,7 +1177,7 @@ iptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle) /* Zeroes the counters in a chain. */ int -iptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle) +TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { unsigned int i, end; struct chain_cache *c; @@ -1337,48 +1203,48 @@ iptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle) /* To create a chain, create two rules: error node and unconditional * return. */ int -iptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle) +TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { int ret; struct { - struct ipt_entry head; + STRUCT_ENTRY head; struct ipt_error_target name; - struct ipt_entry ret; - struct ipt_standard_target target; + STRUCT_ENTRY ret; + STRUCT_STANDARD_TARGET target; } newc; - iptc_fn = iptc_create_chain; + iptc_fn = TC_CREATE_CHAIN; /* find_label doesn't cover built-in targets: DROP, ACCEPT, QUEUE, RETURN. */ if (find_label(chain, *handle) - || strcmp(chain, IPTC_LABEL_DROP) == 0 - || strcmp(chain, IPTC_LABEL_ACCEPT) == 0 + || strcmp(chain, LABEL_DROP) == 0 + || strcmp(chain, LABEL_ACCEPT) == 0 || strcmp(chain, IPTC_LABEL_QUEUE) == 0 - || strcmp(chain, IPTC_LABEL_RETURN) == 0) { + || strcmp(chain, LABEL_RETURN) == 0) { errno = EEXIST; return 0; } - if (strlen(chain)+1 > sizeof(ipt_chainlabel)) { + if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { errno = EINVAL; return 0; } memset(&newc, 0, sizeof(newc)); - newc.head.target_offset = sizeof(struct ipt_entry); + newc.head.target_offset = sizeof(STRUCT_ENTRY); newc.head.next_offset - = sizeof(struct ipt_entry) + sizeof(struct ipt_error_target); + = sizeof(STRUCT_ENTRY) + sizeof(struct ipt_error_target); strcpy(newc.name.t.u.user.name, IPT_ERROR_TARGET); newc.name.t.u.target_size = sizeof(struct ipt_error_target); strcpy(newc.name.error, chain); - newc.ret.target_offset = sizeof(struct ipt_entry); + newc.ret.target_offset = sizeof(STRUCT_ENTRY); newc.ret.next_offset - = sizeof(struct ipt_entry)+sizeof(struct ipt_standard_target); - strcpy(newc.target.target.u.user.name, IPT_STANDARD_TARGET); - newc.target.target.u.target_size = sizeof(struct ipt_standard_target); - newc.target.verdict = IPT_RETURN; + = sizeof(STRUCT_ENTRY)+sizeof(STRUCT_STANDARD_TARGET); + strcpy(newc.target.target.u.user.name, STANDARD_TARGET); + newc.target.target.u.target_size = sizeof(STRUCT_STANDARD_TARGET); + newc.target.verdict = RETURN; /* Add just before terminal entry */ ret = insert_rules(2, sizeof(newc), &newc.head, @@ -1389,12 +1255,12 @@ iptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle) } static int -count_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref) +count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref) { - struct ipt_standard_target *t; + STRUCT_STANDARD_TARGET *t; - if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) == 0) { - t = (struct ipt_standard_target *)ipt_get_target(e); + if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) { + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); if (t->verdict == offset) (*ref)++; @@ -1405,8 +1271,8 @@ count_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref) /* Get the number of references to this chain. */ int -iptc_get_references(unsigned int *ref, const ipt_chainlabel chain, - iptc_handle_t *handle) +TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, + TC_HANDLE_T *handle) { struct chain_cache *c; @@ -1416,27 +1282,27 @@ iptc_get_references(unsigned int *ref, const ipt_chainlabel chain, } *ref = 0; - IPT_ENTRY_ITERATE((*handle)->entries.entries, - (*handle)->entries.size, - count_ref, entry2offset(*handle, c->start), ref); + ENTRY_ITERATE((*handle)->entries.entries, + (*handle)->entries.size, + count_ref, entry2offset(*handle, c->start), ref); return 1; } /* Deletes a chain. */ int -iptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle) +TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { unsigned int labelidx, labeloff; unsigned int references; struct chain_cache *c; int ret; - if (!iptc_get_references(&references, chain, handle)) + if (!TC_GET_REFERENCES(&references, chain, handle)) return 0; - iptc_fn = iptc_delete_chain; + iptc_fn = TC_DELETE_CHAIN; - if (iptc_builtin(chain, *handle)) { + if (TC_BUILTIN(chain, *handle)) { errno = EINVAL; return 0; } @@ -1468,33 +1334,33 @@ iptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle) } /* Renames a chain. */ -int iptc_rename_chain(const ipt_chainlabel oldname, - const ipt_chainlabel newname, - iptc_handle_t *handle) +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 = iptc_rename_chain; + iptc_fn = TC_RENAME_CHAIN; /* find_label doesn't cover built-in targets: DROP, ACCEPT RETURN. */ if (find_label(newname, *handle) - || strcmp(newname, IPTC_LABEL_DROP) == 0 - || strcmp(newname, IPTC_LABEL_ACCEPT) == 0 - || strcmp(newname, IPTC_LABEL_RETURN) == 0) { + || strcmp(newname, LABEL_DROP) == 0 + || strcmp(newname, LABEL_ACCEPT) == 0 + || strcmp(newname, LABEL_RETURN) == 0) { errno = EEXIST; return 0; } if (!(c = find_label(oldname, *handle)) - || iptc_builtin(oldname, *handle)) { + || TC_BUILTIN(oldname, *handle)) { errno = ENOENT; return 0; } - if (strlen(newname)+1 > sizeof(ipt_chainlabel)) { + if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) { errno = EINVAL; return 0; } @@ -1504,7 +1370,7 @@ int iptc_rename_chain(const ipt_chainlabel oldname, labeloff = index2offset(*handle, labelidx); t = (struct ipt_error_target *) - ipt_get_target(get_entry(*handle, labeloff)); + GET_TARGET(get_entry(*handle, labeloff)); memset(t->error, 0, sizeof(t->error)); strcpy(t->error, newname); @@ -1515,18 +1381,18 @@ int iptc_rename_chain(const ipt_chainlabel oldname, /* Sets the policy on a built-in chain. */ int -iptc_set_policy(const ipt_chainlabel chain, - const ipt_chainlabel policy, - iptc_handle_t *handle) +TC_SET_POLICY(const IPT_CHAINLABEL chain, + const IPT_CHAINLABEL policy, + TC_HANDLE_T *handle) { unsigned int hook; unsigned int policyoff; - struct ipt_entry *e; - struct ipt_standard_target *t; + STRUCT_ENTRY *e; + STRUCT_STANDARD_TARGET *t; - iptc_fn = iptc_set_policy; + iptc_fn = TC_SET_POLICY; /* Figure out which chain. */ - hook = iptc_builtin(chain, *handle); + hook = TC_BUILTIN(chain, *handle); if (hook == 0) { errno = ENOENT; return 0; @@ -1541,11 +1407,11 @@ iptc_set_policy(const ipt_chainlabel chain, } e = get_entry(*handle, policyoff); - t = (struct ipt_standard_target *)ipt_get_target(e); + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); - if (strcmp(policy, IPTC_LABEL_ACCEPT) == 0) + if (strcmp(policy, LABEL_ACCEPT) == 0) t->verdict = -NF_ACCEPT - 1; - else if (strcmp(policy, IPTC_LABEL_DROP) == 0) + else if (strcmp(policy, LABEL_DROP) == 0) t->verdict = -NF_DROP - 1; else { errno = EINVAL; @@ -1559,34 +1425,34 @@ iptc_set_policy(const ipt_chainlabel chain, } /* Without this, on gcc 2.7.2.3, we get: - libiptc.c: In function `iptc_commit': + 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 ipt_counters *answer, - const struct ipt_counters *a, - const struct ipt_counters *b) +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 -iptc_commit(iptc_handle_t *handle) +TC_COMMIT(TC_HANDLE_T *handle) { /* Replace, then map back the counters. */ - struct ipt_replace *repl; - struct ipt_counters_info *newcounters; + STRUCT_REPLACE *repl; + STRUCT_COUNTERS_INFO *newcounters; unsigned int i; size_t counterlen - = sizeof(struct ipt_counters_info) - + sizeof(struct ipt_counters) * (*handle)->new_number; + = sizeof(STRUCT_COUNTERS_INFO) + + sizeof(STRUCT_COUNTERS) * (*handle)->new_number; CHECK(*handle); #if 0 - dump_entries(*handle); + TC_TC_DUMP_ENTRIES(*handle); #endif /* Don't commit if nothing changed. */ @@ -1600,7 +1466,7 @@ iptc_commit(iptc_handle_t *handle) } /* These are the old counters we will get from kernel */ - repl->counters = malloc(sizeof(struct ipt_counters) + repl->counters = malloc(sizeof(STRUCT_COUNTERS) * (*handle)->info.num_entries); if (!repl->counters) { free(repl); @@ -1629,7 +1495,7 @@ iptc_commit(iptc_handle_t *handle) memcpy(repl->entries, (*handle)->entries.entries, (*handle)->entries.size); - if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_REPLACE, repl, + if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, sizeof(*repl) + (*handle)->entries.size) < 0) { free(repl->counters); free(repl); @@ -1645,7 +1511,7 @@ iptc_commit(iptc_handle_t *handle) switch ((*handle)->counter_map[i].maptype) { case COUNTER_MAP_NOMAP: newcounters->counters[i] - = ((struct ipt_counters){ 0, 0 }); + = ((STRUCT_COUNTERS){ 0, 0 }); break; case COUNTER_MAP_NORMAL_MAP: @@ -1674,8 +1540,8 @@ iptc_commit(iptc_handle_t *handle) } } - if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_ADD_COUNTERS, - newcounters, counterlen) < 0) { + if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, + newcounters, counterlen) < 0) { free(repl->counters); free(repl); free(newcounters); @@ -1696,14 +1562,14 @@ iptc_commit(iptc_handle_t *handle) /* Get raw socket. */ int -iptc_get_raw_socket() +TC_GET_RAW_SOCKET() { return sockfd; } /* Translates errno numbers into more human-readable form than strerror. */ const char * -iptc_strerror(int err) +TC_STRERROR(int err) { unsigned int i; struct table_struct { @@ -1715,27 +1581,27 @@ iptc_strerror(int err) { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, { NULL, ENOSYS, "Will be implemented real soon. I promise." }, { NULL, ENOMEM, "Memory allocation problem" }, - { iptc_init, EPERM, "Permission denied (you must be root)" }, - { iptc_init, EINVAL, "Module is wrong version" }, - { iptc_delete_chain, ENOTEMPTY, "Chain is not empty" }, - { iptc_delete_chain, EINVAL, "Can't delete built-in chain" }, - { iptc_delete_chain, EMLINK, + { TC_INIT, EPERM, "Permission denied (you must be root)" }, + { TC_INIT, EINVAL, "Module is wrong version" }, + { 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" }, - { iptc_create_chain, EEXIST, "Chain already exists" }, - { iptc_insert_entry, E2BIG, "Index of insertion too big" }, - { iptc_replace_entry, E2BIG, "Index of replacement too big" }, - { iptc_delete_num_entry, E2BIG, "Index of deletion too big" }, - { iptc_insert_entry, ELOOP, "Loop found in table" }, - { iptc_insert_entry, EINVAL, "Target problem" }, + { 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_INSERT_ENTRY, ELOOP, "Loop found in table" }, + { TC_INSERT_ENTRY, EINVAL, "Target problem" }, /* EINVAL for CHECK probably means bad interface. */ - { iptc_check_packet, EINVAL, + { TC_CHECK_PACKET, EINVAL, "Bad arguments (does that interface exist?)" }, /* ENOENT for DELETE probably means no matching rule */ - { iptc_delete_entry, ENOENT, + { TC_DELETE_ENTRY, ENOENT, "Bad rule (does a matching rule exist in that chain?)" }, - { iptc_set_policy, ENOENT, + { TC_SET_POLICY, ENOENT, "Bad built-in chain name" }, - { iptc_set_policy, EINVAL, + { TC_SET_POLICY, EINVAL, "Bad policy name" }, { NULL, ENOENT, "No extended target/match by that name" } }; @@ -1748,218 +1614,3 @@ iptc_strerror(int err) return strerror(err); } - -/***************************** DEBUGGING ********************************/ -static inline int -unconditional(const struct ipt_ip *ip) -{ - unsigned int i; - - for (i = 0; i < sizeof(*ip)/sizeof(u_int32_t); i++) - if (((u_int32_t *)ip)[i]) - return 0; - - return 1; -} - -static inline int -check_match(const struct ipt_entry_match *m, unsigned int *off) -{ - assert(m->u.match_size >= sizeof(struct ipt_entry_match)); - assert(IPT_ALIGN(m->u.match_size) == m->u.match_size); - - (*off) += m->u.match_size; - return 0; -} - -static inline int -check_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, - unsigned int user_offset, int *was_return, - iptc_handle_t h) -{ - unsigned int toff; - struct ipt_standard_target *t; - - assert(e->target_offset >= sizeof(struct ipt_entry)); - assert(e->next_offset >= e->target_offset - + sizeof(struct ipt_entry_target)); - toff = sizeof(struct ipt_entry); - IPT_MATCH_ITERATE(e, check_match, &toff); - - assert(toff == e->target_offset); - - t = (struct ipt_standard_target *) - ipt_get_target((struct ipt_entry *)e); - /* next_offset will have to be multiple of entry alignment. */ - assert(e->next_offset == IPT_ALIGN(e->next_offset)); - assert(e->target_offset == IPT_ALIGN(e->target_offset)); - assert(t->target.u.target_size == IPT_ALIGN(t->target.u.target_size)); - assert(!iptc_is_chain(t->target.u.user.name, h)); - - if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0) { - assert(t->target.u.target_size - == IPT_ALIGN(sizeof(struct ipt_standard_target))); - - assert(t->verdict == -NF_DROP-1 - || t->verdict == -NF_ACCEPT-1 - || t->verdict == IPT_RETURN - || t->verdict < (int)h->entries.size); - - if (t->verdict >= 0) { - struct ipt_entry *te = get_entry(h, t->verdict); - int idx; - - idx = entry2index(h, te); - assert(strcmp(ipt_get_target(te)->u.user.name, - IPT_ERROR_TARGET) - != 0); - assert(te != e); - - /* Prior node must be error node, or this node. */ - assert(t->verdict == entry2offset(h, e)+e->next_offset - || strcmp(ipt_get_target(index2entry(h, idx-1)) - ->u.user.name, IPT_ERROR_TARGET) - == 0); - } - - if (t->verdict == IPT_RETURN - && unconditional(&e->ip) - && e->target_offset == sizeof(*e)) - *was_return = 1; - else - *was_return = 0; - } else if (strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0) { - assert(t->target.u.target_size - == IPT_ALIGN(sizeof(struct ipt_error_target))); - - /* If this is in user area, previous must have been return */ - if (*off > user_offset) - assert(*was_return); - - *was_return = 0; - } - else *was_return = 0; - - if (*off == user_offset) - assert(strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0); - - (*off) += e->next_offset; - (*i)++; - return 0; -} - -#ifndef NDEBUG -/* Do every conceivable sanity check on the handle */ -static void -do_check(iptc_handle_t h, unsigned int line) -{ - unsigned int i, n; - unsigned int user_offset; /* Offset of first user chain */ - int was_return; - - assert(h->changed == 0 || h->changed == 1); - if (strcmp(h->info.name, "filter") == 0) { - assert(h->info.valid_hooks - == (1 << NF_IP_LOCAL_IN - | 1 << NF_IP_FORWARD - | 1 << NF_IP_LOCAL_OUT)); - - /* Hooks should be first three */ - assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0); - - n = get_chain_end(h, 0); - n += get_entry(h, n)->next_offset; - assert(h->info.hook_entry[NF_IP_FORWARD] == n); - - n = get_chain_end(h, n); - n += get_entry(h, n)->next_offset; - assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); - - user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; - } else if (strcmp(h->info.name, "nat") == 0) { - assert(h->info.valid_hooks - == (1 << NF_IP_PRE_ROUTING - | 1 << NF_IP_POST_ROUTING - | 1 << NF_IP_LOCAL_OUT)); - - assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); - - n = get_chain_end(h, 0); - n += get_entry(h, n)->next_offset; - assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n); - - n = get_chain_end(h, n); - n += get_entry(h, n)->next_offset; - assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); - - user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; - } else if (strcmp(h->info.name, "mangle") == 0) { - assert(h->info.valid_hooks - == (1 << NF_IP_PRE_ROUTING - | 1 << NF_IP_LOCAL_OUT)); - - /* Hooks should be first three */ - assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); - - n = get_chain_end(h, 0); - n += get_entry(h, n)->next_offset; - assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); - - user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; - } else - abort(); - - /* User chain == end of last builtin + policy entry */ - user_offset = get_chain_end(h, user_offset); - user_offset += get_entry(h, user_offset)->next_offset; - - /* Overflows should be end of entry chains, and unconditional - policy nodes. */ - for (i = 0; i < NF_IP_NUMHOOKS; i++) { - struct ipt_entry *e; - struct ipt_standard_target *t; - - if (!(h->info.valid_hooks & (1 << i))) - continue; - assert(h->info.underflow[i] - == get_chain_end(h, h->info.hook_entry[i])); - - e = get_entry(h, get_chain_end(h, h->info.hook_entry[i])); - assert(unconditional(&e->ip)); - assert(e->target_offset == sizeof(*e)); - assert(e->next_offset == sizeof(*e) + sizeof(*t)); - t = (struct ipt_standard_target *)ipt_get_target(e); - - assert(strcmp(t->target.u.user.name, IPT_STANDARD_TARGET)==0); - assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1); - - /* Hooks and underflows must be valid entries */ - entry2index(h, get_entry(h, h->info.hook_entry[i])); - entry2index(h, get_entry(h, h->info.underflow[i])); - } - - assert(h->info.size - >= h->info.num_entries * (sizeof(struct ipt_entry) - +sizeof(struct ipt_standard_target))); - - assert(h->entries.size - >= (h->new_number - * (sizeof(struct ipt_entry) - + sizeof(struct ipt_standard_target)))); - assert(strcmp(h->info.name, h->entries.name) == 0); - - i = 0; n = 0; - was_return = 0; - /* Check all the entries. */ - IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, - check_entry, &i, &n, user_offset, &was_return, h); - - assert(i == h->new_number); - assert(n == h->entries.size); - - /* Final entry must be error node */ - assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1)) - ->u.user.name, - IPT_ERROR_TARGET) == 0); -} -#endif /*NDEBUG*/ -- cgit v1.2.3