1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/cnv.h> 32 #include <sys/dnv.h> 33 #include <sys/nv.h> 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 37 #include <assert.h> 38 #include <errno.h> 39 #include <netdb.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <libcasper.h> 45 #include <libcasper_service.h> 46 47 #include "cap_net.h" 48 49 #define CAPNET_MASK (CAPNET_ADDR2NAME | CAPNET_NAME2ADDR \ 50 CAPNET_DEPRECATED_ADDR2NAME | CAPNET_DEPRECATED_NAME2ADDR | \ 51 CAPNET_CONNECT | CAPNET_BIND | CAPNET_CONNECTDNS) 52 53 /* 54 * Defines for the names of the limits. 55 * XXX: we should convert all string constats to this to avoid typos. 56 */ 57 #define LIMIT_NV_BIND "bind" 58 #define LIMIT_NV_CONNECT "connect" 59 #define LIMIT_NV_ADDR2NAME "addr2name" 60 #define LIMIT_NV_NAME2ADDR "name2addr" 61 62 struct cap_net_limit { 63 cap_channel_t *cnl_chan; 64 uint64_t cnl_mode; 65 nvlist_t *cnl_addr2name; 66 nvlist_t *cnl_name2addr; 67 nvlist_t *cnl_connect; 68 nvlist_t *cnl_bind; 69 }; 70 71 static struct hostent hent; 72 73 static void 74 hostent_free(struct hostent *hp) 75 { 76 unsigned int ii; 77 78 free(hp->h_name); 79 hp->h_name = NULL; 80 if (hp->h_aliases != NULL) { 81 for (ii = 0; hp->h_aliases[ii] != NULL; ii++) 82 free(hp->h_aliases[ii]); 83 free(hp->h_aliases); 84 hp->h_aliases = NULL; 85 } 86 if (hp->h_addr_list != NULL) { 87 for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) 88 free(hp->h_addr_list[ii]); 89 free(hp->h_addr_list); 90 hp->h_addr_list = NULL; 91 } 92 } 93 94 static struct hostent * 95 hostent_unpack(const nvlist_t *nvl, struct hostent *hp) 96 { 97 unsigned int ii, nitems; 98 char nvlname[64]; 99 int n; 100 101 hostent_free(hp); 102 103 hp->h_name = strdup(nvlist_get_string(nvl, "name")); 104 if (hp->h_name == NULL) 105 goto fail; 106 hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype"); 107 hp->h_length = (int)nvlist_get_number(nvl, "length"); 108 109 nitems = (unsigned int)nvlist_get_number(nvl, "naliases"); 110 hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1); 111 if (hp->h_aliases == NULL) 112 goto fail; 113 for (ii = 0; ii < nitems; ii++) { 114 n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 115 assert(n > 0 && n < (int)sizeof(nvlname)); 116 hp->h_aliases[ii] = 117 strdup(nvlist_get_string(nvl, nvlname)); 118 if (hp->h_aliases[ii] == NULL) 119 goto fail; 120 } 121 hp->h_aliases[ii] = NULL; 122 123 nitems = (unsigned int)nvlist_get_number(nvl, "naddrs"); 124 hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1); 125 if (hp->h_addr_list == NULL) 126 goto fail; 127 for (ii = 0; ii < nitems; ii++) { 128 hp->h_addr_list[ii] = malloc(hp->h_length); 129 if (hp->h_addr_list[ii] == NULL) 130 goto fail; 131 n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 132 assert(n > 0 && n < (int)sizeof(nvlname)); 133 bcopy(nvlist_get_binary(nvl, nvlname, NULL), 134 hp->h_addr_list[ii], hp->h_length); 135 } 136 hp->h_addr_list[ii] = NULL; 137 138 return (hp); 139 fail: 140 hostent_free(hp); 141 h_errno = NO_RECOVERY; 142 return (NULL); 143 } 144 145 static int 146 request_cb(cap_channel_t *chan, const char *name, int s, 147 const struct sockaddr *saddr, socklen_t len) 148 { 149 nvlist_t *nvl; 150 int serrno; 151 152 nvl = nvlist_create(0); 153 nvlist_add_string(nvl, "cmd", name); 154 nvlist_add_descriptor(nvl, "s", s); 155 nvlist_add_binary(nvl, "saddr", saddr, len); 156 157 nvl = cap_xfer_nvlist(chan, nvl); 158 if (nvl == NULL) 159 return (-1); 160 161 if (nvlist_get_number(nvl, "error") != 0) { 162 serrno = (int)nvlist_get_number(nvl, "error"); 163 nvlist_destroy(nvl); 164 errno = serrno; 165 return (-1); 166 } 167 168 s = dup2(s, nvlist_get_descriptor(nvl, "s")); 169 nvlist_destroy(nvl); 170 171 return (s == -1 ? -1 : 0); 172 } 173 174 int 175 cap_bind(cap_channel_t *chan, int s, const struct sockaddr *addr, 176 socklen_t addrlen) 177 { 178 179 return (request_cb(chan, LIMIT_NV_BIND, s, addr, addrlen)); 180 } 181 182 int 183 cap_connect(cap_channel_t *chan, int s, const struct sockaddr *name, 184 socklen_t namelen) 185 { 186 187 return (request_cb(chan, LIMIT_NV_CONNECT, s, name, namelen)); 188 } 189 190 191 struct hostent * 192 cap_gethostbyname(cap_channel_t *chan, const char *name) 193 { 194 195 return (cap_gethostbyname2(chan, name, AF_INET)); 196 } 197 198 struct hostent * 199 cap_gethostbyname2(cap_channel_t *chan, const char *name, int af) 200 { 201 struct hostent *hp; 202 nvlist_t *nvl; 203 204 nvl = nvlist_create(0); 205 nvlist_add_string(nvl, "cmd", "gethostbyname"); 206 nvlist_add_number(nvl, "family", (uint64_t)af); 207 nvlist_add_string(nvl, "name", name); 208 nvl = cap_xfer_nvlist(chan, nvl); 209 if (nvl == NULL) { 210 h_errno = NO_RECOVERY; 211 return (NULL); 212 } 213 if (nvlist_get_number(nvl, "error") != 0) { 214 h_errno = (int)nvlist_get_number(nvl, "error"); 215 nvlist_destroy(nvl); 216 return (NULL); 217 } 218 219 hp = hostent_unpack(nvl, &hent); 220 nvlist_destroy(nvl); 221 return (hp); 222 } 223 224 struct hostent * 225 cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len, 226 int af) 227 { 228 struct hostent *hp; 229 nvlist_t *nvl; 230 231 nvl = nvlist_create(0); 232 nvlist_add_string(nvl, "cmd", "gethostbyaddr"); 233 nvlist_add_binary(nvl, "addr", addr, (size_t)len); 234 nvlist_add_number(nvl, "family", (uint64_t)af); 235 nvl = cap_xfer_nvlist(chan, nvl); 236 if (nvl == NULL) { 237 h_errno = NO_RECOVERY; 238 return (NULL); 239 } 240 if (nvlist_get_number(nvl, "error") != 0) { 241 h_errno = (int)nvlist_get_number(nvl, "error"); 242 nvlist_destroy(nvl); 243 return (NULL); 244 } 245 hp = hostent_unpack(nvl, &hent); 246 nvlist_destroy(nvl); 247 return (hp); 248 } 249 250 static struct addrinfo * 251 addrinfo_unpack(const nvlist_t *nvl) 252 { 253 struct addrinfo *ai; 254 const void *addr; 255 size_t addrlen; 256 const char *canonname; 257 258 addr = nvlist_get_binary(nvl, "ai_addr", &addrlen); 259 ai = malloc(sizeof(*ai) + addrlen); 260 if (ai == NULL) 261 return (NULL); 262 ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags"); 263 ai->ai_family = (int)nvlist_get_number(nvl, "ai_family"); 264 ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype"); 265 ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol"); 266 ai->ai_addrlen = (socklen_t)addrlen; 267 canonname = dnvlist_get_string(nvl, "ai_canonname", NULL); 268 if (canonname != NULL) { 269 ai->ai_canonname = strdup(canonname); 270 if (ai->ai_canonname == NULL) { 271 free(ai); 272 return (NULL); 273 } 274 } else { 275 ai->ai_canonname = NULL; 276 } 277 ai->ai_addr = (void *)(ai + 1); 278 bcopy(addr, ai->ai_addr, addrlen); 279 ai->ai_next = NULL; 280 281 return (ai); 282 } 283 284 int 285 cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname, 286 const struct addrinfo *hints, struct addrinfo **res) 287 { 288 struct addrinfo *firstai, *prevai, *curai; 289 unsigned int ii; 290 const nvlist_t *nvlai; 291 char nvlname[64]; 292 nvlist_t *nvl; 293 int error, n; 294 295 nvl = nvlist_create(0); 296 nvlist_add_string(nvl, "cmd", "getaddrinfo"); 297 if (hostname != NULL) 298 nvlist_add_string(nvl, "hostname", hostname); 299 if (servname != NULL) 300 nvlist_add_string(nvl, "servname", servname); 301 if (hints != NULL) { 302 nvlist_add_number(nvl, "hints.ai_flags", 303 (uint64_t)hints->ai_flags); 304 nvlist_add_number(nvl, "hints.ai_family", 305 (uint64_t)hints->ai_family); 306 nvlist_add_number(nvl, "hints.ai_socktype", 307 (uint64_t)hints->ai_socktype); 308 nvlist_add_number(nvl, "hints.ai_protocol", 309 (uint64_t)hints->ai_protocol); 310 } 311 nvl = cap_xfer_nvlist(chan, nvl); 312 if (nvl == NULL) 313 return (EAI_MEMORY); 314 if (nvlist_get_number(nvl, "error") != 0) { 315 error = (int)nvlist_get_number(nvl, "error"); 316 nvlist_destroy(nvl); 317 return (error); 318 } 319 320 nvlai = NULL; 321 firstai = prevai = curai = NULL; 322 for (ii = 0; ; ii++) { 323 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 324 assert(n > 0 && n < (int)sizeof(nvlname)); 325 if (!nvlist_exists_nvlist(nvl, nvlname)) 326 break; 327 nvlai = nvlist_get_nvlist(nvl, nvlname); 328 curai = addrinfo_unpack(nvlai); 329 if (curai == NULL) 330 return (EAI_MEMORY); 331 if (prevai != NULL) 332 prevai->ai_next = curai; 333 else 334 firstai = curai; 335 prevai = curai; 336 } 337 nvlist_destroy(nvl); 338 if (curai == NULL && nvlai != NULL) { 339 if (firstai == NULL) 340 freeaddrinfo(firstai); 341 return (EAI_MEMORY); 342 } 343 344 *res = firstai; 345 return (0); 346 } 347 348 int 349 cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen, 350 char *host, size_t hostlen, char *serv, size_t servlen, int flags) 351 { 352 nvlist_t *nvl; 353 int error; 354 355 nvl = nvlist_create(0); 356 nvlist_add_string(nvl, "cmd", "getnameinfo"); 357 nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen); 358 nvlist_add_number(nvl, "servlen", (uint64_t)servlen); 359 nvlist_add_binary(nvl, "sa", sa, (size_t)salen); 360 nvlist_add_number(nvl, "flags", (uint64_t)flags); 361 nvl = cap_xfer_nvlist(chan, nvl); 362 if (nvl == NULL) 363 return (EAI_MEMORY); 364 if (nvlist_get_number(nvl, "error") != 0) { 365 error = (int)nvlist_get_number(nvl, "error"); 366 nvlist_destroy(nvl); 367 return (error); 368 } 369 370 if (host != NULL && nvlist_exists_string(nvl, "host")) 371 strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1); 372 if (serv != NULL && nvlist_exists_string(nvl, "serv")) 373 strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1); 374 nvlist_destroy(nvl); 375 return (0); 376 } 377 378 cap_net_limit_t * 379 cap_net_limit_init(cap_channel_t *chan, uint64_t mode) 380 { 381 cap_net_limit_t *limit; 382 383 limit = calloc(1, sizeof(*limit)); 384 if (limit != NULL) { 385 limit->cnl_mode = mode; 386 limit->cnl_chan = chan; 387 limit->cnl_addr2name = nvlist_create(0); 388 limit->cnl_name2addr = nvlist_create(0); 389 limit->cnl_connect = nvlist_create(0); 390 limit->cnl_bind = nvlist_create(0); 391 } 392 393 return (limit); 394 } 395 396 static void 397 pack_limit(nvlist_t *lnvl, const char *name, nvlist_t *limit) 398 { 399 400 if (!nvlist_empty(limit)) { 401 nvlist_move_nvlist(lnvl, name, limit); 402 } else { 403 nvlist_destroy(limit); 404 } 405 } 406 407 int 408 cap_net_limit(cap_net_limit_t *limit) 409 { 410 nvlist_t *lnvl; 411 cap_channel_t *chan; 412 413 lnvl = nvlist_create(0); 414 nvlist_add_number(lnvl, "mode", limit->cnl_mode); 415 416 pack_limit(lnvl, LIMIT_NV_ADDR2NAME, limit->cnl_addr2name); 417 pack_limit(lnvl, LIMIT_NV_NAME2ADDR, limit->cnl_name2addr); 418 pack_limit(lnvl, LIMIT_NV_CONNECT, limit->cnl_connect); 419 pack_limit(lnvl, LIMIT_NV_BIND, limit->cnl_bind); 420 421 chan = limit->cnl_chan; 422 free(limit); 423 424 return (cap_limit_set(chan, lnvl)); 425 } 426 427 void 428 cap_net_free(cap_net_limit_t *limit) 429 { 430 431 if (limit == NULL) 432 return; 433 434 nvlist_destroy(limit->cnl_addr2name); 435 nvlist_destroy(limit->cnl_name2addr); 436 nvlist_destroy(limit->cnl_connect); 437 nvlist_destroy(limit->cnl_bind); 438 439 free(limit); 440 } 441 442 static void 443 pack_family(nvlist_t *nvl, int *family, size_t size) 444 { 445 size_t i; 446 447 i = 0; 448 if (!nvlist_exists_number_array(nvl, "family")) { 449 uint64_t val; 450 451 val = family[0]; 452 nvlist_add_number_array(nvl, "family", &val, 1); 453 i += 1; 454 } 455 456 for (; i < size; i++) { 457 nvlist_append_number_array(nvl, "family", family[i]); 458 } 459 } 460 461 static void 462 pack_sockaddr(nvlist_t *res, const struct sockaddr *sa, socklen_t salen) 463 { 464 nvlist_t *nvl; 465 466 if (!nvlist_exists_nvlist(res, "sockaddr")) { 467 nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 468 } else { 469 nvl = nvlist_take_nvlist(res, "sockaddr"); 470 } 471 472 nvlist_add_binary(nvl, "", sa, salen); 473 nvlist_move_nvlist(res, "sockaddr", nvl); 474 } 475 476 cap_net_limit_t * 477 cap_net_limit_addr2name_family(cap_net_limit_t *limit, int *family, size_t size) 478 { 479 480 pack_family(limit->cnl_addr2name, family, size); 481 return (limit); 482 } 483 484 cap_net_limit_t * 485 cap_net_limit_name2addr_family(cap_net_limit_t *limit, int *family, size_t size) 486 { 487 488 pack_family(limit->cnl_name2addr, family, size); 489 return (limit); 490 } 491 492 cap_net_limit_t * 493 cap_net_limit_name2addr(cap_net_limit_t *limit, const char *host, 494 const char *serv) 495 { 496 nvlist_t *nvl; 497 498 if (!nvlist_exists_nvlist(limit->cnl_name2addr, "hosts")) { 499 nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 500 } else { 501 nvl = nvlist_take_nvlist(limit->cnl_name2addr, "hosts"); 502 } 503 504 nvlist_add_string(nvl, 505 host != NULL ? host : "", 506 serv != NULL ? serv : ""); 507 508 nvlist_move_nvlist(limit->cnl_name2addr, "hosts", nvl); 509 return (limit); 510 } 511 512 cap_net_limit_t * 513 cap_net_limit_addr2name(cap_net_limit_t *limit, const struct sockaddr *sa, 514 socklen_t salen) 515 { 516 517 pack_sockaddr(limit->cnl_addr2name, sa, salen); 518 return (limit); 519 } 520 521 522 cap_net_limit_t * 523 cap_net_limit_connect(cap_net_limit_t *limit, const struct sockaddr *sa, 524 socklen_t salen) 525 { 526 527 pack_sockaddr(limit->cnl_connect, sa, salen); 528 return (limit); 529 } 530 531 cap_net_limit_t * 532 cap_net_limit_bind(cap_net_limit_t *limit, const struct sockaddr *sa, 533 socklen_t salen) 534 { 535 536 pack_sockaddr(limit->cnl_bind, sa, salen); 537 return (limit); 538 } 539 540 /* 541 * Service functions. 542 */ 543 544 static nvlist_t *capdnscache; 545 546 static void 547 net_add_sockaddr_to_cache(struct sockaddr *sa, socklen_t salen, bool deprecated) 548 { 549 void *cookie; 550 551 if (capdnscache == NULL) { 552 capdnscache = nvlist_create(NV_FLAG_NO_UNIQUE); 553 } else { 554 /* Lets keep it clean. Look for dups. */ 555 cookie = NULL; 556 while (nvlist_next(capdnscache, NULL, &cookie) != NULL) { 557 const void *data; 558 size_t size; 559 560 assert(cnvlist_type(cookie) == NV_TYPE_BINARY); 561 562 data = cnvlist_get_binary(cookie, &size); 563 if (salen != size) 564 continue; 565 if (memcmp(data, sa, size) == 0) 566 return; 567 } 568 } 569 570 nvlist_add_binary(capdnscache, deprecated ? "d" : "", sa, salen); 571 } 572 573 static void 574 net_add_hostent_to_cache(const char *address, size_t asize, int family) 575 { 576 577 if (family != AF_INET && family != AF_INET6) 578 return; 579 580 if (family == AF_INET6) { 581 struct sockaddr_in6 connaddr; 582 583 memset(&connaddr, 0, sizeof(connaddr)); 584 connaddr.sin6_family = AF_INET6; 585 memcpy((char *)&connaddr.sin6_addr, address, asize); 586 connaddr.sin6_port = 0; 587 588 net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 589 sizeof(connaddr), true); 590 } else { 591 struct sockaddr_in connaddr; 592 593 memset(&connaddr, 0, sizeof(connaddr)); 594 connaddr.sin_family = AF_INET; 595 memcpy((char *)&connaddr.sin_addr.s_addr, address, asize); 596 connaddr.sin_port = 0; 597 598 net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 599 sizeof(connaddr), true); 600 } 601 } 602 603 static bool 604 net_allowed_mode(const nvlist_t *limits, uint64_t mode) 605 { 606 607 if (limits == NULL) 608 return (true); 609 610 return ((nvlist_get_number(limits, "mode") & mode) == mode); 611 } 612 613 static bool 614 net_allowed_family(const nvlist_t *limits, int family) 615 { 616 const uint64_t *allowedfamily; 617 size_t i, allsize; 618 619 if (limits == NULL) 620 return (true); 621 622 /* If there are no familes at all, allow any mode. */ 623 if (!nvlist_exists_number_array(limits, "family")) 624 return (true); 625 626 allowedfamily = nvlist_get_number_array(limits, "family", &allsize); 627 for (i = 0; i < allsize; i++) { 628 /* XXX: what with AF_UNSPEC? */ 629 if (allowedfamily[i] == (uint64_t)family) { 630 return (true); 631 } 632 } 633 634 return (false); 635 } 636 637 static bool 638 net_allowed_bsaddr_impl(const nvlist_t *salimits, const void *saddr, 639 size_t saddrsize) 640 { 641 void *cookie; 642 const void *limit; 643 size_t limitsize; 644 645 cookie = NULL; 646 while (nvlist_next(salimits, NULL, &cookie) != NULL) { 647 limit = cnvlist_get_binary(cookie, &limitsize); 648 649 if (limitsize != saddrsize) { 650 continue; 651 } 652 if (memcmp(limit, saddr, limitsize) == 0) { 653 return (true); 654 } 655 656 /* 657 * In case of deprecated version (gethostbyname) we have to 658 * ignore port, because there is no such info in the hostent. 659 * Suporting only AF_INET and AF_INET6. 660 */ 661 if (strcmp(cnvlist_name(cookie), "d") != 0 || 662 (saddrsize != sizeof(struct sockaddr_in) && 663 saddrsize != sizeof(struct sockaddr_in6))) { 664 continue; 665 } 666 if (saddrsize == sizeof(struct sockaddr_in)) { 667 const struct sockaddr_in *saddrptr; 668 struct sockaddr_in sockaddr; 669 670 saddrptr = (const struct sockaddr_in *)saddr; 671 memcpy(&sockaddr, limit, sizeof(sockaddr)); 672 sockaddr.sin_port = saddrptr->sin_port; 673 674 if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 675 return (true); 676 } 677 } else if (saddrsize == sizeof(struct sockaddr_in6)) { 678 const struct sockaddr_in6 *saddrptr; 679 struct sockaddr_in6 sockaddr; 680 681 saddrptr = (const struct sockaddr_in6 *)saddr; 682 memcpy(&sockaddr, limit, sizeof(sockaddr)); 683 sockaddr.sin6_port = saddrptr->sin6_port; 684 685 if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 686 return (true); 687 } 688 } 689 } 690 691 return (false); 692 } 693 694 static bool 695 net_allowed_bsaddr(const nvlist_t *limits, const void *saddr, size_t saddrsize) 696 { 697 698 if (limits == NULL) 699 return (true); 700 701 if (!nvlist_exists_nvlist(limits, "sockaddr")) 702 return (true); 703 704 return (net_allowed_bsaddr_impl(nvlist_get_nvlist(limits, "sockaddr"), 705 saddr, saddrsize)); 706 } 707 708 static bool 709 net_allowed_hosts(const nvlist_t *limits, const char *name, const char *srvname) 710 { 711 void *cookie; 712 const nvlist_t *hlimits; 713 const char *testname, *testsrvname; 714 715 if (limits == NULL) { 716 return (true); 717 } 718 719 /* If there are no hosts at all, allow any. */ 720 if (!nvlist_exists_nvlist(limits, "hosts")) { 721 return (true); 722 } 723 724 cookie = NULL; 725 testname = (name == NULL ? "" : name); 726 testsrvname = (srvname == NULL ? "" : srvname); 727 hlimits = nvlist_get_nvlist(limits, "hosts"); 728 while (nvlist_next(hlimits, NULL, &cookie) != NULL) { 729 if (strcmp(cnvlist_name(cookie), "") != 0 && 730 strcmp(cnvlist_name(cookie), testname) != 0) { 731 continue; 732 } 733 734 if (strcmp(cnvlist_get_string(cookie), "") != 0 && 735 strcmp(cnvlist_get_string(cookie), testsrvname) != 0) { 736 continue; 737 } 738 739 return (true); 740 } 741 742 return (false); 743 } 744 745 static void 746 hostent_pack(const struct hostent *hp, nvlist_t *nvl, bool addtocache) 747 { 748 unsigned int ii; 749 char nvlname[64]; 750 int n; 751 752 nvlist_add_string(nvl, "name", hp->h_name); 753 nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype); 754 nvlist_add_number(nvl, "length", (uint64_t)hp->h_length); 755 756 if (hp->h_aliases == NULL) { 757 nvlist_add_number(nvl, "naliases", 0); 758 } else { 759 for (ii = 0; hp->h_aliases[ii] != NULL; ii++) { 760 n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 761 assert(n > 0 && n < (int)sizeof(nvlname)); 762 nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]); 763 } 764 nvlist_add_number(nvl, "naliases", (uint64_t)ii); 765 } 766 767 if (hp->h_addr_list == NULL) { 768 nvlist_add_number(nvl, "naddrs", 0); 769 } else { 770 for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) { 771 n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 772 assert(n > 0 && n < (int)sizeof(nvlname)); 773 nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii], 774 (size_t)hp->h_length); 775 if (addtocache) { 776 net_add_hostent_to_cache(hp->h_addr_list[ii], 777 hp->h_length, hp->h_addrtype); 778 } 779 } 780 nvlist_add_number(nvl, "naddrs", (uint64_t)ii); 781 } 782 } 783 784 static int 785 net_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin, 786 nvlist_t *nvlout) 787 { 788 struct hostent *hp; 789 int family; 790 const nvlist_t *funclimit; 791 const char *name; 792 bool dnscache; 793 794 if (!net_allowed_mode(limits, CAPNET_DEPRECATED_NAME2ADDR)) 795 return (ENOTCAPABLE); 796 797 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 798 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, NULL); 799 800 family = (int)nvlist_get_number(nvlin, "family"); 801 if (!net_allowed_family(funclimit, family)) 802 return (ENOTCAPABLE); 803 804 name = nvlist_get_string(nvlin, "name"); 805 if (!net_allowed_hosts(funclimit, name, "")) 806 return (ENOTCAPABLE); 807 808 hp = gethostbyname2(name, family); 809 if (hp == NULL) 810 return (h_errno); 811 hostent_pack(hp, nvlout, dnscache); 812 return (0); 813 } 814 815 static int 816 net_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin, 817 nvlist_t *nvlout) 818 { 819 struct hostent *hp; 820 const void *addr; 821 size_t addrsize; 822 int family; 823 const nvlist_t *funclimit; 824 825 if (!net_allowed_mode(limits, CAPNET_DEPRECATED_ADDR2NAME)) 826 return (ENOTCAPABLE); 827 828 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, NULL); 829 830 family = (int)nvlist_get_number(nvlin, "family"); 831 if (!net_allowed_family(funclimit, family)) 832 return (ENOTCAPABLE); 833 834 addr = nvlist_get_binary(nvlin, "addr", &addrsize); 835 if (!net_allowed_bsaddr(funclimit, addr, addrsize)) 836 return (ENOTCAPABLE); 837 838 hp = gethostbyaddr(addr, (socklen_t)addrsize, family); 839 if (hp == NULL) 840 return (h_errno); 841 hostent_pack(hp, nvlout, false); 842 return (0); 843 } 844 845 static int 846 net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 847 { 848 struct sockaddr_storage sast; 849 const void *sabin; 850 char *host, *serv; 851 size_t sabinsize, hostlen, servlen; 852 socklen_t salen; 853 int error, flags; 854 const nvlist_t *funclimit; 855 856 if (!net_allowed_mode(limits, CAPNET_ADDR2NAME)) 857 return (ENOTCAPABLE); 858 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, NULL); 859 860 error = 0; 861 host = serv = NULL; 862 memset(&sast, 0, sizeof(sast)); 863 864 hostlen = (size_t)nvlist_get_number(nvlin, "hostlen"); 865 servlen = (size_t)nvlist_get_number(nvlin, "servlen"); 866 867 if (hostlen > 0) { 868 host = calloc(1, hostlen + 1); 869 if (host == NULL) { 870 error = EAI_MEMORY; 871 goto out; 872 } 873 } 874 if (servlen > 0) { 875 serv = calloc(1, servlen + 1); 876 if (serv == NULL) { 877 error = EAI_MEMORY; 878 goto out; 879 } 880 } 881 882 sabin = nvlist_get_binary(nvlin, "sa", &sabinsize); 883 if (sabinsize > sizeof(sast)) { 884 error = EAI_FAIL; 885 goto out; 886 } 887 if (!net_allowed_bsaddr(funclimit, sabin, sabinsize)) 888 return (ENOTCAPABLE); 889 890 memcpy(&sast, sabin, sabinsize); 891 salen = (socklen_t)sabinsize; 892 893 if ((sast.ss_family != AF_INET || 894 salen != sizeof(struct sockaddr_in)) && 895 (sast.ss_family != AF_INET6 || 896 salen != sizeof(struct sockaddr_in6))) { 897 error = EAI_FAIL; 898 goto out; 899 } 900 901 if (!net_allowed_family(funclimit, (int)sast.ss_family)) { 902 error = ENOTCAPABLE; 903 goto out; 904 } 905 906 flags = (int)nvlist_get_number(nvlin, "flags"); 907 908 error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen, 909 serv, servlen, flags); 910 if (error != 0) 911 goto out; 912 913 if (host != NULL) 914 nvlist_move_string(nvlout, "host", host); 915 if (serv != NULL) 916 nvlist_move_string(nvlout, "serv", serv); 917 out: 918 if (error != 0) { 919 free(host); 920 free(serv); 921 } 922 return (error); 923 } 924 925 static nvlist_t * 926 addrinfo_pack(const struct addrinfo *ai) 927 { 928 nvlist_t *nvl; 929 930 nvl = nvlist_create(0); 931 nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags); 932 nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family); 933 nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype); 934 nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol); 935 nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen); 936 if (ai->ai_canonname != NULL) 937 nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname); 938 939 return (nvl); 940 } 941 942 static int 943 net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 944 { 945 struct addrinfo hints, *hintsp, *res, *cur; 946 const char *hostname, *servname; 947 char nvlname[64]; 948 nvlist_t *elem; 949 unsigned int ii; 950 int error, family, n; 951 const nvlist_t *funclimit; 952 bool dnscache; 953 954 if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) 955 return (ENOTCAPABLE); 956 dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 957 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, NULL); 958 959 hostname = dnvlist_get_string(nvlin, "hostname", NULL); 960 servname = dnvlist_get_string(nvlin, "servname", NULL); 961 if (nvlist_exists_number(nvlin, "hints.ai_flags")) { 962 hints.ai_flags = (int)nvlist_get_number(nvlin, 963 "hints.ai_flags"); 964 hints.ai_family = (int)nvlist_get_number(nvlin, 965 "hints.ai_family"); 966 hints.ai_socktype = (int)nvlist_get_number(nvlin, 967 "hints.ai_socktype"); 968 hints.ai_protocol = (int)nvlist_get_number(nvlin, 969 "hints.ai_protocol"); 970 hints.ai_addrlen = 0; 971 hints.ai_addr = NULL; 972 hints.ai_canonname = NULL; 973 hints.ai_next = NULL; 974 hintsp = &hints; 975 family = hints.ai_family; 976 } else { 977 hintsp = NULL; 978 family = AF_UNSPEC; 979 } 980 981 if (!net_allowed_family(funclimit, family)) 982 return (ENOTCAPABLE); 983 if (!net_allowed_hosts(funclimit, hostname, servname)) 984 return (ENOTCAPABLE); 985 error = getaddrinfo(hostname, servname, hintsp, &res); 986 if (error != 0) { 987 goto out; 988 } 989 990 for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) { 991 elem = addrinfo_pack(cur); 992 n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 993 assert(n > 0 && n < (int)sizeof(nvlname)); 994 nvlist_move_nvlist(nvlout, nvlname, elem); 995 if (dnscache) { 996 net_add_sockaddr_to_cache(cur->ai_addr, 997 cur->ai_addrlen, false); 998 } 999 } 1000 1001 freeaddrinfo(res); 1002 error = 0; 1003 out: 1004 return (error); 1005 } 1006 1007 static int 1008 net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1009 { 1010 int socket, serrno; 1011 const void *saddr; 1012 size_t len; 1013 const nvlist_t *funclimit; 1014 1015 if (!net_allowed_mode(limits, CAPNET_BIND)) 1016 return (ENOTCAPABLE); 1017 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_BIND, NULL); 1018 1019 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1020 1021 if (!net_allowed_bsaddr(funclimit, saddr, len)) 1022 return (ENOTCAPABLE); 1023 1024 socket = nvlist_take_descriptor(nvlin, "s"); 1025 if (bind(socket, saddr, len) < 0) { 1026 serrno = errno; 1027 close(socket); 1028 return (serrno); 1029 } 1030 1031 nvlist_move_descriptor(nvlout, "s", socket); 1032 1033 return (0); 1034 } 1035 1036 static int 1037 net_connect(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1038 { 1039 int socket, serrno; 1040 const void *saddr; 1041 const nvlist_t *funclimit; 1042 size_t len; 1043 bool conn, conndns; 1044 1045 conn = net_allowed_mode(limits, CAPNET_CONNECT); 1046 conndns = net_allowed_mode(limits, CAPNET_CONNECTDNS); 1047 1048 if (!conn && !conndns) 1049 return (ENOTCAPABLE); 1050 1051 funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_CONNECT, NULL); 1052 1053 saddr = nvlist_get_binary(nvlin, "saddr", &len); 1054 if (conn && !net_allowed_bsaddr(funclimit, saddr, len)) { 1055 return (ENOTCAPABLE); 1056 } else if (conndns && (capdnscache == NULL || 1057 !net_allowed_bsaddr_impl(capdnscache, saddr, len))) { 1058 return (ENOTCAPABLE); 1059 } 1060 socket = dup(nvlist_get_descriptor(nvlin, "s")); 1061 if (connect(socket, saddr, len) < 0) { 1062 serrno = errno; 1063 close(socket); 1064 return (serrno); 1065 } 1066 1067 nvlist_move_descriptor(nvlout, "s", socket); 1068 1069 return (0); 1070 } 1071 1072 static bool 1073 verify_only_sa_newlimts(const nvlist_t *oldfunclimits, 1074 const nvlist_t *newfunclimit) 1075 { 1076 void *cookie; 1077 1078 cookie = NULL; 1079 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1080 void *sacookie; 1081 1082 if (strcmp(cnvlist_name(cookie), "sockaddr") != 0) 1083 return (false); 1084 1085 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1086 return (false); 1087 1088 sacookie = NULL; 1089 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1090 &sacookie) != NULL) { 1091 const void *sa; 1092 size_t sasize; 1093 1094 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1095 return (false); 1096 1097 sa = cnvlist_get_binary(sacookie, &sasize); 1098 if (!net_allowed_bsaddr(oldfunclimits, sa, sasize)) 1099 return (false); 1100 } 1101 } 1102 1103 return (true); 1104 } 1105 1106 static bool 1107 verify_bind_newlimts(const nvlist_t *oldlimits, 1108 const nvlist_t *newfunclimit) 1109 { 1110 const nvlist_t *oldfunclimits; 1111 1112 oldfunclimits = NULL; 1113 if (oldlimits != NULL) { 1114 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_BIND, 1115 NULL); 1116 } 1117 1118 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1119 } 1120 1121 1122 static bool 1123 verify_connect_newlimits(const nvlist_t *oldlimits, 1124 const nvlist_t *newfunclimit) 1125 { 1126 const nvlist_t *oldfunclimits; 1127 1128 oldfunclimits = NULL; 1129 if (oldlimits != NULL) { 1130 oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_CONNECT, 1131 NULL); 1132 } 1133 1134 return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1135 } 1136 1137 static bool 1138 verify_addr2name_newlimits(const nvlist_t *oldlimits, 1139 const nvlist_t *newfunclimit) 1140 { 1141 void *cookie; 1142 const nvlist_t *oldfunclimits; 1143 1144 oldfunclimits = NULL; 1145 if (oldlimits != NULL) { 1146 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1147 LIMIT_NV_ADDR2NAME, NULL); 1148 } 1149 1150 cookie = NULL; 1151 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1152 if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) { 1153 void *sacookie; 1154 1155 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1156 return (false); 1157 1158 sacookie = NULL; 1159 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1160 &sacookie) != NULL) { 1161 const void *sa; 1162 size_t sasize; 1163 1164 if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1165 return (false); 1166 1167 sa = cnvlist_get_binary(sacookie, &sasize); 1168 if (!net_allowed_bsaddr(oldfunclimits, sa, 1169 sasize)) { 1170 return (false); 1171 } 1172 } 1173 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1174 size_t i, sfamilies; 1175 const uint64_t *families; 1176 1177 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1178 return (false); 1179 1180 families = cnvlist_get_number_array(cookie, &sfamilies); 1181 for (i = 0; i < sfamilies; i++) { 1182 if (!net_allowed_family(oldfunclimits, 1183 families[i])) { 1184 return (false); 1185 } 1186 } 1187 } else { 1188 return (false); 1189 } 1190 } 1191 1192 return (true); 1193 } 1194 1195 static bool 1196 verify_name2addr_newlimits(const nvlist_t *oldlimits, 1197 const nvlist_t *newfunclimit) 1198 { 1199 void *cookie; 1200 const nvlist_t *oldfunclimits; 1201 1202 oldfunclimits = NULL; 1203 if (oldlimits != NULL) { 1204 oldfunclimits = dnvlist_get_nvlist(oldlimits, 1205 LIMIT_NV_ADDR2NAME, NULL); 1206 } 1207 1208 cookie = NULL; 1209 while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1210 if (strcmp(cnvlist_name(cookie), "hosts") == 0) { 1211 void *hostcookie; 1212 1213 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1214 return (false); 1215 1216 hostcookie = NULL; 1217 while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1218 &hostcookie) != NULL) { 1219 if (cnvlist_type(hostcookie) != NV_TYPE_STRING) 1220 return (false); 1221 1222 if (!net_allowed_hosts(oldfunclimits, 1223 cnvlist_name(hostcookie), 1224 cnvlist_get_string(hostcookie))) { 1225 return (false); 1226 } 1227 } 1228 } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1229 size_t i, sfamilies; 1230 const uint64_t *families; 1231 1232 if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1233 return (false); 1234 1235 families = cnvlist_get_number_array(cookie, &sfamilies); 1236 for (i = 0; i < sfamilies; i++) { 1237 if (!net_allowed_family(oldfunclimits, 1238 families[i])) { 1239 return (false); 1240 } 1241 } 1242 } else { 1243 return (false); 1244 } 1245 } 1246 1247 return (true); 1248 } 1249 1250 static int 1251 net_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) 1252 { 1253 const char *name; 1254 void *cookie; 1255 bool hasmode, hasconnect, hasbind, hasaddr2name, hasname2addr; 1256 1257 /* 1258 * Modes: 1259 * ADDR2NAME: 1260 * getnameinfo 1261 * DEPRECATED_ADDR2NAME: 1262 * gethostbyaddr 1263 * 1264 * NAME2ADDR: 1265 * getaddrinfo 1266 * DEPRECATED_NAME2ADDR: 1267 * gethostbyname 1268 * 1269 * Limit scheme: 1270 * mode : NV_TYPE_NUMBER 1271 * connect : NV_TYPE_NVLIST 1272 * sockaddr : NV_TYPE_NVLIST 1273 * "" : NV_TYPE_BINARY 1274 * ... : NV_TYPE_BINARY 1275 * bind : NV_TYPE_NVLIST 1276 * sockaddr : NV_TYPE_NVLIST 1277 * "" : NV_TYPE_BINARY 1278 * ... : NV_TYPE_BINARY 1279 * addr2name : NV_TYPE_NVLIST 1280 * family : NV_TYPE_NUMBER_ARRAY 1281 * sockaddr : NV_TYPE_NVLIST 1282 * "" : NV_TYPE_BINARY 1283 * ... : NV_TYPE_BINARY 1284 * name2addr : NV_TYPE_NVLIST 1285 * family : NV_TYPE_NUMBER 1286 * hosts : NV_TYPE_NVLIST 1287 * host : servname : NV_TYPE_STRING 1288 */ 1289 1290 hasmode = false; 1291 hasconnect = false; 1292 hasbind = false; 1293 hasaddr2name = false; 1294 hasname2addr = false; 1295 1296 cookie = NULL; 1297 while ((name = nvlist_next(newlimits, NULL, &cookie)) != NULL) { 1298 if (strcmp(name, "mode") == 0) { 1299 if (cnvlist_type(cookie) != NV_TYPE_NUMBER) { 1300 return (NO_RECOVERY); 1301 } 1302 if (!net_allowed_mode(oldlimits, 1303 cnvlist_get_number(cookie))) { 1304 return (ENOTCAPABLE); 1305 } 1306 hasmode = true; 1307 continue; 1308 } 1309 1310 if (cnvlist_type(cookie) != NV_TYPE_NVLIST) { 1311 return (NO_RECOVERY); 1312 } 1313 1314 if (strcmp(name, LIMIT_NV_BIND) == 0) { 1315 hasbind = true; 1316 if (!verify_bind_newlimts(oldlimits, 1317 cnvlist_get_nvlist(cookie))) { 1318 return (ENOTCAPABLE); 1319 } 1320 } else if (strcmp(name, LIMIT_NV_CONNECT) == 0) { 1321 hasconnect = true; 1322 if (!verify_connect_newlimits(oldlimits, 1323 cnvlist_get_nvlist(cookie))) { 1324 return (ENOTCAPABLE); 1325 } 1326 } else if (strcmp(name, LIMIT_NV_ADDR2NAME) == 0) { 1327 hasaddr2name = true; 1328 if (!verify_addr2name_newlimits(oldlimits, 1329 cnvlist_get_nvlist(cookie))) { 1330 return (ENOTCAPABLE); 1331 } 1332 } else if (strcmp(name, LIMIT_NV_NAME2ADDR) == 0) { 1333 hasname2addr = true; 1334 if (!verify_name2addr_newlimits(oldlimits, 1335 cnvlist_get_nvlist(cookie))) { 1336 return (ENOTCAPABLE); 1337 } 1338 } 1339 } 1340 1341 /* Mode is required. */ 1342 if (!hasmode) 1343 return (ENOTCAPABLE); 1344 1345 /* 1346 * If the new limit doesn't mention mode or family we have to 1347 * check if the current limit does have those. Missing mode or 1348 * family in the limit means that all modes or families are 1349 * allowed. 1350 */ 1351 if (oldlimits == NULL) 1352 return (0); 1353 if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_BIND)) 1354 return (ENOTCAPABLE); 1355 if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_CONNECT)) 1356 return (ENOTCAPABLE); 1357 if (!hasaddr2name && nvlist_exists(oldlimits, LIMIT_NV_ADDR2NAME)) 1358 return (ENOTCAPABLE); 1359 if (!hasname2addr && nvlist_exists(oldlimits, LIMIT_NV_NAME2ADDR)) 1360 return (ENOTCAPABLE); 1361 return (0); 1362 } 1363 1364 static int 1365 net_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, 1366 nvlist_t *nvlout) 1367 { 1368 1369 if (strcmp(cmd, "bind") == 0) 1370 return (net_bind(limits, nvlin, nvlout)); 1371 else if (strcmp(cmd, "connect") == 0) 1372 return (net_connect(limits, nvlin, nvlout)); 1373 else if (strcmp(cmd, "gethostbyname") == 0) 1374 return (net_gethostbyname(limits, nvlin, nvlout)); 1375 else if (strcmp(cmd, "gethostbyaddr") == 0) 1376 return (net_gethostbyaddr(limits, nvlin, nvlout)); 1377 else if (strcmp(cmd, "getnameinfo") == 0) 1378 return (net_getnameinfo(limits, nvlin, nvlout)); 1379 else if (strcmp(cmd, "getaddrinfo") == 0) 1380 return (net_getaddrinfo(limits, nvlin, nvlout)); 1381 1382 return (EINVAL); 1383 } 1384 1385 CREATE_SERVICE("system.net", net_limit, net_command, 0); 1386