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