diff -Nurp linux-2.6.22.10-vs2.3.0.29-pl01/include/linux/sysctl.h linux-2.6.22.10-vs2.3.0.29-pl02/include/linux/sysctl.h --- linux-2.6.22.10-vs2.3.0.29-pl01/include/linux/sysctl.h 2007-10-29 21:23:59.000000000 -0400 +++ linux-2.6.22.10-vs2.3.0.29-pl02/include/linux/sysctl.h 2007-11-14 13:58:15.000000000 -0500 @@ -442,6 +442,13 @@ enum NET_TCP_ALLOWED_CONG_CONTROL=123, NET_TCP_MAX_SSTHRESH=124, NET_TCP_FRTO_RESPONSE=125, +#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 -Nurp linux-2.6.22.10-vs2.3.0.29-pl01/include/net/icmp.h linux-2.6.22.10-vs2.3.0.29-pl02/include/net/icmp.h --- linux-2.6.22.10-vs2.3.0.29-pl01/include/net/icmp.h 2007-05-04 09:57:44.000000000 -0400 +++ linux-2.6.22.10-vs2.3.0.29-pl02/include/net/icmp.h 2007-11-14 13:57:27.000000000 -0500 @@ -64,4 +64,12 @@ extern int sysctl_icmp_errors_use_inboun extern int sysctl_icmp_ratelimit; extern int sysctl_icmp_ratemask; +#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 + #endif /* _ICMP_H */ diff -Nurp linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/icmp.c linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/icmp.c --- linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/icmp.c 2007-07-21 18:00:25.000000000 -0400 +++ linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/icmp.c 2007-11-14 14:00:56.000000000 -0500 @@ -922,6 +922,67 @@ static void icmp_address_reply(struct sk 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_transport_header(skb); + struct iphdr *iph = skb_network_header(skb); + 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) { } @@ -1036,12 +1097,21 @@ static const struct icmp_control icmp_po .handler = icmp_redirect, .error = 1, }, +#ifdef CONFIG_ICMP_IPOD + [6] = { + .output_entry = ICMP_MIB_DUMMY, + .input_entry = ICMP_MIB_DUMMY, + .handler = icmp_ping_of_death, + .error = 1, + }, +#else [6] = { .output_entry = ICMP_MIB_DUMMY, .input_entry = ICMP_MIB_INERRORS, .handler = icmp_discard, .error = 1, }, +#endif [7] = { .output_entry = ICMP_MIB_DUMMY, .input_entry = ICMP_MIB_INERRORS, diff -Nurp linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/Kconfig linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/Kconfig --- linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/Kconfig 2007-07-21 18:00:25.000000000 -0400 +++ linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/Kconfig 2007-11-14 14:00:36.000000000 -0500 @@ -660,3 +660,14 @@ config TCP_MD5SIG 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 -Nurp linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/sysctl_net_ipv4.c linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/sysctl_net_ipv4.c --- linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/sysctl_net_ipv4.c 2007-07-21 18:00:27.000000000 -0400 +++ linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/sysctl_net_ipv4.c 2007-11-14 14:00:36.000000000 -0500 @@ -456,6 +456,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_ICMP_ERRORS_USE_INBOUND_IFADDR, .procname = "icmp_errors_use_inbound_ifaddr", diff -Nurp linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/udp.c linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/udp.c --- linux-2.6.22.10-vs2.3.0.29-pl01/net/ipv4/udp.c 2007-10-29 21:23:59.000000000 -0400 +++ linux-2.6.22.10-vs2.3.0.29-pl02/net/ipv4/udp.c 2007-11-14 14:00:36.000000000 -0500 @@ -1212,6 +1212,75 @@ static inline int udp4_csum_init(struct return 0; } +/* XXX (mef) need to generalize the IPOD stuff. Right now I am borrowing + from the ICMP infrastructure. */ +#ifdef CONFIG_ICMP_IPOD +#include + +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]; +#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 udp_ping_of_death(struct sk_buff *skb, struct udphdr *uh, u32 saddr) +{ + int doit = 0; + + /* + * If IPOD not enabled or wrong UDP IPOD port, ignore. + */ + if (!sysctl_icmp_ipod_enabled || (ntohs(uh->dest) != 664)) + return; + +#if 0 + printk(KERN_INFO "IPOD: got udp pod request, host=%u.%u.%u.%u\n", NIPQUAD(saddr)); +#endif + + + /* + * First check the source address info. + * If host not set, ignore. + */ + if (sysctl_icmp_ipod_host != 0xffffffff && + (ntohl(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)+sizeof(struct udphdr)-1)){ +#if 0 + int i; + for (i=0;i<32+1;i++){ + printk("%c",((char*)skb->data)[i+sizeof(struct udphdr)]); + } + printk("\n"); +#endif + if (IPOD_VALID_KEY(skb->data+sizeof(struct udphdr))) + 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(saddr)); + machine_restart(NULL); + } else { + printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n", + NIPQUAD(saddr)); + } +} +#endif + /* * All we need to do is get the socket, and then do a checksum. */ @@ -1249,6 +1318,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); +#ifdef CONFIG_ICMP_IPOD + udp_ping_of_death(skb, uh, saddr); +#endif + sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex, udptable );