Annotation of src/sys/netinet6/ip6_forward.c, Revision 1.12.2.7
1.12.2.7! he 1: /* $NetBSD: ip6_forward.c,v 1.12.2.6 2001/10/25 13:22:12 jhawk Exp $ */
1.12.2.4 itojun 2: /* $KAME: ip6_forward.c,v 1.56 2000/09/22 04:01:37 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.10 itojun 7: *
1.2 itojun 8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
1.10 itojun 19: *
1.2 itojun 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
1.12.2.2 itojun 33: #include "opt_ipsec.h"
34:
1.2 itojun 35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/malloc.h>
38: #include <sys/mbuf.h>
39: #include <sys/domain.h>
40: #include <sys/protosw.h>
41: #include <sys/socket.h>
42: #include <sys/errno.h>
43: #include <sys/time.h>
44: #include <sys/kernel.h>
45: #include <sys/syslog.h>
46:
47: #include <net/if.h>
48: #include <net/route.h>
1.12.2.7! he 49: #ifdef PFIL_HOOKS
! 50: #include <net/pfil.h>
! 51: #endif
1.2 itojun 52:
53: #include <netinet/in.h>
54: #include <netinet/in_var.h>
1.7 itojun 55: #include <netinet/ip_var.h>
1.8 itojun 56: #include <netinet/ip6.h>
1.2 itojun 57: #include <netinet6/ip6_var.h>
1.8 itojun 58: #include <netinet/icmp6.h>
1.5 itojun 59: #include <netinet6/nd6.h>
60:
1.12.2.2 itojun 61: #ifdef IPSEC
1.5 itojun 62: #include <netinet6/ipsec.h>
63: #include <netkey/key.h>
1.12.2.2 itojun 64: #endif /* IPSEC */
1.5 itojun 65:
66: #ifdef IPV6FIREWALL
67: #include <netinet6/ip6_fw.h>
68: #endif
69:
70: #include <net/net_osdep.h>
1.2 itojun 71:
72: struct route_in6 ip6_forward_rt;
73:
74: /*
75: * Forward a packet. If some error occurs return the sender
76: * an icmp packet. Note we can't always generate a meaningful
77: * icmp message because icmp doesn't have a large enough repertoire
78: * of codes and types.
79: *
80: * If not forwarding, just drop the packet. This could be confusing
81: * if ipforwarding was zero but some routing protocol was advancing
82: * us as a gateway to somewhere. However, we must let the routing
83: * protocol deal with that.
84: *
85: */
86:
87: void
88: ip6_forward(m, srcrt)
89: struct mbuf *m;
90: int srcrt;
91: {
1.5 itojun 92: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.2 itojun 93: register struct sockaddr_in6 *dst;
94: register struct rtentry *rt;
95: int error, type = 0, code = 0;
1.5 itojun 96: struct mbuf *mcopy = NULL;
1.10 itojun 97: struct ifnet *origifp; /* maybe unnecessary */
1.12.2.7! he 98: #ifdef PFIL_HOOKS
! 99: struct packet_filter_hook *pfh;
! 100: struct mbuf *m1;
! 101: int rv;
! 102: #endif /* PFIL_HOOKS */
1.12.2.2 itojun 103: #ifdef IPSEC
1.5 itojun 104: struct secpolicy *sp = NULL;
105: #endif
106: long time_second = time.tv_sec;
107:
1.12.2.2 itojun 108: #ifdef IPSEC
1.5 itojun 109: /*
110: * Check AH/ESP integrity.
111: */
112: /*
113: * Don't increment ip6s_cantforward because this is the check
114: * before forwarding packet actually.
115: */
116: if (ipsec6_in_reject(m, NULL)) {
117: ipsec6stat.in_polvio++;
118: m_freem(m);
119: return;
120: }
1.12.2.2 itojun 121: #endif /*IPSEC*/
1.2 itojun 122:
1.12.2.3 itojun 123: /*
124: * Do not forward packets to multicast destination (should be handled
125: * by ip6_mforward().
126: * Do not forward packets with unspecified source. It was discussed
127: * in July 2000, on ipngwg mailing list.
128: */
1.9 itojun 129: if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
1.12.2.3 itojun 130: IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
131: IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1.2 itojun 132: ip6stat.ip6s_cantforward++;
1.5 itojun 133: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
1.2 itojun 134: if (ip6_log_time + ip6_log_interval < time_second) {
135: ip6_log_time = time_second;
136: log(LOG_DEBUG,
137: "cannot forward "
138: "from %s to %s nxt %d received on %s\n",
1.9 itojun 139: ip6_sprintf(&ip6->ip6_src),
140: ip6_sprintf(&ip6->ip6_dst),
1.2 itojun 141: ip6->ip6_nxt,
1.5 itojun 142: if_name(m->m_pkthdr.rcvif));
1.2 itojun 143: }
144: m_freem(m);
145: return;
146: }
147:
148: if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
1.5 itojun 149: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
1.2 itojun 150: icmp6_error(m, ICMP6_TIME_EXCEEDED,
151: ICMP6_TIME_EXCEED_TRANSIT, 0);
152: return;
153: }
154: ip6->ip6_hlim -= IPV6_HLIMDEC;
155:
1.5 itojun 156: /*
157: * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
158: * size of IPv6 + ICMPv6 headers) bytes of the packet in case
159: * we need to generate an ICMP6 message to the src.
160: * Thanks to M_EXT, in most cases copy will not occur.
161: *
162: * It is important to save it before IPsec processing as IPsec
163: * processing may modify the mbuf.
164: */
165: mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
166:
1.12.2.2 itojun 167: #ifdef IPSEC
1.5 itojun 168: /* get a security policy for this packet */
1.12.2.4 itojun 169: sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
170: &error);
1.5 itojun 171: if (sp == NULL) {
172: ipsec6stat.out_inval++;
173: ip6stat.ip6s_cantforward++;
174: if (mcopy) {
175: #if 0
176: /* XXX: what icmp ? */
177: #else
178: m_freem(mcopy);
179: #endif
180: }
181: m_freem(m);
182: return;
183: }
184:
185: error = 0;
186:
187: /* check policy */
188: switch (sp->policy) {
189: case IPSEC_POLICY_DISCARD:
190: /*
191: * This packet is just discarded.
192: */
193: ipsec6stat.out_polvio++;
194: ip6stat.ip6s_cantforward++;
195: key_freesp(sp);
196: if (mcopy) {
197: #if 0
198: /* XXX: what icmp ? */
199: #else
200: m_freem(mcopy);
201: #endif
202: }
203: m_freem(m);
204: return;
205:
206: case IPSEC_POLICY_BYPASS:
207: case IPSEC_POLICY_NONE:
208: /* no need to do IPsec. */
209: key_freesp(sp);
210: goto skip_ipsec;
1.12.2.1 itojun 211:
1.5 itojun 212: case IPSEC_POLICY_IPSEC:
213: if (sp->req == NULL) {
214: /* XXX should be panic ? */
215: printf("ip6_forward: No IPsec request specified.\n");
216: ip6stat.ip6s_cantforward++;
217: key_freesp(sp);
218: if (mcopy) {
219: #if 0
220: /* XXX: what icmp ? */
221: #else
222: m_freem(mcopy);
223: #endif
224: }
225: m_freem(m);
226: return;
227: }
228: /* do IPsec */
229: break;
230:
231: case IPSEC_POLICY_ENTRUST:
232: default:
233: /* should be panic ?? */
234: printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
235: key_freesp(sp);
236: goto skip_ipsec;
237: }
238:
239: {
240: struct ipsec_output_state state;
241:
242: /*
243: * All the extension headers will become inaccessible
244: * (since they can be encrypted).
245: * Don't panic, we need no more updates to extension headers
246: * on inner IPv6 packet (since they are now encapsulated).
247: *
248: * IPv6 [ESP|AH] IPv6 [extension headers] payload
249: */
250: bzero(&state, sizeof(state));
251: state.m = m;
252: state.ro = NULL; /* update at ipsec6_output_tunnel() */
253: state.dst = NULL; /* update at ipsec6_output_tunnel() */
254:
255: error = ipsec6_output_tunnel(&state, sp, 0);
256:
257: m = state.m;
258: #if 0 /* XXX allocate a route (ro, dst) again later */
259: ro = (struct route_in6 *)state.ro;
260: dst = (struct sockaddr_in6 *)state.dst;
261: #endif
262: key_freesp(sp);
263:
264: if (error) {
265: /* mbuf is already reclaimed in ipsec6_output_tunnel. */
266: switch (error) {
267: case EHOSTUNREACH:
268: case ENETUNREACH:
269: case EMSGSIZE:
270: case ENOBUFS:
271: case ENOMEM:
272: break;
273: default:
274: printf("ip6_output (ipsec): error code %d\n", error);
275: /*fall through*/
276: case ENOENT:
277: /* don't show these error codes to the user */
278: break;
279: }
280: ip6stat.ip6s_cantforward++;
281: if (mcopy) {
282: #if 0
283: /* XXX: what icmp ? */
284: #else
285: m_freem(mcopy);
286: #endif
287: }
288: m_freem(m);
289: return;
290: }
291: }
292: skip_ipsec:
1.12.2.2 itojun 293: #endif /* IPSEC */
1.5 itojun 294:
1.2 itojun 295: dst = &ip6_forward_rt.ro_dst;
296: if (!srcrt) {
297: /*
298: * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
299: */
300: if (ip6_forward_rt.ro_rt == 0 ||
301: (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
302: if (ip6_forward_rt.ro_rt) {
303: RTFREE(ip6_forward_rt.ro_rt);
304: ip6_forward_rt.ro_rt = 0;
305: }
306: /* this probably fails but give it a try again */
1.5 itojun 307: rtalloc((struct route *)&ip6_forward_rt);
1.2 itojun 308: }
1.12.2.1 itojun 309:
1.2 itojun 310: if (ip6_forward_rt.ro_rt == 0) {
311: ip6stat.ip6s_noroute++;
1.5 itojun 312: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
313: if (mcopy) {
314: icmp6_error(mcopy, ICMP6_DST_UNREACH,
315: ICMP6_DST_UNREACH_NOROUTE, 0);
316: }
317: m_freem(m);
1.2 itojun 318: return;
319: }
320: } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
321: !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
322: if (ip6_forward_rt.ro_rt) {
323: RTFREE(ip6_forward_rt.ro_rt);
324: ip6_forward_rt.ro_rt = 0;
325: }
326: bzero(dst, sizeof(*dst));
327: dst->sin6_len = sizeof(struct sockaddr_in6);
328: dst->sin6_family = AF_INET6;
329: dst->sin6_addr = ip6->ip6_dst;
330:
331: rtalloc((struct route *)&ip6_forward_rt);
332: if (ip6_forward_rt.ro_rt == 0) {
333: ip6stat.ip6s_noroute++;
1.5 itojun 334: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
335: if (mcopy) {
336: icmp6_error(mcopy, ICMP6_DST_UNREACH,
337: ICMP6_DST_UNREACH_NOROUTE, 0);
338: }
339: m_freem(m);
1.2 itojun 340: return;
341: }
342: }
343: rt = ip6_forward_rt.ro_rt;
1.9 itojun 344:
345: /*
346: * Scope check: if a packet can't be delivered to its destination
347: * for the reason that the destination is beyond the scope of the
348: * source address, discard the packet and return an icmp6 destination
349: * unreachable error with Code 2 (beyond scope of source address).
350: * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
351: */
352: if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
353: in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
354: ip6stat.ip6s_cantforward++;
355: ip6stat.ip6s_badscope++;
356: in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
357:
358: if (ip6_log_time + ip6_log_interval < time_second) {
359: ip6_log_time = time_second;
360: log(LOG_DEBUG,
361: "cannot forward "
362: "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
363: ip6_sprintf(&ip6->ip6_src),
364: ip6_sprintf(&ip6->ip6_dst),
365: ip6->ip6_nxt,
366: if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
367: }
368: if (mcopy)
369: icmp6_error(mcopy, ICMP6_DST_UNREACH,
370: ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
371: m_freem(m);
372: return;
373: }
374:
1.5 itojun 375: if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
376: in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
377: if (mcopy) {
378: u_long mtu;
1.12.2.2 itojun 379: #ifdef IPSEC
1.7 itojun 380: struct secpolicy *sp;
381: int ipsecerror;
382: size_t ipsechdrsiz;
383: #endif
1.5 itojun 384:
385: mtu = rt->rt_ifp->if_mtu;
1.12.2.2 itojun 386: #ifdef IPSEC
1.7 itojun 387: /*
388: * When we do IPsec tunnel ingress, we need to play
389: * with if_mtu value (decrement IPsec header size
390: * from mtu value). The code is much simpler than v4
391: * case, as we have the outgoing interface for
392: * encapsulated packet as "rt->rt_ifp".
393: */
394: sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
395: IP_FORWARDING, &ipsecerror);
396: if (sp) {
397: ipsechdrsiz = ipsec6_hdrsiz(mcopy,
398: IPSEC_DIR_OUTBOUND, NULL);
399: if (ipsechdrsiz < mtu)
400: mtu -= ipsechdrsiz;
401: }
402:
403: /*
1.10 itojun 404: * if mtu becomes less than minimum MTU,
1.7 itojun 405: * tell minimum MTU (and I'll need to fragment it).
406: */
407: if (mtu < IPV6_MMTU)
408: mtu = IPV6_MMTU;
409: #endif
1.5 itojun 410: icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
411: }
412: m_freem(m);
1.2 itojun 413: return;
414: }
415:
416: if (rt->rt_flags & RTF_GATEWAY)
417: dst = (struct sockaddr_in6 *)rt->rt_gateway;
418:
419: /*
420: * If we are to forward the packet using the same interface
421: * as one we got the packet from, perhaps we should send a redirect
422: * to sender to shortcut a hop.
423: * Only send redirect if source is sending directly to us,
424: * and if packet was not source routed (or has any options).
425: * Also, don't send redirect if forwarding using a route
426: * modified by a redirect.
427: */
428: if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
429: (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0)
430: type = ND_REDIRECT;
431:
1.5 itojun 432: #ifdef IPV6FIREWALL
433: /*
434: * Check with the firewall...
435: */
436: if (ip6_fw_chk_ptr) {
437: u_short port = 0;
438: /* If ipfw says divert, we have to just drop packet */
439: if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) {
440: m_freem(m);
441: goto freecopy;
442: }
443: if (!m)
444: goto freecopy;
445: }
446: #endif
447:
1.10 itojun 448: /*
449: * Fake scoped addresses. Note that even link-local source or
450: * destinaion can appear, if the originating node just sends the
451: * packet to us (without address resolution for the destination).
452: * Since both icmp6_error and icmp6_redirect_output fill the embedded
453: * link identifiers, we can do this stuff after make a copy for
454: * returning error.
455: */
456: if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
457: /*
458: * See corresponding comments in ip6_output.
459: * XXX: but is it possible that ip6_forward() sends a packet
460: * to a loopback interface? I don't think so, and thus
461: * I bark here. (jinmei@kame.net)
1.12 itojun 462: * XXX: it is common to route invalid packets to loopback.
1.12.2.1 itojun 463: * also, the codepath will be visited on use of ::1 in
464: * rthdr. (itojun)
1.10 itojun 465: */
1.12.2.1 itojun 466: #if 1
467: if (0)
468: #else
469: if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
470: #endif
471: {
1.12 itojun 472: printf("ip6_forward: outgoing interface is loopback. "
473: "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
474: ip6_sprintf(&ip6->ip6_src),
475: ip6_sprintf(&ip6->ip6_dst),
476: ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
477: if_name(rt->rt_ifp));
478: }
1.12.2.1 itojun 479:
1.10 itojun 480: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
481: origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
482: else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
483: origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
484: else
485: origifp = rt->rt_ifp;
486: }
487: else
488: origifp = rt->rt_ifp;
489: #ifndef FAKE_LOOPBACK_IF
1.11 itojun 490: if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
1.10 itojun 491: #else
492: if (1)
493: #endif
494: {
495: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
496: ip6->ip6_src.s6_addr16[1] = 0;
497: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
498: ip6->ip6_dst.s6_addr16[1] = 0;
499: }
500:
1.12.2.7! he 501: #ifdef PFIL_HOOKS
! 502: /*
! 503: * Run through list of hooks for output packets.
! 504: */
! 505: m1 = m;
! 506: pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
! 507: for (; pfh; pfh = pfh->pfil_link.tqe_next)
! 508: if (pfh->pfil_func) {
! 509: rv = pfh->pfil_func(ip6, sizeof(*ip6),
! 510: rt->rt_ifp, 1, &m1);
! 511: m = m1;
! 512: if (m == NULL)
! 513: goto freecopy;
! 514: if (rv) {
! 515: error = EHOSTUNREACH;
! 516: goto senderr;
! 517: }
! 518: ip6 = mtod(m, struct ip6_hdr *);
! 519: }
! 520: #endif /* PFIL_HOOKS */
! 521:
1.5 itojun 522: #ifdef OLDIP6OUTPUT
1.2 itojun 523: error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m,
524: (struct sockaddr *)dst,
525: ip6_forward_rt.ro_rt);
1.5 itojun 526: #else
1.10 itojun 527: error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
528: #endif
1.5 itojun 529: if (error) {
530: in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
1.2 itojun 531: ip6stat.ip6s_cantforward++;
1.5 itojun 532: } else {
1.2 itojun 533: ip6stat.ip6s_forward++;
1.5 itojun 534: in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
1.2 itojun 535: if (type)
536: ip6stat.ip6s_redirectsent++;
537: else {
538: if (mcopy)
539: goto freecopy;
540: }
541: }
1.12.2.7! he 542:
! 543: #ifdef PFIL_HOOKS
! 544: senderr:
! 545: #endif
1.2 itojun 546: if (mcopy == NULL)
547: return;
548:
549: switch (error) {
550: case 0:
551: #if 1
552: if (type == ND_REDIRECT) {
553: icmp6_redirect_output(mcopy, rt);
554: return;
555: }
556: #endif
557: goto freecopy;
558:
559: case EMSGSIZE:
560: /* xxx MTU is constant in PPP? */
561: goto freecopy;
562:
563: case ENOBUFS:
564: /* Tell source to slow down like source quench in IP? */
565: goto freecopy;
566:
567: case ENETUNREACH: /* shouldn't happen, checked above */
568: case EHOSTUNREACH:
569: case ENETDOWN:
570: case EHOSTDOWN:
571: default:
572: type = ICMP6_DST_UNREACH;
573: code = ICMP6_DST_UNREACH_ADDR;
574: break;
575: }
576: icmp6_error(mcopy, type, code, 0);
577: return;
578:
579: freecopy:
580: m_freem(mcopy);
1.5 itojun 581: return;
1.2 itojun 582: }
CVSweb <webmaster@jp.NetBSD.org>