2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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. 
  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 
  14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the 
  17  * License for the specific language governing rights and limitations 
  20  * @APPLE_LICENSE_HEADER_END@ 
  23  * Copyright (c) 1982, 1986, 1988, 1993 
  24  *      The Regents of the University of California.  All rights reserved. 
  26  * Redistribution and use in source and binary forms, with or without 
  27  * modification, are permitted provided that the following conditions 
  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. 
  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 
  54  *      @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94 
  57 #include <sys/param.h> 
  58 #include <sys/systm.h> 
  60 #include <sys/protosw.h> 
  61 #include <sys/socket.h> 
  63 #include <sys/kernel.h> 
  64 #include <sys/sysctl.h> 
  67 #include <net/route.h> 
  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> 
  79 #include <netinet6/ipsec.h> 
  80 #include <netkey/key.h> 
  83 #if defined(NFAITH) && NFAITH > 0 
  85 #include <net/if_types.h> 
  89  * ICMP routines: error generation, receive packet processing, and 
  90  * routines to turnaround packets back to the originator, and 
  91  * host table maintenance routines. 
  94 static struct   icmpstat icmpstat
; 
  95 SYSCTL_STRUCT(_net_inet_icmp
, ICMPCTL_STATS
, stats
, CTLFLAG_RD
, 
  96         &icmpstat
, icmpstat
, ""); 
  98 static int      icmpmaskrepl 
= 0; 
  99 SYSCTL_INT(_net_inet_icmp
, ICMPCTL_MASKREPL
, maskrepl
, CTLFLAG_RW
, 
 100         &icmpmaskrepl
, 0, ""); 
 102 static int      drop_redirect 
= 0; 
 103 SYSCTL_INT(_net_inet_icmp
, OID_AUTO
, drop_redirect
, CTLFLAG_RW
,  
 104         &drop_redirect
, 0, ""); 
 106 static int      log_redirect 
= 0; 
 107 SYSCTL_INT(_net_inet_icmp
, OID_AUTO
, log_redirect
, CTLFLAG_RW
,  
 108         &log_redirect
, 0, ""); 
 113  * ICMP error-response bandwidth limiting sysctl.  If not enabled, sysctl 
 114  *      variable content is -1 and read-only. 
 117 static int      icmplim 
