|
|
1.1 root 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. Neither the name of the University nor the names of its contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: *
29: * @(#)ip_input.c 8.2 (Berkeley) 1/4/94
30: * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
31: */
32:
33: /*
34: * Changes and additions relating to SLiRP are
35: * Copyright (c) 1995 Danny Gasparovski.
36: *
37: * Please read the file COPYRIGHT for the
38: * terms and conditions of the copyright.
39: */
40:
41: #include <stdarg.h>
42: #include <stddef.h>
43: #include <stdbool.h>
44: #include <sys/types.h>
45:
46: #define container_of(ptr, type, member) ({ \
47: typeof(((type *) 0)->member) *__mptr = (ptr); \
48: (type *) ((char *) __mptr - offsetof(type, member));})
49:
50:
51: #include <slirp.h>
52: #include "ip_icmp.h"
53:
54: int ip_defttl;
55: struct ipstat ipstat;
56: struct ipq ipq;
57:
58: /*
59: * IP initialization: fill in IP protocol switch table.
60: * All protocols not implemented in kernel go to raw IP protocol handler.
61: */
62: void
63: ip_init()
64: {
65: ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link;
66: ip_id = tt.tv_sec & 0xffff;
67: udp_init();
68: tcp_init();
69: ip_defttl = IPDEFTTL;
70: }
71:
72: /*
73: * Ip input routine. Checksum and byte swap header. If fragmented
74: * try to reassemble. Process options. Pass to next level.
75: */
76: void
77: ip_input(m)
78: struct mbuf *m;
79: {
80: register struct ip *ip;
81: u_int hlen;
82:
83: DEBUG_CALL("ip_input");
84: DEBUG_ARG("m = %lx", (long)m);
85: DEBUG_ARG("m_len = %zu", m->m_len);
86:
87: ipstat.ips_total++;
88:
89: if (m->m_len < sizeof (struct ip)) {
90: ipstat.ips_toosmall++;
91: return;
92: }
93:
94: ip = mtod(m, struct ip *);
95:
96: if (ip->ip_v != IPVERSION) {
97: ipstat.ips_badvers++;
98: goto bad;
99: }
100:
101: hlen = ip->ip_hl << 2;
102: if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
103: ipstat.ips_badhlen++; /* or packet too short */
104: goto bad;
105: }
106:
107: /* keep ip header intact for ICMP reply
108: * ip->ip_sum = cksum(m, hlen);
109: * if (ip->ip_sum) {
110: */
111: if(cksum(m,hlen)) {
112: ipstat.ips_badsum++;
113: goto bad;
114: }
115:
116: /*
117: * Convert fields to host representation.
118: */
119: NTOHS(ip->ip_len);
120: if (ip->ip_len < hlen) {
121: ipstat.ips_badlen++;
122: goto bad;
123: }
124: NTOHS(ip->ip_id);
125: NTOHS(ip->ip_off);
126:
127: /*
128: * Check that the amount of data in the buffers
129: * is as at least much as the IP header would have us expect.
130: * Trim mbufs if longer than we expect.
131: * Drop packet if shorter than we expect.
132: */
133: if (m->m_len < ip->ip_len) {
134: ipstat.ips_tooshort++;
135: goto bad;
136: }
137: /* Should drop packet if mbuf too long? hmmm... */
138: if (m->m_len > ip->ip_len)
139: m_adj(m, ip->ip_len - m->m_len);
140:
141: /* check ip_ttl for a correct ICMP reply */
142: if(ip->ip_ttl==0 || ip->ip_ttl==1) {
143: icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0, "ttl");
144: goto bad;
145: }
146:
147: /*
148: * Process options and, if not destined for us,
149: * ship it on. ip_dooptions returns 1 when an
150: * error was detected (causing an icmp message
151: * to be sent and the original packet to be freed).
152: */
153: /* We do no IP options */
154: /* if (hlen > sizeof (struct ip) && ip_dooptions(m))
155: * goto next;
156: */
157: /*
158: * If offset or IP_MF are set, must reassemble.
159: * Otherwise, nothing need be done.
160: * (We could look in the reassembly queue to see
161: * if the packet was previously fragmented,
162: * but it's not worth the time; just let them time out.)
163: *
164: * XXX This should fail, don't fragment yet
165: */
166: if (ip->ip_off &~ IP_DF) {
167: register struct ipq *fp;
168: struct qlink *l;
169: /*
170: * Look for queue of fragments
171: * of this datagram.
172: */
173: for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) {
174: fp = container_of(l, struct ipq, ip_link);
175: if (ip->ip_id == fp->ipq_id &&
176: ip->ip_src.s_addr == fp->ipq_src.s_addr &&
177: ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
178: ip->ip_p == fp->ipq_p)
179: goto found;
180: }
181: fp = NULL;
182: found:
183:
184: /*
185: * Adjust ip_len to not reflect header,
186: * set ip_mff if more fragments are expected,
187: * convert offset of this to bytes.
188: */
189: ip->ip_len -= hlen;
190: if (ip->ip_off & IP_MF)
191: ip->ip_tos |= 1;
192: else
193: ip->ip_tos &= ~1;
194:
195: ip->ip_off <<= 3;
196:
197: /*
198: * If datagram marked as having more fragments
199: * or if this is not the first fragment,
200: * attempt reassembly; if it succeeds, proceed.
201: */
202: if (ip->ip_tos & 1 || ip->ip_off) {
203: ipstat.ips_fragments++;
204: ip = ip_reass(ip, fp);
205: if (ip == 0)
206: return;
207: ipstat.ips_reassembled++;
208: m = dtom(ip);
209: } else
210: if (fp)
211: ip_freef(fp);
212:
213: } else
214: ip->ip_len -= hlen;
215:
216: /*
217: * Switch out to protocol's input routine.
218: */
219: ipstat.ips_delivered++;
220: switch (ip->ip_p) {
221: case IPPROTO_TCP:
222: tcp_input(m, hlen, (struct socket *)NULL);
223: break;
224: case IPPROTO_UDP:
225: udp_input(m, hlen);
226: break;
227: case IPPROTO_ICMP:
228: icmp_input(m, hlen);
229: break;
230: default:
231: ipstat.ips_noproto++;
232: m_free(m);
233: }
234: return;
235: bad:
236: m_freem(m);
237: return;
238: }
239:
240: #define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
241: #define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
242: /*
243: * Take incoming datagram fragment and try to
244: * reassemble it into whole datagram. If a chain for
245: * reassembly of this datagram already exists, then it
246: * is given as fp; otherwise have to make a chain.
247: */
248: struct ip *
249: ip_reass(register struct ip *ip, register struct ipq *fp)
250: {
251: register struct mbuf *m = dtom(ip);
252: register struct ipasfrag *q;
253: int hlen = ip->ip_hl << 2;
254: int i, next;
255:
256: DEBUG_CALL("ip_reass");
257: DEBUG_ARG("ip = %lx", (long)ip);
258: DEBUG_ARG("fp = %lx", (long)fp);
259: DEBUG_ARG("m = %lx", (long)m);
260:
261: /*
262: * Presence of header sizes in mbufs
263: * would confuse code below.
264: * Fragment m_data is concatenated.
265: */
266: m->m_data += hlen;
267: m->m_len -= hlen;
268:
269: /*
270: * If first fragment to arrive, create a reassembly queue.
271: */
272: if (fp == 0) {
273: struct mbuf *t;
274: if ((t = m_get()) == NULL) goto dropfrag;
275: fp = mtod(t, struct ipq *);
276: insque(&fp->ip_link, &ipq.ip_link);
277: fp->ipq_ttl = IPFRAGTTL;
278: fp->ipq_p = ip->ip_p;
279: fp->ipq_id = ip->ip_id;
280: fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
281: fp->ipq_src = ip->ip_src;
282: fp->ipq_dst = ip->ip_dst;
283: q = (struct ipasfrag *)fp;
284: goto insert;
285: }
286:
287: /*
288: * Find a segment which begins after this one does.
289: */
290: for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
291: q = q->ipf_next)
292: if (q->ipf_off > ip->ip_off)
293: break;
294:
295: /*
296: * If there is a preceding segment, it may provide some of
297: * our data already. If so, drop the data from the incoming
298: * segment. If it provides all of our data, drop us.
299: */
300: if (q->ipf_prev != &fp->frag_link) {
301: struct ipasfrag *pq = q->ipf_prev;
302: i = pq->ipf_off + pq->ipf_len - ip->ip_off;
303: if (i > 0) {
304: if (i >= ip->ip_len)
305: goto dropfrag;
306: m_adj(dtom(ip), i);
307: ip->ip_off += i;
308: ip->ip_len -= i;
309: }
310: }
311:
312: /*
313: * While we overlap succeeding segments trim them or,
314: * if they are completely covered, dequeue them.
315: */
316: while (q != (struct ipasfrag*)&fp->frag_link &&
317: ip->ip_off + ip->ip_len > q->ipf_off) {
318: i = (ip->ip_off + ip->ip_len) - q->ipf_off;
319: if (i < q->ipf_len) {
320: q->ipf_len -= i;
321: q->ipf_off += i;
322: m_adj(dtom(q), i);
323: break;
324: }
325: q = q->ipf_next;
326: m_freem(dtom(q->ipf_prev));
327: ip_deq(q->ipf_prev);
328: }
329:
330: insert:
331: /*
332: * Stick new segment in its place;
333: * check for complete reassembly.
334: */
335: ip_enq(iptofrag(ip), q->ipf_prev);
336: next = 0;
337: for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
338: q = q->ipf_next) {
339: if (q->ipf_off != next)
340: return (0);
341: next += q->ipf_len;
342: }
343: if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
344: return (0);
345:
346: /*
347: * Reassembly is complete; concatenate fragments.
348: */
349: q = fp->frag_link.next;
350: m = dtom(q);
351:
352: q = (struct ipasfrag *) q->ipf_next;
353: while (q != (struct ipasfrag*)&fp->frag_link) {
354: struct mbuf *t = dtom(q);
355: q = (struct ipasfrag *) q->ipf_next;
356: m_cat(m, t);
357: }
358:
359: /*
360: * Create header for new ip packet by
361: * modifying header of first packet;
362: * dequeue and discard fragment reassembly header.
363: * Make header visible.
364: */
365: q = fp->frag_link.next;
366:
367: /*
368: * If the fragments concatenated to an mbuf that's
369: * bigger than the total size of the fragment, then and
370: * m_ext buffer was alloced. But fp->ipq_next points to
371: * the old buffer (in the mbuf), so we must point ip
372: * into the new buffer.
373: */
374: if (m->m_flags & M_EXT) {
375: int delta;
376: delta = (char *)q - m->m_dat;
377: q = (struct ipasfrag *)(m->m_ext + delta);
378: }
379:
380: /* DEBUG_ARG("ip = %lx", (long)ip);
381: * ip=(struct ipasfrag *)m->m_data; */
382:
383: ip = fragtoip(q);
384: ip->ip_len = next;
385: ip->ip_tos &= ~1;
386: ip->ip_src = fp->ipq_src;
387: ip->ip_dst = fp->ipq_dst;
388: remque(&fp->ip_link);
389: (void) m_free(dtom(fp));
390: m->m_len += (ip->ip_hl << 2);
391: m->m_data -= (ip->ip_hl << 2);
392:
393: return ip;
394:
395: dropfrag:
396: ipstat.ips_fragdropped++;
397: m_freem(m);
398: return (0);
399: }
400:
401: /*
402: * Free a fragment reassembly header and all
403: * associated datagrams.
404: */
405: void
406: ip_freef(fp)
407: struct ipq *fp;
408: {
409: register struct ipasfrag *q, *p;
410:
411: for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
412: p = q->ipf_next;
413: ip_deq(q);
414: m_freem(dtom(q));
415: }
416: remque(&fp->ip_link);
417: (void) m_free(dtom(fp));
418: }
419:
420: /*
421: * Put an ip fragment on a reassembly chain.
422: * Like insque, but pointers in middle of structure.
423: */
424: void
425: ip_enq(p, prev)
426: register struct ipasfrag *p, *prev;
427: {
428: DEBUG_CALL("ip_enq");
429: DEBUG_ARG("prev = %lx", (long)prev);
430: p->ipf_prev = prev;
431: p->ipf_next = prev->ipf_next;
432: ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
433: prev->ipf_next = p;
434: }
435:
436: /*
437: * To ip_enq as remque is to insque.
438: */
439: void
440: ip_deq(p)
441: register struct ipasfrag *p;
442: {
443: ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
444: ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
445: }
446:
447: /*
448: * IP timer processing;
449: * if a timer expires on a reassembly
450: * queue, discard it.
451: */
452: void
453: ip_slowtimo()
454: {
455: struct qlink *l;
456:
457: DEBUG_CALL("ip_slowtimo");
458:
459: l = ipq.ip_link.next;
460:
461: if (l == 0)
462: return;
463:
464: while (l != &ipq.ip_link) {
465: struct ipq *fp = container_of(l, struct ipq, ip_link);
466: l = l->next;
467: if (--fp->ipq_ttl == 0) {
468: ipstat.ips_fragtimeout++;
469: ip_freef(fp);
470: }
471: }
472: }
473:
474: /*
475: * Do option processing on a datagram,
476: * possibly discarding it if bad options are encountered,
477: * or forwarding it if source-routed.
478: * Returns 1 if packet has been forwarded/freed,
479: * 0 if the packet should be processed further.
480: */
481:
482: #ifdef notdef
483:
484: int
485: ip_dooptions(m)
486: struct mbuf *m;
487: {
488: register struct ip *ip = mtod(m, struct ip *);
489: register u_char *cp;
490: register struct ip_timestamp *ipt;
491: register struct in_ifaddr *ia;
492: /* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */
493: int opt, optlen, cnt, off, code, type, forward = 0;
494: struct in_addr *sin, dst;
495: typedef u_int32_t n_time;
496: n_time ntime;
497:
498: dst = ip->ip_dst;
499: cp = (u_char *)(ip + 1);
500: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
501: for (; cnt > 0; cnt -= optlen, cp += optlen) {
502: opt = cp[IPOPT_OPTVAL];
503: if (opt == IPOPT_EOL)
504: break;
505: if (opt == IPOPT_NOP)
506: optlen = 1;
507: else {
508: optlen = cp[IPOPT_OLEN];
509: if (optlen <= 0 || optlen > cnt) {
510: code = &cp[IPOPT_OLEN] - (u_char *)ip;
511: goto bad;
512: }
513: }
514: switch (opt) {
515:
516: default:
517: break;
518:
519: /*
520: * Source routing with record.
521: * Find interface with current destination address.
522: * If none on this machine then drop if strictly routed,
523: * or do nothing if loosely routed.
524: * Record interface address and bring up next address
525: * component. If strictly routed make sure next
526: * address is on directly accessible net.
527: */
528: case IPOPT_LSRR:
529: case IPOPT_SSRR:
530: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
531: code = &cp[IPOPT_OFFSET] - (u_char *)ip;
532: goto bad;
533: }
534: ipaddr.sin_addr = ip->ip_dst;
535: ia = (struct in_ifaddr *)
536: ifa_ifwithaddr((struct sockaddr *)&ipaddr);
537: if (ia == 0) {
538: if (opt == IPOPT_SSRR) {
539: type = ICMP_UNREACH;
540: code = ICMP_UNREACH_SRCFAIL;
541: goto bad;
542: }
543: /*
544: * Loose routing, and not at next destination
545: * yet; nothing to do except forward.
546: */
547: break;
548: }
549: off--; / * 0 origin * /
550: if (off > optlen - sizeof(struct in_addr)) {
551: /*
552: * End of source route. Should be for us.
553: */
554: save_rte(cp, ip->ip_src);
555: break;
556: }
557: /*
558: * locate outgoing interface
559: */
560: bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
561: sizeof(ipaddr.sin_addr));
562: if (opt == IPOPT_SSRR) {
563: #define INA struct in_ifaddr *
564: #define SA struct sockaddr *
565: if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
566: ia = (INA)ifa_ifwithnet((SA)&ipaddr);
567: } else
568: ia = ip_rtaddr(ipaddr.sin_addr);
569: if (ia == 0) {
570: type = ICMP_UNREACH;
571: code = ICMP_UNREACH_SRCFAIL;
572: goto bad;
573: }
574: ip->ip_dst = ipaddr.sin_addr;
575: bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
576: (caddr_t)(cp + off), sizeof(struct in_addr));
577: cp[IPOPT_OFFSET] += sizeof(struct in_addr);
578: /*
579: * Let ip_intr's mcast routing check handle mcast pkts
580: */
581: forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
582: break;
583:
584: case IPOPT_RR:
585: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
586: code = &cp[IPOPT_OFFSET] - (u_char *)ip;
587: goto bad;
588: }
589: /*
590: * If no space remains, ignore.
591: */
592: off--; * 0 origin *
593: if (off > optlen - sizeof(struct in_addr))
594: break;
595: bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
596: sizeof(ipaddr.sin_addr));
597: /*
598: * locate outgoing interface; if we're the destination,
599: * use the incoming interface (should be same).
600: */
601: if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
602: (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
603: type = ICMP_UNREACH;
604: code = ICMP_UNREACH_HOST;
605: goto bad;
606: }
607: bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
608: (caddr_t)(cp + off), sizeof(struct in_addr));
609: cp[IPOPT_OFFSET] += sizeof(struct in_addr);
610: break;
611:
612: case IPOPT_TS:
613: code = cp - (u_char *)ip;
614: ipt = (struct ip_timestamp *)cp;
615: if (ipt->ipt_len < 5)
616: goto bad;
617: if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) {
618: if (++ipt->ipt_oflw == 0)
619: goto bad;
620: break;
621: }
622: sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
623: switch (ipt->ipt_flg) {
624:
625: case IPOPT_TS_TSONLY:
626: break;
627:
628: case IPOPT_TS_TSANDADDR:
629: if (ipt->ipt_ptr + sizeof(n_time) +
630: sizeof(struct in_addr) > ipt->ipt_len)
631: goto bad;
632: ipaddr.sin_addr = dst;
633: ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr,
634: m->m_pkthdr.rcvif);
635: if (ia == 0)
636: continue;
637: bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
638: (caddr_t)sin, sizeof(struct in_addr));
639: ipt->ipt_ptr += sizeof(struct in_addr);
640: break;
641:
642: case IPOPT_TS_PRESPEC:
643: if (ipt->ipt_ptr + sizeof(n_time) +
644: sizeof(struct in_addr) > ipt->ipt_len)
645: goto bad;
646: bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
647: sizeof(struct in_addr));
648: if (ifa_ifwithaddr((SA)&ipaddr) == 0)
649: continue;
650: ipt->ipt_ptr += sizeof(struct in_addr);
651: break;
652:
653: default:
654: goto bad;
655: }
656: ntime = iptime();
657: bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
658: sizeof(n_time));
659: ipt->ipt_ptr += sizeof(n_time);
660: }
661: }
662: if (forward) {
663: ip_forward(m, 1);
664: return (1);
665: }
666: }
667: }
668: return (0);
669: bad:
670: /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */
671:
672: /* Not yet */
673: icmp_error(m, type, code, 0, 0);
674:
675: ipstat.ips_badoptions++;
676: return (1);
677: }
678:
679: #endif /* notdef */
680:
681: /*
682: * Strip out IP options, at higher
683: * level protocol in the kernel.
684: * Second argument is buffer to which options
685: * will be moved, and return value is their length.
686: * (XXX) should be deleted; last arg currently ignored.
687: */
688: void
689: ip_stripoptions(m, mopt)
690: register struct mbuf *m;
691: struct mbuf *mopt;
692: {
693: register int i;
694: struct ip *ip = mtod(m, struct ip *);
695: register caddr_t opts;
696: int olen;
697:
698: olen = (ip->ip_hl<<2) - sizeof (struct ip);
699: opts = (caddr_t)(ip + 1);
700: i = m->m_len - (sizeof (struct ip) + olen);
701: memcpy(opts, opts + olen, (unsigned)i);
702: m->m_len -= olen;
703:
704: ip->ip_hl = sizeof(struct ip) >> 2;
705: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.