|
|
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 root 130: addr.sin_addr = dns_addr;
1.1.1.5 ! root 131: } else {
1.1 root 132: addr.sin_addr = loopback_addr;
133: }
134: } else {
135: addr.sin_addr = so->so_faddr;
136: }
137: addr.sin_port = so->so_fport;
138: if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
139: (struct sockaddr *)&addr, sizeof(addr)) == -1) {
140: DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
141: errno,strerror(errno)));
1.1.1.3 root 142: icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
1.1 root 143: udp_detach(so);
144: }
1.1.1.2 root 145: } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
1.1 root 146: break;
147: case ICMP_UNREACH:
148: /* XXX? report error? close socket? */
149: case ICMP_TIMXCEED:
150: case ICMP_PARAMPROB:
151: case ICMP_SOURCEQUENCH:
152: case ICMP_TSTAMP:
153: case ICMP_MASKREQ:
154: case ICMP_REDIRECT:
155: m_freem(m);
156: break;
1.1.1.3 root 157:
1.1 root 158: default:
159: m_freem(m);
160: } /* swith */
161:
162: end_error:
163: /* m is m_free()'d xor put in a socket xor or given to ip_send */
164: return;
165: }
166:
167:
168: /*
169: * Send an ICMP message in response to a situation
170: *
171: * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
172: * MUST NOT change this header information.
173: * MUST NOT reply to a multicast/broadcast IP address.
174: * MUST NOT reply to a multicast/broadcast MAC address.
175: * MUST reply to only the first fragment.
176: */
177: /*
178: * Send ICMP_UNREACH back to the source regarding msrc.
179: * mbuf *msrc is used as a template, but is NOT m_free()'d.
180: * It is reported as the bad ip packet. The header should
181: * be fully correct and in host byte order.
1.1.1.3 root 182: * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
1.1 root 183: * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
184: */
185:
186: #define ICMP_MAXDATALEN (IP_MSS-28)
187: void
1.1.1.4 root 188: icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
189: const char *message)
1.1 root 190: {
191: unsigned hlen, shlen, s_ip_len;
192: register struct ip *ip;
193: register struct icmp *icp;
194: register struct mbuf *m;
195:
196: DEBUG_CALL("icmp_error");
197: DEBUG_ARG("msrc = %lx", (long )msrc);
198: DEBUG_ARG("msrc_len = %d", msrc->m_len);
199:
200: if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
201:
202: /* check msrc */
203: if(!msrc) goto end_error;
204: ip = mtod(msrc, struct ip *);
1.1.1.4 root 205: #ifdef DEBUG
1.1 root 206: { char bufa[20], bufb[20];
207: strcpy(bufa, inet_ntoa(ip->ip_src));
208: strcpy(bufb, inet_ntoa(ip->ip_dst));
209: DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
210: }
211: #endif
212: if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */
213:
214: shlen=ip->ip_hl << 2;
215: s_ip_len=ip->ip_len;
216: if(ip->ip_p == IPPROTO_ICMP) {
217: icp = (struct icmp *)((char *)ip + shlen);
218: /*
219: * Assume any unknown ICMP type is an error. This isn't
220: * specified by the RFC, but think about it..
221: */
222: if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
223: }
224:
225: /* make a copy */
1.1.1.5 ! root 226: m = m_get(msrc->slirp);
! 227: if (!m) {
! 228: goto end_error;
! 229: }
! 230:
1.1 root 231: { int new_m_size;
232: new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
233: if(new_m_size>m->m_size) m_inc(m, new_m_size);
234: }
235: memcpy(m->m_data, msrc->m_data, msrc->m_len);
236: m->m_len = msrc->m_len; /* copy msrc to m */
237:
238: /* make the header of the reply packet */
239: ip = mtod(m, struct ip *);
240: hlen= sizeof(struct ip ); /* no options in reply */
1.1.1.3 root 241:
1.1 root 242: /* fill in icmp */
1.1.1.3 root 243: m->m_data += hlen;
1.1 root 244: m->m_len -= hlen;
245:
246: icp = mtod(m, struct icmp *);
247:
248: if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */
249: else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */
250: s_ip_len=ICMP_MAXDATALEN;
251:
1.1.1.3 root 252: m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */
1.1 root 253:
254: /* min. size = 8+sizeof(struct ip)+8 */
255:
256: icp->icmp_type = type;
257: icp->icmp_code = code;
258: icp->icmp_id = 0;
259: icp->icmp_seq = 0;
260:
261: memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
262: HTONS(icp->icmp_ip.ip_len);
263: HTONS(icp->icmp_ip.ip_id);
264: HTONS(icp->icmp_ip.ip_off);
265:
1.1.1.4 root 266: #ifdef DEBUG
1.1 root 267: if(message) { /* DEBUG : append message to ICMP packet */
268: int message_len;
269: char *cpnt;
270: message_len=strlen(message);
271: if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
272: cpnt=(char *)m->m_data+m->m_len;
273: memcpy(cpnt, message, message_len);
274: m->m_len+=message_len;
275: }
276: #endif
277:
278: icp->icmp_cksum = 0;
279: icp->icmp_cksum = cksum(m, m->m_len);
280:
281: m->m_data -= hlen;
282: m->m_len += hlen;
283:
284: /* fill in ip */
285: ip->ip_hl = hlen >> 2;
286: ip->ip_len = m->m_len;
1.1.1.3 root 287:
1.1 root 288: ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
289:
290: ip->ip_ttl = MAXTTL;
291: ip->ip_p = IPPROTO_ICMP;
292: ip->ip_dst = ip->ip_src; /* ip adresses */
1.1.1.5 ! root 293: ip->ip_src = m->slirp->vhost_addr;
1.1 root 294:
295: (void ) ip_output((struct socket *)NULL, m);
1.1.1.3 root 296:
1.1 root 297: end_error:
298: return;
299: }
300: #undef ICMP_MAXDATALEN
301:
302: /*
303: * Reflect the ip packet back to the source
304: */
305: void
1.1.1.5 ! root 306: icmp_reflect(struct mbuf *m)
1.1 root 307: {
308: register struct ip *ip = mtod(m, struct ip *);
309: int hlen = ip->ip_hl << 2;
310: int optlen = hlen - sizeof(struct ip );
311: register struct icmp *icp;
312:
313: /*
314: * Send an icmp packet back to the ip level,
315: * after supplying a checksum.
316: */
317: m->m_data += hlen;
318: m->m_len -= hlen;
319: icp = mtod(m, struct icmp *);
320:
321: icp->icmp_cksum = 0;
322: icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
323:
324: m->m_data -= hlen;
325: m->m_len += hlen;
326:
327: /* fill in ip */
328: if (optlen > 0) {
329: /*
330: * Strip out original options by copying rest of first
331: * mbuf's data back, and adjust the IP length.
332: */
333: memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen,
334: (unsigned )(m->m_len - hlen));
335: hlen -= optlen;
336: ip->ip_hl = hlen >> 2;
337: ip->ip_len -= optlen;
338: m->m_len -= optlen;
339: }
340:
341: ip->ip_ttl = MAXTTL;
342: { /* swap */
343: struct in_addr icmp_dst;
344: icmp_dst = ip->ip_dst;
345: ip->ip_dst = ip->ip_src;
346: ip->ip_src = icmp_dst;
347: }
348:
349: (void ) ip_output((struct socket *)NULL, m);
350: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.