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