]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/ip_icmp.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / netinet / ip_icmp.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright (c) 1982, 1986, 1988, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
58 */
59
60#include <sys/param.h>
61#include <sys/systm.h>
62#include <sys/mbuf.h>
63#include <sys/protosw.h>
64#include <sys/socket.h>
65#include <sys/time.h>
66#include <sys/kernel.h>
67#include <sys/sysctl.h>
68
69#include <net/if.h>
70#include <net/route.h>
71
72#define _IP_VHL
73#include <netinet/in.h>
74#include <netinet/in_systm.h>
75#include <netinet/in_var.h>
76#include <netinet/ip.h>
77#include <netinet/ip_icmp.h>
78#include <netinet/ip_var.h>
79#include <netinet/icmp_var.h>
80
81#if IPSEC
82#include <netinet6/ipsec.h>
83#include <netkey/key.h>
84#endif
85
86#if defined(NFAITH) && NFAITH > 0
87#include "faith.h"
88#include <net/if_types.h>
89#endif
90
91/*
92 * ICMP routines: error generation, receive packet processing, and
93 * routines to turnaround packets back to the originator, and
94 * host table maintenance routines.
95 */
96
97static struct icmpstat icmpstat;
98SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD,
99 &icmpstat, icmpstat, "");
100
101static int icmpmaskrepl = 0;
102SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
103 &icmpmaskrepl, 0, "");
104
9bccf70c
A
105static int drop_redirect = 0;
106SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW,
107 &drop_redirect, 0, "");
108
109static int log_redirect = 0;
110SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW,
111 &log_redirect, 0, "");
112
1c79356b
A
113#if ICMP_BANDLIM
114
115/*
116 * ICMP error-response bandwidth limiting sysctl. If not enabled, sysctl
117 * variable content is -1 and read-only.
118 */
119
120static int icmplim = 100;
121SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW,
122 &icmplim, 0, "");
123#else
124
125static int icmplim = -1;
126SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD,
127 &icmplim, 0, "");
128
129#endif
130
131/*
132 * ICMP broadcast echo sysctl
133 */
134
9bccf70c
A
135static int icmpbmcastecho = 1;
136SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW,
137 &icmpbmcastecho, 0, "");
1c79356b
A
138
139
140#if ICMPPRINTFS
141int icmpprintfs = 0;
142#endif
143
144static void icmp_reflect __P((struct mbuf *));
145static void icmp_send __P((struct mbuf *, struct mbuf *));
9bccf70c 146static int ip_next_mtu __P((int, int));
1c79356b
A
147
148extern struct protosw inetsw[];
149
150/*
151 * Generate an error packet of type error
152 * in response to bad packet ip.
153 */
154void
155icmp_error(n, type, code, dest, destifp)
156 struct mbuf *n;
157 int type, code;
158 n_long dest;
159 struct ifnet *destifp;
160{
161 register struct ip *oip = mtod(n, struct ip *), *nip;
162 register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
163 register struct icmp *icp;
164 register struct mbuf *m;
165 unsigned icmplen;
166
167#if ICMPPRINTFS
168 if (icmpprintfs)
169 printf("icmp_error(%p, %x, %d)\n", oip, type, code);
170#endif
171 if (type != ICMP_REDIRECT)
172 icmpstat.icps_error++;
173 /*
1c79356b
A
174 * Don't send error if not the first fragment of message.
175 * Don't error if the old packet protocol was ICMP
176 * error message, only known informational types.
177 */
1c79356b
A
178 if (oip->ip_off &~ (IP_MF|IP_DF))
179 goto freeit;
180 if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
181 n->m_len >= oiplen + ICMP_MINLEN &&
182 !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
183 icmpstat.icps_oldicmp++;
184 goto freeit;
185 }
186 /* Don't send error in response to a multicast or broadcast packet */
187 if (n->m_flags & (M_BCAST|M_MCAST))
188 goto freeit;
189 /*
190 * First, formulate icmp message
191 */
192 m = m_gethdr(M_DONTWAIT, MT_HEADER);
193 if (m == NULL)
194 goto freeit;
9bccf70c
A
195 icmplen = min(oiplen + 8, oip->ip_len);
196 if (icmplen < sizeof(struct ip)) {
197 printf("icmp_error: bad length\n");
198 m_free(m);
199 goto freeit;
200 }
1c79356b
A
201 m->m_len = icmplen + ICMP_MINLEN;
202 MH_ALIGN(m, m->m_len);
203 icp = mtod(m, struct icmp *);
204 if ((u_int)type > ICMP_MAXTYPE)
205 panic("icmp_error");
206 icmpstat.icps_outhist[type]++;
207 icp->icmp_type = type;
208 if (type == ICMP_REDIRECT)
209 icp->icmp_gwaddr.s_addr = dest;
210 else {
211 icp->icmp_void = 0;
212 /*
213 * The following assignments assume an overlay with the
214 * zeroed icmp_void field.
215 */
216 if (type == ICMP_PARAMPROB) {
217 icp->icmp_pptr = code;
218 code = 0;
219 } else if (type == ICMP_UNREACH &&
220 code == ICMP_UNREACH_NEEDFRAG && destifp) {
221 icp->icmp_nextmtu = htons(destifp->if_mtu);
222 }
223 }
224
225 icp->icmp_code = code;
9bccf70c 226 m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
1c79356b 227 nip = &icp->icmp_ip;
9bccf70c
A
228
229 /*
230 * Convert fields to network representation.
231 */
232 HTONS(nip->ip_len);
233 HTONS(nip->ip_off);
1c79356b
A
234
235 /*
236 * Now, copy old ip header (without options)
237 * in front of icmp message.
238 */
239 if (m->m_data - sizeof(struct ip) < m->m_pktdat)
240 panic("icmp len");
241 m->m_data -= sizeof(struct ip);
242 m->m_len += sizeof(struct ip);
243 m->m_pkthdr.len = m->m_len;
244 m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
245 m->m_pkthdr.aux = NULL; /* for IPsec */
246 nip = mtod(m, struct ip *);
247 bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
248 nip->ip_len = m->m_len;
249 nip->ip_vhl = IP_VHL_BORING;
250 nip->ip_p = IPPROTO_ICMP;
251 nip->ip_tos = 0;
252 icmp_reflect(m);
253
254freeit:
255 m_freem(n);
256}
257
258static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
259static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
260static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
261
262/*
263 * Process a received ICMP message.
264 */
265void
266icmp_input(m, hlen)
267 register struct mbuf *m;
268 int hlen;
269{
270 register struct icmp *icp;
271 register struct ip *ip = mtod(m, struct ip *);
272 int icmplen = ip->ip_len;
273 register int i;
274 struct in_ifaddr *ia;
275 void (*ctlfunc) __P((int, struct sockaddr *, void *));
276 int code;
277
278 /*
279 * Locate icmp structure in mbuf, and check
280 * that not corrupted and of at least minimum length.
281 */
282#if ICMPPRINTFS
283 if (icmpprintfs) {
284 char buf[4 * sizeof "123"];
285 strcpy(buf, inet_ntoa(ip->ip_src));
286 printf("icmp_input from %s to %s, len %d\n",
287 buf, inet_ntoa(ip->ip_dst), icmplen);
288 }
289#endif
290 if (icmplen < ICMP_MINLEN) {
291 icmpstat.icps_tooshort++;
292 goto freeit;
293 }
294 i = hlen + min(icmplen, ICMP_ADVLENMIN);
295 if (m->m_len < i && (m = m_pullup(m, i)) == 0) {
296 icmpstat.icps_tooshort++;
297 return;
298 }
299 ip = mtod(m, struct ip *);
300 m->m_len -= hlen;
301 m->m_data += hlen;
302 icp = mtod(m, struct icmp *);
303 if (in_cksum(m, icmplen)) {
304 icmpstat.icps_checksum++;
305 goto freeit;
306 }
307 m->m_len += hlen;
308 m->m_data -= hlen;
309
310#if defined(NFAITH) && 0 < NFAITH
311 if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
312 /*
313 * Deliver very specific ICMP type only.
314 */
315 switch (icp->icmp_type) {
316 case ICMP_UNREACH:
317 case ICMP_TIMXCEED:
318 break;
319 default:
320 goto freeit;
321 }
322 }
323#endif
324
325#if ICMPPRINTFS
326 if (icmpprintfs)
327 printf("icmp_input, type %d code %d\n", icp->icmp_type,
328 icp->icmp_code);
329#endif
330
1c79356b
A
331 /*
332 * Message type specific processing.
333 */
334 if (icp->icmp_type > ICMP_MAXTYPE)
335 goto raw;
336 icmpstat.icps_inhist[icp->icmp_type]++;
337 code = icp->icmp_code;
338 switch (icp->icmp_type) {
339
340 case ICMP_UNREACH:
341 switch (code) {
342 case ICMP_UNREACH_NET:
343 case ICMP_UNREACH_HOST:
1c79356b 344 case ICMP_UNREACH_SRCFAIL:
9bccf70c
A
345 case ICMP_UNREACH_NET_UNKNOWN:
346 case ICMP_UNREACH_HOST_UNKNOWN:
347 case ICMP_UNREACH_ISOLATED:
348 case ICMP_UNREACH_TOSNET:
349 case ICMP_UNREACH_TOSHOST:
350 case ICMP_UNREACH_HOST_PRECEDENCE:
351 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
352 code = PRC_UNREACH_NET;
1c79356b
A
353 break;
354
355 case ICMP_UNREACH_NEEDFRAG:
356 code = PRC_MSGSIZE;
357 break;
358
9bccf70c
A
359 /*
360 * RFC 1122, Sections 3.2.2.1 and 4.2.3.9.
361 * Treat subcodes 2,3 as immediate RST
362 */
363 case ICMP_UNREACH_PROTOCOL:
364 case ICMP_UNREACH_PORT:
365 code = PRC_UNREACH_PORT;
1c79356b
A
366 break;
367
9bccf70c 368 case ICMP_UNREACH_NET_PROHIB:
1c79356b 369 case ICMP_UNREACH_HOST_PROHIB:
1c79356b 370 case ICMP_UNREACH_FILTER_PROHIB:
9bccf70c 371 code = PRC_UNREACH_ADMIN_PROHIB;
1c79356b
A
372 break;
373
374 default:
375 goto badcode;
376 }
377 goto deliver;
378
379 case ICMP_TIMXCEED:
380 if (code > 1)
381 goto badcode;
382 code += PRC_TIMXCEED_INTRANS;
383 goto deliver;
384
385 case ICMP_PARAMPROB:
386 if (code > 1)
387 goto badcode;
388 code = PRC_PARAMPROB;
389 goto deliver;
390
391 case ICMP_SOURCEQUENCH:
392 if (code)
393 goto badcode;
394 code = PRC_QUENCH;
395 deliver:
396 /*
397 * Problem with datagram; advise higher level routines.
398 */
399 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
400 IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
401 icmpstat.icps_badlen++;
402 goto freeit;
403 }
404 NTOHS(icp->icmp_ip.ip_len);
405 /* Discard ICMP's in response to multicast packets */
406 if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
407 goto badcode;
408#if ICMPPRINTFS
409 if (icmpprintfs)
410 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
411#endif
412 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
413#if 1
414 /*
415 * MTU discovery:
416 * If we got a needfrag and there is a host route to the
417 * original destination, and the MTU is not locked, then
418 * set the MTU in the route to the suggested new value
419 * (if given) and then notify as usual. The ULPs will
420 * notice that the MTU has changed and adapt accordingly.
421 * If no new MTU was suggested, then we guess a new one
422 * less than the current value. If the new MTU is
423 * unreasonably small (arbitrarily set at 296), then
424 * we reset the MTU to the interface value and enable the
425 * lock bit, indicating that we are no longer doing MTU
426 * discovery.
427 */
428 if (code == PRC_MSGSIZE) {
429 struct rtentry *rt;
430 int mtu;
431
432 rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
433 RTF_CLONING | RTF_PRCLONING);
434 if (rt && (rt->rt_flags & RTF_HOST)
435 && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
436 mtu = ntohs(icp->icmp_nextmtu);
437 if (!mtu)
438 mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
439 1);
440#if DEBUG_MTUDISC
441 printf("MTU for %s reduced to %d\n",
442 inet_ntoa(icmpsrc.sin_addr), mtu);
443#endif
444 if (mtu < 296) {
445 /* rt->rt_rmx.rmx_mtu =
446 rt->rt_ifp->if_mtu; */
447 rt->rt_rmx.rmx_locks |= RTV_MTU;
448 } else if (rt->rt_rmx.rmx_mtu > mtu) {
449 rt->rt_rmx.rmx_mtu = mtu;
450 }
451 }
452 if (rt)
9bccf70c 453 rtfree(rt);
1c79356b
A
454 }
455
456#endif
457 /*
458 * XXX if the packet contains [IPv4 AH TCP], we can't make a
459 * notification to TCP layer.
460 */
461 ctlfunc = ip_protox[icp->icmp_ip.ip_p]->pr_ctlinput;
462 if (ctlfunc)
463 (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
464 (void *)&icp->icmp_ip);
465 break;
466
467 badcode:
468 icmpstat.icps_badcode++;
469 break;
470
471 case ICMP_ECHO:
472 if (!icmpbmcastecho
473 && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
474 icmpstat.icps_bmcastecho++;
475 break;
476 }
477 icp->icmp_type = ICMP_ECHOREPLY;
9bccf70c
A
478#if ICMP_BANDLIM
479 if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0)
480 goto freeit;
481 else
482#endif
483 goto reflect;
1c79356b
A
484
485 case ICMP_TSTAMP:
486 if (!icmpbmcastecho
487 && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
488 icmpstat.icps_bmcasttstamp++;
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! */
9bccf70c
A
498#if ICMP_BANDLIM
499 if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0)
500 goto freeit;
501 else
502#endif
503 goto reflect;
1c79356b
A
504
505 case ICMP_MASKREQ:
506#define satosin(sa) ((struct sockaddr_in *)(sa))
507 if (icmpmaskrepl == 0)
508 break;
509 /*
510 * We are not able to respond with all ones broadcast
511 * unless we receive it over a point-to-point interface.
512 */
513 if (icmplen < ICMP_MASKLEN)
514 break;
515 switch (ip->ip_dst.s_addr) {
516
517 case INADDR_BROADCAST:
518 case INADDR_ANY:
519 icmpdst.sin_addr = ip->ip_src;
520 break;
521
522 default:
523 icmpdst.sin_addr = ip->ip_dst;
524 }
525 ia = (struct in_ifaddr *)ifaof_ifpforaddr(
526 (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
527 if (ia == 0)
528 break;
529 if (ia->ia_ifp == 0)
530 break;
531 icp->icmp_type = ICMP_MASKREPLY;
532 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
533 if (ip->ip_src.s_addr == 0) {
534 if (ia->ia_ifp->if_flags & IFF_BROADCAST)
535 ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
536 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
537 ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
538 }
539reflect:
540 ip->ip_len += hlen; /* since ip_input deducts this */
541 icmpstat.icps_reflect++;
542 icmpstat.icps_outhist[icp->icmp_type]++;
543 icmp_reflect(m);
544 return;
545
546 case ICMP_REDIRECT:
9bccf70c
A
547 if (log_redirect) {
548 u_long src, dst, gw;
549
550 src = ntohl(ip->ip_src.s_addr);
551 dst = ntohl(icp->icmp_ip.ip_dst.s_addr);
552 gw = ntohl(icp->icmp_gwaddr.s_addr);
553 printf("icmp redirect from %d.%d.%d.%d: "
554 "%d.%d.%d.%d => %d.%d.%d.%d\n",
555 (int)(src >> 24), (int)((src >> 16) & 0xff),
556 (int)((src >> 8) & 0xff), (int)(src & 0xff),
557 (int)(dst >> 24), (int)((dst >> 16) & 0xff),
558 (int)((dst >> 8) & 0xff), (int)(dst & 0xff),
559 (int)(gw >> 24), (int)((gw >> 16) & 0xff),
560 (int)((gw >> 8) & 0xff), (int)(gw & 0xff));
561 }
562 if (drop_redirect)
563 break;
1c79356b
A
564 if (code > 3)
565 goto badcode;
566 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
567 IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
568 icmpstat.icps_badlen++;
569 break;
570 }
571 /*
572 * Short circuit routing redirects to force
573 * immediate change in the kernel's routing
574 * tables. The message is also handed to anyone
575 * listening on a raw socket (e.g. the routing
576 * daemon for use in updating its tables).
577 */
578 icmpgw.sin_addr = ip->ip_src;
579 icmpdst.sin_addr = icp->icmp_gwaddr;
580#if ICMPPRINTFS
581 if (icmpprintfs) {
582 char buf[4 * sizeof "123"];
583 strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
584
585 printf("redirect dst %s to %s\n",
586 buf, inet_ntoa(icp->icmp_gwaddr));
587 }
588#endif
589 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
590 rtredirect((struct sockaddr *)&icmpsrc,
591 (struct sockaddr *)&icmpdst,
592 (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
593 (struct sockaddr *)&icmpgw, (struct rtentry **)0);
594 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
595#if IPSEC
596 key_sa_routechange((struct sockaddr *)&icmpsrc);
597#endif
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 default:
611 break;
612 }
613
614raw:
615 rip_input(m, hlen);
616 return;
617
618freeit:
619 m_freem(m);
620}
621
622/*
623 * Reflect the ip packet back to the source
624 */
625static void
626icmp_reflect(m)
627 struct mbuf *m;
628{
629 register struct ip *ip = mtod(m, struct ip *);
630 register struct in_ifaddr *ia;
631 struct in_addr t;
632 struct mbuf *opts = 0;
633 int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
634
635 if (!in_canforward(ip->ip_src) &&
636 ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
637 (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
638 m_freem(m); /* Bad return address */
639 goto done; /* Ip_output() will check for broadcast */
640 }
641 t = ip->ip_dst;
642 ip->ip_dst = ip->ip_src;
643 /*
644 * If the incoming packet was addressed directly to us,
645 * use dst as the src for the reply. Otherwise (broadcast
646 * or anonymous), use the address which corresponds
647 * to the incoming interface.
648 */
649 for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) {
650 if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
651 break;
652 if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) &&
653 t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
654 break;
655 }
656 icmpdst.sin_addr = t;
657 if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif)
658 ia = (struct in_ifaddr *)ifaof_ifpforaddr(
659 (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
660 /*
661 * The following happens if the packet was not addressed to us,
662 * and was received on an interface with no IP address.
663 */
664 if (ia == (struct in_ifaddr *)0)
665 ia = in_ifaddrhead.tqh_first;
666 t = IA_SIN(ia)->sin_addr;
667 ip->ip_src = t;
9bccf70c 668 ip->ip_ttl = ip_defttl;
1c79356b
A
669
670 if (optlen > 0) {
671 register u_char *cp;
672 int opt, cnt;
673 u_int len;
674
675 /*
676 * Retrieve any source routing from the incoming packet;
677 * add on any record-route or timestamp options.
678 */
679 cp = (u_char *) (ip + 1);
680 if ((opts = ip_srcroute()) == 0 &&
681 (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
682 opts->m_len = sizeof(struct in_addr);
683 mtod(opts, struct in_addr *)->s_addr = 0;
684 }
685 if (opts) {
686#if ICMPPRINTFS
687 if (icmpprintfs)
688 printf("icmp_reflect optlen %d rt %d => ",
689 optlen, opts->m_len);
690#endif
691 for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
692 opt = cp[IPOPT_OPTVAL];
693 if (opt == IPOPT_EOL)
694 break;
695 if (opt == IPOPT_NOP)
696 len = 1;
697 else {
698 if (cnt < IPOPT_OLEN + sizeof(*cp))
699 break;
700 len = cp[IPOPT_OLEN];
701 if (len < IPOPT_OLEN + sizeof(*cp) ||
9bccf70c 702 len > cnt)
1c79356b
A
703 break;
704 }
705 /*
706 * Should check for overflow, but it "can't happen"
707 */
708 if (opt == IPOPT_RR || opt == IPOPT_TS ||
709 opt == IPOPT_SECURITY) {
710 bcopy((caddr_t)cp,
711 mtod(opts, caddr_t) + opts->m_len, len);
712 opts->m_len += len;
713 }
714 }
715 /* Terminate & pad, if necessary */
716 cnt = opts->m_len % 4;
717 if (cnt) {
718 for (; cnt < 4; cnt++) {
719 *(mtod(opts, caddr_t) + opts->m_len) =
720 IPOPT_EOL;
721 opts->m_len++;
722 }
723 }
724#if ICMPPRINTFS
725 if (icmpprintfs)
726 printf("%d\n", opts->m_len);
727#endif
728 }
729 /*
730 * Now strip out original options by copying rest of first
731 * mbuf's data back, and adjust the IP length.
732 */
733 ip->ip_len -= optlen;
734 ip->ip_vhl = IP_VHL_BORING;
735 m->m_len -= optlen;
736 if (m->m_flags & M_PKTHDR)
737 m->m_pkthdr.len -= optlen;
738 optlen += sizeof(struct ip);
739 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
740 (unsigned)(m->m_len - sizeof(struct ip)));
741 }
742 m->m_flags &= ~(M_BCAST|M_MCAST);
743 icmp_send(m, opts);
744done:
745 if (opts)
746 (void)m_free(opts);
747}
748
749/*
750 * Send an icmp packet back to the ip level,
751 * after supplying a checksum.
752 */
753static void
754icmp_send(m, opts)
755 register struct mbuf *m;
756 struct mbuf *opts;
757{
758 register struct ip *ip = mtod(m, struct ip *);
759 register int hlen;
760 register struct icmp *icp;
761 struct route ro;
762
763 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
764 m->m_data += hlen;
765 m->m_len -= hlen;
766 icp = mtod(m, struct icmp *);
767 icp->icmp_cksum = 0;
768 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
769 m->m_data -= hlen;
770 m->m_len += hlen;
771 m->m_pkthdr.rcvif = (struct ifnet *)0;
772 m->m_pkthdr.aux = NULL;
0b4e3aa0
A
773 m->m_pkthdr.csum_data = 0;
774 m->m_pkthdr.csum_flags = 0;
1c79356b
A
775#if ICMPPRINTFS
776 if (icmpprintfs) {
777 char buf[4 * sizeof "123"];
778 strcpy(buf, inet_ntoa(ip->ip_dst));
779 printf("icmp_send dst %s src %s\n",
780 buf, inet_ntoa(ip->ip_src));
781 }
782#endif
783 bzero(&ro, sizeof ro);
1c79356b
A
784 (void) ip_output(m, opts, &ro, 0, NULL);
785 if (ro.ro_rt)
9bccf70c 786 rtfree(ro.ro_rt);
1c79356b
A
787}
788
789n_time
790iptime()
791{
792 struct timeval atv;
793 u_long t;
794
795 microtime(&atv);
796 t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
797 return (htonl(t));
798}
799
800#if 1
801/*
802 * Return the next larger or smaller MTU plateau (table from RFC 1191)
803 * given current value MTU. If DIR is less than zero, a larger plateau
804 * is returned; otherwise, a smaller value is returned.
805 */
9bccf70c 806static int
1c79356b
A
807ip_next_mtu(mtu, dir)
808 int mtu;
809 int dir;
810{
811 static int mtutab[] = {
812 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
813 68, 0
814 };
815 int i;
816
817 for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
818 if (mtu >= mtutab[i])
819 break;
820 }
821
822 if (dir < 0) {
823 if (i == 0) {
824 return 0;
825 } else {
826 return mtutab[i - 1];
827 }
828 } else {
829 if (mtutab[i] == 0) {
830 return 0;
831 } else if(mtu > mtutab[i]) {
832 return mtutab[i];
833 } else {
834 return mtutab[i + 1];
835 }
836 }
837}
838#endif
839
840#if ICMP_BANDLIM
841
842/*
843 * badport_bandlim() - check for ICMP bandwidth limit
844 *
845 * Return 0 if it is ok to send an ICMP error response, -1 if we have
846 * hit our bandwidth limit and it is not ok.
847 *
848 * If icmplim is <= 0, the feature is disabled and 0 is returned.
849 *
850 * For now we separate the TCP and UDP subsystems w/ different 'which'
851 * values. We may eventually remove this separation (and simplify the
852 * code further).
853 *
854 * Note that the printing of the error message is delayed so we can
855 * properly print the icmp error rate that the system was trying to do
856 * (i.e. 22000/100 pps, etc...). This can cause long delays in printing
857 * the 'final' error, but it doesn't make sense to solve the printing
858 * delay with more complex code.
859 */
860
861int
862badport_bandlim(int which)
863{
9bccf70c
A
864 static struct timeval lticks[BANDLIM_MAX + 1];
865 static int lpackets[BANDLIM_MAX + 1];
866 struct timeval time;
867 int secs;
868
869 const char *bandlimittype[] = {
870 "Limiting icmp unreach response",
871 "Limiting icmp ping response",
872 "Limiting icmp tstamp response",
873 "Limiting closed port RST response",
874 "Limiting open port RST response"
875 };
1c79356b
A
876
877 /*
878 * Return ok status if feature disabled or argument out of
879 * ranage.
880 */
881
9bccf70c 882 if (icmplim <= 0 || which > BANDLIM_MAX || which < 0)
1c79356b 883 return(0);
1c79356b 884
9bccf70c
A
885 getmicrotime(&time);
886
887 secs = time.tv_sec - lticks[which].tv_sec ;
888
1c79356b 889 /*
9bccf70c 890 * reset stats when cumulative delta exceeds one second.
1c79356b
A
891 */
892
9bccf70c 893 if ((secs > 1) || (secs == 1 && (lticks[which].tv_usec > time.tv_usec))) {
1c79356b 894 if (lpackets[which] > icmplim) {
9bccf70c
A
895 printf("%s from %d to %d packets per second\n",
896 bandlimittype[which],
1c79356b
A
897 lpackets[which],
898 icmplim
899 );
900 }
9bccf70c
A
901 lticks[which].tv_sec = time.tv_sec;
902 lticks[which].tv_usec = time.tv_usec;
1c79356b
A
903 lpackets[which] = 0;
904 }
905
906 /*
907 * bump packet count
908 */
909
910 if (++lpackets[which] > icmplim) {
911 return(-1);
912 }
913 return(0);
914}
915
916#endif
917
9bccf70c
A
918#if __APPLE__
919
920/*
921 * Non-privileged ICMP socket operations
922 * - send ICMP echo request
923 * - all ICMP
924 * - limited socket options
925 */
926
927#include <netinet/ip_icmp.h>
928#include <netinet/in_pcb.h>
929
930extern struct domain inetdomain;
931extern u_long rip_sendspace;
932extern u_long rip_recvspace;
933extern struct inpcbinfo ripcbinfo;
934
935int rip_abort(struct socket *);
936int rip_bind(struct socket *, struct sockaddr *, struct proc *);
937int rip_connect(struct socket *, struct sockaddr *, struct proc *);
938int rip_detach(struct socket *);
939int rip_disconnect(struct socket *);
940int rip_shutdown(struct socket *);
941
942__private_extern__ int icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p);
943__private_extern__ int icmp_dgram_attach(struct socket *so, int proto, struct proc *p);
944__private_extern__ int icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt);
945
946__private_extern__ struct pr_usrreqs icmp_dgram_usrreqs = {
947 rip_abort, pru_accept_notsupp, icmp_dgram_attach, rip_bind, rip_connect,
948 pru_connect2_notsupp, in_control, rip_detach, rip_disconnect,
949 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
950 pru_rcvoob_notsupp, icmp_dgram_send, pru_sense_null, rip_shutdown,
951 in_setsockaddr, sosend, soreceive, sopoll
952};
953
954/* Like rip_attach but without root privilege enforcement */
955__private_extern__ int
956icmp_dgram_attach(struct socket *so, int proto, struct proc *p)
957{
958 struct inpcb *inp;
959 int error, s;
960
961 inp = sotoinpcb(so);
962 if (inp)
963 panic("icmp_dgram_attach");
964
965 error = soreserve(so, rip_sendspace, rip_recvspace);
966 if (error)
967 return error;
968 s = splnet();
969 error = in_pcballoc(so, &ripcbinfo, p);
970 splx(s);
971 if (error)
972 return error;
973 inp = (struct inpcb *)so->so_pcb;
974 inp->inp_vflag |= INP_IPV4;
975 inp->inp_ip_p = IPPROTO_ICMP;
976 inp->inp_ip_ttl = ip_defttl;
977 return 0;
978}
979
980/*
981 * Raw IP socket option processing.
982 */
983__private_extern__ int
984icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt)
985{
986 struct inpcb *inp = sotoinpcb(so);
987 int error, optval;
988
989 if (sopt->sopt_level != IPPROTO_IP)
990 return (EINVAL);
991
992 switch (sopt->sopt_name) {
993 case IP_OPTIONS:
994 case IP_HDRINCL:
995 case IP_TOS:
996 case IP_TTL:
997 case IP_RECVOPTS:
998 case IP_RECVRETOPTS:
999 case IP_RECVDSTADDR:
1000 case IP_RETOPTS:
1001 case IP_MULTICAST_IF:
1002 case IP_MULTICAST_TTL:
1003 case IP_MULTICAST_LOOP:
1004 case IP_ADD_MEMBERSHIP:
1005 case IP_DROP_MEMBERSHIP:
1006 case IP_MULTICAST_VIF:
1007 case IP_PORTRANGE:
1008 case IP_RECVIF:
1009 case IP_IPSEC_POLICY:
1010#if defined(NFAITH) && NFAITH > 0
1011 case IP_FAITH:
1012#endif
1013 case IP_STRIPHDR:
1014 error = rip_ctloutput(so, sopt);
1015 break;
1016
1017 default:
1018 error = EINVAL;
1019 break;
1020 }
1021
1022 return (error);
1023}
1024
1025__private_extern__ int
1026icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
1027 struct mbuf *control, struct proc *p)
1028{
1029 struct ip *ip;
1030 struct inpcb *inp = sotoinpcb(so);
1031 int hlen;
1032 struct icmp *icp;
1033 struct in_ifaddr *ia = NULL;
1034 int icmplen;
1035
1036 if ((inp->inp_flags & INP_HDRINCL) != 0) {
1037 /*
1038 * This is not raw IP, we liberal only for fields TOS, id and TTL
1039 */
1040 ip = mtod(m, struct ip *);
1041
1042 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
1043 /* Some sanity checks */
1044 if (m->m_pkthdr.len < hlen + ICMP_MINLEN) {
1045 goto bad;
1046 }
1047 /* Only IPv4 */
1048 if (IP_VHL_V(ip->ip_vhl) != 4)
1049 goto bad;
1050 if (hlen < 20 || hlen > 40 || ip->ip_len != m->m_pkthdr.len ||
1051 ip->ip_len > 65535)
1052 goto bad;
1053 /* Bogus fragments can tie up peer resources */
1054 if (ip->ip_off != 0)
1055 goto bad;
1056 /* Allow only ICMP even for user provided IP header */
1057 if (ip->ip_p != IPPROTO_ICMP)
1058 goto bad;
1059 /* To prevent spoofing, specified source address must be one of ours */
1060 if (ip->ip_src.s_addr != INADDR_ANY) {
1061 if (TAILQ_EMPTY(&in_ifaddrhead))
1062 goto bad;
1063 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
1064 if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_src.s_addr)
1065 goto ours;
1066 }
1067 goto bad;
1068 }
1069ours:
1070 /* Do not trust we got a valid checksum */
1071 ip->ip_sum = 0;
1072
1073 icp = (struct icmp *)(((char *)m->m_data) + hlen);
1074 icmplen = m->m_pkthdr.len - hlen;
1075 } else {
1076 if ((icmplen = m->m_pkthdr.len) < ICMP_MINLEN) {
1077 goto bad;
1078 }
1079 icp = mtod(m, struct icmp *);
1080 }
1081 /*
1082 * Allow only to send request types with code 0
1083 */
1084 if (icp->icmp_code != 0)
1085 goto bad;
1086 switch (icp->icmp_type) {
1087 case ICMP_ECHO:
1088 break;
1089 case ICMP_TSTAMP:
1090 if (icmplen != 20)
1091 goto bad;
1092 break;
1093 case ICMP_MASKREQ:
1094 if (icmplen != 12)
1095 goto bad;
1096 break;
1097 default:
1098 goto bad;
1099 }
1100 return rip_send(so, flags, m, nam, control, p);
1101bad:
1102 m_freem(m);
1103 return EINVAL;
1104}
1105
1106#endif /* __APPLE__ */
1c79356b 1107