Line data Source code
1 : /* $OpenBSD: in6_pcb.c,v 1.106 2018/09/11 21:04:03 bluhm Exp $ */
2 :
3 : /*
4 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. Neither the name of the project nor the names of its contributors
16 : * may be used to endorse or promote products derived from this software
17 : * without specific prior written permission.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 : * SUCH DAMAGE.
30 : */
31 :
32 : /*
33 : * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
34 : *
35 : * NRL grants permission for redistribution and use in source and binary
36 : * forms, with or without modification, of the software and documentation
37 : * created at NRL provided that the following conditions are met:
38 : *
39 : * 1. Redistributions of source code must retain the above copyright
40 : * notice, this list of conditions and the following disclaimer.
41 : * 2. Redistributions in binary form must reproduce the above copyright
42 : * notice, this list of conditions and the following disclaimer in the
43 : * documentation and/or other materials provided with the distribution.
44 : * 3. All advertising materials mentioning features or use of this software
45 : * must display the following acknowledgements:
46 : * This product includes software developed by the University of
47 : * California, Berkeley and its contributors.
48 : * This product includes software developed at the Information
49 : * Technology Division, US Naval Research Laboratory.
50 : * 4. Neither the name of the NRL nor the names of its contributors
51 : * may be used to endorse or promote products derived from this software
52 : * without specific prior written permission.
53 : *
54 : * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
55 : * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
57 : * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
58 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
59 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
60 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
61 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
62 : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
63 : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64 : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 : *
66 : * The views and conclusions contained in the software and documentation
67 : * are those of the authors and should not be interpreted as representing
68 : * official policies, either expressed or implied, of the US Naval
69 : * Research Laboratory (NRL).
70 : */
71 :
72 : /*
73 : * Copyright (c) 1982, 1986, 1990, 1993, 1995
74 : * Regents of the University of California. All rights reserved.
75 : *
76 : * Redistribution and use in source and binary forms, with or without
77 : * modification, are permitted provided that the following conditions
78 : * are met:
79 : * 1. Redistributions of source code must retain the above copyright
80 : * notice, this list of conditions and the following disclaimer.
81 : * 2. Redistributions in binary form must reproduce the above copyright
82 : * notice, this list of conditions and the following disclaimer in the
83 : * documentation and/or other materials provided with the distribution.
84 : * 3. Neither the name of the University nor the names of its contributors
85 : * may be used to endorse or promote products derived from this software
86 : * without specific prior written permission.
87 : *
88 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
89 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
92 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98 : * SUCH DAMAGE.
99 : *
100 : */
101 :
102 : #include "pf.h"
103 :
104 : #include <sys/param.h>
105 : #include <sys/systm.h>
106 : #include <sys/mbuf.h>
107 : #include <sys/protosw.h>
108 : #include <sys/socket.h>
109 : #include <sys/socketvar.h>
110 :
111 : #include <net/if.h>
112 : #include <net/if_var.h>
113 : #include <net/pfvar.h>
114 :
115 : #include <netinet/in.h>
116 : #include <netinet/ip.h>
117 : #include <netinet/ip_var.h>
118 : #include <netinet/in_pcb.h>
119 :
120 : #include <netinet6/in6_var.h>
121 :
122 : const struct in6_addr zeroin6_addr;
123 :
124 : struct inpcbhead *
125 0 : in6_pcbhash(struct inpcbtable *table, int rdom,
126 : const struct in6_addr *faddr, u_short fport,
127 : const struct in6_addr *laddr, u_short lport)
128 : {
129 0 : SIPHASH_CTX ctx;
130 0 : u_int32_t nrdom = htonl(rdom);
131 :
132 0 : SipHash24_Init(&ctx, &table->inpt_key);
133 0 : SipHash24_Update(&ctx, &nrdom, sizeof(nrdom));
134 0 : SipHash24_Update(&ctx, faddr, sizeof(*faddr));
135 0 : SipHash24_Update(&ctx, &fport, sizeof(fport));
136 0 : SipHash24_Update(&ctx, laddr, sizeof(*laddr));
137 0 : SipHash24_Update(&ctx, &lport, sizeof(lport));
138 :
139 0 : return (&table->inpt_hashtbl[SipHash24_End(&ctx) & table->inpt_mask]);
140 0 : }
141 :
142 : int
143 0 : in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild,
144 : struct proc *p)
145 : {
146 0 : struct socket *so = inp->inp_socket;
147 0 : struct inpcbtable *table = inp->inp_table;
148 0 : u_short lport = sin6->sin6_port;
149 0 : int reuseport = (so->so_options & SO_REUSEPORT);
150 :
151 0 : wild |= INPLOOKUP_IPV6;
152 : /* KAME hack: embed scopeid */
153 0 : if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0)
154 0 : return (EINVAL);
155 : /* this must be cleared for ifa_ifwithaddr() */
156 0 : sin6->sin6_scope_id = 0;
157 : /* reject IPv4 mapped address, we have no support for it */
158 0 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
159 0 : return (EADDRNOTAVAIL);
160 :
161 0 : if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
162 : /*
163 : * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
164 : * allow complete duplication of binding if
165 : * SO_REUSEPORT is set, or if SO_REUSEADDR is set
166 : * and a multicast address is bound on both
167 : * new and duplicated sockets.
168 : */
169 0 : if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT))
170 0 : reuseport = SO_REUSEADDR | SO_REUSEPORT;
171 0 : } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
172 : struct ifaddr *ifa = NULL;
173 :
174 0 : sin6->sin6_port = 0; /*
175 : * Yechhhh, because of upcoming
176 : * call to ifa_ifwithaddr(), which
177 : * does bcmp's over the PORTS as
178 : * well. (What about flow?)
179 : */
180 0 : sin6->sin6_flowinfo = 0;
181 0 : if (!(so->so_options & SO_BINDANY) &&
182 0 : (ifa = ifa_ifwithaddr(sin6tosa(sin6),
183 0 : inp->inp_rtableid)) == NULL)
184 0 : return (EADDRNOTAVAIL);
185 0 : sin6->sin6_port = lport;
186 :
187 : /*
188 : * bind to an anycast address might accidentally
189 : * cause sending a packet with an anycast source
190 : * address, so we forbid it.
191 : *
192 : * We should allow to bind to a deprecated address,
193 : * since the application dare to use it.
194 : * But, can we assume that they are careful enough
195 : * to check if the address is deprecated or not?
196 : * Maybe, as a safeguard, we should have a setsockopt
197 : * flag to control the bind(2) behavior against
198 : * deprecated addresses (default: forbid bind(2)).
199 : */
200 0 : if (ifa && ifatoia6(ifa)->ia6_flags & (IN6_IFF_ANYCAST|
201 : IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED|IN6_IFF_DETACHED))
202 0 : return (EADDRNOTAVAIL);
203 0 : }
204 0 : if (lport) {
205 : struct inpcb *t;
206 :
207 0 : if (so->so_euid) {
208 0 : t = in_pcblookup_local(table,
209 0 : (struct in_addr *)&sin6->sin6_addr, lport,
210 : INPLOOKUP_WILDCARD | INPLOOKUP_IPV6,
211 0 : inp->inp_rtableid);
212 0 : if (t && (so->so_euid != t->inp_socket->so_euid))
213 0 : return (EADDRINUSE);
214 : }
215 0 : t = in_pcblookup_local(table,
216 0 : (struct in_addr *)&sin6->sin6_addr, lport,
217 0 : wild, inp->inp_rtableid);
218 0 : if (t && (reuseport & t->inp_socket->so_options) == 0)
219 0 : return (EADDRINUSE);
220 0 : }
221 0 : return (0);
222 0 : }
223 :
224 : /*
225 : * Connect from a socket to a specified address.
226 : * Both address and port must be specified in argument sin6.
227 : * Eventually, flow labels will have to be dealt with here, as well.
228 : *
229 : * If don't have a local address for this socket yet,
230 : * then pick one.
231 : */
232 : int
233 0 : in6_pcbconnect(struct inpcb *inp, struct mbuf *nam)
234 : {
235 0 : struct in6_addr *in6a = NULL;
236 0 : struct sockaddr_in6 *sin6;
237 : int error;
238 0 : struct sockaddr_in6 tmp;
239 :
240 0 : KASSERT(inp->inp_flags & INP_IPV6);
241 :
242 0 : if ((error = in6_nam2sin6(nam, &sin6)))
243 0 : return (error);
244 0 : if (sin6->sin6_port == 0)
245 0 : return (EADDRNOTAVAIL);
246 : /* reject IPv4 mapped address, we have no support for it */
247 0 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
248 0 : return (EADDRNOTAVAIL);
249 :
250 : /* protect *sin6 from overwrites */
251 0 : tmp = *sin6;
252 0 : sin6 = &tmp;
253 :
254 : /* KAME hack: embed scopeid */
255 0 : if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0)
256 0 : return EINVAL;
257 : /* this must be cleared for ifa_ifwithaddr() */
258 0 : sin6->sin6_scope_id = 0;
259 :
260 : /* Source address selection. */
261 : /*
262 : * XXX: in6_selectsrc might replace the bound local address
263 : * with the address specified by setsockopt(IPV6_PKTINFO).
264 : * Is it the intended behavior?
265 : */
266 0 : error = in6_pcbselsrc(&in6a, sin6, inp, inp->inp_outputopts6);
267 0 : if (error)
268 0 : return (error);
269 :
270 0 : inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp);
271 :
272 0 : if (in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
273 0 : IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6,
274 0 : inp->inp_lport, inp->inp_rtableid) != NULL) {
275 0 : return (EADDRINUSE);
276 : }
277 :
278 0 : KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || inp->inp_lport);
279 :
280 0 : if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
281 0 : if (inp->inp_lport == 0) {
282 0 : error = in_pcbbind(inp, NULL, curproc);
283 0 : if (error)
284 0 : return (error);
285 0 : if (in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr,
286 0 : sin6->sin6_port, in6a, inp->inp_lport,
287 0 : inp->inp_rtableid) != NULL) {
288 0 : inp->inp_lport = 0;
289 0 : return (EADDRINUSE);
290 : }
291 : }
292 0 : inp->inp_laddr6 = *in6a;
293 0 : }
294 0 : inp->inp_faddr6 = sin6->sin6_addr;
295 0 : inp->inp_fport = sin6->sin6_port;
296 0 : inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK;
297 0 : if (ip6_auto_flowlabel)
298 0 : inp->inp_flowinfo |=
299 0 : (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
300 0 : in_pcbrehash(inp);
301 0 : return (0);
302 0 : }
303 :
304 : /*
305 : * Get the local address/port, and put it in a sockaddr_in6.
306 : * This services the getsockname(2) call.
307 : */
308 : int
309 0 : in6_setsockaddr(struct inpcb *inp, struct mbuf *nam)
310 : {
311 : struct sockaddr_in6 *sin6;
312 :
313 0 : nam->m_len = sizeof(struct sockaddr_in6);
314 0 : sin6 = mtod(nam,struct sockaddr_in6 *);
315 :
316 0 : bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
317 0 : sin6->sin6_family = AF_INET6;
318 0 : sin6->sin6_len = sizeof(struct sockaddr_in6);
319 0 : sin6->sin6_port = inp->inp_lport;
320 0 : sin6->sin6_addr = inp->inp_laddr6;
321 : /* KAME hack: recover scopeid */
322 0 : in6_recoverscope(sin6, &inp->inp_laddr6);
323 :
324 0 : return 0;
325 : }
326 :
327 : /*
328 : * Get the foreign address/port, and put it in a sockaddr_in6.
329 : * This services the getpeername(2) call.
330 : */
331 : int
332 0 : in6_setpeeraddr(struct inpcb *inp, struct mbuf *nam)
333 : {
334 : struct sockaddr_in6 *sin6;
335 :
336 0 : nam->m_len = sizeof(struct sockaddr_in6);
337 0 : sin6 = mtod(nam,struct sockaddr_in6 *);
338 :
339 0 : bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
340 0 : sin6->sin6_family = AF_INET6;
341 0 : sin6->sin6_len = sizeof(struct sockaddr_in6);
342 0 : sin6->sin6_port = inp->inp_fport;
343 0 : sin6->sin6_addr = inp->inp_faddr6;
344 : /* KAME hack: recover scopeid */
345 0 : in6_recoverscope(sin6, &inp->inp_faddr6);
346 :
347 0 : return 0;
348 : }
349 :
350 : /*
351 : * Pass some notification to all connections of a protocol
352 : * associated with address dst. The local address and/or port numbers
353 : * may be specified to limit the search. The "usual action" will be
354 : * taken, depending on the ctlinput cmd. The caller must filter any
355 : * cmds that are uninteresting (e.g., no error in the map).
356 : * Call the protocol specific routine (if any) to report
357 : * any errors for each matching socket.
358 : *
359 : * Also perform input-side security policy check
360 : * once PCB to be notified has been located.
361 : */
362 : int
363 0 : in6_pcbnotify(struct inpcbtable *table, struct sockaddr_in6 *dst,
364 : uint fport_arg, const struct sockaddr_in6 *src, uint lport_arg,
365 : u_int rtable, int cmd, void *cmdarg, void (*notify)(struct inpcb *, int))
366 : {
367 : struct inpcb *inp, *ninp;
368 0 : u_short fport = fport_arg, lport = lport_arg;
369 0 : struct sockaddr_in6 sa6_src;
370 : int errno, nmatch = 0;
371 : u_int32_t flowinfo;
372 : u_int rdomain;
373 :
374 0 : NET_ASSERT_LOCKED();
375 :
376 0 : if ((unsigned)cmd >= PRC_NCMDS)
377 0 : return (0);
378 :
379 0 : if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr))
380 0 : return (0);
381 0 : if (IN6_IS_ADDR_V4MAPPED(&dst->sin6_addr)) {
382 : #ifdef DIAGNOSTIC
383 0 : printf("Huh? Thought in6_pcbnotify() never got "
384 : "called with mapped!\n");
385 : #endif
386 0 : return (0);
387 : }
388 :
389 : /*
390 : * note that src can be NULL when we get notify by local fragmentation.
391 : */
392 0 : sa6_src = (src == NULL) ? sa6_any : *src;
393 0 : flowinfo = sa6_src.sin6_flowinfo;
394 :
395 : /*
396 : * Redirects go to all references to the destination,
397 : * and use in_rtchange to invalidate the route cache.
398 : * Dead host indications: also use in_rtchange to invalidate
399 : * the cache, and deliver the error to all the sockets.
400 : * Otherwise, if we have knowledge of the local port and address,
401 : * deliver only to that socket.
402 : */
403 0 : if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
404 : fport = 0;
405 : lport = 0;
406 0 : sa6_src.sin6_addr = in6addr_any;
407 :
408 0 : if (cmd != PRC_HOSTDEAD)
409 0 : notify = in_rtchange;
410 : }
411 0 : errno = inet6ctlerrmap[cmd];
412 :
413 0 : rdomain = rtable_l2(rtable);
414 0 : TAILQ_FOREACH_SAFE(inp, &table->inpt_queue, inp_queue, ninp) {
415 0 : if ((inp->inp_flags & INP_IPV6) == 0)
416 : continue;
417 :
418 : /*
419 : * Under the following condition, notify of redirects
420 : * to the pcb, without making address matches against inpcb.
421 : * - redirect notification is arrived.
422 : * - the inpcb is unconnected.
423 : * - the inpcb is caching !RTF_HOST routing entry.
424 : * - the ICMPv6 notification is from the gateway cached in the
425 : * inpcb. i.e. ICMPv6 notification is from nexthop gateway
426 : * the inpcb used very recently.
427 : *
428 : * This is to improve interaction between netbsd/openbsd
429 : * redirect handling code, and inpcb route cache code.
430 : * without the clause, !RTF_HOST routing entry (which carries
431 : * gateway used by inpcb right before the ICMPv6 redirect)
432 : * will be cached forever in unconnected inpcb.
433 : *
434 : * There still is a question regarding to what is TRT:
435 : * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
436 : * generated on packet output. inpcb will always cache
437 : * RTF_HOST routing entry so there's no need for the clause
438 : * (ICMPv6 redirect will update RTF_HOST routing entry,
439 : * and inpcb is caching it already).
440 : * However, bsdi/freebsd are vulnerable to local DoS attacks
441 : * due to the cloned routing entries.
442 : * - Specwise, "destination cache" is mentioned in RFC2461.
443 : * Jinmei says that it implies bsdi/freebsd behavior, itojun
444 : * is not really convinced.
445 : * - Having hiwat/lowat on # of cloned host route (redirect/
446 : * pmtud) may be a good idea. netbsd/openbsd has it. see
447 : * icmp6_mtudisc_update().
448 : */
449 0 : if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
450 0 : IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
451 0 : inp->inp_route.ro_rt &&
452 0 : !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
453 : struct sockaddr_in6 *dst6;
454 :
455 0 : dst6 = satosin6(&inp->inp_route.ro_dst);
456 0 : if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
457 : &dst->sin6_addr))
458 0 : goto do_notify;
459 0 : }
460 :
461 : /*
462 : * Detect if we should notify the error. If no source and
463 : * destination ports are specified, but non-zero flowinfo and
464 : * local address match, notify the error. This is the case
465 : * when the error is delivered with an encrypted buffer
466 : * by ESP. Otherwise, just compare addresses and ports
467 : * as usual.
468 : */
469 0 : if (lport == 0 && fport == 0 && flowinfo &&
470 0 : inp->inp_socket != NULL &&
471 0 : flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
472 0 : IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
473 : goto do_notify;
474 0 : else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
475 0 : &dst->sin6_addr) ||
476 0 : rtable_l2(inp->inp_rtableid) != rdomain ||
477 0 : inp->inp_socket == 0 ||
478 0 : (lport && inp->inp_lport != lport) ||
479 0 : (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
480 0 : !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
481 0 : &sa6_src.sin6_addr)) ||
482 0 : (fport && inp->inp_fport != fport)) {
483 : continue;
484 : }
485 : do_notify:
486 0 : nmatch++;
487 0 : if (notify)
488 0 : (*notify)(inp, errno);
489 : }
490 0 : return (nmatch);
491 0 : }
492 :
493 : struct inpcb *
494 0 : in6_pcbhashlookup(struct inpcbtable *table, const struct in6_addr *faddr,
495 : u_int fport_arg, const struct in6_addr *laddr, u_int lport_arg,
496 : u_int rtable)
497 : {
498 : struct inpcbhead *head;
499 : struct inpcb *inp;
500 0 : u_int16_t fport = fport_arg, lport = lport_arg;
501 : u_int rdomain;
502 :
503 0 : rdomain = rtable_l2(rtable);
504 0 : head = in6_pcbhash(table, rdomain, faddr, fport, laddr, lport);
505 0 : LIST_FOREACH(inp, head, inp_hash) {
506 0 : if (!(inp->inp_flags & INP_IPV6))
507 : continue;
508 0 : if (IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) &&
509 0 : inp->inp_fport == fport && inp->inp_lport == lport &&
510 0 : IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) &&
511 0 : rtable_l2(inp->inp_rtableid) == rdomain) {
512 : /*
513 : * Move this PCB to the head of hash chain so that
514 : * repeated accesses are quicker. This is analogous to
515 : * the historic single-entry PCB cache.
516 : */
517 0 : if (inp != LIST_FIRST(head)) {
518 0 : LIST_REMOVE(inp, inp_hash);
519 0 : LIST_INSERT_HEAD(head, inp, inp_hash);
520 0 : }
521 : break;
522 : }
523 : }
524 : #ifdef DIAGNOSTIC
525 0 : if (inp == NULL && in_pcbnotifymiss) {
526 0 : printf("%s: faddr= fport=%d laddr= lport=%d rdom=%u\n",
527 0 : __func__, ntohs(fport), ntohs(lport), rdomain);
528 0 : }
529 : #endif
530 0 : return (inp);
531 : }
532 :
533 : struct inpcb *
534 0 : in6_pcblookup_listen(struct inpcbtable *table, struct in6_addr *laddr,
535 : u_int lport_arg, struct mbuf *m, u_int rtable)
536 : {
537 : struct inpcbhead *head;
538 : const struct in6_addr *key1, *key2;
539 : struct inpcb *inp;
540 0 : u_int16_t lport = lport_arg;
541 : u_int rdomain;
542 :
543 : key1 = laddr;
544 : key2 = &zeroin6_addr;
545 : #if NPF > 0
546 0 : if (m && m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
547 : struct pf_divert *divert;
548 :
549 0 : divert = pf_find_divert(m);
550 0 : KASSERT(divert != NULL);
551 0 : switch (divert->type) {
552 : case PF_DIVERT_TO:
553 0 : key1 = key2 = &divert->addr.v6;
554 0 : lport = divert->port;
555 : break;
556 : case PF_DIVERT_REPLY:
557 0 : return (NULL);
558 : default:
559 0 : panic("%s: unknown divert type %d, mbuf %p, divert %p",
560 : __func__, divert->type, m, divert);
561 : }
562 0 : } else if (m && m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST) {
563 : /*
564 : * Redirected connections should not be treated the same
565 : * as connections directed to ::1 since localhost
566 : * can only be accessed from the host itself.
567 : */
568 : key1 = &zeroin6_addr;
569 : key2 = laddr;
570 0 : }
571 : #endif
572 :
573 0 : rdomain = rtable_l2(rtable);
574 0 : head = in6_pcbhash(table, rdomain, &zeroin6_addr, 0, key1, lport);
575 0 : LIST_FOREACH(inp, head, inp_hash) {
576 0 : if (!(inp->inp_flags & INP_IPV6))
577 : continue;
578 0 : if (inp->inp_lport == lport && inp->inp_fport == 0 &&
579 0 : IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key1) &&
580 0 : IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) &&
581 0 : rtable_l2(inp->inp_rtableid) == rdomain)
582 : break;
583 : }
584 0 : if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) {
585 0 : head = in6_pcbhash(table, rdomain,
586 : &zeroin6_addr, 0, key2, lport);
587 0 : LIST_FOREACH(inp, head, inp_hash) {
588 0 : if (!(inp->inp_flags & INP_IPV6))
589 : continue;
590 0 : if (inp->inp_lport == lport && inp->inp_fport == 0 &&
591 0 : IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key2) &&
592 0 : IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) &&
593 0 : rtable_l2(inp->inp_rtableid) == rdomain)
594 : break;
595 : }
596 : }
597 : /*
598 : * Move this PCB to the head of hash chain so that
599 : * repeated accesses are quicker. This is analogous to
600 : * the historic single-entry PCB cache.
601 : */
602 0 : if (inp != NULL && inp != LIST_FIRST(head)) {
603 0 : LIST_REMOVE(inp, inp_hash);
604 0 : LIST_INSERT_HEAD(head, inp, inp_hash);
605 0 : }
606 : #ifdef DIAGNOSTIC
607 0 : if (inp == NULL && in_pcbnotifymiss) {
608 0 : printf("%s: laddr= lport=%d rdom=%u\n",
609 0 : __func__, ntohs(lport), rdomain);
610 0 : }
611 : #endif
612 0 : return (inp);
613 0 : }
|