VirtualBox

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

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

rtadvd_recv: declare optlen as int to avoid "unary minus operator
applied to unsigned type, result still unsigned".

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

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