ip_icmp.c revision 8b23a6c7e1aee255004dd19098d4c2462b61b849
18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 1982, 1986, 1988, 1993 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The Regents of the University of California. All rights reserved. 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Redistribution and use in source and binary forms, with or without 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * modification, are permitted provided that the following conditions 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * are met: 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 1. Redistributions of source code must retain the above copyright 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * notice, this list of conditions and the following disclaimer. 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * notice, this list of conditions and the following disclaimer in the 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * documentation and/or other materials provided with the distribution. 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 3. All advertising materials mentioning features or use of this software 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * must display the following acknowledgement: 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This product includes software developed by the University of 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * California, Berkeley and its contributors. 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 4. Neither the name of the University nor the names of its contributors 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * may be used to endorse or promote products derived from this software 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * without specific prior written permission. 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * SUCH DAMAGE. 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "slirp.h" 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "ip_icmp.h" 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "sockets.h" 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct icmpstat icmpstat; 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* The message sent when emulating PING */ 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Be nice and tell them it's just a psuedo-ping packet */ 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectchar icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* list of actions for icmp_error() on RX of an icmp message */ 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int icmp_flush[19] = { 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ECHO REPLY (0) */ 0, 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* DEST UNREACH (3) */ 1, 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* SOURCE QUENCH (4)*/ 1, 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* REDIRECT (5) */ 1, 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ECHO (8) */ 0, 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ROUTERADVERT (9) */ 1, 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ROUTERSOLICIT (10) */ 1, 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TIME EXCEEDED (11) */ 1, 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* PARAMETER PROBLEM (12) */ 1, 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TIMESTAMP (13) */ 0, 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TIMESTAMP REPLY (14) */ 0, 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* INFO (15) */ 0, 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* INFO REPLY (16) */ 0, 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ADDR MASK (17) */ 0, 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ADDR MASK REPLY (18) */ 0 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Process a received ICMP message. 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecticmp_input(m, hlen) 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project MBuf m; 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int hlen; 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct icmp *icp; 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct ip *ip=MBUF_TO(m, struct ip *); 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int icmplen=ip->ip_len; 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* int code; */ 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_CALL("icmp_input"); 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("m = %lx", (long )m); 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("m_len = %d", m->m_len); 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_received++; 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Locate icmp structure in mbuf, and check 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * that its not corrupted and of at least minimum length. 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_tooshort++; 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project freeit: 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mbuf_free(m); 978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto end_error; 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= hlen; 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data += hlen; 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp = MBUF_TO(m, struct icmp *); 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (cksum(m, icmplen)) { 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_checksum++; 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto freeit; 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len += hlen; 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data -= hlen; 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* icmpstat.icps_inhist[icp->icmp_type]++; */ 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* code = icp->icmp_code; */ 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("icmp_type = %d", icp->icmp_type); 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (icp->icmp_type) { 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_ECHO: 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_type = ICMP_ECHOREPLY; 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len += hlen; /* since ip_input subtracts this */ 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ip_geth(ip->ip_dst) == alias_addr_ip) { 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmp_reflect(m); 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project struct socket *so; 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SockAddress addr; 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t addr_ip; 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint16_t addr_port; 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ((so = socreate()) == NULL) goto freeit; 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(udp_attach(so) == -1) { 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project errno,errno_str)); 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project sofree(so); 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mbuf_free(m); 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto end_error; 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_m = m; 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_faddr_ip = ip_geth(ip->ip_dst); 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_faddr_port = 7; 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_laddr_ip = ip_geth(ip->ip_src); 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_laddr_port = 9; 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_iptos = ip->ip_tos; 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_type = IPPROTO_ICMP; 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_state = SS_ISFCONNECTED; 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Send the packet */ 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) { 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* It's an alias */ 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int low = so->so_faddr_ip & 0xff; 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (low >= CTL_DNS && low < CTL_DNS + dns_addr_count) 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr_ip = dns_addr[low - CTL_DNS]; 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr_ip = loopback_addr_ip; 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr_ip = so->so_faddr_ip; 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project addr_port = so->so_faddr_port; 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project sock_address_init_inet( &addr, addr_ip, addr_port ); 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(socket_sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), &addr) < 0) { 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project errno,errno_str)); 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,errno_str); 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project udp_detach(so); 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_UNREACH: 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* XXX? report error? close socket? */ 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_TIMXCEED: 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_PARAMPROB: 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_SOURCEQUENCH: 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_TSTAMP: 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_MASKREQ: 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_REDIRECT: 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_notsupp++; 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mbuf_free(m); 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_badtype++; 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mbuf_free(m); 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } /* swith */ 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectend_error: 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* m is mbuf_free()'d xor put in a socket xor or given to ip_send */ 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Send an ICMP message in response to a situation 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). 1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST NOT change this header information. 1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST NOT reply to a multicast/broadcast IP address. 1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST NOT reply to a multicast/broadcast MAC address. 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST reply to only the first fragment. 1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Send ICMP_UNREACH back to the source regarding msrc. 2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * mbuf *msrc is used as a template, but is NOT mbuf_free()'d. 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * It is reported as the bad ip packet. The header should 2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * be fully correct and in host byte order. 2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ICMP fragmentation is illegal. All machines must accept 576 bytes in one 2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ICMP_MAXDATALEN (IP_MSS-28) 2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid 2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecticmp_error(msrc, type, code, minsize, message) 2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project MBuf msrc; 2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project u_char type; 2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project u_char code; 2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int minsize; 2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char *message; 2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned hlen, shlen, s_ip_len; 2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct ip *ip; 2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct icmp *icp; 2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register MBuf m; 2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_CALL("icmp_error"); 2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("msrc = %lx", (long )msrc); 2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("msrc_len = %d", msrc->m_len); 2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; 2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* check msrc */ 2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(!msrc) goto end_error; 2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip = MBUF_TO(msrc, struct ip *); 2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if DEBUG 2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { char bufa[20], bufb[20]; 2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project strcpy(bufa, inet_iptostr(ip_geth(ip->ip_src))); 2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project strcpy(bufb, inet_iptostr(ip_geth(ip->ip_dst))); 2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); 2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ 2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project shlen=ip->ip_hl << 2; 2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s_ip_len=ip->ip_len; 2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ip->ip_p == IPPROTO_ICMP) { 2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp = (struct icmp *)((char *)ip + shlen); 2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Assume any unknown ICMP type is an error. This isn't 2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * specified by the RFC, but think about it.. 2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* make a copy */ 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(!(m=mbuf_alloc())) goto end_error; /* get mbuf */ 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { int new_m_size; 2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; 2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(new_m_size>m->m_size) mbuf_ensure(m, new_m_size); 2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(m->m_data, msrc->m_data, msrc->m_len); 2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len = msrc->m_len; /* copy msrc to m */ 2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* make the header of the reply packet */ 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip = MBUF_TO(m, struct ip *); 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project hlen= sizeof(struct ip ); /* no options in reply */ 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fill in icmp */ 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data += hlen; 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= hlen; 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp = MBUF_TO(m, struct icmp *); 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ 2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ 2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s_ip_len=ICMP_MAXDATALEN; 2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ 2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* min. size = 8+sizeof(struct ip)+8 */ 2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_type = type; 2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_code = code; 2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_id = 0; 2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_seq = 0; 2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ 2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HTONS(icp->icmp_ip.ip_len); 2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HTONS(icp->icmp_ip.ip_id); 2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HTONS(icp->icmp_ip.ip_off); 2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if DEBUG 2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(message) { /* DEBUG : append message to ICMP packet */ 2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int message_len; 2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *cpnt; 2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project message_len=strlen(message); 2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; 2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpnt=(char *)m->m_data+m->m_len; 2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(cpnt, message, message_len); 2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len+=message_len; 2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = 0; 3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = cksum(m, m->m_len); 3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data -= hlen; 3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len += hlen; 3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fill in ip */ 3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_hl = hlen >> 2; 3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len = m->m_len; 3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ 3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_ttl = MAXTTL; 3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_p = IPPROTO_ICMP; 3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_dst = ip->ip_src; /* ip adresses */ 3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_src = ip_setn(alias_addr_ip); 3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (void ) ip_output((struct socket *)NULL, m); 3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_reflect++; 3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectend_error: 3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef ICMP_MAXDATALEN 3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Reflect the ip packet back to the source 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecticmp_reflect(m) 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project MBuf m; 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct ip *ip = MBUF_TO(m, struct ip *); 3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int hlen = ip->ip_hl << 2; 3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int optlen = hlen - sizeof(struct ip ); 3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct icmp *icp; 3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Send an icmp packet back to the ip level, 3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * after supplying a checksum. 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data += hlen; 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= hlen; 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp = MBUF_TO(m, struct icmp *); 3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = 0; 3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = cksum(m, ip->ip_len - hlen); 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data -= hlen; 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len += hlen; 3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fill in ip */ 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (optlen > 0) { 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Strip out original options by copying rest of first 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * mbuf's data back, and adjust the IP length. 3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen, 3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (unsigned )(m->m_len - hlen)); 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project hlen -= optlen; 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_hl = hlen >> 2; 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len -= optlen; 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= optlen; 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_ttl = MAXTTL; 3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { /* swap */ 3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ipaddr_t icmp_dst; 3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmp_dst = ip->ip_dst; 3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_dst = ip->ip_src; 3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_src = icmp_dst; 3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (void ) ip_output((struct socket *)NULL, m); 3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmpstat.icps_reflect++; 3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 378