--- /dev/null
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/version.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
+#include "compat_xtnu.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && \
+ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
+static int xtnu_match_run(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *cm, const void *matchinfo, int offset,
+ unsigned int protoff, int *hotdrop)
+{
+ struct xtnu_match *nm = xtcompat_numatch(cm);
+ bool lo_drop, lo_ret;
+
+ if (nm == NULL || nm->match == NULL)
+ return false;
+ lo_ret = nm->match(skb, in, out, nm, matchinfo,
+ offset, protoff, &lo_drop);
+ *hotdrop = lo_drop;
+ return lo_ret;
+}
+
+static int xtnu_match_check(const char *table, const void *entry,
+ const struct xt_match *cm, void *matchinfo, unsigned int hook_mask)
+{
+ struct xtnu_match *nm = xtcompat_numatch(cm);
+
+ if (nm == NULL)
+ return false;
+ if (nm->checkentry == NULL)
+ return true;
+ return nm->checkentry(table, entry, nm, matchinfo, hook_mask);
+}
+
+static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo)
+{
+ struct xtnu_match *nm = xtcompat_numatch(cm);
+
+ if (nm != NULL && nm->destroy != NULL)
+ nm->destroy(nm, matchinfo);
+}
+
+int xtnu_register_match(struct xtnu_match *nt)
+{
+ struct xt_match *ct;
+ char *tmp;
+ int ret;
+
+ ct = kzalloc(sizeof(struct xt_match), GFP_KERNEL);
+ if (ct == NULL)
+ return -ENOMEM;
+
+ tmp = (char *)ct->name;
+ memcpy(tmp, nt->name, sizeof(nt->name));
+ tmp = (char *)(ct->name + sizeof(ct->name) - sizeof(void *));
+ *(tmp-1) = '\0';
+ memcpy(tmp, &nt, sizeof(void *));
+
+ ct->revision = nt->revision;
+ ct->family = nt->family;
+ ct->table = (char *)nt->table;
+ ct->hooks = nt->hooks;
+ ct->proto = nt->proto;
+ ct->match = xtnu_match_run;
+ ct->checkentry = xtnu_match_check;
+ ct->destroy = xtnu_match_destroy;
+ ct->matchsize = nt->matchsize;
+ ct->me = nt->me;
+
+ nt->__compat_match = ct;
+ ret = xt_register_match(ct);
+ if (ret != 0)
+ kfree(ct);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xtnu_register_match);
+
+int xtnu_register_matches(struct xtnu_match *nt, unsigned int num)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num; ++i) {
+ ret = xtnu_register_match(&nt[i]);
+ if (ret < 0) {
+ if (i > 0)
+ xtnu_unregister_matches(nt, i);
+ return ret;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xtnu_register_matches);
+
+void xtnu_unregister_match(struct xtnu_match *nt)
+{
+ xt_unregister_match(nt->__compat_match);
+ kfree(nt->__compat_match);
+}
+EXPORT_SYMBOL_GPL(xtnu_unregister_match);
+
+void xtnu_unregister_matches(struct xtnu_match *nt, unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; ++i)
+ xtnu_unregister_match(&nt[i]);
+}
+EXPORT_SYMBOL_GPL(xtnu_unregister_matches);
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
+static int xtnu_target_check(const char *table, const void *entry,
+ const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
+{
+ struct xtnu_target *nt = xtcompat_nutarget(ct);
+ if (nt == NULL)
+ return false;
+ if (nt->checkentry == NULL)
+ /* this is valid, just like if there was no function */
+ return true;
+ return nt->checkentry(table, entry, nt, targinfo, hook_mask);
+}
+#endif
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 23)
+static bool xtnu_target_check(const char *table, const void *entry,
+ const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
+{
+ struct xtnu_target *nt = xtcompat_nutarget(ct);
+ if (nt == NULL)
+ return false;
+ if (nt->checkentry == NULL)
+ /* this is valid, just like if there was no function */
+ return true;
+ return nt->checkentry(table, entry, nt, targinfo, hook_mask);
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && \
+ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+static unsigned int xtnu_target_run(struct sk_buff **pskb,
+ const struct net_device *in, const struct net_device *out,
+ unsigned int hooknum, const struct xt_target *ct, const void *targinfo)
+{
+ struct xtnu_target *nt = xtcompat_nutarget(ct);
+ if (nt != NULL && nt->target != NULL)
+ return nt->target(*pskb, in, out, hooknum, nt, targinfo);
+ return XT_CONTINUE;
+}
+
+static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo)
+{
+ struct xtnu_target *nt = xtcompat_nutarget(ct);
+ if (nt != NULL && nt->destroy != NULL)
+ nt->destroy(nt, targinfo);
+}
+
+int xtnu_register_target(struct xtnu_target *nt)
+{
+ struct xt_target *ct;
+ char *tmp;
+ int ret;
+
+ ct = kzalloc(sizeof(struct xt_target), GFP_KERNEL);
+ if (ct == NULL)
+ return -ENOMEM;
+
+ tmp = (char *)ct->name;
+ memcpy(tmp, nt->name, sizeof(nt->name));
+ tmp = (char *)(ct->name + sizeof(ct->name) - sizeof(void *));
+ *(tmp-1) = '\0';
+ memcpy(tmp, &nt, sizeof(void *));
+
+ ct->revision = nt->revision;
+ ct->family = nt->family;
+ ct->table = (char *)nt->table;
+ ct->hooks = nt->hooks;
+ ct->proto = nt->proto;
+ ct->target = xtnu_target_run;
+ ct->checkentry = xtnu_target_check;
+ ct->destroy = xtnu_target_destroy;
+ ct->targetsize = nt->targetsize;
+ ct->me = nt->me;
+
+ nt->__compat_target = ct;
+ ret = xt_register_target(ct);
+ if (ret != 0)
+ kfree(ct);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xtnu_register_target);
+
+void xtnu_unregister_target(struct xtnu_target *nt)
+{
+ xt_unregister_target(nt->__compat_target);
+ kfree(nt->__compat_target);
+}
+EXPORT_SYMBOL_GPL(xtnu_unregister_target);
+
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+int xtnu_ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
+{
+ return ip_route_me_harder(&skb, addr_type);
+}
+EXPORT_SYMBOL_GPL(xtnu_ip_route_me_harder);
+#endif
+
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef _XTABLES_COMPAT_H
+#define _XTABLES_COMPAT_H 1
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+# define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING
+# define NF_INET_LOCAL_IN NF_IP_LOCAL_IN
+# define NF_INET_FORWARD NF_IP_FORWARD
+# define NF_INET_LOCAL_OUT NF_IP_LOCAL_OUT
+# define NF_INET_POST_ROUTING NF_IP_POST_ROUTING
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
+# include "compat_nfinetaddr.h"
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
+# define xt_match xtnu_match
+# define xt_register_match xtnu_register_match
+# define xt_unregister_match xtnu_unregister_match
+# define xt_register_matches xtnu_register_matches
+# define xt_unregister_matches xtnu_unregister_matches
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+# define xt_target xtnu_target
+# define ip_route_me_harder xtnu_ip_route_me_harder
+# define xt_register_target xtnu_register_target
+# define xt_unregister_target xtnu_unregister_target
+#endif
+
+#include "compat_xtnu.h"
+
+#endif /* _XTABLES_COMPAT_H */
--- /dev/null
+#ifndef _COMPAT_XTNU_H
+#define _COMPAT_XTNU_H 1
+
+#include <linux/list.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/spinlock.h>
+
+struct module;
+struct net_device;
+struct sk_buff;
+
+struct xtnu_match {
+ struct list_head list;
+ char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)];
+ bool (*match)(const struct sk_buff *, const struct net_device *,
+ const struct net_device *, const struct xtnu_match *,
+ const void *, int, unsigned int, bool *);
+ bool (*checkentry)(const char *, const void *,
+ const struct xtnu_match *, void *, unsigned int);
+ void (*destroy)(const struct xtnu_match *, void *);
+ struct module *me;
+ const char *table;
+ unsigned int matchsize, hooks;
+ unsigned short proto, family;
+ uint8_t revision;
+
+ void *__compat_match;
+};
+
+struct xtnu_target {
+ struct list_head list;
+ char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)];
+ unsigned int (*target)(struct sk_buff *, const struct net_device *,
+ const struct net_device *, unsigned int,
+ const struct xtnu_target *, const void *);
+ bool (*checkentry)(const char *, const void *,
+ const struct xtnu_target *, void *, unsigned int);
+ void (*destroy)(const struct xtnu_target *, void *);
+ struct module *me;
+ const char *table;
+ unsigned int targetsize, hooks;
+ unsigned short proto, family;
+ uint8_t revision;
+
+ void *__compat_target;
+};
+
+static inline struct xtnu_match *xtcompat_numatch(const struct xt_match *m)
+{
+ void *q;
+ memcpy(&q, m->name + sizeof(m->name) - sizeof(void *), sizeof(void *));
+ return q;
+}
+
+static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
+{
+ void *q;
+ memcpy(&q, t->name + sizeof(t->name) - sizeof(void *), sizeof(void *));
+ return q;
+}
+
+extern int xtnu_ip_route_me_harder(struct sk_buff *, unsigned int);
+extern int xtnu_register_match(struct xtnu_match *);
+extern void xtnu_unregister_match(struct xtnu_match *);
+extern int xtnu_register_matches(struct xtnu_match *, unsigned int);
+extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int);
+extern int xtnu_register_target(struct xtnu_target *);
+extern void xtnu_unregister_target(struct xtnu_target *);
+
+#endif /* _COMPAT_XTNU_H */