ip6_forward.c revision 59391
1/* 2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sys/netinet6/ip6_forward.c 59391 2000-04-19 14:58:28Z phk $ 30 */ 31 32#include "opt_ipsec.h" 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/mbuf.h> 37#include <sys/domain.h> 38#include <sys/protosw.h> 39#include <sys/socket.h> 40#include <sys/errno.h> 41#include <sys/time.h> 42#include <sys/kernel.h> 43#include <sys/syslog.h> 44 45#include <net/if.h> 46#include <net/route.h> 47 48#include <netinet/in.h> 49#include <netinet/in_var.h> 50#include <netinet6/ip6.h> 51#include <netinet6/ip6_var.h> 52#include <netinet6/icmp6.h> 53#include <netinet6/nd6.h> 54 55#ifdef IPSEC_IPV6FWD 56#include <netinet6/ipsec.h> 57#include <netinet6/ipsec6.h> 58#include <netkey/key.h> 59#ifdef IPSEC_DEBUG 60#include <netkey/key_debug.h> 61#else 62#define KEYDEBUG(lev,arg) 63#endif 64#endif /* IPSEC_IPV6FWD */ 65 66#ifdef IPV6FIREWALL 67#include <netinet6/ip6_fw.h> 68#endif 69 70#include <net/net_osdep.h> 71 72struct 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 87void 88ip6_forward(m, srcrt) 89 struct mbuf *m; 90 int srcrt; 91{ 92 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 93 register struct sockaddr_in6 *dst; 94 register struct rtentry *rt; 95 int error, type = 0, code = 0; 96 struct mbuf *mcopy; 97#ifdef IPSEC_IPV6FWD 98 struct secpolicy *sp = NULL; 99#endif 100 101#ifdef IPSEC_IPV6FWD 102 /* 103 * Check AH/ESP integrity. 104 */ 105 /* 106 * Don't increment ip6s_cantforward because this is the check 107 * before forwarding packet actually. 108 */ 109 if (ipsec6_in_reject(m, NULL)) { 110 ipsec6stat.in_polvio++; 111 m_freem(m); 112 return; 113 } 114#endif /*IPSEC_IPV6FWD*/ 115 116 if (m->m_flags & (M_BCAST|M_MCAST) || 117 in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) { 118 ip6stat.ip6s_cantforward++; 119 ip6stat.ip6s_badscope++; 120 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ 121 if (ip6_log_time + ip6_log_interval < time_second) { 122 char addr[INET6_ADDRSTRLEN]; 123 ip6_log_time = time_second; 124 strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr)); 125 log(LOG_DEBUG, 126 "cannot forward " 127 "from %s to %s nxt %d received on %s\n", 128 addr, ip6_sprintf(&ip6->ip6_dst), 129 ip6->ip6_nxt, 130 if_name(m->m_pkthdr.rcvif)); 131 } 132 m_freem(m); 133 return; 134 } 135 136 if (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 ip6->ip6_hlim -= IPV6_HLIMDEC; 143 144#ifdef IPSEC_IPV6FWD 145 /* get a security policy for this packet */ 146 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); 147 if (sp == NULL) { 148 ipsec6stat.out_inval++; 149 ip6stat.ip6s_cantforward++; 150 /* XXX: any icmp ? */ 151 m_freem(m); 152 return; 153 } 154 155 error = 0; 156 157 /* check policy */ 158 switch (sp->policy) { 159 case IPSEC_POLICY_DISCARD: 160 /* 161 * This packet is just discarded. 162 */ 163 ipsec6stat.out_polvio++; 164 ip6stat.ip6s_cantforward++; 165 key_freesp(sp); 166 /* XXX: any icmp ? */ 167 m_freem(m); 168 return; 169 170 case IPSEC_POLICY_BYPASS: 171 case IPSEC_POLICY_NONE: 172 /* no need to do IPsec. */ 173 key_freesp(sp); 174 goto skip_ipsec; 175 176 case IPSEC_POLICY_IPSEC: 177 if (sp->req == NULL) { 178 /* XXX should be panic ? */ 179 printf("ip6_forward: No IPsec request specified.\n"); 180 ip6stat.ip6s_cantforward++; 181 key_freesp(sp); 182 /* XXX: any icmp ? */ 183 m_freem(m); 184 return; 185 } 186 /* do IPsec */ 187 break; 188 189 case IPSEC_POLICY_ENTRUST: 190 default: 191 /* should be panic ?? */ 192 printf("ip6_forward: Invalid policy found. %d\n", sp->policy); 193 key_freesp(sp); 194 goto skip_ipsec; 195 } 196 197 { 198 struct ipsec_output_state state; 199 200 /* 201 * All the extension headers will become inaccessible 202 * (since they can be encrypted). 203 * Don't panic, we need no more updates to extension headers 204 * on inner IPv6 packet (since they are now encapsulated). 205 * 206 * IPv6 [ESP|AH] IPv6 [extension headers] payload 207 */ 208 bzero(&state, sizeof(state)); 209 state.m = m; 210 state.ro = NULL; /* update at ipsec6_output_tunnel() */ 211 state.dst = NULL; /* update at ipsec6_output_tunnel() */ 212 213 error = ipsec6_output_tunnel(&state, sp, 0); 214 215 m = state.m; 216 /* XXX allocate a route (ro, dst) again later */ 217 key_freesp(sp); 218 219 if (error) { 220 /* mbuf is already reclaimed in ipsec6_output_tunnel. */ 221 switch (error) { 222 case EHOSTUNREACH: 223 case ENETUNREACH: 224 case EMSGSIZE: 225 case ENOBUFS: 226 case ENOMEM: 227 break; 228 default: 229 printf("ip6_output (ipsec): error code %d\n", error); 230 /*fall through*/ 231 case ENOENT: 232 /* don't show these error codes to the user */ 233 break; 234 } 235 ip6stat.ip6s_cantforward++; 236 /* XXX: any icmp ? */ 237 m_freem(m); 238 return; 239 } 240 } 241 skip_ipsec: 242#endif /* IPSEC_IPV6FWD */ 243 244 dst = &ip6_forward_rt.ro_dst; 245 if (!srcrt) { 246 /* 247 * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst 248 */ 249 if (ip6_forward_rt.ro_rt == 0 || 250 (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) { 251 if (ip6_forward_rt.ro_rt) { 252 RTFREE(ip6_forward_rt.ro_rt); 253 ip6_forward_rt.ro_rt = 0; 254 } 255 /* this probably fails but give it a try again */ 256 rtalloc_ign((struct route *)&ip6_forward_rt, 257 RTF_PRCLONING); 258 } 259 260 if (ip6_forward_rt.ro_rt == 0) { 261 ip6stat.ip6s_noroute++; 262 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ 263 icmp6_error(m, ICMP6_DST_UNREACH, 264 ICMP6_DST_UNREACH_NOROUTE, 0); 265 return; 266 } 267 } else if ((rt = ip6_forward_rt.ro_rt) == 0 || 268 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) { 269 if (ip6_forward_rt.ro_rt) { 270 RTFREE(ip6_forward_rt.ro_rt); 271 ip6_forward_rt.ro_rt = 0; 272 } 273 bzero(dst, sizeof(*dst)); 274 dst->sin6_len = sizeof(struct sockaddr_in6); 275 dst->sin6_family = AF_INET6; 276 dst->sin6_addr = ip6->ip6_dst; 277 278 rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); 279 if (ip6_forward_rt.ro_rt == 0) { 280 ip6stat.ip6s_noroute++; 281 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */ 282 icmp6_error(m, ICMP6_DST_UNREACH, 283 ICMP6_DST_UNREACH_NOROUTE, 0); 284 return; 285 } 286 } 287 rt = ip6_forward_rt.ro_rt; 288 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu){ 289 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); 290 icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, rt->rt_ifp->if_mtu); 291 return; 292 } 293 294 if (rt->rt_flags & RTF_GATEWAY) 295 dst = (struct sockaddr_in6 *)rt->rt_gateway; 296 /* 297 * Save at most 528 bytes of the packet in case 298 * we need to generate an ICMP6 message to the src. 299 * Thanks to M_EXT, in most cases copy will not occur. 300 */ 301 mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); 302 303 /* 304 * If we are to forward the packet using the same interface 305 * as one we got the packet from, perhaps we should send a redirect 306 * to sender to shortcut a hop. 307 * Only send redirect if source is sending directly to us, 308 * and if packet was not source routed (or has any options). 309 * Also, don't send redirect if forwarding using a route 310 * modified by a redirect. 311 */ 312 if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && 313 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) 314 type = ND_REDIRECT; 315 316#ifdef IPV6FIREWALL 317 /* 318 * Check with the firewall... 319 */ 320 if (ip6_fw_chk_ptr) { 321 u_short port = 0; 322 /* If ipfw says divert, we have to just drop packet */ 323 if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) { 324 m_freem(m); 325 goto freecopy; 326 } 327 if (!m) 328 goto freecopy; 329 } 330#endif 331 332 error = nd6_output(rt->rt_ifp, m, dst, rt); 333 if (error) { 334 in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard); 335 ip6stat.ip6s_cantforward++; 336 } else { 337 ip6stat.ip6s_forward++; 338 in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward); 339 if (type) 340 ip6stat.ip6s_redirectsent++; 341 else { 342 if (mcopy) 343 goto freecopy; 344 } 345 } 346 if (mcopy == NULL) 347 return; 348 349 switch (error) { 350 case 0: 351 if (type == ND_REDIRECT) { 352 icmp6_redirect_output(mcopy, rt); 353 return; 354 } 355 goto freecopy; 356 357 case EMSGSIZE: 358 /* xxx MTU is constant in PPP? */ 359 goto freecopy; 360 361 case ENOBUFS: 362 /* Tell source to slow down like source quench in IP? */ 363 goto freecopy; 364 365 case ENETUNREACH: /* shouldn't happen, checked above */ 366 case EHOSTUNREACH: 367 case ENETDOWN: 368 case EHOSTDOWN: 369 default: 370 type = ICMP6_DST_UNREACH; 371 code = ICMP6_DST_UNREACH_ADDR; 372 break; 373 } 374 icmp6_error(mcopy, type, code, 0); 375 return; 376 377 freecopy: 378 m_freem(mcopy); 379 return; 380} 381