Annotation of qemu/slirp/ip_icmp.c, revision 1.1.1.6
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:
63: /*
64: * Process a received ICMP message.
65: */
66: void
1.1.1.5 root 67: icmp_input(struct mbuf *m, int hlen)
1.1 root 68: {
69: register struct icmp *icp;
70: register struct ip *ip=mtod(m, struct ip *);
71: int icmplen=ip->ip_len;
1.1.1.5 root 72: Slirp *slirp = m->slirp;
1.1.1.3 root 73:
1.1 root 74: DEBUG_CALL("icmp_input");
75: DEBUG_ARG("m = %lx", (long )m);
76: DEBUG_ARG("m_len = %d", m->m_len);
77:
78: /*
79: * Locate icmp structure in mbuf, and check
80: * that its not corrupted and of at least minimum length.
81: */
82: if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
83: freeit:
84: m_freem(m);
85: goto end_error;
86: }
87:
88: m->m_len -= hlen;
89: m->m_data += hlen;
90: icp = mtod(m, struct icmp *);
91: if (cksum(m, icmplen)) {
92: goto freeit;
93: }
94: m->m_len += hlen;
95: m->m_data -= hlen;
1.1.1.3 root 96:
1.1 root 97: DEBUG_ARG("icmp_type = %d", icp->icmp_type);
98: switch (icp->icmp_type) {
99: case ICMP_ECHO:
100: icp->icmp_type = ICMP_ECHOREPLY;
101: ip->ip_len += hlen; /* since ip_input subtracts this */
1.1.1.5 root 102: if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
1.1 root 103: icmp_reflect(m);
104: } else {
105: struct socket *so;
106: struct sockaddr_in addr;
1.1.1.5 root 107: if ((so = socreate(slirp)) == NULL) goto freeit;
1.1 root 108: if(udp_attach(so) == -1) {
1.1.1.3 root 109: DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
1.1 root 110: errno,strerror(errno)));
111: sofree(so);
112: m_free(m);
113: goto end_error;
114: }
115: so->so_m = m;
116: so->so_faddr = ip->ip_dst;
117: so->so_fport = htons(7);
118: so->so_laddr = ip->ip_src;
119: so->so_lport = htons(9);
120: so->so_iptos = ip->ip_tos;
121: so->so_type = IPPROTO_ICMP;
122: so->so_state = SS_ISFCONNECTED;
1.1.1.3 root 123:
1.1 root 124: /* Send the packet */
125: addr.sin_family = AF_INET;
1.1.1.5 root 126: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
127: slirp->vnetwork_addr.s_addr) {
1.1 root 128: /* It's an alias */
1.1.1.5 root 129: if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
1.1.1.6 ! root 130: if (get_dns_addr(&addr.sin_addr) < 0)
! 131: addr.sin_addr = loopback_addr;
1.1.1.5 root 132: } else {
1.1 root 133: addr.sin_addr = loopback_addr;
134: }
135: } else {
136: addr.sin_addr = so->so_faddr;
137: }
138: addr.sin_port = so->so_fport;
139: if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
140: (struct sockaddr *)&addr, sizeof(addr)) == -1) {
141: DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
142: errno,strerror(errno)));
1.1.1.3 root 143: icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
1.1 root 144: udp_detach(so);
145: }
1.1.1.2 root 146: } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
1.1 root 147: break;
148: case ICMP_UNREACH:
149: /* XXX? report error? close socket? */
150: case ICMP_TIMXCEED:
151: case ICMP_PARAMPROB:
152: case ICMP_SOURCEQUENCH:
153: case ICMP_TSTAMP:
154: case ICMP_MASKREQ:
155: case ICMP_REDIRECT:
156: m_freem(m);
157: break;
1.1.1.3 root 158:
1.1 root 159: default:
160: m_freem(m);
161: } /* swith */
162:
163: end_error:
164: /* m is m_free()'d xor put in a socket xor or given to ip_send */
165: return;
166: }
167:
168:
169: /*
170: * Send an ICMP message in response to a situation
171: *
172: * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
173: * MUST NOT change this header information.
174: * MUST NOT reply to a multicast/broadcast IP address.
175: * MUST NOT reply to a multicast/broadcast MAC address.
176: * MUST reply to only the first fragment.
177: */
178: /*
179: * Send ICMP_UNREACH back to the source regarding msrc.
180: * mbuf *msrc is used as a template, but is NOT m_free()'d.
181: * It is reported as the bad ip packet. The header should
182: * be fully correct and in host byte order.
1.1.1.3 root 183: * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
1.1 root 184: * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
185: */
186:
187: #define ICMP_MAXDATALEN (IP_MSS-28)
188: void
1.1.1.4 root 189: icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
190: const char *message)
1.1 root 191: {
192: unsigned hlen, shlen, s_ip_len;
193: register struct ip *ip;
194: register struct icmp *icp;
195: register struct mbuf *m;
196:
197: DEBUG_CALL("icmp_error");
198: DEBUG_ARG("msrc = %lx", (long )msrc);
199: DEBUG_ARG("msrc_len = %d", msrc->m_len);
200:
201: if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
202:
203: /* check msrc */
204: if(!msrc) goto end_error;
205: ip = mtod(msrc, struct ip *);
1.1.1.4 root 206: #ifdef DEBUG
1.1 root 207: { char bufa[20], bufb[20];
208: strcpy(bufa, inet_ntoa(ip->ip_src));
209: strcpy(bufb, inet_ntoa(ip->ip_dst));
210: DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
211: }
212: #endif
213: if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */
214:
215: shlen=ip->ip_hl << 2;
216: s_ip_len=ip->ip_len;
217: if(ip->ip_p == IPPROTO_ICMP) {
218: icp = (struct icmp *)((char *)ip + shlen);
219: /*
220: * Assume any unknown ICMP type is an error. This isn't
221: * specified by the RFC, but think about it..
222: */
223: if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
224: }
225:
226: /* make a copy */
1.1.1.5 root 227: m = m_get(msrc->slirp);
228: if (!m) {
229: goto end_error;
230: }
231:
1.1 root 232: { int new_m_size;
233: new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
234: if(new_m_size>m->m_size) m_inc(m, new_m_size);
235: }
236: memcpy(m->m_data, msrc->m_data, msrc->m_len);
237: m->m_len = msrc->m_len; /* copy msrc to m */
238:
239: /* make the header of the reply packet */
240: ip = mtod(m, struct ip *);
241: hlen= sizeof(struct ip ); /* no options in reply */
1.1.1.3 root 242:
1.1 root 243: /* fill in icmp */
1.1.1.3 root 244: m->m_data += hlen;
1.1 root 245: m->m_len -= hlen;
246:
247: icp = mtod(m, struct icmp *);
248:
249: if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */
250: else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */
251: s_ip_len=ICMP_MAXDATALEN;
252:
1.1.1.3 root 253: m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */
1.1 root 254:
255: /* min. size = 8+sizeof(struct ip)+8 */
256:
257: icp->icmp_type = type;
258: icp->icmp_code = code;
259: icp->icmp_id = 0;
260: icp->icmp_seq = 0;
261:
262: memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
263: HTONS(icp->icmp_ip.ip_len);
264: HTONS(icp->icmp_ip.ip_id);
265: HTONS(icp->icmp_ip.ip_off);
266:
1.1.1.4 root 267: #ifdef DEBUG
1.1 root 268: if(message) { /* DEBUG : append message to ICMP packet */
269: int message_len;
270: char *cpnt;
271: message_len=strlen(message);
272: if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
273: cpnt=(char *)m->m_data+m->m_len;
274: memcpy(cpnt, message, message_len);
275: m->m_len+=message_len;
276: }
277: #endif
278:
279: icp->icmp_cksum = 0;
280: icp->icmp_cksum = cksum(m, m->m_len);
281:
282: m->m_data -= hlen;
283: m->m_len += hlen;
284:
285: /* fill in ip */
286: ip->ip_hl = hlen >> 2;
287: ip->ip_len = m->m_len;
1.1.1.3 root 288:
1.1 root 289: ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
290:
291: ip->ip_ttl = MAXTTL;
292: ip->ip_p = IPPROTO_ICMP;
293: ip->ip_dst = ip->ip_src; /* ip adresses */
1.1.1.5 root 294: ip->ip_src = m->slirp->vhost_addr;
1.1 root 295:
296: (void ) ip_output((struct socket *)NULL, m);
1.1.1.3 root 297:
1.1 root 298: end_error:
299: return;
300: }
301: #undef ICMP_MAXDATALEN
302:
303: /*
304: * Reflect the ip packet back to the source
305: */
306: void
1.1.1.5 root 307: icmp_reflect(struct mbuf *m)
1.1 root 308: {
309: register struct ip *ip = mtod(m, struct ip *);
310: int hlen = ip->ip_hl << 2;
311: int optlen = hlen - sizeof(struct ip );
312: register struct icmp *icp;
313:
314: /*
315: * Send an icmp packet back to the ip level,
316: * after supplying a checksum.
317: */
318: m->m_data += hlen;
319: m->m_len -= hlen;
320: icp = mtod(m, struct icmp *);
321:
322: icp->icmp_cksum = 0;
323: icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
324:
325: m->m_data -= hlen;
326: m->m_len += hlen;
327:
328: /* fill in ip */
329: if (optlen > 0) {
330: /*
331: * Strip out original options by copying rest of first
332: * mbuf's data back, and adjust the IP length.
333: */
334: memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen,
335: (unsigned )(m->m_len - hlen));
336: hlen -= optlen;
337: ip->ip_hl = hlen >> 2;
338: ip->ip_len -= optlen;
339: m->m_len -= optlen;
340: }
341:
342: ip->ip_ttl = MAXTTL;
343: { /* swap */
344: struct in_addr icmp_dst;
345: icmp_dst = ip->ip_dst;
346: ip->ip_dst = ip->ip_src;
347: ip->ip_src = icmp_dst;
348: }
349:
350: (void ) ip_output((struct socket *)NULL, m);
351: }
unix.superglobalmegacorp.com