|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988, 1993 ! 3: * The Regents of the University of California. All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. Neither the name of the University nor the names of its contributors ! 14: * may be used to endorse or promote products derived from this software ! 15: * without specific prior written permission. ! 16: * ! 17: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 27: * SUCH DAMAGE. ! 28: * ! 29: * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 ! 30: * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp ! 31: */ ! 32: ! 33: #include "slirp.h" ! 34: #include "ip_icmp.h" ! 35: ! 36: struct icmpstat icmpstat; ! 37: ! 38: /* The message sent when emulating PING */ ! 39: /* Be nice and tell them it's just a psuedo-ping packet */ ! 40: char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; ! 41: ! 42: /* list of actions for icmp_error() on RX of an icmp message */ ! 43: static int icmp_flush[19] = { ! 44: /* ECHO REPLY (0) */ 0, ! 45: 1, ! 46: 1, ! 47: /* DEST UNREACH (3) */ 1, ! 48: /* SOURCE QUENCH (4)*/ 1, ! 49: /* REDIRECT (5) */ 1, ! 50: 1, ! 51: 1, ! 52: /* ECHO (8) */ 0, ! 53: /* ROUTERADVERT (9) */ 1, ! 54: /* ROUTERSOLICIT (10) */ 1, ! 55: /* TIME EXCEEDED (11) */ 1, ! 56: /* PARAMETER PROBLEM (12) */ 1, ! 57: /* TIMESTAMP (13) */ 0, ! 58: /* TIMESTAMP REPLY (14) */ 0, ! 59: /* INFO (15) */ 0, ! 60: /* INFO REPLY (16) */ 0, ! 61: /* ADDR MASK (17) */ 0, ! 62: /* ADDR MASK REPLY (18) */ 0 ! 63: }; ! 64: ! 65: /* ! 66: * Process a received ICMP message. ! 67: */ ! 68: void ! 69: icmp_input(m, hlen) ! 70: struct mbuf *m; ! 71: int hlen; ! 72: { ! 73: register struct icmp *icp; ! 74: register struct ip *ip=mtod(m, struct ip *); ! 75: int icmplen=ip->ip_len; ! 76: /* int code; */ ! 77: ! 78: DEBUG_CALL("icmp_input"); ! 79: DEBUG_ARG("m = %lx", (long )m); ! 80: DEBUG_ARG("m_len = %zu", m->m_len); ! 81: ! 82: icmpstat.icps_received++; ! 83: ! 84: /* ! 85: * Locate icmp structure in mbuf, and check ! 86: * that its not corrupted and of at least minimum length. ! 87: */ ! 88: if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ ! 89: icmpstat.icps_tooshort++; ! 90: freeit: ! 91: m_freem(m); ! 92: goto end_error; ! 93: } ! 94: ! 95: m->m_len -= hlen; ! 96: m->m_data += hlen; ! 97: icp = mtod(m, struct icmp *); ! 98: if (cksum(m, icmplen)) { ! 99: icmpstat.icps_checksum++; ! 100: goto freeit; ! 101: } ! 102: m->m_len += hlen; ! 103: m->m_data -= hlen; ! 104: ! 105: /* icmpstat.icps_inhist[icp->icmp_type]++; */ ! 106: /* code = icp->icmp_code; */ ! 107: ! 108: DEBUG_ARG("icmp_type = %d", icp->icmp_type); ! 109: switch (icp->icmp_type) { ! 110: case ICMP_ECHO: ! 111: icp->icmp_type = ICMP_ECHOREPLY; ! 112: ip->ip_len += hlen; /* since ip_input subtracts this */ ! 113: if (ip->ip_dst.s_addr == alias_addr.s_addr) { ! 114: icmp_reflect(m); ! 115: } else { ! 116: struct socket *so; ! 117: struct sockaddr_in addr; ! 118: if ((so = socreate()) == NULL) goto freeit; ! 119: if(udp_attach(so) == -1) { ! 120: DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", ! 121: errno,strerror(errno))); ! 122: sofree(so); ! 123: m_free(m); ! 124: goto end_error; ! 125: } ! 126: so->so_m = m; ! 127: so->so_faddr = ip->ip_dst; ! 128: so->so_fport = htons(7); ! 129: so->so_laddr = ip->ip_src; ! 130: so->so_lport = htons(9); ! 131: so->so_iptos = ip->ip_tos; ! 132: so->so_type = IPPROTO_ICMP; ! 133: so->so_state = SS_ISFCONNECTED; ! 134: ! 135: /* Send the packet */ ! 136: addr.sin_family = AF_INET; ! 137: if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { ! 138: /* It's an alias */ ! 139: switch(ntohl(so->so_faddr.s_addr) & 0xff) { ! 140: case CTL_DNS: ! 141: addr.sin_addr = dns_addr; ! 142: break; ! 143: case CTL_ALIAS: ! 144: default: ! 145: addr.sin_addr = loopback_addr; ! 146: break; ! 147: } ! 148: } else { ! 149: addr.sin_addr = so->so_faddr; ! 150: } ! 151: addr.sin_port = so->so_fport; ! 152: if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, ! 153: (struct sockaddr *)&addr, sizeof(addr)) == -1) { ! 154: DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", ! 155: errno,strerror(errno))); ! 156: icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); ! 157: udp_detach(so); ! 158: } ! 159: } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ ! 160: break; ! 161: case ICMP_UNREACH: ! 162: /* XXX? report error? close socket? */ ! 163: case ICMP_TIMXCEED: ! 164: case ICMP_PARAMPROB: ! 165: case ICMP_SOURCEQUENCH: ! 166: case ICMP_TSTAMP: ! 167: case ICMP_MASKREQ: ! 168: case ICMP_REDIRECT: ! 169: icmpstat.icps_notsupp++; ! 170: m_freem(m); ! 171: break; ! 172: ! 173: default: ! 174: icmpstat.icps_badtype++; ! 175: m_freem(m); ! 176: } /* swith */ ! 177: ! 178: end_error: ! 179: /* m is m_free()'d xor put in a socket xor or given to ip_send */ ! 180: return; ! 181: } ! 182: ! 183: ! 184: /* ! 185: * Send an ICMP message in response to a situation ! 186: * ! 187: * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). ! 188: * MUST NOT change this header information. ! 189: * MUST NOT reply to a multicast/broadcast IP address. ! 190: * MUST NOT reply to a multicast/broadcast MAC address. ! 191: * MUST reply to only the first fragment. ! 192: */ ! 193: /* ! 194: * Send ICMP_UNREACH back to the source regarding msrc. ! 195: * mbuf *msrc is used as a template, but is NOT m_free()'d. ! 196: * It is reported as the bad ip packet. The header should ! 197: * be fully correct and in host byte order. ! 198: * ICMP fragmentation is illegal. All machines must accept 576 bytes in one ! 199: * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 ! 200: */ ! 201: ! 202: #define ICMP_MAXDATALEN (IP_MSS-28) ! 203: void ! 204: icmp_error( ! 205: struct mbuf *msrc, ! 206: u_char type, ! 207: u_char code, ! 208: int minsize, ! 209: const char *message) ! 210: { ! 211: unsigned hlen, shlen, s_ip_len; ! 212: register struct ip *ip; ! 213: register struct icmp *icp; ! 214: register struct mbuf *m; ! 215: ! 216: DEBUG_CALL("icmp_error"); ! 217: DEBUG_ARG("msrc = %lx", (long )msrc); ! 218: DEBUG_ARG("msrc_len = %zu", msrc->m_len); ! 219: ! 220: if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; ! 221: ! 222: /* check msrc */ ! 223: if(!msrc) goto end_error; ! 224: ip = mtod(msrc, struct ip *); ! 225: #if DEBUG ! 226: { char bufa[INET_ADDRSTRLEN], bufb[INET_ADDRSTRLEN]; ! 227: inet_ntop(AF_INET, &ip->ip_src, bufa, sizeof(bufa)); ! 228: inet_ntop(AF_INET, &ip->ip_dst, bufb, sizeof(bufb)); ! 229: DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); ! 230: } ! 231: #endif ! 232: if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ ! 233: ! 234: shlen=ip->ip_hl << 2; ! 235: s_ip_len=ip->ip_len; ! 236: if(ip->ip_p == IPPROTO_ICMP) { ! 237: icp = (struct icmp *)((char *)ip + shlen); ! 238: /* ! 239: * Assume any unknown ICMP type is an error. This isn't ! 240: * specified by the RFC, but think about it.. ! 241: */ ! 242: if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; ! 243: } ! 244: ! 245: /* make a copy */ ! 246: if(!(m=m_get())) goto end_error; /* get mbuf */ ! 247: { u_int new_m_size; ! 248: new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; ! 249: if(new_m_size>m->m_size) m_inc(m, new_m_size); ! 250: } ! 251: memcpy(m->m_data, msrc->m_data, msrc->m_len); ! 252: m->m_len = msrc->m_len; /* copy msrc to m */ ! 253: ! 254: /* make the header of the reply packet */ ! 255: ip = mtod(m, struct ip *); ! 256: hlen= sizeof(struct ip ); /* no options in reply */ ! 257: ! 258: /* fill in icmp */ ! 259: m->m_data += hlen; ! 260: m->m_len -= hlen; ! 261: ! 262: icp = mtod(m, struct icmp *); ! 263: ! 264: if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ ! 265: else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ ! 266: s_ip_len=ICMP_MAXDATALEN; ! 267: ! 268: m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ ! 269: ! 270: /* min. size = 8+sizeof(struct ip)+8 */ ! 271: ! 272: icp->icmp_type = type; ! 273: icp->icmp_code = code; ! 274: icp->icmp_id = 0; ! 275: icp->icmp_seq = 0; ! 276: ! 277: memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ ! 278: HTONS(icp->icmp_ip.ip_len); ! 279: HTONS(icp->icmp_ip.ip_id); ! 280: HTONS(icp->icmp_ip.ip_off); ! 281: ! 282: #if DEBUG ! 283: if(message) { /* DEBUG : append message to ICMP packet */ ! 284: int message_len; ! 285: char *cpnt; ! 286: message_len=strlen(message); ! 287: if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; ! 288: cpnt=(char *)m->m_data+m->m_len; ! 289: memcpy(cpnt, message, message_len); ! 290: m->m_len+=message_len; ! 291: } ! 292: #endif ! 293: ! 294: icp->icmp_cksum = 0; ! 295: icp->icmp_cksum = cksum(m, m->m_len); ! 296: ! 297: m->m_data -= hlen; ! 298: m->m_len += hlen; ! 299: ! 300: /* fill in ip */ ! 301: ip->ip_hl = hlen >> 2; ! 302: ip->ip_len = (u_int16_t)m->m_len; ! 303: ! 304: ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ ! 305: ! 306: ip->ip_ttl = MAXTTL; ! 307: ip->ip_p = IPPROTO_ICMP; ! 308: ip->ip_dst = ip->ip_src; /* ip adresses */ ! 309: ip->ip_src = alias_addr; ! 310: ! 311: (void ) ip_output((struct socket *)NULL, m); ! 312: ! 313: icmpstat.icps_reflect++; ! 314: ! 315: end_error: ! 316: return; ! 317: } ! 318: #undef ICMP_MAXDATALEN ! 319: ! 320: /* ! 321: * Reflect the ip packet back to the source ! 322: */ ! 323: void ! 324: icmp_reflect(m) ! 325: struct mbuf *m; ! 326: { ! 327: register struct ip *ip = mtod(m, struct ip *); ! 328: int hlen = ip->ip_hl << 2; ! 329: int optlen = hlen - sizeof(struct ip ); ! 330: register struct icmp *icp; ! 331: ! 332: /* ! 333: * Send an icmp packet back to the ip level, ! 334: * after supplying a checksum. ! 335: */ ! 336: m->m_data += hlen; ! 337: m->m_len -= hlen; ! 338: icp = mtod(m, struct icmp *); ! 339: ! 340: icp->icmp_cksum = 0; ! 341: icp->icmp_cksum = cksum(m, ip->ip_len - hlen); ! 342: ! 343: m->m_data -= hlen; ! 344: m->m_len += hlen; ! 345: ! 346: /* fill in ip */ ! 347: if (optlen > 0) { ! 348: /* ! 349: * Strip out original options by copying rest of first ! 350: * mbuf's data back, and adjust the IP length. ! 351: */ ! 352: memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen, ! 353: (unsigned )(m->m_len - hlen)); ! 354: hlen -= optlen; ! 355: ip->ip_hl = hlen >> 2; ! 356: ip->ip_len -= optlen; ! 357: m->m_len -= optlen; ! 358: } ! 359: ! 360: ip->ip_ttl = MAXTTL; ! 361: { /* swap */ ! 362: struct in_addr icmp_dst; ! 363: icmp_dst = ip->ip_dst; ! 364: ip->ip_dst = ip->ip_src; ! 365: ip->ip_src = icmp_dst; ! 366: } ! 367: ! 368: (void ) ip_output((struct socket *)NULL, m); ! 369: ! 370: icmpstat.icps_reflect++; ! 371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.