diff options
Diffstat (limited to 'xtables.c')
-rw-r--r-- | xtables.c | 104 |
1 files changed, 93 insertions, 11 deletions
@@ -27,9 +27,11 @@ #include <unistd.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/statfs.h> #include <sys/types.h> #include <sys/wait.h> #include <arpa/inet.h> +#include <linux/magic.h> /* for PROC_SUPER_MAGIC */ #include <xtables.h> #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */ @@ -58,6 +60,12 @@ #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #endif +/* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the + * current line of the input file, in order to give a more precise error + * message. ip6?tables itself doesn't need this, so it is initialized to the + * magic number of -1 */ +int line = -1; + void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); struct xtables_globals *xt_params = NULL; @@ -133,6 +141,7 @@ struct option *xtables_merge_options(struct option *orig_opts, static const struct xtables_afinfo afinfo_ipv4 = { .kmod = "ip_tables", + .proc_exists = "/proc/net/ip_tables_names", .libprefix = "libipt_", .family = NFPROTO_IPV4, .ipproto = IPPROTO_IP, @@ -142,6 +151,7 @@ static const struct xtables_afinfo afinfo_ipv4 = { static const struct xtables_afinfo afinfo_ipv6 = { .kmod = "ip6_tables", + .proc_exists = "/proc/net/ip6_tables_names", .libprefix = "libip6t_", .family = NFPROTO_IPV6, .ipproto = IPPROTO_IPV6, @@ -157,10 +167,18 @@ static const char *xtables_libdir; /* the path to command to load kernel module */ const char *xtables_modprobe_program; -/* Keeping track of external matches and targets: linked lists. */ +/* Keep track of matches/targets pending full registration: linked lists. */ +struct xtables_match *xtables_pending_matches; +struct xtables_target *xtables_pending_targets; + +/* Keep track of fully registered external matches/targets: linked lists. */ struct xtables_match *xtables_matches; struct xtables_target *xtables_targets; +/* Fully register a match/target which was previously partially registered. */ +static void xtables_fully_register_pending_match(struct xtables_match *me); +static void xtables_fully_register_pending_target(struct xtables_target *me); + void xtables_init(void) { xtables_libdir = getenv("XTABLES_LIBDIR"); @@ -355,15 +373,39 @@ int xtables_insmod(const char *modname, const char *modprobe, bool quiet) return -1; } +/* return true if a given file exists within procfs */ +static bool proc_file_exists(const char *filename) +{ + struct stat s; + struct statfs f; + + if (lstat(filename, &s)) + return false; + if (!S_ISREG(s.st_mode)) + return false; + if (statfs(filename, &f)) + return false; + if (f.f_type != PROC_SUPER_MAGIC) + return false; + return true; +} + int xtables_load_ko(const char *modprobe, bool quiet) { static bool loaded = false; - static int ret = -1; + int ret; - if (!loaded) { - ret = xtables_insmod(afinfo->kmod, modprobe, quiet); - loaded = (ret == 0); - } + if (loaded) + return 0; + + if (proc_file_exists(afinfo->proc_exists)) { + loaded = true; + return 0; + }; + + ret = xtables_insmod(afinfo->kmod, modprobe, quiet); + if (ret == 0) + loaded = true; return ret; } @@ -539,6 +581,7 @@ struct xtables_match * xtables_find_match(const char *name, enum xtables_tryload tryload, struct xtables_rule_match **matches) { + struct xtables_match **dptr; struct xtables_match *ptr; const char *icmp6 = "icmp6"; @@ -554,6 +597,18 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, (strcmp(name,"icmp6") == 0) ) name = icmp6; + /* Trigger delayed initialization */ + for (dptr = &xtables_pending_matches; *dptr; ) { + if (strcmp(name, (*dptr)->name) == 0) { + ptr = *dptr; + *dptr = (*dptr)->next; + ptr->next = NULL; + xtables_fully_register_pending_match(ptr); + } else { + dptr = &((*dptr)->next); + } + } + for (ptr = xtables_matches; ptr; ptr = ptr->next) { if (strcmp(name, ptr->name) == 0) { struct xtables_match *clone; @@ -619,6 +674,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, struct xtables_target * xtables_find_target(const char *name, enum xtables_tryload tryload) { + struct xtables_target **dptr; struct xtables_target *ptr; /* Standard target? */ @@ -629,6 +685,18 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) || strcmp(name, XTC_LABEL_RETURN) == 0) name = "standard"; + /* Trigger delayed initialization */ + for (dptr = &xtables_pending_targets; *dptr; ) { + if (strcmp(name, (*dptr)->name) == 0) { + ptr = *dptr; + *dptr = (*dptr)->next; + ptr->next = NULL; + xtables_fully_register_pending_target(ptr); + } else { + dptr = &((*dptr)->next); + } + } + for (ptr = xtables_targets; ptr; ptr = ptr->next) { if (strcmp(name, ptr->name) == 0) break; @@ -740,8 +808,6 @@ static void xtables_check_options(const char *name, const struct option *opt) void xtables_register_match(struct xtables_match *me) { - struct xtables_match **i, *old; - if (me->version == NULL) { fprintf(stderr, "%s: match %s<%u> is missing a version\n", xt_params->program_name, me->name, me->revision); @@ -777,6 +843,15 @@ void xtables_register_match(struct xtables_match *me) if (me->family != afinfo->family && me->family != AF_UNSPEC) return; + /* place on linked list of matches pending full registration */ + me->next = xtables_pending_matches; + xtables_pending_matches = me; +} + +static void xtables_fully_register_pending_match(struct xtables_match *me) +{ + struct xtables_match **i, *old; + old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); if (old) { if (old->revision == me->revision && @@ -830,8 +905,6 @@ void xtables_register_matches(struct xtables_match *match, unsigned int n) void xtables_register_target(struct xtables_target *me) { - struct xtables_target *old; - if (me->version == NULL) { fprintf(stderr, "%s: target %s<%u> is missing a version\n", xt_params->program_name, me->name, me->revision); @@ -867,6 +940,15 @@ void xtables_register_target(struct xtables_target *me) if (me->family != afinfo->family && me->family != AF_UNSPEC) return; + /* place on linked list of targets pending full registration */ + me->next = xtables_pending_targets; + xtables_pending_targets = me; +} + +static void xtables_fully_register_pending_target(struct xtables_target *me) +{ + struct xtables_target *old; + old = xtables_find_target(me->name, XTF_DURING_LOAD); if (old) { struct xtables_target **i; @@ -1323,7 +1405,7 @@ void xtables_ipparse_any(const char *name, struct in_addr **addrpp, const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp) { - /* 0000:0000:0000:0000:0000:000.000.000.000 + /* 0000:0000:0000:0000:0000:0000:000.000.000.000 * 0000:0000:0000:0000:0000:0000:0000:0000 */ static char buf[50+1]; return inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); |