]> git.proxmox.com Git - mirror_qemu.git/blob - slirp/ip6_icmp.c
slirp: introduce SLIRP_DEBUG environment variable
[mirror_qemu.git] / slirp / ip6_icmp.c
1 /*
2 * Copyright (c) 2013
3 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
4 */
5
6 #include "qemu/osdep.h"
7 #include "slirp.h"
8 #include "ip6_icmp.h"
9 #include "qemu/timer.h"
10 #include "qemu/error-report.h"
11 #include "qemu/log.h"
12
13 #define NDP_Interval g_rand_int_range(slirp->grand, \
14 NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
15
16 static void ra_timer_handler(void *opaque)
17 {
18 Slirp *slirp = opaque;
19 timer_mod(slirp->ra_timer,
20 qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
21 ndp_send_ra(slirp);
22 }
23
24 void icmp6_init(Slirp *slirp)
25 {
26 if (!slirp->in6_enabled) {
27 return;
28 }
29
30 slirp->ra_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
31 SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
32 ra_timer_handler, slirp);
33 timer_mod(slirp->ra_timer,
34 qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
35 }
36
37 void icmp6_cleanup(Slirp *slirp)
38 {
39 if (!slirp->in6_enabled) {
40 return;
41 }
42
43 timer_del(slirp->ra_timer);
44 timer_free(slirp->ra_timer);
45 }
46
47 static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
48 struct icmp6 *icmp)
49 {
50 struct mbuf *t = m_get(slirp);
51 t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
52 memcpy(t->m_data, m->m_data, t->m_len);
53
54 /* IPv6 Packet */
55 struct ip6 *rip = mtod(t, struct ip6 *);
56 rip->ip_dst = ip->ip_src;
57 rip->ip_src = ip->ip_dst;
58
59 /* ICMPv6 packet */
60 t->m_data += sizeof(struct ip6);
61 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
62 ricmp->icmp6_type = ICMP6_ECHO_REPLY;
63 ricmp->icmp6_cksum = 0;
64
65 /* Checksum */
66 t->m_data -= sizeof(struct ip6);
67 ricmp->icmp6_cksum = ip6_cksum(t);
68
69 ip6_output(NULL, t, 0);
70 }
71
72 void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
73 {
74 Slirp *slirp = m->slirp;
75 struct mbuf *t;
76 struct ip6 *ip = mtod(m, struct ip6 *);
77 char addrstr[INET6_ADDRSTRLEN];
78
79 DEBUG_CALL("icmp6_send_error");
80 DEBUG_ARGS(" type = %d, code = %d\n", type, code);
81
82 if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) ||
83 in6_zero(&ip->ip_src)) {
84 /* TODO icmp error? */
85 return;
86 }
87
88 t = m_get(slirp);
89
90 /* IPv6 packet */
91 struct ip6 *rip = mtod(t, struct ip6 *);
92 rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
93 rip->ip_dst = ip->ip_src;
94 inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
95 DEBUG_ARG("target = %s", addrstr);
96
97 rip->ip_nh = IPPROTO_ICMPV6;
98 const int error_data_len = MIN(m->m_len,
99 IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
100 rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
101 t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
102
103 /* ICMPv6 packet */
104 t->m_data += sizeof(struct ip6);
105 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
106 ricmp->icmp6_type = type;
107 ricmp->icmp6_code = code;
108 ricmp->icmp6_cksum = 0;
109
110 switch (type) {
111 case ICMP6_UNREACH:
112 case ICMP6_TIMXCEED:
113 ricmp->icmp6_err.unused = 0;
114 break;
115 case ICMP6_TOOBIG:
116 ricmp->icmp6_err.mtu = htonl(IF_MTU);
117 break;
118 case ICMP6_PARAMPROB:
119 /* TODO: Handle this case */
120 break;
121 default:
122 g_assert_not_reached();
123 break;
124 }
125 t->m_data += ICMP6_ERROR_MINLEN;
126 memcpy(t->m_data, m->m_data, error_data_len);
127
128 /* Checksum */
129 t->m_data -= ICMP6_ERROR_MINLEN;
130 t->m_data -= sizeof(struct ip6);
131 ricmp->icmp6_cksum = ip6_cksum(t);
132
133 ip6_output(NULL, t, 0);
134 }
135
136 /*
137 * Send NDP Router Advertisement
138 */
139 void ndp_send_ra(Slirp *slirp)
140 {
141 DEBUG_CALL("ndp_send_ra");
142
143 /* Build IPv6 packet */
144 struct mbuf *t = m_get(slirp);
145 struct ip6 *rip = mtod(t, struct ip6 *);
146 size_t pl_size = 0;
147 struct in6_addr addr;
148 uint32_t scope_id;
149
150 rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
151 rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
152 rip->ip_nh = IPPROTO_ICMPV6;
153
154 /* Build ICMPv6 packet */
155 t->m_data += sizeof(struct ip6);
156 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
157 ricmp->icmp6_type = ICMP6_NDP_RA;
158 ricmp->icmp6_code = 0;
159 ricmp->icmp6_cksum = 0;
160
161 /* NDP */
162 ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
163 ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
164 ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
165 ricmp->icmp6_nra.reserved = 0;
166 ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
167 ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
168 ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
169 t->m_data += ICMP6_NDP_RA_MINLEN;
170 pl_size += ICMP6_NDP_RA_MINLEN;
171
172 /* Source link-layer address (NDP option) */
173 struct ndpopt *opt = mtod(t, struct ndpopt *);
174 opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
175 opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
176 in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
177 t->m_data += NDPOPT_LINKLAYER_LEN;
178 pl_size += NDPOPT_LINKLAYER_LEN;
179
180 /* Prefix information (NDP option) */
181 struct ndpopt *opt2 = mtod(t, struct ndpopt *);
182 opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
183 opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
184 opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
185 opt2->ndpopt_prefixinfo.L = 1;
186 opt2->ndpopt_prefixinfo.A = 1;
187 opt2->ndpopt_prefixinfo.reserved1 = 0;
188 opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
189 opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
190 opt2->ndpopt_prefixinfo.reserved2 = 0;
191 opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
192 t->m_data += NDPOPT_PREFIXINFO_LEN;
193 pl_size += NDPOPT_PREFIXINFO_LEN;
194
195 /* Prefix information (NDP option) */
196 if (get_dns6_addr(&addr, &scope_id) >= 0) {
197 /* Host system does have an IPv6 DNS server, announce our proxy. */
198 struct ndpopt *opt3 = mtod(t, struct ndpopt *);
199 opt3->ndpopt_type = NDPOPT_RDNSS;
200 opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
201 opt3->ndpopt_rdnss.reserved = 0;
202 opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
203 opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
204 t->m_data += NDPOPT_RDNSS_LEN;
205 pl_size += NDPOPT_RDNSS_LEN;
206 }
207
208 rip->ip_pl = htons(pl_size);
209 t->m_data -= sizeof(struct ip6) + pl_size;
210 t->m_len = sizeof(struct ip6) + pl_size;
211
212 /* ICMPv6 Checksum */
213 ricmp->icmp6_cksum = ip6_cksum(t);
214
215 ip6_output(NULL, t, 0);
216 }
217
218 /*
219 * Send NDP Neighbor Solitication
220 */
221 void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
222 {
223 char addrstr[INET6_ADDRSTRLEN];
224
225 inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
226
227 DEBUG_CALL("ndp_send_ns");
228 DEBUG_ARG("target = %s", addrstr);
229
230 /* Build IPv6 packet */
231 struct mbuf *t = m_get(slirp);
232 struct ip6 *rip = mtod(t, struct ip6 *);
233 rip->ip_src = slirp->vhost_addr6;
234 rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
235 memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
236 rip->ip_nh = IPPROTO_ICMPV6;
237 rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
238 t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
239
240 /* Build ICMPv6 packet */
241 t->m_data += sizeof(struct ip6);
242 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
243 ricmp->icmp6_type = ICMP6_NDP_NS;
244 ricmp->icmp6_code = 0;
245 ricmp->icmp6_cksum = 0;
246
247 /* NDP */
248 ricmp->icmp6_nns.reserved = 0;
249 ricmp->icmp6_nns.target = addr;
250
251 /* Build NDP option */
252 t->m_data += ICMP6_NDP_NS_MINLEN;
253 struct ndpopt *opt = mtod(t, struct ndpopt *);
254 opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
255 opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
256 in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
257
258 /* ICMPv6 Checksum */
259 t->m_data -= ICMP6_NDP_NA_MINLEN;
260 t->m_data -= sizeof(struct ip6);
261 ricmp->icmp6_cksum = ip6_cksum(t);
262
263 ip6_output(NULL, t, 1);
264 }
265
266 /*
267 * Send NDP Neighbor Advertisement
268 */
269 static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
270 {
271 /* Build IPv6 packet */
272 struct mbuf *t = m_get(slirp);
273 struct ip6 *rip = mtod(t, struct ip6 *);
274 rip->ip_src = icmp->icmp6_nns.target;
275 if (in6_zero(&ip->ip_src)) {
276 rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
277 } else {
278 rip->ip_dst = ip->ip_src;
279 }
280 rip->ip_nh = IPPROTO_ICMPV6;
281 rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
282 + NDPOPT_LINKLAYER_LEN);
283 t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
284
285 /* Build ICMPv6 packet */
286 t->m_data += sizeof(struct ip6);
287 struct icmp6 *ricmp = mtod(t, struct icmp6 *);
288 ricmp->icmp6_type = ICMP6_NDP_NA;
289 ricmp->icmp6_code = 0;
290 ricmp->icmp6_cksum = 0;
291
292 /* NDP */
293 ricmp->icmp6_nna.R = NDP_IsRouter;
294 ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
295 ricmp->icmp6_nna.O = 1;
296 ricmp->icmp6_nna.reserved_hi = 0;
297 ricmp->icmp6_nna.reserved_lo = 0;
298 ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
299
300 /* Build NDP option */
301 t->m_data += ICMP6_NDP_NA_MINLEN;
302 struct ndpopt *opt = mtod(t, struct ndpopt *);
303 opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
304 opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
305 in6_compute_ethaddr(ricmp->icmp6_nna.target,
306 opt->ndpopt_linklayer);
307
308 /* ICMPv6 Checksum */
309 t->m_data -= ICMP6_NDP_NA_MINLEN;
310 t->m_data -= sizeof(struct ip6);
311 ricmp->icmp6_cksum = ip6_cksum(t);
312
313 ip6_output(NULL, t, 0);
314 }
315
316 /*
317 * Process a NDP message
318 */
319 static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
320 struct icmp6 *icmp)
321 {
322 m->m_len += ETH_HLEN;
323 m->m_data -= ETH_HLEN;
324 struct ethhdr *eth = mtod(m, struct ethhdr *);
325 m->m_len -= ETH_HLEN;
326 m->m_data += ETH_HLEN;
327
328 switch (icmp->icmp6_type) {
329 case ICMP6_NDP_RS:
330 DEBUG_CALL(" type = Router Solicitation");
331 if (ip->ip_hl == 255
332 && icmp->icmp6_code == 0
333 && ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
334 /* Gratuitous NDP */
335 ndp_table_add(slirp, ip->ip_src, eth->h_source);
336
337 ndp_send_ra(slirp);
338 }
339 break;
340
341 case ICMP6_NDP_RA:
342 DEBUG_CALL(" type = Router Advertisement");
343 slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't");
344 break;
345
346 case ICMP6_NDP_NS:
347 DEBUG_CALL(" type = Neighbor Solicitation");
348 if (ip->ip_hl == 255
349 && icmp->icmp6_code == 0
350 && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target)
351 && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
352 && (!in6_zero(&ip->ip_src)
353 || in6_solicitednode_multicast(&ip->ip_dst))) {
354 if (in6_equal_host(&icmp->icmp6_nns.target)) {
355 /* Gratuitous NDP */
356 ndp_table_add(slirp, ip->ip_src, eth->h_source);
357 ndp_send_na(slirp, ip, icmp);
358 }
359 }
360 break;
361
362 case ICMP6_NDP_NA:
363 DEBUG_CALL(" type = Neighbor Advertisement");
364 if (ip->ip_hl == 255
365 && icmp->icmp6_code == 0
366 && ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN
367 && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target)
368 && (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst)
369 || icmp->icmp6_nna.S == 0)) {
370 ndp_table_add(slirp, ip->ip_src, eth->h_source);
371 }
372 break;
373
374 case ICMP6_NDP_REDIRECT:
375 DEBUG_CALL(" type = Redirect");
376 slirp->cb->guest_error(
377 "Warning: guest sent NDP REDIRECT, but shouldn't");
378 break;
379 }
380 }
381
382 /*
383 * Process a received ICMPv6 message.
384 */
385 void icmp6_input(struct mbuf *m)
386 {
387 struct icmp6 *icmp;
388 struct ip6 *ip = mtod(m, struct ip6 *);
389 Slirp *slirp = m->slirp;
390 int hlen = sizeof(struct ip6);
391
392 DEBUG_CALL("icmp6_input");
393 DEBUG_ARG("m = %lx", (long) m);
394 DEBUG_ARG("m_len = %d", m->m_len);
395
396 if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
397 goto end;
398 }
399
400 if (ip6_cksum(m)) {
401 goto end;
402 }
403
404 m->m_len -= hlen;
405 m->m_data += hlen;
406 icmp = mtod(m, struct icmp6 *);
407 m->m_len += hlen;
408 m->m_data -= hlen;
409
410 DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
411 switch (icmp->icmp6_type) {
412 case ICMP6_ECHO_REQUEST:
413 if (in6_equal_host(&ip->ip_dst)) {
414 icmp6_send_echoreply(m, slirp, ip, icmp);
415 } else {
416 /* TODO */
417 g_critical("external icmpv6 not supported yet");
418 }
419 break;
420
421 case ICMP6_NDP_RS:
422 case ICMP6_NDP_RA:
423 case ICMP6_NDP_NS:
424 case ICMP6_NDP_NA:
425 case ICMP6_NDP_REDIRECT:
426 ndp_input(m, slirp, ip, icmp);
427 break;
428
429 case ICMP6_UNREACH:
430 case ICMP6_TOOBIG:
431 case ICMP6_TIMXCEED:
432 case ICMP6_PARAMPROB:
433 /* XXX? report error? close socket? */
434 default:
435 break;
436 }
437
438 end:
439 m_free(m);
440 }