From 283882f5d3d81bb9d8e4bfc4e1f9524b2f6756d3 Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Wed, 8 Sep 2004 17:46:51 +0000 Subject: [PATCH] - port, cleanup Emulab ICMP Ping Of Death (IPOD) patch from 2.4.x --- include/linux/sysctl.h | 7 ++++ net/ipv4/Kconfig | 11 ++++++ net/ipv4/icmp.c | 70 ++++++++++++++++++++++++++++++++++++++ net/ipv4/sysctl_net_ipv4.c | 50 +++++++++++++++++++++++++++ 4 files changed, 138 insertions(+) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 40d1f8f88..7b0218e86 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -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 { diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 847b938e5..31e54166a 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -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. diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index e0007a314..75c7952e4 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -911,6 +911,67 @@ static void icmp_address_reply(struct sk_buff *skb) out:; } +#ifdef CONFIG_ICMP_IPOD +#include + +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), diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 6b0b74430..e6a0ce3af 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -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", -- 2.47.0