1 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
2 index 0344615..dc0f0d8 100644
3 --- a/include/linux/sysctl.h
4 +++ b/include/linux/sysctl.h
5 @@ -436,6 +436,13 @@ enum
6 NET_TCP_ALLOWED_CONG_CONTROL=123,
7 NET_TCP_MAX_SSTHRESH=124,
8 NET_TCP_FRTO_RESPONSE=125,
9 +#ifdef CONFIG_ICMP_IPOD
10 + NET_IPV4_ICMP_IPOD_VERSION,
11 + NET_IPV4_ICMP_IPOD_ENABLED,
12 + NET_IPV4_ICMP_IPOD_HOST,
13 + NET_IPV4_ICMP_IPOD_MASK,
14 + NET_IPV4_ICMP_IPOD_KEY
19 diff --git a/include/net/icmp.h b/include/net/icmp.h
20 index dfa72d4..55cdc47 100644
21 --- a/include/net/icmp.h
22 +++ b/include/net/icmp.h
23 @@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(const struct sock *sk)
24 return (struct raw_sock *)sk;
27 +#ifdef CONFIG_ICMP_IPOD
28 +extern int sysctl_icmp_ipod_version;
29 +extern int sysctl_icmp_ipod_enabled;
30 +extern u32 sysctl_icmp_ipod_host;
31 +extern u32 sysctl_icmp_ipod_mask;
32 +extern char sysctl_icmp_ipod_key[32+1];
36 diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
37 index 0c94a1a..31a67cc 100644
38 --- a/net/ipv4/Kconfig
39 +++ b/net/ipv4/Kconfig
40 @@ -627,3 +627,14 @@ config TCP_MD5SIG
49 + bool "ICMP: ICMP Ping-of-Death (Emulab)"
50 + depends on INET && SYSCTL
52 + Support immediately rebooting upon receiving a specially
53 + formed ICMP type 6 packet whose payload matches a string
54 + configured by the administrator.
55 diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
56 index 5bc13fe..5324406 100644
59 @@ -960,6 +960,67 @@ static void icmp_address_reply(struct sk_buff *skb)
63 +#ifdef CONFIG_ICMP_IPOD
64 +#include <linux/reboot.h>
66 +int sysctl_icmp_ipod_version = 2;
67 +int sysctl_icmp_ipod_enabled = 0;
68 +u32 sysctl_icmp_ipod_host = 0xffffffff;
69 +u32 sysctl_icmp_ipod_mask = 0xffffffff;
70 +char sysctl_icmp_ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
71 +#define IPOD_CHECK_KEY \
72 + (sysctl_icmp_ipod_key[0] != 0)
73 +#define IPOD_VALID_KEY(d) \
74 + (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
76 +static void icmp_ping_of_death(struct sk_buff *skb)
78 + struct icmphdr *icmph = (struct icmphdr *)skb_transport_header(skb);
79 + struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
83 + printk(KERN_INFO "IPOD: got type=6, code=%d, host=%u.%u.%u.%u\n", icmph->code, ntohs(iph->tot_len), NIPQUAD(iph->saddr));
87 + * If IPOD not enabled or wrong ICMP code, ignore.
89 + if (!sysctl_icmp_ipod_enabled || icmph->code != 6)
93 + * First check the source address info.
94 + * If host not set, ignore.
96 + if (sysctl_icmp_ipod_host != 0xffffffff &&
97 + (ntohl(iph->saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
99 + * Now check the key if enabled.
100 + * If packet doesn't contain enough data or key
101 + * is otherwise invalid, ignore.
103 + if (IPOD_CHECK_KEY) {
104 + if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)-1) &&
105 + IPOD_VALID_KEY(skb->data))
113 + sysctl_icmp_ipod_enabled = 0;
114 + printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
115 + NIPQUAD(iph->saddr));
116 + machine_restart(NULL);
118 + printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
119 + NIPQUAD(iph->saddr));
124 static void icmp_discard(struct sk_buff *skb)
127 @@ -1083,10 +1144,17 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
128 .handler = icmp_redirect,
131 +#ifdef CONFIG_ICMP_IPOD
133 + .handler = icmp_ping_of_death,
138 .handler = icmp_discard,
143 .handler = icmp_discard,
145 diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
146 index 2dcf04d..2bcd5df 100644
147 --- a/net/ipv4/sysctl_net_ipv4.c
148 +++ b/net/ipv4/sysctl_net_ipv4.c
149 @@ -770,6 +770,49 @@ static struct ctl_table ipv4_net_table[] = {
151 .proc_handler = proc_dointvec
153 +#ifdef CONFIG_ICMP_IPOD
155 + .ctl_name = NET_IPV4_ICMP_IPOD_VERSION,
156 + .procname = "icmp_ipod_version",
157 + .data = &sysctl_icmp_ipod_version,
158 + .maxlen = sizeof(sysctl_icmp_ipod_version),
160 + .proc_handler = &proc_dointvec
163 + .ctl_name = NET_IPV4_ICMP_IPOD_ENABLED,
164 + .procname = "icmp_ipod_enabled",
165 + .data = &sysctl_icmp_ipod_enabled,
166 + .maxlen = sizeof(sysctl_icmp_ipod_enabled),
168 + .proc_handler = &proc_dointvec
171 + .ctl_name = NET_IPV4_ICMP_IPOD_HOST,
172 + .procname = "icmp_ipod_host",
173 + .data = &sysctl_icmp_ipod_host,
174 + .maxlen = sizeof(sysctl_icmp_ipod_host),
176 + .proc_handler = &proc_dointvec
179 + .ctl_name = NET_IPV4_ICMP_IPOD_MASK,
180 + .procname = "icmp_ipod_mask",
181 + .data = &sysctl_icmp_ipod_mask,
182 + .maxlen = sizeof(sysctl_icmp_ipod_mask),
184 + .proc_handler = &proc_dointvec
187 + .ctl_name = NET_IPV4_ICMP_IPOD_KEY,
188 + .procname = "icmp_ipod_key",
189 + .data = &sysctl_icmp_ipod_key,
190 + .maxlen = sizeof(sysctl_icmp_ipod_key),
192 + .proc_handler = &proc_dostring,
193 + .strategy = &sysctl_string
197 .ctl_name = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
198 .procname = "icmp_errors_use_inbound_ifaddr",
199 diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
200 index 59f9451..6bcf1f1 100644
203 @@ -1282,6 +1282,75 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
207 +/* XXX (mef) need to generalize the IPOD stuff. Right now I am borrowing
208 + from the ICMP infrastructure. */
209 +#ifdef CONFIG_ICMP_IPOD
210 +#include <linux/reboot.h>
212 +extern int sysctl_icmp_ipod_version;
213 +extern int sysctl_icmp_ipod_enabled;
214 +extern u32 sysctl_icmp_ipod_host;
215 +extern u32 sysctl_icmp_ipod_mask;
216 +extern char sysctl_icmp_ipod_key[32+1];
217 +#define IPOD_CHECK_KEY \
218 + (sysctl_icmp_ipod_key[0] != 0)
219 +#define IPOD_VALID_KEY(d) \
220 + (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
222 +static void udp_ping_of_death(struct sk_buff *skb, struct udphdr *uh, u32 saddr)
227 + * If IPOD not enabled or wrong UDP IPOD port, ignore.
229 + if (!sysctl_icmp_ipod_enabled || (ntohs(uh->dest) != 664))
233 + printk(KERN_INFO "IPOD: got udp pod request, host=%u.%u.%u.%u\n", NIPQUAD(saddr));
238 + * First check the source address info.
239 + * If host not set, ignore.
241 + if (sysctl_icmp_ipod_host != 0xffffffff &&
242 + (ntohl(saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
244 + * Now check the key if enabled.
245 + * If packet doesn't contain enough data or key
246 + * is otherwise invalid, ignore.
248 + if (IPOD_CHECK_KEY) {
249 + if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)+sizeof(struct udphdr)-1)){
252 + for (i=0;i<32+1;i++){
253 + printk("%c",((char*)skb->data)[i+sizeof(struct udphdr)]);
257 + if (IPOD_VALID_KEY(skb->data+sizeof(struct udphdr)))
265 + sysctl_icmp_ipod_enabled = 0;
266 + printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
268 + machine_restart(NULL);
270 + printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
277 * All we need to do is get the socket, and then do a checksum.
279 @@ -1324,6 +1393,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
280 return __udp4_lib_mcast_deliver(net, skb, uh,
281 saddr, daddr, udptable);
283 +#ifdef CONFIG_ICMP_IPOD
284 + udp_ping_of_death(skb, uh, saddr);
287 sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);