udp_blackhole and tcp_blackhole sysctls for Linux.
-Frank Denis <j [at] pureftpd [dot] org>.

diff -ur orig/linux-source-3.2.0/include/net/netns/ipv6.h linux-source-3.2.0/linux-source-3.2.0/include/net/netns/ipv6.h
--- orig/linux-source-3.2.0/include/net/netns/ipv6.h	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/include/net/netns/ipv6.h	2012-02-03 15:26:57.911212138 -0800
@@ -25,6 +25,8 @@
 	int ip6_rt_mtu_expires;
 	int ip6_rt_min_advmss;
 	int icmpv6_time;
+	int udp_blackhole;
+	int tcp_blackhole;
 };
 
 struct netns_ipv6 {
diff -ur orig/linux-source-3.2.0/include/net/tcp.h linux-source-3.2.0/linux-source-3.2.0/include/net/tcp.h
--- orig/linux-source-3.2.0/include/net/tcp.h	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/include/net/tcp.h	2012-02-03 14:28:49.580448545 -0800
@@ -251,6 +251,7 @@
 extern int sysctl_tcp_cookie_size;
 extern int sysctl_tcp_thin_linear_timeouts;
 extern int sysctl_tcp_thin_dupack;
+extern int sysctl_tcp_blackhole;
 
 extern atomic_long_t tcp_memory_allocated;
 extern struct percpu_counter tcp_sockets_allocated;
diff -ur orig/linux-source-3.2.0/include/net/udp.h linux-source-3.2.0/linux-source-3.2.0/include/net/udp.h
--- orig/linux-source-3.2.0/include/net/udp.h	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/include/net/udp.h	2012-02-03 14:29:10.011831704 -0800
@@ -111,6 +111,7 @@
 extern long sysctl_udp_mem[3];
 extern int sysctl_udp_rmem_min;
 extern int sysctl_udp_wmem_min;
+extern int sysctl_udp_blackhole;
 
 struct sk_buff;
 
diff -ur orig/linux-source-3.2.0/net/ipv4/sysctl_net_ipv4.c linux-source-3.2.0/linux-source-3.2.0/net/ipv4/sysctl_net_ipv4.c
--- orig/linux-source-3.2.0/net/ipv4/sysctl_net_ipv4.c	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/net/ipv4/sysctl_net_ipv4.c	2012-02-03 14:27:32.086803007 -0800
@@ -721,6 +721,20 @@
 		.mode		= 0644,
 		.proc_handler	= ipv4_ping_group_range,
 	},
+	{
+		.procname	= "udp_blackhole",
+		.data		= &sysctl_udp_blackhole,
+		.maxlen		= sizeof(sysctl_udp_blackhole),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+	{
+		.procname	= "tcp_blackhole",
+		.data		= &sysctl_tcp_blackhole,
+		.maxlen		= sizeof(sysctl_tcp_blackhole),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 	{ }
 };
 
diff -ur orig/linux-source-3.2.0/net/ipv4/tcp_ipv4.c linux-source-3.2.0/linux-source-3.2.0/net/ipv4/tcp_ipv4.c
--- orig/linux-source-3.2.0/net/ipv4/tcp_ipv4.c	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/net/ipv4/tcp_ipv4.c	2012-02-03 15:18:09.905888263 -0800
@@ -75,6 +75,7 @@
 #include <net/secure_seq.h>
 
 #include <linux/inet.h>
+#include <linux/inetdevice.h>
 #include <linux/ipv6.h>
 #include <linux/stddef.h>
 #include <linux/proc_fs.h>
@@ -87,6 +88,8 @@
 int sysctl_tcp_low_latency __read_mostly;
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
+int sysctl_tcp_blackhole __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_blackhole);
 
 #ifdef CONFIG_TCP_MD5SIG
 static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
@@ -610,6 +613,9 @@
 	if (skb_rtable(skb)->rt_type != RTN_LOCAL)
 		return;
 
+	if (sysctl_tcp_blackhole > 0)
+		return;     
+   
 	/* Swap the send and the receive. */
 	memset(&rep, 0, sizeof(rep));
 	rep.th.dest   = th->source;
diff -ur orig/linux-source-3.2.0/net/ipv4/udp.c linux-source-3.2.0/linux-source-3.2.0/net/ipv4/udp.c
--- orig/linux-source-3.2.0/net/ipv4/udp.c	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/net/ipv4/udp.c	2012-02-03 15:17:53.149692232 -0800
@@ -120,6 +120,9 @@
 int sysctl_udp_wmem_min __read_mostly;
 EXPORT_SYMBOL(sysctl_udp_wmem_min);
 
+int sysctl_udp_blackhole __read_mostly;
+EXPORT_SYMBOL(sysctl_udp_blackhole);
+
 atomic_long_t udp_memory_allocated;
 EXPORT_SYMBOL(udp_memory_allocated);
 
@@ -1675,7 +1678,8 @@
 		goto csum_error;
 
 	UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
-	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+	if (sysctl_udp_blackhole <= 0)
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 
 	/*
 	 * Hmm.  We got an UDP packet to a port to which we
diff -ur orig/linux-source-3.2.0/net/ipv6/sysctl_net_ipv6.c linux-source-3.2.0/linux-source-3.2.0/net/ipv6/sysctl_net_ipv6.c
--- orig/linux-source-3.2.0/net/ipv6/sysctl_net_ipv6.c	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/net/ipv6/sysctl_net_ipv6.c	2012-02-03 15:24:48.756774624 -0800
@@ -48,6 +48,20 @@
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec
 	},
+	{
+		.procname	= "udp_blackhole",
+		.data		= &init_net.ipv6.sysctl.udp_blackhole,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+	{
+		.procname	= "tcp_blackhole",
+		.data		= &init_net.ipv6.sysctl.tcp_blackhole,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 	{ }
 };
 
diff -ur orig/linux-source-3.2.0/net/ipv6/tcp_ipv6.c linux-source-3.2.0/linux-source-3.2.0/net/ipv6/tcp_ipv6.c
--- orig/linux-source-3.2.0/net/ipv6/tcp_ipv6.c	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/net/ipv6/tcp_ipv6.c	2012-02-03 16:19:30.342931290 -0800
@@ -1783,6 +1783,7 @@
 bad_packet:
 		TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
 	} else {
+	   if (init_net.ipv6.sysctl.tcp_blackhole <= 0)
 		tcp_v6_send_reset(NULL, skb);
 	}
 
diff -ur orig/linux-source-3.2.0/net/ipv6/udp.c linux-source-3.2.0/linux-source-3.2.0/net/ipv6/udp.c
--- orig/linux-source-3.2.0/net/ipv6/udp.c	2012-01-04 15:55:44.000000000 -0800
+++ linux-source-3.2.0/linux-source-3.2.0/net/ipv6/udp.c	2012-02-03 16:15:54.526934850 -0800
@@ -779,8 +779,8 @@
 			goto discard;
 		UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS,
 				proto == IPPROTO_UDPLITE);
-
-		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
+		if (init_net.ipv6.sysctl.udp_blackhole <= 0)
+			icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
 
 		kfree_skb(skb);
 		return 0;
