Skip to content

Instantly share code, notes, and snippets.

@Chion82
Last active May 27, 2020 10:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Chion82/9a6880edf4cd6e1993e22b5460bde869 to your computer and use it in GitHub Desktop.
Save Chion82/9a6880edf4cd6e1993e22b5460bde869 to your computer and use it in GitHub Desktop.
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