Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/ip6_icmp.c
2 views
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
* Copyright (c) 2013
4
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
5
*/
6
7
#include "slirp.h"
8
#include "ip6_icmp.h"
9
10
#define NDP_Interval \
11
g_rand_int_range(slirp->grand, NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
12
13
/* The message sent when emulating PING */
14
/* Be nice and tell them it's just a pseudo-ping packet */
15
static const char icmp6_ping_msg[] =
16
"This is a pseudo-PING packet used by Slirp to emulate ICMPV6 ECHO-REQUEST "
17
"packets.\n";
18
19
void icmp6_post_init(Slirp *slirp)
20
{
21
if (!slirp->in6_enabled) {
22
return;
23
}
24
25
slirp->ra_timer =
26
slirp_timer_new(slirp, SLIRP_TIMER_RA, NULL);
27
slirp->cb->timer_mod(slirp->ra_timer,
28
slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
29
NDP_Interval,
30
slirp->opaque);
31
}
32
33
void icmp6_cleanup(Slirp *slirp)
34
{
35
if (!slirp->in6_enabled) {
36
return;
37
}
38
39
slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
40
}
41
42
/* Send ICMP packet to the Internet, and save it to so_m */
43
static int icmp6_send(struct socket *so, struct mbuf *m, int hlen)
44
{
45
Slirp *slirp = m->slirp;
46
47
struct sockaddr_in6 addr;
48
49
/*
50
* The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
51
* between host OSes. On Linux, only the ICMP header and payload is
52
* included. On macOS/Darwin, the socket acts like a raw socket and
53
* includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
54
* sockets aren't supported at all, so we treat them like raw sockets. It
55
* isn't possible to detect this difference at runtime, so we must use an
56
* #ifdef to determine if we need to remove the IP header.
57
*/
58
#if defined(BSD) && !defined(__GNU__)
59
so->so_type = IPPROTO_IPV6;
60
#else
61
so->so_type = IPPROTO_ICMPV6;
62
#endif
63
64
so->s = slirp_socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
65
if (so->s == -1) {
66
if (errno == EAFNOSUPPORT
67
|| errno == EPROTONOSUPPORT
68
|| errno == EACCES) {
69
/* Kernel doesn't support or allow ping sockets. */
70
so->so_type = IPPROTO_IPV6;
71
so->s = slirp_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
72
}
73
}
74
if (so->s == -1) {
75
return -1;
76
}
77
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
78
79
if (slirp_bind_outbound(so, AF_INET6) != 0) {
80
// bind failed - close socket
81
closesocket(so->s);
82
so->s = -1;
83
return -1;
84
}
85
86
M_DUP_DEBUG(slirp, m, 0, 0);
87
struct ip6 *ip = mtod(m, struct ip6 *);
88
89
so->so_m = m;
90
so->so_faddr6 = ip->ip_dst;
91
so->so_laddr6 = ip->ip_src;
92
so->so_state = SS_ISFCONNECTED;
93
so->so_expire = curtime + SO_EXPIRE;
94
95
addr.sin6_family = AF_INET6;
96
addr.sin6_addr = so->so_faddr6;
97
98
slirp_insque(so, &so->slirp->icmp);
99
100
if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
101
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
102
DEBUG_MISC("icmp6_input icmp sendto tx errno = %d-%s", errno,
103
strerror(errno));
104
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
105
icmp_detach(so);
106
}
107
108
return 0;
109
}
110
111
static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
112
struct icmp6 *icmp)
113
{
114
struct mbuf *t = m_get(slirp);
115
t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
116
memcpy(t->m_data, m->m_data, t->m_len);
117
118
/* IPv6 Packet */
119
struct ip6 *rip = mtod(t, struct ip6 *);
120
rip->ip_dst = ip->ip_src;
121
rip->ip_src = ip->ip_dst;
122
123
/* ICMPv6 packet */
124
t->m_data += sizeof(struct ip6);
125
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
126
ricmp->icmp6_type = ICMP6_ECHO_REPLY;
127
ricmp->icmp6_cksum = 0;
128
129
/* Checksum */
130
t->m_data -= sizeof(struct ip6);
131
ricmp->icmp6_cksum = ip6_cksum(t);
132
133
ip6_output(NULL, t, 0);
134
}
135
136
void icmp6_forward_error(struct mbuf *m, uint8_t type, uint8_t code, struct in6_addr *src)
137
{
138
Slirp *slirp = m->slirp;
139
struct mbuf *t;
140
struct ip6 *ip = mtod(m, struct ip6 *);
141
char addrstr[INET6_ADDRSTRLEN];
142
143
DEBUG_CALL("icmp6_send_error");
144
DEBUG_ARG("type = %d, code = %d", type, code);
145
146
if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || in6_zero(&ip->ip_src)) {
147
/* TODO icmp error? */
148
return;
149
}
150
151
t = m_get(slirp);
152
153
/* IPv6 packet */
154
struct ip6 *rip = mtod(t, struct ip6 *);
155
rip->ip_src = *src;
156
rip->ip_dst = ip->ip_src;
157
inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
158
DEBUG_ARG("target = %s", addrstr);
159
160
rip->ip_nh = IPPROTO_ICMPV6;
161
const int error_data_len = MIN(
162
m->m_len, slirp->if_mtu - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
163
rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
164
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
165
166
/* ICMPv6 packet */
167
t->m_data += sizeof(struct ip6);
168
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
169
ricmp->icmp6_type = type;
170
ricmp->icmp6_code = code;
171
ricmp->icmp6_cksum = 0;
172
173
switch (type) {
174
case ICMP6_UNREACH:
175
case ICMP6_TIMXCEED:
176
ricmp->icmp6_err.unused = 0;
177
break;
178
case ICMP6_TOOBIG:
179
ricmp->icmp6_err.mtu = htonl(slirp->if_mtu);
180
break;
181
case ICMP6_PARAMPROB:
182
/* TODO: Handle this case */
183
break;
184
default:
185
g_assert_not_reached();
186
}
187
t->m_data += ICMP6_ERROR_MINLEN;
188
memcpy(t->m_data, m->m_data, error_data_len);
189
190
/* Checksum */
191
t->m_data -= ICMP6_ERROR_MINLEN;
192
t->m_data -= sizeof(struct ip6);
193
ricmp->icmp6_cksum = ip6_cksum(t);
194
195
ip6_output(NULL, t, 0);
196
}
197
198
void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
199
{
200
struct in6_addr src = LINKLOCAL_ADDR;
201
icmp6_forward_error(m, type, code, &src);
202
}
203
204
/*
205
* Reflect the ip packet back to the source
206
*/
207
void icmp6_reflect(struct mbuf *m)
208
{
209
register struct ip6 *ip = mtod(m, struct ip6 *);
210
int hlen = sizeof(struct ip6);
211
register struct icmp6 *icp;
212
213
/*
214
* Send an icmp packet back to the ip level,
215
* after supplying a checksum.
216
*/
217
m->m_data += hlen;
218
m->m_len -= hlen;
219
icp = mtod(m, struct icmp6 *);
220
221
icp->icmp6_type = ICMP6_ECHO_REPLY;
222
223
m->m_data -= hlen;
224
m->m_len += hlen;
225
226
icp->icmp6_cksum = 0;
227
icp->icmp6_cksum = ip6_cksum(m);
228
229
ip->ip_hl = MAXTTL;
230
{ /* swap */
231
struct in6_addr icmp_dst;
232
icmp_dst = ip->ip_dst;
233
ip->ip_dst = ip->ip_src;
234
ip->ip_src = icmp_dst;
235
}
236
237
ip6_output((struct socket *)NULL, m, 0);
238
}
239
240
void icmp6_receive(struct socket *so)
241
{
242
struct mbuf *m = so->so_m;
243
int hlen = sizeof(struct ip6);
244
uint8_t error_code;
245
struct icmp6 *icp;
246
int id, seq, len;
247
248
m->m_data += hlen;
249
m->m_len -= hlen;
250
icp = mtod(m, struct icmp6 *);
251
252
id = icp->icmp6_id;
253
seq = icp->icmp6_seq;
254
len = recv(so->s, icp, M_ROOM(m), 0);
255
256
icp->icmp6_id = id;
257
icp->icmp6_seq = seq;
258
259
m->m_data -= hlen;
260
m->m_len += hlen;
261
262
if (len == -1 || len == 0) {
263
if (errno == ENETUNREACH) {
264
error_code = ICMP6_UNREACH_NO_ROUTE;
265
} else {
266
error_code = ICMP6_UNREACH_ADDRESS;
267
}
268
DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno));
269
icmp6_send_error(so->so_m, ICMP_UNREACH, error_code);
270
} else {
271
icmp6_reflect(so->so_m);
272
so->so_m = NULL; /* Don't m_free() it again! */
273
}
274
icmp_detach(so);
275
}
276
277
/*
278
* Send NDP Router Advertisement
279
*/
280
static void ndp_send_ra(Slirp *slirp)
281
{
282
DEBUG_CALL("ndp_send_ra");
283
284
/* Build IPv6 packet */
285
struct mbuf *t = m_get(slirp);
286
struct ip6 *rip = mtod(t, struct ip6 *);
287
size_t pl_size = 0;
288
struct in6_addr addr;
289
uint32_t scope_id;
290
291
rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
292
rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
293
rip->ip_nh = IPPROTO_ICMPV6;
294
295
/* Build ICMPv6 packet */
296
t->m_data += sizeof(struct ip6);
297
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
298
ricmp->icmp6_type = ICMP6_NDP_RA;
299
ricmp->icmp6_code = 0;
300
ricmp->icmp6_cksum = 0;
301
302
/* NDP */
303
ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
304
ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
305
ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
306
ricmp->icmp6_nra.reserved = 0;
307
ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
308
ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
309
ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
310
t->m_data += ICMP6_NDP_RA_MINLEN;
311
pl_size += ICMP6_NDP_RA_MINLEN;
312
313
/* Source link-layer address (NDP option) */
314
struct ndpopt *opt = mtod(t, struct ndpopt *);
315
opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
316
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
317
in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
318
t->m_data += NDPOPT_LINKLAYER_LEN;
319
pl_size += NDPOPT_LINKLAYER_LEN;
320
321
/* Prefix information (NDP option) */
322
struct ndpopt *opt2 = mtod(t, struct ndpopt *);
323
opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
324
opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
325
opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
326
opt2->ndpopt_prefixinfo.L = 1;
327
opt2->ndpopt_prefixinfo.A = 1;
328
opt2->ndpopt_prefixinfo.reserved1 = 0;
329
opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
330
opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
331
opt2->ndpopt_prefixinfo.reserved2 = 0;
332
opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
333
t->m_data += NDPOPT_PREFIXINFO_LEN;
334
pl_size += NDPOPT_PREFIXINFO_LEN;
335
336
/* Prefix information (NDP option) */
337
if (get_dns6_addr(&addr, &scope_id) >= 0) {
338
/* Host system does have an IPv6 DNS server, announce our proxy. */
339
struct ndpopt *opt3 = mtod(t, struct ndpopt *);
340
opt3->ndpopt_type = NDPOPT_RDNSS;
341
opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
342
opt3->ndpopt_rdnss.reserved = 0;
343
opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
344
opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
345
t->m_data += NDPOPT_RDNSS_LEN;
346
pl_size += NDPOPT_RDNSS_LEN;
347
}
348
349
rip->ip_pl = htons(pl_size);
350
t->m_data -= sizeof(struct ip6) + pl_size;
351
t->m_len = sizeof(struct ip6) + pl_size;
352
353
/* ICMPv6 Checksum */
354
ricmp->icmp6_cksum = ip6_cksum(t);
355
356
ip6_output(NULL, t, 0);
357
}
358
359
void ra_timer_handler(Slirp *slirp, void *unused)
360
{
361
slirp->cb->timer_mod(slirp->ra_timer,
362
slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS +
363
NDP_Interval,
364
slirp->opaque);
365
ndp_send_ra(slirp);
366
}
367
368
/*
369
* Send NDP Neighbor Solitication
370
*/
371
void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
372
{
373
char addrstr[INET6_ADDRSTRLEN];
374
375
inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
376
377
DEBUG_CALL("ndp_send_ns");
378
DEBUG_ARG("target = %s", addrstr);
379
380
/* Build IPv6 packet */
381
struct mbuf *t = m_get(slirp);
382
struct ip6 *rip = mtod(t, struct ip6 *);
383
rip->ip_src = slirp->vhost_addr6;
384
rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
385
memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
386
rip->ip_nh = IPPROTO_ICMPV6;
387
rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
388
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
389
390
/* Build ICMPv6 packet */
391
t->m_data += sizeof(struct ip6);
392
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
393
ricmp->icmp6_type = ICMP6_NDP_NS;
394
ricmp->icmp6_code = 0;
395
ricmp->icmp6_cksum = 0;
396
397
/* NDP */
398
ricmp->icmp6_nns.reserved = 0;
399
ricmp->icmp6_nns.target = addr;
400
401
/* Build NDP option */
402
t->m_data += ICMP6_NDP_NS_MINLEN;
403
struct ndpopt *opt = mtod(t, struct ndpopt *);
404
opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
405
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
406
in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
407
408
/* ICMPv6 Checksum */
409
t->m_data -= ICMP6_NDP_NA_MINLEN;
410
t->m_data -= sizeof(struct ip6);
411
ricmp->icmp6_cksum = ip6_cksum(t);
412
413
ip6_output(NULL, t, 1);
414
}
415
416
/*
417
* Send NDP Neighbor Advertisement
418
*/
419
static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
420
{
421
/* Build IPv6 packet */
422
struct mbuf *t = m_get(slirp);
423
struct ip6 *rip = mtod(t, struct ip6 *);
424
rip->ip_src = icmp->icmp6_nns.target;
425
if (in6_zero(&ip->ip_src)) {
426
rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
427
} else {
428
rip->ip_dst = ip->ip_src;
429
}
430
rip->ip_nh = IPPROTO_ICMPV6;
431
rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN + NDPOPT_LINKLAYER_LEN);
432
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
433
434
/* Build ICMPv6 packet */
435
t->m_data += sizeof(struct ip6);
436
struct icmp6 *ricmp = mtod(t, struct icmp6 *);
437
ricmp->icmp6_type = ICMP6_NDP_NA;
438
ricmp->icmp6_code = 0;
439
ricmp->icmp6_cksum = 0;
440
441
/* NDP */
442
ricmp->icmp6_nna.R = NDP_IsRouter;
443
ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
444
ricmp->icmp6_nna.O = 1;
445
ricmp->icmp6_nna.reserved_1 = 0;
446
ricmp->icmp6_nna.reserved_2 = 0;
447
ricmp->icmp6_nna.reserved_3 = 0;
448
ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
449
450
/* Build NDP option */
451
t->m_data += ICMP6_NDP_NA_MINLEN;
452
struct ndpopt *opt = mtod(t, struct ndpopt *);
453
opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
454
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
455
in6_compute_ethaddr(ricmp->icmp6_nna.target, opt->ndpopt_linklayer);
456
457
/* ICMPv6 Checksum */
458
t->m_data -= ICMP6_NDP_NA_MINLEN;
459
t->m_data -= sizeof(struct ip6);
460
ricmp->icmp6_cksum = ip6_cksum(t);
461
462
ip6_output(NULL, t, 0);
463
}
464
465
/*
466
* Process a NDP message
467
*/
468
static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
469
struct icmp6 *icmp)
470
{
471
g_assert(M_ROOMBEFORE(m) >= ETH_HLEN);
472
473
m->m_len += ETH_HLEN;
474
m->m_data -= ETH_HLEN;
475
struct ethhdr *eth = mtod(m, struct ethhdr *);
476
m->m_len -= ETH_HLEN;
477
m->m_data += ETH_HLEN;
478
479
switch (icmp->icmp6_type) {
480
case ICMP6_NDP_RS:
481
DEBUG_CALL(" type = Router Solicitation");
482
if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
483
ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
484
/* Gratuitous NDP */
485
ndp_table_add(slirp, ip->ip_src, eth->h_source);
486
487
ndp_send_ra(slirp);
488
}
489
break;
490
491
case ICMP6_NDP_RA:
492
DEBUG_CALL(" type = Router Advertisement");
493
slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
494
slirp->opaque);
495
break;
496
497
case ICMP6_NDP_NS:
498
DEBUG_CALL(" type = Neighbor Solicitation");
499
if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
500
!IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target) &&
501
ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN &&
502
(!in6_zero(&ip->ip_src) ||
503
in6_solicitednode_multicast(&ip->ip_dst))) {
504
if (in6_equal_host(&icmp->icmp6_nns.target)) {
505
/* Gratuitous NDP */
506
ndp_table_add(slirp, ip->ip_src, eth->h_source);
507
ndp_send_na(slirp, ip, icmp);
508
}
509
}
510
break;
511
512
case ICMP6_NDP_NA:
513
DEBUG_CALL(" type = Neighbor Advertisement");
514
if (ip->ip_hl == 255 && icmp->icmp6_code == 0 &&
515
ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN &&
516
!IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target) &&
517
(!IN6_IS_ADDR_MULTICAST(&ip->ip_dst) || icmp->icmp6_nna.S == 0)) {
518
ndp_table_add(slirp, icmp->icmp6_nna.target, eth->h_source);
519
}
520
break;
521
522
case ICMP6_NDP_REDIRECT:
523
DEBUG_CALL(" type = Redirect");
524
slirp->cb->guest_error(
525
"Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
526
break;
527
}
528
}
529
530
/*
531
* Process a received ICMPv6 message.
532
*/
533
void icmp6_input(struct mbuf *m)
534
{
535
Slirp *slirp = m->slirp;
536
/* NDP reads the ethernet header for gratuitous NDP */
537
M_DUP_DEBUG(slirp, m, 1, ETH_HLEN);
538
539
struct icmp6 *icmp;
540
struct ip6 *ip = mtod(m, struct ip6 *);
541
int hlen = sizeof(struct ip6);
542
543
DEBUG_CALL("icmp6_input");
544
DEBUG_ARG("m = %p", m);
545
DEBUG_ARG("m_len = %d", m->m_len);
546
547
if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
548
freeit:
549
m_free(m);
550
goto end_error;
551
}
552
553
if (ip6_cksum(m)) {
554
goto freeit;
555
}
556
557
m->m_len -= hlen;
558
m->m_data += hlen;
559
icmp = mtod(m, struct icmp6 *);
560
m->m_len += hlen;
561
m->m_data -= hlen;
562
563
DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
564
switch (icmp->icmp6_type) {
565
case ICMP6_ECHO_REQUEST:
566
if (in6_equal_host(&ip->ip_dst)) {
567
icmp6_send_echoreply(m, slirp, ip, icmp);
568
} else if (slirp->restricted) {
569
goto freeit;
570
} else {
571
struct socket *so;
572
struct sockaddr_storage addr;
573
int ttl;
574
575
so = socreate(slirp, IPPROTO_ICMPV6);
576
if (icmp6_send(so, m, hlen) == 0) {
577
/* We could send this as ICMP, good! */
578
return;
579
}
580
581
/* We could not send this as ICMP, try to send it on UDP echo
582
* service (7), wishfully hoping that it is open there. */
583
584
if (udp_attach(so, AF_INET6) == -1) {
585
DEBUG_MISC("icmp6_input udp_attach errno = %d-%s", errno,
586
strerror(errno));
587
sofree(so);
588
m_free(m);
589
goto end_error;
590
}
591
so->so_m = m;
592
so->so_ffamily = AF_INET6;
593
so->so_faddr6 = ip->ip_dst;
594
so->so_fport = htons(7);
595
so->so_lfamily = AF_INET6;
596
so->so_laddr6 = ip->ip_src;
597
so->so_lport = htons(9);
598
so->so_state = SS_ISFCONNECTED;
599
600
/* Send the packet */
601
addr = so->fhost.ss;
602
if (sotranslate_out(so, &addr) < 0) {
603
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
604
udp_detach(so);
605
return;
606
}
607
608
/*
609
* Check for TTL
610
*/
611
ttl = ip->ip_hl-1;
612
if (ttl <= 0) {
613
DEBUG_MISC("udp ttl exceeded");
614
icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
615
udp_detach(so);
616
break;
617
}
618
setsockopt(so->s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
619
620
if (sendto(so->s, icmp6_ping_msg, strlen(icmp6_ping_msg), 0,
621
(struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
622
DEBUG_MISC("icmp6_input udp sendto tx errno = %d-%s", errno,
623
strerror(errno));
624
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
625
udp_detach(so);
626
}
627
} /* if (in6_equal_host(&ip->ip_dst)) */
628
break;
629
630
case ICMP6_NDP_RS:
631
case ICMP6_NDP_RA:
632
case ICMP6_NDP_NS:
633
case ICMP6_NDP_NA:
634
case ICMP6_NDP_REDIRECT:
635
ndp_input(m, slirp, ip, icmp);
636
m_free(m);
637
break;
638
639
case ICMP6_UNREACH:
640
case ICMP6_TOOBIG:
641
case ICMP6_TIMXCEED:
642
case ICMP6_PARAMPROB:
643
/* XXX? report error? close socket? */
644
default:
645
m_free(m);
646
break;
647
}
648
649
end_error:
650
/* m is m_free()'d xor put in a socket xor or given to ip_send */
651
return;
652
}
653
654