|
|
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.