VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/ip_input.c@ 22206

最後變更 在這個檔案從22206是 22013,由 vboxsync 提交於 15 年 前

NAT: clearing (removing non-libalias code)

  • 屬性 svn:eol-style 設為 native
檔案大小: 15.5 KB
 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)ip_input.c 8.2 (Berkeley) 1/4/94
34 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
35 */
36
37/*
38 * Changes and additions relating to SLiRP are
39 * Copyright (c) 1995 Danny Gasparovski.
40 *
41 * Please read the file COPYRIGHT for the
42 * terms and conditions of the copyright.
43 */
44
45#include <slirp.h>
46#include "ip_icmp.h"
47#include "alias.h"
48
49
50/*
51 * IP initialization: fill in IP protocol switch table.
52 * All protocols not implemented in kernel go to raw IP protocol handler.
53 */
54void
55ip_init(PNATState pData)
56{
57 int i = 0;
58 for (i = 0; i < IPREASS_NHASH; ++i)
59 TAILQ_INIT(&ipq[i]);
60 maxnipq = 100; /* ??? */
61 maxfragsperpacket = 16;
62 nipq = 0;
63 ip_currid = tt.tv_sec & 0xffff;
64 udp_init(pData);
65 tcp_init(pData);
66}
67
68/*
69 * Ip input routine. Checksum and byte swap header. If fragmented
70 * try to reassemble. Process options. Pass to next level.
71 */
72void
73ip_input(PNATState pData, struct mbuf *m)
74{
75 register struct ip *ip;
76 int hlen = 0;
77 STAM_PROFILE_START(&pData->StatIP_input, a);
78
79 DEBUG_CALL("ip_input");
80 DEBUG_ARG("m = %lx", (long)m);
81 ip = mtod(m, struct ip *);
82 Log2(("ip_dst=%R[IP4](len:%d) m_len = %d", &ip->ip_dst, ntohs(ip->ip_len), m->m_len));
83 Log2(("ip_dst=%R[IP4](len:%d) m_len = %d\n", &ip->ip_dst, ntohs(ip->ip_len), m->m_len));
84
85 ipstat.ips_total++;
86 {
87 int rc;
88 STAM_PROFILE_START(&pData->StatALIAS_input, a);
89 rc = LibAliasIn(m->m_la ? m->m_la : pData->proxy_alias, mtod(m, char *),
90 m->m_len);
91 STAM_PROFILE_STOP(&pData->StatALIAS_input, a);
92 Log2(("NAT: LibAlias return %d\n", rc));
93 }
94
95 if (m->m_len < sizeof(struct ip))
96 {
97 ipstat.ips_toosmall++;
98 STAM_PROFILE_STOP(&pData->StatIP_input, a);
99 return;
100 }
101
102 ip = mtod(m, struct ip *);
103 if (ip->ip_v != IPVERSION)
104 {
105 ipstat.ips_badvers++;
106 goto bad;
107 }
108
109 hlen = ip->ip_hl << 2;
110 if ( hlen < sizeof(struct ip)
111 || hlen > m->m_len)
112 {
113 /* min header length */
114 ipstat.ips_badhlen++; /* or packet too short */
115 goto bad;
116 }
117
118 /* keep ip header intact for ICMP reply
119 * ip->ip_sum = cksum(m, hlen);
120 * if (ip->ip_sum) {
121 */
122 if (cksum(m, hlen))
123 {
124 ipstat.ips_badsum++;
125 goto bad;
126 }
127
128 /*
129 * Convert fields to host representation.
130 */
131 NTOHS(ip->ip_len);
132 if (ip->ip_len < hlen)
133 {
134 ipstat.ips_badlen++;
135 goto bad;
136 }
137 NTOHS(ip->ip_id);
138 NTOHS(ip->ip_off);
139
140 /*
141 * Check that the amount of data in the buffers
142 * is as at least much as the IP header would have us expect.
143 * Trim mbufs if longer than we expect.
144 * Drop packet if shorter than we expect.
145 */
146 if (m->m_len < ip->ip_len)
147 {
148 ipstat.ips_tooshort++;
149 goto bad;
150 }
151 /* Should drop packet if mbuf too long? hmmm... */
152 if (m->m_len > ip->ip_len)
153 m_adj(m, ip->ip_len - m->m_len);
154
155 /* check ip_ttl for a correct ICMP reply */
156 if (ip->ip_ttl==0 || ip->ip_ttl == 1)
157 {
158 icmp_error(pData, m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
159 goto bad;
160 }
161
162 ip->ip_ttl--;
163 /*
164 * If offset or IP_MF are set, must reassemble.
165 * Otherwise, nothing need be done.
166 * (We could look in the reassembly queue to see
167 * if the packet was previously fragmented,
168 * but it's not worth the time; just let them time out.)
169 *
170 * XXX This should fail, don't fragment yet
171 */
172 if (ip->ip_off & (IP_MF | IP_OFFMASK))
173 {
174 m = ip_reass(pData, m);
175 if (m == NULL)
176 {
177 STAM_PROFILE_STOP(&pData->StatIP_input, a);
178 return;
179 }
180 ip = mtod(m, struct ip *);
181 hlen = ip->ip_len;
182 }
183 else
184 ip->ip_len -= hlen;
185
186 /*
187 * Switch out to protocol's input routine.
188 */
189 ipstat.ips_delivered++;
190 switch (ip->ip_p)
191 {
192 case IPPROTO_TCP:
193 tcp_input(pData, m, hlen, (struct socket *)NULL);
194 break;
195 case IPPROTO_UDP:
196 udp_input(pData, m, hlen);
197 break;
198 case IPPROTO_ICMP:
199 icmp_input(pData, m, hlen);
200 break;
201 default:
202 ipstat.ips_noproto++;
203 m_free(pData, m);
204 }
205 STAM_PROFILE_STOP(&pData->StatIP_input, a);
206 return;
207bad:
208 Log2(("NAT: IP datagram to %R[IP4] with size(%d) claimed as bad\n",
209 &ip->ip_dst, ip->ip_len));
210 m_freem(pData, m);
211 STAM_PROFILE_STOP(&pData->StatIP_input, a);
212 return;
213}
214
215struct mbuf *
216ip_reass(PNATState pData, struct mbuf* m)
217{
218 struct ip *ip;
219 struct mbuf *p, *q, *nq;
220 struct ipq_t *fp = NULL;
221 struct ipqhead *head;
222 int i, hlen, next;
223 u_short hash;
224
225 /* If maxnipq or maxfragsperpacket are 0, never accept fragments. */
226 if ( maxnipq == 0
227 || maxfragsperpacket == 0)
228 {
229 ipstat.ips_fragments++;
230 ipstat.ips_fragdropped++;
231 m_freem(pData, m);
232 return (NULL);
233 }
234
235 ip = mtod(m, struct ip *);
236 hlen = ip->ip_hl << 2;
237
238 hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
239 head = &ipq[hash];
240
241 /*
242 * Look for queue of fragments
243 * of this datagram.
244 */
245 TAILQ_FOREACH(fp, head, ipq_list)
246 if (ip->ip_id == fp->ipq_id &&
247 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
248 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
249 ip->ip_p == fp->ipq_p)
250 goto found;
251
252 fp = NULL;
253
254 /*
255 * Attempt to trim the number of allocated fragment queues if it
256 * exceeds the administrative limit.
257 */
258 if ((nipq > maxnipq) && (maxnipq > 0))
259 {
260 /*
261 * drop something from the tail of the current queue
262 * before proceeding further
263 */
264 struct ipq_t *q = TAILQ_LAST(head, ipqhead);
265 if (q == NULL)
266 {
267 /* gak */
268 for (i = 0; i < IPREASS_NHASH; i++)
269 {
270 struct ipq_t *r = TAILQ_LAST(&ipq[i], ipqhead);
271 if (r)
272 {
273 ipstat.ips_fragtimeout += r->ipq_nfrags;
274 ip_freef(pData, &ipq[i], r);
275 break;
276 }
277 }
278 }
279 else
280 {
281 ipstat.ips_fragtimeout += q->ipq_nfrags;
282 ip_freef(pData, head, q);
283 }
284 }
285
286found:
287 /*
288 * Adjust ip_len to not reflect header,
289 * convert offset of this to bytes.
290 */
291 ip->ip_len -= hlen;
292 if (ip->ip_off & IP_MF)
293 {
294 /*
295 * Make sure that fragments have a data length
296 * that's a non-zero multiple of 8 bytes.
297 */
298 if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0)
299 {
300 ipstat.ips_toosmall++; /* XXX */
301 goto dropfrag;
302 }
303 m->m_flags |= M_FRAG;
304 }
305 else
306 m->m_flags &= ~M_FRAG;
307 ip->ip_off <<= 3;
308
309
310 /*
311 * Attempt reassembly; if it succeeds, proceed.
312 * ip_reass() will return a different mbuf.
313 */
314 ipstat.ips_fragments++;
315
316 /* Previous ip_reass() started here. */
317 /*
318 * Presence of header sizes in mbufs
319 * would confuse code below.
320 */
321 m->m_data += hlen;
322 m->m_len -= hlen;
323
324 /*
325 * If first fragment to arrive, create a reassembly queue.
326 */
327 if (fp == NULL)
328 {
329 fp = RTMemAlloc(sizeof(struct ipq_t));
330 if (fp == NULL)
331 goto dropfrag;
332 TAILQ_INSERT_HEAD(head, fp, ipq_list);
333 nipq++;
334 fp->ipq_nfrags = 1;
335 fp->ipq_ttl = IPFRAGTTL;
336 fp->ipq_p = ip->ip_p;
337 fp->ipq_id = ip->ip_id;
338 fp->ipq_src = ip->ip_src;
339 fp->ipq_dst = ip->ip_dst;
340 fp->ipq_frags = m;
341 m->m_nextpkt = NULL;
342 goto done;
343 }
344 else
345 {
346 fp->ipq_nfrags++;
347 }
348
349#define GETIP(m) ((struct ip*)(MBUF_IP_HEADER(m)))
350
351
352 /*
353 * Find a segment which begins after this one does.
354 */
355 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
356 if (GETIP(q)->ip_off > ip->ip_off)
357 break;
358
359 /*
360 * If there is a preceding segment, it may provide some of
361 * our data already. If so, drop the data from the incoming
362 * segment. If it provides all of our data, drop us, otherwise
363 * stick new segment in the proper place.
364 *
365 * If some of the data is dropped from the the preceding
366 * segment, then it's checksum is invalidated.
367 */
368 if (p)
369 {
370 i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
371 if (i > 0)
372 {
373 if (i >= ip->ip_len)
374 goto dropfrag;
375 m_adj(m, i);
376 ip->ip_off += i;
377 ip->ip_len -= i;
378 }
379 m->m_nextpkt = p->m_nextpkt;
380 p->m_nextpkt = m;
381 }
382 else
383 {
384 m->m_nextpkt = fp->ipq_frags;
385 fp->ipq_frags = m;
386 }
387
388 /*
389 * While we overlap succeeding segments trim them or,
390 * if they are completely covered, dequeue them.
391 */
392 for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
393 q = nq)
394 {
395 i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off;
396 if (i < GETIP(q)->ip_len)
397 {
398 GETIP(q)->ip_len -= i;
399 GETIP(q)->ip_off += i;
400 m_adj(q, i);
401 break;
402 }
403 nq = q->m_nextpkt;
404 m->m_nextpkt = nq;
405 ipstat.ips_fragdropped++;
406 fp->ipq_nfrags--;
407 m_freem(pData, q);
408 }
409
410 /*
411 * Check for complete reassembly and perform frag per packet
412 * limiting.
413 *
414 * Frag limiting is performed here so that the nth frag has
415 * a chance to complete the packet before we drop the packet.
416 * As a result, n+1 frags are actually allowed per packet, but
417 * only n will ever be stored. (n = maxfragsperpacket.)
418 *
419 */
420 next = 0;
421 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
422 {
423 if (GETIP(q)->ip_off != next)
424 {
425 if (fp->ipq_nfrags > maxfragsperpacket)
426 {
427 ipstat.ips_fragdropped += fp->ipq_nfrags;
428 ip_freef(pData, head, fp);
429 }
430 goto done;
431 }
432 next += GETIP(q)->ip_len;
433 }
434 /* Make sure the last packet didn't have the IP_MF flag */
435 if (p->m_flags & M_FRAG)
436 {
437 if (fp->ipq_nfrags > maxfragsperpacket)
438 {
439 ipstat.ips_fragdropped += fp->ipq_nfrags;
440 ip_freef(pData, head, fp);
441 }
442 goto done;
443 }
444
445 /*
446 * Reassembly is complete. Make sure the packet is a sane size.
447 */
448 q = fp->ipq_frags;
449 ip = GETIP(q);
450 if (next + (ip->ip_hl << 2) > IP_MAXPACKET)
451 {
452 ipstat.ips_fragdropped += fp->ipq_nfrags;
453 ip_freef(pData, head, fp);
454 goto done;
455 }
456
457 /*
458 * Concatenate fragments.
459 */
460 m = q;
461 nq = q->m_nextpkt;
462 q->m_nextpkt = NULL;
463 for (q = nq; q != NULL; q = nq)
464 {
465 nq = q->m_nextpkt;
466 q->m_nextpkt = NULL;
467 m_cat(pData, m, q);
468 }
469
470 /*
471 * Create header for new ip packet by modifying header of first
472 * packet; dequeue and discard fragment reassembly header.
473 * Make header visible.
474 */
475#if 0
476 ip->ip_len = (ip->ip_hl << 2) + next;
477#else
478 ip->ip_len = next;
479#endif
480 ip->ip_src = fp->ipq_src;
481 ip->ip_dst = fp->ipq_dst;
482 TAILQ_REMOVE(head, fp, ipq_list);
483 nipq--;
484 RTMemFree(fp);
485
486 m->m_len += (ip->ip_hl << 2);
487 m->m_data -= (ip->ip_hl << 2);
488 /* some debugging cruft by sklower, below, will go away soon */
489#if 0
490 if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
491 m_fixhdr(m);
492#endif
493 ipstat.ips_reassembled++;
494 return (m);
495
496dropfrag:
497 ipstat.ips_fragdropped++;
498 if (fp != NULL)
499 fp->ipq_nfrags--;
500 m_freem(pData, m);
501
502done:
503 return NULL;
504
505#undef GETIP
506}
507
508void
509ip_freef(PNATState pData, struct ipqhead *fhp, struct ipq_t *fp)
510{
511 struct mbuf *q;
512
513 while (fp->ipq_frags)
514 {
515 q = fp->ipq_frags;
516 fp->ipq_frags = q->m_nextpkt;
517 m_freem(pData, q);
518 }
519 TAILQ_REMOVE(fhp, fp, ipq_list);
520 RTMemFree(fp);
521 nipq--;
522}
523
524/*
525 * IP timer processing;
526 * if a timer expires on a reassembly
527 * queue, discard it.
528 */
529void
530ip_slowtimo(PNATState pData)
531{
532 register struct ipq_t *fp;
533
534 /* XXX: the fragment expiration is the same but requier
535 * additional loop see (see ip_input.c in FreeBSD tree)
536 */
537 int i;
538 DEBUG_CALL("ip_slowtimo");
539 for (i = 0; i < IPREASS_NHASH; i++)
540 {
541 for(fp = TAILQ_FIRST(&ipq[i]); fp;)
542 {
543 struct ipq_t *fpp;
544
545 fpp = fp;
546 fp = TAILQ_NEXT(fp, ipq_list);
547 if(--fpp->ipq_ttl == 0)
548 {
549 ipstat.ips_fragtimeout += fpp->ipq_nfrags;
550 ip_freef(pData, &ipq[i], fpp);
551 }
552 }
553 }
554 /*
555 * If we are over the maximum number of fragments
556 * (due to the limit being lowered), drain off
557 * enough to get down to the new limit.
558 */
559 if (maxnipq >= 0 && nipq > maxnipq)
560 {
561 for (i = 0; i < IPREASS_NHASH; i++)
562 {
563 while (nipq > maxnipq && !TAILQ_EMPTY(&ipq[i]))
564 {
565 ipstat.ips_fragdropped += TAILQ_FIRST(&ipq[i])->ipq_nfrags;
566 ip_freef(pData, &ipq[i], TAILQ_FIRST(&ipq[i]));
567 }
568 }
569 }
570}
571
572
573/*
574 * Strip out IP options, at higher
575 * level protocol in the kernel.
576 * Second argument is buffer to which options
577 * will be moved, and return value is their length.
578 * (XXX) should be deleted; last arg currently ignored.
579 */
580void
581ip_stripoptions(struct mbuf *m, struct mbuf *mopt)
582{
583 register int i;
584 struct ip *ip = mtod(m, struct ip *);
585 register caddr_t opts;
586 int olen;
587
588 olen = (ip->ip_hl<<2) - sizeof(struct ip);
589 opts = (caddr_t)(ip + 1);
590 i = m->m_len - (sizeof(struct ip) + olen);
591 memcpy(opts, opts + olen, (unsigned)i);
592 m->m_len -= olen;
593
594 ip->ip_hl = sizeof(struct ip) >> 2;
595}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette