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