From 8d91b0f47840b3472e3ca973c439f07b202f2806 Mon Sep 17 00:00:00 2001 From: S.Çağlar Onur Date: Tue, 7 Dec 2010 11:05:48 -0500 Subject: [PATCH] linux-2.6-510-ipod.patch --- include/linux/sysctl.h | 7 ++++ include/net/icmp.h | 8 +++++ net/ipv4/Kconfig | 11 ++++++ net/ipv4/icmp.c | 68 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/sysctl_net_ipv4.c | 43 ++++++++++++++++++++++++++ net/ipv4/udp.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 210 insertions(+), 0 deletions(-) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index ad17717..246538d 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -436,6 +436,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 --git a/include/net/icmp.h b/include/net/icmp.h index dfa72d4..55cdc47 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(const struct sock *sk) 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 --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 0c94a1a..31a67cc 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -627,3 +627,14 @@ config TCP_MD5SIG If unsure, say N. +# +# 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 5bc13fe..5324406 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -960,6 +960,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 = (struct icmphdr *)skb_transport_header(skb); + struct iphdr *iph = (struct iphdr *)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) { } @@ -1083,10 +1144,17 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { .handler = icmp_redirect, .error = 1, }, +#ifdef CONFIG_ICMP_IPOD + [6] = { + .handler = icmp_ping_of_death, + .error = 1, + }, +#else [6] = { .handler = icmp_discard, .error = 1, }, +#endif [7] = { .handler = icmp_discard, .error = 1, diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 3aab5bd..f1052a3 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -777,6 +777,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 --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5c85d37..f98b6a6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1283,6 +1283,75 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, 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. */ @@ -1325,6 +1394,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, 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_skb(skb, uh->source, uh->dest, udptable); if (sk != NULL) { -- 1.5.4.3