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