uipc_domain.c revision 1.95
1/* $NetBSD: uipc_domain.c,v 1.95 2014/09/05 09:20:59 matt Exp $ */ 2 3/* 4 * Copyright (c) 1982, 1986, 1993 5 * The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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 * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95 32 */ 33 34#include <sys/cdefs.h> 35__KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.95 2014/09/05 09:20:59 matt Exp $"); 36 37#include <sys/param.h> 38#include <sys/socket.h> 39#include <sys/socketvar.h> 40#include <sys/protosw.h> 41#include <sys/domain.h> 42#include <sys/mbuf.h> 43#include <sys/time.h> 44#include <sys/kernel.h> 45#include <sys/systm.h> 46#include <sys/callout.h> 47#include <sys/queue.h> 48#include <sys/proc.h> 49#include <sys/sysctl.h> 50#include <sys/un.h> 51#include <sys/unpcb.h> 52#include <sys/file.h> 53#include <sys/filedesc.h> 54#include <sys/kauth.h> 55#include <netinet/in.h> 56 57MALLOC_DECLARE(M_SOCKADDR); 58 59MALLOC_DEFINE(M_SOCKADDR, "sockaddr", "socket endpoints"); 60 61void pffasttimo(void *); 62void pfslowtimo(void *); 63 64struct domainhead domains = STAILQ_HEAD_INITIALIZER(domains); 65static struct domain *domain_array[AF_MAX]; 66 67callout_t pffasttimo_ch, pfslowtimo_ch; 68 69/* 70 * Current time values for fast and slow timeouts. We can use u_int 71 * relatively safely. The fast timer will roll over in 27 years and 72 * the slow timer in 68 years. 73 */ 74u_int pfslowtimo_now; 75u_int pffasttimo_now; 76 77static struct sysctllog *domain_sysctllog; 78static void sysctl_net_setup(void); 79 80/* ensure successful linkage even without any domains in link sets */ 81static struct domain domain_dummy; 82__link_set_add_rodata(domains,domain_dummy); 83 84void 85domaininit(bool attach) 86{ 87 __link_set_decl(domains, struct domain); 88 struct domain * const * dpp; 89 struct domain *rt_domain = NULL; 90 91 sysctl_net_setup(); 92 93 /* 94 * Add all of the domains. Make sure the PF_ROUTE 95 * domain is added last. 96 */ 97 if (attach) { 98 __link_set_foreach(dpp, domains) { 99 if (*dpp == &domain_dummy) 100 continue; 101 if ((*dpp)->dom_family == PF_ROUTE) 102 rt_domain = *dpp; 103 else 104 domain_attach(*dpp); 105 } 106 if (rt_domain) 107 domain_attach(rt_domain); 108 } 109 110 callout_init(&pffasttimo_ch, CALLOUT_MPSAFE); 111 callout_init(&pfslowtimo_ch, CALLOUT_MPSAFE); 112 113 callout_reset(&pffasttimo_ch, 1, pffasttimo, NULL); 114 callout_reset(&pfslowtimo_ch, 1, pfslowtimo, NULL); 115} 116 117void 118domain_attach(struct domain *dp) 119{ 120 const struct protosw *pr; 121 122 STAILQ_INSERT_TAIL(&domains, dp, dom_link); 123 if (dp->dom_family < __arraycount(domain_array)) 124 domain_array[dp->dom_family] = dp; 125 126 if (dp->dom_init) 127 (*dp->dom_init)(); 128 129#ifdef MBUFTRACE 130 if (dp->dom_mowner.mo_name[0] == '\0') { 131 strncpy(dp->dom_mowner.mo_name, dp->dom_name, 132 sizeof(dp->dom_mowner.mo_name)); 133 MOWNER_ATTACH(&dp->dom_mowner); 134 } 135#endif 136 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { 137 if (pr->pr_init) 138 (*pr->pr_init)(); 139 } 140 141 if (max_linkhdr < 16) /* XXX */ 142 max_linkhdr = 16; 143 max_hdr = max_linkhdr + max_protohdr; 144 max_datalen = MHLEN - max_hdr; 145} 146 147struct domain * 148pffinddomain(int family) 149{ 150 struct domain *dp; 151 152 if (family < __arraycount(domain_array) && domain_array[family] != NULL) 153 return domain_array[family]; 154 155 DOMAIN_FOREACH(dp) 156 if (dp->dom_family == family) 157 return dp; 158 return NULL; 159} 160 161const struct protosw * 162pffindtype(int family, int type) 163{ 164 struct domain *dp; 165 const struct protosw *pr; 166 167 dp = pffinddomain(family); 168 if (dp == NULL) 169 return NULL; 170 171 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 172 if (pr->pr_type && pr->pr_type == type) 173 return pr; 174 175 return NULL; 176} 177 178const struct protosw * 179pffindproto(int family, int protocol, int type) 180{ 181 struct domain *dp; 182 const struct protosw *pr; 183 const struct protosw *maybe = NULL; 184 185 if (family == 0) 186 return NULL; 187 188 dp = pffinddomain(family); 189 if (dp == NULL) 190 return NULL; 191 192 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { 193 if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) 194 return pr; 195 196 if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && 197 pr->pr_protocol == 0 && maybe == NULL) 198 maybe = pr; 199 } 200 return maybe; 201} 202 203void * 204sockaddr_addr(struct sockaddr *sa, socklen_t *slenp) 205{ 206 const struct domain *dom; 207 208 if ((dom = pffinddomain(sa->sa_family)) == NULL || 209 dom->dom_sockaddr_addr == NULL) 210 return NULL; 211 212 return (*dom->dom_sockaddr_addr)(sa, slenp); 213} 214 215const void * 216sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp) 217{ 218 const struct domain *dom; 219 220 if ((dom = pffinddomain(sa->sa_family)) == NULL || 221 dom->dom_sockaddr_const_addr == NULL) 222 return NULL; 223 224 return (*dom->dom_sockaddr_const_addr)(sa, slenp); 225} 226 227const struct sockaddr * 228sockaddr_any_by_family(int family) 229{ 230 const struct domain *dom; 231 232 if ((dom = pffinddomain(family)) == NULL) 233 return NULL; 234 235 return dom->dom_sa_any; 236} 237 238const struct sockaddr * 239sockaddr_any(const struct sockaddr *sa) 240{ 241 return sockaddr_any_by_family(sa->sa_family); 242} 243 244const void * 245sockaddr_anyaddr(const struct sockaddr *sa, socklen_t *slenp) 246{ 247 const struct sockaddr *any; 248 249 if ((any = sockaddr_any(sa)) == NULL) 250 return NULL; 251 252 return sockaddr_const_addr(any, slenp); 253} 254 255struct sockaddr * 256sockaddr_alloc(sa_family_t af, socklen_t socklen, int flags) 257{ 258 struct sockaddr *sa; 259 socklen_t reallen = MAX(socklen, offsetof(struct sockaddr, sa_data[0])); 260 261 if ((sa = malloc(reallen, M_SOCKADDR, flags)) == NULL) 262 return NULL; 263 264 sa->sa_family = af; 265 sa->sa_len = reallen; 266 return sa; 267} 268 269struct sockaddr * 270sockaddr_copy(struct sockaddr *dst, socklen_t socklen, 271 const struct sockaddr *src) 272{ 273 if (__predict_false(socklen < src->sa_len)) { 274 panic("%s: source too long, %d < %d bytes", __func__, socklen, 275 src->sa_len); 276 } 277 return memcpy(dst, src, src->sa_len); 278} 279 280struct sockaddr * 281sockaddr_externalize(struct sockaddr *dst, socklen_t socklen, 282 const struct sockaddr *src) 283{ 284 struct domain *dom; 285 286 dom = pffinddomain(src->sa_family); 287 288 if (dom != NULL && dom->dom_sockaddr_externalize != NULL) 289 return (*dom->dom_sockaddr_externalize)(dst, socklen, src); 290 291 return sockaddr_copy(dst, socklen, src); 292} 293 294int 295sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) 296{ 297 int len, rc; 298 struct domain *dom; 299 300 if (sa1->sa_family != sa2->sa_family) 301 return sa1->sa_family - sa2->sa_family; 302 303 dom = pffinddomain(sa1->sa_family); 304 305 if (dom != NULL && dom->dom_sockaddr_cmp != NULL) 306 return (*dom->dom_sockaddr_cmp)(sa1, sa2); 307 308 len = MIN(sa1->sa_len, sa2->sa_len); 309 310 if (dom == NULL || dom->dom_sa_cmplen == 0) { 311 if ((rc = memcmp(sa1, sa2, len)) != 0) 312 return rc; 313 return sa1->sa_len - sa2->sa_len; 314 } 315 316 if ((rc = memcmp((const char *)sa1 + dom->dom_sa_cmpofs, 317 (const char *)sa2 + dom->dom_sa_cmpofs, 318 MIN(dom->dom_sa_cmplen, 319 len - MIN(len, dom->dom_sa_cmpofs)))) != 0) 320 return rc; 321 322 return MIN(dom->dom_sa_cmplen + dom->dom_sa_cmpofs, sa1->sa_len) - 323 MIN(dom->dom_sa_cmplen + dom->dom_sa_cmpofs, sa2->sa_len); 324} 325 326struct sockaddr * 327sockaddr_dup(const struct sockaddr *src, int flags) 328{ 329 struct sockaddr *dst; 330 331 if ((dst = sockaddr_alloc(src->sa_family, src->sa_len, flags)) == NULL) 332 return NULL; 333 334 return sockaddr_copy(dst, dst->sa_len, src); 335} 336 337void 338sockaddr_free(struct sockaddr *sa) 339{ 340 free(sa, M_SOCKADDR); 341} 342 343void 344sockaddr_format(const struct sockaddr *sa, char *buf, size_t len) 345{ 346 const struct sockaddr_un *sun = (const struct sockaddr_un *)sa; 347 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 348 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 349 const uint8_t *data; 350 size_t data_len; 351 352 if (sa == NULL) { 353 strlcpy(buf, "(null)", len); 354 return; 355 } 356 357 switch (sa->sa_family) { 358 default: 359 snprintf(buf, len, "(unknown socket family %d)", 360 (int)sa->sa_family); 361 return; 362 case AF_LOCAL: 363 strlcpy(buf, "unix:", len); 364 strlcat(buf, sun->sun_path, len); 365 return; 366 case AF_INET: 367 strlcpy(buf, "inet:", len); 368 if (len < 6) 369 return; 370 buf += 5; 371 len -= 5; 372 data = (const uint8_t *)&sin->sin_addr; 373 data_len = sizeof(sin->sin_addr); 374 break; 375 case AF_INET6: 376 strlcpy(buf, "inet6:", len); 377 if (len < 7) 378 return; 379 buf += 6; 380 len -= 6; 381 data = (const uint8_t *)&sin6->sin6_addr; 382 data_len = sizeof(sin6->sin6_addr); 383 break; 384 } 385 for (;;) { 386 if (--len == 0) 387 break; 388 389 uint8_t hi = *data >> 4; 390 uint8_t lo = *data & 15; 391 --data_len; 392 ++data; 393 *buf++ = hi + (hi >= 10 ? 'a' - 10 : '0'); 394 if (--len == 0) 395 break; 396 *buf++ = lo + (lo >= 10 ? 'a' - 10 : '0'); 397 if (data_len == 0) 398 break; 399 } 400 *buf = 0; 401} 402 403/* 404 * sysctl helper to stuff PF_LOCAL pcbs into sysctl structures 405 */ 406static void 407sysctl_dounpcb(struct kinfo_pcb *pcb, const struct socket *so) 408{ 409 struct unpcb *unp = sotounpcb(so); 410 struct sockaddr_un *un = unp->unp_addr; 411 412 memset(pcb, 0, sizeof(*pcb)); 413 414 pcb->ki_family = so->so_proto->pr_domain->dom_family; 415 pcb->ki_type = so->so_proto->pr_type; 416 pcb->ki_protocol = so->so_proto->pr_protocol; 417 pcb->ki_pflags = unp->unp_flags; 418 419 pcb->ki_pcbaddr = PTRTOUINT64(unp); 420 /* pcb->ki_ppcbaddr = unp has no ppcb... */ 421 pcb->ki_sockaddr = PTRTOUINT64(so); 422 423 pcb->ki_sostate = so->so_state; 424 /* pcb->ki_prstate = unp has no state... */ 425 426 pcb->ki_rcvq = so->so_rcv.sb_cc; 427 pcb->ki_sndq = so->so_snd.sb_cc; 428 429 un = (struct sockaddr_un *)pcb->ki_spad; 430 /* 431 * local domain sockets may bind without having a local 432 * endpoint. bleah! 433 */ 434 if (unp->unp_addr != NULL) { 435 /* 436 * We've added one to sun_len when allocating to 437 * hold terminating NUL which we want here. See 438 * makeun(). 439 */ 440 memcpy(un, unp->unp_addr, 441 min(sizeof(pcb->ki_spad), unp->unp_addr->sun_len + 1)); 442 } 443 else { 444 un->sun_len = offsetof(struct sockaddr_un, sun_path); 445 un->sun_family = pcb->ki_family; 446 } 447 if (unp->unp_conn != NULL) { 448 un = (struct sockaddr_un *)pcb->ki_dpad; 449 if (unp->unp_conn->unp_addr != NULL) { 450 memcpy(un, unp->unp_conn->unp_addr, 451 min(sizeof(pcb->ki_dpad), unp->unp_conn->unp_addr->sun_len + 1)); 452 } 453 else { 454 un->sun_len = offsetof(struct sockaddr_un, sun_path); 455 un->sun_family = pcb->ki_family; 456 } 457 } 458 459 pcb->ki_inode = unp->unp_ino; 460 pcb->ki_vnode = PTRTOUINT64(unp->unp_vnode); 461 pcb->ki_conn = PTRTOUINT64(unp->unp_conn); 462 pcb->ki_refs = PTRTOUINT64(unp->unp_refs); 463 pcb->ki_nextref = PTRTOUINT64(unp->unp_nextref); 464} 465 466static int 467sysctl_unpcblist(SYSCTLFN_ARGS) 468{ 469 struct file *fp, *dfp; 470 struct socket *so; 471 struct kinfo_pcb pcb; 472 char *dp; 473 size_t len, needed, elem_size, out_size; 474 int error, elem_count, pf, type; 475 476 if (namelen == 1 && name[0] == CTL_QUERY) 477 return sysctl_query(SYSCTLFN_CALL(rnode)); 478 479 if (namelen != 4) 480 return EINVAL; 481 482 if (oldp != NULL) { 483 len = *oldlenp; 484 elem_size = name[2]; 485 elem_count = name[3]; 486 if (elem_size != sizeof(pcb)) 487 return EINVAL; 488 } else { 489 len = 0; 490 elem_size = sizeof(pcb); 491 elem_count = INT_MAX; 492 } 493 error = 0; 494 dp = oldp; 495 out_size = elem_size; 496 needed = 0; 497 498 if (name - oname != 4) 499 return EINVAL; 500 501 pf = oname[1]; 502 type = oname[2]; 503 504 /* 505 * allocate dummy file descriptor to make position in list. 506 */ 507 sysctl_unlock(); 508 if ((dfp = fgetdummy()) == NULL) { 509 sysctl_relock(); 510 return ENOMEM; 511 } 512 513 /* 514 * there's no "list" of local domain sockets, so we have 515 * to walk the file list looking for them. :-/ 516 */ 517 mutex_enter(&filelist_lock); 518 LIST_FOREACH(fp, &filehead, f_list) { 519 if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET || 520 fp->f_socket == NULL) 521 continue; 522 so = fp->f_socket; 523 if (so->so_type != type) 524 continue; 525 if (so->so_proto->pr_domain->dom_family != pf) 526 continue; 527 if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET, 528 KAUTH_REQ_NETWORK_SOCKET_CANSEE, so, NULL, NULL) != 0) 529 continue; 530 if (len >= elem_size && elem_count > 0) { 531 mutex_enter(&fp->f_lock); 532 fp->f_count++; 533 mutex_exit(&fp->f_lock); 534 LIST_INSERT_AFTER(fp, dfp, f_list); 535 mutex_exit(&filelist_lock); 536 sysctl_dounpcb(&pcb, so); 537 error = copyout(&pcb, dp, out_size); 538 closef(fp); 539 mutex_enter(&filelist_lock); 540 LIST_REMOVE(dfp, f_list); 541 if (error) 542 break; 543 dp += elem_size; 544 len -= elem_size; 545 } 546 needed += elem_size; 547 if (elem_count > 0 && elem_count != INT_MAX) 548 elem_count--; 549 } 550 mutex_exit(&filelist_lock); 551 fputdummy(dfp); 552 *oldlenp = needed; 553 if (oldp == NULL) 554 *oldlenp += PCB_SLOP * sizeof(struct kinfo_pcb); 555 sysctl_relock(); 556 557 return error; 558} 559 560static void 561sysctl_net_setup(void) 562{ 563 564 KASSERT(domain_sysctllog == NULL); 565 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 566 CTLFLAG_PERMANENT, 567 CTLTYPE_NODE, "local", 568 SYSCTL_DESCR("PF_LOCAL related settings"), 569 NULL, 0, NULL, 0, 570 CTL_NET, PF_LOCAL, CTL_EOL); 571 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 572 CTLFLAG_PERMANENT, 573 CTLTYPE_NODE, "stream", 574 SYSCTL_DESCR("SOCK_STREAM settings"), 575 NULL, 0, NULL, 0, 576 CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_EOL); 577 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 578 CTLFLAG_PERMANENT, 579 CTLTYPE_NODE, "seqpacket", 580 SYSCTL_DESCR("SOCK_SEQPACKET settings"), 581 NULL, 0, NULL, 0, 582 CTL_NET, PF_LOCAL, SOCK_SEQPACKET, CTL_EOL); 583 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 584 CTLFLAG_PERMANENT, 585 CTLTYPE_NODE, "dgram", 586 SYSCTL_DESCR("SOCK_DGRAM settings"), 587 NULL, 0, NULL, 0, 588 CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_EOL); 589 590 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 591 CTLFLAG_PERMANENT, 592 CTLTYPE_STRUCT, "pcblist", 593 SYSCTL_DESCR("SOCK_STREAM protocol control block list"), 594 sysctl_unpcblist, 0, NULL, 0, 595 CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_CREATE, CTL_EOL); 596 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 597 CTLFLAG_PERMANENT, 598 CTLTYPE_STRUCT, "pcblist", 599 SYSCTL_DESCR("SOCK_SEQPACKET protocol control " 600 "block list"), 601 sysctl_unpcblist, 0, NULL, 0, 602 CTL_NET, PF_LOCAL, SOCK_SEQPACKET, CTL_CREATE, CTL_EOL); 603 sysctl_createv(&domain_sysctllog, 0, NULL, NULL, 604 CTLFLAG_PERMANENT, 605 CTLTYPE_STRUCT, "pcblist", 606 SYSCTL_DESCR("SOCK_DGRAM protocol control block list"), 607 sysctl_unpcblist, 0, NULL, 0, 608 CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_CREATE, CTL_EOL); 609} 610 611void 612pfctlinput(int cmd, const struct sockaddr *sa) 613{ 614 struct domain *dp; 615 const struct protosw *pr; 616 617 DOMAIN_FOREACH(dp) { 618 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { 619 if (pr->pr_ctlinput != NULL) 620 (*pr->pr_ctlinput)(cmd, sa, NULL); 621 } 622 } 623} 624 625void 626pfctlinput2(int cmd, const struct sockaddr *sa, void *ctlparam) 627{ 628 struct domain *dp; 629 const struct protosw *pr; 630 631 if (sa == NULL) 632 return; 633 634 DOMAIN_FOREACH(dp) { 635 /* 636 * the check must be made by xx_ctlinput() anyways, to 637 * make sure we use data item pointed to by ctlparam in 638 * correct way. the following check is made just for safety. 639 */ 640 if (dp->dom_family != sa->sa_family) 641 continue; 642 643 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { 644 if (pr->pr_ctlinput != NULL) 645 (*pr->pr_ctlinput)(cmd, sa, ctlparam); 646 } 647 } 648} 649 650void 651pfslowtimo(void *arg) 652{ 653 struct domain *dp; 654 const struct protosw *pr; 655 656 pfslowtimo_now++; 657 658 DOMAIN_FOREACH(dp) { 659 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 660 if (pr->pr_slowtimo) 661 (*pr->pr_slowtimo)(); 662 } 663 callout_schedule(&pfslowtimo_ch, hz / PR_SLOWHZ); 664} 665 666void 667pffasttimo(void *arg) 668{ 669 struct domain *dp; 670 const struct protosw *pr; 671 672 pffasttimo_now++; 673 674 DOMAIN_FOREACH(dp) { 675 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 676 if (pr->pr_fasttimo) 677 (*pr->pr_fasttimo)(); 678 } 679 callout_schedule(&pffasttimo_ch, hz / PR_FASTHZ); 680} 681