Index: lib/libcasper/services/cap_net/Makefile =================================================================== --- lib/libcasper/services/cap_net/Makefile +++ lib/libcasper/services/cap_net/Makefile @@ -44,5 +44,6 @@ MLINKS+=cap_net.3 cap_gethostbyname.3 MLINKS+=cap_net.3 cap_gethostbyname2.3 MLINKS+=cap_net.3 cap_getnameinfo.3 +MLINKS+=cap_net.3 cap_getprotobyname.3 .include Index: lib/libcasper/services/cap_net/cap_net.h =================================================================== --- lib/libcasper/services/cap_net/cap_net.h +++ lib/libcasper/services/cap_net/cap_net.h @@ -36,11 +36,11 @@ #include #include - #include struct addrinfo; struct hostent; +struct protoent; struct cap_net_limit; typedef struct cap_net_limit cap_net_limit_t; @@ -66,6 +66,8 @@ socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); +struct protoent *cap_getprotobyname(cap_channel_t *chan, const char *name); + /* Limit functions. */ cap_net_limit_t *cap_net_limit_init(cap_channel_t *chan, uint64_t mode); int cap_net_limit(cap_net_limit_t *limit); @@ -103,6 +105,8 @@ getaddrinfo(hostname, servname, hints, res) #define cap_getnameinfo(chan, sa, salen, host, hostlen, serv, servlen, flags) \ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) +#define cap_getprotobyname(chan, name) \ + getprotobyname(name) /* Limit functions. */ #define cap_net_limit_init(chan, mode) ((cap_net_limit_t *)malloc(8)) Index: lib/libcasper/services/cap_net/cap_net.3 =================================================================== --- lib/libcasper/services/cap_net/cap_net.3 +++ lib/libcasper/services/cap_net/cap_net.3 @@ -34,6 +34,7 @@ .Nm cap_gethostbyname , .Nm cap_gethostbyname2 , .Nm cap_getnameinfo , +.Nm cap_getprotobyname , .Nm cap_net_free , .Nm cap_net_limit , .Nm cap_net_limit_addr2name , @@ -64,6 +65,8 @@ .Fn cap_gethostbyname2 "const cap_channel_t *chan" "const char *name" "int af" .Ft "struct hostent *" .Fn cap_gethostbyaddr "const cap_channel_t *chan" "const void *addr" "socklen_t len" "int af" +.Ft "struct protoent *" +.Fn cap_getprotobyname "const cap_channel_t *chan" "const char *name" .Ft "cap_net_limit_t *" .Fn cap_net_limit_init "cap_channel_t *chan" "uint64_t mode" .Ft int @@ -89,17 +92,19 @@ .Fn cap_connect, .Fn cap_gethostbyname , .Fn cap_gethostbyname2 , -.Fn cap_gethostbyaddr +.Fn cap_gethostbyaddr , +.Fn cap_getnameinfo , and -.Fn cap_getnameinfo +.Fn cap_getprotobyname are respectively equivalent to .Xr bind 2 , .Xr connect 2 , .Xr gethostbyname 3 , .Xr gethostbyname2 3 , -.Xr gethostbyaddr 3 +.Xr gethostbyaddr 3 , +.Xr getnameinfo 3 , and -.Xr getnameinfo 3 +.Xr getprotobyname 3 except that the connection to the .Nm system.net service needs to be provided. @@ -224,6 +229,7 @@ int familylimit, error, s; const char *host = "example.com"; struct addrinfo hints, *res; +struct protoent *ent; /* Open capability to Casper. */ capcas = cap_init(); @@ -245,20 +251,26 @@ /* Close Casper capability. */ cap_close(capcas); +/* Get information about TCP. */ +ent = cap_getprotobyname(capnet, "tcp"); +if (ent == NULL) + err(1, "Unable to get TCP info"); + /* Limit system.net to reserve IPv4 addresses, to host example.com . */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR | CAPNET_CONNECTDNS); if (limit == NULL) - err(1, "Unable to create limits."); + err(1, "Unable to create limits"); cap_net_limit_name2addr(limit, host, "80"); familylimit = AF_INET; cap_net_limit_name2addr_family(limit, &familylimit, 1); if (cap_net_limit(limit) < 0) - err(1, "Unable to apply limits."); + err(1, "Unable to apply limits"); /* Find IP addresses for the given host. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; +hints.ai_protocol = ent->p_proto; error = cap_getaddrinfo(capnet, host, "80", &hints, &res); if (error != 0) @@ -281,7 +293,9 @@ .Xr gethostbyname 3 , .Xr gethostbyname2 3 , .Xr getnameinfo 3 , +.Xr getprotobyname 3 , .Xr capsicum 4 , .Xr nv 9 .Sh AUTHORS .An Mariusz Zaborski Aq Mt oshogbo@FreeBSD.org +.An Ryan Moeller Aq Mt freqlabs@FreeBSD.org Index: lib/libcasper/services/cap_net/cap_net.c =================================================================== --- lib/libcasper/services/cap_net/cap_net.c +++ lib/libcasper/services/cap_net/cap_net.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2020 Mariusz Zaborski + * Copyright (c) 2020 Ryan Moeller * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -375,6 +377,74 @@ return (0); } +static void +protoent_free(struct protoent *pp) +{ + + free(pp->p_name); + pp->p_name = NULL; + if (pp->p_aliases != NULL) { + while (*pp->p_aliases != NULL) + free(*pp->p_aliases++); + free(pp->p_aliases); + } +} + +static struct protoent * +protoent_unpack(const nvlist_t *nvl, struct protoent *pp) +{ + const char * const *aliases = NULL; + size_t n; + + protoent_free(pp); + + pp->p_name = strdup(nvlist_get_string(nvl, "name")); + if (pp->p_name == NULL) + goto fail; + + aliases = nvlist_get_string_array(nvl, "aliases", &n); + if (aliases == NULL) + goto fail; + pp->p_aliases = calloc(sizeof(char *), n + 1); + if (pp->p_aliases == NULL) + goto fail; + pp->p_aliases[n] = NULL; + while (n-- > 0) { + if ((pp->p_aliases[n] = strdup(aliases[n])) == NULL) { + for (++n; pp->p_aliases[n] != NULL; ++n) { + free(pp->p_aliases[n]); + pp->p_aliases[n] = NULL; + } + goto fail; + } + } + + pp->p_proto = (int)nvlist_get_number(nvl, "proto"); + + return (pp); +fail: + protoent_free(pp); + return (NULL); +} + +struct protoent * +cap_getprotobyname(cap_channel_t *chan, const char *name) +{ + struct protoent *pp, pent = { 0 }; + nvlist_t *nvl; + + nvl = nvlist_create(0); + nvlist_add_string(nvl, "cmd", "getprotobyname"); + nvlist_add_string(nvl, "name", name); + nvl = cap_xfer_nvlist(chan, nvl); + if (nvl == NULL || dnvlist_get_number(nvl, "error", 0) != 0) + return (NULL); + + pp = protoent_unpack(nvl, &pent); + nvlist_destroy(nvl); + return (pp); +} + cap_net_limit_t * cap_net_limit_init(cap_channel_t *chan, uint64_t mode) { @@ -1004,6 +1074,34 @@ return (error); } +static void +protoent_pack(const struct protoent *pp, nvlist_t *nvl) +{ + int n = 0; + + nvlist_add_string(nvl, "name", pp->p_name); + + while (pp->p_aliases[n] != NULL) + ++n; + nvlist_add_string_array(nvl, "aliases", + (const char * const *)pp->p_aliases, n); + + nvlist_add_number(nvl, "proto", (uint64_t)pp->p_proto); +} + +static int +net_getprotobyname(const nvlist_t *limits __unused, const nvlist_t *nvlin, + nvlist_t *nvlout) +{ + struct protoent *pp; + + pp = getprotobyname(nvlist_get_string(nvlin, "name")); + if (pp == NULL) + return (ENOENT); + protoent_pack(pp, nvlout); + return (0); +} + static int net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) { @@ -1378,6 +1476,8 @@ return (net_getnameinfo(limits, nvlin, nvlout)); else if (strcmp(cmd, "getaddrinfo") == 0) return (net_getaddrinfo(limits, nvlin, nvlout)); + else if (strcmp(cmd, "getprotobyname") == 0) + return (net_getprotobyname(limits, nvlin, nvlout)); return (EINVAL); } Index: lib/libcasper/services/cap_net/tests/net_test.c =================================================================== --- lib/libcasper/services/cap_net/tests/net_test.c +++ lib/libcasper/services/cap_net/tests/net_test.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2020 Mariusz Zaborski + * Copyright (c) 2020 Ryan Moeller * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1126,6 +1127,28 @@ cap_close(capnet); } +ATF_TC_WITHOUT_HEAD(capnet__getprotobyname); +ATF_TC_BODY(capnet__getprotobyname, tc) +{ + cap_channel_t *capnet; + struct protoent *pp; + size_t n = 0; + + capnet = create_network_service(); + + pp = cap_getprotobyname(capnet, "tcp"); + ATF_REQUIRE(pp != NULL); + + ATF_REQUIRE(pp->p_name != NULL); + ATF_REQUIRE(pp->p_aliases != NULL); + while (pp->p_aliases[n] != NULL) + ++n; + ATF_REQUIRE(n > 0); + ATF_REQUIRE(pp->p_proto != 0); + + cap_close(capnet); +} + ATF_TP_ADD_TCS(tp) { @@ -1156,5 +1179,7 @@ ATF_TP_ADD_TC(tp, capnet__limits_connecttodns); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_connecttodns); + ATF_TP_ADD_TC(tp, capnet__getprotobyname); + return (atf_no_error()); }