summaryrefslogtreecommitdiffstats
path: root/iptables.c
diff options
context:
space:
mode:
authorYasuyuki KOZAKAI <yasuyuki@netfilter.org>2007-07-24 05:52:07 +0000
committerYasuyuki KOZAKAI <yasuyuki@netfilter.org>2007-07-24 05:52:07 +0000
commit0d502bcdbc97ed359e84f6a21dfa0049b3b60a6c (patch)
tree537187d08bae1bac51328c5d27f3c24f72b6cc06 /iptables.c
parent0b82e8e81e887843011c8771f70d2302901f7e5e (diff)
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.
Diffstat (limited to 'iptables.c')
-rw-r--r--iptables.c331
1 files changed, 21 insertions, 310 deletions
diff --git a/iptables.c b/iptables.c
index 39b8e015..47de8648 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)