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