1 /* $OpenBSD: ip6_forward.c,v 1.125 2025/01/03 21:27:40 bluhm 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/mbuf.h> 38 #include <sys/socket.h> 39 #include <sys/errno.h> 40 #include <sys/time.h> 41 #include <sys/kernel.h> 42 #include <sys/syslog.h> 43 44 #include <net/if.h> 45 #include <net/if_var.h> 46 #include <net/if_enc.h> 47 #include <net/route.h> 48 #if NPF > 0 49 #include <net/pfvar.h> 50 #endif 51 52 #include <netinet/in.h> 53 #include <netinet/ip_var.h> 54 #include <netinet6/in6_var.h> 55 #include <netinet/ip6.h> 56 #include <netinet6/ip6_var.h> 57 #include <netinet/icmp6.h> 58 #include <netinet6/nd6.h> 59 #include <netinet/udp.h> 60 #include <netinet/tcp.h> 61 #include <netinet/tcp_timer.h> 62 #include <netinet/tcp_var.h> 63 #ifdef IPSEC 64 #include <netinet/ip_ipsp.h> 65 #include <netinet/ip_ah.h> 66 #include <netinet/ip_esp.h> 67 #endif 68 69 /* 70 * Forward a packet. If some error occurs return the sender 71 * an icmp packet. Note we can't always generate a meaningful 72 * icmp message because icmp doesn't have a large enough repertoire 73 * of codes and types. 74 * 75 * If not forwarding, just drop the packet. This could be confusing 76 * if ip6_forwarding was zero but some routing protocol was advancing 77 * us as a gateway to somewhere. However, we must let the routing 78 * protocol deal with that. 79 * 80 */ 81 82 void 83 ip6_forward(struct mbuf *m, struct route *ro, int flags) 84 { 85 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 86 struct route iproute; 87 struct rtentry *rt; 88 struct sockaddr *dst; 89 struct ifnet *ifp = NULL; 90 u_int rtableid = m->m_pkthdr.ph_rtableid; 91 u_int ifidx = m->m_pkthdr.ph_ifidx; 92 u_int8_t loopcnt = m->m_pkthdr.ph_loopcnt; 93 u_int icmp_len; 94 char icmp_buf[MHLEN]; 95 CTASSERT(sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + 96 MAX_TCPOPTLEN <= sizeof(icmp_buf)); 97 u_short mflags, pfflags; 98 struct mbuf *mcopy; 99 int error = 0, type = 0, code = 0, destmtu = 0; 100 #ifdef IPSEC 101 struct tdb *tdb = NULL; 102 #endif /* IPSEC */ 103 char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN]; 104 105 /* 106 * Do not forward packets to multicast destination (should be handled 107 * by ip6_mforward(). 108 * Do not forward packets with unspecified source. It was discussed 109 * in July 2000, on ipngwg mailing list. 110 */ 111 if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || 112 IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || 113 IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { 114 time_t uptime; 115 116 ip6stat_inc(ip6s_cantforward); 117 uptime = getuptime(); 118 119 if (ip6_log_time + ip6_log_interval < uptime) { 120 ip6_log_time = uptime; 121 inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6)); 122 inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6)); 123 log(LOG_DEBUG, 124 "cannot forward " 125 "from %s to %s nxt %d received on interface %u\n", 126 src6, dst6, ip6->ip6_nxt, ifidx); 127 } 128 m_freem(m); 129 goto done; 130 } 131 132 if (ip6->ip6_hlim <= IPV6_HLIMDEC) { 133 icmp6_error(m, ICMP6_TIME_EXCEEDED, 134 ICMP6_TIME_EXCEED_TRANSIT, 0); 135 goto done; 136 } 137 ip6->ip6_hlim -= IPV6_HLIMDEC; 138 139 /* 140 * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU - 141 * size of IPv6 + ICMPv6 headers) bytes of the packet in case 142 * we need to generate an ICMP6 message to the src. 143 * Thanks to M_EXT, in most cases copy will not occur. 144 * For small packets copy original onto stack instead of mbuf. 145 * 146 * For final protocol header like TCP or UDP, full header chain in 147 * ICMP6 packet is not necessary. In this case only copy small 148 * part of original packet and save it on stack instead of mbuf. 149 * Although this violates RFC 4443 2.4. (c), it avoids additional 150 * mbuf allocations. Also pf nat and rdr do not affect the shared 151 * mbuf cluster. 152 * 153 * It is important to save it before IPsec processing as IPsec 154 * processing may modify the mbuf. 155 */ 156 switch (ip6->ip6_nxt) { 157 case IPPROTO_TCP: 158 icmp_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + 159 MAX_TCPOPTLEN; 160 break; 161 case IPPROTO_UDP: 162 icmp_len = sizeof(struct ip6_hdr) + sizeof(struct udphdr); 163 break; 164 case IPPROTO_ESP: 165 icmp_len = sizeof(struct ip6_hdr) + 2 * sizeof(u_int32_t); 166 break; 167 default: 168 icmp_len = ICMPV6_PLD_MAXLEN; 169 break; 170 } 171 if (icmp_len > m->m_pkthdr.len) 172 icmp_len = m->m_pkthdr.len; 173 if (icmp_len <= sizeof(icmp_buf)) { 174 mflags = m->m_flags; 175 pfflags = m->m_pkthdr.pf.flags; 176 m_copydata(m, 0, icmp_len, icmp_buf); 177 mcopy = NULL; 178 } else { 179 mcopy = m_copym(m, 0, icmp_len, M_NOWAIT); 180 icmp_len = 0; 181 } 182 183 #if NPF > 0 184 reroute: 185 #endif 186 187 #ifdef IPSEC 188 if (ipsec_in_use) { 189 error = ip6_output_ipsec_lookup(m, NULL, &tdb); 190 if (error) { 191 /* 192 * -EINVAL is used to indicate that the packet should 193 * be silently dropped, typically because we've asked 194 * key management for an SA. 195 */ 196 if (error == -EINVAL) /* Should silently drop packet */ 197 error = 0; 198 199 m_freem(m); 200 goto freecopy; 201 } 202 } 203 #endif /* IPSEC */ 204 205 if (ro == NULL) { 206 ro = &iproute; 207 ro->ro_rt = NULL; 208 } 209 rt = route6_mpath(ro, &ip6->ip6_dst, &ip6->ip6_src, 210 m->m_pkthdr.ph_rtableid); 211 if (rt == NULL) { 212 ip6stat_inc(ip6s_noroute); 213 type = ICMP6_DST_UNREACH; 214 code = ICMP6_DST_UNREACH_NOROUTE; 215 m_freem(m); 216 goto icmperror; 217 } 218 dst = &ro->ro_dstsa; 219 220 /* 221 * Scope check: if a packet can't be delivered to its destination 222 * for the reason that the destination is beyond the scope of the 223 * source address, discard the packet and return an icmp6 destination 224 * unreachable error with Code 2 (beyond scope of source address). 225 * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] 226 */ 227 if (in6_addr2scopeid(ifidx, &ip6->ip6_src) != 228 in6_addr2scopeid(rt->rt_ifidx, &ip6->ip6_src)) { 229 time_t uptime; 230 231 ip6stat_inc(ip6s_cantforward); 232 ip6stat_inc(ip6s_badscope); 233 uptime = getuptime(); 234 235 if (ip6_log_time + ip6_log_interval < uptime) { 236 ip6_log_time = uptime; 237 inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6)); 238 inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6)); 239 log(LOG_DEBUG, 240 "cannot forward " 241 "src %s, dst %s, nxt %d, rcvif %u, outif %u\n", 242 src6, dst6, ip6->ip6_nxt, ifidx, rt->rt_ifidx); 243 } 244 type = ICMP6_DST_UNREACH; 245 code = ICMP6_DST_UNREACH_BEYONDSCOPE; 246 m_freem(m); 247 goto icmperror; 248 } 249 250 #ifdef IPSEC 251 /* 252 * Check if the packet needs encapsulation. 253 * ipsp_process_packet will never come back to here. 254 */ 255 if (tdb != NULL) { 256 /* Callee frees mbuf */ 257 error = ip6_output_ipsec_send(tdb, m, ro, 0, 1); 258 rt = ro->ro_rt; 259 if (error) 260 goto senderr; 261 goto freecopy; 262 } 263 #endif /* IPSEC */ 264 265 if (rt->rt_flags & RTF_GATEWAY) 266 dst = rt->rt_gateway; 267 268 /* 269 * If we are to forward the packet using the same interface 270 * as one we got the packet from, perhaps we should send a redirect 271 * to sender to shortcut a hop. 272 * Only send redirect if source is sending directly to us, 273 * and if packet was not source routed (or has any options). 274 * Also, don't send redirect if forwarding using a route 275 * modified by a redirect. 276 */ 277 ifp = if_get(rt->rt_ifidx); 278 if (ifp == NULL) { 279 m_freem(m); 280 goto freecopy; 281 } 282 if (rt->rt_ifidx == ifidx && 283 !ISSET(rt->rt_flags, RTF_DYNAMIC|RTF_MODIFIED) && 284 !ISSET(flags, IPV6_REDIRECT) && 285 atomic_load_int(&ip6_sendredirects)) { 286 if ((ifp->if_flags & IFF_POINTOPOINT) && 287 nd6_is_addr_neighbor(&ro->ro_dstsin6, ifp)) { 288 /* 289 * If the incoming interface is equal to the outgoing 290 * one, the link attached to the interface is 291 * point-to-point, and the IPv6 destination is 292 * regarded as on-link on the link, then it will be 293 * highly probable that the destination address does 294 * not exist on the link and that the packet is going 295 * to loop. Thus, we immediately drop the packet and 296 * send an ICMPv6 error message. 297 * For other routing loops, we dare to let the packet 298 * go to the loop, so that a remote diagnosing host 299 * can detect the loop by traceroute. 300 * type/code is based on suggestion by Rich Draves. 301 * not sure if it is the best pick. 302 */ 303 type = ICMP6_DST_UNREACH; 304 code = ICMP6_DST_UNREACH_ADDR; 305 m_freem(m); 306 goto icmperror; 307 } 308 type = ND_REDIRECT; 309 } 310 311 /* 312 * Fake scoped addresses. Note that even link-local source or 313 * destination can appear, if the originating node just sends the 314 * packet to us (without address resolution for the destination). 315 * Since both icmp6_error and icmp6_redirect_output fill the embedded 316 * link identifiers, we can do this stuff after making a copy for 317 * returning an error. 318 */ 319 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 320 ip6->ip6_src.s6_addr16[1] = 0; 321 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 322 ip6->ip6_dst.s6_addr16[1] = 0; 323 324 #if NPF > 0 325 if (pf_test(AF_INET6, PF_FWD, ifp, &m) != PF_PASS) { 326 m_freem(m); 327 goto senderr; 328 } 329 if (m == NULL) 330 goto senderr; 331 ip6 = mtod(m, struct ip6_hdr *); 332 if ((m->m_pkthdr.pf.flags & (PF_TAG_REROUTE | PF_TAG_GENERATED)) == 333 (PF_TAG_REROUTE | PF_TAG_GENERATED)) { 334 /* already rerun the route lookup, go on */ 335 m->m_pkthdr.pf.flags &= ~(PF_TAG_GENERATED | PF_TAG_REROUTE); 336 } else if (m->m_pkthdr.pf.flags & PF_TAG_REROUTE) { 337 /* tag as generated to skip over pf_test on rerun */ 338 m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 339 SET(flags, IPV6_REDIRECT); 340 if (ro == &iproute) 341 rtfree(ro->ro_rt); 342 ro = NULL; 343 if_put(ifp); 344 ifp = NULL; 345 goto reroute; 346 } 347 #endif 348 349 #ifdef IPSEC 350 if (ISSET(flags, IPV6_FORWARDING) && 351 ISSET(flags, IPV6_FORWARDING_IPSEC) && 352 !ISSET(m->m_pkthdr.ph_tagsset, PACKET_TAG_IPSEC_IN_DONE)) { 353 error = EHOSTUNREACH; 354 goto senderr; 355 } 356 #endif 357 358 error = if_output_tso(ifp, &m, dst, rt, ifp->if_mtu); 359 if (error) 360 ip6stat_inc(ip6s_cantforward); 361 else if (m == NULL) 362 ip6stat_inc(ip6s_forward); 363 if (error || m == NULL) 364 goto senderr; 365 366 type = ICMP6_PACKET_TOO_BIG; 367 destmtu = ifp->if_mtu; 368 m_freem(m); 369 goto icmperror; 370 371 senderr: 372 if (mcopy == NULL && icmp_len == 0) 373 goto done; 374 375 switch (error) { 376 case 0: 377 if (type == ND_REDIRECT) { 378 if (icmp_len != 0) { 379 mcopy = m_gethdr(M_DONTWAIT, MT_DATA); 380 if (mcopy == NULL) 381 goto done; 382 mcopy->m_len = mcopy->m_pkthdr.len = icmp_len; 383 mcopy->m_flags |= (mflags & M_COPYFLAGS); 384 mcopy->m_pkthdr.ph_rtableid = rtableid; 385 mcopy->m_pkthdr.ph_ifidx = ifidx; 386 mcopy->m_pkthdr.ph_loopcnt = loopcnt; 387 mcopy->m_pkthdr.pf.flags |= 388 (pfflags & PF_TAG_GENERATED); 389 memcpy(mcopy->m_data, icmp_buf, icmp_len); 390 } 391 if (mcopy != NULL) { 392 icmp6_redirect_output(mcopy, rt); 393 ip6stat_inc(ip6s_redirectsent); 394 } 395 goto done; 396 } 397 goto freecopy; 398 399 case EMSGSIZE: 400 type = ICMP6_PACKET_TOO_BIG; 401 if (rt != NULL) { 402 u_int rtmtu; 403 404 rtmtu = atomic_load_int(&rt->rt_mtu); 405 if (rtmtu != 0) { 406 destmtu = rtmtu; 407 } else { 408 struct ifnet *destifp; 409 410 destifp = if_get(rt->rt_ifidx); 411 if (destifp != NULL) 412 destmtu = destifp->if_mtu; 413 if_put(destifp); 414 } 415 } 416 ip6stat_inc(ip6s_cantfrag); 417 if (destmtu == 0) 418 goto freecopy; 419 break; 420 421 case EACCES: 422 /* 423 * pf(4) blocked the packet. There is no need to send an ICMP 424 * packet back since pf(4) takes care of it. 425 */ 426 goto freecopy; 427 428 case ENOBUFS: 429 /* Tell source to slow down like source quench in IP? */ 430 goto freecopy; 431 432 case ENETUNREACH: /* shouldn't happen, checked above */ 433 case EHOSTUNREACH: 434 case ENETDOWN: 435 case EHOSTDOWN: 436 default: 437 type = ICMP6_DST_UNREACH; 438 code = ICMP6_DST_UNREACH_ADDR; 439 break; 440 } 441 icmperror: 442 if (icmp_len != 0) { 443 mcopy = m_gethdr(M_DONTWAIT, MT_DATA); 444 if (mcopy == NULL) 445 goto done; 446 mcopy->m_len = mcopy->m_pkthdr.len = icmp_len; 447 mcopy->m_flags |= (mflags & M_COPYFLAGS); 448 mcopy->m_pkthdr.ph_rtableid = rtableid; 449 mcopy->m_pkthdr.ph_ifidx = ifidx; 450 mcopy->m_pkthdr.ph_loopcnt = loopcnt; 451 mcopy->m_pkthdr.pf.flags |= (pfflags & PF_TAG_GENERATED); 452 memcpy(mcopy->m_data, icmp_buf, icmp_len); 453 } 454 if (mcopy != NULL) 455 icmp6_error(mcopy, type, code, destmtu); 456 goto done; 457 458 freecopy: 459 m_freem(mcopy); 460 done: 461 if (ro == &iproute) 462 rtfree(ro->ro_rt); 463 if_put(ifp); 464 #ifdef IPSEC 465 tdb_unref(tdb); 466 #endif /* IPSEC */ 467 } 468