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