VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/proxy_rtadvd.c@ 48576

最後變更 在這個檔案從48576是 48338,由 vboxsync 提交於 11 年 前

Disable stateless DHCPv6 server for now. It only tells guests the
nameserver IPv6 address, but HostDnsService doesn't support IPv6
nameserver addresses yet. Do not set "O" (other configuration) flag
in router advertisements, accordingly. This should avoid confusion
for the beta.

Add "TODO" comments in DHCPv6 server code where the nameserver address
should be picked up - it currently has leftover testing kludge, that
advertised mapped host loopback as IPv6 nameserver (with a
corresponding hack to remap IPv6 to IPv4 in pxudp.c that has been
disabled since).

  • 屬性 svn:eol-style 設為 native
檔案大小: 10.5 KB
 
1/* -*- indent-tabs-mode: nil; -*- */
2#include "winutils.h"
3
4#include "proxytest.h"
5
6#include "lwip/opt.h"
7#include "lwip/sys.h"
8#include "lwip/stats.h"
9#include "lwip/timers.h"
10
11#include "lwip/inet_chksum.h"
12#include "lwip/icmp6.h"
13#include "lwip/nd6.h"
14
15#include "lwip/raw.h"
16
17#include <string.h>
18
19
20static void proxy_rtadvd_timer(void *);
21static void proxy_rtadvd_send_multicast(struct netif *);
22static void proxy_rtadvd_fill_payload(struct netif *, int);
23
24static u8_t rtadvd_recv(void *, struct raw_pcb *, struct pbuf *, ip6_addr_t *);
25
26
27/* ff02::1 - link-local all nodes multicast address */
28static ip6_addr_t allnodes_linklocal = {
29 { PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x00000001UL) }
30};
31
32
33/*
34 * Unsolicited Router Advertisement payload.
35 *
36 * NB: Since ICMP checksum covers pseudo-header with destination
37 * address (link-local allnodes multicast in this case) this payload
38 * cannot be used for solicited replies to unicast addresses.
39 */
40static unsigned int unsolicited_ra_payload_length;
41static u8_t unsolicited_ra_payload[
42 sizeof(struct ra_header)
43 /* reserves enough space for NETIF_MAX_HWADDR_LEN */
44 + sizeof(struct lladdr_option)
45 /* we only announce one prefix */
46 + sizeof(struct prefix_option) * 1
47];
48
49
50static int ndefaults = 0;
51
52static struct raw_pcb *rtadvd_pcb;
53
54
55void
56proxy_rtadvd_start(struct netif *proxy_netif)
57{
58
59 ndefaults = rtmon_get_defaults();
60 if (ndefaults < 0) {
61 DPRINTF0(("rtadvd: failed to read IPv6 routing table, aborting\n"));
62 return;
63 }
64
65 proxy_rtadvd_fill_payload(proxy_netif, ndefaults > 0);
66
67 rtadvd_pcb = raw_new_ip6(IP6_NEXTH_ICMP6);
68 if (rtadvd_pcb == NULL) {
69 DPRINTF0(("rtadvd: failed to allocate pcb, aborting\n"));
70 return;
71 }
72
73 /*
74 * We cannot use raw_bind_ip6() since raw_input() doesn't grok
75 * multicasts. We are going to use ip6_output_if() directly.
76 */
77 raw_recv_ip6(rtadvd_pcb, rtadvd_recv, proxy_netif);
78
79 sys_timeout(3 * 1000, proxy_rtadvd_timer, proxy_netif);
80}
81
82
83static int quick_ras = 2;
84
85static void
86proxy_rtadvd_timer(void *arg)
87{
88 struct netif *proxy_netif = (struct netif *)arg;
89 int newdefs;
90 u32_t delay;
91
92 newdefs = rtmon_get_defaults();
93 if (newdefs != ndefaults && newdefs != -1) {
94 ndefaults = newdefs;
95 proxy_rtadvd_fill_payload(proxy_netif, ndefaults > 0);
96 }
97
98 proxy_rtadvd_send_multicast(proxy_netif);
99
100 if (quick_ras > 0) {
101 --quick_ras;
102 delay = 16 * 1000;
103 }
104 else {
105 delay = 600 * 1000;
106 }
107
108 sys_timeout(delay, proxy_rtadvd_timer, proxy_netif);
109}
110
111
112/*
113 * This should be folded into icmp6/nd6 input, but I don't want to
114 * solve this in general, making it configurable, etc.
115 *
116 * Cf. RFC 4861:
117 * 6.1.1. Validation of Router Solicitation Messages
118 */
119static u8_t
120rtadvd_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip6_addr_t *addr)
121{
122 enum raw_recv_status { RAW_RECV_CONTINUE = 0, RAW_RECV_CONSUMED = 1 };
123
124 struct netif *proxy_netif = (struct netif *)arg;
125 struct ip6_hdr *ip6_hdr;
126 struct icmp6_hdr *icmp6_hdr;
127 struct lladdr_option *lladdr_opt;
128 void *option;
129 u8_t opttype, optlen8;
130
131 LWIP_UNUSED_ARG(pcb);
132 LWIP_UNUSED_ARG(addr);
133
134 /* save a pointer to IP6 header and skip to ICMP6 payload */
135 ip6_hdr = (struct ip6_hdr *)p->payload;
136 pbuf_header(p, -ip_current_header_tot_len());
137
138 if (p->len < sizeof(struct icmp6_hdr)) {
139 ICMP6_STATS_INC(icmp6.lenerr);
140 goto drop;
141 }
142
143 if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len,
144 ip6_current_src_addr(),
145 ip6_current_dest_addr()) != 0)
146 {
147 ICMP6_STATS_INC(icmp6.chkerr);
148 goto drop;
149 }
150
151 icmp6_hdr = (struct icmp6_hdr *)p->payload;
152 if (icmp6_hdr->type != ICMP6_TYPE_RS) {
153 pbuf_header(p, ip_current_header_tot_len()); /* restore payload ptr */
154 return RAW_RECV_CONTINUE; /* not interested */
155 }
156
157 /* only now that we know it's ICMP6_TYPE_RS we can check IP6 hop limit */
158 if (IP6H_HOPLIM(ip6_hdr) != 255) {
159 ICMP6_STATS_INC(icmp6.proterr);
160 goto drop;
161 }
162
163 /* future, backward-incompatible changes may use different Code values. */
164 if (icmp6_hdr->code != 0) {
165 ICMP6_STATS_INC(icmp6.proterr);
166 goto drop;
167 }
168
169 /* skip past rs_header, nothing interesting in it */
170 if (p->len < sizeof(struct rs_header)) {
171 ICMP6_STATS_INC(icmp6.lenerr);
172 goto drop;
173 }
174 pbuf_header(p, -(s16_t)sizeof(struct rs_header));
175
176 lladdr_opt = NULL;
177 while (p->len > 0) {
178 unsigned int optlen;
179
180 if (p->len < 8) {
181 ICMP6_STATS_INC(icmp6.lenerr);
182 goto drop;
183 }
184
185 option = p->payload;
186 opttype = ((u8_t *)option)[0];
187 optlen8 = ((u8_t *)option)[1]; /* in units of 8 octets */
188
189 if (optlen8 == 0) {
190 ICMP6_STATS_INC(icmp6.proterr);
191 goto drop;
192 }
193
194 optlen = (unsigned int)optlen8 << 3;
195 if (p->len < optlen) {
196 ICMP6_STATS_INC(icmp6.lenerr);
197 goto drop;
198 }
199
200 if (opttype == ND6_OPTION_TYPE_SOURCE_LLADDR) {
201 if (lladdr_opt != NULL) { /* duplicate */
202 ICMP6_STATS_INC(icmp6.proterr);
203 goto drop;
204 }
205 lladdr_opt = (struct lladdr_option *)option;
206 }
207
208 pbuf_header(p, -optlen);
209 }
210
211 if (ip6_addr_isany(ip6_current_src_addr())) {
212 if (lladdr_opt != NULL) {
213 ICMP6_STATS_INC(icmp6.proterr);
214 goto drop;
215 }
216
217 /* reply with multicast RA */
218 }
219 else {
220 /*
221 * XXX: Router is supposed to update its Neighbor Cache (6.2.6),
222 * but it's hidden inside nd6.c.
223 */
224
225 /* may reply with either unicast or multicast RA */
226 }
227 /* we just always reply with multicast RA */
228
229 pbuf_free(p); /* NB: this invalidates lladdr_option */
230
231 sys_untimeout(proxy_rtadvd_timer, proxy_netif);
232 proxy_rtadvd_timer(proxy_netif); /* sends and re-arms */
233
234 return RAW_RECV_CONSUMED;
235
236 drop:
237 pbuf_free(p);
238 ICMP6_STATS_INC(icmp6.drop);
239 return RAW_RECV_CONSUMED;
240}
241
242
243static void
244proxy_rtadvd_send_multicast(struct netif *proxy_netif)
245{
246 struct pbuf *ph, *pp;
247 err_t error;
248
249 ph = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
250 if (ph == NULL) {
251 DPRINTF0(("%s: failed to allocate RA header pbuf", __func__));
252 return;
253 }
254
255 pp = pbuf_alloc(PBUF_RAW, unsolicited_ra_payload_length, PBUF_ROM);
256 if (pp == NULL) {
257 DPRINTF0(("%s: failed to allocate RA payload pbuf", __func__));
258 pbuf_free(ph);
259 return;
260 }
261 pp->payload = unsolicited_ra_payload;
262 pbuf_chain(ph, pp);
263
264 error = ip6_output_if(ph,
265 netif_ip6_addr(proxy_netif, 0), /* src: link-local */
266 &allnodes_linklocal, /* dst */
267 255, /* hop limit */
268 0, /* traffic class */
269 IP6_NEXTH_ICMP6,
270 proxy_netif);
271 if (error != ERR_OK) {
272 DPRINTF0(("%s: failed to send RA (err=%d)", __func__, error));
273 }
274
275 pbuf_free(pp);
276 pbuf_free(ph);
277}
278
279
280/*
281 * XXX: TODO: Only ra_header::router_lifetime (and hence
282 * ra_header::chksum) need to be changed, so we can precompute it once
283 * and then only update these two fields.
284 */
285static void
286proxy_rtadvd_fill_payload(struct netif *proxy_netif, int is_default)
287{
288 struct pbuf *p;
289 struct ra_header *ra_hdr;
290 struct lladdr_option *lladdr_opt;
291 struct prefix_option *pfx_opt;
292 unsigned int lladdr_optlen;
293
294 LWIP_ASSERT("netif hwaddr too long",
295 proxy_netif->hwaddr_len <= NETIF_MAX_HWADDR_LEN);
296
297 /* type + length + ll addr + round up to 8 octets */
298 lladdr_optlen = (2 + proxy_netif->hwaddr_len + 7) & ~0x7;
299
300 /* actual payload length */
301 unsolicited_ra_payload_length =
302 sizeof(struct ra_header)
303 + lladdr_optlen
304 + sizeof(struct prefix_option) * 1;
305
306 /* Set fields. */
307 ra_hdr = (struct ra_header *)unsolicited_ra_payload;
308 lladdr_opt = (struct lladdr_option *)((u8_t *)ra_hdr + sizeof(struct ra_header));
309 pfx_opt = (struct prefix_option *)((u8_t *)lladdr_opt + lladdr_optlen);
310
311 memset(unsolicited_ra_payload, 0, sizeof(unsolicited_ra_payload));
312
313 ra_hdr->type = ICMP6_TYPE_RA;
314
315#if 0
316 /*
317 * "M" flag. Tell guests to use stateful DHCP6. Disabled here
318 * since we don't provide stateful server.
319 */
320 ra_hdr->flags |= ND6_RA_FLAG_MANAGED_ADDR_CONFIG;
321#endif
322 /*
323 * XXX: TODO: Disable "O" flag for now to match disabled stateless
324 * server. We don't yet get IPv6 nameserver addresses from
325 * HostDnsService, so we have nothing to say, don't tell guests to
326 * come asking.
327 */
328#if 0
329 /*
330 * "O" flag. Tell guests to use DHCP6 for DNS and the like. This
331 * is served by simple stateless server (RFC 3736).
332 *
333 * XXX: "STATEFUL" in the flag name was probably a bug in RFC2461.
334 * It's present in the text, but not in the router configuration
335 * variable name. It's dropped in the text in RFC4861.
336 */
337 ra_hdr->flags |= ND6_RA_FLAG_OTHER_STATEFUL_CONFIG;
338#endif
339
340 if (is_default) {
341 ra_hdr->router_lifetime = PP_HTONS(1200); /* seconds */
342 }
343 else {
344 ra_hdr->router_lifetime = 0;
345 }
346
347 lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR;
348 lladdr_opt->length = lladdr_optlen >> 3; /* in units of 8 octets */
349 memcpy(lladdr_opt->addr, proxy_netif->hwaddr, proxy_netif->hwaddr_len);
350
351 pfx_opt->type = ND6_OPTION_TYPE_PREFIX_INFO;
352 pfx_opt->length = 4;
353 pfx_opt->prefix_length = 64;
354 pfx_opt->flags = ND6_PREFIX_FLAG_ON_LINK
355 | ND6_PREFIX_FLAG_AUTONOMOUS;
356 pfx_opt->valid_lifetime = ~0U; /* infinite */
357 pfx_opt->preferred_lifetime = ~0U; /* infinite */
358 pfx_opt->prefix.addr[0] = netif_ip6_addr(proxy_netif, 1)->addr[0];
359 pfx_opt->prefix.addr[1] = netif_ip6_addr(proxy_netif, 1)->addr[1];
360
361
362 /* we need a temp pbuf to calculate the checksum */
363 p = pbuf_alloc(PBUF_IP, unsolicited_ra_payload_length, PBUF_ROM);
364 if (p == NULL) {
365 DPRINTF0(("rtadvd: failed to allocate RA pbuf\n"));
366 return;
367 }
368 p->payload = unsolicited_ra_payload;
369
370 ra_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
371 /* src addr: netif's link-local */
372 netif_ip6_addr(proxy_netif, 0),
373 /* dst addr */
374 &allnodes_linklocal);
375 pbuf_free(p);
376}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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