- port, cleanup Emulab ICMP Ping Of Death (IPOD) patch from 2.4.x
authorMark Huang <mlhuang@cs.princeton.edu>
Wed, 8 Sep 2004 17:46:51 +0000 (17:46 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Wed, 8 Sep 2004 17:46:51 +0000 (17:46 +0000)
include/linux/sysctl.h
net/ipv4/Kconfig
net/ipv4/icmp.c
net/ipv4/sysctl_net_ipv4.c

index 40d1f8f..7b0218e 100644 (file)
@@ -340,6 +340,13 @@ enum
        NET_TCP_BIC_LOW_WINDOW=104,
        NET_TCP_DEFAULT_WIN_SCALE=105,
        NET_TCP_MODERATE_RCVBUF=106,
+#ifdef CONFIG_ICMP_IPOD
+       NET_IPV4_ICMP_IPOD_VERSION,
+       NET_IPV4_ICMP_IPOD_ENABLED,
+       NET_IPV4_ICMP_IPOD_HOST,
+       NET_IPV4_ICMP_IPOD_MASK,
+       NET_IPV4_ICMP_IPOD_KEY,
+#endif
 };
 
 enum {
index 847b938..31e5416 100644 (file)
@@ -384,3 +384,14 @@ config ACCEPT_QUEUES
 
 source "net/ipv4/ipvs/Kconfig"
 
+#
+# Emulab special
+#
+
+config ICMP_IPOD
+       bool "ICMP: ICMP Ping-of-Death (Emulab)"
+       depends on INET && SYSCTL
+       ---help---
+          Support immediately rebooting upon receiving a specially
+         formed ICMP type 6 packet whose payload matches a string
+         configured by the administrator.
index e0007a3..75c7952 100644 (file)
@@ -911,6 +911,67 @@ static void icmp_address_reply(struct sk_buff *skb)
 out:;
 }
 
+#ifdef CONFIG_ICMP_IPOD
+#include <linux/reboot.h>
+
+int sysctl_icmp_ipod_version = 2;
+int sysctl_icmp_ipod_enabled = 0;
+u32 sysctl_icmp_ipod_host = 0xffffffff;
+u32 sysctl_icmp_ipod_mask = 0xffffffff;
+char sysctl_icmp_ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
+#define IPOD_CHECK_KEY \
+       (sysctl_icmp_ipod_key[0] != 0)
+#define IPOD_VALID_KEY(d) \
+       (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
+
+static void icmp_ping_of_death(struct sk_buff *skb)
+{
+       struct icmphdr *icmph = skb->h.icmph;
+       struct iphdr *iph = skb->nh.iph;
+       int doit = 0;
+
+#if 0
+       printk(KERN_INFO "IPOD: got type=6, code=%d, host=%u.%u.%u.%u\n", icmph->code, ntohs(iph->tot_len), NIPQUAD(iph->saddr));
+#endif
+
+       /*
+        * If IPOD not enabled or wrong ICMP code, ignore.
+        */
+       if (!sysctl_icmp_ipod_enabled || icmph->code != 6)
+               return;
+
+       /*
+        * First check the source address info.
+        * If host not set, ignore.
+        */
+       if (sysctl_icmp_ipod_host != 0xffffffff &&
+           (ntohl(iph->saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
+               /*
+                * Now check the key if enabled.
+                * If packet doesn't contain enough data or key
+                * is otherwise invalid, ignore.
+                */
+               if (IPOD_CHECK_KEY) {
+                       if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)-1) &&
+                           IPOD_VALID_KEY(skb->data))
+                               doit = 1;
+               } else {
+                       doit = 1;
+               }
+       }
+
+       if (doit) {
+               sysctl_icmp_ipod_enabled = 0;
+               printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
+                      NIPQUAD(iph->saddr));
+               machine_restart(NULL);
+       } else {
+               printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
+                      NIPQUAD(iph->saddr));
+       }
+}
+#endif
+
 static void icmp_discard(struct sk_buff *skb)
 {
 }
@@ -1025,12 +1086,21 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
                .handler = icmp_redirect,
                .error = 1,
        },
+#ifdef CONFIG_ICMP_IPOD
+       [6] = {
+               .output_off = offsetof(struct icmp_mib, dummy),
+               .input_off = offsetof(struct icmp_mib, dummy),
+               .handler = icmp_ping_of_death,
+               .error = 1,
+       },
+#else
        [6] = {
                .output_off = offsetof(struct icmp_mib, dummy),
                .input_off = offsetof(struct icmp_mib, IcmpInErrors),
                .handler = icmp_discard,
                .error = 1,
        },
+#endif
        [7] = {
                .output_off = offsetof(struct icmp_mib, dummy),
                .input_off = offsetof(struct icmp_mib, IcmpInErrors),
index 6b0b744..e6a0ce3 100644 (file)
@@ -23,6 +23,13 @@ extern int sysctl_ip_nonlocal_bind;
 extern int sysctl_icmp_echo_ignore_all;
 extern int sysctl_icmp_echo_ignore_broadcasts;
 extern int sysctl_icmp_ignore_bogus_error_responses;
+#ifdef CONFIG_ICMP_IPOD
+extern int sysctl_icmp_ipod_version;
+extern int sysctl_icmp_ipod_enabled;
+extern u32 sysctl_icmp_ipod_host;
+extern u32 sysctl_icmp_ipod_mask;
+extern char sysctl_icmp_ipod_key[32+1];
+#endif
 
 /* From ip_fragment.c */
 extern int sysctl_ipfrag_low_thresh;
@@ -395,6 +402,49 @@ ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
+#ifdef CONFIG_ICMP_IPOD
+       {
+               .ctl_name       = NET_IPV4_ICMP_IPOD_VERSION,
+               .procname       = "icmp_ipod_version",
+               .data           = &sysctl_icmp_ipod_version,
+               .maxlen         = sizeof(sysctl_icmp_ipod_version),
+               .mode           = 0444,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .ctl_name       = NET_IPV4_ICMP_IPOD_ENABLED,
+               .procname       = "icmp_ipod_enabled",
+               .data           = &sysctl_icmp_ipod_enabled,
+               .maxlen         = sizeof(sysctl_icmp_ipod_enabled),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .ctl_name       = NET_IPV4_ICMP_IPOD_HOST,
+               .procname       = "icmp_ipod_host",
+               .data           = &sysctl_icmp_ipod_host,
+               .maxlen         = sizeof(sysctl_icmp_ipod_host),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .ctl_name       = NET_IPV4_ICMP_IPOD_MASK,
+               .procname       = "icmp_ipod_mask",
+               .data           = &sysctl_icmp_ipod_mask,
+               .maxlen         = sizeof(sysctl_icmp_ipod_mask),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .ctl_name       = NET_IPV4_ICMP_IPOD_KEY,
+               .procname       = "icmp_ipod_key",
+               .data           = &sysctl_icmp_ipod_key,
+               .maxlen         = sizeof(sysctl_icmp_ipod_key),
+               .mode           = 0600,
+               .proc_handler   = &proc_dostring,
+               .strategy       = &sysctl_string
+       },
+#endif
        {
                .ctl_name       = NET_IPV4_ROUTE,
                .procname       = "route",