1 /* $OpenBSD: in6_pcb.c,v 1.26 2001/06/05 02:31:37 deraadt 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. All advertising materials mentioning features or use of this software 85 * must display the following acknowledgement: 86 * This product includes software developed by the University of 87 * California, Berkeley and its contributors. 88 * 4. Neither the name of the University nor the names of its contributors 89 * may be used to endorse or promote products derived from this software 90 * without specific prior written permission. 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 93 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 95 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 96 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 97 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 98 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 100 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 102 * SUCH DAMAGE. 103 * 104 */ 105 106 #include <sys/param.h> 107 #include <sys/systm.h> 108 #include <sys/malloc.h> 109 #include <sys/mbuf.h> 110 #include <sys/domain.h> 111 #include <sys/protosw.h> 112 #include <sys/socket.h> 113 #include <sys/socketvar.h> 114 #include <sys/errno.h> 115 #include <sys/time.h> 116 #include <sys/proc.h> 117 118 #include <net/if.h> 119 #include <net/route.h> 120 121 #include <netinet/in.h> 122 #include <netinet/in_systm.h> 123 #include <netinet/ip.h> 124 #include <netinet/in_pcb.h> 125 126 #include <netinet6/in6_var.h> 127 #include <netinet/ip6.h> 128 #include <netinet6/ip6_var.h> 129 130 /* 131 * External globals 132 */ 133 134 #include <dev/rndvar.h> 135 136 extern struct in6_ifaddr *in6_ifaddr; 137 extern struct in_ifaddr *in_ifaddr; 138 139 /* 140 * Globals 141 */ 142 143 struct in6_addr zeroin6_addr; 144 145 extern int ipport_firstauto; 146 extern int ipport_lastauto; 147 extern int ipport_hifirstauto; 148 extern int ipport_hilastauto; 149 150 /* 151 * Keep separate inet6ctlerrmap, because I may remap some of these. 152 * I also put it here, because, quite frankly, it belongs here, not in 153 * ip{v6,}_input(). 154 */ 155 #if 0 156 u_char inet6ctlerrmap[PRC_NCMDS] = { 157 0, 0, 0, 0, 158 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 159 EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 160 EMSGSIZE, EHOSTUNREACH, 0, 0, 161 0, 0, 0, 0, 162 ENOPROTOOPT 163 }; 164 #endif 165 166 /* 167 * Bind an address (or at least a port) to an PF_INET6 socket. 168 */ 169 int 170 in6_pcbbind(inp, nam) 171 struct inpcb *inp; 172 struct mbuf *nam; 173 { 174 struct socket *so = inp->inp_socket; 175 176 struct inpcbtable *head = inp->inp_table; 177 struct sockaddr_in6 *sin6; 178 struct proc *p = curproc; /* XXX */ 179 u_short lport = 0; 180 int wild = INPLOOKUP_IPV6, reuseport = (so->so_options & SO_REUSEPORT); 181 int error; 182 183 /* 184 * REMINDER: Once up to speed, flow label processing should go here, 185 * too. (Same with in6_pcbconnect.) 186 */ 187 if (in6_ifaddr == 0 || in_ifaddr == 0) 188 return EADDRNOTAVAIL; 189 190 if (inp->inp_lport != 0 || !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) 191 return EINVAL; /* If already bound, EINVAL! */ 192 193 if ((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0 && 194 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 195 (so->so_options & SO_ACCEPTCONN) == 0)) 196 wild |= INPLOOKUP_WILDCARD; 197 198 /* 199 * If I did get a sockaddr passed in... 200 */ 201 if (nam) { 202 sin6 = mtod(nam, struct sockaddr_in6 *); 203 if (nam->m_len != sizeof (*sin6)) 204 return EINVAL; 205 206 /* 207 * Unlike v4, I have no qualms about EAFNOSUPPORT if the 208 * wretched family is not filled in! 209 */ 210 if (sin6->sin6_family != AF_INET6) 211 return EAFNOSUPPORT; 212 213 /* KAME hack: embed scopeid */ 214 if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0) 215 return EINVAL; 216 /* this must be cleared for ifa_ifwithaddr() */ 217 sin6->sin6_scope_id = 0; 218 219 lport = sin6->sin6_port; 220 221 /* reject IPv4 mapped address, we have no support for it */ 222 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 223 return EADDRNOTAVAIL; 224 225 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 226 /* 227 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 228 * allow complete duplication of binding if 229 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 230 * and a multicast address is bound on both 231 * new and duplicated sockets. 232 */ 233 if (so->so_options & SO_REUSEADDR) 234 reuseport = SO_REUSEADDR | SO_REUSEPORT; 235 } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 236 struct ifaddr *ia = NULL; 237 238 sin6->sin6_port = 0; /* 239 * Yechhhh, because of upcoming 240 * call to ifa_ifwithaddr(), which 241 * does bcmp's over the PORTS as 242 * well. (What about flow?) 243 */ 244 sin6->sin6_flowinfo = 0; 245 if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) 246 == NULL) 247 return EADDRNOTAVAIL; 248 249 /* 250 * XXX: bind to an anycast address might accidentally 251 * cause sending a packet with anycast source address. 252 * We should allow to bind to a deprecated address, since 253 * the application dare to use it. 254 */ 255 if (ia && 256 ((struct in6_ifaddr *)ia)->ia6_flags & 257 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) 258 return(EADDRNOTAVAIL); 259 } 260 #if 0 /* we don't support it */ 261 else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 262 struct sockaddr_in sin; 263 264 bzero(&sin, sizeof(sin)); 265 sin.sin_port = 0; 266 sin.sin_len = sizeof(sin); 267 sin.sin_family = AF_INET; 268 sin.sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 269 270 /* 271 * Yechhhh, because of upcoming call to 272 * ifa_ifwithaddr(), which does bcmp's 273 * over the PORTS as well. (What about flow?) 274 */ 275 sin6->sin6_port = 0; 276 sin6->sin6_flowinfo = 0; 277 if (ifa_ifwithaddr((struct sockaddr *)sin6) == 0) { 278 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 279 ifa_ifwithaddr((struct sockaddr *)&sin) == 0) { 280 return EADDRNOTAVAIL; 281 } 282 } 283 } 284 #endif 285 if (lport) { 286 struct inpcb *t; 287 #if 0 /* we don't support IPv4 mapped address */ 288 struct in_addr fa,la; 289 #endif 290 291 /* 292 * Question: Do we wish to continue the Berkeley 293 * tradition of ports < IPPORT_RESERVED be only for 294 * root? 295 * Answer: For now yes, but IMHO, it should be REMOVED! 296 * OUCH: One other thing, is there no better way of 297 * finding a process for a socket instead of using 298 * curproc? (Marked with BSD's {in,}famous XXX ? 299 */ 300 if (ntohs(lport) < IPPORT_RESERVED && 301 (error = suser(p->p_ucred, &p->p_acflag))) 302 return error; 303 304 #if 0 /* we don't support IPv4 mapped address */ 305 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 306 fa.s_addr = 0; 307 la.s_addr = sin6->sin6_addr.s6_addr32[3]; 308 wild &= ~INPLOOKUP_IPV6; 309 310 t = in_pcblookup(head, (struct in_addr *)&fa, 0, 311 (struct in_addr *)&la, lport, wild); 312 } else 313 #endif 314 { 315 t = in_pcblookup(head, 316 (struct in_addr *)&zeroin6_addr, 0, 317 (struct in_addr *)&sin6->sin6_addr, lport, 318 wild); 319 } 320 321 if (t && (reuseport & t->inp_socket->so_options) == 0) 322 return EADDRINUSE; 323 } 324 inp->inp_laddr6 = sin6->sin6_addr; 325 326 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 327 inp->inp_ipv6.ip6_flow = htonl(0x60000000) | 328 (sin6->sin6_flowinfo & htonl(0x0fffffff)); 329 } 330 } 331 332 if (lport == 0) { 333 error = in6_pcbsetport(&inp->inp_laddr6, inp); 334 if (error != 0) 335 return error; 336 } else 337 inp->inp_lport = lport; 338 339 in_pcbrehash(inp); 340 341 return 0; 342 } 343 344 int 345 in6_pcbsetport(laddr, inp) 346 struct in6_addr *laddr; 347 struct inpcb *inp; 348 { 349 struct socket *so = inp->inp_socket; 350 struct inpcbtable *table = inp->inp_table; 351 u_int16_t first, last, old = 0; 352 u_int16_t *lastport = &inp->inp_table->inpt_lastport; 353 u_int16_t lport = 0; 354 int count; 355 int loopcount = 0; 356 int wild = INPLOOKUP_IPV6; 357 struct proc *p = curproc; /* XXX */ 358 int error; 359 360 /* XXX we no longer support IPv4 mapped address, so no tweaks here */ 361 362 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && 363 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || 364 (so->so_options & SO_ACCEPTCONN) == 0)) 365 wild |= INPLOOKUP_WILDCARD; 366 367 if (inp->inp_flags & INP_HIGHPORT) { 368 first = ipport_hifirstauto; /* sysctl */ 369 last = ipport_hilastauto; 370 } else if (inp->inp_flags & INP_LOWPORT) { 371 if ((error = suser(p->p_ucred, &p->p_acflag))) 372 return (EACCES); 373 first = IPPORT_RESERVED-1; /* 1023 */ 374 last = 600; /* not IPPORT_RESERVED/2 */ 375 } else { 376 first = ipport_firstauto; /* sysctl */ 377 last = ipport_lastauto; 378 } 379 380 /* 381 * Simple check to ensure all ports are not used up causing 382 * a deadlock here. 383 * 384 * We split the two cases (up and down) so that the direction 385 * is not being tested on each round of the loop. 386 */ 387 388 portloop: 389 if (first > last) { 390 /* 391 * counting down 392 */ 393 if (loopcount == 0) { /* only do this once. */ 394 old = first; 395 first -= (arc4random() % (first - last)); 396 } 397 count = first - last; 398 *lastport = first; /* restart each time */ 399 400 do { 401 if (count-- <= 0) { /* completely used? */ 402 if (loopcount == 0) { 403 last = old; 404 loopcount++; 405 goto portloop; 406 } 407 return (EADDRNOTAVAIL); 408 } 409 --*lastport; 410 if (*lastport > first || *lastport < last) 411 *lastport = first; 412 lport = htons(*lastport); 413 } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) || 414 in_pcblookup(table, &zeroin6_addr, 0, 415 &inp->inp_laddr6, lport, wild)); 416 } else { 417 /* 418 * counting up 419 */ 420 if (loopcount == 0) { /* only do this once. */ 421 old = first; 422 first += (arc4random() % (last - first)); 423 } 424 count = last - first; 425 *lastport = first; /* restart each time */ 426 427 do { 428 if (count-- <= 0) { /* completely used? */ 429 if (loopcount == 0) { 430 first = old; 431 loopcount++; 432 goto portloop; 433 } 434 return (EADDRNOTAVAIL); 435 } 436 ++*lastport; 437 if (*lastport < first || *lastport > last) 438 *lastport = first; 439 lport = htons(*lastport); 440 } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) || 441 in_pcblookup(table, &zeroin6_addr, 0, 442 &inp->inp_laddr6, lport, wild)); 443 } 444 445 inp->inp_lport = lport; 446 in_pcbrehash(inp); 447 448 return 0; 449 } 450 451 /* 452 * Connect from a socket to a specified address. 453 * Both address and port must be specified in argument sin6. 454 * Eventually, flow labels will have to be dealt with here, as well. 455 * 456 * If don't have a local address for this socket yet, 457 * then pick one. 458 * 459 * I believe this has to be called at splnet(). 460 */ 461 int 462 in6_pcbconnect(inp, nam) 463 struct inpcb *inp; 464 struct mbuf *nam; 465 { 466 struct in6_addr *in6a = NULL; 467 struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *); 468 struct ifnet *ifp = NULL; /* outgoing interface */ 469 int error = 0; 470 struct in6_addr mapped; 471 struct sockaddr_in6 tmp; 472 473 (void)&in6a; /* XXX fool gcc */ 474 475 if (nam->m_len != sizeof(*sin6)) 476 return(EINVAL); 477 if (sin6->sin6_family != AF_INET6) 478 return(EAFNOSUPPORT); 479 if (sin6->sin6_port == 0) 480 return(EADDRNOTAVAIL); 481 482 /* reject IPv4 mapped address, we have no support for it */ 483 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 484 return EADDRNOTAVAIL; 485 486 /* sanity check for mapped address case */ 487 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 488 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) 489 inp->inp_laddr6.s6_addr16[5] = htons(0xffff); 490 if (!IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6)) 491 return EINVAL; 492 } else { 493 if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6)) 494 return EINVAL; 495 } 496 497 /* protect *sin6 from overwrites */ 498 tmp = *sin6; 499 sin6 = &tmp; 500 501 /* KAME hack: embed scopeid */ 502 if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0) 503 return EINVAL; 504 /* this must be cleared for ifa_ifwithaddr() */ 505 sin6->sin6_scope_id = 0; 506 507 /* Source address selection. */ 508 if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6) && 509 inp->inp_laddr6.s6_addr32[3] == 0) { 510 struct sockaddr_in sin, *sinp; 511 512 bzero(&sin, sizeof(sin)); 513 sin.sin_len = sizeof(sin); 514 sin.sin_family = AF_INET; 515 bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr, 516 sizeof(sin.sin_addr)); 517 sinp = in_selectsrc(&sin, (struct route *)&inp->inp_route6, 518 inp->inp_socket->so_options, NULL, &error); 519 if (sinp == 0) { 520 if (error == 0) 521 error = EADDRNOTAVAIL; 522 return(error); 523 } 524 bzero(&mapped, sizeof(mapped)); 525 mapped.s6_addr16[5] = htons(0xffff); 526 bcopy(&sinp->sin_addr, &mapped.s6_addr32[3], sizeof(sinp->sin_addr)); 527 in6a = &mapped; 528 } else { 529 /* 530 * XXX: in6_selectsrc might replace the bound local address 531 * with the address specified by setsockopt(IPV6_PKTINFO). 532 * Is it the intended behavior? 533 */ 534 in6a = in6_selectsrc(sin6, inp->inp_outputopts6, 535 inp->inp_moptions6, &inp->inp_route6, &inp->inp_laddr6, 536 &error); 537 if (in6a == 0) { 538 if (error == 0) 539 error = EADDRNOTAVAIL; 540 return(error); 541 } 542 } 543 if (inp->inp_route6.ro_rt) 544 ifp = inp->inp_route6.ro_rt->rt_ifp; 545 546 inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp); 547 548 if (in_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port, 549 IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6, 550 inp->inp_lport, INPLOOKUP_IPV6)) { 551 return(EADDRINUSE); 552 } 553 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || 554 (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6) && 555 inp->inp_laddr6.s6_addr32[3] == 0)) { 556 if (inp->inp_lport == 0) 557 (void)in6_pcbbind(inp, (struct mbuf *)0); 558 inp->inp_laddr6 = *in6a; 559 } 560 inp->inp_faddr6 = sin6->sin6_addr; 561 inp->inp_fport = sin6->sin6_port; 562 /* 563 * xxx kazu flowlabel is necessary for connect? 564 * but if this line is missing, the garbage value remains. 565 */ 566 inp->inp_ipv6.ip6_flow = sin6->sin6_flowinfo; 567 in_pcbrehash(inp); 568 return(0); 569 } 570 571 /* 572 * Pass some notification to all connections of a protocol 573 * associated with address dst. The local address and/or port numbers 574 * may be specified to limit the search. The "usual action" will be 575 * taken, depending on the ctlinput cmd. The caller must filter any 576 * cmds that are uninteresting (e.g., no error in the map). 577 * Call the protocol specific routine (if any) to report 578 * any errors for each matching socket. 579 * 580 * Also perform input-side security policy check 581 * once PCB to be notified has been located. 582 * 583 * Must be called at splnet. 584 */ 585 int 586 in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) 587 struct inpcbtable *head; 588 struct sockaddr *dst, *src; 589 uint fport_arg; 590 uint lport_arg; 591 int cmd; 592 void *cmdarg; 593 void (*notify) __P((struct inpcb *, int)); 594 { 595 struct inpcb *inp, *ninp; 596 u_short fport = fport_arg, lport = lport_arg; 597 struct sockaddr_in6 sa6_src, *sa6_dst; 598 int errno, nmatch = 0; 599 u_int32_t flowinfo; 600 601 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6) 602 return 1; 603 604 sa6_dst = (struct sockaddr_in6 *)dst; 605 if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr)) 606 return 1; 607 if (IN6_IS_ADDR_V4MAPPED(&sa6_dst->sin6_addr)) 608 printf("Huh? Thought in6_pcbnotify() never got " 609 "called with mapped!\n"); 610 611 /* 612 * note that src can be NULL when we get notify by local fragmentation. 613 */ 614 sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src; 615 flowinfo = sa6_src.sin6_flowinfo; 616 617 /* 618 * Redirects go to all references to the destination, 619 * and use in_rtchange to invalidate the route cache. 620 * Dead host indications: also use in_rtchange to invalidate 621 * the cache, and deliver the error to all the sockets. 622 * Otherwise, if we have knowledge of the local port and address, 623 * deliver only to that socket. 624 */ 625 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 626 fport = 0; 627 lport = 0; 628 sa6_src.sin6_addr = in6addr_any; 629 630 if (cmd != PRC_HOSTDEAD) 631 notify = in_rtchange; 632 } 633 errno = inet6ctlerrmap[cmd]; 634 635 for (inp = head->inpt_queue.cqh_first; 636 inp != (struct inpcb *)&head->inpt_queue; inp = ninp) { 637 ninp = inp->inp_queue.cqe_next; 638 639 if ((inp->inp_flags & INP_IPV6) == 0) 640 continue; 641 642 /* 643 * Under the following condition, notify of redirects 644 * to the pcb, without making address matches against inpcb. 645 * - redirect notification is arrived. 646 * - the inpcb is unconnected. 647 * - the inpcb is caching !RTF_HOST routing entry. 648 * - the ICMPv6 notification is from the gateway cached in the 649 * inpcb. i.e. ICMPv6 notification is from nexthop gateway 650 * the inpcb used very recently. 651 * 652 * This is to improve interaction between netbsd/openbsd 653 * redirect handling code, and inpcb route cache code. 654 * without the clause, !RTF_HOST routing entry (which carries 655 * gateway used by inpcb right before the ICMPv6 redirect) 656 * will be cached forever in unconnected inpcb. 657 * 658 * There still is a question regarding to what is TRT: 659 * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be 660 * generated on packet output. inpcb will always cache 661 * RTF_HOST routing entry so there's no need for the clause 662 * (ICMPv6 redirect will update RTF_HOST routing entry, 663 * and inpcb is caching it already). 664 * However, bsdi/freebsd are vulnerable to local DoS attacks 665 * due to the cloned routing entries. 666 * - Specwise, "destination cache" is mentioned in RFC2461. 667 * Jinmei says that it implies bsdi/freebsd behavior, itojun 668 * is not really convinced. 669 * - Having hiwat/lowat on # of cloned host route (redirect/ 670 * pmtud) may be a good idea. netbsd/openbsd has it. see 671 * icmp6_mtudisc_update(). 672 */ 673 if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) && 674 IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && 675 inp->inp_route.ro_rt && 676 !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) { 677 struct sockaddr_in6 *dst6; 678 679 dst6 = (struct sockaddr_in6 *)&inp->inp_route.ro_dst; 680 if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, 681 &sa6_dst->sin6_addr)) 682 goto do_notify; 683 } 684 685 /* 686 * Detect if we should notify the error. If no source and 687 * destination ports are specifed, but non-zero flowinfo and 688 * local address match, notify the error. This is the case 689 * when the error is delivered with an encrypted buffer 690 * by ESP. Otherwise, just compare addresses and ports 691 * as usual. 692 */ 693 if (lport == 0 && fport == 0 && flowinfo && 694 inp->inp_socket != NULL && 695 flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) && 696 IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr)) 697 goto do_notify; 698 else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, 699 &sa6_dst->sin6_addr) || 700 inp->inp_socket == 0 || 701 (lport && inp->inp_lport != lport) || 702 (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && 703 !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, 704 &sa6_src.sin6_addr)) || 705 (fport && inp->inp_fport != fport)) { 706 continue; 707 } 708 do_notify: 709 nmatch++; 710 if (notify) 711 (*notify)(inp, errno); 712 } 713 return 0; 714 } 715 716 /* 717 * Get the local address/port, and put it in a sockaddr_in6. 718 * This services the getsockname(2) call. 719 */ 720 int 721 in6_setsockaddr(inp, nam) 722 struct inpcb *inp; 723 struct mbuf *nam; 724 { 725 struct sockaddr_in6 *sin6; 726 727 nam->m_len = sizeof(struct sockaddr_in6); 728 sin6 = mtod(nam,struct sockaddr_in6 *); 729 730 bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6)); 731 sin6->sin6_family = AF_INET6; 732 sin6->sin6_len = sizeof(struct sockaddr_in6); 733 sin6->sin6_port = inp->inp_lport; 734 sin6->sin6_addr = inp->inp_laddr6; 735 /* KAME hack: recover scopeid */ 736 (void)in6_recoverscope(sin6, &inp->inp_laddr6, NULL); 737 738 return 0; 739 } 740 741 /* 742 * Get the foreign address/port, and put it in a sockaddr_in6. 743 * This services the getpeername(2) call. 744 */ 745 int 746 in6_setpeeraddr(inp, nam) 747 struct inpcb *inp; 748 struct mbuf *nam; 749 { 750 struct sockaddr_in6 *sin6; 751 752 nam->m_len = sizeof(struct sockaddr_in6); 753 sin6 = mtod(nam,struct sockaddr_in6 *); 754 755 bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6)); 756 sin6->sin6_family = AF_INET6; 757 sin6->sin6_len = sizeof(struct sockaddr_in6); 758 sin6->sin6_port = inp->inp_fport; 759 sin6->sin6_addr = inp->inp_faddr6; 760 761 return 0; 762 } 763