Annotation of sys/netinet6/ip6_forward.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ip6_forward.c,v 1.39 2007/06/01 00:52:38 henning Exp $ */
2: /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */
3:
4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
7: *
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.
19: *
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:
33: #include "pf.h"
34:
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>
49:
50: #include <netinet/in.h>
51: #include <netinet/in_var.h>
52: #include <netinet/ip_var.h>
53: #include <netinet/ip6.h>
54: #include <netinet6/ip6_var.h>
55: #include <netinet/icmp6.h>
56: #include <netinet6/nd6.h>
57:
58: #if NPF > 0
59: #include <net/pfvar.h>
60: #endif
61:
62: #ifdef IPSEC
63: #include <netinet/ip_ipsp.h>
64: #include <netinet/ip_ah.h>
65: #include <netinet/ip_esp.h>
66: #include <netinet/udp.h>
67: #include <netinet/tcp.h>
68: #include <net/pfkeyv2.h>
69: #endif
70:
71: struct route_in6 ip6_forward_rt;
72: int ip6_forward_rtableid;
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: {
92: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
93: struct sockaddr_in6 *dst;
94: struct rtentry *rt;
95: int error = 0, type = 0, code = 0;
96: struct mbuf *mcopy = NULL;
97: struct ifnet *origifp; /* maybe unnecessary */
98: #ifdef IPSEC
99: u_int8_t sproto = 0;
100: struct m_tag *mtag;
101: union sockaddr_union sdst;
102: struct tdb_ident *tdbi;
103: u_int32_t sspi;
104: struct tdb *tdb;
105: int s;
106: #endif /* IPSEC */
107: int rtableid = 0;
108:
109: /*
110: * Do not forward packets to multicast destination (should be handled
111: * by ip6_mforward().
112: * Do not forward packets with unspecified source. It was discussed
113: * in July 2000, on ipngwg mailing list.
114: */
115: if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
116: IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
117: IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
118: ip6stat.ip6s_cantforward++;
119: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
120: if (ip6_log_time + ip6_log_interval < time_second) {
121: ip6_log_time = time_second;
122: log(LOG_DEBUG,
123: "cannot forward "
124: "from %s to %s nxt %d received on %s\n",
125: ip6_sprintf(&ip6->ip6_src),
126: ip6_sprintf(&ip6->ip6_dst),
127: ip6->ip6_nxt,
128: m->m_pkthdr.rcvif->if_xname);
129: }
130: m_freem(m);
131: return;
132: }
133:
134: if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
135: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
136: icmp6_error(m, ICMP6_TIME_EXCEEDED,
137: ICMP6_TIME_EXCEED_TRANSIT, 0);
138: return;
139: }
140: ip6->ip6_hlim -= IPV6_HLIMDEC;
141:
142: #ifdef IPSEC
143: if (!ipsec_in_use)
144: goto done_spd;
145:
146: s = splnet();
147:
148: /*
149: * Check if there was an outgoing SA bound to the flow
150: * from a transport protocol.
151: */
152:
153: /* Do we have any pending SAs to apply ? */
154: mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
155: if (mtag != NULL) {
156: #ifdef DIAGNOSTIC
157: if (mtag->m_tag_len != sizeof (struct tdb_ident))
158: panic("ip6_forward: tag of length %d (should be %d",
159: mtag->m_tag_len, sizeof (struct tdb_ident));
160: #endif
161: tdbi = (struct tdb_ident *)(mtag + 1);
162: tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
163: if (tdb == NULL)
164: error = -EINVAL;
165: m_tag_delete(m, mtag);
166: } else
167: tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
168: &error, IPSP_DIRECTION_OUT, NULL, NULL);
169:
170: if (tdb == NULL) {
171: splx(s);
172:
173: if (error == 0) {
174: /*
175: * No IPsec processing required, we'll just send the
176: * packet out.
177: */
178: sproto = 0;
179:
180: /* Fall through to routing/multicast handling */
181: } else {
182: /*
183: * -EINVAL is used to indicate that the packet should
184: * be silently dropped, typically because we've asked
185: * key management for an SA.
186: */
187: if (error == -EINVAL) /* Should silently drop packet */
188: error = 0;
189:
190: goto freecopy;
191: }
192: } else {
193: /* Loop detection */
194: for (mtag = m_tag_first(m); mtag != NULL;
195: mtag = m_tag_next(m, mtag)) {
196: if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
197: mtag->m_tag_id !=
198: PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
199: continue;
200: tdbi = (struct tdb_ident *)(mtag + 1);
201: if (tdbi->spi == tdb->tdb_spi &&
202: tdbi->proto == tdb->tdb_sproto &&
203: !bcmp(&tdbi->dst, &tdb->tdb_dst,
204: sizeof(union sockaddr_union))) {
205: splx(s);
206: sproto = 0; /* mark as no-IPsec-needed */
207: goto done_spd;
208: }
209: }
210:
211: /* We need to do IPsec */
212: bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
213: sspi = tdb->tdb_spi;
214: sproto = tdb->tdb_sproto;
215: splx(s);
216: }
217:
218: /* Fall through to the routing/multicast handling code */
219: done_spd:
220: #endif /* IPSEC */
221:
222: #if NPF > 0
223: rtableid = m->m_pkthdr.pf.rtableid;
224: #endif
225:
226: /*
227: * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
228: * size of IPv6 + ICMPv6 headers) bytes of the packet in case
229: * we need to generate an ICMP6 message to the src.
230: * Thanks to M_EXT, in most cases copy will not occur.
231: *
232: * It is important to save it before IPsec processing as IPsec
233: * processing may modify the mbuf.
234: */
235: mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
236:
237: dst = &ip6_forward_rt.ro_dst;
238: if (!srcrt) {
239: /*
240: * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
241: */
242: if (ip6_forward_rt.ro_rt == 0 ||
243: (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 ||
244: ip6_forward_rtableid != rtableid) {
245: if (ip6_forward_rt.ro_rt) {
246: RTFREE(ip6_forward_rt.ro_rt);
247: ip6_forward_rt.ro_rt = 0;
248: }
249: /* this probably fails but give it a try again */
250: rtalloc_mpath((struct route *)&ip6_forward_rt,
251: &ip6->ip6_src.s6_addr32[0], rtableid);
252: ip6_forward_rtableid = rtableid;
253: }
254:
255: if (ip6_forward_rt.ro_rt == 0) {
256: ip6stat.ip6s_noroute++;
257: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
258: if (mcopy) {
259: icmp6_error(mcopy, ICMP6_DST_UNREACH,
260: ICMP6_DST_UNREACH_NOROUTE, 0);
261: }
262: m_freem(m);
263: return;
264: }
265: } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
266: !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
267: if (ip6_forward_rt.ro_rt) {
268: RTFREE(ip6_forward_rt.ro_rt);
269: ip6_forward_rt.ro_rt = 0;
270: }
271: bzero(dst, sizeof(*dst));
272: dst->sin6_len = sizeof(struct sockaddr_in6);
273: dst->sin6_family = AF_INET6;
274: dst->sin6_addr = ip6->ip6_dst;
275:
276: rtalloc_mpath((struct route *)&ip6_forward_rt,
277: &ip6->ip6_src.s6_addr32[0], 0);
278:
279: if (ip6_forward_rt.ro_rt == 0) {
280: ip6stat.ip6s_noroute++;
281: /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
282: if (mcopy) {
283: icmp6_error(mcopy, ICMP6_DST_UNREACH,
284: ICMP6_DST_UNREACH_NOROUTE, 0);
285: }
286: m_freem(m);
287: return;
288: }
289: }
290: rt = ip6_forward_rt.ro_rt;
291:
292: /*
293: * Scope check: if a packet can't be delivered to its destination
294: * for the reason that the destination is beyond the scope of the
295: * source address, discard the packet and return an icmp6 destination
296: * unreachable error with Code 2 (beyond scope of source address).
297: * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
298: */
299: if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
300: in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
301: ip6stat.ip6s_cantforward++;
302: ip6stat.ip6s_badscope++;
303: in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
304:
305: if (ip6_log_time + ip6_log_interval < time_second) {
306: ip6_log_time = time_second;
307: log(LOG_DEBUG,
308: "cannot forward "
309: "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
310: ip6_sprintf(&ip6->ip6_src),
311: ip6_sprintf(&ip6->ip6_dst),
312: ip6->ip6_nxt,
313: m->m_pkthdr.rcvif->if_xname, rt->rt_ifp->if_xname);
314: }
315: if (mcopy)
316: icmp6_error(mcopy, ICMP6_DST_UNREACH,
317: ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
318: m_freem(m);
319: goto freert;
320: }
321:
322: #ifdef IPSEC
323: /*
324: * Check if the packet needs encapsulation.
325: * ipsp_process_packet will never come back to here.
326: * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
327: * PMTU notification. is it okay?
328: */
329: if (sproto != 0) {
330: s = splnet();
331:
332: tdb = gettdb(sspi, &sdst, sproto);
333: if (tdb == NULL) {
334: splx(s);
335: error = EHOSTUNREACH;
336: m_freem(m);
337: goto senderr; /*XXX*/
338: }
339:
340: m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
341:
342: /* Callee frees mbuf */
343: error = ipsp_process_packet(m, tdb, AF_INET6, 0);
344: splx(s);
345: m_freem(mcopy);
346: goto freert;
347: }
348: #endif /* IPSEC */
349:
350: if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
351: in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
352: if (mcopy) {
353: u_long mtu;
354:
355: mtu = IN6_LINKMTU(rt->rt_ifp);
356:
357: icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
358: }
359: m_freem(m);
360: goto freert;
361: }
362:
363: if (rt->rt_flags & RTF_GATEWAY)
364: dst = (struct sockaddr_in6 *)rt->rt_gateway;
365:
366: /*
367: * If we are to forward the packet using the same interface
368: * as one we got the packet from, perhaps we should send a redirect
369: * to sender to shortcut a hop.
370: * Only send redirect if source is sending directly to us,
371: * and if packet was not source routed (or has any options).
372: * Also, don't send redirect if forwarding using a route
373: * modified by a redirect.
374: */
375: if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects &&
376: (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
377: if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
378: nd6_is_addr_neighbor((struct sockaddr_in6 *)&ip6_forward_rt.ro_dst, rt->rt_ifp)) {
379: /*
380: * If the incoming interface is equal to the outgoing
381: * one, the link attached to the interface is
382: * point-to-point, and the IPv6 destination is
383: * regarded as on-link on the link, then it will be
384: * highly probable that the destination address does
385: * not exist on the link and that the packet is going
386: * to loop. Thus, we immediately drop the packet and
387: * send an ICMPv6 error message.
388: * For other routing loops, we dare to let the packet
389: * go to the loop, so that a remote diagnosing host
390: * can detect the loop by traceroute.
391: * type/code is based on suggestion by Rich Draves.
392: * not sure if it is the best pick.
393: */
394: icmp6_error(mcopy, ICMP6_DST_UNREACH,
395: ICMP6_DST_UNREACH_ADDR, 0);
396: m_freem(m);
397: goto freert;
398: }
399: type = ND_REDIRECT;
400: }
401:
402: /*
403: * Fake scoped addresses. Note that even link-local source or
404: * destinaion can appear, if the originating node just sends the
405: * packet to us (without address resolution for the destination).
406: * Since both icmp6_error and icmp6_redirect_output fill the embedded
407: * link identifiers, we can do this stuff after making a copy for
408: * returning an error.
409: */
410: if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
411: /*
412: * See corresponding comments in ip6_output.
413: * XXX: but is it possible that ip6_forward() sends a packet
414: * to a loopback interface? I don't think so, and thus
415: * I bark here. (jinmei@kame.net)
416: * XXX: it is common to route invalid packets to loopback.
417: * also, the codepath will be visited on use of ::1 in
418: * rthdr. (itojun)
419: */
420: #if 1
421: if (0)
422: #else
423: if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
424: #endif
425: {
426: printf("ip6_forward: outgoing interface is loopback. "
427: "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
428: ip6_sprintf(&ip6->ip6_src),
429: ip6_sprintf(&ip6->ip6_dst),
430: ip6->ip6_nxt, m->m_pkthdr.rcvif->if_xname,
431: rt->rt_ifp->if_xname);
432: }
433:
434: /* we can just use rcvif in forwarding. */
435: origifp = m->m_pkthdr.rcvif;
436: }
437: else
438: origifp = rt->rt_ifp;
439: if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
440: ip6->ip6_src.s6_addr16[1] = 0;
441: if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
442: ip6->ip6_dst.s6_addr16[1] = 0;
443:
444: #if NPF > 0
445: if (pf_test6(PF_OUT, rt->rt_ifp, &m, NULL) != PF_PASS) {
446: m_freem(m);
447: goto senderr;
448: }
449: if (m == NULL)
450: goto senderr;
451:
452: ip6 = mtod(m, struct ip6_hdr *);
453: #endif
454:
455: error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
456: if (error) {
457: in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
458: ip6stat.ip6s_cantforward++;
459: } else {
460: ip6stat.ip6s_forward++;
461: in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
462: if (type)
463: ip6stat.ip6s_redirectsent++;
464: else {
465: if (mcopy)
466: goto freecopy;
467: }
468: }
469:
470: #if NPF > 0 || defined(IPSEC)
471: senderr:
472: #endif
473: if (mcopy == NULL)
474: goto freert;
475: switch (error) {
476: case 0:
477: if (type == ND_REDIRECT) {
478: icmp6_redirect_output(mcopy, rt);
479: goto freert;
480: }
481: goto freecopy;
482:
483: case EMSGSIZE:
484: /* xxx MTU is constant in PPP? */
485: goto freecopy;
486:
487: case ENOBUFS:
488: /* Tell source to slow down like source quench in IP? */
489: goto freecopy;
490:
491: case ENETUNREACH: /* shouldn't happen, checked above */
492: case EHOSTUNREACH:
493: case ENETDOWN:
494: case EHOSTDOWN:
495: default:
496: type = ICMP6_DST_UNREACH;
497: code = ICMP6_DST_UNREACH_ADDR;
498: break;
499: }
500: icmp6_error(mcopy, type, code, 0);
501: goto freert;
502:
503: freecopy:
504: m_freem(mcopy);
505: freert:
506: #ifndef SMALL_KERNEL
507: if (ip6_multipath && ip6_forward_rt.ro_rt &&
508: (ip6_forward_rt.ro_rt->rt_flags & RTF_MPATH)) {
509: RTFREE(ip6_forward_rt.ro_rt);
510: ip6_forward_rt.ro_rt = 0;
511: }
512: #endif
513: return;
514: }
CVSweb