VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/ip_output.c@ 36965

Last change on this file since 36965 was 36965, checked in by vboxsync, 14 years ago

NAT: Attempt to fix (the rest of vbox/7711 and vbox/8701).
The reason of such corruption is aliasing of fragments, libalias
processing fragments diffenrently from first fragment,
it's set aliasing address to the source IP address. That insults
guest TCP/IP stack and it drops the rest of the fragments. In this
changeset we let chewing first packet, letting libalias apply its
modules changes if any and do not pass the rest of fragments, because
libalias can't recognize the fragments anyway.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: ip_output.c 36965 2011-05-05 03:03:22Z vboxsync $ */
2/** @file
3 * NAT - IP output.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * Copyright (c) 1982, 1986, 1988, 1990, 1993
22 * The Regents of the University of California. All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. All advertising materials mentioning features or use of this software
33 * must display the following acknowledgement:
34 * This product includes software developed by the University of
35 * California, Berkeley and its contributors.
36 * 4. Neither the name of the University nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
53 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
54 */
55
56/*
57 * Changes and additions relating to SLiRP are
58 * Copyright (c) 1995 Danny Gasparovski.
59 *
60 * Please read the file COPYRIGHT for the
61 * terms and conditions of the copyright.
62 */
63
64#include <slirp.h>
65#include "alias.h"
66
67static const uint8_t broadcast_ethaddr[6] =
68{
69 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
70};
71
72static int rt_lookup_in_cache(PNATState pData, uint32_t dst, uint8_t *ether)
73{
74 int rc;
75 if (dst == INADDR_BROADCAST)
76 {
77 memcpy(ether, broadcast_ethaddr, ETH_ALEN);
78 return VINF_SUCCESS;
79 }
80
81 rc = slirp_arp_lookup_ether_by_ip(pData, dst, ether);
82 if (RT_SUCCESS(rc))
83 return rc;
84
85 rc = bootp_cache_lookup_ether_by_ip(pData, dst, ether);
86 if (RT_SUCCESS(rc))
87 return rc;
88 /*
89 * no chance to send this packet, sorry, we will request ether address via ARP
90 */
91 slirp_arp_who_has(pData, dst);
92 return VERR_NOT_FOUND;
93}
94
95/*
96 * IP output. The packet in mbuf chain m contains a skeletal IP
97 * header (with len, off, ttl, proto, tos, src, dst).
98 * The mbuf chain containing the packet will be freed.
99 * The mbuf opt, if present, will not be freed.
100 */
101int
102ip_output(PNATState pData, struct socket *so, struct mbuf *m0)
103{
104 return ip_output0(pData, so, m0, 0);
105}
106
107/* This function will free m0! */
108int
109ip_output0(PNATState pData, struct socket *so, struct mbuf *m0, int urg)
110{
111 register struct ip *ip;
112 register struct mbuf *m = m0;
113 register int hlen = sizeof(struct ip);
114 int len, off, error = 0;
115 extern uint8_t zerro_ethaddr[ETH_ALEN];
116 struct ethhdr *eh = NULL;
117 uint8_t eth_dst[ETH_ALEN];
118 int rc = 1;
119
120 STAM_PROFILE_START(&pData->StatIP_output, a);
121
122 LogFlow(("ip_output: so = %lx, m0 = %lx\n", (long)so, (long)m0));
123
124 M_ASSERTPKTHDR(m);
125 Assert(m->m_pkthdr.header);
126
127#if 0 /* We do no options */
128 if (opt)
129 {
130 m = ip_insertoptions(m, opt, &len);
131 hlen = len;
132 }
133#endif
134 ip = mtod(m, struct ip *);
135 /*
136 * Fill in IP header.
137 */
138 ip->ip_v = IPVERSION;
139 ip->ip_off &= IP_DF;
140 ip->ip_id = RT_H2N_U16(ip_currid++);
141 ip->ip_hl = hlen >> 2;
142 ipstat.ips_localout++;
143
144 /* Current TCP/IP stack hasn't routing information at
145 * all so we need to calculate destination ethernet address
146 */
147 rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst);
148 if (RT_FAILURE(rc))
149 goto exit_drop_package;
150
151 eh = (struct ethhdr *)(m->m_data - ETH_HLEN);
152 /*
153 * If small enough for interface, can just send directly.
154 */
155 if ((u_int16_t)ip->ip_len <= if_mtu)
156 {
157 ip->ip_len = RT_H2N_U16((u_int16_t)ip->ip_len);
158 ip->ip_off = RT_H2N_U16((u_int16_t)ip->ip_off);
159 ip->ip_sum = 0;
160 ip->ip_sum = cksum(m, hlen);
161
162 {
163 struct m_tag *t;
164 STAM_PROFILE_START(&pData->StatALIAS_output, b);
165 if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0)
166 rc = LibAliasOut((struct libalias *)&t[1], mtod(m, char *),
167 m_length(m, NULL));
168 else
169 rc = LibAliasOut(pData->proxy_alias, mtod(m, char *),
170 m_length(m, NULL));
171
172 if (rc == PKT_ALIAS_IGNORED)
173 {
174 Log(("NAT: packet was droppped\n"));
175 goto exit_drop_package;
176 }
177 STAM_PROFILE_STOP(&pData->StatALIAS_output, b);
178 }
179
180 memcpy(eh->h_source, eth_dst, ETH_ALEN);
181
182 if_encap(pData, ETH_P_IP, m, urg? ETH_ENCAP_URG : 0);
183 goto done;
184 }
185
186 /*
187 * Too large for interface; fragment if possible.
188 * Must be able to put at least 8 bytes per fragment.
189 */
190 if (ip->ip_off & IP_DF)
191 {
192 error = -1;
193 ipstat.ips_cantfrag++;
194 goto exit_drop_package;
195 }
196
197 len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */
198 if (len < 8)
199 {
200 error = -1;
201 goto exit_drop_package;
202 }
203
204 {
205 int mhlen, firstlen = len;
206 struct mbuf **mnext = &m->m_nextpkt;
207 char *buf; /* intermediate buffer we'll use for a copy of the original packet */
208 /*
209 * Loop through length of segment after first fragment,
210 * make new header and copy data of each part and link onto chain.
211 */
212 m0 = m;
213 mhlen = ip->ip_hl << 2;
214 Log(("NAT:ip:frag: mhlen = %d\n", mhlen));
215 for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len)
216 {
217 register struct ip *mhip;
218 m = m_getjcl(pData, M_NOWAIT, MT_HEADER , M_PKTHDR, slirp_size(pData));
219 if (m == 0)
220 {
221 error = -1;
222 ipstat.ips_odropped++;
223 goto send_or_free;
224 }
225 m->m_data += if_maxlinkhdr;
226 mhip = mtod(m, struct ip *);
227 *mhip = *ip;
228 m->m_pkthdr.header = mtod(m, void *);
229 /* we've calculated eth_dst for first packet */
230#if 0 /* No options */
231 if (hlen > sizeof (struct ip))
232 {
233 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
234 mhip->ip_hl = mhlen >> 2;
235 }
236#endif
237 m->m_len = mhlen;
238 mhip->ip_off = ((off - mhlen) >> 3) + (ip->ip_off & ~IP_MF);
239 if (ip->ip_off & IP_MF)
240 mhip->ip_off |= IP_MF;
241 if (off + len >= (u_int16_t)ip->ip_len)
242 len = (u_int16_t)ip->ip_len - off;
243 else
244 mhip->ip_off |= IP_MF;
245 mhip->ip_len = RT_H2N_U16((u_int16_t)(len + mhlen));
246
247 buf = RTMemAlloc(len);
248 Log(("NAT:ip:frag: alloc = %d\n", len));
249 m_copydata(m0, off, len, buf); /* copy to buffer */
250 Log(("NAT:ip:frag: m_copydata(m0 = %p,off = %d, len = %d,)\n", m0, off, len));
251
252 m->m_data += mhlen;
253 m->m_len -= mhlen;
254 m_copyback(pData, m, 0, len, buf); /* copy from buffer */
255 Log(("NAT:ip:frag: m_copyback(m = %p,, len = %d,)\n", m, len));
256 m->m_data -= mhlen;
257 m->m_len += mhlen;
258 RTMemFree(buf);
259 Assert((m->m_len == (mhlen + len)));
260
261 mhip->ip_off = RT_H2N_U16((u_int16_t)(mhip->ip_off));
262 mhip->ip_sum = 0;
263 mhip->ip_sum = cksum(m, mhlen);
264 *mnext = m;
265 mnext = &m->m_nextpkt;
266 ipstat.ips_ofragments++;
267 }
268 /*
269 * Update first fragment by trimming what's been copied out
270 * and updating header, then send each fragment (in order).
271 *
272 * note: m_adj do all required releases for chained mbufs.
273 */
274 m = m0;
275 m_adj(m, mhlen + firstlen - (u_int16_t)ip->ip_len);
276 Log(("NAT:ip:frag: m_adj(m(m_len:%d) = %p, len = %d)\n", m->m_len, m, mhlen + firstlen - (u_int16_t)ip->ip_len));
277 ip->ip_len = RT_H2N_U16((u_int16_t)mhlen + firstlen);
278 ip->ip_off = RT_H2N_U16((u_int16_t)(ip->ip_off | IP_MF));
279 ip->ip_sum = 0;
280 ip->ip_sum = cksum(m, mhlen);
281
282send_or_free:
283 {
284 /* We're aliasing all fragments */
285 struct m_tag *t;
286 int rcLa;
287 if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0)
288 rcLa = LibAliasOut((struct libalias *)&t[1], mtod(m, char *), m->m_len);
289 else
290 rcLa = LibAliasOut(pData->proxy_alias, mtod(m, char *), m->m_len);
291
292 if (rcLa == PKT_ALIAS_IGNORED)
293 {
294 Log(("NAT: packet was droppped\n"));
295 goto exit_drop_package;
296 }
297 Log2(("NAT: LibAlias return %d\n", rcLa));
298 }
299 for (m = m0; m; m = m0)
300 {
301 m0 = m->m_nextpkt;
302 m->m_nextpkt = 0;
303 if (error == 0)
304 {
305 m->m_data -= ETH_HLEN;
306 eh = mtod(m, struct ethhdr *);
307 m->m_data += ETH_HLEN;
308 memcpy(eh->h_source, eth_dst, ETH_ALEN);
309
310 Log(("NAT:ip:frag: if_encap(,,m(m_len = %d) = %p,0)\n", m->m_len, m));
311 if_encap(pData, ETH_P_IP, m, 0);
312 }
313 else
314 m_freem(pData, m);
315 }
316
317 if (error == 0)
318 ipstat.ips_fragmented++;
319 }
320
321done:
322 STAM_PROFILE_STOP(&pData->StatIP_output, a);
323 return error;
324
325exit_drop_package:
326 m_freem(pData, m0);
327 STAM_PROFILE_STOP(&pData->StatIP_output, a);
328 return error;
329}
Note: See TracBrowser for help on using the repository browser.

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