Setting tag linux-2.6-32-36
[linux-2.6.git] / linux-2.6-510-ipod.patch
1 From 8d91b0f47840b3472e3ca973c439f07b202f2806 Mon Sep 17 00:00:00 2001
2 From: S.Çağlar Onur <caglar@cs.princeton.edu>
3 Date: Tue, 7 Dec 2010 11:05:48 -0500
4 Subject: [PATCH] linux-2.6-510-ipod.patch
5
6 ---
7  include/linux/sysctl.h     |    7 ++++
8  include/net/icmp.h         |    8 +++++
9  net/ipv4/Kconfig           |   11 ++++++
10  net/ipv4/icmp.c            |   68 +++++++++++++++++++++++++++++++++++++++++
11  net/ipv4/sysctl_net_ipv4.c |   43 ++++++++++++++++++++++++++
12  net/ipv4/udp.c             |   73 ++++++++++++++++++++++++++++++++++++++++++++
13  6 files changed, 210 insertions(+), 0 deletions(-)
14
15 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
16 index ad17717..246538d 100644
17 --- a/include/linux/sysctl.h
18 +++ b/include/linux/sysctl.h
19 @@ -436,6 +436,13 @@ enum
20         NET_TCP_ALLOWED_CONG_CONTROL=123,
21         NET_TCP_MAX_SSTHRESH=124,
22         NET_TCP_FRTO_RESPONSE=125,
23 +#ifdef CONFIG_ICMP_IPOD
24 +       NET_IPV4_ICMP_IPOD_VERSION,
25 +       NET_IPV4_ICMP_IPOD_ENABLED,
26 +       NET_IPV4_ICMP_IPOD_HOST,
27 +       NET_IPV4_ICMP_IPOD_MASK,
28 +       NET_IPV4_ICMP_IPOD_KEY
29 +#endif
30  };
31  
32  enum {
33 diff --git a/include/net/icmp.h b/include/net/icmp.h
34 index dfa72d4..55cdc47 100644
35 --- a/include/net/icmp.h
36 +++ b/include/net/icmp.h
37 @@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(const struct sock *sk)
38         return (struct raw_sock *)sk;
39  }
40  
41 +#ifdef CONFIG_ICMP_IPOD
42 +extern int sysctl_icmp_ipod_version;
43 +extern int sysctl_icmp_ipod_enabled;
44 +extern u32 sysctl_icmp_ipod_host;
45 +extern u32 sysctl_icmp_ipod_mask;
46 +extern char sysctl_icmp_ipod_key[32+1];
47 +#endif
48 +
49  #endif /* _ICMP_H */
50 diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
51 index 0c94a1a..31a67cc 100644
52 --- a/net/ipv4/Kconfig
53 +++ b/net/ipv4/Kconfig
54 @@ -627,3 +627,14 @@ config TCP_MD5SIG
55  
56           If unsure, say N.
57  
58 +#
59 +# Emulab special
60 +#
61 +
62 +config ICMP_IPOD
63 +       bool "ICMP: ICMP Ping-of-Death (Emulab)"
64 +       depends on INET && SYSCTL
65 +       ---help---
66 +          Support immediately rebooting upon receiving a specially
67 +         formed ICMP type 6 packet whose payload matches a string
68 +         configured by the administrator.
69 diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
70 index 5bc13fe..5324406 100644
71 --- a/net/ipv4/icmp.c
72 +++ b/net/ipv4/icmp.c
73 @@ -960,6 +960,67 @@ static void icmp_address_reply(struct sk_buff *skb)
74  out:;
75  }
76  
77 +#ifdef CONFIG_ICMP_IPOD
78 +#include <linux/reboot.h>
79 +
80 +int sysctl_icmp_ipod_version = 2;
81 +int sysctl_icmp_ipod_enabled = 0;
82 +u32 sysctl_icmp_ipod_host = 0xffffffff;
83 +u32 sysctl_icmp_ipod_mask = 0xffffffff;
84 +char sysctl_icmp_ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
85 +#define IPOD_CHECK_KEY \
86 +       (sysctl_icmp_ipod_key[0] != 0)
87 +#define IPOD_VALID_KEY(d) \
88 +       (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
89 +
90 +static void icmp_ping_of_death(struct sk_buff *skb)
91 +{
92 +       struct icmphdr *icmph = (struct icmphdr *)skb_transport_header(skb);
93 +       struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
94 +       int doit = 0;
95 +
96 +#if 0
97 +       printk(KERN_INFO "IPOD: got type=6, code=%d, host=%u.%u.%u.%u\n", icmph->code, ntohs(iph->tot_len), NIPQUAD(iph->saddr));
98 +#endif
99 +
100 +       /*
101 +        * If IPOD not enabled or wrong ICMP code, ignore.
102 +        */
103 +       if (!sysctl_icmp_ipod_enabled || icmph->code != 6)
104 +               return;
105 +
106 +       /*
107 +        * First check the source address info.
108 +        * If host not set, ignore.
109 +        */
110 +       if (sysctl_icmp_ipod_host != 0xffffffff &&
111 +           (ntohl(iph->saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
112 +               /*
113 +                * Now check the key if enabled.
114 +                * If packet doesn't contain enough data or key
115 +                * is otherwise invalid, ignore.
116 +                */
117 +               if (IPOD_CHECK_KEY) {
118 +                       if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)-1) &&
119 +                           IPOD_VALID_KEY(skb->data))
120 +                               doit = 1;
121 +               } else {
122 +                       doit = 1;
123 +               }
124 +       }
125 +
126 +       if (doit) {
127 +               sysctl_icmp_ipod_enabled = 0;
128 +               printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
129 +                      NIPQUAD(iph->saddr));
130 +               machine_restart(NULL);
131 +       } else {
132 +               printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
133 +                      NIPQUAD(iph->saddr));
134 +       }
135 +}
136 +#endif
137 +
138  static void icmp_discard(struct sk_buff *skb)
139  {
140  }
141 @@ -1083,10 +1144,17 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
142                 .handler = icmp_redirect,
143                 .error = 1,
144         },
145 +#ifdef CONFIG_ICMP_IPOD
146 +       [6] = {
147 +               .handler = icmp_ping_of_death,
148 +               .error = 1,
149 +       },
150 +#else
151         [6] = {
152                 .handler = icmp_discard,
153                 .error = 1,
154         },
155 +#endif
156         [7] = {
157                 .handler = icmp_discard,
158                 .error = 1,
159 diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
160 index 3aab5bd..f1052a3 100644
161 --- a/net/ipv4/sysctl_net_ipv4.c
162 +++ b/net/ipv4/sysctl_net_ipv4.c
163 @@ -777,6 +777,49 @@ static struct ctl_table ipv4_net_table[] = {
164                 .mode           = 0644,
165                 .proc_handler   = proc_dointvec
166         },
167 +#ifdef CONFIG_ICMP_IPOD
168 +       {
169 +               .ctl_name       = NET_IPV4_ICMP_IPOD_VERSION,
170 +               .procname       = "icmp_ipod_version",
171 +               .data           = &sysctl_icmp_ipod_version,
172 +               .maxlen         = sizeof(sysctl_icmp_ipod_version),
173 +               .mode           = 0444,
174 +               .proc_handler   = &proc_dointvec
175 +       },
176 +       {
177 +               .ctl_name       = NET_IPV4_ICMP_IPOD_ENABLED,
178 +               .procname       = "icmp_ipod_enabled",
179 +               .data           = &sysctl_icmp_ipod_enabled,
180 +               .maxlen         = sizeof(sysctl_icmp_ipod_enabled),
181 +               .mode           = 0644,
182 +               .proc_handler   = &proc_dointvec
183 +       },
184 +       {
185 +               .ctl_name       = NET_IPV4_ICMP_IPOD_HOST,
186 +               .procname       = "icmp_ipod_host",
187 +               .data           = &sysctl_icmp_ipod_host,
188 +               .maxlen         = sizeof(sysctl_icmp_ipod_host),
189 +               .mode           = 0644,
190 +               .proc_handler   = &proc_dointvec
191 +       },
192 +       {
193 +               .ctl_name       = NET_IPV4_ICMP_IPOD_MASK,
194 +               .procname       = "icmp_ipod_mask",
195 +               .data           = &sysctl_icmp_ipod_mask,
196 +               .maxlen         = sizeof(sysctl_icmp_ipod_mask),
197 +               .mode           = 0644,
198 +               .proc_handler   = &proc_dointvec
199 +       },
200 +       {
201 +               .ctl_name       = NET_IPV4_ICMP_IPOD_KEY,
202 +               .procname       = "icmp_ipod_key",
203 +               .data           = &sysctl_icmp_ipod_key,
204 +               .maxlen         = sizeof(sysctl_icmp_ipod_key),
205 +               .mode           = 0600,
206 +               .proc_handler   = &proc_dostring,
207 +               .strategy       = &sysctl_string
208 +       },
209 +#endif
210         {
211                 .ctl_name       = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
212                 .procname       = "icmp_errors_use_inbound_ifaddr",
213 diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
214 index 5c85d37..f98b6a6 100644
215 --- a/net/ipv4/udp.c
216 +++ b/net/ipv4/udp.c
217 @@ -1283,6 +1283,75 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
218         return 0;
219  }
220  
221 +/* XXX (mef) need to generalize the IPOD stuff.  Right now I am borrowing 
222 +   from the ICMP infrastructure. */
223 +#ifdef CONFIG_ICMP_IPOD
224 +#include <linux/reboot.h>
225 +
226 +extern int sysctl_icmp_ipod_version;
227 +extern int sysctl_icmp_ipod_enabled;
228 +extern u32 sysctl_icmp_ipod_host;
229 +extern u32 sysctl_icmp_ipod_mask;
230 +extern char sysctl_icmp_ipod_key[32+1];
231 +#define IPOD_CHECK_KEY \
232 +       (sysctl_icmp_ipod_key[0] != 0)
233 +#define IPOD_VALID_KEY(d) \
234 +       (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
235 +
236 +static void udp_ping_of_death(struct sk_buff *skb, struct udphdr *uh, u32 saddr)
237 +{
238 +       int doit = 0;
239 +
240 +       /*
241 +        * If IPOD not enabled or wrong UDP IPOD port, ignore.
242 +        */
243 +       if (!sysctl_icmp_ipod_enabled || (ntohs(uh->dest) != 664))
244 +               return;
245 +
246 +#if 0
247 +       printk(KERN_INFO "IPOD: got udp pod request, host=%u.%u.%u.%u\n", NIPQUAD(saddr));
248 +#endif
249 +
250 +
251 +       /*
252 +        * First check the source address info.
253 +        * If host not set, ignore.
254 +        */
255 +       if (sysctl_icmp_ipod_host != 0xffffffff &&
256 +           (ntohl(saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
257 +               /*
258 +                * Now check the key if enabled.
259 +                * If packet doesn't contain enough data or key
260 +                * is otherwise invalid, ignore.
261 +                */
262 +               if (IPOD_CHECK_KEY) {
263 +                       if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)+sizeof(struct udphdr)-1)){
264 +#if 0
265 +                           int i;
266 +                           for (i=0;i<32+1;i++){
267 +                               printk("%c",((char*)skb->data)[i+sizeof(struct udphdr)]);
268 +                           }   
269 +                           printk("\n");
270 +#endif
271 +                           if (IPOD_VALID_KEY(skb->data+sizeof(struct udphdr)))
272 +                               doit = 1;
273 +                       }
274 +               } else {
275 +                       doit = 1;
276 +               }
277 +       }
278 +       if (doit) {
279 +               sysctl_icmp_ipod_enabled = 0;
280 +               printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
281 +                      NIPQUAD(saddr));
282 +               machine_restart(NULL);
283 +       } else {
284 +               printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
285 +                      NIPQUAD(saddr));
286 +       }
287 +}
288 +#endif
289 +
290  /*
291   *     All we need to do is get the socket, and then do a checksum.
292   */
293 @@ -1325,6 +1394,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
294                 return __udp4_lib_mcast_deliver(net, skb, uh,
295                                 saddr, daddr, udptable);
296  
297 +#ifdef CONFIG_ICMP_IPOD
298 +       udp_ping_of_death(skb, uh, saddr);
299 +#endif
300 +
301         sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
302  
303         if (sk != NULL) {
304 -- 
305 1.5.4.3
306