|
|
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.
1.1.1.4 root 13: * 3. Neither the name of the University nor the names of its contributors
1.1 root 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: /* The message sent when emulating PING */
1.1.1.3 root 37: /* Be nice and tell them it's just a pseudo-ping packet */
1.1.1.4 root 38: static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
1.1 root 39:
40: /* list of actions for icmp_error() on RX of an icmp message */
1.1.1.3 root 41: static const int icmp_flush[19] = {
1.1 root 42: /* ECHO REPLY (0) */ 0,
43: 1,
44: 1,
45: /* DEST UNREACH (3) */ 1,
46: /* SOURCE QUENCH (4)*/ 1,
47: /* REDIRECT (5) */ 1,
48: 1,
49: 1,
50: /* ECHO (8) */ 0,
51: /* ROUTERADVERT (9) */ 1,
52: /* ROUTERSOLICIT (10) */ 1,
53: /* TIME EXCEEDED (11) */ 1,
54: /* PARAMETER PROBLEM (12) */ 1,
55: /* TIMESTAMP (13) */ 0,
56: /* TIMESTAMP REPLY (14) */ 0,
57: /* INFO (15) */ 0,
58: /* INFO REPLY (16) */ 0,
59: /* ADDR MASK (17) */ 0,
1.1.1.3 root 60: /* ADDR MASK REPLY (18) */ 0
1.1 root 61: };
62:
1.1.1.7 ! root 63: void icmp_init(Slirp *slirp)
! 64: {
! 65: slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
! 66: slirp->icmp_last_so = &slirp->icmp;
! 67: }
! 68:
! 69: static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
! 70: {
! 71: struct ip *ip = mtod(m, struct ip *);
! 72: struct sockaddr_in addr;
! 73:
! 74: so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
! 75: if (so->s == -1) {
! 76: return -1;
! 77: }
! 78:
! 79: so->so_m = m;
! 80: so->so_faddr = ip->ip_dst;
! 81: so->so_laddr = ip->ip_src;
! 82: so->so_iptos = ip->ip_tos;
! 83: so->so_type = IPPROTO_ICMP;
! 84: so->so_state = SS_ISFCONNECTED;
! 85: so->so_expire = curtime + SO_EXPIRE;
! 86:
! 87: addr.sin_family = AF_INET;
! 88: addr.sin_addr = so->so_faddr;
! 89:
! 90: insque(so, &so->slirp->icmp);
! 91:
! 92: if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
! 93: (struct sockaddr *)&addr, sizeof(addr)) == -1) {
! 94: DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n",
! 95: errno, strerror(errno)));
! 96: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
! 97: icmp_detach(so);
! 98: }
! 99:
! 100: return 0;
! 101: }
! 102:
! 103: void icmp_detach(struct socket *so)
! 104: {
! 105: closesocket(so->s);
! 106: sofree(so);
! 107: }
! 108:
1.1 root 109: /*
110: * Process a received ICMP message.
111: */
112: void
1.1.1.5 root 113: icmp_input(struct mbuf *m, int hlen)
1.1 root 114: {
115: register struct icmp *icp;
116: register struct ip *ip=mtod(m, struct ip *);
117: int icmplen=ip->ip_len;
1.1.1.5 root 118: Slirp *slirp = m->slirp;
1.1.1.3 root 119:
1.1 root 120: DEBUG_CALL("icmp_input");
121: DEBUG_ARG("m = %lx", (long )m);
122: DEBUG_ARG("m_len = %d", m->m_len);
123:
124: /*
125: * Locate icmp structure in mbuf, and check
126: * that its not corrupted and of at least minimum length.
127: */
128: if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
129: freeit:
1.1.1.7 ! root 130: m_free(m);
1.1 root 131: goto end_error;
132: }
133:
134: m->m_len -= hlen;
135: m->m_data += hlen;
136: icp = mtod(m, struct icmp *);
137: if (cksum(m, icmplen)) {
138: goto freeit;
139: }
140: m->m_len += hlen;
141: m->m_data -= hlen;
1.1.1.3 root 142:
1.1 root 143: DEBUG_ARG("icmp_type = %d", icp->icmp_type);
144: switch (icp->icmp_type) {
145: case ICMP_ECHO:
146: ip->ip_len += hlen; /* since ip_input subtracts this */
1.1.1.5 root 147: if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
1.1 root 148: icmp_reflect(m);
1.1.1.7 ! root 149: } else if (slirp->restricted) {
! 150: goto freeit;
1.1 root 151: } else {
152: struct socket *so;
153: struct sockaddr_in addr;
1.1.1.5 root 154: if ((so = socreate(slirp)) == NULL) goto freeit;
1.1.1.7 ! root 155: if (icmp_send(so, m, hlen) == 0) {
! 156: return;
! 157: }
1.1 root 158: if(udp_attach(so) == -1) {
1.1.1.3 root 159: DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
1.1 root 160: errno,strerror(errno)));
161: sofree(so);
162: m_free(m);
163: goto end_error;
164: }
165: so->so_m = m;
166: so->so_faddr = ip->ip_dst;
167: so->so_fport = htons(7);
168: so->so_laddr = ip->ip_src;
169: so->so_lport = htons(9);
170: so->so_iptos = ip->ip_tos;
171: so->so_type = IPPROTO_ICMP;
172: so->so_state = SS_ISFCONNECTED;
1.1.1.3 root 173:
1.1 root 174: /* Send the packet */
175: addr.sin_family = AF_INET;
1.1.1.5 root 176: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
177: slirp->vnetwork_addr.s_addr) {
1.1 root 178: /* It's an alias */
1.1.1.5 root 179: if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
1.1.1.6 root 180: if (get_dns_addr(&addr.sin_addr) < 0)
181: addr.sin_addr = loopback_addr;
1.1.1.5 root 182: } else {
1.1 root 183: addr.sin_addr = loopback_addr;
184: }
185: } else {
186: addr.sin_addr = so->so_faddr;
187: }
188: addr.sin_port = so->so_fport;
189: if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
190: (struct sockaddr *)&addr, sizeof(addr)) == -1) {
191: DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
192: errno,strerror(errno)));
1.1.1.3 root 193: icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
1.1 root 194: udp_detach(so);
195: }
1.1.1.2 root 196: } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
1.1 root 197: break;
198: case ICMP_UNREACH:
199: /* XXX? report error? close socket? */
200: case ICMP_TIMXCEED:
201: case ICMP_PARAMPROB:
202: case ICMP_SOURCEQUENCH:
203: case ICMP_TSTAMP:
204: case ICMP_MASKREQ:
205: case ICMP_REDIRECT:
1.1.1.7 ! root 206: m_free(m);
1.1 root 207: break;
1.1.1.3 root 208:
1.1 root 209: default:
1.1.1.7 ! root 210: m_free(m);
1.1 root 211: } /* swith */
212:
213: end_error:
214: /* m is m_free()'d xor put in a socket xor or given to ip_send */
215: return;
216: }
217:
218:
219: /*
220: * Send an ICMP message in response to a situation
221: *
222: * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
223: * MUST NOT change this header information.
224: * MUST NOT reply to a multicast/broadcast IP address.
225: * MUST NOT reply to a multicast/broadcast MAC address.
226: * MUST reply to only the first fragment.
227: */
228: /*
229: * Send ICMP_UNREACH back to the source regarding msrc.
230: * mbuf *msrc is used as a template, but is NOT m_free()'d.
231: * It is reported as the bad ip packet. The header should
232: * be fully correct and in host byte order.
1.1.1.3 root 233: * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
1.1 root 234: * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
235: */
236:
237: #define ICMP_MAXDATALEN (IP_MSS-28)
238: void
1.1.1.4 root 239: icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
240: const char *message)
1.1 root 241: {
242: unsigned hlen, shlen, s_ip_len;
243: register struct ip *ip;
244: register struct icmp *icp;
245: register struct mbuf *m;
246:
247: DEBUG_CALL("icmp_error");
248: DEBUG_ARG("msrc = %lx", (long )msrc);
249: DEBUG_ARG("msrc_len = %d", msrc->m_len);
250:
251: if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
252:
253: /* check msrc */
254: if(!msrc) goto end_error;
255: ip = mtod(msrc, struct ip *);
1.1.1.4 root 256: #ifdef DEBUG
1.1 root 257: { char bufa[20], bufb[20];
258: strcpy(bufa, inet_ntoa(ip->ip_src));
259: strcpy(bufb, inet_ntoa(ip->ip_dst));
260: DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
261: }
262: #endif
263: if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */
264:
265: shlen=ip->ip_hl << 2;
266: s_ip_len=ip->ip_len;
267: if(ip->ip_p == IPPROTO_ICMP) {
268: icp = (struct icmp *)((char *)ip + shlen);
269: /*
270: * Assume any unknown ICMP type is an error. This isn't
271: * specified by the RFC, but think about it..
272: */
273: if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
274: }
275:
276: /* make a copy */
1.1.1.5 root 277: m = m_get(msrc->slirp);
278: if (!m) {
279: goto end_error;
280: }
281:
1.1 root 282: { int new_m_size;
283: new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
284: if(new_m_size>m->m_size) m_inc(m, new_m_size);
285: }
286: memcpy(m->m_data, msrc->m_data, msrc->m_len);
287: m->m_len = msrc->m_len; /* copy msrc to m */
288:
289: /* make the header of the reply packet */
290: ip = mtod(m, struct ip *);
291: hlen= sizeof(struct ip ); /* no options in reply */
1.1.1.3 root 292:
1.1 root 293: /* fill in icmp */
1.1.1.3 root 294: m->m_data += hlen;
1.1 root 295: m->m_len -= hlen;
296:
297: icp = mtod(m, struct icmp *);
298:
299: if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */
300: else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */
301: s_ip_len=ICMP_MAXDATALEN;
302:
1.1.1.3 root 303: m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */
1.1 root 304:
305: /* min. size = 8+sizeof(struct ip)+8 */
306:
307: icp->icmp_type = type;
308: icp->icmp_code = code;
309: icp->icmp_id = 0;
310: icp->icmp_seq = 0;
311:
312: memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
313: HTONS(icp->icmp_ip.ip_len);
314: HTONS(icp->icmp_ip.ip_id);
315: HTONS(icp->icmp_ip.ip_off);
316:
1.1.1.4 root 317: #ifdef DEBUG
1.1 root 318: if(message) { /* DEBUG : append message to ICMP packet */
319: int message_len;
320: char *cpnt;
321: message_len=strlen(message);
322: if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
323: cpnt=(char *)m->m_data+m->m_len;
324: memcpy(cpnt, message, message_len);
325: m->m_len+=message_len;
326: }
327: #endif
328:
329: icp->icmp_cksum = 0;
330: icp->icmp_cksum = cksum(m, m->m_len);
331:
332: m->m_data -= hlen;
333: m->m_len += hlen;
334:
335: /* fill in ip */
336: ip->ip_hl = hlen >> 2;
337: ip->ip_len = m->m_len;
1.1.1.3 root 338:
1.1 root 339: ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
340:
341: ip->ip_ttl = MAXTTL;
342: ip->ip_p = IPPROTO_ICMP;
343: ip->ip_dst = ip->ip_src; /* ip adresses */
1.1.1.5 root 344: ip->ip_src = m->slirp->vhost_addr;
1.1 root 345:
346: (void ) ip_output((struct socket *)NULL, m);
1.1.1.3 root 347:
1.1 root 348: end_error:
349: return;
350: }
351: #undef ICMP_MAXDATALEN
352:
353: /*
354: * Reflect the ip packet back to the source
355: */
356: void
1.1.1.5 root 357: icmp_reflect(struct mbuf *m)
1.1 root 358: {
359: register struct ip *ip = mtod(m, struct ip *);
360: int hlen = ip->ip_hl << 2;
361: int optlen = hlen - sizeof(struct ip );
362: register struct icmp *icp;
363:
364: /*
365: * Send an icmp packet back to the ip level,
366: * after supplying a checksum.
367: */
368: m->m_data += hlen;
369: m->m_len -= hlen;
370: icp = mtod(m, struct icmp *);
371:
1.1.1.7 ! root 372: icp->icmp_type = ICMP_ECHOREPLY;
1.1 root 373: icp->icmp_cksum = 0;
374: icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
375:
376: m->m_data -= hlen;
377: m->m_len += hlen;
378:
379: /* fill in ip */
380: if (optlen > 0) {
381: /*
382: * Strip out original options by copying rest of first
383: * mbuf's data back, and adjust the IP length.
384: */
385: memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen,
386: (unsigned )(m->m_len - hlen));
387: hlen -= optlen;
388: ip->ip_hl = hlen >> 2;
389: ip->ip_len -= optlen;
390: m->m_len -= optlen;
391: }
392:
393: ip->ip_ttl = MAXTTL;
394: { /* swap */
395: struct in_addr icmp_dst;
396: icmp_dst = ip->ip_dst;
397: ip->ip_dst = ip->ip_src;
398: ip->ip_src = icmp_dst;
399: }
400:
401: (void ) ip_output((struct socket *)NULL, m);
402: }
1.1.1.7 ! root 403:
! 404: void icmp_receive(struct socket *so)
! 405: {
! 406: struct mbuf *m = so->so_m;
! 407: struct ip *ip = mtod(m, struct ip *);
! 408: int hlen = ip->ip_hl << 2;
! 409: u_char error_code;
! 410: struct icmp *icp;
! 411: int id, len;
! 412:
! 413: m->m_data += hlen;
! 414: m->m_len -= hlen;
! 415: icp = mtod(m, struct icmp *);
! 416:
! 417: id = icp->icmp_id;
! 418: len = qemu_recv(so->s, icp, m->m_len, 0);
! 419: icp->icmp_id = id;
! 420:
! 421: m->m_data -= hlen;
! 422: m->m_len += hlen;
! 423:
! 424: if (len == -1 || len == 0) {
! 425: if (errno == ENETUNREACH) {
! 426: error_code = ICMP_UNREACH_NET;
! 427: } else {
! 428: error_code = ICMP_UNREACH_HOST;
! 429: }
! 430: DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno,
! 431: strerror(errno)));
! 432: icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
! 433: } else {
! 434: icmp_reflect(so->so_m);
! 435: so->so_m = NULL; /* Don't m_free() it again! */
! 436: }
! 437: icmp_detach(so);
! 438: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.