From 7c634a2c1c4b4a866faee328d206195e7857d194 Mon Sep 17 00:00:00 2001 From: "/C=JP/ST=JP/CN=Yasuyuki Kozakai/emailAddress=yasuyuki@netfilter.org" Date: Tue, 24 Jul 2007 05:52:07 +0000 Subject: Introduces xtables match/target registration - moves lib_dir to xtables.c - introduces struct pfinfo which has protocol family dependent infomations. - unifies load_ip[6]tables_ko() and moves them as load_xtables_ko() - introduces xt_{match,match_rule,target,tryload} and replaces ip[6]t_* with them - unifies following functions and move them to xtables.c - find_{match,find_target} - compatible_revision, compatible_{match,target}_revision - introduces xtables_register_{match,target} and make register_{match,target}[6] call them. xtables_register_* register ONLY matches/targets matched protocol family Some concepts: - source compatibility for libip[6]t_xxx.c with warning on compilation not binary compatibility. - binary compatibility between 2.4/2.6 kernel and iptables/ip6tables, of cause. - xtables is enough to support only one address family at runtime. Then xtables keeps infomations of only the focused address famiy in struct afinfo. --- iptables.c | 331 ++++--------------------------------------------------------- 1 file changed, 21 insertions(+), 310 deletions(-) (limited to 'iptables.c') diff --git a/iptables.c b/iptables.c index 39b8e01..47de864 100644 --- a/iptables.c +++ b/iptables.c @@ -187,15 +187,9 @@ static int inverse_for_options[NUMBER_OF_OPT] = const char *program_version; const char *program_name; -char *lib_dir; int kernel_version; -/* 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 @@ -205,6 +199,15 @@ struct pprot { u_int8_t num; }; +struct afinfo afinfo = { + .family = AF_INET, + .libprefix = "libipt_", + .ipproto = IPPROTO_IP, + .kmod = "ip_tables", + .so_rev_match = IPT_SO_GET_REVISION_MATCH, + .so_rev_target = IPT_SO_GET_REVISION_TARGET, +}; + /* Primitive headers... */ /* defined in netinet/in.h */ #if 0 @@ -472,7 +475,7 @@ exit_printhelp(struct iptables_rule_match *matches) /* Print out any special helps. A user might like to be able to add a --help to the commandline, and see expected results. So we call help for all specified matches & targets */ - for (t = iptables_targets; t ;t = t->next) { + for (t = xtables_targets; t ;t = t->next) { if (t->used) { printf("\n"); t->help(); @@ -698,82 +701,6 @@ parse_hostnetworkmask(const char *name, struct in_addr **addrpp, } } -struct iptables_match * -find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_match **matches) -{ - struct iptables_match *ptr; - - for (ptr = iptables_matches; ptr; ptr = ptr->next) { - if (strcmp(name, ptr->name) == 0) { - struct iptables_match *clone; - - /* First match of this type: */ - if (ptr->m == NULL) - break; - - /* Second and subsequent clones */ - clone = fw_malloc(sizeof(struct iptables_match)); - memcpy(clone, ptr, sizeof(struct iptables_match)); - clone->mflags = 0; - /* This is a clone: */ - clone->next = clone; - - ptr = clone; - break; - } - } - -#ifndef NO_SHARED_LIBS - if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) { - char path[strlen(lib_dir) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, "%s/libipt_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) { - /* Found library. If it didn't register itself, - maybe they specified target as match. */ - ptr = find_match(name, DONT_LOAD, NULL); - - if (!ptr) - exit_error(PARAMETER_PROBLEM, - "Couldn't load match `%s'\n", - name); - } else if (tryload == LOAD_MUST_SUCCEED) - exit_error(PARAMETER_PROBLEM, - "Couldn't load match `%s':%s\n", - name, dlerror()); - } -#else - if (ptr && !ptr->loaded) { - if (tryload != DONT_LOAD) - ptr->loaded = 1; - else - ptr = NULL; - } - if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { - exit_error(PARAMETER_PROBLEM, - "Couldn't find match `%s'\n", name); - } -#endif - - if (ptr && matches) { - struct iptables_rule_match **i; - struct iptables_rule_match *newentry; - - newentry = fw_malloc(sizeof(struct iptables_rule_match)); - - for (i = matches; *i; i = &(*i)->next) { - if (strcmp(name, (*i)->match->name) == 0) - (*i)->completed = 1; - } - newentry->match = ptr; - newentry->completed = 0; - newentry->next = NULL; - *i = newentry; - } - - return ptr; -} - /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ static struct iptables_match * find_proto(const char *pname, enum ipt_tryload tryload, int nolookup, struct iptables_rule_match **matches) @@ -1025,61 +952,6 @@ set_option(unsigned int *options, unsigned int option, u_int8_t *invflg, } } -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 && tryload != DURING_LOAD) { - char path[strlen(lib_dir) + sizeof("/libipt_.so") - + strlen(name)]; - sprintf(path, "%s/libipt_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) { - /* Found library. If it didn't register itself, - maybe they specified match as a target. */ - ptr = find_target(name, DONT_LOAD); - if (!ptr) - exit_error(PARAMETER_PROBLEM, - "Couldn't load target `%s'\n", - name); - } else if (tryload == LOAD_MUST_SUCCEED) - exit_error(PARAMETER_PROBLEM, - "Couldn't load target `%s':%s\n", - name, dlerror()); - } -#else - if (ptr && !ptr->loaded) { - if (tryload != DONT_LOAD) - ptr->loaded = 1; - else - ptr = NULL; - } - if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { - exit_error(PARAMETER_PROBLEM, - "Couldn't find target `%s'\n", name); - } -#endif - - if (ptr) - ptr->used = 1; - - return ptr; -} - static struct option * merge_options(struct option *oldopts, const struct option *newopts, unsigned int *option_offset) @@ -1105,164 +977,16 @@ merge_options(struct option *oldopts, const struct option *newopts, return merge; } -static int compatible_revision(const char *name, u_int8_t revision, int opt) +void register_match(struct iptables_match *me) { - struct ipt_get_revision rev; - socklen_t s = sizeof(rev); - int max_rev, sockfd; - - sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (sockfd < 0) { - fprintf(stderr, "Could not open socket to kernel: %s\n", - strerror(errno)); - exit(1); - } - - load_iptables_ko(modprobe, 1); - - strcpy(rev.name, name); - rev.revision = revision; - - max_rev = getsockopt(sockfd, IPPROTO_IP, opt, &rev, &s); - if (max_rev < 0) { - /* Definitely don't support this? */ - if (errno == ENOENT || errno == EPROTONOSUPPORT) { - close(sockfd); - return 0; - } else if (errno == ENOPROTOOPT) { - close(sockfd); - /* Assume only revision 0 support (old kernel) */ - return (revision == 0); - } else { - fprintf(stderr, "getsockopt failed strangely: %s\n", - strerror(errno)); - exit(1); - } - } - close(sockfd); - return 1; -} - -static int compatible_match_revision(const char *name, u_int8_t revision) -{ - return compatible_revision(name, revision, IPT_SO_GET_REVISION_MATCH); -} - -static int compatible_target_revision(const char *name, u_int8_t revision) -{ - return compatible_revision(name, revision, IPT_SO_GET_REVISION_TARGET); -} - -void -register_match(struct iptables_match *me) -{ - struct iptables_match **i, *old; - - if (strcmp(me->version, program_version) != 0) { - fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n", - program_name, me->name, me->version, program_version); - exit(1); - } - - /* Revision field stole a char from name. */ - if (strlen(me->name) >= IPT_FUNCTION_MAXNAMELEN-1) { - fprintf(stderr, "%s: target `%s' has invalid name\n", - program_name, me->name); - exit(1); - } - - old = find_match(me->name, DURING_LOAD, NULL); - if (old) { - if (old->revision == me->revision) { - fprintf(stderr, - "%s: match `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - /* Now we have two (or more) options, check compatibility. */ - if (compatible_match_revision(old->name, old->revision) - && old->revision > me->revision) - return; - - /* Replace if compatible. */ - if (!compatible_match_revision(me->name, me->revision)) - return; - - /* Delete old one. */ - for (i = &iptables_matches; *i!=old; i = &(*i)->next); - *i = old->next; - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: match `%s' has invalid size %u.\n", - program_name, me->name, (unsigned int)me->size); - exit(1); - } - - /* Append to list. */ - for (i = &iptables_matches; *i; i = &(*i)->next); - me->next = NULL; - *i = me; - - me->m = NULL; - me->mflags = 0; + me->family = PF_INET; + xtables_register_match(me); } -void -register_target(struct iptables_target *me) +void register_target(struct iptables_target *me) { - struct iptables_target *old; - - 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); - } - - /* Revision field stole a char from name. */ - if (strlen(me->name) >= IPT_FUNCTION_MAXNAMELEN-1) { - fprintf(stderr, "%s: target `%s' has invalid name\n", - program_name, me->name); - exit(1); - } - - old = find_target(me->name, DURING_LOAD); - if (old) { - struct iptables_target **i; - - if (old->revision == me->revision) { - fprintf(stderr, - "%s: target `%s' already registered.\n", - program_name, me->name); - exit(1); - } - - /* Now we have two (or more) options, check compatibility. */ - if (compatible_target_revision(old->name, old->revision) - && old->revision > me->revision) - return; - - /* Replace if compatible. */ - if (!compatible_target_revision(me->name, me->revision)) - return; - - /* Delete old one. */ - for (i = &iptables_targets; *i!=old; i = &(*i)->next); - *i = old->next; - } - - if (me->size != IPT_ALIGN(me->size)) { - fprintf(stderr, "%s: target `%s' has invalid size %u.\n", - program_name, me->name, (unsigned int)me->size); - exit(1); - } - - /* Prepend to list. */ - me->next = iptables_targets; - iptables_targets = me; - me->t = NULL; - me->tflags = 0; + me->family = PF_INET; + xtables_register_target(me); } static void @@ -1580,7 +1304,7 @@ make_delete_mask(struct ipt_entry *fw, struct iptables_rule_match *matches) mask = fw_calloc(1, size + IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->size); + + xtables_targets->size); memset(mask, 0xFF, sizeof(struct ipt_entry)); mptr = mask + sizeof(struct ipt_entry); @@ -1594,7 +1318,7 @@ make_delete_mask(struct ipt_entry *fw, struct iptables_rule_match *matches) memset(mptr, 0xFF, IPT_ALIGN(sizeof(struct ipt_entry_target)) - + iptables_targets->userspacesize); + + xtables_targets->userspacesize); return mask; } @@ -1754,19 +1478,6 @@ list_entries(const ipt_chainlabel chain, int verbose, int numeric, return found; } -int load_iptables_ko(const char *modprobe, int quiet) -{ - static int loaded = 0; - static int ret = -1; - - if (!loaded) { - ret = xtables_insmod("ip_tables", modprobe, quiet); - loaded = (ret == 0); - } - - return ret; -} - static struct ipt_entry * generate_entry(const struct ipt_entry *fw, struct iptables_rule_match *matches, @@ -1870,10 +1581,10 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) /* clear mflags in case do_command gets called a second time * (we clear the global list of all matches for security)*/ - for (m = iptables_matches; m; m = m->next) + for (m = xtables_matches; m; m = m->next) m->mflags = 0; - for (t = iptables_targets; t; t = t->next) { + for (t = xtables_targets; t; t = t->next) { t->tflags = 0; t->used = 0; } @@ -2347,7 +2058,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) *handle = iptc_init(*table); /* try to insmod the module if iptc_init failed */ - if (!*handle && load_iptables_ko(modprobe, 0) != -1) + if (!*handle && load_xtables_ko(modprobe, 0) != -1) *handle = iptc_init(*table); if (!*handle) -- cgit v1.2.3