This source file includes following definitions.
- ip_options_build
- ip_options_echo
- ip_options_fragment
- ip_options_compile
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/types.h>
13 #include <linux/skbuff.h>
14 #include <linux/ip.h>
15 #include <linux/icmp.h>
16 #include <linux/netdevice.h>
17 #include <net/sock.h>
18 #include <net/ip.h>
19 #include <net/icmp.h>
20
21
22
23
24
25
26
27
28
29 void ip_options_build(struct sk_buff * skb, struct options * opt,
30 __u32 daddr, __u32 saddr,
31 int is_frag)
32 {
33 unsigned char * iph = (unsigned char*)skb->ip_hdr;
34
35 memcpy(skb->proto_priv, opt, sizeof(struct options));
36 memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);
37 opt = (struct options*)skb->proto_priv;
38 opt->is_data = 0;
39
40 if (opt->srr)
41 memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4);
42
43 if (!is_frag)
44 {
45 if (opt->rr_needaddr)
46 memcpy(iph+opt->rr+iph[opt->rr+2]-5, &saddr, 4);
47 if (opt->ts_needaddr)
48 memcpy(iph+opt->ts+iph[opt->ts+2]-9, &saddr, 4);
49 if (opt->ts_needtime)
50 {
51 struct timeval tv;
52 __u32 midtime;
53 do_gettimeofday(&tv);
54 midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
55 memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
56 }
57 return;
58 }
59 if (opt->rr)
60 {
61 memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]);
62 opt->rr = 0;
63 opt->rr_needaddr = 0;
64 }
65 if (opt->ts)
66 {
67 memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]);
68 opt->ts = 0;
69 opt->ts_needaddr = opt->ts_needtime = 0;
70 }
71 }
72
73 int ip_options_echo(struct options * dopt, struct options * sopt,
74 __u32 daddr, __u32 saddr,
75 struct sk_buff * skb)
76 {
77 unsigned char *sptr, *dptr;
78 int soffset, doffset;
79 int optlen;
80
81 memset(dopt, 0, sizeof(struct options));
82
83 dopt->is_data = 1;
84
85 if (!sopt)
86 sopt = (struct options*)skb->proto_priv;
87
88 if (sopt->optlen == 0)
89 {
90 dopt->optlen = 0;
91 return 0;
92 }
93
94 sptr = (sopt->is_data ? sopt->__data - sizeof(struct iphdr) :
95 (unsigned char *)skb->ip_hdr);
96 dptr = dopt->__data;
97
98 if (sopt->rr)
99 {
100 optlen = sptr[sopt->rr+1];
101 soffset = sptr[sopt->rr+2];
102 dopt->rr = dopt->optlen + sizeof(struct iphdr);
103 memcpy(dptr, sptr+sopt->rr, optlen);
104 if (sopt->rr_needaddr && soffset <= optlen) {
105 if (soffset + 3 > optlen)
106 return -EINVAL;
107 dptr[2] = soffset + 4;
108 dopt->rr_needaddr = 1;
109 }
110 dptr += optlen;
111 dopt->optlen += optlen;
112 }
113 if (sopt->ts)
114 {
115 optlen = sptr[sopt->ts+1];
116 soffset = sptr[sopt->ts+2];
117 dopt->ts = dopt->optlen + sizeof(struct iphdr);
118 memcpy(dptr, sptr+sopt->ts, optlen);
119 if (soffset <= optlen)
120 {
121 if (sopt->ts_needaddr)
122 {
123 if (soffset + 3 > optlen)
124 return -EINVAL;
125 dopt->ts_needaddr = 1;
126 soffset += 4;
127 }
128 if (sopt->ts_needtime)
129 {
130 if (soffset + 3 > optlen)
131 return -EINVAL;
132 dopt->ts_needtime = 1;
133 soffset += 4;
134 }
135 if (((struct timestamp*)(dptr+1))->flags == IPOPT_TS_PRESPEC)
136 {
137 __u32 addr;
138 memcpy(&addr, sptr+soffset-9, 4);
139 if (ip_chk_addr(addr) == 0)
140 {
141 dopt->ts_needtime = 0;
142 dopt->ts_needaddr = 0;
143 soffset -= 8;
144 }
145 }
146 dptr[2] = soffset;
147 }
148 dptr += optlen;
149 dopt->optlen += optlen;
150 }
151 if (sopt->srr)
152 {
153 unsigned char * start = sptr+sopt->srr;
154 __u32 faddr;
155
156 optlen = start[1];
157 soffset = start[2];
158 doffset = 0;
159 if (soffset > optlen)
160 soffset = optlen + 1;
161 soffset -= 4;
162 if (soffset > 3)
163 {
164 memcpy(&faddr, &start[soffset-1], 4);
165 for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4)
166 memcpy(&dptr[doffset-1], &start[soffset-1], 4);
167
168
169
170 if (memcmp(&saddr, &start[soffset+3], 4) == 0)
171 doffset -= 4;
172 }
173 if (doffset > 3)
174 {
175 memcpy(&start[doffset-1], &daddr, 4);
176 dopt->faddr = faddr;
177 dptr[0] = start[0];
178 dptr[1] = doffset+3;
179 dptr[2] = 4;
180 dptr += doffset+3;
181 dopt->srr = dopt->optlen + sizeof(struct iphdr);
182 dopt->optlen += doffset+3;
183 dopt->is_strictroute = sopt->is_strictroute;
184 }
185 }
186 while (dopt->optlen & 3)
187 {
188 *dptr++ = IPOPT_END;
189 dopt->optlen++;
190 }
191 return 0;
192 }
193
194 void ip_options_fragment(struct sk_buff * skb)
195 {
196 unsigned char * optptr = (unsigned char*)skb->ip_hdr;
197 struct options * opt = (struct options*)skb->proto_priv;
198 int l = opt->optlen;
199 int optlen;
200
201 while (l > 0)
202 {
203 switch (*optptr)
204 {
205 case IPOPT_END:
206 return;
207 case IPOPT_NOOP:
208 l--;
209 optptr++;
210 continue;
211 }
212 optlen = optptr[1];
213 if (l<2 || optlen>l)
214 return;
215 if (!(*optptr & 0x80))
216 memset(optptr, IPOPT_NOOP, optlen);
217 l -= optlen;
218 optptr += optlen;
219 }
220 opt->ts = 0;
221 opt->rr = 0;
222 opt->rr_needaddr = 0;
223 opt->ts_needaddr = 0;
224 opt->ts_needtime = 0;
225 return;
226 }
227
228
229
230
231
232
233
234 int ip_options_compile(struct options * opt, struct sk_buff * skb)
235 {
236 int l;
237 unsigned char * iph;
238 unsigned char * optptr;
239 int optlen;
240 unsigned char * pp_ptr = NULL;
241
242 if (!opt)
243 {
244 opt = (struct options*)skb->proto_priv;
245 memset(opt, 0, sizeof(struct options));
246 iph = (unsigned char*)skb->ip_hdr;
247 opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);
248 optptr = iph + sizeof(struct iphdr);
249 opt->is_data = 0;
250 }
251 else
252 {
253 optptr = opt->is_data ? opt->__data : (unsigned char*)&skb->ip_hdr[1];
254 iph = optptr - sizeof(struct iphdr);
255 }
256
257 for (l = opt->optlen; l > 0; )
258 {
259 switch (*optptr)
260 {
261 case IPOPT_END:
262 for (optptr++, l--; l>0; l--)
263 {
264 if (*optptr != IPOPT_END)
265 {
266 *optptr = IPOPT_END;
267 opt->is_changed = 1;
268 }
269 }
270 goto eol;
271 case IPOPT_NOOP:
272 l--;
273 optptr++;
274 continue;
275 }
276 optlen = optptr[1];
277 if (l<2 || optlen>l)
278 {
279 pp_ptr = optptr;
280 break;
281 }
282 switch (*optptr)
283 {
284 case IPOPT_SSRR:
285 case IPOPT_LSRR:
286 if (optlen < 3)
287 {
288 pp_ptr = optptr + 1;
289 break;
290 }
291 if (optptr[2] < 4)
292 {
293 pp_ptr = optptr + 2;
294 break;
295 }
296
297 if (opt->srr)
298 {
299 pp_ptr = optptr;
300 break;
301 }
302 if (!skb)
303 {
304 if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3))
305 {
306 pp_ptr = optptr + 1;
307 break;
308 }
309 memcpy(&opt->faddr, &optptr[3], 4);
310 if (optlen > 7)
311 memmove(&optptr[3], &optptr[7], optlen-7);
312 }
313 opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
314 opt->srr = optptr - iph;
315 break;
316 case IPOPT_RR:
317 if (opt->rr)
318 {
319 pp_ptr = optptr;
320 break;
321 }
322 if (optlen < 3)
323 {
324 pp_ptr = optptr + 1;
325 break;
326 }
327 if (optptr[2] < 4)
328 {
329 pp_ptr = optptr + 2;
330 break;
331 }
332 if (optptr[2] <= optlen)
333 {
334 if (optptr[2]+3 > optlen)
335 {
336 pp_ptr = optptr + 2;
337 break;
338 }
339 if (skb)
340 {
341 memcpy(&optptr[optptr[2]-1], &skb->dev->pa_addr, 4);
342 opt->is_changed = 1;
343 }
344 optptr[2] += 4;
345 opt->rr_needaddr = 1;
346 }
347 opt->rr = optptr - iph;
348 break;
349 case IPOPT_TIMESTAMP:
350 if (opt->ts)
351 {
352 pp_ptr = optptr;
353 break;
354 }
355 if (optlen < 4)
356 {
357 pp_ptr = optptr + 1;
358 break;
359 }
360 if (optptr[2] < 5)
361 {
362 pp_ptr = optptr + 2;
363 break;
364 }
365 if (optptr[2] <= optlen)
366 {
367 struct timestamp * ts = (struct timestamp*)(optptr+1);
368 __u32 * timeptr = NULL;
369 if (ts->ptr+3 > ts->len)
370 {
371 pp_ptr = optptr + 2;
372 break;
373 }
374 switch (ts->flags)
375 {
376 case IPOPT_TS_TSONLY:
377 opt->ts = optptr - iph;
378 if (skb)
379 timeptr = (__u32*)&optptr[ts->ptr-1];
380 opt->ts_needtime = 1;
381 ts->ptr += 4;
382 break;
383 case IPOPT_TS_TSANDADDR:
384 if (ts->ptr+7 > ts->len)
385 {
386 pp_ptr = optptr + 2;
387 break;
388 }
389 opt->ts = optptr - iph;
390 if (skb)
391 {
392 memcpy(&optptr[ts->ptr-1], &skb->dev->pa_addr, 4);
393 timeptr = (__u32*)&optptr[ts->ptr+3];
394 }
395 opt->ts_needaddr = 1;
396 opt->ts_needtime = 1;
397 ts->ptr += 8;
398 break;
399 case IPOPT_TS_PRESPEC:
400 if (ts->ptr+7 > ts->len)
401 {
402 pp_ptr = optptr + 2;
403 break;
404 }
405 opt->ts = optptr - iph;
406 {
407 __u32 addr;
408 memcpy(&addr, &optptr[ts->ptr-1], 4);
409 if (ip_chk_addr(addr) == 0)
410 break;
411 if (skb)
412 timeptr = (__u32*)&optptr[ts->ptr+3];
413 }
414 opt->ts_needaddr = 1;
415 opt->ts_needtime = 1;
416 ts->ptr += 8;
417 break;
418 default:
419 pp_ptr = optptr + 3;
420 break;
421 }
422 if (timeptr)
423 {
424 struct timeval tv;
425 __u32 midtime;
426 do_gettimeofday(&tv);
427 midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
428 memcpy(timeptr, &midtime, sizeof(__u32));
429 opt->is_changed = 1;
430 }
431 }
432 else
433 {
434 struct timestamp * ts = (struct timestamp*)(optptr+1);
435 if (ts->overflow == 15)
436 {
437 pp_ptr = optptr + 3;
438 break;
439 }
440 opt->ts = optptr - iph;
441 if (skb)
442 {
443 ts->overflow++;
444 opt->is_changed = 1;
445 }
446 }
447 break;
448 case IPOPT_SEC:
449 case IPOPT_SID:
450 default:
451 if (!skb)
452 {
453 pp_ptr = optptr;
454 break;
455 }
456 break;
457 }
458 l -= optlen;
459 optptr += optlen;
460 }
461
462 eol:
463 if (!pp_ptr)
464 return 0;
465
466 if (skb)
467 {
468 icmp_send(skb, ICMP_PARAMETERPROB, 0, pp_ptr-iph, skb->dev);
469 kfree_skb(skb, FREE_READ);
470 }
471 return -EINVAL;
472 }
473