Last active
May 27, 2020 10:58
-
-
Save Chion82/9a6880edf4cd6e1993e22b5460bde869 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/xt_FULLCONENAT.c b/xt_FULLCONENAT.c | |
index 8555b54..8edaf7b 100644 | |
--- a/xt_FULLCONENAT.c | |
+++ b/xt_FULLCONENAT.c | |
@@ -21,6 +21,7 @@ | |
#include <linux/netfilter.h> | |
#include <linux/netfilter_ipv4.h> | |
#include <linux/netfilter/x_tables.h> | |
+#include <linux/notifier.h> | |
#include <net/netfilter/nf_nat.h> | |
#include <net/netfilter/nf_conntrack.h> | |
#include <net/netfilter/nf_conntrack_zones.h> | |
@@ -468,6 +469,8 @@ static unsigned int fullconenat_tg(struct sk_buff *skb, const struct xt_action_p | |
enum ip_conntrack_info ctinfo; | |
struct nf_conntrack_tuple *ct_tuple, *ct_tuple_origin; | |
+ struct nf_conn_nat *nat; | |
+ | |
struct net_device *net_dev; | |
struct nat_mapping *mapping, *src_mapping; | |
@@ -494,6 +497,7 @@ static unsigned int fullconenat_tg(struct sk_buff *skb, const struct xt_action_p | |
ret = XT_CONTINUE; | |
ct = nf_ct_get(skb, &ctinfo); | |
+ nat = nfct_nat(ct); | |
net = nf_ct_net(ct); | |
zone = nf_ct_zone(ct); | |
@@ -599,6 +603,8 @@ static unsigned int fullconenat_tg(struct sk_buff *skb, const struct xt_action_p | |
newrange.max_addr.ip = new_ip; | |
} | |
+ nat->masq_index = ifindex; | |
+ | |
/* do SNAT now */ | |
ret = nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par))); | |
@@ -700,6 +706,73 @@ static struct xt_target tg_reg[] __read_mostly = { | |
}, | |
}; | |
+static int device_cmp(struct nf_conn *i, void *ifindex) | |
+{ | |
+ const struct nf_conn_nat *nat = nfct_nat(i); | |
+ | |
+ if (!nat) | |
+ return 0; | |
+ | |
+ return nat->masq_index == (int)(long)ifindex; | |
+} | |
+ | |
+static int fullconenat_device_event(struct notifier_block *this, | |
+ unsigned long event, | |
+ void *ptr) | |
+{ | |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) | |
+ const struct net_device *dev = netdev_notifier_info_to_dev(ptr); | |
+#else | |
+ const struct net_device *dev = ptr; | |
+#endif | |
+ struct net *net = dev_net(dev); | |
+ | |
+ if (event == NETDEV_DOWN) { | |
+ /* Device was downed. Search entire table for | |
+ conntracks which were associated with that device, | |
+ and forget them. */ | |
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) | |
+ NF_CT_ASSERT(dev->ifindex != 0); | |
+#endif | |
+ | |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) | |
+ nf_ct_iterate_cleanup_net(net, device_cmp, | |
+ (void *)(long)dev->ifindex, 0, 0); | |
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) | |
+ nf_ct_iterate_cleanup(net, device_cmp, | |
+ (void *)(long)dev->ifindex, 0, 0); | |
+#else | |
+ nf_ct_iterate_cleanup(net, device_cmp, | |
+ (void *)(long)dev->ifindex); | |
+#endif | |
+ } | |
+ | |
+ return NOTIFY_DONE; | |
+} | |
+ | |
+static int fullconenat_inet_event(struct notifier_block *this, | |
+ unsigned long event, | |
+ void *ptr) | |
+{ | |
+ struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; | |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) | |
+ struct netdev_notifier_info info; | |
+ | |
+ netdev_notifier_info_init(&info, dev); | |
+ return fullconenat_device_event(this, event, &info); | |
+#else | |
+ return fullconenat_device_event(this, event, dev); | |
+#endif | |
+} | |
+ | |
+static struct notifier_block fullconenat_dev_notifier = { | |
+ .notifier_call = fullconenat_device_event, | |
+}; | |
+ | |
+static struct notifier_block fullconenat_inet_notifier = { | |
+ .notifier_call = fullconenat_inet_event, | |
+}; | |
+ | |
static int __init fullconenat_tg_init(void) | |
{ | |
wq = create_singlethread_workqueue("xt_FULLCONENAT"); | |
@@ -707,6 +780,9 @@ static int __init fullconenat_tg_init(void) | |
printk("xt_FULLCONENAT: warning: failed to create workqueue\n"); | |
} | |
+ register_netdevice_notifier(&fullconenat_dev_notifier); | |
+ register_inetaddr_notifier(&fullconenat_inet_notifier); | |
+ | |
return xt_register_targets(tg_reg, ARRAY_SIZE(tg_reg)); | |
} | |
@@ -722,6 +798,9 @@ static void fullconenat_tg_exit(void) | |
handle_dying_tuples(); | |
destroy_mappings(); | |
+ | |
+ unregister_netdevice_notifier(&fullconenat_dev_notifier); | |
+ unregister_inetaddr_notifier(&fullconenat_inet_notifier); | |
} | |
module_init(fullconenat_tg_init); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment