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 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef LOG_ENABLED 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct icmpstat icmpstat; 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* The message sent when emulating PING */ 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Be nice and tell them it's just a pseudo-ping packet */ 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* list of actions for icmp_error() on RX of an icmp message */ 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const int icmp_flush[19] = { 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ECHO REPLY (0) */ 0, 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* DEST UNREACH (3) */ 1, 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* SOURCE QUENCH (4)*/ 1, 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* REDIRECT (5) */ 1, 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1, 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ECHO (8) */ 0, 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ROUTERADVERT (9) */ 1, 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ROUTERSOLICIT (10) */ 1, 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TIME EXCEEDED (11) */ 1, 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* PARAMETER PROBLEM (12) */ 1, 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TIMESTAMP (13) */ 0, 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TIMESTAMP REPLY (14) */ 0, 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* INFO (15) */ 0, 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* INFO REPLY (16) */ 0, 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ADDR MASK (17) */ 0, 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ADDR MASK REPLY (18) */ 0 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Process a received ICMP message. 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnericmp_input(struct mbuf *m, int hlen) 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct icmp *icp; 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner register struct ip *ip=mtod(m, struct ip *); 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int icmplen=ip->ip_len; 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* int code; */ 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_CALL("icmp_input"); 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("m = %lx", (long )m); 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("m_len = %d", m->m_len); 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_received++); 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Locate icmp structure in mbuf, and check 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * that its not corrupted and of at least minimum length. 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_tooshort++); 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project freeit: 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_freem(m); 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto end_error; 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= hlen; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data += hlen; 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner icp = mtod(m, struct icmp *); 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (cksum(m, icmplen)) { 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_checksum++); 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto freeit; 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len += hlen; 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data -= hlen; 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* icmpstat.icps_inhist[icp->icmp_type]++; */ 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* code = icp->icmp_code; */ 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("icmp_type = %d", icp->icmp_type); 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (icp->icmp_type) { 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_ECHO: 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_type = ICMP_ECHOREPLY; 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len += hlen; /* since ip_input subtracts this */ 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ip->ip_dst.s_addr == alias_addr.s_addr) { 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icmp_reflect(m); 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project struct socket *so; 1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct sockaddr_in addr; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ((so = socreate()) == NULL) goto freeit; 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(udp_attach(so) == -1) { 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", 1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner errno,strerror(errno))); 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project sofree(so); 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_free(m); 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto end_error; 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_m = m; 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner so->so_faddr = ip->ip_dst; 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner so->so_fport = htons(7); 1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner so->so_laddr = ip->ip_src; 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner so->so_lport = htons(9); 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_iptos = ip->ip_tos; 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_type = IPPROTO_ICMP; 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project so->so_state = SS_ISFCONNECTED; 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Send the packet */ 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr.sin_family = AF_INET; 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* It's an alias */ 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch(ntohl(so->so_faddr.s_addr) & 0xff) { 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case CTL_DNS: 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr.sin_addr = dns_addr; 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case CTL_ALIAS: 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr.sin_addr = loopback_addr; 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr.sin_addr = so->so_faddr; 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner addr.sin_port = so->so_fport; 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (struct sockaddr *)&addr, sizeof(addr)) == -1) { 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", 1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner errno,strerror(errno))); 1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner udp_detach(so); 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_UNREACH: 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* XXX? report error? close socket? */ 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_TIMXCEED: 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_PARAMPROB: 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_SOURCEQUENCH: 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_TSTAMP: 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_MASKREQ: 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ICMP_REDIRECT: 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_notsupp++); 1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_freem(m); 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_badtype++); 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_freem(m); 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } /* swith */ 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectend_error: 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* m is m_free()'d xor put in a socket xor or given to ip_send */ 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Send an ICMP message in response to a situation 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 1878b23a6c7e1aee255004dd19098d4c2462b61b849The 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). 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST NOT change this header information. 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST NOT reply to a multicast/broadcast IP address. 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST NOT reply to a multicast/broadcast MAC address. 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MUST reply to only the first fragment. 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Send ICMP_UNREACH back to the source regarding msrc. 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * mbuf *msrc is used as a template, but is NOT m_free()'d. 1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * It is reported as the bad ip packet. The header should 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * be fully correct and in host byte order. 1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ICMP fragmentation is illegal. All machines must accept 576 bytes in one 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ICMP_MAXDATALEN (IP_MSS-28) 2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnericmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *message) 2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project unsigned hlen, shlen, s_ip_len; 2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct ip *ip; 2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct icmp *icp; 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner register struct mbuf *m; 2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_CALL("icmp_error"); 2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("msrc = %lx", (long )msrc); 2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("msrc_len = %d", msrc->m_len); 2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; 2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* check msrc */ 2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(!msrc) goto end_error; 2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ip = mtod(msrc, struct ip *); 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG 2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { char bufa[20], bufb[20]; 2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner strcpy(bufa, inet_ntoa(ip->ip_src)); 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner strcpy(bufb, inet_ntoa(ip->ip_dst)); 2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); 2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ 2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project shlen=ip->ip_hl << 2; 2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s_ip_len=ip->ip_len; 2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ip->ip_p == IPPROTO_ICMP) { 2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp = (struct icmp *)((char *)ip + shlen); 2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Assume any unknown ICMP type is an error. This isn't 2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * specified by the RFC, but think about it.. 2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; 2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* make a copy */ 2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(!(m=m_get())) goto end_error; /* get mbuf */ 2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { int new_m_size; 2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; 2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(new_m_size>m->m_size) m_inc(m, new_m_size); 2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(m->m_data, msrc->m_data, msrc->m_len); 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len = msrc->m_len; /* copy msrc to m */ 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* make the header of the reply packet */ 2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ip = mtod(m, struct ip *); 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project hlen= sizeof(struct ip ); /* no options in reply */ 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fill in icmp */ 2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data += hlen; 2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= hlen; 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner icp = mtod(m, struct icmp *); 2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s_ip_len=ICMP_MAXDATALEN; 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* min. size = 8+sizeof(struct ip)+8 */ 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_type = type; 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_code = code; 2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_id = 0; 2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_seq = 0; 2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ 2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HTONS(icp->icmp_ip.ip_len); 2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HTONS(icp->icmp_ip.ip_id); 2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HTONS(icp->icmp_ip.ip_off); 2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG 2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(message) { /* DEBUG : append message to ICMP packet */ 2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int message_len; 2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char *cpnt; 2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project message_len=strlen(message); 2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; 2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpnt=(char *)m->m_data+m->m_len; 2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(cpnt, message, message_len); 2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len+=message_len; 2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = 0; 2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = cksum(m, m->m_len); 2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data -= hlen; 2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len += hlen; 2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fill in ip */ 2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_hl = hlen >> 2; 2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len = m->m_len; 2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ 3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_ttl = MAXTTL; 3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_p = IPPROTO_ICMP; 3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_dst = ip->ip_src; /* ip adresses */ 3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ip->ip_src = alias_addr; 3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (void ) ip_output((struct socket *)NULL, m); 3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_reflect++); 3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectend_error: 3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef ICMP_MAXDATALEN 3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Reflect the ip packet back to the source 3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid 3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnericmp_reflect(struct mbuf *m) 3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner register struct ip *ip = mtod(m, struct ip *); 3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int hlen = ip->ip_hl << 2; 3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int optlen = hlen - sizeof(struct ip ); 3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct icmp *icp; 3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Send an icmp packet back to the ip level, 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * after supplying a checksum. 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data += hlen; 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= hlen; 3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner icp = mtod(m, struct icmp *); 3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = 0; 3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project icp->icmp_cksum = cksum(m, ip->ip_len - hlen); 3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_data -= hlen; 3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len += hlen; 3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* fill in ip */ 3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (optlen > 0) { 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Strip out original options by copying rest of first 3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * mbuf's data back, and adjust the IP length. 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen, 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (unsigned )(m->m_len - hlen)); 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project hlen -= optlen; 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_hl = hlen >> 2; 3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len -= optlen; 3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len -= optlen; 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_ttl = MAXTTL; 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { /* swap */ 3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct in_addr icmp_dst; 3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner icmp_dst = ip->ip_dst; 3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_dst = ip->ip_src; 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_src = icmp_dst; 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (void ) ip_output((struct socket *)NULL, m); 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(icmpstat.icps_reflect++); 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 367