1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1991-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * icmp4.c, Code implementing the Internet Control Message Protocol (v4) ICMP. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <sys/types.h> 32 #include <socket_impl.h> 33 #include <socket_inet.h> 34 #include <sys/salib.h> 35 #include <sys/socket.h> 36 #include <netinet/in_systm.h> 37 #include <netinet/in.h> 38 #include <netinet/ip.h> 39 #include <netinet/udp.h> 40 #include <netinet/ip_icmp.h> 41 #include <sys/bootconf.h> 42 #include <sys/fcntl.h> 43 44 #include "icmp4.h" 45 #include "ipv4.h" 46 #include "ipv4_impl.h" 47 #include "mac.h" 48 #include "v4_sum_impl.h" 49 #include <sys/bootdebug.h> 50 51 /* 52 * Handle ICMP redirects, ICMP echo messages. We only deal with redirects to a 53 * different default router by changing the default route to the specified 54 * value. 55 */ 56 void 57 icmp4(struct inetgram *igp, struct ip *iphp, uint16_t iphlen, 58 struct in_addr ipsrc) 59 { 60 int icmp_len; 61 struct in_addr our_ip; 62 struct icmp *icmphp; 63 64 icmp_len = ntohs(iphp->ip_len) - iphlen; 65 if (icmp_len < ICMP_MINLEN) { 66 #ifdef DEBUG 67 printf("icmp4: ICMP message from %s is too short\n", 68 inet_ntoa(ipsrc)); 69 #endif /* DEBUG */ 70 return; 71 } 72 73 icmphp = (struct icmp *)(igp->igm_mp->b_rptr + iphlen); 74 75 /* check alignment */ 76 if ((uintptr_t)icmphp % sizeof (uint16_t)) { 77 dprintf("icmp4: ICMP header not aligned (from %s)\n", 78 inet_ntoa(ipsrc)); 79 return; 80 } 81 if (ipv4cksum((uint16_t *)icmphp, icmp_len) != 0) { 82 dprintf("icmp4: Bad ICMP checksum (from %s)\n", 83 inet_ntoa(ipsrc)); 84 return; 85 } 86 switch (icmphp->icmp_type) { 87 case ICMP_REDIRECT: 88 if (icmphp->icmp_code != ICMP_REDIRECT_HOST) 89 break; 90 dprintf("ICMP Redirect to gateway %s.\n", 91 inet_ntoa(icmphp->icmp_gwaddr)); 92 if (ipv4_route(IPV4_ADD_ROUTE, RT_HOST, &icmphp->icmp_ip.ip_dst, 93 &icmphp->icmp_gwaddr) != 0) { 94 dprintf("icmp4: Cannot add route %s, %d\n", 95 inet_ntoa(icmphp->icmp_ip.ip_dst), errno); 96 } 97 break; 98 case ICMP_UNREACH: 99 /* 100 * Need to highlight an error on the socket, and save the 101 * destination address so that we can ensure it is destined 102 * to this socket. We need the port number to be sure... 103 */ 104 dprintf("ICMP destination unreachable (%s)\n", 105 inet_ntoa(icmphp->icmp_ip.ip_dst)); 106 break; 107 case ICMP_ECHO: 108 /* 109 * swap the source and destination IP addresses 110 * and send a reply right out. 111 */ 112 ipv4_getipaddr(&our_ip); 113 if (our_ip.s_addr != INADDR_ANY) { 114 int s; 115 struct sockaddr_in dest; 116 117 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { 118 dprintf("icmp4: socket: %d\n", errno); 119 break; 120 } 121 icmphp->icmp_type = ICMP_ECHOREPLY; 122 icmphp->icmp_cksum = 0; 123 icmphp->icmp_cksum = ipv4cksum((uint16_t *)icmphp, 124 icmp_len); 125 dest.sin_family = AF_INET; 126 dest.sin_addr.s_addr = ipsrc.s_addr; 127 dest.sin_port = htons(0); 128 (void) sendto(s, (caddr_t)icmphp, icmp_len, 0, 129 (const struct sockaddr *)&dest, sizeof (dest)); 130 (void) socket_close(s); 131 } 132 break; 133 default: 134 dprintf("icmp4: Unsupported ICMP message type: 0x%x " 135 "received from %s\n", icmphp->icmp_type, inet_ntoa(ipsrc)); 136 break; 137 } 138 } 139