File: | netinet6/ip6_forward.c |
Warning: | line 193, column 23 Access to field 'rt_ifidx' results in a dereference of a null pointer (loaded from variable 'rt') |
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; | |||
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
| |||
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 | } |