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