Annotation of sys/netinet/ip_icmp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ip_icmp.c,v 1.76 2007/06/11 11:29:35 henning Exp $ */
2: /* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1982, 1986, 1988, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: *
32: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
33: *
34: * NRL grants permission for redistribution and use in source and binary
35: * forms, with or without modification, of the software and documentation
36: * created at NRL provided that the following conditions are met:
37: *
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgements:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * This product includes software developed at the Information
48: * Technology Division, US Naval Research Laboratory.
49: * 4. Neither the name of the NRL nor the names of its contributors
50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
54: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
56: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
57: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64: *
65: * The views and conclusions contained in the software and documentation
66: * are those of the authors and should not be interpreted as representing
67: * official policies, either expressed or implied, of the US Naval
68: * Research Laboratory (NRL).
69: */
70:
71: #include "carp.h"
72:
73: #include <sys/param.h>
74: #include <sys/systm.h>
75: #include <sys/mbuf.h>
76: #include <sys/protosw.h>
77: #include <sys/socket.h>
78: #include <sys/sysctl.h>
79:
80: #include <net/if.h>
81: #include <net/route.h>
82:
83: #include <netinet/in.h>
84: #include <netinet/in_systm.h>
85: #include <netinet/in_var.h>
86: #include <netinet/ip.h>
87: #include <netinet/ip_icmp.h>
88: #include <netinet/ip_var.h>
89: #include <netinet/icmp_var.h>
90:
91: #if NCARP > 0
92: #include <net/if_types.h>
93: #include <netinet/ip_carp.h>
94: #endif
95:
96: /*
97: * ICMP routines: error generation, receive packet processing, and
98: * routines to turnaround packets back to the originator, and
99: * host table maintenance routines.
100: */
101:
102: int icmpmaskrepl = 0;
103: int icmpbmcastecho = 0;
104: int icmptstamprepl = 1;
105: #ifdef ICMPPRINTFS
106: int icmpprintfs = 0;
107: #endif
108: int icmperrppslim = 100;
109: int icmperrpps_count = 0;
110: struct timeval icmperrppslim_last;
111: int icmp_rediraccept = 1;
112: int icmp_redirtimeout = 10 * 60;
113: static struct rttimer_queue *icmp_redirect_timeout_q = NULL;
114: struct icmpstat icmpstat;
115:
116: int *icmpctl_vars[ICMPCTL_MAXID] = ICMPCTL_VARS;
117:
118: void icmp_mtudisc_timeout(struct rtentry *, struct rttimer *);
119: int icmp_ratelimit(const struct in_addr *, const int, const int);
120: void icmp_redirect_timeout(struct rtentry *, struct rttimer *);
121:
122: extern struct protosw inetsw[];
123:
124: void
125: icmp_init(void)
126: {
127: /*
128: * This is only useful if the user initializes redirtimeout to
129: * something other than zero.
130: */
131: if (icmp_redirtimeout != 0) {
132: icmp_redirect_timeout_q =
133: rt_timer_queue_create(icmp_redirtimeout);
134: }
135: }
136:
137: struct mbuf *
138: icmp_do_error(struct mbuf *n, int type, int code, n_long dest, int destmtu)
139: {
140: struct ip *oip = mtod(n, struct ip *), *nip;
141: unsigned oiplen = oip->ip_hl << 2;
142: struct icmp *icp;
143: struct mbuf *m;
144: unsigned icmplen, mblen;
145:
146: #ifdef ICMPPRINTFS
147: if (icmpprintfs)
148: printf("icmp_error(%x, %d, %d)\n", oip, type, code);
149: #endif
150: if (type != ICMP_REDIRECT)
151: icmpstat.icps_error++;
152: /*
153: * Don't send error if not the first fragment of message.
154: * Don't error if the old packet protocol was ICMP
155: * error message, only known informational types.
156: */
157: if (oip->ip_off & htons(IP_OFFMASK))
158: goto freeit;
159: if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
160: n->m_len >= oiplen + ICMP_MINLEN &&
161: !ICMP_INFOTYPE(((struct icmp *)
162: ((caddr_t)oip + oiplen))->icmp_type)) {
163: icmpstat.icps_oldicmp++;
164: goto freeit;
165: }
166: /* Don't send error in response to a multicast or broadcast packet */
167: if (n->m_flags & (M_BCAST|M_MCAST))
168: goto freeit;
169:
170: /*
171: * First, do a rate limitation check.
172: */
173: if (icmp_ratelimit(&oip->ip_src, type, code))
174: goto freeit; /* XXX stat */
175:
176: /*
177: * Now, formulate icmp message
178: */
179: icmplen = oiplen + min(8, ntohs(oip->ip_len));
180: /*
181: * Defend against mbuf chains shorter than oip->ip_len:
182: */
183: mblen = 0;
184: for (m = n; m && (mblen < icmplen); m = m->m_next)
185: mblen += m->m_len;
186: icmplen = min(mblen, icmplen);
187:
188: /*
189: * As we are not required to return everything we have,
190: * we return whatever we can return at ease.
191: *
192: * Note that ICMP datagrams longer than 576 octets are out of spec
193: * according to RFC1812;
194: */
195:
196: KASSERT(ICMP_MINLEN <= MCLBYTES);
197:
198: if (icmplen + ICMP_MINLEN > MCLBYTES)
199: icmplen = MCLBYTES - ICMP_MINLEN - sizeof (struct ip);
200:
201: m = m_gethdr(M_DONTWAIT, MT_HEADER);
202: if (m && (sizeof (struct ip) + icmplen + ICMP_MINLEN > MHLEN)) {
203: MCLGET(m, M_DONTWAIT);
204: if ((m->m_flags & M_EXT) == 0) {
205: m_freem(m);
206: m = NULL;
207: }
208: }
209: if (m == NULL)
210: goto freeit;
211: m->m_len = icmplen + ICMP_MINLEN;
212: if ((m->m_flags & M_EXT) == 0)
213: MH_ALIGN(m, m->m_len);
214: icp = mtod(m, struct icmp *);
215: if ((u_int)type > ICMP_MAXTYPE)
216: panic("icmp_error");
217: icmpstat.icps_outhist[type]++;
218: icp->icmp_type = type;
219: if (type == ICMP_REDIRECT)
220: icp->icmp_gwaddr.s_addr = dest;
221: else {
222: icp->icmp_void = 0;
223: /*
224: * The following assignments assume an overlay with the
225: * zeroed icmp_void field.
226: */
227: if (type == ICMP_PARAMPROB) {
228: icp->icmp_pptr = code;
229: code = 0;
230: } else if (type == ICMP_UNREACH &&
231: code == ICMP_UNREACH_NEEDFRAG && destmtu)
232: icp->icmp_nextmtu = htons(destmtu);
233: }
234:
235: icp->icmp_code = code;
236: m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
237:
238: /*
239: * Now, copy old ip header (without options)
240: * in front of icmp message.
241: */
242: if ((m->m_flags & M_EXT) == 0 &&
243: m->m_data - sizeof(struct ip) < m->m_pktdat)
244: panic("icmp len");
245: m->m_data -= sizeof(struct ip);
246: m->m_len += sizeof(struct ip);
247: m->m_pkthdr.len = m->m_len;
248: m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
249: nip = mtod(m, struct ip *);
250: /* ip_v set in ip_output */
251: nip->ip_hl = sizeof(struct ip) >> 2;
252: nip->ip_tos = 0;
253: nip->ip_len = htons(m->m_len);
254: /* ip_id set in ip_output */
255: nip->ip_off = 0;
256: /* ip_ttl set in icmp_reflect */
257: nip->ip_p = IPPROTO_ICMP;
258: nip->ip_src = oip->ip_src;
259: nip->ip_dst = oip->ip_dst;
260:
261: /* move PF_GENERATED to new packet, if existant XXX preserve more? */
262: if (n->m_pkthdr.pf.flags & PF_TAG_GENERATED)
263: m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
264:
265: m_freem(n);
266: return (m);
267:
268: freeit:
269: m_freem(n);
270: return (NULL);
271: }
272:
273: /*
274: * Generate an error packet of type error
275: * in response to bad packet ip.
276: *
277: * The ip packet inside has ip_off and ip_len in host byte order.
278: */
279: void
280: icmp_error(struct mbuf *n, int type, int code, n_long dest, int destmtu)
281: {
282: struct mbuf *m;
283:
284: m = icmp_do_error(n, type, code, dest, destmtu);
285: if (m != NULL)
286: icmp_reflect(m);
287: }
288:
289: struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
290: static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
291: static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
292:
293: /*
294: * Process a received ICMP message.
295: */
296: void
297: icmp_input(struct mbuf *m, ...)
298: {
299: struct icmp *icp;
300: struct ip *ip = mtod(m, struct ip *);
301: int icmplen;
302: int i;
303: struct in_ifaddr *ia;
304: void *(*ctlfunc)(int, struct sockaddr *, void *);
305: int code;
306: extern u_char ip_protox[];
307: int hlen;
308: va_list ap;
309: struct rtentry *rt;
310:
311: va_start(ap, m);
312: hlen = va_arg(ap, int);
313: va_end(ap);
314:
315: /*
316: * Locate icmp structure in mbuf, and check
317: * that not corrupted and of at least minimum length.
318: */
319: icmplen = ntohs(ip->ip_len) - hlen;
320: #ifdef ICMPPRINTFS
321: if (icmpprintfs) {
322: char buf[4 * sizeof("123")];
323:
324: strlcpy(buf, inet_ntoa(ip->ip_dst), sizeof buf);
325: printf("icmp_input from %s to %s, len %d\n",
326: inet_ntoa(ip->ip_src), buf, icmplen);
327: }
328: #endif
329: if (icmplen < ICMP_MINLEN) {
330: icmpstat.icps_tooshort++;
331: goto freeit;
332: }
333: i = hlen + min(icmplen, ICMP_ADVLENMIN);
334: if (m->m_len < i && (m = m_pullup(m, i)) == NULL) {
335: icmpstat.icps_tooshort++;
336: return;
337: }
338: ip = mtod(m, struct ip *);
339: m->m_len -= hlen;
340: m->m_data += hlen;
341: icp = mtod(m, struct icmp *);
342: if (in_cksum(m, icmplen)) {
343: icmpstat.icps_checksum++;
344: goto freeit;
345: }
346: m->m_len += hlen;
347: m->m_data -= hlen;
348:
349: #ifdef ICMPPRINTFS
350: /*
351: * Message type specific processing.
352: */
353: if (icmpprintfs)
354: printf("icmp_input, type %d code %d\n", icp->icmp_type,
355: icp->icmp_code);
356: #endif
357: if (icp->icmp_type > ICMP_MAXTYPE)
358: goto raw;
359: icmpstat.icps_inhist[icp->icmp_type]++;
360: code = icp->icmp_code;
361: switch (icp->icmp_type) {
362:
363: case ICMP_UNREACH:
364: switch (code) {
365: case ICMP_UNREACH_NET:
366: case ICMP_UNREACH_HOST:
367: case ICMP_UNREACH_PROTOCOL:
368: case ICMP_UNREACH_PORT:
369: case ICMP_UNREACH_SRCFAIL:
370: code += PRC_UNREACH_NET;
371: break;
372:
373: case ICMP_UNREACH_NEEDFRAG:
374: code = PRC_MSGSIZE;
375: break;
376:
377: case ICMP_UNREACH_NET_UNKNOWN:
378: case ICMP_UNREACH_NET_PROHIB:
379: case ICMP_UNREACH_TOSNET:
380: code = PRC_UNREACH_NET;
381: break;
382:
383: case ICMP_UNREACH_HOST_UNKNOWN:
384: case ICMP_UNREACH_ISOLATED:
385: case ICMP_UNREACH_HOST_PROHIB:
386: case ICMP_UNREACH_TOSHOST:
387: case ICMP_UNREACH_FILTER_PROHIB:
388: case ICMP_UNREACH_HOST_PRECEDENCE:
389: case ICMP_UNREACH_PRECEDENCE_CUTOFF:
390: code = PRC_UNREACH_HOST;
391: break;
392:
393: default:
394: goto badcode;
395: }
396: goto deliver;
397:
398: case ICMP_TIMXCEED:
399: if (code > 1)
400: goto badcode;
401: code += PRC_TIMXCEED_INTRANS;
402: goto deliver;
403:
404: case ICMP_PARAMPROB:
405: if (code > 1)
406: goto badcode;
407: code = PRC_PARAMPROB;
408: goto deliver;
409:
410: case ICMP_SOURCEQUENCH:
411: if (code)
412: goto badcode;
413: code = PRC_QUENCH;
414: deliver:
415: /* Free packet atttributes */
416: if (m->m_flags & M_PKTHDR)
417: m_tag_delete_chain(m);
418:
419: /*
420: * Problem with datagram; advise higher level routines.
421: */
422: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
423: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
424: icmpstat.icps_badlen++;
425: goto freeit;
426: }
427: if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr))
428: goto badcode;
429: #ifdef INET6
430: /* Get more contiguous data for a v6 in v4 ICMP message. */
431: if (icp->icmp_ip.ip_p == IPPROTO_IPV6) {
432: if (icmplen < ICMP_V6ADVLENMIN ||
433: icmplen < ICMP_V6ADVLEN(icp)) {
434: icmpstat.icps_badlen++;
435: goto freeit;
436: } else {
437: if ((m = m_pullup(m, (ip->ip_hl << 2) +
438: ICMP_V6ADVLEN(icp))) == NULL) {
439: icmpstat.icps_tooshort++;
440: return;
441: }
442: ip = mtod(m, struct ip *);
443: icp = (struct icmp *)
444: (m->m_data + (ip->ip_hl << 2));
445: }
446: }
447: #endif /* INET6 */
448: #ifdef ICMPPRINTFS
449: if (icmpprintfs)
450: printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
451: #endif
452: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
453: #if NCARP > 0
454: if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
455: m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
456: carp_lsdrop(m, AF_INET, &icmpsrc.sin_addr.s_addr,
457: &ip->ip_dst.s_addr))
458: goto freeit;
459: #endif
460: /*
461: * XXX if the packet contains [IPv4 AH TCP], we can't make a
462: * notification to TCP layer.
463: */
464: ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
465: if (ctlfunc)
466: (*ctlfunc)(code, sintosa(&icmpsrc), &icp->icmp_ip);
467: break;
468:
469: badcode:
470: icmpstat.icps_badcode++;
471: break;
472:
473: case ICMP_ECHO:
474: if (!icmpbmcastecho &&
475: (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
476: icmpstat.icps_bmcastecho++;
477: break;
478: }
479: icp->icmp_type = ICMP_ECHOREPLY;
480: goto reflect;
481:
482: case ICMP_TSTAMP:
483: if (icmptstamprepl == 0)
484: break;
485:
486: if (!icmpbmcastecho &&
487: (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
488: icmpstat.icps_bmcastecho++;
489: break;
490: }
491: if (icmplen < ICMP_TSLEN) {
492: icmpstat.icps_badlen++;
493: break;
494: }
495: icp->icmp_type = ICMP_TSTAMPREPLY;
496: icp->icmp_rtime = iptime();
497: icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
498: goto reflect;
499:
500: case ICMP_MASKREQ:
501: if (icmpmaskrepl == 0)
502: break;
503: /*
504: * We are not able to respond with all ones broadcast
505: * unless we receive it over a point-to-point interface.
506: */
507: if (icmplen < ICMP_MASKLEN) {
508: icmpstat.icps_badlen++;
509: break;
510: }
511: if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
512: ip->ip_dst.s_addr == INADDR_ANY)
513: icmpdst.sin_addr = ip->ip_src;
514: else
515: icmpdst.sin_addr = ip->ip_dst;
516: if (m->m_pkthdr.rcvif == NULL)
517: break;
518: ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst),
519: m->m_pkthdr.rcvif));
520: if (ia == 0)
521: break;
522: icp->icmp_type = ICMP_MASKREPLY;
523: icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
524: if (ip->ip_src.s_addr == 0) {
525: if (ia->ia_ifp->if_flags & IFF_BROADCAST)
526: ip->ip_src = ia->ia_broadaddr.sin_addr;
527: else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
528: ip->ip_src = ia->ia_dstaddr.sin_addr;
529: }
530: reflect:
531: #if NCARP > 0
532: if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
533: m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
534: carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr,
535: &ip->ip_dst.s_addr))
536: goto freeit;
537: #endif
538: /* Free packet atttributes */
539: if (m->m_flags & M_PKTHDR)
540: m_tag_delete_chain(m);
541:
542: icmpstat.icps_reflect++;
543: icmpstat.icps_outhist[icp->icmp_type]++;
544: icmp_reflect(m);
545: return;
546:
547: case ICMP_REDIRECT:
548: /* Free packet atttributes */
549: if (m->m_flags & M_PKTHDR)
550: m_tag_delete_chain(m);
551: if (icmp_rediraccept == 0)
552: goto freeit;
553: if (code > 3)
554: goto badcode;
555: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
556: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
557: icmpstat.icps_badlen++;
558: break;
559: }
560: /*
561: * Short circuit routing redirects to force
562: * immediate change in the kernel's routing
563: * tables. The message is also handed to anyone
564: * listening on a raw socket (e.g. the routing
565: * daemon for use in updating its tables).
566: */
567: icmpgw.sin_addr = ip->ip_src;
568: icmpdst.sin_addr = icp->icmp_gwaddr;
569: #ifdef ICMPPRINTFS
570: if (icmpprintfs) {
571: char buf[4 * sizeof("123")];
572: strlcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst),
573: sizeof buf);
574:
575: printf("redirect dst %s to %s\n",
576: buf, inet_ntoa(icp->icmp_gwaddr));
577: }
578: #endif
579: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
580: #if NCARP > 0
581: if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
582: m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
583: carp_lsdrop(m, AF_INET, &icmpsrc.sin_addr.s_addr,
584: &ip->ip_dst.s_addr))
585: goto freeit;
586: #endif
587: rt = NULL;
588: rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),
589: (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
590: sintosa(&icmpgw), (struct rtentry **)&rt);
591: if (rt != NULL && icmp_redirtimeout != 0) {
592: (void)rt_timer_add(rt, icmp_redirect_timeout,
593: icmp_redirect_timeout_q);
594: }
595: if (rt != NULL)
596: rtfree(rt);
597: pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc));
598: break;
599:
600: /*
601: * No kernel processing for the following;
602: * just fall through to send to raw listener.
603: */
604: case ICMP_ECHOREPLY:
605: case ICMP_ROUTERADVERT:
606: case ICMP_ROUTERSOLICIT:
607: case ICMP_TSTAMPREPLY:
608: case ICMP_IREQREPLY:
609: case ICMP_MASKREPLY:
610: case ICMP_TRACEROUTE:
611: case ICMP_DATACONVERR:
612: case ICMP_MOBILE_REDIRECT:
613: case ICMP_IPV6_WHEREAREYOU:
614: case ICMP_IPV6_IAMHERE:
615: case ICMP_MOBILE_REGREQUEST:
616: case ICMP_MOBILE_REGREPLY:
617: case ICMP_PHOTURIS:
618: default:
619: break;
620: }
621:
622: raw:
623: rip_input(m);
624: return;
625:
626: freeit:
627: m_freem(m);
628: }
629:
630: /*
631: * Reflect the ip packet back to the source
632: */
633: void
634: icmp_reflect(struct mbuf *m)
635: {
636: struct ip *ip = mtod(m, struct ip *);
637: struct in_ifaddr *ia;
638: struct in_addr t;
639: struct mbuf *opts = 0;
640: int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
641:
642: if (!in_canforward(ip->ip_src) &&
643: ((ip->ip_src.s_addr & IN_CLASSA_NET) !=
644: htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
645: m_freem(m); /* Bad return address */
646: goto done; /* ip_output() will check for broadcast */
647: }
648: t = ip->ip_dst;
649: ip->ip_dst = ip->ip_src;
650: /*
651: * If the incoming packet was addressed directly to us,
652: * use dst as the src for the reply. For broadcast, use
653: * the address which corresponds to the incoming interface.
654: */
655: TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
656: if (t.s_addr == ia->ia_addr.sin_addr.s_addr)
657: break;
658: if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
659: t.s_addr == ia->ia_broadaddr.sin_addr.s_addr)
660: break;
661: }
662: /*
663: * The following happens if the packet was not addressed to us.
664: * Use the new source address and do a route lookup. If it fails
665: * drop the packet as there is no path to the host.
666: */
667: if (ia == (struct in_ifaddr *)0) {
668: struct sockaddr_in *dst;
669: struct route ro;
670:
671: bzero((caddr_t) &ro, sizeof(ro));
672: dst = satosin(&ro.ro_dst);
673: dst->sin_family = AF_INET;
674: dst->sin_len = sizeof(*dst);
675: dst->sin_addr = ip->ip_src;
676:
677: rtalloc(&ro);
678: if (ro.ro_rt == 0) {
679: ipstat.ips_noroute++;
680: m_freem(m);
681: goto done;
682: }
683:
684: ia = ifatoia(ro.ro_rt->rt_ifa);
685: ro.ro_rt->rt_use++;
686: RTFREE(ro.ro_rt);
687: }
688:
689: t = ia->ia_addr.sin_addr;
690: ip->ip_src = t;
691: ip->ip_ttl = MAXTTL;
692:
693: if (optlen > 0) {
694: u_char *cp;
695: int opt, cnt;
696: u_int len;
697:
698: /*
699: * Retrieve any source routing from the incoming packet;
700: * add on any record-route or timestamp options.
701: */
702: cp = (u_char *) (ip + 1);
703: if ((opts = ip_srcroute()) == 0 &&
704: (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
705: opts->m_len = sizeof(struct in_addr);
706: mtod(opts, struct in_addr *)->s_addr = 0;
707: }
708: if (opts) {
709: #ifdef ICMPPRINTFS
710: if (icmpprintfs)
711: printf("icmp_reflect optlen %d rt %d => ",
712: optlen, opts->m_len);
713: #endif
714: for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
715: opt = cp[IPOPT_OPTVAL];
716: if (opt == IPOPT_EOL)
717: break;
718: if (opt == IPOPT_NOP)
719: len = 1;
720: else {
721: if (cnt < IPOPT_OLEN + sizeof(*cp))
722: break;
723: len = cp[IPOPT_OLEN];
724: if (len < IPOPT_OLEN + sizeof(*cp) ||
725: len > cnt)
726: break;
727: }
728: /*
729: * Should check for overflow, but it
730: * "can't happen"
731: */
732: if (opt == IPOPT_RR || opt == IPOPT_TS ||
733: opt == IPOPT_SECURITY) {
734: bcopy((caddr_t)cp,
735: mtod(opts, caddr_t) + opts->m_len,
736: len);
737: opts->m_len += len;
738: }
739: }
740: /* Terminate & pad, if necessary */
741: if ((cnt = opts->m_len % 4) != 0)
742: for (; cnt < 4; cnt++) {
743: *(mtod(opts, caddr_t) + opts->m_len) =
744: IPOPT_EOL;
745: opts->m_len++;
746: }
747: #ifdef ICMPPRINTFS
748: if (icmpprintfs)
749: printf("%d\n", opts->m_len);
750: #endif
751: }
752: /*
753: * Now strip out original options by copying rest of first
754: * mbuf's data back, and adjust the IP length.
755: */
756: ip->ip_len = htons(ntohs(ip->ip_len) - optlen);
757: ip->ip_hl = sizeof(struct ip) >> 2;
758: m->m_len -= optlen;
759: if (m->m_flags & M_PKTHDR)
760: m->m_pkthdr.len -= optlen;
761: optlen += sizeof(struct ip);
762: bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
763: (unsigned)(m->m_len - sizeof(struct ip)));
764: }
765: m->m_flags &= ~(M_BCAST|M_MCAST);
766: icmp_send(m, opts);
767: done:
768: if (opts)
769: (void)m_free(opts);
770: }
771:
772: /*
773: * Send an icmp packet back to the ip level,
774: * after supplying a checksum.
775: */
776: void
777: icmp_send(struct mbuf *m, struct mbuf *opts)
778: {
779: struct ip *ip = mtod(m, struct ip *);
780: int hlen;
781: struct icmp *icp;
782:
783: hlen = ip->ip_hl << 2;
784: m->m_data += hlen;
785: m->m_len -= hlen;
786: icp = mtod(m, struct icmp *);
787: icp->icmp_cksum = 0;
788: icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
789: m->m_data -= hlen;
790: m->m_len += hlen;
791: #ifdef ICMPPRINTFS
792: if (icmpprintfs) {
793: char buf[4 * sizeof("123")];
794:
795: strlcpy(buf, inet_ntoa(ip->ip_dst), sizeof buf);
796: printf("icmp_send dst %s src %s\n",
797: buf, inet_ntoa(ip->ip_src));
798: }
799: #endif
800: (void)ip_output(m, opts, (void *)NULL, 0, (void *)NULL, (void *)NULL);
801: }
802:
803: n_time
804: iptime(void)
805: {
806: struct timeval atv;
807: u_long t;
808:
809: microtime(&atv);
810: t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
811: return (htonl(t));
812: }
813:
814: int
815: icmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
816: size_t newlen)
817: {
818:
819: /* All sysctl names at this level are terminal. */
820: if (namelen != 1)
821: return (ENOTDIR);
822:
823: switch (name[0]) {
824: case ICMPCTL_REDIRTIMEOUT: {
825: int error;
826:
827: error = sysctl_int(oldp, oldlenp, newp, newlen,
828: &icmp_redirtimeout);
829: if (icmp_redirect_timeout_q != NULL) {
830: if (icmp_redirtimeout == 0) {
831: rt_timer_queue_destroy(icmp_redirect_timeout_q,
832: TRUE);
833: icmp_redirect_timeout_q = NULL;
834: } else
835: rt_timer_queue_change(icmp_redirect_timeout_q,
836: icmp_redirtimeout);
837: } else if (icmp_redirtimeout > 0) {
838: icmp_redirect_timeout_q =
839: rt_timer_queue_create(icmp_redirtimeout);
840: }
841: return (error);
842:
843: break;
844: }
845: default:
846: if (name[0] < ICMPCTL_MAXID)
847: return (sysctl_int_arr(icmpctl_vars, name, namelen,
848: oldp, oldlenp, newp, newlen));
849: return (ENOPROTOOPT);
850: }
851: /* NOTREACHED */
852: }
853:
854:
855: /* XXX only handles table 0 right now */
856: struct rtentry *
857: icmp_mtudisc_clone(struct sockaddr *dst)
858: {
859: struct rtentry *rt;
860: int error;
861:
862: rt = rtalloc1(dst, 1, 0);
863: if (rt == 0)
864: return (NULL);
865:
866: /* If we didn't get a host route, allocate one */
867:
868: if ((rt->rt_flags & RTF_HOST) == 0) {
869: struct rtentry *nrt;
870:
871: error = rtrequest((int) RTM_ADD, dst,
872: (struct sockaddr *) rt->rt_gateway,
873: (struct sockaddr *) 0,
874: RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt, 0);
875: if (error) {
876: rtfree(rt);
877: return (NULL);
878: }
879: nrt->rt_rmx = rt->rt_rmx;
880: rtfree(rt);
881: rt = nrt;
882: }
883: error = rt_timer_add(rt, icmp_mtudisc_timeout, ip_mtudisc_timeout_q);
884: if (error) {
885: rtfree(rt);
886: return (NULL);
887: }
888:
889: return (rt);
890: }
891:
892: void
893: icmp_mtudisc(struct icmp *icp)
894: {
895: struct rtentry *rt;
896: struct sockaddr *dst = sintosa(&icmpsrc);
897: u_long mtu = ntohs(icp->icmp_nextmtu); /* Why a long? IPv6 */
898:
899: /* Table of common MTUs: */
900:
901: static u_short mtu_table[] = {
902: 65535, 65280, 32000, 17914, 9180, 8166,
903: 4352, 2002, 1492, 1006, 508, 296, 68, 0
904: };
905:
906: rt = icmp_mtudisc_clone(dst);
907: if (rt == 0)
908: return;
909:
910: if (mtu == 0) {
911: int i = 0;
912:
913: mtu = ntohs(icp->icmp_ip.ip_len);
914: /* Some 4.2BSD-based routers incorrectly adjust the ip_len */
915: if (mtu > rt->rt_rmx.rmx_mtu && rt->rt_rmx.rmx_mtu != 0)
916: mtu -= (icp->icmp_ip.ip_hl << 2);
917:
918: /* If we still can't guess a value, try the route */
919:
920: if (mtu == 0) {
921: mtu = rt->rt_rmx.rmx_mtu;
922:
923: /* If no route mtu, default to the interface mtu */
924:
925: if (mtu == 0)
926: mtu = rt->rt_ifp->if_mtu;
927: }
928:
929: for (i = 0; i < sizeof(mtu_table) / sizeof(mtu_table[0]); i++)
930: if (mtu > mtu_table[i]) {
931: mtu = mtu_table[i];
932: break;
933: }
934: }
935:
936: /*
937: * XXX: RTV_MTU is overloaded, since the admin can set it
938: * to turn off PMTU for a route, and the kernel can
939: * set it to indicate a serious problem with PMTU
940: * on a route. We should be using a separate flag
941: * for the kernel to indicate this.
942: */
943:
944: if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
945: if (mtu < 296 || mtu > rt->rt_ifp->if_mtu)
946: rt->rt_rmx.rmx_locks |= RTV_MTU;
947: else if (rt->rt_rmx.rmx_mtu > mtu ||
948: rt->rt_rmx.rmx_mtu == 0)
949: rt->rt_rmx.rmx_mtu = mtu;
950: }
951:
952: rtfree(rt);
953: }
954:
955: /* XXX only handles table 0 right now */
956: void
957: icmp_mtudisc_timeout(struct rtentry *rt, struct rttimer *r)
958: {
959: if (rt == NULL)
960: panic("icmp_mtudisc_timeout: bad route to timeout");
961: if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
962: (RTF_DYNAMIC | RTF_HOST)) {
963: void *(*ctlfunc)(int, struct sockaddr *, void *);
964: extern u_char ip_protox[];
965: struct sockaddr_in sa;
966:
967: sa = *(struct sockaddr_in *)rt_key(rt);
968: rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
969: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
970:
971: /* Notify TCP layer of increased Path MTU estimate */
972: ctlfunc = inetsw[ip_protox[IPPROTO_TCP]].pr_ctlinput;
973: if (ctlfunc)
974: (*ctlfunc)(PRC_MTUINC,(struct sockaddr *)&sa, NULL);
975: } else
976: if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
977: rt->rt_rmx.rmx_mtu = 0;
978: }
979:
980: /*
981: * Perform rate limit check.
982: * Returns 0 if it is okay to send the icmp packet.
983: * Returns 1 if the router SHOULD NOT send this icmp packet due to rate
984: * limitation.
985: *
986: * XXX per-destination/type check necessary?
987: */
988: int
989: icmp_ratelimit(const struct in_addr *dst, const int type, const int code)
990: {
991:
992: /* PPS limit */
993: if (!ppsratecheck(&icmperrppslim_last, &icmperrpps_count,
994: icmperrppslim))
995: return 1;
996:
997: /*okay to send*/
998: return 0;
999: }
1000:
1001: /* XXX only handles table 0 right now */
1002: void
1003: icmp_redirect_timeout(struct rtentry *rt, struct rttimer *r)
1004: {
1005: if (rt == NULL)
1006: panic("icmp_redirect_timeout: bad route to timeout");
1007: if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
1008: (RTF_DYNAMIC | RTF_HOST)) {
1009: rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
1010: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
1011: }
1012: }
CVSweb