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