= 100; 
 118 SYSCTL_INT(_net_inet_icmp
, ICMPCTL_ICMPLIM
, icmplim
, CTLFLAG_RW
, 
 122 static int      icmplim 
= -1; 
 123 SYSCTL_INT(_net_inet_icmp
, ICMPCTL_ICMPLIM
, icmplim
, CTLFLAG_RD
, 
 129  * ICMP broadcast echo sysctl 
 132 static int      icmpbmcastecho 
= 1; 
 133 SYSCTL_INT(_net_inet_icmp
, OID_AUTO
, bmcastecho
, CTLFLAG_RW
, 
 134         &icmpbmcastecho
, 0, ""); 
 141 static void     icmp_reflect 
__P((struct mbuf 
*)); 
 142 static void     icmp_send 
__P((struct mbuf 
*, struct mbuf 
*)); 
 143 static int      ip_next_mtu 
__P((int, int)); 
 145 extern  struct protosw inetsw
[]; 
 148  * Generate an error packet of type error 
 149  * in response to bad packet ip. 
 152 icmp_error(n
, type
, code
, dest
, destifp
) 
 156         struct ifnet 
*destifp
; 
 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
; 
 166                 printf("icmp_error(%p, %x, %d)\n", oip
, type
, code
); 
 168         if (type 
!= ICMP_REDIRECT
) 
 169                 icmpstat
.icps_error
++; 
 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. 
 175         if (oip
->ip_off 
&~ (IP_MF
|IP_DF
)) 
 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
++; 
 183         /* Don't send error in response to a multicast or broadcast packet */ 
 184         if (n
->m_flags 
& (M_BCAST
|M_MCAST
)) 
 187          * First, formulate icmp message 
 189         m 
= m_gethdr(M_DONTWAIT
, MT_HEADER
); 
 192         icmplen 
= min(oiplen 
+ 8, oip
->ip_len
); 
 193         if (icmplen 
< sizeof(struct ip
)) { 
 194                 printf("icmp_error: bad length\n"); 
 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
) 
 203         icmpstat
.icps_outhist
[type
]++; 
 204         icp
->icmp_type 
= type
; 
 205         if (type 
== ICMP_REDIRECT
) 
 206                 icp
->icmp_gwaddr
.s_addr 
= dest
; 
 210                  * The following assignments assume an overlay with the 
 211                  * zeroed icmp_void field. 
 213                 if (type 
== ICMP_PARAMPROB
) { 
 214                         icp
->icmp_pptr 
= code
; 
 216                 } else if (type 
== ICMP_UNREACH 
&& 
 217                         code 
== ICMP_UNREACH_NEEDFRAG 
&& destifp
) { 
 218                         icp
->icmp_nextmtu 
= htons(destifp
->if_mtu
); 
 222         icp
->icmp_code 
= code
; 
 223         m_copydata(n
, 0, icmplen
, (caddr_t
)&icp
->icmp_ip
); 
 227          * Convert fields to network representation. 
 233          * Now, copy old ip header (without options) 
 234          * in front of icmp message. 
 236         if (m
->m_data 
- sizeof(struct ip
) < m
->m_pktdat
) 
 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
; 
 255 static struct sockaddr_in icmpsrc 
= { sizeof (struct sockaddr_in
), AF_INET 
}; 
 256 static struct sockaddr_in icmpdst 
= { sizeof (struct sockaddr_in
), AF_INET 
}; 
 257 static struct sockaddr_in icmpgw 
= { sizeof (struct sockaddr_in
), AF_INET 
}; 
 260  * Process a received ICMP message. 
 264         register struct mbuf 
*m
; 
 267         register struct icmp 
*icp
; 
 268         register struct ip 
*ip 
= mtod(m
, struct ip 
*); 
 269         int icmplen 
= ip
->ip_len
; 
 271         struct in_ifaddr 
*ia
; 
 272         void (*ctlfunc
) __P((int, struct sockaddr 
*, void *)); 
 276          * Locate icmp structure in mbuf, and check 
 277          * that not corrupted and of at least minimum length. 
 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
); 
 287         if (icmplen 
< ICMP_MINLEN
) { 
 288                 icmpstat
.icps_tooshort
++; 
 291         i 
= hlen 
+ min(icmplen
, ICMP_ADVLENMIN
); 
 292         if (m
->m_len 
< i 
&& (m 
= m_pullup(m
, i
)) == 0)  { 
 293                 icmpstat
.icps_tooshort
++; 
 296         ip 
= mtod(m
, struct ip 
*); 
 299         icp 
= mtod(m
, struct icmp 
*); 
 300         if (in_cksum(m
, icmplen
)) { 
 301                 icmpstat
.icps_checksum
++; 
 307 #if defined(NFAITH) && 0 < NFAITH 
 308         if (m
->m_pkthdr
.rcvif 
&& m
->m_pkthdr
.rcvif
->if_type 
== IFT_FAITH
) { 
 310                  * Deliver very specific ICMP type only. 
 312                 switch (icp
->icmp_type
) { 
 324                 printf("icmp_input, type %d code %d\n", icp
->icmp_type
, 
 329          * Message type specific processing. 
 331         if (icp
->icmp_type 
> ICMP_MAXTYPE
) 
 333         icmpstat
.icps_inhist
[icp
->icmp_type
]++; 
 334         code 
= icp
->icmp_code
; 
 335         switch (icp
->icmp_type
) { 
 339                         case ICMP_UNREACH_NET
: 
 340                         case ICMP_UNREACH_HOST
: 
 341                         case ICMP_UNREACH_SRCFAIL
: 
 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
; 
 352                         case ICMP_UNREACH_NEEDFRAG
: 
 357                          * RFC 1122, Sections 3.2.2.1 and 4.2.3.9. 
 358                          * Treat subcodes 2,3 as immediate RST 
 360                         case ICMP_UNREACH_PROTOCOL
: 
 361                         case ICMP_UNREACH_PORT
: 
 362                                 code 
= PRC_UNREACH_PORT
; 
 365                         case ICMP_UNREACH_NET_PROHIB
: 
 366                         case ICMP_UNREACH_HOST_PROHIB
: 
 367                         case ICMP_UNREACH_FILTER_PROHIB
: 
 368                                 code 
= PRC_UNREACH_ADMIN_PROHIB
; 
 379                 code 
+= PRC_TIMXCEED_INTRANS
; 
 385                 code 
= PRC_PARAMPROB
; 
 388         case ICMP_SOURCEQUENCH
: 
 394                  * Problem with datagram; advise higher level routines. 
 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
++; 
 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
))) 
 407                         printf("deliver to protocol %d\n", icp
->icmp_ip
.ip_p
); 
 409                 icmpsrc
.sin_addr 
= icp
->icmp_ip
.ip_dst
; 
 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 
 425                 if (code 
== PRC_MSGSIZE
) { 
 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
); 
 435                                         mtu 
= ip_next_mtu(rt
->rt_rmx
.rmx_mtu
, 
 438                                 printf("MTU for %s reduced to %d\n", 
 439                                         inet_ntoa(icmpsrc
.sin_addr
), mtu
); 
 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
; 
 455                  * XXX if the packet contains [IPv4 AH TCP], we can't make a 
 456                  * notification to TCP layer. 
 458                 ctlfunc 
= ip_protox
[icp
->icmp_ip
.ip_p
]->pr_ctlinput
; 
 460                         (*ctlfunc
)(code
, (struct sockaddr 
*)&icmpsrc
, 
 461                                    (void *)&icp
->icmp_ip
); 
 465                 icmpstat
.icps_badcode
++; 
 470                     && (m
->m_flags 
& (M_MCAST 
| M_BCAST
)) != 0) { 
 471                         icmpstat
.icps_bmcastecho
++; 
 474                 icp
->icmp_type 
= ICMP_ECHOREPLY
; 
 476                 if (badport_bandlim(BANDLIM_ICMP_ECHO
) < 0) 
 484                     && (m
->m_flags 
& (M_MCAST 
| M_BCAST
)) != 0) { 
 485                         icmpstat
.icps_bmcasttstamp
++; 
 488                 if (icmplen 
< ICMP_TSLEN
) { 
 489                         icmpstat
.icps_badlen
++; 
 492                 icp
->icmp_type 
= ICMP_TSTAMPREPLY
; 
 493                 icp
->icmp_rtime 
= iptime(); 
 494                 icp
->icmp_ttime 
= icp
->icmp_rtime
;      /* bogus, do later! */ 
 496                 if (badport_bandlim(BANDLIM_ICMP_TSTAMP
) < 0) 
 503 #define satosin(sa)     ((struct sockaddr_in *)(sa)) 
 504                 if (icmpmaskrepl 
== 0) 
 507                  * We are not able to respond with all ones broadcast 
 508                  * unless we receive it over a point-to-point interface. 
 510                 if (icmplen 
< ICMP_MASKLEN
) 
 512                 switch (ip
->ip_dst
.s_addr
) { 
 514                 case INADDR_BROADCAST
: 
 516                         icmpdst
.sin_addr 
= ip
->ip_src
; 
 520                         icmpdst
.sin_addr 
= ip
->ip_dst
; 
 522                 ia 
= (struct in_ifaddr 
*)ifaof_ifpforaddr( 
 523                             (struct sockaddr 
*)&icmpdst
, m
->m_pkthdr
.rcvif
); 
 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
; 
 537                 ip
->ip_len 
+= hlen
;     /* since ip_input deducts this */ 
 538                 icmpstat
.icps_reflect
++; 
 539                 icmpstat
.icps_outhist
[icp
->icmp_type
]++; 
 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)); 
 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
++; 
 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). 
 575                 icmpgw
.sin_addr 
= ip
->ip_src
; 
 576                 icmpdst
.sin_addr 
= icp
->icmp_gwaddr
; 
 579                         char buf
[4 * sizeof "123"]; 
 580                         strcpy(buf
, inet_ntoa(icp
->icmp_ip
.ip_dst
)); 
 582                         printf("redirect dst %s to %s\n", 
 583                                buf
, inet_ntoa(icp
->icmp_gwaddr
)); 
 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
); 
 593                 key_sa_routechange((struct sockaddr 
*)&icmpsrc
); 
 598          * No kernel processing for the following; 
 599          * just fall through to send to raw listener. 
 602         case ICMP_ROUTERADVERT
: 
 603         case ICMP_ROUTERSOLICIT
: 
 604         case ICMP_TSTAMPREPLY
: 
 620  * Reflect the ip packet back to the source 
 626         register struct ip 
*ip 
= mtod(m
, struct ip 
*); 
 627         register struct in_ifaddr 
*ia
; 
 629         struct mbuf 
*opts 
= 0; 
 630         int optlen 
= (IP_VHL_HL(ip
->ip_vhl
) << 2) - sizeof(struct ip
); 
 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 */ 
 639         ip
->ip_dst 
= ip
->ip_src
; 
 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. 
 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
) 
 649                 if (ia
->ia_ifp 
&& (ia
->ia_ifp
->if_flags 
& IFF_BROADCAST
) && 
 650                     t
.s_addr 
== satosin(&ia
->ia_broadaddr
)->sin_addr
.s_addr
) 
 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
); 
 658          * The following happens if the packet was not addressed to us, 
 659          * and was received on an interface with no IP address. 
 661         if (ia 
== (struct in_ifaddr 
*)0) 
 662                 ia 
= in_ifaddrhead
.tqh_first
; 
 663         t 
= IA_SIN(ia
)->sin_addr
; 
 665         ip
->ip_ttl 
= ip_defttl
; 
 673                  * Retrieve any source routing from the incoming packet; 
 674                  * add on any record-route or timestamp options. 
 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; 
 685                             printf("icmp_reflect optlen %d rt %d => ", 
 686                                 optlen
, opts
->m_len
); 
 688                     for (cnt 
= optlen
; cnt 
> 0; cnt 
-= len
, cp 
+= len
) { 
 689                             opt 
= cp
[IPOPT_OPTVAL
]; 
 690                             if (opt 
== IPOPT_EOL
) 
 692                             if (opt 
== IPOPT_NOP
) 
 695                                     if (cnt 
< IPOPT_OLEN 
+ sizeof(*cp
)) 
 697                                     len 
= cp
[IPOPT_OLEN
]; 
 698                                     if (len 
< IPOPT_OLEN 
+ sizeof(*cp
) || 
 703                              * Should check for overflow, but it "can't happen" 
 705                             if (opt 
== IPOPT_RR 
|| opt 
== IPOPT_TS 
|| 
 706                                 opt 
== IPOPT_SECURITY
) { 
 708                                         mtod(opts
, caddr_t
) + opts
->m_len
, len
); 
 712                     /* Terminate & pad, if necessary */ 
 713                     cnt 
= opts
->m_len 
% 4; 
 715                             for (; cnt 
< 4; cnt
++) { 
 716                                     *(mtod(opts
, caddr_t
) + opts
->m_len
) = 
 723                             printf("%d\n", opts
->m_len
); 
 727                  * Now strip out original options by copying rest of first 
 728                  * mbuf's data back, and adjust the IP length. 
 730                 ip
->ip_len 
-= optlen
; 
 731                 ip
->ip_vhl 
= IP_VHL_BORING
; 
 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
))); 
 739         m
->m_flags 
&= ~(M_BCAST
|M_MCAST
); 
 747  * Send an icmp packet back to the ip level, 
 748  * after supplying a checksum. 
 752         register struct mbuf 
*m
; 
 755         register struct ip 
*ip 
= mtod(m
, struct ip 
*); 
 757         register struct icmp 
*icp
; 
 760         hlen 
= IP_VHL_HL(ip
->ip_vhl
) << 2; 
 763         icp 
= mtod(m
, struct icmp 
*); 
 765         icp
->icmp_cksum 
= in_cksum(m
, ip
->ip_len 
- hlen
); 
 768         m
->m_pkthdr
.rcvif 
= (struct ifnet 
*)0; 
 769         m
->m_pkthdr
.aux 
= NULL
; 
 770         m
->m_pkthdr
.csum_data 
= 0; 
 771         m
->m_pkthdr
.csum_flags 
= 0; 
 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
)); 
 780         bzero(&ro
, sizeof ro
); 
 781         (void) ip_output(m
, opts
, &ro
, 0, NULL
); 
 793         t 
= (atv
.tv_sec 
% (24*60*60)) * 1000 + atv
.tv_usec 
/ 1000; 
 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. 
 804 ip_next_mtu(mtu
, dir
) 
 808         static int mtutab
[] = { 
 809                 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 
 814         for (i 
= 0; i 
< (sizeof mtutab
) / (sizeof mtutab
[0]); i
++) { 
 815                 if (mtu 
>= mtutab
[i
]) 
 823                         return mtutab
[i 
- 1]; 
 826                 if (mtutab
[i
] == 0) { 
 828                 } else if(mtu 
> mtutab
[i
]) { 
 831                         return mtutab
[i 
+ 1]; 
 840  * badport_bandlim() - check for ICMP bandwidth limit 
 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.   
 845  *      If icmplim is <= 0, the feature is disabled and 0 is returned. 
 847  *      For now we separate the TCP and UDP subsystems w/ different 'which' 
 848  *      values.  We may eventually remove this separation (and simplify the 
 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. 
 859 badport_bandlim(int which
) 
 861         static struct timeval lticks
[BANDLIM_MAX 
+ 1]; 
 862         static int lpackets
[BANDLIM_MAX 
+ 1]; 
 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" 
 875          * Return ok status if feature disabled or argument out of 
 879         if (icmplim 
<= 0 || which 
> BANDLIM_MAX 
|| which 
< 0) 
 884         secs 
= time
.tv_sec 
- lticks
[which
].tv_sec 
; 
 887          * reset stats when cumulative delta exceeds one second. 
 890         if ((secs 
> 1) || (secs 
== 1 && (lticks
[which
].tv_usec 
> time
.tv_usec
))) {  
 891                 if (lpackets
[which
] > icmplim
) { 
 892                         printf("%s from %d to %d packets per second\n", 
 893                                 bandlimittype
[which
], 
 898                 lticks
[which
].tv_sec 
= time
.tv_sec
; 
 899                 lticks
[which
].tv_usec 
= time
.tv_usec
; 
 907         if (++lpackets
[which
] > icmplim
) { 
 918  * Non-privileged ICMP socket operations 
 919  * - send ICMP echo request 
 921  * - limited socket options 
 924 #include <netinet/ip_icmp.h> 
 925 #include <netinet/in_pcb.h> 
 927 extern struct domain inetdomain
; 
 928 extern u_long rip_sendspace
; 
 929 extern u_long rip_recvspace
; 
 930 extern struct inpcbinfo ripcbinfo
; 
 932 int rip_abort(struct socket 
*); 
 933 int rip_bind(struct socket 
*, struct sockaddr 
*, struct proc 
*); 
 934 int rip_connect(struct socket 
*, struct sockaddr 
*, struct proc 
*); 
 935 int rip_detach(struct socket 
*); 
 936 int rip_disconnect(struct socket 
*); 
 937 int rip_shutdown(struct socket 
*); 
 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
); 
 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
 
 951 /* Like rip_attach but without root privilege enforcement */ 
 952 __private_extern__ 
int 
 953 icmp_dgram_attach(struct socket 
*so
, int proto
, struct proc 
*p
) 
 960                 panic("icmp_dgram_attach"); 
 962         error 
= soreserve(so
, rip_sendspace
, rip_recvspace
); 
 966         error 
= in_pcballoc(so
, &ripcbinfo
, p
); 
 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
; 
 978  * Raw IP socket option processing. 
 980 __private_extern__ 
int 
 981 icmp_dgram_ctloutput(struct socket 
*so
, struct sockopt 
*sopt
) 
 983         struct  inpcb 
*inp 
= sotoinpcb(so
); 
 986         if (sopt
->sopt_level 
!= IPPROTO_IP
) 
 989         switch (sopt
->sopt_name
) { 
 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
: 
1006                 case IP_IPSEC_POLICY
: 
1007 #if defined(NFAITH) && NFAITH > 0 
1011                         error 
= rip_ctloutput(so
, sopt
); 
1022 __private_extern__ 
int 
1023 icmp_dgram_send(struct socket 
*so
, int flags
, struct mbuf 
*m
, struct sockaddr 
*nam
, 
1024          struct mbuf 
*control
, struct proc 
*p
) 
1027         struct inpcb 
*inp 
= sotoinpcb(so
); 
1030         struct in_ifaddr 
*ia 
= NULL
; 
1033         if ((inp
->inp_flags 
& INP_HDRINCL
) != 0) { 
1035                  * This is not raw IP, we liberal only for fields TOS, id and TTL  
1037                 ip 
= mtod(m
, struct ip 
*); 
1039                 hlen 
= IP_VHL_HL(ip
->ip_vhl
) << 2; 
1040                 /* Some sanity checks */ 
1041                 if (m
->m_pkthdr
.len 
< hlen 
+ ICMP_MINLEN
) { 
1045                 if (IP_VHL_V(ip
->ip_vhl
) != 4) 
1047                 if (hlen 
< 20 || hlen 
> 40 || ip
->ip_len 
!= m
->m_pkthdr
.len 
|| 
1050                 /* Bogus fragments can tie up peer resources */  
1051                 if (ip
->ip_off 
!= 0) 
1053                 /* Allow only ICMP even for user provided IP header */ 
1054                 if (ip
->ip_p 
!= IPPROTO_ICMP
) 
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
)) 
1060                         TAILQ_FOREACH(ia
, &in_ifaddrhead
, ia_link
) { 
1061                                 if (IA_SIN(ia
)->sin_addr
.s_addr 
== ip
->ip_src
.s_addr
) 
1067                 /* Do not trust we got a valid checksum */ 
1070                 icp 
= (struct icmp 
*)(((char *)m
->m_data
) + hlen
); 
1071                 icmplen 
= m
->m_pkthdr
.len 
- hlen
; 
1073                 if ((icmplen 
= m
->m_pkthdr
.len
) < ICMP_MINLEN
) { 
1076                 icp 
= mtod(m
, struct icmp 
*); 
1079          * Allow only to send request types with code 0 
1081         if (icp
->icmp_code 
!= 0) 
1083         switch (icp
->icmp_type
) { 
1097         return rip_send(so
, flags
, m
, nam
, control
, p
); 
1103 #endif /* __APPLE__ */