diff -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-P/include/linux/sysctl.h linux-2.6.27.10-vs2.3.x-P510/include/linux/sysctl.h --- linux-2.6.27.10-vs2.3.x-P/include/linux/sysctl.h 2008-10-13 14:54:20.000000000 +0200 +++ linux-2.6.27.10-vs2.3.x-P510/include/linux/sysctl.h 2009-01-12 01:18:23.000000000 +0100 @@ -437,6 +437,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 -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-P/include/net/icmp.h linux-2.6.27.10-vs2.3.x-P510/include/net/icmp.h --- linux-2.6.27.10-vs2.3.x-P/include/net/icmp.h 2008-10-13 14:52:09.000000000 +0200 +++ linux-2.6.27.10-vs2.3.x-P510/include/net/icmp.h 2009-01-12 01:18:23.000000000 +0100 @@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(co return (struct raw_sock *)sk; } +#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 -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-P/net/ipv4/icmp.c linux-2.6.27.10-vs2.3.x-P510/net/ipv4/icmp.c --- linux-2.6.27.10-vs2.3.x-P/net/ipv4/icmp.c 2008-10-13 14:52:09.000000000 +0200 +++ linux-2.6.27.10-vs2.3.x-P510/net/ipv4/icmp.c 2009-01-12 01:52:06.000000000 +0100 @@ -962,6 +962,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) { } @@ -1084,10 +1145,19 @@ 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] = { .handler = icmp_discard, .error = 1, }, +#endif [7] = { .handler = icmp_discard, .error = 1, diff -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-P/net/ipv4/Kconfig linux-2.6.27.10-vs2.3.x-P510/net/ipv4/Kconfig --- linux-2.6.27.10-vs2.3.x-P/net/ipv4/Kconfig 2008-10-13 14:52:09.000000000 +0200 +++ linux-2.6.27.10-vs2.3.x-P510/net/ipv4/Kconfig 2009-01-12 01:18:23.000000000 +0100 @@ -632,3 +632,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 -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-P/net/ipv4/sysctl_net_ipv4.c linux-2.6.27.10-vs2.3.x-P510/net/ipv4/sysctl_net_ipv4.c --- linux-2.6.27.10-vs2.3.x-P/net/ipv4/sysctl_net_ipv4.c 2008-10-13 14:52:09.000000000 +0200 +++ linux-2.6.27.10-vs2.3.x-P510/net/ipv4/sysctl_net_ipv4.c 2009-01-12 01:18:23.000000000 +0100 @@ -773,6 +773,49 @@ static struct ctl_table ipv4_net_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 -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-P/net/ipv4/udp.c linux-2.6.27.10-vs2.3.x-P510/net/ipv4/udp.c --- linux-2.6.27.10-vs2.3.x-P/net/ipv4/udp.c 2008-12-19 12:09:14.000000000 +0100 +++ linux-2.6.27.10-vs2.3.x-P510/net/ipv4/udp.c 2009-01-12 01:54:04.000000000 +0100 @@ -1171,6 +1171,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. */ @@ -1210,6 +1279,9 @@ int __udp4_lib_rcv(struct sk_buff *skb, return __udp4_lib_mcast_deliver(net, skb, uh, saddr, daddr, udptable); +#ifdef CONFIG_ICMP_IPOD + udp_ping_of_death(skb, uh, saddr); +#endif sk = __udp4_lib_lookup(net, saddr, uh->source, daddr, uh->dest, inet_iif(skb), udptable); ; fixup diff -NurpP --exclude '*.orig' --exclude '*.rej' linux-2.6.27.10-vs2.3.x-PS-02.0/net/ipv4/icmp.c linux-2.6.27.10-vs2.3.x-PS-02.1/net/ipv4/icmp.c --- linux-2.6.27.10-vs2.3.x-PS-02.0/net/ipv4/icmp.c 2009-01-25 02:29:31.000000000 +0100 +++ linux-2.6.27.10-vs2.3.x-PS-02.1/net/ipv4/icmp.c 2009-01-25 01:41:43.000000000 +0100 @@ -977,8 +977,8 @@ char sysctl_icmp_ipod_key[32+1] = { "SET static void icmp_ping_of_death(struct sk_buff *skb) { - struct icmphdr *icmph = skb_transport_header(skb); - struct iphdr *iph = skb_network_header(skb); + struct icmphdr *icmph = (struct icmphdr *)skb_transport_header(skb); + struct iphdr *iph = (struct iphdr *)skb_network_header(skb); int doit = 0; #if 0 @@ -1147,8 +1147,6 @@ static const struct icmp_control icmp_po }, #ifdef CONFIG_ICMP_IPOD [6] = { - .output_entry = ICMP_MIB_DUMMY, - .input_entry = ICMP_MIB_DUMMY, .handler = icmp_ping_of_death, .error = 1, },