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