patch-2.3.99-pre2 linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c

Next file: linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
Previous file: linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre1/linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -0,0 +1,111 @@
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/icmp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+
+#define ICMP_TIMEOUT (30*HZ)
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int icmp_pkt_to_tuple(const void *datah, size_t datalen,
+			     struct ip_conntrack_tuple *tuple)
+{
+	const struct icmphdr *hdr = datah;
+
+	tuple->dst.u.icmp.type = hdr->type;
+	tuple->src.u.icmp.id = hdr->un.echo.id;
+	tuple->dst.u.icmp.code = hdr->code;
+
+	return 1;
+}
+
+static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple,
+			     const struct ip_conntrack_tuple *orig)
+{
+	/* Add 1; spaces filled with 0. */
+	static u_int8_t invmap[]
+		= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
+		    [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
+		    [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
+		    [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
+		    [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
+		    [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
+		    [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
+		    [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
+
+	if (orig->dst.u.icmp.type >= sizeof(invmap)
+	    || !invmap[orig->dst.u.icmp.type])
+		return 0;
+
+	tuple->src.u.icmp.id = orig->src.u.icmp.id;
+	tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
+	tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static unsigned int icmp_print_tuple(char *buffer,
+				     const struct ip_conntrack_tuple *tuple)
+{
+	return sprintf(buffer, "type=%u code=%u id=%u ",
+		       tuple->dst.u.icmp.type,
+		       tuple->dst.u.icmp.code,
+		       ntohs(tuple->src.u.icmp.id));
+}
+
+/* Print out the private part of the conntrack. */
+static unsigned int icmp_print_conntrack(char *buffer,
+				     const struct ip_conntrack *conntrack)
+{
+	return 0;
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int icmp_packet(struct ip_conntrack *ct,
+		       struct iphdr *iph, size_t len,
+		       enum ip_conntrack_info ctinfo)
+{
+	/* FIXME: Should keep count of orig - reply packets: if == 0,
+           destroy --RR */
+	/* Delete connection immediately on reply: won't actually
+           vanish as we still have skb */
+	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
+		if (del_timer(&ct->timeout))
+			ct->timeout.function((unsigned long)ct);
+	} else
+		ip_ct_refresh(ct, ICMP_TIMEOUT);
+
+	return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int icmp_new(struct ip_conntrack *conntrack,
+		     struct iphdr *iph, size_t len)
+{
+	static u_int8_t valid_new[]
+		= { [ICMP_ECHO] = 1,
+		    [ICMP_TIMESTAMP] = 1,
+		    [ICMP_INFO_REQUEST] = 1,
+		    [ICMP_ADDRESS] = 1 };
+
+	if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
+	    || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
+		/* Can't create a new ICMP `conn' with this. */
+		DEBUGP("icmp: can't create new conn with type %u\n",
+		       conntrack->tuplehash[0].tuple.dst.u.icmp.type);
+		DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
+		return 0;
+	}
+	return 1;
+}
+
+struct ip_conntrack_protocol ip_conntrack_protocol_icmp
+= { { NULL, NULL }, IPPROTO_ICMP, "icmp",
+    icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
+    icmp_print_conntrack, icmp_packet, icmp_new, NULL };

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)