]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ip6_forward.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_forward.c
CommitLineData
b0d623f7 1/*
39236c6e 2 * Copyright (c) 2009-2013 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
55e303ae 29/* $FreeBSD: src/sys/netinet6/ip6_forward.c,v 1.16 2002/10/16 02:25:05 sam Exp $ */
9bccf70c 30/* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */
1c79356b
A
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
1c79356b
A
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/malloc.h>
65#include <sys/mbuf.h>
66#include <sys/domain.h>
67#include <sys/protosw.h>
68#include <sys/socket.h>
69#include <sys/errno.h>
70#include <sys/time.h>
71#include <sys/kernel.h>
72#include <sys/syslog.h>
73
74#include <net/if.h>
75#include <net/route.h>
76
77#include <netinet/in.h>
78#include <netinet/in_var.h>
9bccf70c
A
79#include <netinet/in_systm.h>
80#include <netinet/ip.h>
1c79356b 81#include <netinet/ip_var.h>
9bccf70c 82#include <netinet6/in6_var.h>
1c79356b
A
83#include <netinet/ip6.h>
84#include <netinet6/ip6_var.h>
85#include <netinet/icmp6.h>
86#include <netinet6/nd6.h>
6d2010ae 87#include <netinet6/scope6_var.h>
1c79356b 88
9bccf70c
A
89#include <netinet/in_pcb.h>
90
91#if IPSEC
1c79356b 92#include <netinet6/ipsec.h>
9bccf70c
A
93#if INET6
94#include <netinet6/ipsec6.h>
95#endif
1c79356b 96#include <netkey/key.h>
9bccf70c
A
97extern int ipsec_bypass;
98#endif /* IPSEC */
1c79356b 99
1c79356b 100#include <netinet6/ip6_fw.h>
1c79356b
A
101
102#include <net/net_osdep.h>
103
b0d623f7
A
104#if PF
105#include <net/pfvar.h>
106#endif /* PF */
107
1c79356b
A
108/*
109 * Forward a packet. If some error occurs return the sender
110 * an icmp packet. Note we can't always generate a meaningful
111 * icmp message because icmp doesn't have a large enough repertoire
112 * of codes and types.
113 *
114 * If not forwarding, just drop the packet. This could be confusing
115 * if ipforwarding was zero but some routing protocol was advancing
116 * us as a gateway to somewhere. However, we must let the routing
117 * protocol deal with that.
118 *
119 */
120
316670eb 121struct mbuf *
2d21ac55 122ip6_forward(struct mbuf *m, struct route_in6 *ip6forward_rt,
6d2010ae 123 int srcrt)
1c79356b
A
124{
125 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
9bccf70c
A
126 struct sockaddr_in6 *dst;
127 struct rtentry *rt;
1c79356b 128 int error, type = 0, code = 0;
316670eb 129 boolean_t proxy = FALSE;
1c79356b 130 struct mbuf *mcopy = NULL;
39236c6e
A
131 struct ifnet *ifp, *rcvifp, *origifp; /* maybe unnecessary */
132 u_int32_t inzone, outzone, len;
6d2010ae 133 struct in6_addr src_in6, dst_in6;
39236c6e 134 uint64_t curtime = net_uptime();
9bccf70c 135#if IPSEC
1c79356b
A
136 struct secpolicy *sp = NULL;
137#endif
6d2010ae
A
138 unsigned int ifscope = IFSCOPE_NONE;
139#if PF
140 struct pf_mtag *pf_mtag;
141#endif /* PF */
91447636 142
39236c6e
A
143 /*
144 * In the prefix proxying case, the route to the proxied node normally
145 * gets created by nd6_prproxy_ns_output(), as part of forwarding a
146 * NS (NUD/AR) packet to the proxied node. In the event that such
147 * packet did not arrive in time before the correct route gets created,
148 * ip6_input() would have performed a rtalloc() which most likely will
149 * create the wrong cloned route; this route points back to the same
150 * interface as the inbound interface, since the parent non-scoped
151 * prefix route points there. Therefore we check if that is the case
152 * and perform the necessary fixup to get the correct route installed.
153 */
154 if (!srcrt && nd6_prproxy &&
155 (rt = ip6forward_rt->ro_rt) != NULL && (rt->rt_flags & RTF_PROXY)) {
156 nd6_proxy_find_fwdroute(m->m_pkthdr.rcvif, ip6forward_rt);
157 if ((rt = ip6forward_rt->ro_rt) != NULL)
158 ifscope = rt->rt_ifp->if_index;
159 }
160
6d2010ae
A
161#if PF
162 pf_mtag = pf_find_mtag(m);
316670eb
A
163 if (pf_mtag != NULL && pf_mtag->pftag_rtableid != IFSCOPE_NONE)
164 ifscope = pf_mtag->pftag_rtableid;
165
166 /*
167 * If the caller provides a route which is on a different interface
168 * than the one specified for scoped forwarding, discard the route
169 * and do a lookup below.
170 */
171 if (ifscope != IFSCOPE_NONE && (rt = ip6forward_rt->ro_rt) != NULL) {
172 RT_LOCK(rt);
173 if (rt->rt_ifp->if_index != ifscope) {
174 RT_UNLOCK(rt);
39236c6e
A
175 ROUTE_RELEASE(ip6forward_rt);
176 rt = NULL;
316670eb
A
177 } else {
178 RT_UNLOCK(rt);
179 }
180 }
6d2010ae 181#endif /* PF */
1c79356b 182
9bccf70c 183#if IPSEC
1c79356b
A
184 /*
185 * Check AH/ESP integrity.
186 */
187 /*
188 * Don't increment ip6s_cantforward because this is the check
189 * before forwarding packet actually.
190 */
91447636 191 if (ipsec_bypass == 0) {
91447636 192 if (ipsec6_in_reject(m, NULL)) {
2d21ac55 193 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636 194 m_freem(m);
316670eb 195 return (NULL);
91447636 196 }
1c79356b 197 }
9bccf70c 198#endif /*IPSEC*/
1c79356b 199
9bccf70c 200 /*
fe8ab488 201 * Do not forward packets to multicast destination.
9bccf70c
A
202 * Do not forward packets with unspecified source. It was discussed
203 * in July 2000, on ipngwg mailing list.
204 */
1c79356b 205 if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
9bccf70c
A
206 IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
207 IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1c79356b
A
208 ip6stat.ip6s_cantforward++;
209 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
39236c6e
A
210 if (ip6_log_time + ip6_log_interval < curtime) {
211 ip6_log_time = curtime;
1c79356b
A
212 log(LOG_DEBUG,
213 "cannot forward "
214 "from %s to %s nxt %d received on %s\n",
215 ip6_sprintf(&ip6->ip6_src),
216 ip6_sprintf(&ip6->ip6_dst),
217 ip6->ip6_nxt,
218 if_name(m->m_pkthdr.rcvif));
219 }
220 m_freem(m);
316670eb 221 return (NULL);
1c79356b
A
222 }
223
224 if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
225 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
226 icmp6_error(m, ICMP6_TIME_EXCEEDED,
227 ICMP6_TIME_EXCEED_TRANSIT, 0);
316670eb
A
228 return (NULL);
229 }
230
231 /*
232 * See if the destination is a proxied address, and if so pretend
233 * that it's for us. This is mostly to handle NUD probes against
234 * the proxied addresses. We filter for ICMPv6 here and will let
235 * icmp6_input handle the rest.
236 */
237 if (!srcrt && nd6_prproxy) {
238 VERIFY(!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst));
239 proxy = nd6_prproxy_isours(m, ip6, ip6forward_rt, ifscope);
240 /*
241 * Don't update hop limit while proxying; RFC 4389 4.1.
242 * Also skip IPsec forwarding path processing as this
243 * packet is not to be forwarded.
244 */
245 if (proxy)
246 goto skip_ipsec;
1c79356b 247 }
316670eb 248
1c79356b
A
249 ip6->ip6_hlim -= IPV6_HLIMDEC;
250
251 /*
252 * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
253 * size of IPv6 + ICMPv6 headers) bytes of the packet in case
254 * we need to generate an ICMP6 message to the src.
255 * Thanks to M_EXT, in most cases copy will not occur.
256 *
257 * It is important to save it before IPsec processing as IPsec
258 * processing may modify the mbuf.
259 */
260 mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
261
9bccf70c
A
262#if IPSEC
263 if (ipsec_bypass != 0)
264 goto skip_ipsec;
1c79356b 265 /* get a security policy for this packet */
9bccf70c
A
266 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
267 &error);
1c79356b 268 if (sp == NULL) {
2d21ac55 269 IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
1c79356b
A
270 ip6stat.ip6s_cantforward++;
271 if (mcopy) {
272#if 0
273 /* XXX: what icmp ? */
274#else
275 m_freem(mcopy);
276#endif
277 }
278 m_freem(m);
316670eb 279 return (NULL);
1c79356b
A
280 }
281
282 error = 0;
283
284 /* check policy */
285 switch (sp->policy) {
286 case IPSEC_POLICY_DISCARD:
2d21ac55 287 case IPSEC_POLICY_GENERATE:
1c79356b
A
288 /*
289 * This packet is just discarded.
290 */
2d21ac55 291 IPSEC_STAT_INCREMENT(ipsec6stat.out_polvio);
1c79356b 292 ip6stat.ip6s_cantforward++;
2d21ac55 293 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b
A
294 if (mcopy) {
295#if 0
296 /* XXX: what icmp ? */
297#else
298 m_freem(mcopy);
299#endif
300 }
301 m_freem(m);
316670eb 302 return (NULL);
1c79356b
A
303
304 case IPSEC_POLICY_BYPASS:
305 case IPSEC_POLICY_NONE:
306 /* no need to do IPsec. */
2d21ac55 307 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b 308 goto skip_ipsec;
9bccf70c 309
1c79356b
A
310 case IPSEC_POLICY_IPSEC:
311 if (sp->req == NULL) {
312 /* XXX should be panic ? */
313 printf("ip6_forward: No IPsec request specified.\n");
314 ip6stat.ip6s_cantforward++;
2d21ac55 315 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b
A
316 if (mcopy) {
317#if 0
318 /* XXX: what icmp ? */
319#else
320 m_freem(mcopy);
321#endif
322 }
323 m_freem(m);
316670eb 324 return (NULL);
1c79356b
A
325 }
326 /* do IPsec */
327 break;
328
329 case IPSEC_POLICY_ENTRUST:
330 default:
331 /* should be panic ?? */
332 printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
2d21ac55 333 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b
A
334 goto skip_ipsec;
335 }
336
337 {
338 struct ipsec_output_state state;
339
340 /*
341 * All the extension headers will become inaccessible
342 * (since they can be encrypted).
343 * Don't panic, we need no more updates to extension headers
344 * on inner IPv6 packet (since they are now encapsulated).
345 *
346 * IPv6 [ESP|AH] IPv6 [extension headers] payload
347 */
348 bzero(&state, sizeof(state));
349 state.m = m;
1c79356b
A
350 state.dst = NULL; /* update at ipsec6_output_tunnel() */
351
ebb1b9f4 352 error = ipsec6_output_tunnel(&state, sp, 0);
2d21ac55 353 key_freesp(sp, KEY_SADB_UNLOCKED);
39236c6e
A
354 if (state.tunneled == 4) {
355 ROUTE_RELEASE(&state.ro);
316670eb 356 return (NULL); /* packet is gone - sent over IPv4 */
ebb1b9f4 357 }
39236c6e
A
358
359 m = state.m;
360 ROUTE_RELEASE(&state.ro);
361
1c79356b
A
362 if (error) {
363 /* mbuf is already reclaimed in ipsec6_output_tunnel. */
364 switch (error) {
365 case EHOSTUNREACH:
366 case ENETUNREACH:
367 case EMSGSIZE:
368 case ENOBUFS:
369 case ENOMEM:
370 break;
371 default:
372 printf("ip6_output (ipsec): error code %d\n", error);
55e303ae 373 /* fall through */
1c79356b
A
374 case ENOENT:
375 /* don't show these error codes to the user */
376 break;
377 }
378 ip6stat.ip6s_cantforward++;
379 if (mcopy) {
380#if 0
381 /* XXX: what icmp ? */
382#else
383 m_freem(mcopy);
384#endif
385 }
386 m_freem(m);
316670eb 387 return (NULL);
1c79356b
A
388 }
389 }
9bccf70c 390#endif /* IPSEC */
39236c6e 391 skip_ipsec:
9bccf70c 392
2d21ac55 393 dst = (struct sockaddr_in6 *)&ip6forward_rt->ro_dst;
b0d623f7
A
394 if ((rt = ip6forward_rt->ro_rt) != NULL) {
395 RT_LOCK(rt);
396 /* Take an extra ref for ourselves */
397 RT_ADDREF_LOCKED(rt);
398 }
399
39236c6e 400 VERIFY(rt == NULL || rt == ip6forward_rt->ro_rt);
1c79356b
A
401 if (!srcrt) {
402 /*
2d21ac55 403 * ip6forward_rt->ro_dst.sin6_addr is equal to ip6->ip6_dst
1c79356b 404 */
39236c6e 405 if (ROUTE_UNUSABLE(ip6forward_rt)) {
b0d623f7
A
406 if (rt != NULL) {
407 /* Release extra ref */
408 RT_REMREF_LOCKED(rt);
409 RT_UNLOCK(rt);
1c79356b 410 }
39236c6e
A
411 ROUTE_RELEASE(ip6forward_rt);
412
1c79356b 413 /* this probably fails but give it a try again */
6d2010ae
A
414 rtalloc_scoped_ign((struct route *)ip6forward_rt,
415 RTF_PRCLONING, ifscope);
b0d623f7
A
416 if ((rt = ip6forward_rt->ro_rt) != NULL) {
417 RT_LOCK(rt);
418 /* Take an extra ref for ourselves */
419 RT_ADDREF_LOCKED(rt);
420 }
1c79356b 421 }
9bccf70c 422
b0d623f7 423 if (rt == NULL) {
1c79356b 424 ip6stat.ip6s_noroute++;
9bccf70c 425 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
6d2010ae 426 if (mcopy)
1c79356b
A
427 icmp6_error(mcopy, ICMP6_DST_UNREACH,
428 ICMP6_DST_UNREACH_NOROUTE, 0);
1c79356b 429 m_freem(m);
316670eb 430 return (NULL);
1c79356b 431 }
b0d623f7 432 RT_LOCK_ASSERT_HELD(rt);
39236c6e
A
433 } else if (ROUTE_UNUSABLE(ip6forward_rt) ||
434 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
b0d623f7
A
435 if (rt != NULL) {
436 /* Release extra ref */
437 RT_REMREF_LOCKED(rt);
438 RT_UNLOCK(rt);
1c79356b 439 }
39236c6e
A
440 ROUTE_RELEASE(ip6forward_rt);
441
1c79356b
A
442 bzero(dst, sizeof(*dst));
443 dst->sin6_len = sizeof(struct sockaddr_in6);
444 dst->sin6_family = AF_INET6;
445 dst->sin6_addr = ip6->ip6_dst;
446
6d2010ae
A
447 rtalloc_scoped_ign((struct route *)ip6forward_rt,
448 RTF_PRCLONING, ifscope);
b0d623f7 449 if ((rt = ip6forward_rt->ro_rt) == NULL) {
1c79356b 450 ip6stat.ip6s_noroute++;
9bccf70c 451 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
6d2010ae 452 if (mcopy)
1c79356b 453 icmp6_error(mcopy, ICMP6_DST_UNREACH,
b0d623f7 454 ICMP6_DST_UNREACH_NOROUTE, 0);
1c79356b 455 m_freem(m);
316670eb 456 return (NULL);
1c79356b 457 }
b0d623f7
A
458 RT_LOCK(rt);
459 /* Take an extra ref for ourselves */
460 RT_ADDREF_LOCKED(rt);
1c79356b 461 }
1c79356b
A
462
463 /*
6d2010ae
A
464 * Source scope check: if a packet can't be delivered to its
465 * destination for the reason that the destination is beyond the scope
466 * of the source address, discard the packet and return an icmp6
467 * destination unreachable error with Code 2 (beyond scope of source
316670eb
A
468 * address) unless we are proxying (source address is link local
469 * for NUDs.) We use a local copy of ip6_src, since in6_setscope()
6d2010ae
A
470 * will possibly modify its first argument.
471 * [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1]
1c79356b 472 */
6d2010ae
A
473 src_in6 = ip6->ip6_src;
474 if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
475 /* XXX: this should not happen */
476 ip6stat.ip6s_cantforward++;
477 ip6stat.ip6s_badscope++;
478 m_freem(m);
316670eb 479 return (NULL);
6d2010ae
A
480 }
481 if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
482 ip6stat.ip6s_cantforward++;
483 ip6stat.ip6s_badscope++;
484 m_freem(m);
316670eb 485 return (NULL);
6d2010ae 486 }
316670eb
A
487
488 if (inzone != outzone && !proxy) {
1c79356b
A
489 ip6stat.ip6s_cantforward++;
490 ip6stat.ip6s_badscope++;
491 in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
492
39236c6e
A
493 if (ip6_log_time + ip6_log_interval < curtime) {
494 ip6_log_time = curtime;
1c79356b
A
495 log(LOG_DEBUG,
496 "cannot forward "
497 "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
498 ip6_sprintf(&ip6->ip6_src),
499 ip6_sprintf(&ip6->ip6_dst),
500 ip6->ip6_nxt,
501 if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
502 }
b0d623f7
A
503 /* Release extra ref */
504 RT_REMREF_LOCKED(rt);
505 RT_UNLOCK(rt);
91447636 506 if (mcopy) {
1c79356b
A
507 icmp6_error(mcopy, ICMP6_DST_UNREACH,
508 ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
91447636 509 }
1c79356b 510 m_freem(m);
316670eb 511 return (NULL);
1c79356b
A
512 }
513
6d2010ae
A
514 /*
515 * Destination scope check: if a packet is going to break the scope
516 * zone of packet's destination address, discard it. This case should
517 * usually be prevented by appropriately-configured routing table, but
518 * we need an explicit check because we may mistakenly forward the
519 * packet to a different zone by (e.g.) a default route.
520 */
521 dst_in6 = ip6->ip6_dst;
522 if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
523 in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
524 inzone != outzone) {
525 ip6stat.ip6s_cantforward++;
526 ip6stat.ip6s_badscope++;
527 m_freem(m);
316670eb 528 return (NULL);
6d2010ae
A
529 }
530
1c79356b
A
531 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
532 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
533 if (mcopy) {
b0d623f7 534 uint32_t mtu;
9bccf70c 535#if IPSEC
2d21ac55 536 struct secpolicy *sp2;
1c79356b
A
537 int ipsecerror;
538 size_t ipsechdrsiz;
539#endif
540
541 mtu = rt->rt_ifp->if_mtu;
55e303ae 542#if IPSEC
1c79356b
A
543 /*
544 * When we do IPsec tunnel ingress, we need to play
6d2010ae 545 * with the link value (decrement IPsec header size
1c79356b
A
546 * from mtu value). The code is much simpler than v4
547 * case, as we have the outgoing interface for
548 * encapsulated packet as "rt->rt_ifp".
549 */
2d21ac55 550 sp2 = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
1c79356b 551 IP_FORWARDING, &ipsecerror);
2d21ac55 552 if (sp2) {
1c79356b
A
553 ipsechdrsiz = ipsec6_hdrsiz(mcopy,
554 IPSEC_DIR_OUTBOUND, NULL);
555 if (ipsechdrsiz < mtu)
556 mtu -= ipsechdrsiz;
2d21ac55 557 key_freesp(sp2, KEY_SADB_UNLOCKED);
1c79356b 558 }
1c79356b
A
559 /*
560 * if mtu becomes less than minimum MTU,
561 * tell minimum MTU (and I'll need to fragment it).
562 */
563 if (mtu < IPV6_MMTU)
564 mtu = IPV6_MMTU;
565#endif
b0d623f7
A
566 /* Release extra ref */
567 RT_REMREF_LOCKED(rt);
568 RT_UNLOCK(rt);
1c79356b 569 icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
b0d623f7
A
570 } else {
571 /* Release extra ref */
572 RT_REMREF_LOCKED(rt);
573 RT_UNLOCK(rt);
1c79356b
A
574 }
575 m_freem(m);
316670eb 576 return (NULL);
1c79356b
A
577 }
578
579 if (rt->rt_flags & RTF_GATEWAY)
316670eb 580 dst = (struct sockaddr_in6 *)(void *)rt->rt_gateway;
1c79356b
A
581
582 /*
583 * If we are to forward the packet using the same interface
584 * as one we got the packet from, perhaps we should send a redirect
585 * to sender to shortcut a hop.
586 * Only send redirect if source is sending directly to us,
587 * and if packet was not source routed (or has any options).
588 * Also, don't send redirect if forwarding using a route
589 * modified by a redirect.
590 */
316670eb
A
591 if (!proxy &&
592 ip6_sendredirects && rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
9bccf70c
A
593 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
594 if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) {
595 /*
596 * If the incoming interface is equal to the outgoing
597 * one, and the link attached to the interface is
598 * point-to-point, then it will be highly probable
599 * that a routing loop occurs. Thus, we immediately
600 * drop the packet and send an ICMPv6 error message.
601 *
602 * type/code is based on suggestion by Rich Draves.
603 * not sure if it is the best pick.
604 */
b0d623f7
A
605 RT_REMREF_LOCKED(rt); /* Release extra ref */
606 RT_UNLOCK(rt);
9bccf70c
A
607 icmp6_error(mcopy, ICMP6_DST_UNREACH,
608 ICMP6_DST_UNREACH_ADDR, 0);
609 m_freem(m);
316670eb 610 return (NULL);
9bccf70c 611 }
1c79356b 612 type = ND_REDIRECT;
9bccf70c 613 }
1c79356b 614
7e4a7d39 615#if IPFW2
1c79356b
A
616 /*
617 * Check with the firewall...
618 */
9bccf70c 619 if (ip6_fw_enable && ip6_fw_chk_ptr) {
1c79356b 620 u_short port = 0;
b0d623f7
A
621 ifp = rt->rt_ifp;
622 /* Drop the lock but retain the extra ref */
623 RT_UNLOCK(rt);
1c79356b 624 /* If ipfw says divert, we have to just drop packet */
b0d623f7 625 if (ip6_fw_chk_ptr(&ip6, ifp, &port, &m)) {
1c79356b
A
626 m_freem(m);
627 goto freecopy;
628 }
b0d623f7 629 if (!m) {
1c79356b 630 goto freecopy;
b0d623f7
A
631 }
632 /* We still have the extra ref on rt */
633 RT_LOCK(rt);
1c79356b 634 }
7e4a7d39 635#endif
1c79356b 636
9bccf70c
A
637 /*
638 * Fake scoped addresses. Note that even link-local source or
639 * destinaion can appear, if the originating node just sends the
640 * packet to us (without address resolution for the destination).
641 * Since both icmp6_error and icmp6_redirect_output fill the embedded
642 * link identifiers, we can do this stuff after making a copy for
643 * returning an error.
644 */
645 if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
646 /*
647 * See corresponding comments in ip6_output.
648 * XXX: but is it possible that ip6_forward() sends a packet
649 * to a loopback interface? I don't think so, and thus
650 * I bark here. (jinmei@kame.net)
651 * XXX: it is common to route invalid packets to loopback.
652 * also, the codepath will be visited on use of ::1 in
653 * rthdr. (itojun)
654 */
655#if 1
fe8ab488 656 if ((0))
1c79356b 657#else
9bccf70c
A
658 if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
659#endif
660 {
661 printf("ip6_forward: outgoing interface is loopback. "
55e303ae
A
662 "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
663 ip6_sprintf(&ip6->ip6_src),
664 ip6_sprintf(&ip6->ip6_dst),
665 ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
666 if_name(rt->rt_ifp));
9bccf70c
A
667 }
668
669 /* we can just use rcvif in forwarding. */
39236c6e
A
670 origifp = rcvifp = m->m_pkthdr.rcvif;
671 } else if (nd6_prproxy) {
672 /*
673 * In the prefix proxying case, we need to inform nd6_output()
674 * about the inbound interface, so that any subsequent NS
675 * packets generated by nd6_prproxy_ns_output() will not be
676 * sent back to that same interface.
677 */
678 origifp = rcvifp = m->m_pkthdr.rcvif;
679 } else {
680 rcvifp = m->m_pkthdr.rcvif;
9bccf70c 681 origifp = rt->rt_ifp;
39236c6e 682 }
9bccf70c
A
683 /*
684 * clear embedded scope identifiers if necessary.
685 * in6_clearscope will touch the addresses only when necessary.
686 */
687 in6_clearscope(&ip6->ip6_src);
688 in6_clearscope(&ip6->ip6_dst);
9bccf70c 689
b0d623f7
A
690 ifp = rt->rt_ifp;
691 /* Drop the lock but retain the extra ref */
692 RT_UNLOCK(rt);
693
316670eb
A
694 /*
695 * If this is to be processed locally, let ip6_input have it.
696 */
697 if (proxy) {
39236c6e 698 VERIFY(m->m_pkthdr.pkt_flags & PKTF_PROXY_DST);
316670eb
A
699 /* Release extra ref */
700 RT_REMREF(rt);
701 if (mcopy != NULL)
702 m_freem(mcopy);
703 return (m);
704 }
705
b0d623f7 706#if PF
b0d623f7 707 /* Invoke outbound packet filter */
316670eb 708 error = pf_af_hook(ifp, NULL, &m, AF_INET6, FALSE, NULL);
b0d623f7 709
316670eb 710 if (error != 0 || m == NULL) {
b0d623f7
A
711 if (m != NULL) {
712 panic("%s: unexpected packet %p\n", __func__, m);
713 /* NOTREACHED */
714 }
715 /* Already freed by callee */
716 goto senderr;
717 }
718 ip6 = mtod(m, struct ip6_hdr *);
719#endif /* PF */
720
39236c6e
A
721 /* Mark this packet as being forwarded from another interface */
722 m->m_pkthdr.pkt_flags |= PKTF_FORWARDED;
723 len = m_pktlen(m);
724
316670eb 725 error = nd6_output(ifp, origifp, m, dst, rt, NULL);
1c79356b 726 if (error) {
b0d623f7 727 in6_ifstat_inc(ifp, ifs6_out_discard);
1c79356b
A
728 ip6stat.ip6s_cantforward++;
729 } else {
39236c6e
A
730 /*
731 * Increment stats on the source interface; the ones
732 * for destination interface has been taken care of
733 * during output above by virtue of PKTF_FORWARDED.
734 */
735 rcvifp->if_fpackets++;
736 rcvifp->if_fbytes += len;
737
1c79356b 738 ip6stat.ip6s_forward++;
b0d623f7 739 in6_ifstat_inc(ifp, ifs6_out_forward);
1c79356b
A
740 if (type)
741 ip6stat.ip6s_redirectsent++;
742 else {
b0d623f7 743 if (mcopy) {
1c79356b 744 goto freecopy;
b0d623f7 745 }
1c79356b
A
746 }
747 }
b0d623f7
A
748#if PF
749senderr:
750#endif /* PF */
751 if (mcopy == NULL) {
752 /* Release extra ref */
753 RT_REMREF(rt);
316670eb 754 return (NULL);
b0d623f7 755 }
1c79356b
A
756 switch (error) {
757 case 0:
758#if 1
759 if (type == ND_REDIRECT) {
760 icmp6_redirect_output(mcopy, rt);
b0d623f7
A
761 /* Release extra ref */
762 RT_REMREF(rt);
316670eb 763 return (NULL);
1c79356b
A
764 }
765#endif
766 goto freecopy;
767
768 case EMSGSIZE:
769 /* xxx MTU is constant in PPP? */
770 goto freecopy;
771
772 case ENOBUFS:
773 /* Tell source to slow down like source quench in IP? */
774 goto freecopy;
775
776 case ENETUNREACH: /* shouldn't happen, checked above */
777 case EHOSTUNREACH:
778 case ENETDOWN:
779 case EHOSTDOWN:
780 default:
781 type = ICMP6_DST_UNREACH;
782 code = ICMP6_DST_UNREACH_ADDR;
783 break;
784 }
785 icmp6_error(mcopy, type, code, 0);
b0d623f7
A
786 /* Release extra ref */
787 RT_REMREF(rt);
316670eb 788 return (NULL);
1c79356b
A
789
790 freecopy:
791 m_freem(mcopy);
b0d623f7
A
792 /* Release extra ref */
793 RT_REMREF(rt);
316670eb 794 return (NULL);
1c79356b 795}