1832dc76bSMariusz Zaborski /*- 2832dc76bSMariusz Zaborski * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3832dc76bSMariusz Zaborski * 4832dc76bSMariusz Zaborski * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org> 5832dc76bSMariusz Zaborski * 6832dc76bSMariusz Zaborski * Redistribution and use in source and binary forms, with or without 7832dc76bSMariusz Zaborski * modification, are permitted provided that the following conditions 8832dc76bSMariusz Zaborski * are met: 9832dc76bSMariusz Zaborski * 1. Redistributions of source code must retain the above copyright 10832dc76bSMariusz Zaborski * notice, this list of conditions and the following disclaimer. 11832dc76bSMariusz Zaborski * 2. Redistributions in binary form must reproduce the above copyright 12832dc76bSMariusz Zaborski * notice, this list of conditions and the following disclaimer in the 13832dc76bSMariusz Zaborski * documentation and/or other materials provided with the distribution. 14832dc76bSMariusz Zaborski * 15832dc76bSMariusz Zaborski * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16832dc76bSMariusz Zaborski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17832dc76bSMariusz Zaborski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18832dc76bSMariusz Zaborski * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19832dc76bSMariusz Zaborski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20832dc76bSMariusz Zaborski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21832dc76bSMariusz Zaborski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22832dc76bSMariusz Zaborski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23832dc76bSMariusz Zaborski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24832dc76bSMariusz Zaborski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25832dc76bSMariusz Zaborski * SUCH DAMAGE. 26832dc76bSMariusz Zaborski */ 27832dc76bSMariusz Zaborski 28832dc76bSMariusz Zaborski #include <sys/cdefs.h> 29832dc76bSMariusz Zaborski __FBSDID("$FreeBSD$"); 30832dc76bSMariusz Zaborski 31832dc76bSMariusz Zaborski #include <sys/cnv.h> 32832dc76bSMariusz Zaborski #include <sys/dnv.h> 33832dc76bSMariusz Zaborski #include <sys/nv.h> 34832dc76bSMariusz Zaborski #include <sys/socket.h> 35832dc76bSMariusz Zaborski #include <netinet/in.h> 36832dc76bSMariusz Zaborski 37832dc76bSMariusz Zaborski #include <assert.h> 38832dc76bSMariusz Zaborski #include <errno.h> 39832dc76bSMariusz Zaborski #include <netdb.h> 40832dc76bSMariusz Zaborski #include <stdio.h> 41832dc76bSMariusz Zaborski #include <string.h> 42832dc76bSMariusz Zaborski #include <unistd.h> 43832dc76bSMariusz Zaborski 44832dc76bSMariusz Zaborski #include <libcasper.h> 45832dc76bSMariusz Zaborski #include <libcasper_service.h> 46832dc76bSMariusz Zaborski 47832dc76bSMariusz Zaborski #include "cap_net.h" 48832dc76bSMariusz Zaborski 49832dc76bSMariusz Zaborski #define CAPNET_MASK (CAPNET_ADDR2NAME | CAPNET_NAME2ADDR \ 50832dc76bSMariusz Zaborski CAPNET_DEPRECATED_ADDR2NAME | CAPNET_DEPRECATED_NAME2ADDR | \ 51832dc76bSMariusz Zaborski CAPNET_CONNECT | CAPNET_BIND | CAPNET_CONNECTDNS) 52832dc76bSMariusz Zaborski 53832dc76bSMariusz Zaborski /* 54832dc76bSMariusz Zaborski * Defines for the names of the limits. 55832dc76bSMariusz Zaborski * XXX: we should convert all string constats to this to avoid typos. 56832dc76bSMariusz Zaborski */ 57832dc76bSMariusz Zaborski #define LIMIT_NV_BIND "bind" 58832dc76bSMariusz Zaborski #define LIMIT_NV_CONNECT "connect" 59832dc76bSMariusz Zaborski #define LIMIT_NV_ADDR2NAME "addr2name" 60832dc76bSMariusz Zaborski #define LIMIT_NV_NAME2ADDR "name2addr" 61832dc76bSMariusz Zaborski 62832dc76bSMariusz Zaborski struct cap_net_limit { 63832dc76bSMariusz Zaborski cap_channel_t *cnl_chan; 64832dc76bSMariusz Zaborski uint64_t cnl_mode; 65832dc76bSMariusz Zaborski nvlist_t *cnl_addr2name; 66832dc76bSMariusz Zaborski nvlist_t *cnl_name2addr; 67832dc76bSMariusz Zaborski nvlist_t *cnl_connect; 68832dc76bSMariusz Zaborski nvlist_t *cnl_bind; 69832dc76bSMariusz Zaborski }; 70832dc76bSMariusz Zaborski 71832dc76bSMariusz Zaborski static struct hostent hent; 72832dc76bSMariusz Zaborski 73832dc76bSMariusz Zaborski static void 74832dc76bSMariusz Zaborski hostent_free(struct hostent *hp) 75832dc76bSMariusz Zaborski { 76832dc76bSMariusz Zaborski unsigned int ii; 77832dc76bSMariusz Zaborski 78832dc76bSMariusz Zaborski free(hp->h_name); 79832dc76bSMariusz Zaborski hp->h_name = NULL; 80832dc76bSMariusz Zaborski if (hp->h_aliases != NULL) { 81832dc76bSMariusz Zaborski for (ii = 0; hp->h_aliases[ii] != NULL; ii++) 82832dc76bSMariusz Zaborski free(hp->h_aliases[ii]); 83832dc76bSMariusz Zaborski free(hp->h_aliases); 84832dc76bSMariusz Zaborski hp->h_aliases = NULL; 85832dc76bSMariusz Zaborski } 86832dc76bSMariusz Zaborski if (hp->h_addr_list != NULL) { 87832dc76bSMariusz Zaborski for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) 88832dc76bSMariusz Zaborski free(hp->h_addr_list[ii]); 89832dc76bSMariusz Zaborski free(hp->h_addr_list); 90832dc76bSMariusz Zaborski hp->h_addr_list = NULL; 91832dc76bSMariusz Zaborski } 92832dc76bSMariusz Zaborski } 93832dc76bSMariusz Zaborski 94832dc76bSMariusz Zaborski static struct hostent * 95832dc76bSMariusz Zaborski hostent_unpack(const nvlist_t *nvl, struct hostent *hp) 96832dc76bSMariusz Zaborski { 97832dc76bSMariusz Zaborski unsigned int ii, nitems; 98832dc76bSMariusz Zaborski char nvlname[64]; 99832dc76bSMariusz Zaborski int n; 100832dc76bSMariusz Zaborski 101832dc76bSMariusz Zaborski hostent_free(hp); 102832dc76bSMariusz Zaborski 103832dc76bSMariusz Zaborski hp->h_name = strdup(nvlist_get_string(nvl, "name")); 104832dc76bSMariusz Zaborski if (hp->h_name == NULL) 105832dc76bSMariusz Zaborski goto fail; 106832dc76bSMariusz Zaborski hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype"); 107832dc76bSMariusz Zaborski hp->h_length = (int)nvlist_get_number(nvl, "length"); 108832dc76bSMariusz Zaborski 109832dc76bSMariusz Zaborski nitems = (unsigned int)nvlist_get_number(nvl, "naliases"); 110832dc76bSMariusz Zaborski hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1); 111832dc76bSMariusz Zaborski if (hp->h_aliases == NULL) 112832dc76bSMariusz Zaborski goto fail; 113832dc76bSMariusz Zaborski for (ii = 0; ii < nitems; ii++) { 114832dc76bSMariusz Zaborski n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 115832dc76bSMariusz Zaborski assert(n > 0 && n < (int)sizeof(nvlname)); 116832dc76bSMariusz Zaborski hp->h_aliases[ii] = 117832dc76bSMariusz Zaborski strdup(nvlist_get_string(nvl, nvlname)); 118832dc76bSMariusz Zaborski if (hp->h_aliases[ii] == NULL) 119832dc76bSMariusz Zaborski goto fail; 120832dc76bSMariusz Zaborski } 121832dc76bSMariusz Zaborski hp->h_aliases[ii] = NULL; 122832dc76bSMariusz Zaborski 123832dc76bSMariusz Zaborski nitems = (unsigned int)nvlist_get_number(nvl, "naddrs"); 124832dc76bSMariusz Zaborski hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1); 125832dc76bSMariusz Zaborski if (hp->h_addr_list == NULL) 126832dc76bSMariusz Zaborski goto fail; 127832dc76bSMariusz Zaborski for (ii = 0; ii < nitems; ii++) { 128832dc76bSMariusz Zaborski hp->h_addr_list[ii] = malloc(hp->h_length); 129832dc76bSMariusz Zaborski if (hp->h_addr_list[ii] == NULL) 130832dc76bSMariusz Zaborski goto fail; 131832dc76bSMariusz Zaborski n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 132832dc76bSMariusz Zaborski assert(n > 0 && n < (int)sizeof(nvlname)); 133832dc76bSMariusz Zaborski bcopy(nvlist_get_binary(nvl, nvlname, NULL), 134832dc76bSMariusz Zaborski hp->h_addr_list[ii], hp->h_length); 135832dc76bSMariusz Zaborski } 136832dc76bSMariusz Zaborski hp->h_addr_list[ii] = NULL; 137832dc76bSMariusz Zaborski 138832dc76bSMariusz Zaborski return (hp); 139832dc76bSMariusz Zaborski fail: 140832dc76bSMariusz Zaborski hostent_free(hp); 141832dc76bSMariusz Zaborski h_errno = NO_RECOVERY; 142832dc76bSMariusz Zaborski return (NULL); 143832dc76bSMariusz Zaborski } 144832dc76bSMariusz Zaborski 145832dc76bSMariusz Zaborski static int 146832dc76bSMariusz Zaborski request_cb(cap_channel_t *chan, const char *name, int s, 147832dc76bSMariusz Zaborski const struct sockaddr *saddr, socklen_t len) 148832dc76bSMariusz Zaborski { 149832dc76bSMariusz Zaborski nvlist_t *nvl; 150832dc76bSMariusz Zaborski int serrno; 151832dc76bSMariusz Zaborski 152832dc76bSMariusz Zaborski nvl = nvlist_create(0); 153832dc76bSMariusz Zaborski nvlist_add_string(nvl, "cmd", name); 154832dc76bSMariusz Zaborski nvlist_add_descriptor(nvl, "s", s); 155832dc76bSMariusz Zaborski nvlist_add_binary(nvl, "saddr", saddr, len); 156832dc76bSMariusz Zaborski 157832dc76bSMariusz Zaborski nvl = cap_xfer_nvlist(chan, nvl); 158832dc76bSMariusz Zaborski if (nvl == NULL) 159832dc76bSMariusz Zaborski return (-1); 160832dc76bSMariusz Zaborski 161832dc76bSMariusz Zaborski if (nvlist_get_number(nvl, "error") != 0) { 162832dc76bSMariusz Zaborski serrno = (int)nvlist_get_number(nvl, "error"); 163832dc76bSMariusz Zaborski nvlist_destroy(nvl); 164832dc76bSMariusz Zaborski errno = serrno; 165832dc76bSMariusz Zaborski return (-1); 166832dc76bSMariusz Zaborski } 167832dc76bSMariusz Zaborski 168832dc76bSMariusz Zaborski s = dup2(s, nvlist_get_descriptor(nvl, "s")); 169832dc76bSMariusz Zaborski nvlist_destroy(nvl); 170832dc76bSMariusz Zaborski 171832dc76bSMariusz Zaborski return (s == -1 ? -1 : 0); 172832dc76bSMariusz Zaborski } 173832dc76bSMariusz Zaborski 174832dc76bSMariusz Zaborski int 175832dc76bSMariusz Zaborski cap_bind(cap_channel_t *chan, int s, const struct sockaddr *addr, 176832dc76bSMariusz Zaborski socklen_t addrlen) 177832dc76bSMariusz Zaborski { 178832dc76bSMariusz Zaborski 179832dc76bSMariusz Zaborski return (request_cb(chan, LIMIT_NV_BIND, s, addr, addrlen)); 180832dc76bSMariusz Zaborski } 181832dc76bSMariusz Zaborski 182832dc76bSMariusz Zaborski int 183832dc76bSMariusz Zaborski cap_connect(cap_channel_t *chan, int s, const struct sockaddr *name, 184832dc76bSMariusz Zaborski socklen_t namelen) 185832dc76bSMariusz Zaborski { 186832dc76bSMariusz Zaborski 187832dc76bSMariusz Zaborski return (request_cb(chan, LIMIT_NV_CONNECT, s, name, namelen)); 188832dc76bSMariusz Zaborski } 189832dc76bSMariusz Zaborski 190832dc76bSMariusz Zaborski 191832dc76bSMariusz Zaborski struct hostent * 192832dc76bSMariusz Zaborski cap_gethostbyname(cap_channel_t *chan, const char *name) 193832dc76bSMariusz Zaborski { 194832dc76bSMariusz Zaborski 195832dc76bSMariusz Zaborski return (cap_gethostbyname2(chan, name, AF_INET)); 196832dc76bSMariusz Zaborski } 197832dc76bSMariusz Zaborski 198832dc76bSMariusz Zaborski struct hostent * 199832dc76bSMariusz Zaborski cap_gethostbyname2(cap_channel_t *chan, const char *name, int af) 200832dc76bSMariusz Zaborski { 201832dc76bSMariusz Zaborski struct hostent *hp; 202832dc76bSMariusz Zaborski nvlist_t *nvl; 203832dc76bSMariusz Zaborski 204832dc76bSMariusz Zaborski nvl = nvlist_create(0); 205832dc76bSMariusz Zaborski nvlist_add_string(nvl, "cmd", "gethostbyname"); 206832dc76bSMariusz Zaborski nvlist_add_number(nvl, "family", (uint64_t)af); 207832dc76bSMariusz Zaborski nvlist_add_string(nvl, "name", name); 208832dc76bSMariusz Zaborski nvl = cap_xfer_nvlist(chan, nvl); 209832dc76bSMariusz Zaborski if (nvl == NULL) { 210832dc76bSMariusz Zaborski h_errno = NO_RECOVERY; 211832dc76bSMariusz Zaborski return (NULL); 212832dc76bSMariusz Zaborski } 213832dc76bSMariusz Zaborski if (nvlist_get_number(nvl, "error") != 0) { 214832dc76bSMariusz Zaborski h_errno = (int)nvlist_get_number(nvl, "error"); 215832dc76bSMariusz Zaborski nvlist_destroy(nvl); 216832dc76bSMariusz Zaborski return (NULL); 217832dc76bSMariusz Zaborski } 218832dc76bSMariusz Zaborski 219832dc76bSMariusz Zaborski hp = hostent_unpack(nvl, &hent); 220832dc76bSMariusz Zaborski nvlist_destroy(nvl); 221832dc76bSMariusz Zaborski return (hp); 222832dc76bSMariusz Zaborski } 223832dc76bSMariusz Zaborski 224832dc76bSMariusz Zaborski struct hostent * 225832dc76bSMariusz Zaborski cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len, 226832dc76bSMariusz Zaborski int af) 227832dc76bSMariusz Zaborski { 228832dc76bSMariusz Zaborski struct hostent *hp; 229832dc76bSMariusz Zaborski nvlist_t *nvl; 230832dc76bSMariusz Zaborski 231832dc76bSMariusz Zaborski nvl = nvlist_create(0); 232832dc76bSMariusz Zaborski nvlist_add_string(nvl, "cmd", "gethostbyaddr"); 233832dc76bSMariusz Zaborski nvlist_add_binary(nvl, "addr", addr, (size_t)len); 234832dc76bSMariusz Zaborski nvlist_add_number(nvl, "family", (uint64_t)af); 235832dc76bSMariusz Zaborski nvl = cap_xfer_nvlist(chan, nvl); 236832dc76bSMariusz Zaborski if (nvl == NULL) { 237832dc76bSMariusz Zaborski h_errno = NO_RECOVERY; 238832dc76bSMariusz Zaborski return (NULL); 239832dc76bSMariusz Zaborski } 240832dc76bSMariusz Zaborski if (nvlist_get_number(nvl, "error") != 0) { 241832dc76bSMariusz Zaborski h_errno = (int)nvlist_get_number(nvl, "error"); 242832dc76bSMariusz Zaborski nvlist_destroy(nvl); 243832dc76bSMariusz Zaborski return (NULL); 244832dc76bSMariusz Zaborski } 245832dc76bSMariusz Zaborski hp = hostent_unpack(nvl, &hent); 246832dc76bSMariusz Zaborski nvlist_destroy(nvl); 247832dc76bSMariusz Zaborski return (hp); 248832dc76bSMariusz Zaborski } 249832dc76bSMariusz Zaborski 250832dc76bSMariusz Zaborski static struct addrinfo * 251832dc76bSMariusz Zaborski addrinfo_unpack(const nvlist_t *nvl) 252832dc76bSMariusz Zaborski { 253832dc76bSMariusz Zaborski struct addrinfo *ai; 254832dc76bSMariusz Zaborski const void *addr; 255832dc76bSMariusz Zaborski size_t addrlen; 256832dc76bSMariusz Zaborski const char *canonname; 257832dc76bSMariusz Zaborski 258832dc76bSMariusz Zaborski addr = nvlist_get_binary(nvl, "ai_addr", &addrlen); 259832dc76bSMariusz Zaborski ai = malloc(sizeof(*ai) + addrlen); 260832dc76bSMariusz Zaborski if (ai == NULL) 261832dc76bSMariusz Zaborski return (NULL); 262832dc76bSMariusz Zaborski ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags"); 263832dc76bSMariusz Zaborski ai->ai_family = (int)nvlist_get_number(nvl, "ai_family"); 264832dc76bSMariusz Zaborski ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype"); 265832dc76bSMariusz Zaborski ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol"); 266832dc76bSMariusz Zaborski ai->ai_addrlen = (socklen_t)addrlen; 267832dc76bSMariusz Zaborski canonname = dnvlist_get_string(nvl, "ai_canonname", NULL); 268832dc76bSMariusz Zaborski if (canonname != NULL) { 269832dc76bSMariusz Zaborski ai->ai_canonname = strdup(canonname); 270832dc76bSMariusz Zaborski if (ai->ai_canonname == NULL) { 271832dc76bSMariusz Zaborski free(ai); 272832dc76bSMariusz Zaborski return (NULL); 273832dc76bSMariusz Zaborski } 274832dc76bSMariusz Zaborski } else { 275832dc76bSMariusz Zaborski ai->ai_canonname = NULL; 276832dc76bSMariusz Zaborski } 277832dc76bSMariusz Zaborski ai->ai_addr = (void *)(ai + 1); 278832dc76bSMariusz Zaborski bcopy(addr, ai->ai_addr, addrlen); 279832dc76bSMariusz Zaborski ai->ai_next = NULL; 280832dc76bSMariusz Zaborski 281832dc76bSMariusz Zaborski return (ai); 282832dc76bSMariusz Zaborski } 283832dc76bSMariusz Zaborski 284832dc76bSMariusz Zaborski int 285832dc76bSMariusz Zaborski cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname, 286832dc76bSMariusz Zaborski const struct addrinfo *hints, struct addrinfo **res) 287832dc76bSMariusz Zaborski { 288832dc76bSMariusz Zaborski struct addrinfo *firstai, *prevai, *curai; 289832dc76bSMariusz Zaborski unsigned int ii; 290832dc76bSMariusz Zaborski const nvlist_t *nvlai; 291832dc76bSMariusz Zaborski char nvlname[64]; 292832dc76bSMariusz Zaborski nvlist_t *nvl; 293832dc76bSMariusz Zaborski int error, n; 294832dc76bSMariusz Zaborski 295832dc76bSMariusz Zaborski nvl = nvlist_create(0); 296832dc76bSMariusz Zaborski nvlist_add_string(nvl, "cmd", "getaddrinfo"); 297832dc76bSMariusz Zaborski if (hostname != NULL) 298832dc76bSMariusz Zaborski nvlist_add_string(nvl, "hostname", hostname); 299832dc76bSMariusz Zaborski if (servname != NULL) 300832dc76bSMariusz Zaborski nvlist_add_string(nvl, "servname", servname); 301832dc76bSMariusz Zaborski if (hints != NULL) { 302832dc76bSMariusz Zaborski nvlist_add_number(nvl, "hints.ai_flags", 303832dc76bSMariusz Zaborski (uint64_t)hints->ai_flags); 304832dc76bSMariusz Zaborski nvlist_add_number(nvl, "hints.ai_family", 305832dc76bSMariusz Zaborski (uint64_t)hints->ai_family); 306832dc76bSMariusz Zaborski nvlist_add_number(nvl, "hints.ai_socktype", 307832dc76bSMariusz Zaborski (uint64_t)hints->ai_socktype); 308832dc76bSMariusz Zaborski nvlist_add_number(nvl, "hints.ai_protocol", 309832dc76bSMariusz Zaborski (uint64_t)hints->ai_protocol); 310832dc76bSMariusz Zaborski } 311832dc76bSMariusz Zaborski nvl = cap_xfer_nvlist(chan, nvl); 312832dc76bSMariusz Zaborski if (nvl == NULL) 313832dc76bSMariusz Zaborski return (EAI_MEMORY); 314832dc76bSMariusz Zaborski if (nvlist_get_number(nvl, "error") != 0) { 315832dc76bSMariusz Zaborski error = (int)nvlist_get_number(nvl, "error"); 316832dc76bSMariusz Zaborski nvlist_destroy(nvl); 317832dc76bSMariusz Zaborski return (error); 318832dc76bSMariusz Zaborski } 319832dc76bSMariusz Zaborski 320832dc76bSMariusz Zaborski nvlai = NULL; 321832dc76bSMariusz Zaborski firstai = prevai = curai = NULL; 322832dc76bSMariusz Zaborski for (ii = 0; ; ii++) { 323832dc76bSMariusz Zaborski n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 324832dc76bSMariusz Zaborski assert(n > 0 && n < (int)sizeof(nvlname)); 325832dc76bSMariusz Zaborski if (!nvlist_exists_nvlist(nvl, nvlname)) 326832dc76bSMariusz Zaborski break; 327832dc76bSMariusz Zaborski nvlai = nvlist_get_nvlist(nvl, nvlname); 328832dc76bSMariusz Zaborski curai = addrinfo_unpack(nvlai); 329*88910b8bSMariusz Zaborski if (curai == NULL) { 330*88910b8bSMariusz Zaborski nvlist_destroy(nvl); 331832dc76bSMariusz Zaborski return (EAI_MEMORY); 332*88910b8bSMariusz Zaborski } 333832dc76bSMariusz Zaborski if (prevai != NULL) 334832dc76bSMariusz Zaborski prevai->ai_next = curai; 335832dc76bSMariusz Zaborski else 336832dc76bSMariusz Zaborski firstai = curai; 337832dc76bSMariusz Zaborski prevai = curai; 338832dc76bSMariusz Zaborski } 339832dc76bSMariusz Zaborski nvlist_destroy(nvl); 340832dc76bSMariusz Zaborski if (curai == NULL && nvlai != NULL) { 341832dc76bSMariusz Zaborski if (firstai == NULL) 342832dc76bSMariusz Zaborski freeaddrinfo(firstai); 343832dc76bSMariusz Zaborski return (EAI_MEMORY); 344832dc76bSMariusz Zaborski } 345832dc76bSMariusz Zaborski 346832dc76bSMariusz Zaborski *res = firstai; 347832dc76bSMariusz Zaborski return (0); 348832dc76bSMariusz Zaborski } 349832dc76bSMariusz Zaborski 350832dc76bSMariusz Zaborski int 351832dc76bSMariusz Zaborski cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen, 352832dc76bSMariusz Zaborski char *host, size_t hostlen, char *serv, size_t servlen, int flags) 353832dc76bSMariusz Zaborski { 354832dc76bSMariusz Zaborski nvlist_t *nvl; 355832dc76bSMariusz Zaborski int error; 356832dc76bSMariusz Zaborski 357832dc76bSMariusz Zaborski nvl = nvlist_create(0); 358832dc76bSMariusz Zaborski nvlist_add_string(nvl, "cmd", "getnameinfo"); 359832dc76bSMariusz Zaborski nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen); 360832dc76bSMariusz Zaborski nvlist_add_number(nvl, "servlen", (uint64_t)servlen); 361832dc76bSMariusz Zaborski nvlist_add_binary(nvl, "sa", sa, (size_t)salen); 362832dc76bSMariusz Zaborski nvlist_add_number(nvl, "flags", (uint64_t)flags); 363832dc76bSMariusz Zaborski nvl = cap_xfer_nvlist(chan, nvl); 364832dc76bSMariusz Zaborski if (nvl == NULL) 365832dc76bSMariusz Zaborski return (EAI_MEMORY); 366832dc76bSMariusz Zaborski if (nvlist_get_number(nvl, "error") != 0) { 367832dc76bSMariusz Zaborski error = (int)nvlist_get_number(nvl, "error"); 368832dc76bSMariusz Zaborski nvlist_destroy(nvl); 369832dc76bSMariusz Zaborski return (error); 370832dc76bSMariusz Zaborski } 371832dc76bSMariusz Zaborski 372832dc76bSMariusz Zaborski if (host != NULL && nvlist_exists_string(nvl, "host")) 373832dc76bSMariusz Zaborski strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1); 374832dc76bSMariusz Zaborski if (serv != NULL && nvlist_exists_string(nvl, "serv")) 375832dc76bSMariusz Zaborski strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1); 376832dc76bSMariusz Zaborski nvlist_destroy(nvl); 377832dc76bSMariusz Zaborski return (0); 378832dc76bSMariusz Zaborski } 379832dc76bSMariusz Zaborski 380832dc76bSMariusz Zaborski cap_net_limit_t * 381832dc76bSMariusz Zaborski cap_net_limit_init(cap_channel_t *chan, uint64_t mode) 382832dc76bSMariusz Zaborski { 383832dc76bSMariusz Zaborski cap_net_limit_t *limit; 384832dc76bSMariusz Zaborski 385832dc76bSMariusz Zaborski limit = calloc(1, sizeof(*limit)); 386832dc76bSMariusz Zaborski if (limit != NULL) { 387832dc76bSMariusz Zaborski limit->cnl_mode = mode; 388832dc76bSMariusz Zaborski limit->cnl_chan = chan; 389832dc76bSMariusz Zaborski limit->cnl_addr2name = nvlist_create(0); 390832dc76bSMariusz Zaborski limit->cnl_name2addr = nvlist_create(0); 391832dc76bSMariusz Zaborski limit->cnl_connect = nvlist_create(0); 392832dc76bSMariusz Zaborski limit->cnl_bind = nvlist_create(0); 393832dc76bSMariusz Zaborski } 394832dc76bSMariusz Zaborski 395832dc76bSMariusz Zaborski return (limit); 396832dc76bSMariusz Zaborski } 397832dc76bSMariusz Zaborski 398832dc76bSMariusz Zaborski static void 399832dc76bSMariusz Zaborski pack_limit(nvlist_t *lnvl, const char *name, nvlist_t *limit) 400832dc76bSMariusz Zaborski { 401832dc76bSMariusz Zaborski 402832dc76bSMariusz Zaborski if (!nvlist_empty(limit)) { 403832dc76bSMariusz Zaborski nvlist_move_nvlist(lnvl, name, limit); 404832dc76bSMariusz Zaborski } else { 405832dc76bSMariusz Zaborski nvlist_destroy(limit); 406832dc76bSMariusz Zaborski } 407832dc76bSMariusz Zaborski } 408832dc76bSMariusz Zaborski 409832dc76bSMariusz Zaborski int 410832dc76bSMariusz Zaborski cap_net_limit(cap_net_limit_t *limit) 411832dc76bSMariusz Zaborski { 412832dc76bSMariusz Zaborski nvlist_t *lnvl; 413832dc76bSMariusz Zaborski cap_channel_t *chan; 414832dc76bSMariusz Zaborski 415832dc76bSMariusz Zaborski lnvl = nvlist_create(0); 416832dc76bSMariusz Zaborski nvlist_add_number(lnvl, "mode", limit->cnl_mode); 417832dc76bSMariusz Zaborski 418832dc76bSMariusz Zaborski pack_limit(lnvl, LIMIT_NV_ADDR2NAME, limit->cnl_addr2name); 419832dc76bSMariusz Zaborski pack_limit(lnvl, LIMIT_NV_NAME2ADDR, limit->cnl_name2addr); 420832dc76bSMariusz Zaborski pack_limit(lnvl, LIMIT_NV_CONNECT, limit->cnl_connect); 421832dc76bSMariusz Zaborski pack_limit(lnvl, LIMIT_NV_BIND, limit->cnl_bind); 422832dc76bSMariusz Zaborski 423832dc76bSMariusz Zaborski chan = limit->cnl_chan; 424832dc76bSMariusz Zaborski free(limit); 425832dc76bSMariusz Zaborski 426832dc76bSMariusz Zaborski return (cap_limit_set(chan, lnvl)); 427832dc76bSMariusz Zaborski } 428832dc76bSMariusz Zaborski 429832dc76bSMariusz Zaborski void 430832dc76bSMariusz Zaborski cap_net_free(cap_net_limit_t *limit) 431832dc76bSMariusz Zaborski { 432832dc76bSMariusz Zaborski 433832dc76bSMariusz Zaborski if (limit == NULL) 434832dc76bSMariusz Zaborski return; 435832dc76bSMariusz Zaborski 436832dc76bSMariusz Zaborski nvlist_destroy(limit->cnl_addr2name); 437832dc76bSMariusz Zaborski nvlist_destroy(limit->cnl_name2addr); 438832dc76bSMariusz Zaborski nvlist_destroy(limit->cnl_connect); 439832dc76bSMariusz Zaborski nvlist_destroy(limit->cnl_bind); 440832dc76bSMariusz Zaborski 441832dc76bSMariusz Zaborski free(limit); 442832dc76bSMariusz Zaborski } 443832dc76bSMariusz Zaborski 444832dc76bSMariusz Zaborski static void 445832dc76bSMariusz Zaborski pack_family(nvlist_t *nvl, int *family, size_t size) 446832dc76bSMariusz Zaborski { 447832dc76bSMariusz Zaborski size_t i; 448832dc76bSMariusz Zaborski 449832dc76bSMariusz Zaborski i = 0; 450832dc76bSMariusz Zaborski if (!nvlist_exists_number_array(nvl, "family")) { 451832dc76bSMariusz Zaborski uint64_t val; 452832dc76bSMariusz Zaborski 453832dc76bSMariusz Zaborski val = family[0]; 454832dc76bSMariusz Zaborski nvlist_add_number_array(nvl, "family", &val, 1); 455832dc76bSMariusz Zaborski i += 1; 456832dc76bSMariusz Zaborski } 457832dc76bSMariusz Zaborski 458832dc76bSMariusz Zaborski for (; i < size; i++) { 459832dc76bSMariusz Zaborski nvlist_append_number_array(nvl, "family", family[i]); 460832dc76bSMariusz Zaborski } 461832dc76bSMariusz Zaborski } 462832dc76bSMariusz Zaborski 463832dc76bSMariusz Zaborski static void 464832dc76bSMariusz Zaborski pack_sockaddr(nvlist_t *res, const struct sockaddr *sa, socklen_t salen) 465832dc76bSMariusz Zaborski { 466832dc76bSMariusz Zaborski nvlist_t *nvl; 467832dc76bSMariusz Zaborski 468832dc76bSMariusz Zaborski if (!nvlist_exists_nvlist(res, "sockaddr")) { 469832dc76bSMariusz Zaborski nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 470832dc76bSMariusz Zaborski } else { 471832dc76bSMariusz Zaborski nvl = nvlist_take_nvlist(res, "sockaddr"); 472832dc76bSMariusz Zaborski } 473832dc76bSMariusz Zaborski 474832dc76bSMariusz Zaborski nvlist_add_binary(nvl, "", sa, salen); 475832dc76bSMariusz Zaborski nvlist_move_nvlist(res, "sockaddr", nvl); 476832dc76bSMariusz Zaborski } 477832dc76bSMariusz Zaborski 478832dc76bSMariusz Zaborski cap_net_limit_t * 479832dc76bSMariusz Zaborski cap_net_limit_addr2name_family(cap_net_limit_t *limit, int *family, size_t size) 480832dc76bSMariusz Zaborski { 481832dc76bSMariusz Zaborski 482832dc76bSMariusz Zaborski pack_family(limit->cnl_addr2name, family, size); 483832dc76bSMariusz Zaborski return (limit); 484832dc76bSMariusz Zaborski } 485832dc76bSMariusz Zaborski 486832dc76bSMariusz Zaborski cap_net_limit_t * 487832dc76bSMariusz Zaborski cap_net_limit_name2addr_family(cap_net_limit_t *limit, int *family, size_t size) 488832dc76bSMariusz Zaborski { 489832dc76bSMariusz Zaborski 490832dc76bSMariusz Zaborski pack_family(limit->cnl_name2addr, family, size); 491832dc76bSMariusz Zaborski return (limit); 492832dc76bSMariusz Zaborski } 493832dc76bSMariusz Zaborski 494832dc76bSMariusz Zaborski cap_net_limit_t * 495832dc76bSMariusz Zaborski cap_net_limit_name2addr(cap_net_limit_t *limit, const char *host, 496832dc76bSMariusz Zaborski const char *serv) 497832dc76bSMariusz Zaborski { 498832dc76bSMariusz Zaborski nvlist_t *nvl; 499832dc76bSMariusz Zaborski 500832dc76bSMariusz Zaborski if (!nvlist_exists_nvlist(limit->cnl_name2addr, "hosts")) { 501832dc76bSMariusz Zaborski nvl = nvlist_create(NV_FLAG_NO_UNIQUE); 502832dc76bSMariusz Zaborski } else { 503832dc76bSMariusz Zaborski nvl = nvlist_take_nvlist(limit->cnl_name2addr, "hosts"); 504832dc76bSMariusz Zaborski } 505832dc76bSMariusz Zaborski 506832dc76bSMariusz Zaborski nvlist_add_string(nvl, 507832dc76bSMariusz Zaborski host != NULL ? host : "", 508832dc76bSMariusz Zaborski serv != NULL ? serv : ""); 509832dc76bSMariusz Zaborski 510832dc76bSMariusz Zaborski nvlist_move_nvlist(limit->cnl_name2addr, "hosts", nvl); 511832dc76bSMariusz Zaborski return (limit); 512832dc76bSMariusz Zaborski } 513832dc76bSMariusz Zaborski 514832dc76bSMariusz Zaborski cap_net_limit_t * 515832dc76bSMariusz Zaborski cap_net_limit_addr2name(cap_net_limit_t *limit, const struct sockaddr *sa, 516832dc76bSMariusz Zaborski socklen_t salen) 517832dc76bSMariusz Zaborski { 518832dc76bSMariusz Zaborski 519832dc76bSMariusz Zaborski pack_sockaddr(limit->cnl_addr2name, sa, salen); 520832dc76bSMariusz Zaborski return (limit); 521832dc76bSMariusz Zaborski } 522832dc76bSMariusz Zaborski 523832dc76bSMariusz Zaborski 524832dc76bSMariusz Zaborski cap_net_limit_t * 525832dc76bSMariusz Zaborski cap_net_limit_connect(cap_net_limit_t *limit, const struct sockaddr *sa, 526832dc76bSMariusz Zaborski socklen_t salen) 527832dc76bSMariusz Zaborski { 528832dc76bSMariusz Zaborski 529832dc76bSMariusz Zaborski pack_sockaddr(limit->cnl_connect, sa, salen); 530832dc76bSMariusz Zaborski return (limit); 531832dc76bSMariusz Zaborski } 532832dc76bSMariusz Zaborski 533832dc76bSMariusz Zaborski cap_net_limit_t * 534832dc76bSMariusz Zaborski cap_net_limit_bind(cap_net_limit_t *limit, const struct sockaddr *sa, 535832dc76bSMariusz Zaborski socklen_t salen) 536832dc76bSMariusz Zaborski { 537832dc76bSMariusz Zaborski 538832dc76bSMariusz Zaborski pack_sockaddr(limit->cnl_bind, sa, salen); 539832dc76bSMariusz Zaborski return (limit); 540832dc76bSMariusz Zaborski } 541832dc76bSMariusz Zaborski 542832dc76bSMariusz Zaborski /* 543832dc76bSMariusz Zaborski * Service functions. 544832dc76bSMariusz Zaborski */ 545832dc76bSMariusz Zaborski 546832dc76bSMariusz Zaborski static nvlist_t *capdnscache; 547832dc76bSMariusz Zaborski 548832dc76bSMariusz Zaborski static void 549832dc76bSMariusz Zaborski net_add_sockaddr_to_cache(struct sockaddr *sa, socklen_t salen, bool deprecated) 550832dc76bSMariusz Zaborski { 551832dc76bSMariusz Zaborski void *cookie; 552832dc76bSMariusz Zaborski 553832dc76bSMariusz Zaborski if (capdnscache == NULL) { 554832dc76bSMariusz Zaborski capdnscache = nvlist_create(NV_FLAG_NO_UNIQUE); 555832dc76bSMariusz Zaborski } else { 556832dc76bSMariusz Zaborski /* Lets keep it clean. Look for dups. */ 557832dc76bSMariusz Zaborski cookie = NULL; 558832dc76bSMariusz Zaborski while (nvlist_next(capdnscache, NULL, &cookie) != NULL) { 559832dc76bSMariusz Zaborski const void *data; 560832dc76bSMariusz Zaborski size_t size; 561832dc76bSMariusz Zaborski 562832dc76bSMariusz Zaborski assert(cnvlist_type(cookie) == NV_TYPE_BINARY); 563832dc76bSMariusz Zaborski 564832dc76bSMariusz Zaborski data = cnvlist_get_binary(cookie, &size); 565832dc76bSMariusz Zaborski if (salen != size) 566832dc76bSMariusz Zaborski continue; 567832dc76bSMariusz Zaborski if (memcmp(data, sa, size) == 0) 568832dc76bSMariusz Zaborski return; 569832dc76bSMariusz Zaborski } 570832dc76bSMariusz Zaborski } 571832dc76bSMariusz Zaborski 572832dc76bSMariusz Zaborski nvlist_add_binary(capdnscache, deprecated ? "d" : "", sa, salen); 573832dc76bSMariusz Zaborski } 574832dc76bSMariusz Zaborski 575832dc76bSMariusz Zaborski static void 576832dc76bSMariusz Zaborski net_add_hostent_to_cache(const char *address, size_t asize, int family) 577832dc76bSMariusz Zaborski { 578832dc76bSMariusz Zaborski 579832dc76bSMariusz Zaborski if (family != AF_INET && family != AF_INET6) 580832dc76bSMariusz Zaborski return; 581832dc76bSMariusz Zaborski 582832dc76bSMariusz Zaborski if (family == AF_INET6) { 583832dc76bSMariusz Zaborski struct sockaddr_in6 connaddr; 584832dc76bSMariusz Zaborski 585832dc76bSMariusz Zaborski memset(&connaddr, 0, sizeof(connaddr)); 586832dc76bSMariusz Zaborski connaddr.sin6_family = AF_INET6; 587832dc76bSMariusz Zaborski memcpy((char *)&connaddr.sin6_addr, address, asize); 588832dc76bSMariusz Zaborski connaddr.sin6_port = 0; 589832dc76bSMariusz Zaborski 590832dc76bSMariusz Zaborski net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 591832dc76bSMariusz Zaborski sizeof(connaddr), true); 592832dc76bSMariusz Zaborski } else { 593832dc76bSMariusz Zaborski struct sockaddr_in connaddr; 594832dc76bSMariusz Zaborski 595832dc76bSMariusz Zaborski memset(&connaddr, 0, sizeof(connaddr)); 596832dc76bSMariusz Zaborski connaddr.sin_family = AF_INET; 597832dc76bSMariusz Zaborski memcpy((char *)&connaddr.sin_addr.s_addr, address, asize); 598832dc76bSMariusz Zaborski connaddr.sin_port = 0; 599832dc76bSMariusz Zaborski 600832dc76bSMariusz Zaborski net_add_sockaddr_to_cache((struct sockaddr *)&connaddr, 601832dc76bSMariusz Zaborski sizeof(connaddr), true); 602832dc76bSMariusz Zaborski } 603832dc76bSMariusz Zaborski } 604832dc76bSMariusz Zaborski 605832dc76bSMariusz Zaborski static bool 606832dc76bSMariusz Zaborski net_allowed_mode(const nvlist_t *limits, uint64_t mode) 607832dc76bSMariusz Zaborski { 608832dc76bSMariusz Zaborski 609832dc76bSMariusz Zaborski if (limits == NULL) 610832dc76bSMariusz Zaborski return (true); 611832dc76bSMariusz Zaborski 612832dc76bSMariusz Zaborski return ((nvlist_get_number(limits, "mode") & mode) == mode); 613832dc76bSMariusz Zaborski } 614832dc76bSMariusz Zaborski 615832dc76bSMariusz Zaborski static bool 616832dc76bSMariusz Zaborski net_allowed_family(const nvlist_t *limits, int family) 617832dc76bSMariusz Zaborski { 618832dc76bSMariusz Zaborski const uint64_t *allowedfamily; 619832dc76bSMariusz Zaborski size_t i, allsize; 620832dc76bSMariusz Zaborski 621832dc76bSMariusz Zaborski if (limits == NULL) 622832dc76bSMariusz Zaborski return (true); 623832dc76bSMariusz Zaborski 624832dc76bSMariusz Zaborski /* If there are no familes at all, allow any mode. */ 625832dc76bSMariusz Zaborski if (!nvlist_exists_number_array(limits, "family")) 626832dc76bSMariusz Zaborski return (true); 627832dc76bSMariusz Zaborski 628832dc76bSMariusz Zaborski allowedfamily = nvlist_get_number_array(limits, "family", &allsize); 629832dc76bSMariusz Zaborski for (i = 0; i < allsize; i++) { 630832dc76bSMariusz Zaborski /* XXX: what with AF_UNSPEC? */ 631832dc76bSMariusz Zaborski if (allowedfamily[i] == (uint64_t)family) { 632832dc76bSMariusz Zaborski return (true); 633832dc76bSMariusz Zaborski } 634832dc76bSMariusz Zaborski } 635832dc76bSMariusz Zaborski 636832dc76bSMariusz Zaborski return (false); 637832dc76bSMariusz Zaborski } 638832dc76bSMariusz Zaborski 639832dc76bSMariusz Zaborski static bool 640832dc76bSMariusz Zaborski net_allowed_bsaddr_impl(const nvlist_t *salimits, const void *saddr, 641832dc76bSMariusz Zaborski size_t saddrsize) 642832dc76bSMariusz Zaborski { 643832dc76bSMariusz Zaborski void *cookie; 644832dc76bSMariusz Zaborski const void *limit; 645832dc76bSMariusz Zaborski size_t limitsize; 646832dc76bSMariusz Zaborski 647832dc76bSMariusz Zaborski cookie = NULL; 648832dc76bSMariusz Zaborski while (nvlist_next(salimits, NULL, &cookie) != NULL) { 649832dc76bSMariusz Zaborski limit = cnvlist_get_binary(cookie, &limitsize); 650832dc76bSMariusz Zaborski 651832dc76bSMariusz Zaborski if (limitsize != saddrsize) { 652832dc76bSMariusz Zaborski continue; 653832dc76bSMariusz Zaborski } 654832dc76bSMariusz Zaborski if (memcmp(limit, saddr, limitsize) == 0) { 655832dc76bSMariusz Zaborski return (true); 656832dc76bSMariusz Zaborski } 657832dc76bSMariusz Zaborski 658832dc76bSMariusz Zaborski /* 659832dc76bSMariusz Zaborski * In case of deprecated version (gethostbyname) we have to 660832dc76bSMariusz Zaborski * ignore port, because there is no such info in the hostent. 661832dc76bSMariusz Zaborski * Suporting only AF_INET and AF_INET6. 662832dc76bSMariusz Zaborski */ 663832dc76bSMariusz Zaborski if (strcmp(cnvlist_name(cookie), "d") != 0 || 664832dc76bSMariusz Zaborski (saddrsize != sizeof(struct sockaddr_in) && 665832dc76bSMariusz Zaborski saddrsize != sizeof(struct sockaddr_in6))) { 666832dc76bSMariusz Zaborski continue; 667832dc76bSMariusz Zaborski } 668832dc76bSMariusz Zaborski if (saddrsize == sizeof(struct sockaddr_in)) { 669832dc76bSMariusz Zaborski const struct sockaddr_in *saddrptr; 670832dc76bSMariusz Zaborski struct sockaddr_in sockaddr; 671832dc76bSMariusz Zaborski 672832dc76bSMariusz Zaborski saddrptr = (const struct sockaddr_in *)saddr; 673832dc76bSMariusz Zaborski memcpy(&sockaddr, limit, sizeof(sockaddr)); 674832dc76bSMariusz Zaborski sockaddr.sin_port = saddrptr->sin_port; 675832dc76bSMariusz Zaborski 676832dc76bSMariusz Zaborski if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 677832dc76bSMariusz Zaborski return (true); 678832dc76bSMariusz Zaborski } 679832dc76bSMariusz Zaborski } else if (saddrsize == sizeof(struct sockaddr_in6)) { 680832dc76bSMariusz Zaborski const struct sockaddr_in6 *saddrptr; 681832dc76bSMariusz Zaborski struct sockaddr_in6 sockaddr; 682832dc76bSMariusz Zaborski 683832dc76bSMariusz Zaborski saddrptr = (const struct sockaddr_in6 *)saddr; 684832dc76bSMariusz Zaborski memcpy(&sockaddr, limit, sizeof(sockaddr)); 685832dc76bSMariusz Zaborski sockaddr.sin6_port = saddrptr->sin6_port; 686832dc76bSMariusz Zaborski 687832dc76bSMariusz Zaborski if (memcmp(&sockaddr, saddr, saddrsize) == 0) { 688832dc76bSMariusz Zaborski return (true); 689832dc76bSMariusz Zaborski } 690832dc76bSMariusz Zaborski } 691832dc76bSMariusz Zaborski } 692832dc76bSMariusz Zaborski 693832dc76bSMariusz Zaborski return (false); 694832dc76bSMariusz Zaborski } 695832dc76bSMariusz Zaborski 696832dc76bSMariusz Zaborski static bool 697832dc76bSMariusz Zaborski net_allowed_bsaddr(const nvlist_t *limits, const void *saddr, size_t saddrsize) 698832dc76bSMariusz Zaborski { 699832dc76bSMariusz Zaborski 700832dc76bSMariusz Zaborski if (limits == NULL) 701832dc76bSMariusz Zaborski return (true); 702832dc76bSMariusz Zaborski 703832dc76bSMariusz Zaborski if (!nvlist_exists_nvlist(limits, "sockaddr")) 704832dc76bSMariusz Zaborski return (true); 705832dc76bSMariusz Zaborski 706832dc76bSMariusz Zaborski return (net_allowed_bsaddr_impl(nvlist_get_nvlist(limits, "sockaddr"), 707832dc76bSMariusz Zaborski saddr, saddrsize)); 708832dc76bSMariusz Zaborski } 709832dc76bSMariusz Zaborski 710832dc76bSMariusz Zaborski static bool 711832dc76bSMariusz Zaborski net_allowed_hosts(const nvlist_t *limits, const char *name, const char *srvname) 712832dc76bSMariusz Zaborski { 713832dc76bSMariusz Zaborski void *cookie; 714832dc76bSMariusz Zaborski const nvlist_t *hlimits; 715832dc76bSMariusz Zaborski const char *testname, *testsrvname; 716832dc76bSMariusz Zaborski 717832dc76bSMariusz Zaborski if (limits == NULL) { 718832dc76bSMariusz Zaborski return (true); 719832dc76bSMariusz Zaborski } 720832dc76bSMariusz Zaborski 721832dc76bSMariusz Zaborski /* If there are no hosts at all, allow any. */ 722832dc76bSMariusz Zaborski if (!nvlist_exists_nvlist(limits, "hosts")) { 723832dc76bSMariusz Zaborski return (true); 724832dc76bSMariusz Zaborski } 725832dc76bSMariusz Zaborski 726832dc76bSMariusz Zaborski cookie = NULL; 727832dc76bSMariusz Zaborski testname = (name == NULL ? "" : name); 728832dc76bSMariusz Zaborski testsrvname = (srvname == NULL ? "" : srvname); 729832dc76bSMariusz Zaborski hlimits = nvlist_get_nvlist(limits, "hosts"); 730832dc76bSMariusz Zaborski while (nvlist_next(hlimits, NULL, &cookie) != NULL) { 731832dc76bSMariusz Zaborski if (strcmp(cnvlist_name(cookie), "") != 0 && 732832dc76bSMariusz Zaborski strcmp(cnvlist_name(cookie), testname) != 0) { 733832dc76bSMariusz Zaborski continue; 734832dc76bSMariusz Zaborski } 735832dc76bSMariusz Zaborski 736832dc76bSMariusz Zaborski if (strcmp(cnvlist_get_string(cookie), "") != 0 && 737832dc76bSMariusz Zaborski strcmp(cnvlist_get_string(cookie), testsrvname) != 0) { 738832dc76bSMariusz Zaborski continue; 739832dc76bSMariusz Zaborski } 740832dc76bSMariusz Zaborski 741832dc76bSMariusz Zaborski return (true); 742832dc76bSMariusz Zaborski } 743832dc76bSMariusz Zaborski 744832dc76bSMariusz Zaborski return (false); 745832dc76bSMariusz Zaborski } 746832dc76bSMariusz Zaborski 747832dc76bSMariusz Zaborski static void 748832dc76bSMariusz Zaborski hostent_pack(const struct hostent *hp, nvlist_t *nvl, bool addtocache) 749832dc76bSMariusz Zaborski { 750832dc76bSMariusz Zaborski unsigned int ii; 751832dc76bSMariusz Zaborski char nvlname[64]; 752832dc76bSMariusz Zaborski int n; 753832dc76bSMariusz Zaborski 754832dc76bSMariusz Zaborski nvlist_add_string(nvl, "name", hp->h_name); 755832dc76bSMariusz Zaborski nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype); 756832dc76bSMariusz Zaborski nvlist_add_number(nvl, "length", (uint64_t)hp->h_length); 757832dc76bSMariusz Zaborski 758832dc76bSMariusz Zaborski if (hp->h_aliases == NULL) { 759832dc76bSMariusz Zaborski nvlist_add_number(nvl, "naliases", 0); 760832dc76bSMariusz Zaborski } else { 761832dc76bSMariusz Zaborski for (ii = 0; hp->h_aliases[ii] != NULL; ii++) { 762832dc76bSMariusz Zaborski n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii); 763832dc76bSMariusz Zaborski assert(n > 0 && n < (int)sizeof(nvlname)); 764832dc76bSMariusz Zaborski nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]); 765832dc76bSMariusz Zaborski } 766832dc76bSMariusz Zaborski nvlist_add_number(nvl, "naliases", (uint64_t)ii); 767832dc76bSMariusz Zaborski } 768832dc76bSMariusz Zaborski 769832dc76bSMariusz Zaborski if (hp->h_addr_list == NULL) { 770832dc76bSMariusz Zaborski nvlist_add_number(nvl, "naddrs", 0); 771832dc76bSMariusz Zaborski } else { 772832dc76bSMariusz Zaborski for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) { 773832dc76bSMariusz Zaborski n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii); 774832dc76bSMariusz Zaborski assert(n > 0 && n < (int)sizeof(nvlname)); 775832dc76bSMariusz Zaborski nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii], 776832dc76bSMariusz Zaborski (size_t)hp->h_length); 777832dc76bSMariusz Zaborski if (addtocache) { 778832dc76bSMariusz Zaborski net_add_hostent_to_cache(hp->h_addr_list[ii], 779832dc76bSMariusz Zaborski hp->h_length, hp->h_addrtype); 780832dc76bSMariusz Zaborski } 781832dc76bSMariusz Zaborski } 782832dc76bSMariusz Zaborski nvlist_add_number(nvl, "naddrs", (uint64_t)ii); 783832dc76bSMariusz Zaborski } 784832dc76bSMariusz Zaborski } 785832dc76bSMariusz Zaborski 786832dc76bSMariusz Zaborski static int 787832dc76bSMariusz Zaborski net_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin, 788832dc76bSMariusz Zaborski nvlist_t *nvlout) 789832dc76bSMariusz Zaborski { 790832dc76bSMariusz Zaborski struct hostent *hp; 791832dc76bSMariusz Zaborski int family; 792832dc76bSMariusz Zaborski const nvlist_t *funclimit; 793832dc76bSMariusz Zaborski const char *name; 794832dc76bSMariusz Zaborski bool dnscache; 795832dc76bSMariusz Zaborski 796832dc76bSMariusz Zaborski if (!net_allowed_mode(limits, CAPNET_DEPRECATED_NAME2ADDR)) 797832dc76bSMariusz Zaborski return (ENOTCAPABLE); 798832dc76bSMariusz Zaborski 799832dc76bSMariusz Zaborski dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 800b7876aecSMariusz Zaborski funclimit = NULL; 801b7876aecSMariusz Zaborski if (limits != NULL) { 802b7876aecSMariusz Zaborski funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 803b7876aecSMariusz Zaborski NULL); 804b7876aecSMariusz Zaborski } 805832dc76bSMariusz Zaborski 806832dc76bSMariusz Zaborski family = (int)nvlist_get_number(nvlin, "family"); 807832dc76bSMariusz Zaborski if (!net_allowed_family(funclimit, family)) 808832dc76bSMariusz Zaborski return (ENOTCAPABLE); 809832dc76bSMariusz Zaborski 810832dc76bSMariusz Zaborski name = nvlist_get_string(nvlin, "name"); 811832dc76bSMariusz Zaborski if (!net_allowed_hosts(funclimit, name, "")) 812832dc76bSMariusz Zaborski return (ENOTCAPABLE); 813832dc76bSMariusz Zaborski 814832dc76bSMariusz Zaborski hp = gethostbyname2(name, family); 815832dc76bSMariusz Zaborski if (hp == NULL) 816832dc76bSMariusz Zaborski return (h_errno); 817832dc76bSMariusz Zaborski hostent_pack(hp, nvlout, dnscache); 818832dc76bSMariusz Zaborski return (0); 819832dc76bSMariusz Zaborski } 820832dc76bSMariusz Zaborski 821832dc76bSMariusz Zaborski static int 822832dc76bSMariusz Zaborski net_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin, 823832dc76bSMariusz Zaborski nvlist_t *nvlout) 824832dc76bSMariusz Zaborski { 825832dc76bSMariusz Zaborski struct hostent *hp; 826832dc76bSMariusz Zaborski const void *addr; 827832dc76bSMariusz Zaborski size_t addrsize; 828832dc76bSMariusz Zaborski int family; 829832dc76bSMariusz Zaborski const nvlist_t *funclimit; 830832dc76bSMariusz Zaborski 831832dc76bSMariusz Zaborski if (!net_allowed_mode(limits, CAPNET_DEPRECATED_ADDR2NAME)) 832832dc76bSMariusz Zaborski return (ENOTCAPABLE); 833832dc76bSMariusz Zaborski 834b7876aecSMariusz Zaborski funclimit = NULL; 835b7876aecSMariusz Zaborski if (limits != NULL) { 836b7876aecSMariusz Zaborski funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, 837b7876aecSMariusz Zaborski NULL); 838b7876aecSMariusz Zaborski } 839832dc76bSMariusz Zaborski 840832dc76bSMariusz Zaborski family = (int)nvlist_get_number(nvlin, "family"); 841832dc76bSMariusz Zaborski if (!net_allowed_family(funclimit, family)) 842832dc76bSMariusz Zaborski return (ENOTCAPABLE); 843832dc76bSMariusz Zaborski 844832dc76bSMariusz Zaborski addr = nvlist_get_binary(nvlin, "addr", &addrsize); 845832dc76bSMariusz Zaborski if (!net_allowed_bsaddr(funclimit, addr, addrsize)) 846832dc76bSMariusz Zaborski return (ENOTCAPABLE); 847832dc76bSMariusz Zaborski 848832dc76bSMariusz Zaborski hp = gethostbyaddr(addr, (socklen_t)addrsize, family); 849832dc76bSMariusz Zaborski if (hp == NULL) 850832dc76bSMariusz Zaborski return (h_errno); 851832dc76bSMariusz Zaborski hostent_pack(hp, nvlout, false); 852832dc76bSMariusz Zaborski return (0); 853832dc76bSMariusz Zaborski } 854832dc76bSMariusz Zaborski 855832dc76bSMariusz Zaborski static int 856832dc76bSMariusz Zaborski net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 857832dc76bSMariusz Zaborski { 858832dc76bSMariusz Zaborski struct sockaddr_storage sast; 859832dc76bSMariusz Zaborski const void *sabin; 860832dc76bSMariusz Zaborski char *host, *serv; 861832dc76bSMariusz Zaborski size_t sabinsize, hostlen, servlen; 862832dc76bSMariusz Zaborski socklen_t salen; 863832dc76bSMariusz Zaborski int error, flags; 864832dc76bSMariusz Zaborski const nvlist_t *funclimit; 865832dc76bSMariusz Zaborski 866832dc76bSMariusz Zaborski if (!net_allowed_mode(limits, CAPNET_ADDR2NAME)) 867832dc76bSMariusz Zaborski return (ENOTCAPABLE); 868b7876aecSMariusz Zaborski funclimit = NULL; 869b7876aecSMariusz Zaborski if (limits != NULL) { 870b7876aecSMariusz Zaborski funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, 871b7876aecSMariusz Zaborski NULL); 872b7876aecSMariusz Zaborski } 873832dc76bSMariusz Zaborski 874832dc76bSMariusz Zaborski error = 0; 875832dc76bSMariusz Zaborski host = serv = NULL; 876832dc76bSMariusz Zaborski memset(&sast, 0, sizeof(sast)); 877832dc76bSMariusz Zaborski 878832dc76bSMariusz Zaborski hostlen = (size_t)nvlist_get_number(nvlin, "hostlen"); 879832dc76bSMariusz Zaborski servlen = (size_t)nvlist_get_number(nvlin, "servlen"); 880832dc76bSMariusz Zaborski 881832dc76bSMariusz Zaborski if (hostlen > 0) { 882832dc76bSMariusz Zaborski host = calloc(1, hostlen + 1); 883832dc76bSMariusz Zaborski if (host == NULL) { 884832dc76bSMariusz Zaborski error = EAI_MEMORY; 885832dc76bSMariusz Zaborski goto out; 886832dc76bSMariusz Zaborski } 887832dc76bSMariusz Zaborski } 888832dc76bSMariusz Zaborski if (servlen > 0) { 889832dc76bSMariusz Zaborski serv = calloc(1, servlen + 1); 890832dc76bSMariusz Zaborski if (serv == NULL) { 891832dc76bSMariusz Zaborski error = EAI_MEMORY; 892832dc76bSMariusz Zaborski goto out; 893832dc76bSMariusz Zaborski } 894832dc76bSMariusz Zaborski } 895832dc76bSMariusz Zaborski 896832dc76bSMariusz Zaborski sabin = nvlist_get_binary(nvlin, "sa", &sabinsize); 897832dc76bSMariusz Zaborski if (sabinsize > sizeof(sast)) { 898832dc76bSMariusz Zaborski error = EAI_FAIL; 899832dc76bSMariusz Zaborski goto out; 900832dc76bSMariusz Zaborski } 901*88910b8bSMariusz Zaborski if (!net_allowed_bsaddr(funclimit, sabin, sabinsize)) { 902*88910b8bSMariusz Zaborski error = ENOTCAPABLE; 903*88910b8bSMariusz Zaborski goto out; 904*88910b8bSMariusz Zaborski } 905832dc76bSMariusz Zaborski 906832dc76bSMariusz Zaborski memcpy(&sast, sabin, sabinsize); 907832dc76bSMariusz Zaborski salen = (socklen_t)sabinsize; 908832dc76bSMariusz Zaborski 909832dc76bSMariusz Zaborski if ((sast.ss_family != AF_INET || 910832dc76bSMariusz Zaborski salen != sizeof(struct sockaddr_in)) && 911832dc76bSMariusz Zaborski (sast.ss_family != AF_INET6 || 912832dc76bSMariusz Zaborski salen != sizeof(struct sockaddr_in6))) { 913832dc76bSMariusz Zaborski error = EAI_FAIL; 914832dc76bSMariusz Zaborski goto out; 915832dc76bSMariusz Zaborski } 916832dc76bSMariusz Zaborski 917832dc76bSMariusz Zaborski if (!net_allowed_family(funclimit, (int)sast.ss_family)) { 918832dc76bSMariusz Zaborski error = ENOTCAPABLE; 919832dc76bSMariusz Zaborski goto out; 920832dc76bSMariusz Zaborski } 921832dc76bSMariusz Zaborski 922832dc76bSMariusz Zaborski flags = (int)nvlist_get_number(nvlin, "flags"); 923832dc76bSMariusz Zaborski 924832dc76bSMariusz Zaborski error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen, 925832dc76bSMariusz Zaborski serv, servlen, flags); 926832dc76bSMariusz Zaborski if (error != 0) 927832dc76bSMariusz Zaborski goto out; 928832dc76bSMariusz Zaborski 929832dc76bSMariusz Zaborski if (host != NULL) 930832dc76bSMariusz Zaborski nvlist_move_string(nvlout, "host", host); 931832dc76bSMariusz Zaborski if (serv != NULL) 932832dc76bSMariusz Zaborski nvlist_move_string(nvlout, "serv", serv); 933832dc76bSMariusz Zaborski out: 934832dc76bSMariusz Zaborski if (error != 0) { 935832dc76bSMariusz Zaborski free(host); 936832dc76bSMariusz Zaborski free(serv); 937832dc76bSMariusz Zaborski } 938832dc76bSMariusz Zaborski return (error); 939832dc76bSMariusz Zaborski } 940832dc76bSMariusz Zaborski 941832dc76bSMariusz Zaborski static nvlist_t * 942832dc76bSMariusz Zaborski addrinfo_pack(const struct addrinfo *ai) 943832dc76bSMariusz Zaborski { 944832dc76bSMariusz Zaborski nvlist_t *nvl; 945832dc76bSMariusz Zaborski 946832dc76bSMariusz Zaborski nvl = nvlist_create(0); 947832dc76bSMariusz Zaborski nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags); 948832dc76bSMariusz Zaborski nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family); 949832dc76bSMariusz Zaborski nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype); 950832dc76bSMariusz Zaborski nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol); 951832dc76bSMariusz Zaborski nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen); 952832dc76bSMariusz Zaborski if (ai->ai_canonname != NULL) 953832dc76bSMariusz Zaborski nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname); 954832dc76bSMariusz Zaborski 955832dc76bSMariusz Zaborski return (nvl); 956832dc76bSMariusz Zaborski } 957832dc76bSMariusz Zaborski 958832dc76bSMariusz Zaborski static int 959832dc76bSMariusz Zaborski net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 960832dc76bSMariusz Zaborski { 961832dc76bSMariusz Zaborski struct addrinfo hints, *hintsp, *res, *cur; 962832dc76bSMariusz Zaborski const char *hostname, *servname; 963832dc76bSMariusz Zaborski char nvlname[64]; 964832dc76bSMariusz Zaborski nvlist_t *elem; 965832dc76bSMariusz Zaborski unsigned int ii; 966832dc76bSMariusz Zaborski int error, family, n; 967832dc76bSMariusz Zaborski const nvlist_t *funclimit; 968832dc76bSMariusz Zaborski bool dnscache; 969832dc76bSMariusz Zaborski 970832dc76bSMariusz Zaborski if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) 971832dc76bSMariusz Zaborski return (ENOTCAPABLE); 972832dc76bSMariusz Zaborski dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS); 973b7876aecSMariusz Zaborski funclimit = NULL; 974b7876aecSMariusz Zaborski if (limits != NULL) { 975b7876aecSMariusz Zaborski funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, 976b7876aecSMariusz Zaborski NULL); 977b7876aecSMariusz Zaborski } 978832dc76bSMariusz Zaborski 979832dc76bSMariusz Zaborski hostname = dnvlist_get_string(nvlin, "hostname", NULL); 980832dc76bSMariusz Zaborski servname = dnvlist_get_string(nvlin, "servname", NULL); 981832dc76bSMariusz Zaborski if (nvlist_exists_number(nvlin, "hints.ai_flags")) { 982832dc76bSMariusz Zaborski hints.ai_flags = (int)nvlist_get_number(nvlin, 983832dc76bSMariusz Zaborski "hints.ai_flags"); 984832dc76bSMariusz Zaborski hints.ai_family = (int)nvlist_get_number(nvlin, 985832dc76bSMariusz Zaborski "hints.ai_family"); 986832dc76bSMariusz Zaborski hints.ai_socktype = (int)nvlist_get_number(nvlin, 987832dc76bSMariusz Zaborski "hints.ai_socktype"); 988832dc76bSMariusz Zaborski hints.ai_protocol = (int)nvlist_get_number(nvlin, 989832dc76bSMariusz Zaborski "hints.ai_protocol"); 990832dc76bSMariusz Zaborski hints.ai_addrlen = 0; 991832dc76bSMariusz Zaborski hints.ai_addr = NULL; 992832dc76bSMariusz Zaborski hints.ai_canonname = NULL; 993832dc76bSMariusz Zaborski hints.ai_next = NULL; 994832dc76bSMariusz Zaborski hintsp = &hints; 995832dc76bSMariusz Zaborski family = hints.ai_family; 996832dc76bSMariusz Zaborski } else { 997832dc76bSMariusz Zaborski hintsp = NULL; 998832dc76bSMariusz Zaborski family = AF_UNSPEC; 999832dc76bSMariusz Zaborski } 1000832dc76bSMariusz Zaborski 1001832dc76bSMariusz Zaborski if (!net_allowed_family(funclimit, family)) 1002832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1003832dc76bSMariusz Zaborski if (!net_allowed_hosts(funclimit, hostname, servname)) 1004832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1005832dc76bSMariusz Zaborski error = getaddrinfo(hostname, servname, hintsp, &res); 1006832dc76bSMariusz Zaborski if (error != 0) { 1007832dc76bSMariusz Zaborski goto out; 1008832dc76bSMariusz Zaborski } 1009832dc76bSMariusz Zaborski 1010832dc76bSMariusz Zaborski for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) { 1011832dc76bSMariusz Zaborski elem = addrinfo_pack(cur); 1012832dc76bSMariusz Zaborski n = snprintf(nvlname, sizeof(nvlname), "res%u", ii); 1013832dc76bSMariusz Zaborski assert(n > 0 && n < (int)sizeof(nvlname)); 1014832dc76bSMariusz Zaborski nvlist_move_nvlist(nvlout, nvlname, elem); 1015832dc76bSMariusz Zaborski if (dnscache) { 1016832dc76bSMariusz Zaborski net_add_sockaddr_to_cache(cur->ai_addr, 1017832dc76bSMariusz Zaborski cur->ai_addrlen, false); 1018832dc76bSMariusz Zaborski } 1019832dc76bSMariusz Zaborski } 1020832dc76bSMariusz Zaborski 1021832dc76bSMariusz Zaborski freeaddrinfo(res); 1022832dc76bSMariusz Zaborski error = 0; 1023832dc76bSMariusz Zaborski out: 1024832dc76bSMariusz Zaborski return (error); 1025832dc76bSMariusz Zaborski } 1026832dc76bSMariusz Zaborski 1027832dc76bSMariusz Zaborski static int 1028832dc76bSMariusz Zaborski net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1029832dc76bSMariusz Zaborski { 1030832dc76bSMariusz Zaborski int socket, serrno; 1031832dc76bSMariusz Zaborski const void *saddr; 1032832dc76bSMariusz Zaborski size_t len; 1033832dc76bSMariusz Zaborski const nvlist_t *funclimit; 1034832dc76bSMariusz Zaborski 1035832dc76bSMariusz Zaborski if (!net_allowed_mode(limits, CAPNET_BIND)) 1036832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1037b7876aecSMariusz Zaborski funclimit = NULL; 1038b7876aecSMariusz Zaborski if (limits != NULL) 1039832dc76bSMariusz Zaborski funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_BIND, NULL); 1040832dc76bSMariusz Zaborski 1041832dc76bSMariusz Zaborski saddr = nvlist_get_binary(nvlin, "saddr", &len); 1042832dc76bSMariusz Zaborski 1043832dc76bSMariusz Zaborski if (!net_allowed_bsaddr(funclimit, saddr, len)) 1044832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1045832dc76bSMariusz Zaborski 1046832dc76bSMariusz Zaborski socket = nvlist_take_descriptor(nvlin, "s"); 1047832dc76bSMariusz Zaborski if (bind(socket, saddr, len) < 0) { 1048832dc76bSMariusz Zaborski serrno = errno; 1049832dc76bSMariusz Zaborski close(socket); 1050832dc76bSMariusz Zaborski return (serrno); 1051832dc76bSMariusz Zaborski } 1052832dc76bSMariusz Zaborski 1053832dc76bSMariusz Zaborski nvlist_move_descriptor(nvlout, "s", socket); 1054832dc76bSMariusz Zaborski 1055832dc76bSMariusz Zaborski return (0); 1056832dc76bSMariusz Zaborski } 1057832dc76bSMariusz Zaborski 1058832dc76bSMariusz Zaborski static int 1059832dc76bSMariusz Zaborski net_connect(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) 1060832dc76bSMariusz Zaborski { 1061832dc76bSMariusz Zaborski int socket, serrno; 1062832dc76bSMariusz Zaborski const void *saddr; 1063832dc76bSMariusz Zaborski const nvlist_t *funclimit; 1064832dc76bSMariusz Zaborski size_t len; 106534535dacSMariusz Zaborski bool conn, conndns, allowed; 1066832dc76bSMariusz Zaborski 1067832dc76bSMariusz Zaborski conn = net_allowed_mode(limits, CAPNET_CONNECT); 1068832dc76bSMariusz Zaborski conndns = net_allowed_mode(limits, CAPNET_CONNECTDNS); 1069832dc76bSMariusz Zaborski 1070832dc76bSMariusz Zaborski if (!conn && !conndns) 1071832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1072832dc76bSMariusz Zaborski 1073b7876aecSMariusz Zaborski funclimit = NULL; 1074b7876aecSMariusz Zaborski if (limits != NULL) 1075832dc76bSMariusz Zaborski funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_CONNECT, NULL); 1076832dc76bSMariusz Zaborski 1077832dc76bSMariusz Zaborski saddr = nvlist_get_binary(nvlin, "saddr", &len); 107834535dacSMariusz Zaborski allowed = false; 107934535dacSMariusz Zaborski 108034535dacSMariusz Zaborski if (conn && net_allowed_bsaddr(funclimit, saddr, len)) { 108134535dacSMariusz Zaborski allowed = true; 108234535dacSMariusz Zaborski } 108334535dacSMariusz Zaborski if (conndns && capdnscache != NULL && 108434535dacSMariusz Zaborski net_allowed_bsaddr_impl(capdnscache, saddr, len)) { 108534535dacSMariusz Zaborski allowed = true; 108634535dacSMariusz Zaborski } 108734535dacSMariusz Zaborski 108834535dacSMariusz Zaborski if (allowed == false) { 1089832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1090832dc76bSMariusz Zaborski } 109134535dacSMariusz Zaborski 1092832dc76bSMariusz Zaborski socket = dup(nvlist_get_descriptor(nvlin, "s")); 1093832dc76bSMariusz Zaborski if (connect(socket, saddr, len) < 0) { 1094832dc76bSMariusz Zaborski serrno = errno; 1095832dc76bSMariusz Zaborski close(socket); 1096832dc76bSMariusz Zaborski return (serrno); 1097832dc76bSMariusz Zaborski } 1098832dc76bSMariusz Zaborski 1099832dc76bSMariusz Zaborski nvlist_move_descriptor(nvlout, "s", socket); 1100832dc76bSMariusz Zaborski 1101832dc76bSMariusz Zaborski return (0); 1102832dc76bSMariusz Zaborski } 1103832dc76bSMariusz Zaborski 1104832dc76bSMariusz Zaborski static bool 1105832dc76bSMariusz Zaborski verify_only_sa_newlimts(const nvlist_t *oldfunclimits, 1106832dc76bSMariusz Zaborski const nvlist_t *newfunclimit) 1107832dc76bSMariusz Zaborski { 1108832dc76bSMariusz Zaborski void *cookie; 1109832dc76bSMariusz Zaborski 1110832dc76bSMariusz Zaborski cookie = NULL; 1111832dc76bSMariusz Zaborski while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1112832dc76bSMariusz Zaborski void *sacookie; 1113832dc76bSMariusz Zaborski 1114832dc76bSMariusz Zaborski if (strcmp(cnvlist_name(cookie), "sockaddr") != 0) 1115832dc76bSMariusz Zaborski return (false); 1116832dc76bSMariusz Zaborski 1117832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1118832dc76bSMariusz Zaborski return (false); 1119832dc76bSMariusz Zaborski 1120832dc76bSMariusz Zaborski sacookie = NULL; 1121832dc76bSMariusz Zaborski while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1122832dc76bSMariusz Zaborski &sacookie) != NULL) { 1123832dc76bSMariusz Zaborski const void *sa; 1124832dc76bSMariusz Zaborski size_t sasize; 1125832dc76bSMariusz Zaborski 1126832dc76bSMariusz Zaborski if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1127832dc76bSMariusz Zaborski return (false); 1128832dc76bSMariusz Zaborski 1129832dc76bSMariusz Zaborski sa = cnvlist_get_binary(sacookie, &sasize); 1130832dc76bSMariusz Zaborski if (!net_allowed_bsaddr(oldfunclimits, sa, sasize)) 1131832dc76bSMariusz Zaborski return (false); 1132832dc76bSMariusz Zaborski } 1133832dc76bSMariusz Zaborski } 1134832dc76bSMariusz Zaborski 1135832dc76bSMariusz Zaborski return (true); 1136832dc76bSMariusz Zaborski } 1137832dc76bSMariusz Zaborski 1138832dc76bSMariusz Zaborski static bool 1139832dc76bSMariusz Zaborski verify_bind_newlimts(const nvlist_t *oldlimits, 1140832dc76bSMariusz Zaborski const nvlist_t *newfunclimit) 1141832dc76bSMariusz Zaborski { 1142832dc76bSMariusz Zaborski const nvlist_t *oldfunclimits; 1143832dc76bSMariusz Zaborski 1144832dc76bSMariusz Zaborski oldfunclimits = NULL; 1145832dc76bSMariusz Zaborski if (oldlimits != NULL) { 1146832dc76bSMariusz Zaborski oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_BIND, 1147832dc76bSMariusz Zaborski NULL); 1148832dc76bSMariusz Zaborski } 1149832dc76bSMariusz Zaborski 1150832dc76bSMariusz Zaborski return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1151832dc76bSMariusz Zaborski } 1152832dc76bSMariusz Zaborski 1153832dc76bSMariusz Zaborski 1154832dc76bSMariusz Zaborski static bool 1155832dc76bSMariusz Zaborski verify_connect_newlimits(const nvlist_t *oldlimits, 1156832dc76bSMariusz Zaborski const nvlist_t *newfunclimit) 1157832dc76bSMariusz Zaborski { 1158832dc76bSMariusz Zaborski const nvlist_t *oldfunclimits; 1159832dc76bSMariusz Zaborski 1160832dc76bSMariusz Zaborski oldfunclimits = NULL; 1161832dc76bSMariusz Zaborski if (oldlimits != NULL) { 1162832dc76bSMariusz Zaborski oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_CONNECT, 1163832dc76bSMariusz Zaborski NULL); 1164832dc76bSMariusz Zaborski } 1165832dc76bSMariusz Zaborski 1166832dc76bSMariusz Zaborski return (verify_only_sa_newlimts(oldfunclimits, newfunclimit)); 1167832dc76bSMariusz Zaborski } 1168832dc76bSMariusz Zaborski 1169832dc76bSMariusz Zaborski static bool 1170832dc76bSMariusz Zaborski verify_addr2name_newlimits(const nvlist_t *oldlimits, 1171832dc76bSMariusz Zaborski const nvlist_t *newfunclimit) 1172832dc76bSMariusz Zaborski { 1173832dc76bSMariusz Zaborski void *cookie; 1174832dc76bSMariusz Zaborski const nvlist_t *oldfunclimits; 1175832dc76bSMariusz Zaborski 1176832dc76bSMariusz Zaborski oldfunclimits = NULL; 1177832dc76bSMariusz Zaborski if (oldlimits != NULL) { 1178832dc76bSMariusz Zaborski oldfunclimits = dnvlist_get_nvlist(oldlimits, 1179832dc76bSMariusz Zaborski LIMIT_NV_ADDR2NAME, NULL); 1180832dc76bSMariusz Zaborski } 1181832dc76bSMariusz Zaborski 1182832dc76bSMariusz Zaborski cookie = NULL; 1183832dc76bSMariusz Zaborski while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1184832dc76bSMariusz Zaborski if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) { 1185832dc76bSMariusz Zaborski void *sacookie; 1186832dc76bSMariusz Zaborski 1187832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1188832dc76bSMariusz Zaborski return (false); 1189832dc76bSMariusz Zaborski 1190832dc76bSMariusz Zaborski sacookie = NULL; 1191832dc76bSMariusz Zaborski while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1192832dc76bSMariusz Zaborski &sacookie) != NULL) { 1193832dc76bSMariusz Zaborski const void *sa; 1194832dc76bSMariusz Zaborski size_t sasize; 1195832dc76bSMariusz Zaborski 1196832dc76bSMariusz Zaborski if (cnvlist_type(sacookie) != NV_TYPE_BINARY) 1197832dc76bSMariusz Zaborski return (false); 1198832dc76bSMariusz Zaborski 1199832dc76bSMariusz Zaborski sa = cnvlist_get_binary(sacookie, &sasize); 1200832dc76bSMariusz Zaborski if (!net_allowed_bsaddr(oldfunclimits, sa, 1201832dc76bSMariusz Zaborski sasize)) { 1202832dc76bSMariusz Zaborski return (false); 1203832dc76bSMariusz Zaborski } 1204832dc76bSMariusz Zaborski } 1205832dc76bSMariusz Zaborski } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1206832dc76bSMariusz Zaborski size_t i, sfamilies; 1207832dc76bSMariusz Zaborski const uint64_t *families; 1208832dc76bSMariusz Zaborski 1209832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1210832dc76bSMariusz Zaborski return (false); 1211832dc76bSMariusz Zaborski 1212832dc76bSMariusz Zaborski families = cnvlist_get_number_array(cookie, &sfamilies); 1213832dc76bSMariusz Zaborski for (i = 0; i < sfamilies; i++) { 1214832dc76bSMariusz Zaborski if (!net_allowed_family(oldfunclimits, 1215832dc76bSMariusz Zaborski families[i])) { 1216832dc76bSMariusz Zaborski return (false); 1217832dc76bSMariusz Zaborski } 1218832dc76bSMariusz Zaborski } 1219832dc76bSMariusz Zaborski } else { 1220832dc76bSMariusz Zaborski return (false); 1221832dc76bSMariusz Zaborski } 1222832dc76bSMariusz Zaborski } 1223832dc76bSMariusz Zaborski 1224832dc76bSMariusz Zaborski return (true); 1225832dc76bSMariusz Zaborski } 1226832dc76bSMariusz Zaborski 1227832dc76bSMariusz Zaborski static bool 1228832dc76bSMariusz Zaborski verify_name2addr_newlimits(const nvlist_t *oldlimits, 1229832dc76bSMariusz Zaborski const nvlist_t *newfunclimit) 1230832dc76bSMariusz Zaborski { 1231832dc76bSMariusz Zaborski void *cookie; 1232832dc76bSMariusz Zaborski const nvlist_t *oldfunclimits; 1233832dc76bSMariusz Zaborski 1234832dc76bSMariusz Zaborski oldfunclimits = NULL; 1235832dc76bSMariusz Zaborski if (oldlimits != NULL) { 1236832dc76bSMariusz Zaborski oldfunclimits = dnvlist_get_nvlist(oldlimits, 1237832dc76bSMariusz Zaborski LIMIT_NV_ADDR2NAME, NULL); 1238832dc76bSMariusz Zaborski } 1239832dc76bSMariusz Zaborski 1240832dc76bSMariusz Zaborski cookie = NULL; 1241832dc76bSMariusz Zaborski while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) { 1242832dc76bSMariusz Zaborski if (strcmp(cnvlist_name(cookie), "hosts") == 0) { 1243832dc76bSMariusz Zaborski void *hostcookie; 1244832dc76bSMariusz Zaborski 1245832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NVLIST) 1246832dc76bSMariusz Zaborski return (false); 1247832dc76bSMariusz Zaborski 1248832dc76bSMariusz Zaborski hostcookie = NULL; 1249832dc76bSMariusz Zaborski while (nvlist_next(cnvlist_get_nvlist(cookie), NULL, 1250832dc76bSMariusz Zaborski &hostcookie) != NULL) { 1251832dc76bSMariusz Zaborski if (cnvlist_type(hostcookie) != NV_TYPE_STRING) 1252832dc76bSMariusz Zaborski return (false); 1253832dc76bSMariusz Zaborski 1254832dc76bSMariusz Zaborski if (!net_allowed_hosts(oldfunclimits, 1255832dc76bSMariusz Zaborski cnvlist_name(hostcookie), 1256832dc76bSMariusz Zaborski cnvlist_get_string(hostcookie))) { 1257832dc76bSMariusz Zaborski return (false); 1258832dc76bSMariusz Zaborski } 1259832dc76bSMariusz Zaborski } 1260832dc76bSMariusz Zaborski } else if (strcmp(cnvlist_name(cookie), "family") == 0) { 1261832dc76bSMariusz Zaborski size_t i, sfamilies; 1262832dc76bSMariusz Zaborski const uint64_t *families; 1263832dc76bSMariusz Zaborski 1264832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY) 1265832dc76bSMariusz Zaborski return (false); 1266832dc76bSMariusz Zaborski 1267832dc76bSMariusz Zaborski families = cnvlist_get_number_array(cookie, &sfamilies); 1268832dc76bSMariusz Zaborski for (i = 0; i < sfamilies; i++) { 1269832dc76bSMariusz Zaborski if (!net_allowed_family(oldfunclimits, 1270832dc76bSMariusz Zaborski families[i])) { 1271832dc76bSMariusz Zaborski return (false); 1272832dc76bSMariusz Zaborski } 1273832dc76bSMariusz Zaborski } 1274832dc76bSMariusz Zaborski } else { 1275832dc76bSMariusz Zaborski return (false); 1276832dc76bSMariusz Zaborski } 1277832dc76bSMariusz Zaborski } 1278832dc76bSMariusz Zaborski 1279832dc76bSMariusz Zaborski return (true); 1280832dc76bSMariusz Zaborski } 1281832dc76bSMariusz Zaborski 1282832dc76bSMariusz Zaborski static int 1283832dc76bSMariusz Zaborski net_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) 1284832dc76bSMariusz Zaborski { 1285832dc76bSMariusz Zaborski const char *name; 1286832dc76bSMariusz Zaborski void *cookie; 1287832dc76bSMariusz Zaborski bool hasmode, hasconnect, hasbind, hasaddr2name, hasname2addr; 1288832dc76bSMariusz Zaborski 1289832dc76bSMariusz Zaborski /* 1290832dc76bSMariusz Zaborski * Modes: 1291832dc76bSMariusz Zaborski * ADDR2NAME: 1292832dc76bSMariusz Zaborski * getnameinfo 1293832dc76bSMariusz Zaborski * DEPRECATED_ADDR2NAME: 1294832dc76bSMariusz Zaborski * gethostbyaddr 1295832dc76bSMariusz Zaborski * 1296832dc76bSMariusz Zaborski * NAME2ADDR: 1297832dc76bSMariusz Zaborski * getaddrinfo 1298832dc76bSMariusz Zaborski * DEPRECATED_NAME2ADDR: 1299832dc76bSMariusz Zaborski * gethostbyname 1300832dc76bSMariusz Zaborski * 1301832dc76bSMariusz Zaborski * Limit scheme: 1302832dc76bSMariusz Zaborski * mode : NV_TYPE_NUMBER 1303832dc76bSMariusz Zaborski * connect : NV_TYPE_NVLIST 1304832dc76bSMariusz Zaborski * sockaddr : NV_TYPE_NVLIST 1305832dc76bSMariusz Zaborski * "" : NV_TYPE_BINARY 1306832dc76bSMariusz Zaborski * ... : NV_TYPE_BINARY 1307832dc76bSMariusz Zaborski * bind : NV_TYPE_NVLIST 1308832dc76bSMariusz Zaborski * sockaddr : NV_TYPE_NVLIST 1309832dc76bSMariusz Zaborski * "" : NV_TYPE_BINARY 1310832dc76bSMariusz Zaborski * ... : NV_TYPE_BINARY 1311832dc76bSMariusz Zaborski * addr2name : NV_TYPE_NVLIST 1312832dc76bSMariusz Zaborski * family : NV_TYPE_NUMBER_ARRAY 1313832dc76bSMariusz Zaborski * sockaddr : NV_TYPE_NVLIST 1314832dc76bSMariusz Zaborski * "" : NV_TYPE_BINARY 1315832dc76bSMariusz Zaborski * ... : NV_TYPE_BINARY 1316832dc76bSMariusz Zaborski * name2addr : NV_TYPE_NVLIST 1317832dc76bSMariusz Zaborski * family : NV_TYPE_NUMBER 1318832dc76bSMariusz Zaborski * hosts : NV_TYPE_NVLIST 1319832dc76bSMariusz Zaborski * host : servname : NV_TYPE_STRING 1320832dc76bSMariusz Zaborski */ 1321832dc76bSMariusz Zaborski 1322832dc76bSMariusz Zaborski hasmode = false; 1323832dc76bSMariusz Zaborski hasconnect = false; 1324832dc76bSMariusz Zaborski hasbind = false; 1325832dc76bSMariusz Zaborski hasaddr2name = false; 1326832dc76bSMariusz Zaborski hasname2addr = false; 1327832dc76bSMariusz Zaborski 1328832dc76bSMariusz Zaborski cookie = NULL; 1329832dc76bSMariusz Zaborski while ((name = nvlist_next(newlimits, NULL, &cookie)) != NULL) { 1330832dc76bSMariusz Zaborski if (strcmp(name, "mode") == 0) { 1331832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NUMBER) { 1332832dc76bSMariusz Zaborski return (NO_RECOVERY); 1333832dc76bSMariusz Zaborski } 1334832dc76bSMariusz Zaborski if (!net_allowed_mode(oldlimits, 1335832dc76bSMariusz Zaborski cnvlist_get_number(cookie))) { 1336832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1337832dc76bSMariusz Zaborski } 1338832dc76bSMariusz Zaborski hasmode = true; 1339832dc76bSMariusz Zaborski continue; 1340832dc76bSMariusz Zaborski } 1341832dc76bSMariusz Zaborski 1342832dc76bSMariusz Zaborski if (cnvlist_type(cookie) != NV_TYPE_NVLIST) { 1343832dc76bSMariusz Zaborski return (NO_RECOVERY); 1344832dc76bSMariusz Zaborski } 1345832dc76bSMariusz Zaborski 1346832dc76bSMariusz Zaborski if (strcmp(name, LIMIT_NV_BIND) == 0) { 1347832dc76bSMariusz Zaborski hasbind = true; 1348832dc76bSMariusz Zaborski if (!verify_bind_newlimts(oldlimits, 1349832dc76bSMariusz Zaborski cnvlist_get_nvlist(cookie))) { 1350832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1351832dc76bSMariusz Zaborski } 1352832dc76bSMariusz Zaborski } else if (strcmp(name, LIMIT_NV_CONNECT) == 0) { 1353832dc76bSMariusz Zaborski hasconnect = true; 1354832dc76bSMariusz Zaborski if (!verify_connect_newlimits(oldlimits, 1355832dc76bSMariusz Zaborski cnvlist_get_nvlist(cookie))) { 1356832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1357832dc76bSMariusz Zaborski } 1358832dc76bSMariusz Zaborski } else if (strcmp(name, LIMIT_NV_ADDR2NAME) == 0) { 1359832dc76bSMariusz Zaborski hasaddr2name = true; 1360832dc76bSMariusz Zaborski if (!verify_addr2name_newlimits(oldlimits, 1361832dc76bSMariusz Zaborski cnvlist_get_nvlist(cookie))) { 1362832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1363832dc76bSMariusz Zaborski } 1364832dc76bSMariusz Zaborski } else if (strcmp(name, LIMIT_NV_NAME2ADDR) == 0) { 1365832dc76bSMariusz Zaborski hasname2addr = true; 1366832dc76bSMariusz Zaborski if (!verify_name2addr_newlimits(oldlimits, 1367832dc76bSMariusz Zaborski cnvlist_get_nvlist(cookie))) { 1368832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1369832dc76bSMariusz Zaborski } 1370832dc76bSMariusz Zaborski } 1371832dc76bSMariusz Zaborski } 1372832dc76bSMariusz Zaborski 1373832dc76bSMariusz Zaborski /* Mode is required. */ 1374832dc76bSMariusz Zaborski if (!hasmode) 1375832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1376832dc76bSMariusz Zaborski 1377832dc76bSMariusz Zaborski /* 1378832dc76bSMariusz Zaborski * If the new limit doesn't mention mode or family we have to 1379832dc76bSMariusz Zaborski * check if the current limit does have those. Missing mode or 1380832dc76bSMariusz Zaborski * family in the limit means that all modes or families are 1381832dc76bSMariusz Zaborski * allowed. 1382832dc76bSMariusz Zaborski */ 1383832dc76bSMariusz Zaborski if (oldlimits == NULL) 1384832dc76bSMariusz Zaborski return (0); 1385832dc76bSMariusz Zaborski if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_BIND)) 1386832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1387832dc76bSMariusz Zaborski if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_CONNECT)) 1388832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1389832dc76bSMariusz Zaborski if (!hasaddr2name && nvlist_exists(oldlimits, LIMIT_NV_ADDR2NAME)) 1390832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1391832dc76bSMariusz Zaborski if (!hasname2addr && nvlist_exists(oldlimits, LIMIT_NV_NAME2ADDR)) 1392832dc76bSMariusz Zaborski return (ENOTCAPABLE); 1393832dc76bSMariusz Zaborski return (0); 1394832dc76bSMariusz Zaborski } 1395832dc76bSMariusz Zaborski 1396832dc76bSMariusz Zaborski static int 1397832dc76bSMariusz Zaborski net_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, 1398832dc76bSMariusz Zaborski nvlist_t *nvlout) 1399832dc76bSMariusz Zaborski { 1400832dc76bSMariusz Zaborski 1401832dc76bSMariusz Zaborski if (strcmp(cmd, "bind") == 0) 1402832dc76bSMariusz Zaborski return (net_bind(limits, nvlin, nvlout)); 1403832dc76bSMariusz Zaborski else if (strcmp(cmd, "connect") == 0) 1404832dc76bSMariusz Zaborski return (net_connect(limits, nvlin, nvlout)); 1405832dc76bSMariusz Zaborski else if (strcmp(cmd, "gethostbyname") == 0) 1406832dc76bSMariusz Zaborski return (net_gethostbyname(limits, nvlin, nvlout)); 1407832dc76bSMariusz Zaborski else if (strcmp(cmd, "gethostbyaddr") == 0) 1408832dc76bSMariusz Zaborski return (net_gethostbyaddr(limits, nvlin, nvlout)); 1409832dc76bSMariusz Zaborski else if (strcmp(cmd, "getnameinfo") == 0) 1410832dc76bSMariusz Zaborski return (net_getnameinfo(limits, nvlin, nvlout)); 1411832dc76bSMariusz Zaborski else if (strcmp(cmd, "getaddrinfo") == 0) 1412832dc76bSMariusz Zaborski return (net_getaddrinfo(limits, nvlin, nvlout)); 1413832dc76bSMariusz Zaborski 1414832dc76bSMariusz Zaborski return (EINVAL); 1415832dc76bSMariusz Zaborski } 1416832dc76bSMariusz Zaborski 1417832dc76bSMariusz Zaborski CREATE_SERVICE("system.net", net_limit, net_command, 0); 1418