VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/ip_icmp.c@ 1050

Last change on this file since 1050 was 1033, checked in by vboxsync, 18 years ago

Big change to make slirp fully instantiatable (replace all global
variables with local ones, passing a reference to the state/config
structure to all places which are interested). You can now have as many
cards in the guest configured for NAT networking as you want.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette