Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netinet6/ip6_forward.c
102986 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the project nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*
31
* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $
32
*/
33
34
#include "opt_inet.h"
35
#include "opt_inet6.h"
36
#include "opt_ipsec.h"
37
#include "opt_ipstealth.h"
38
#include "opt_sctp.h"
39
40
#include <sys/param.h>
41
#include <sys/systm.h>
42
#include <sys/malloc.h>
43
#include <sys/mbuf.h>
44
#include <sys/domain.h>
45
#include <sys/protosw.h>
46
#include <sys/socket.h>
47
#include <sys/errno.h>
48
#include <sys/time.h>
49
#include <sys/kernel.h>
50
#include <sys/syslog.h>
51
52
#include <net/if.h>
53
#include <net/if_var.h>
54
#include <net/if_private.h>
55
#include <net/netisr.h>
56
#include <net/route.h>
57
#include <net/route/nhop.h>
58
#include <net/pfil.h>
59
60
#include <netinet/in.h>
61
#include <netinet/in_var.h>
62
#include <netinet/in_systm.h>
63
#include <netinet/ip.h>
64
#include <netinet/ip_var.h>
65
#include <netinet6/in6_var.h>
66
#include <netinet/ip6.h>
67
#include <netinet6/in6_fib.h>
68
#include <netinet6/ip6_var.h>
69
#include <netinet6/scope6_var.h>
70
#include <netinet/icmp6.h>
71
#include <netinet6/nd6.h>
72
73
#include <netinet/in_pcb.h>
74
75
#include <netipsec/ipsec_support.h>
76
77
#if defined(SCTP) || defined(SCTP_SUPPORT)
78
#include <netinet/sctp_crc32.h>
79
#endif
80
81
/*
82
* Forward a packet. If some error occurs return the sender
83
* an icmp packet. Note we can't always generate a meaningful
84
* icmp message because icmp doesn't have a large enough repertoire
85
* of codes and types.
86
*
87
* If not forwarding, just drop the packet. This could be confusing
88
* if ipforwarding was zero but some routing protocol was advancing
89
* us as a gateway to somewhere. However, we must let the routing
90
* protocol deal with that.
91
*
92
*/
93
void
94
ip6_forward(struct mbuf *m, int srcrt)
95
{
96
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
97
struct sockaddr_in6 dst;
98
struct nhop_object *nh = NULL;
99
int error, type = 0, code = 0;
100
struct mbuf *mcopy = NULL;
101
struct ifnet *origifp; /* maybe unnecessary */
102
u_int32_t inzone, outzone;
103
struct in6_addr odst;
104
struct m_tag *fwd_tag;
105
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
106
107
/*
108
* Do not forward packets to multicast destination (should be handled
109
* by ip6_mforward().
110
* Do not forward packets with unspecified source. It was discussed
111
* in July 2000, on the ipngwg mailing list.
112
*/
113
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
114
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
115
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) ||
116
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {
117
IP6STAT_INC(ip6s_cantforward);
118
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
119
if (V_ip6_log_cannot_forward && ip6_log_ratelimit()) {
120
log(LOG_DEBUG,
121
"cannot forward "
122
"from %s to %s nxt %d received on %s\n",
123
ip6_sprintf(ip6bufs, &ip6->ip6_src),
124
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
125
ip6->ip6_nxt,
126
if_name(m->m_pkthdr.rcvif));
127
}
128
m_freem(m);
129
return;
130
}
131
132
if (
133
#ifdef IPSTEALTH
134
V_ip6stealth == 0 &&
135
#endif
136
ip6->ip6_hlim <= IPV6_HLIMDEC) {
137
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
138
icmp6_error(m, ICMP6_TIME_EXCEEDED,
139
ICMP6_TIME_EXCEED_TRANSIT, 0);
140
return;
141
}
142
143
/*
144
* Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
145
* size of IPv6 + ICMPv6 headers) bytes of the packet in case
146
* we need to generate an ICMP6 message to the src.
147
* Thanks to M_EXT, in most cases copy will not occur.
148
*
149
* It is important to save it before IPsec processing as IPsec
150
* processing may modify the mbuf.
151
*/
152
mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
153
M_NOWAIT);
154
#ifdef IPSTEALTH
155
if (V_ip6stealth == 0)
156
#endif
157
ip6->ip6_hlim -= IPV6_HLIMDEC;
158
159
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
160
if (IPSEC_ENABLED(ipv6)) {
161
if ((error = IPSEC_FORWARD(ipv6, m)) != 0) {
162
/* mbuf consumed by IPsec */
163
m_freem(mcopy);
164
if (error != EINPROGRESS)
165
IP6STAT_INC(ip6s_cantforward);
166
return;
167
}
168
/* No IPsec processing required */
169
}
170
#endif
171
/*
172
* ip6_forward() operates with IPv6 addresses with deembedded scope.
173
*
174
* There are 3 sources of IPv6 destination address:
175
*
176
* 1) ip6_input(), where ip6_dst contains deembedded address.
177
* In order to deal with forwarding of link-local packets,
178
* calculate the scope based on input interface (RFC 4007, clause 9).
179
* 2) packet filters changing ip6_dst directly. It would embed scope
180
* for LL addresses, so in6_localip() performs properly.
181
* 3) packet filters attaching PACKET_TAG_IPFORWARD would embed
182
* scope for the nexthop.
183
*/
184
bzero(&dst, sizeof(struct sockaddr_in6));
185
dst.sin6_family = AF_INET6;
186
dst.sin6_addr = ip6->ip6_dst;
187
dst.sin6_scope_id = in6_get_unicast_scopeid(&ip6->ip6_dst, m->m_pkthdr.rcvif);
188
again:
189
nh = fib6_lookup(M_GETFIB(m), &dst.sin6_addr, dst.sin6_scope_id,
190
NHR_REF, m->m_pkthdr.flowid);
191
if (nh == NULL) {
192
IP6STAT_INC(ip6s_noroute);
193
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
194
if (mcopy) {
195
icmp6_error(mcopy, ICMP6_DST_UNREACH,
196
ICMP6_DST_UNREACH_NOROUTE, 0);
197
}
198
goto bad;
199
}
200
201
if (nh->nh_flags & (NHF_BLACKHOLE | NHF_REJECT)) {
202
IP6STAT_INC(ip6s_cantforward);
203
if (mcopy != NULL) {
204
if (nh->nh_flags & NHF_REJECT) {
205
icmp6_error(mcopy, ICMP6_DST_UNREACH,
206
ICMP6_DST_UNREACH_REJECT, 0);
207
} else
208
m_freem(mcopy);
209
}
210
goto bad;
211
}
212
213
/*
214
* Source scope check: if a packet can't be delivered to its
215
* destination for the reason that the destination is beyond the scope
216
* of the source address, discard the packet and return an icmp6
217
* destination unreachable error with Code 2 (beyond scope of source
218
* address).
219
* [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1]
220
*/
221
outzone = in6_get_unicast_scopeid(&ip6->ip6_src, nh->nh_ifp);
222
inzone = in6_get_unicast_scopeid(&ip6->ip6_src, m->m_pkthdr.rcvif);
223
if (inzone != outzone) {
224
IP6STAT_INC(ip6s_cantforward);
225
IP6STAT_INC(ip6s_badscope);
226
in6_ifstat_inc(nh->nh_ifp, ifs6_in_discard);
227
228
if (V_ip6_log_cannot_forward && ip6_log_ratelimit()) {
229
log(LOG_DEBUG,
230
"cannot forward "
231
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
232
ip6_sprintf(ip6bufs, &ip6->ip6_src),
233
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
234
ip6->ip6_nxt,
235
if_name(m->m_pkthdr.rcvif), if_name(nh->nh_ifp));
236
}
237
if (mcopy)
238
icmp6_error(mcopy, ICMP6_DST_UNREACH,
239
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
240
goto bad;
241
}
242
243
/*
244
* Destination scope check: if a packet is going to break the scope
245
* zone of packet's destination address, discard it. This case should
246
* usually be prevented by appropriately-configured routing table, but
247
* we need an explicit check because we may mistakenly forward the
248
* packet to a different zone by (e.g.) a default route.
249
*/
250
inzone = in6_get_unicast_scopeid(&ip6->ip6_dst, m->m_pkthdr.rcvif);
251
outzone = in6_get_unicast_scopeid(&ip6->ip6_dst, nh->nh_ifp);
252
253
if (inzone != outzone) {
254
IP6STAT_INC(ip6s_cantforward);
255
IP6STAT_INC(ip6s_badscope);
256
goto bad;
257
}
258
259
if (nh->nh_flags & NHF_GATEWAY) {
260
/* Store gateway address in deembedded form */
261
dst.sin6_addr = nh->gw6_sa.sin6_addr;
262
dst.sin6_scope_id = ntohs(in6_getscope(&dst.sin6_addr));
263
in6_clearscope(&dst.sin6_addr);
264
}
265
266
/*
267
* If we are to forward the packet using the same interface
268
* as one we got the packet from, perhaps we should send a redirect
269
* to sender to shortcut a hop.
270
* Only send redirect if source is sending directly to us,
271
* and if packet was not source routed (or has any options).
272
* Also, don't send redirect if forwarding using a route
273
* modified by a redirect.
274
*/
275
if (V_ip6_sendredirects && nh->nh_ifp == m->m_pkthdr.rcvif && !srcrt &&
276
(nh->nh_flags & NHF_REDIRECT) == 0)
277
type = ND_REDIRECT;
278
279
/*
280
* Fake scoped addresses. Note that even link-local source or
281
* destinaion can appear, if the originating node just sends the
282
* packet to us (without address resolution for the destination).
283
* Since both icmp6_error and icmp6_redirect_output fill the embedded
284
* link identifiers, we can do this stuff after making a copy for
285
* returning an error.
286
*/
287
if ((nh->nh_ifp->if_flags & IFF_LOOPBACK) != 0) {
288
/*
289
* See corresponding comments in ip6_output.
290
* XXX: but is it possible that ip6_forward() sends a packet
291
* to a loopback interface? I don't think so, and thus
292
* I bark here. ([email protected])
293
* XXX: it is common to route invalid packets to loopback.
294
* also, the codepath will be visited on use of ::1 in
295
* rthdr. (itojun)
296
*/
297
#if 1
298
if (0)
299
#else
300
if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
301
#endif
302
{
303
printf("ip6_forward: outgoing interface is loopback. "
304
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
305
ip6_sprintf(ip6bufs, &ip6->ip6_src),
306
ip6_sprintf(ip6bufd, &ip6->ip6_dst),
307
ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
308
if_name(nh->nh_ifp));
309
}
310
311
/* we can just use rcvif in forwarding. */
312
origifp = m->m_pkthdr.rcvif;
313
}
314
else
315
origifp = nh->nh_ifp;
316
/*
317
* clear embedded scope identifiers if necessary.
318
* in6_clearscope will touch the addresses only when necessary.
319
*/
320
in6_clearscope(&ip6->ip6_src);
321
in6_clearscope(&ip6->ip6_dst);
322
323
/* Jump over all PFIL processing if hooks are not active. */
324
if (!PFIL_HOOKED_OUT(V_inet6_pfil_head))
325
goto pass;
326
327
odst = ip6->ip6_dst;
328
/* Run through list of hooks for forwarded packets. */
329
if (pfil_mbuf_fwd(V_inet6_pfil_head, &m, nh->nh_ifp,
330
NULL) != PFIL_PASS)
331
goto freecopy;
332
ip6 = mtod(m, struct ip6_hdr *);
333
334
/* See if destination IP address was changed by packet filter. */
335
if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
336
m->m_flags |= M_SKIP_FIREWALL;
337
/* If destination is now ourself drop to ip6_input(). */
338
if (in6_localip(&ip6->ip6_dst))
339
m->m_flags |= M_FASTFWD_OURS;
340
else {
341
NH_FREE(nh);
342
343
/* Update address and scopeid. Assume scope is embedded */
344
dst.sin6_scope_id = ntohs(in6_getscope(&ip6->ip6_dst));
345
dst.sin6_addr = ip6->ip6_dst;
346
in6_clearscope(&dst.sin6_addr);
347
goto again; /* Redo the routing table lookup. */
348
}
349
}
350
351
/* See if local, if yes, send it to netisr. */
352
if (m->m_flags & M_FASTFWD_OURS) {
353
if (m->m_pkthdr.rcvif == NULL)
354
m->m_pkthdr.rcvif = V_loif;
355
if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
356
m->m_pkthdr.csum_flags |=
357
CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;
358
m->m_pkthdr.csum_data = 0xffff;
359
}
360
#if defined(SCTP) || defined(SCTP_SUPPORT)
361
if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)
362
m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
363
#endif
364
error = netisr_queue(NETISR_IPV6, m);
365
goto out;
366
}
367
/* Or forward to some other address? */
368
if ((m->m_flags & M_IP6_NEXTHOP) &&
369
(fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
370
struct sockaddr_in6 *gw6 = (struct sockaddr_in6 *)(fwd_tag + 1);
371
372
/* Update address and scopeid. Assume scope is embedded */
373
dst.sin6_scope_id = ntohs(in6_getscope(&gw6->sin6_addr));
374
dst.sin6_addr = gw6->sin6_addr;
375
in6_clearscope(&dst.sin6_addr);
376
377
m->m_flags |= M_SKIP_FIREWALL;
378
m->m_flags &= ~M_IP6_NEXTHOP;
379
m_tag_delete(m, fwd_tag);
380
NH_FREE(nh);
381
goto again;
382
}
383
384
pass:
385
/* See if the size was changed by the packet filter. */
386
/* TODO: change to nh->nh_mtu */
387
if (m->m_pkthdr.len > in6_ifmtu(nh->nh_ifp)) {
388
in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig);
389
if (mcopy)
390
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,
391
in6_ifmtu(nh->nh_ifp));
392
goto bad;
393
}
394
395
/*
396
* If TCP/UDP header still needs a valid checksum and interface will not
397
* calculate it for us, do it here.
398
*/
399
if (__predict_false(m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 &
400
~nh->nh_ifp->if_hwassist)) {
401
int offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, NULL);
402
403
if (offset < sizeof(struct ip6_hdr) || offset > m->m_pkthdr.len)
404
goto bad;
405
in6_delayed_cksum(m, m->m_pkthdr.len - offset, offset);
406
m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
407
}
408
#if defined(SCTP) || defined(SCTP_SUPPORT)
409
if (__predict_false(m->m_pkthdr.csum_flags & CSUM_IP6_SCTP &
410
~nh->nh_ifp->if_hwassist)) {
411
int offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, NULL);
412
413
sctp_delayed_cksum(m, offset);
414
m->m_pkthdr.csum_flags &= ~CSUM_IP6_SCTP;
415
}
416
#endif
417
418
/* Currently LLE layer stores embedded IPv6 addresses */
419
if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) {
420
in6_set_unicast_scopeid(&dst.sin6_addr, dst.sin6_scope_id);
421
dst.sin6_scope_id = 0;
422
}
423
error = nd6_output_ifp(nh->nh_ifp, origifp, m, &dst, NULL);
424
if (error) {
425
in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard);
426
IP6STAT_INC(ip6s_cantforward);
427
} else {
428
IP6STAT_INC(ip6s_forward);
429
in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward);
430
if (type)
431
IP6STAT_INC(ip6s_redirectsent);
432
else {
433
if (mcopy)
434
goto freecopy;
435
}
436
}
437
438
if (mcopy == NULL)
439
goto out;
440
switch (error) {
441
case 0:
442
if (type == ND_REDIRECT) {
443
icmp6_redirect_output(mcopy, nh);
444
goto out;
445
}
446
goto freecopy;
447
448
case EMSGSIZE:
449
/* xxx MTU is constant in PPP? */
450
goto freecopy;
451
452
case ENOBUFS:
453
/* Tell source to slow down like source quench in IP? */
454
goto freecopy;
455
456
case ENETUNREACH: /* shouldn't happen, checked above */
457
case EHOSTUNREACH:
458
case ENETDOWN:
459
case EHOSTDOWN:
460
default:
461
type = ICMP6_DST_UNREACH;
462
code = ICMP6_DST_UNREACH_ADDR;
463
break;
464
}
465
icmp6_error(mcopy, type, code, 0);
466
goto out;
467
468
freecopy:
469
m_freem(mcopy);
470
goto out;
471
bad:
472
m_freem(m);
473
out:
474
if (nh != NULL)
475
NH_FREE(nh);
476
}
477
478