/**
* xtables_afinfo - protocol family dependent information
* @kmod: kernel module basename (e.g. "ip_tables")
+ * @proc_exists: file which exists in procfs when module already loaded
* @libprefix: prefix of .so library name (e.g. "libipt_")
* @family: nfproto family
* @ipproto: used by setsockopt (e.g. IPPROTO_IP)
*/
struct xtables_afinfo {
const char *kmod;
+ const char *proc_exists;
const char *libprefix;
uint8_t family;
uint8_t ipproto;
#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 */
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,
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,
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;
}