File: | netinet6/ip6_forward.c |
Warning: | line 160, column 5 Value stored to 'error' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ip6_forward.c,v 1.112 2023/07/07 08:05:02 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 | |
49 | #include <netinet/in.h> |
50 | #include <netinet/ip_var.h> |
51 | #include <netinet6/in6_var.h> |
52 | #include <netinet/ip6.h> |
53 | #include <netinet6/ip6_var.h> |
54 | #include <netinet/icmp6.h> |
55 | #include <netinet6/nd6.h> |
56 | |
57 | #if NPF1 > 0 |
58 | #include <net/pfvar.h> |
59 | #endif |
60 | |
61 | #ifdef IPSEC1 |
62 | #include <netinet/ip_ipsp.h> |
63 | #include <netinet/ip_ah.h> |
64 | #include <netinet/ip_esp.h> |
65 | #include <netinet/udp.h> |
66 | #endif |
67 | #include <netinet/tcp.h> |
68 | #include <netinet/tcp_timer.h> |
69 | #include <netinet/tcp_var.h> |
70 | |
71 | /* |
72 | * Forward a packet. If some error occurs return the sender |
73 | * an icmp packet. Note we can't always generate a meaningful |
74 | * icmp message because icmp doesn't have a large enough repertoire |
75 | * of codes and types. |
76 | * |
77 | * If not forwarding, just drop the packet. This could be confusing |
78 | * if ipforwarding was zero but some routing protocol was advancing |
79 | * us as a gateway to somewhere. However, we must let the routing |
80 | * protocol deal with that. |
81 | * |
82 | */ |
83 | |
84 | void |
85 | ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt) |
86 | { |
87 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)); |
88 | struct sockaddr_in6 *sin6; |
89 | struct route_in6 ro; |
90 | struct ifnet *ifp = NULL((void *)0); |
91 | int error = 0, type = 0, code = 0, destmtu = 0; |
92 | struct mbuf *mcopy = NULL((void *)0); |
93 | #ifdef IPSEC1 |
94 | struct tdb *tdb = NULL((void *)0); |
95 | #endif /* IPSEC */ |
96 | char src6[INET6_ADDRSTRLEN46], dst6[INET6_ADDRSTRLEN46]; |
97 | |
98 | /* |
99 | * Do not forward packets to multicast destination (should be handled |
100 | * by ip6_mforward(). |
101 | * Do not forward packets with unspecified source. It was discussed |
102 | * in July 2000, on ipngwg mailing list. |
103 | */ |
104 | if ((m->m_flagsm_hdr.mh_flags & (M_BCAST0x0100|M_MCAST0x0200)) != 0 || |
105 | IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)((&ip6->ip6_dst)->__u6_addr.__u6_addr8[0] == 0xff) || |
106 | IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)((*(const u_int32_t *)(const void *)(&(&ip6->ip6_src )->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&ip6->ip6_src)->__u6_addr.__u6_addr8 [4]) == 0) && (*(const u_int32_t *)(const void *)(& (&ip6->ip6_src)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t *)(const void *)(&(&ip6->ip6_src )->__u6_addr.__u6_addr8[12]) == 0))) { |
107 | time_t uptime; |
108 | |
109 | ip6stat_inc(ip6s_cantforward); |
110 | uptime = getuptime(); |
111 | |
112 | if (ip6_log_time + ip6_log_interval < uptime) { |
113 | ip6_log_time = uptime; |
114 | inet_ntop(AF_INET624, &ip6->ip6_src, src6, sizeof(src6)); |
115 | inet_ntop(AF_INET624, &ip6->ip6_dst, dst6, sizeof(dst6)); |
116 | log(LOG_DEBUG7, |
117 | "cannot forward " |
118 | "from %s to %s nxt %d received on interface %u\n", |
119 | src6, dst6, |
120 | ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt, |
121 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx); |
122 | } |
123 | m_freem(m); |
124 | goto out; |
125 | } |
126 | |
127 | if (ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim <= IPV6_HLIMDEC1) { |
128 | icmp6_error(m, ICMP6_TIME_EXCEEDED3, |
129 | ICMP6_TIME_EXCEED_TRANSIT0, 0); |
130 | goto out; |
131 | } |
132 | ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim -= IPV6_HLIMDEC1; |
133 | |
134 | /* |
135 | * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU - |
136 | * size of IPv6 + ICMPv6 headers) bytes of the packet in case |
137 | * we need to generate an ICMP6 message to the src. |
138 | * Thanks to M_EXT, in most cases copy will not occur. |
139 | * |
140 | * It is important to save it before IPsec processing as IPsec |
141 | * processing may modify the mbuf. |
142 | */ |
143 | mcopy = m_copym(m, 0, imin(m->m_pkthdrM_dat.MH.MH_pkthdr.len, ICMPV6_PLD_MAXLEN1232), |
144 | M_NOWAIT0x0002); |
145 | |
146 | #if NPF1 > 0 |
147 | reroute: |
148 | #endif |
149 | |
150 | #ifdef IPSEC1 |
151 | if (ipsec_in_use) { |
152 | error = ip6_output_ipsec_lookup(m, NULL((void *)0), &tdb); |
153 | if (error) { |
154 | /* |
155 | * -EINVAL is used to indicate that the packet should |
156 | * be silently dropped, typically because we've asked |
157 | * key management for an SA. |
158 | */ |
159 | if (error == -EINVAL22) /* Should silently drop packet */ |
160 | error = 0; |
Value stored to 'error' is never read | |
161 | |
162 | m_freem(m); |
163 | goto freecopy; |
164 | } |
165 | } |
166 | #endif /* IPSEC */ |
167 | |
168 | memset(&ro, 0, sizeof(ro))__builtin_memset((&ro), (0), (sizeof(ro))); |
169 | sin6 = &ro.ro_dst; |
170 | sin6->sin6_family = AF_INET624; |
171 | sin6->sin6_len = sizeof(*sin6); |
172 | sin6->sin6_addr = ip6->ip6_dst; |
173 | |
174 | if (!rtisvalid(rt)) { |
175 | rtfree(rt); |
176 | rt = rtalloc_mpath(sin6tosa(sin6), &ip6->ip6_src.s6_addr32__u6_addr.__u6_addr32[0], |
177 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid); |
178 | if (rt == NULL((void *)0)) { |
179 | ip6stat_inc(ip6s_noroute); |
180 | if (mcopy) { |
181 | icmp6_error(mcopy, ICMP6_DST_UNREACH1, |
182 | ICMP6_DST_UNREACH_NOROUTE0, 0); |
183 | } |
184 | m_freem(m); |
185 | goto out; |
186 | } |
187 | } |
188 | |
189 | /* |
190 | * Scope check: if a packet can't be delivered to its destination |
191 | * for the reason that the destination is beyond the scope of the |
192 | * source address, discard the packet and return an icmp6 destination |
193 | * unreachable error with Code 2 (beyond scope of source address). |
194 | * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] |
195 | */ |
196 | if (in6_addr2scopeid(m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx, &ip6->ip6_src) != |
197 | in6_addr2scopeid(rt->rt_ifidx, &ip6->ip6_src)) { |
198 | time_t uptime; |
199 | |
200 | ip6stat_inc(ip6s_cantforward); |
201 | ip6stat_inc(ip6s_badscope); |
202 | uptime = getuptime(); |
203 | |
204 | if (ip6_log_time + ip6_log_interval < uptime) { |
205 | ip6_log_time = uptime; |
206 | inet_ntop(AF_INET624, &ip6->ip6_src, src6, sizeof(src6)); |
207 | inet_ntop(AF_INET624, &ip6->ip6_dst, dst6, sizeof(dst6)); |
208 | log(LOG_DEBUG7, |
209 | "cannot forward " |
210 | "src %s, dst %s, nxt %d, rcvif %u, outif %u\n", |
211 | src6, dst6, |
212 | ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt, |
213 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx, rt->rt_ifidx); |
214 | } |
215 | if (mcopy) |
216 | icmp6_error(mcopy, ICMP6_DST_UNREACH1, |
217 | ICMP6_DST_UNREACH_BEYONDSCOPE2, 0); |
218 | m_freem(m); |
219 | goto out; |
220 | } |
221 | |
222 | #ifdef IPSEC1 |
223 | /* |
224 | * Check if the packet needs encapsulation. |
225 | * ipsp_process_packet will never come back to here. |
226 | */ |
227 | if (tdb != NULL((void *)0)) { |
228 | /* Callee frees mbuf */ |
229 | ro.ro_rt = rt; |
230 | ro.ro_tableid = m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid; |
231 | error = ip6_output_ipsec_send(tdb, m, &ro, 0, 1); |
232 | rt = ro.ro_rt; |
233 | if (error) |
234 | goto senderr; |
235 | goto freecopy; |
236 | } |
237 | #endif /* IPSEC */ |
238 | |
239 | if (rt->rt_flags & RTF_GATEWAY0x2) |
240 | sin6 = satosin6(rt->rt_gateway); |
241 | |
242 | /* |
243 | * If we are to forward the packet using the same interface |
244 | * as one we got the packet from, perhaps we should send a redirect |
245 | * to sender to shortcut a hop. |
246 | * Only send redirect if source is sending directly to us, |
247 | * and if packet was not source routed (or has any options). |
248 | * Also, don't send redirect if forwarding using a route |
249 | * modified by a redirect. |
250 | */ |
251 | ifp = if_get(rt->rt_ifidx); |
252 | if (ifp == NULL((void *)0)) { |
253 | m_freem(m); |
254 | goto freecopy; |
255 | } |
256 | if (rt->rt_ifidx == m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx && !srcrt && |
257 | ip6_sendredirects && |
258 | (rt->rt_flags & (RTF_DYNAMIC0x10|RTF_MODIFIED0x20)) == 0) { |
259 | if ((ifp->if_flags & IFF_POINTOPOINT0x10) && |
260 | nd6_is_addr_neighbor(&ro.ro_dst, ifp)) { |
261 | /* |
262 | * If the incoming interface is equal to the outgoing |
263 | * one, the link attached to the interface is |
264 | * point-to-point, and the IPv6 destination is |
265 | * regarded as on-link on the link, then it will be |
266 | * highly probable that the destination address does |
267 | * not exist on the link and that the packet is going |
268 | * to loop. Thus, we immediately drop the packet and |
269 | * send an ICMPv6 error message. |
270 | * For other routing loops, we dare to let the packet |
271 | * go to the loop, so that a remote diagnosing host |
272 | * can detect the loop by traceroute. |
273 | * type/code is based on suggestion by Rich Draves. |
274 | * not sure if it is the best pick. |
275 | */ |
276 | if (mcopy) |
277 | icmp6_error(mcopy, ICMP6_DST_UNREACH1, |
278 | ICMP6_DST_UNREACH_ADDR3, 0); |
279 | m_freem(m); |
280 | goto out; |
281 | } |
282 | type = ND_REDIRECT137; |
283 | } |
284 | |
285 | /* |
286 | * Fake scoped addresses. Note that even link-local source or |
287 | * destination can appear, if the originating node just sends the |
288 | * packet to us (without address resolution for the destination). |
289 | * Since both icmp6_error and icmp6_redirect_output fill the embedded |
290 | * link identifiers, we can do this stuff after making a copy for |
291 | * returning an error. |
292 | */ |
293 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)(((((&ip6->ip6_src)->__u6_addr.__u6_addr8[0] == 0xfe ) && (((&ip6->ip6_src)->__u6_addr.__u6_addr8 [1] & 0xc0) == 0x80))) || ((((&ip6->ip6_src)->__u6_addr .__u6_addr8[0] == 0xff) && (((&ip6->ip6_src)-> __u6_addr.__u6_addr8[1] & 0x0f) == 0x02))) || ((((&ip6 ->ip6_src)->__u6_addr.__u6_addr8[0] == 0xff) && (((&ip6->ip6_src)->__u6_addr.__u6_addr8[1] & 0x0f ) == 0x01))))) |
294 | ip6->ip6_src.s6_addr16__u6_addr.__u6_addr16[1] = 0; |
295 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)(((((&ip6->ip6_dst)->__u6_addr.__u6_addr8[0] == 0xfe ) && (((&ip6->ip6_dst)->__u6_addr.__u6_addr8 [1] & 0xc0) == 0x80))) || ((((&ip6->ip6_dst)->__u6_addr .__u6_addr8[0] == 0xff) && (((&ip6->ip6_dst)-> __u6_addr.__u6_addr8[1] & 0x0f) == 0x02))) || ((((&ip6 ->ip6_dst)->__u6_addr.__u6_addr8[0] == 0xff) && (((&ip6->ip6_dst)->__u6_addr.__u6_addr8[1] & 0x0f ) == 0x01))))) |
296 | ip6->ip6_dst.s6_addr16__u6_addr.__u6_addr16[1] = 0; |
297 | |
298 | #if NPF1 > 0 |
299 | if (pf_test(AF_INET624, PF_FWD, ifp, &m) != PF_PASS) { |
300 | m_freem(m); |
301 | goto senderr; |
302 | } |
303 | if (m == NULL((void *)0)) |
304 | goto senderr; |
305 | ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)); |
306 | if ((m->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags & (PF_TAG_REROUTE0x20 | PF_TAG_GENERATED0x01)) == |
307 | (PF_TAG_REROUTE0x20 | PF_TAG_GENERATED0x01)) { |
308 | /* already rerun the route lookup, go on */ |
309 | m->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags &= ~(PF_TAG_GENERATED0x01 | PF_TAG_REROUTE0x20); |
310 | } else if (m->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags & PF_TAG_REROUTE0x20) { |
311 | /* tag as generated to skip over pf_test on rerun */ |
312 | m->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags |= PF_TAG_GENERATED0x01; |
313 | srcrt = 1; |
314 | rtfree(rt); |
315 | rt = NULL((void *)0); |
316 | if_put(ifp); |
317 | ifp = NULL((void *)0); |
318 | goto reroute; |
319 | } |
320 | #endif |
321 | |
322 | error = if_output_tso(ifp, &m, sin6tosa(sin6), rt, ifp->if_mtuif_data.ifi_mtu); |
323 | if (error) |
324 | ip6stat_inc(ip6s_cantforward); |
325 | else if (m == NULL((void *)0)) |
326 | ip6stat_inc(ip6s_forward); |
327 | if (error || m == NULL((void *)0)) |
328 | goto senderr; |
329 | |
330 | if (mcopy != NULL((void *)0)) |
331 | icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG2, 0, ifp->if_mtuif_data.ifi_mtu); |
332 | m_freem(m); |
333 | goto out; |
334 | |
335 | senderr: |
336 | if (mcopy == NULL((void *)0)) |
337 | goto out; |
338 | |
339 | switch (error) { |
340 | case 0: |
341 | if (type == ND_REDIRECT137) { |
342 | icmp6_redirect_output(mcopy, rt); |
343 | ip6stat_inc(ip6s_redirectsent); |
344 | goto out; |
345 | } |
346 | goto freecopy; |
347 | |
348 | case EMSGSIZE40: |
349 | type = ICMP6_PACKET_TOO_BIG2; |
350 | code = 0; |
351 | if (rt != NULL((void *)0)) { |
352 | if (rt->rt_mturt_rmx.rmx_mtu) { |
353 | destmtu = rt->rt_mturt_rmx.rmx_mtu; |
354 | } else { |
355 | struct ifnet *destifp; |
356 | |
357 | destifp = if_get(rt->rt_ifidx); |
358 | if (destifp != NULL((void *)0)) |
359 | destmtu = destifp->if_mtuif_data.ifi_mtu; |
360 | if_put(destifp); |
361 | } |
362 | } |
363 | ip6stat_inc(ip6s_cantfrag); |
364 | if (destmtu == 0) |
365 | goto freecopy; |
366 | break; |
367 | |
368 | case EACCES13: |
369 | /* |
370 | * pf(4) blocked the packet. There is no need to send an ICMP |
371 | * packet back since pf(4) takes care of it. |
372 | */ |
373 | goto freecopy; |
374 | |
375 | case ENOBUFS55: |
376 | /* Tell source to slow down like source quench in IP? */ |
377 | goto freecopy; |
378 | |
379 | case ENETUNREACH51: /* shouldn't happen, checked above */ |
380 | case EHOSTUNREACH65: |
381 | case ENETDOWN50: |
382 | case EHOSTDOWN64: |
383 | default: |
384 | type = ICMP6_DST_UNREACH1; |
385 | code = ICMP6_DST_UNREACH_ADDR3; |
386 | break; |
387 | } |
388 | icmp6_error(mcopy, type, code, destmtu); |
389 | goto out; |
390 | |
391 | freecopy: |
392 | m_freem(mcopy); |
393 | out: |
394 | rtfree(rt); |
395 | if_put(ifp); |
396 | #ifdef IPSEC1 |
397 | tdb_unref(tdb); |
398 | #endif /* IPSEC */ |
399 | } |