aboutsummaryrefslogtreecommitdiff
path: root/lib/libcasper/services/cap_net/tests/net_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libcasper/services/cap_net/tests/net_test.c')
-rw-r--r--lib/libcasper/services/cap_net/tests/net_test.c1487
1 files changed, 1487 insertions, 0 deletions
diff --git a/lib/libcasper/services/cap_net/tests/net_test.c b/lib/libcasper/services/cap_net/tests/net_test.c
new file mode 100644
index 000000000000..adf5773233c8
--- /dev/null
+++ b/lib/libcasper/services/cap_net/tests/net_test.c
@@ -0,0 +1,1487 @@
+/*-
+ * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+
+#include <atf-c.h>
+
+#include <libcasper.h>
+#include <casper/cap_net.h>
+
+#define TEST_DOMAIN_0 "example.com"
+#define TEST_DOMAIN_1 "freebsd.org"
+#define TEST_IPV4 "1.1.1.1"
+#define TEST_IPV6 "2001:4860:4860::8888"
+#define TEST_BIND_IPV4 "127.0.0.1"
+#define TEST_PORT 80
+#define TEST_PORT_STR "80"
+
+static cap_channel_t *
+create_network_service(void)
+{
+ cap_channel_t *capcas, *capnet;
+
+ capcas = cap_init();
+ ATF_REQUIRE(capcas != NULL);
+
+ capnet = cap_service_open(capcas, "system.net");
+ ATF_REQUIRE(capnet != NULL);
+
+ cap_close(capcas);
+ return (capnet);
+}
+
+static int
+test_getnameinfo_v4(cap_channel_t *chan, int family, const char *ip)
+{
+ struct sockaddr_in ipaddr;
+ char capfn[MAXHOSTNAMELEN];
+ char origfn[MAXHOSTNAMELEN];
+ int capret, sysret;
+
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ ipaddr.sin_family = family;
+ inet_pton(family, ip, &ipaddr.sin_addr);
+
+ capret = cap_getnameinfo(chan, (struct sockaddr *)&ipaddr, sizeof(ipaddr),
+ capfn, sizeof(capfn), NULL, 0, NI_NAMEREQD);
+ if (capret != 0 && capret == ENOTCAPABLE)
+ return (ENOTCAPABLE);
+
+ sysret = getnameinfo((struct sockaddr *)&ipaddr, sizeof(ipaddr), origfn,
+ sizeof(origfn), NULL, 0, NI_NAMEREQD);
+ if (sysret != 0) {
+ atf_tc_skip("getnameinfo(%s) failed: %s",
+ ip, gai_strerror(sysret));
+ }
+ ATF_REQUIRE(capret == 0);
+ ATF_REQUIRE(strcmp(origfn, capfn) == 0);
+
+ return (0);
+}
+
+static int
+test_getnameinfo_v6(cap_channel_t *chan, const char *ip)
+{
+ struct sockaddr_in6 ipaddr;
+ char capfn[MAXHOSTNAMELEN];
+ char origfn[MAXHOSTNAMELEN];
+ int capret, sysret;
+
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ ipaddr.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, ip, &ipaddr.sin6_addr);
+
+ capret = cap_getnameinfo(chan, (struct sockaddr *)&ipaddr, sizeof(ipaddr),
+ capfn, sizeof(capfn), NULL, 0, NI_NAMEREQD);
+ if (capret != 0 && capret == ENOTCAPABLE)
+ return (ENOTCAPABLE);
+
+ sysret = getnameinfo((struct sockaddr *)&ipaddr, sizeof(ipaddr), origfn,
+ sizeof(origfn), NULL, 0, NI_NAMEREQD);
+ if (sysret != 0) {
+ atf_tc_skip("getnameinfo(%s) failed: %s",
+ ip, gai_strerror(sysret));
+ }
+ ATF_REQUIRE(capret == 0);
+ ATF_REQUIRE(strcmp(origfn, capfn) == 0);
+
+ return (0);
+}
+
+static int
+test_getnameinfo(cap_channel_t *chan, int family, const char *ip)
+{
+
+ if (family == AF_INET6) {
+ return (test_getnameinfo_v6(chan, ip));
+ }
+
+ return (test_getnameinfo_v4(chan, family, ip));
+}
+
+static int
+test_gethostbyaddr_v4(cap_channel_t *chan, int family, const char *ip)
+{
+ struct in_addr ipaddr;
+ struct hostent *caphp, *orighp;
+
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ inet_pton(AF_INET, ip, &ipaddr);
+
+ caphp = cap_gethostbyaddr(chan, &ipaddr, sizeof(ipaddr), family);
+ if (caphp == NULL && h_errno == ENOTCAPABLE)
+ return (ENOTCAPABLE);
+
+ orighp = gethostbyaddr(&ipaddr, sizeof(ipaddr), family);
+ if (orighp == NULL)
+ atf_tc_skip("gethostbyaddr(%s) failed", ip);
+ ATF_REQUIRE(caphp != NULL);
+ ATF_REQUIRE(strcmp(orighp->h_name, caphp->h_name) == 0);
+
+ return (0);
+}
+
+static int
+test_gethostbyaddr_v6(cap_channel_t *chan, const char *ip)
+{
+ struct in6_addr ipaddr;
+ struct hostent *caphp, *orighp;
+
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ inet_pton(AF_INET6, ip, &ipaddr);
+
+ caphp = cap_gethostbyaddr(chan, &ipaddr, sizeof(ipaddr), AF_INET6);
+ if (caphp == NULL && h_errno == ENOTCAPABLE)
+ return (ENOTCAPABLE);
+
+ orighp = gethostbyaddr(&ipaddr, sizeof(ipaddr), AF_INET6);
+ if (orighp == NULL)
+ atf_tc_skip("gethostbyaddr(%s) failed", ip);
+ ATF_REQUIRE(caphp != NULL);
+ ATF_REQUIRE(strcmp(orighp->h_name, caphp->h_name) == 0);
+
+ return (0);
+}
+
+static int
+test_gethostbyaddr(cap_channel_t *chan, int family, const char *ip)
+{
+
+ if (family == AF_INET6) {
+ return (test_gethostbyaddr_v6(chan, ip));
+ } else {
+ return (test_gethostbyaddr_v4(chan, family, ip));
+ }
+}
+
+static int
+test_getaddrinfo(cap_channel_t *chan, int family, const char *domain,
+ const char *servname)
+{
+ struct addrinfo hints, *capres, *origres, *res0, *res1;
+ bool found;
+ int capret, sysret;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+
+ capret = cap_getaddrinfo(chan, domain, servname, &hints, &capres);
+ if (capret != 0 && capret == ENOTCAPABLE)
+ return (capret);
+
+ sysret = getaddrinfo(domain, servname, &hints, &origres);
+ if (sysret != 0)
+ atf_tc_skip("getaddrinfo(%s) failed: %s",
+ domain, gai_strerror(sysret));
+ ATF_REQUIRE(capret == 0);
+
+ for (res0 = capres; res0 != NULL; res0 = res0->ai_next) {
+ found = false;
+ for (res1 = origres; res1 != NULL; res1 = res1->ai_next) {
+ if (res1->ai_addrlen == res0->ai_addrlen &&
+ memcmp(res1->ai_addr, res0->ai_addr,
+ res0->ai_addrlen) == 0) {
+ found = true;
+ break;
+ }
+ }
+ ATF_REQUIRE(found);
+ }
+
+ freeaddrinfo(capres);
+ freeaddrinfo(origres);
+ return (0);
+}
+
+static int
+test_gethostbyname(cap_channel_t *chan, int family, const char *domain)
+{
+ struct hostent *caphp, *orighp;
+
+ caphp = cap_gethostbyname2(chan, domain, family);
+ if (caphp == NULL && h_errno == ENOTCAPABLE)
+ return (h_errno);
+
+ orighp = gethostbyname2(domain, family);
+ if (orighp == NULL)
+ atf_tc_skip("gethostbyname2(%s) failed", domain);
+
+ ATF_REQUIRE(caphp != NULL);
+ ATF_REQUIRE(strcmp(caphp->h_name, orighp->h_name) == 0);
+ return (0);
+}
+
+static int
+test_bind(cap_channel_t *chan, const char *ip)
+{
+ struct sockaddr_in ipv4;
+ int capfd, ret, serrno;
+
+ capfd = socket(AF_INET, SOCK_STREAM, 0);
+ ATF_REQUIRE(capfd > 0);
+
+ memset(&ipv4, 0, sizeof(ipv4));
+ ipv4.sin_family = AF_INET;
+ inet_pton(AF_INET, ip, &ipv4.sin_addr);
+
+ ret = cap_bind(chan, capfd, (struct sockaddr *)&ipv4, sizeof(ipv4));
+ serrno = errno;
+ close(capfd);
+
+ return (ret < 0 ? serrno : 0);
+}
+
+static int
+test_connect(cap_channel_t *chan, const char *ip, unsigned short port)
+{
+ struct sockaddr_in ipv4;
+ int capfd, ret, serrno;
+
+ capfd = socket(AF_INET, SOCK_STREAM, 0);
+ ATF_REQUIRE(capfd >= 0);
+
+ memset(&ipv4, 0, sizeof(ipv4));
+ ipv4.sin_family = AF_INET;
+ ipv4.sin_port = htons(port);
+ inet_pton(AF_INET, ip, &ipv4.sin_addr);
+
+ ret = cap_connect(chan, capfd, (struct sockaddr *)&ipv4, sizeof(ipv4));
+ serrno = errno;
+ ATF_REQUIRE(close(capfd) == 0);
+
+ if (ret < 0 && serrno != ENOTCAPABLE) {
+ int sd;
+
+ /*
+ * If the connection failed, it might be because we can't reach
+ * the destination host. To check, try a plain connect() and
+ * see if it fails with the same error.
+ */
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ ATF_REQUIRE(sd >= 0);
+
+ memset(&ipv4, 0, sizeof(ipv4));
+ ipv4.sin_family = AF_INET;
+ ipv4.sin_port = htons(port);
+ inet_pton(AF_INET, ip, &ipv4.sin_addr);
+ ret = connect(sd, (struct sockaddr *)&ipv4, sizeof(ipv4));
+ ATF_REQUIRE(ret < 0);
+ ATF_REQUIRE_MSG(errno == serrno, "errno %d != serrno %d",
+ errno, serrno);
+ ATF_REQUIRE(close(sd) == 0);
+ atf_tc_skip("connect(%s:%d) failed: %s",
+ ip, port, strerror(serrno));
+ }
+
+ return (ret < 0 ? serrno : 0);
+}
+
+static void
+test_extend_mode(cap_channel_t *capnet, int current)
+{
+ cap_net_limit_t *limit;
+ const int rights[] = {
+ CAPNET_ADDR2NAME,
+ CAPNET_NAME2ADDR,
+ CAPNET_DEPRECATED_ADDR2NAME,
+ CAPNET_DEPRECATED_NAME2ADDR,
+ CAPNET_CONNECT,
+ CAPNET_BIND,
+ CAPNET_CONNECTDNS
+ };
+ size_t i;
+
+ for (i = 0; i < nitems(rights); i++) {
+ if (current == rights[i])
+ continue;
+
+ limit = cap_net_limit_init(capnet, current | rights[i]);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+ }
+}
+
+ATF_TC(capnet__getnameinfo);
+ATF_TC_HEAD(capnet__getnameinfo, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__getnameinfo, tc)
+{
+ cap_channel_t *capnet;
+
+ capnet = create_network_service();
+
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__connect);
+ATF_TC_HEAD(capnet__connect, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__connect, tc)
+{
+ cap_channel_t *capnet;
+
+ capnet = create_network_service();
+
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__bind);
+ATF_TC_HEAD(capnet__bind, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__bind, tc)
+{
+ cap_channel_t *capnet;
+
+ capnet = create_network_service();
+
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__getaddrinfo);
+ATF_TC_HEAD(capnet__getaddrinfo, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__getaddrinfo, tc)
+{
+ cap_channel_t *capnet;
+ struct addrinfo hints, *capres;
+
+ capnet = create_network_service();
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+
+ ATF_REQUIRE(cap_getaddrinfo(capnet, TEST_IPV4, "80", &hints, &capres) ==
+ 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__gethostbyname);
+ATF_TC_HEAD(capnet__gethostbyname, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__gethostbyname, tc)
+{
+ cap_channel_t *capnet;
+
+ capnet = create_network_service();
+
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__gethostbyaddr);
+ATF_TC_HEAD(capnet__gethostbyaddr, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__gethostbyaddr, tc)
+{
+ cap_channel_t *capnet;
+
+ capnet = create_network_service();
+
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__getnameinfo_buffer);
+ATF_TC_HEAD(capnet__getnameinfo_buffer, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__getnameinfo_buffer, tc)
+{
+ cap_channel_t *chan;
+ struct sockaddr_in sin;
+ int ret;
+ struct {
+ char host[sizeof(TEST_IPV4)];
+ char host_canary;
+ char serv[sizeof(TEST_PORT_STR)];
+ char serv_canary;
+ } buffers;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(TEST_PORT);
+ ret = inet_pton(AF_INET, TEST_IPV4, &sin.sin_addr);
+ ATF_REQUIRE_EQ(1, ret);
+
+ memset(&buffers, '!', sizeof(buffers));
+
+ chan = create_network_service();
+ ret = cap_getnameinfo(chan, (struct sockaddr *)&sin, sizeof(sin),
+ buffers.host, sizeof(buffers.host),
+ buffers.serv, sizeof(buffers.serv),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ ATF_REQUIRE_EQ_MSG(0, ret, "%d", ret);
+
+ // Verify that cap_getnameinfo worked with minimally sized buffers.
+ ATF_CHECK_EQ(0, strcmp(TEST_IPV4, buffers.host));
+ ATF_CHECK_EQ(0, strcmp(TEST_PORT_STR, buffers.serv));
+
+ // Verify that cap_getnameinfo did not overflow the buffers.
+ ATF_CHECK_EQ('!', buffers.host_canary);
+ ATF_CHECK_EQ('!', buffers.serv_canary);
+
+ cap_close(chan);
+}
+
+ATF_TC(capnet__limits_addr2name_mode);
+ATF_TC_HEAD(capnet__limits_addr2name_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_addr2name_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE);
+
+ test_extend_mode(capnet, CAPNET_ADDR2NAME);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_addr2name_family);
+ATF_TC_HEAD(capnet__limits_addr2name_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_addr2name_family, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ int family[] = { AF_INET6, AF_INET };
+
+ capnet = create_network_service();
+
+ /* Limit to AF_INET6 and AF_INET. */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name_family(limit, family, nitems(family));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0);
+
+ /* Limit to AF_INET6 and AF_INET. */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name_family(limit, &family[0], 1);
+ cap_net_limit_addr2name_family(limit, &family[1], 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0);
+
+ /* Limit to AF_INET6. */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name_family(limit, family, 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_addr2name);
+ATF_TC_HEAD(capnet__limits_addr2name, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_addr2name, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ struct sockaddr_in ipaddrv4;
+ struct sockaddr_in6 ipaddrv6;
+
+ capnet = create_network_service();
+
+ /* Limit to TEST_IPV4 and TEST_IPV6. */
+ memset(&ipaddrv4, 0, sizeof(ipaddrv4));
+ memset(&ipaddrv6, 0, sizeof(ipaddrv6));
+
+ ipaddrv4.sin_family = AF_INET;
+ inet_pton(AF_INET, TEST_IPV4, &ipaddrv4.sin_addr);
+
+ ipaddrv6.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, TEST_IPV6, &ipaddrv6.sin6_addr);
+
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+
+ cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4,
+ sizeof(ipaddrv4));
+ cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv6,
+ sizeof(ipaddrv6));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, "127.0.0.1") ==
+ ENOTCAPABLE);
+
+ /* Limit to AF_INET. */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4,
+ sizeof(ipaddrv4));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, "127.0.0.1") ==
+ ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_deprecated_addr2name_mode);
+ATF_TC_HEAD(capnet__limits_deprecated_addr2name_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_addr2name_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_deprecated_addr2name_family);
+ATF_TC_HEAD(capnet__limits_deprecated_addr2name_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_addr2name_family, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ int family[] = { AF_INET6, AF_INET };
+
+ capnet = create_network_service();
+
+ /* Limit to AF_INET6 and AF_INET. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name_family(limit, family, nitems(family));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, PF_LINK, TEST_IPV4) ==
+ ENOTCAPABLE);
+
+ /* Limit to AF_INET6 and AF_INET. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name_family(limit, &family[0], 1);
+ cap_net_limit_addr2name_family(limit, &family[1], 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, PF_LINK, TEST_IPV4) ==
+ ENOTCAPABLE);
+
+ /* Limit to AF_INET6. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name_family(limit, family, 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, PF_LINK, TEST_IPV4) ==
+ ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_deprecated_addr2name);
+ATF_TC_HEAD(capnet__limits_deprecated_addr2name, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_addr2name, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ struct in_addr ipaddrv4;
+ struct in6_addr ipaddrv6;
+
+ capnet = create_network_service();
+
+ /* Limit to TEST_IPV4 and TEST_IPV6. */
+ memset(&ipaddrv4, 0, sizeof(ipaddrv4));
+ memset(&ipaddrv6, 0, sizeof(ipaddrv6));
+
+ inet_pton(AF_INET, TEST_IPV4, &ipaddrv4);
+ inet_pton(AF_INET6, TEST_IPV6, &ipaddrv6);
+
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+
+ cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4,
+ sizeof(ipaddrv4));
+ cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv6,
+ sizeof(ipaddrv6));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, "127.0.0.1") ==
+ ENOTCAPABLE);
+
+ /* Limit to AF_INET. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4,
+ sizeof(ipaddrv4));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, "127.0.0.1") ==
+ ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+
+ATF_TC(capnet__limits_name2addr_mode);
+ATF_TC_HEAD(capnet__limits_name2addr_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_name2addr_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE);
+
+ test_extend_mode(capnet, CAPNET_ADDR2NAME);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_name2addr_hosts);
+ATF_TC_HEAD(capnet__limits_name2addr_hosts, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_name2addr_hosts, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* Limit to TEST_DOMAIN_0 and localhost only. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr(limit, "localhost", NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, "localhost", NULL) == 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, NULL) ==
+ ENOTCAPABLE);
+
+ /* Limit to TEST_DOMAIN_0 only. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, "localhost", NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ /* Try to extend the limit. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_1, NULL);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_1, NULL);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_name2addr_hosts_servnames_strict);
+ATF_TC_HEAD(capnet__limits_name2addr_hosts_servnames_strict, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_strict, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /*
+ * Limit to TEST_DOMAIN_0 and HTTP service.
+ */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, "http");
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "http") ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "snmp") ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "http") ==
+ ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_name2addr_hosts_servnames_mix);
+ATF_TC_HEAD(capnet__limits_name2addr_hosts_servnames_mix, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_mix, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /*
+ * Limit to TEST_DOMAIN_0 and any servnamex, and any domain with
+ * servname HTTP.
+ */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr(limit, NULL, "http");
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "http") ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "http") ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "snmp") ==
+ ENOTCAPABLE);
+
+ /* Limit to HTTP servname only. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, NULL, "http");
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "http") ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "http") ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "snmp") ==
+ ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_name2addr_family);
+ATF_TC_HEAD(capnet__limits_name2addr_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_name2addr_family, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ int family[] = { AF_INET6, AF_INET };
+
+ capnet = create_network_service();
+
+ /* Limit to AF_INET and AF_INET6. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr_family(limit, family, nitems(family));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET6, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, PF_LINK, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+
+ /* Limit to AF_INET and AF_INET6. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr_family(limit, &family[0], 1);
+ cap_net_limit_name2addr_family(limit, &family[1], 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET6, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, PF_LINK, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+
+ /* Limit to AF_INET6 only. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr_family(limit, family, 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET6, TEST_DOMAIN_0, NULL) ==
+ 0);
+ ATF_REQUIRE(test_getaddrinfo(capnet, PF_LINK, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_deprecated_name2addr_mode);
+ATF_TC_HEAD(capnet__limits_deprecated_name2addr_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_name2addr_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE);
+
+ test_extend_mode(capnet, CAPNET_ADDR2NAME);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_deprecated_name2addr_hosts);
+ATF_TC_HEAD(capnet__limits_deprecated_name2addr_hosts, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_name2addr_hosts, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* Limit to TEST_DOMAIN_0 and localhost only. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr(limit, "localhost", NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0);
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, "localhost") == 0);
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_1) == ENOTCAPABLE);
+
+ /* Limit to TEST_DOMAIN_0 only. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, "localhost") == ENOTCAPABLE);
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_1) == ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_deprecated_name2addr_family);
+ATF_TC_HEAD(capnet__limits_deprecated_name2addr_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_name2addr_family, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ int family[] = { AF_INET6, AF_INET };
+
+ capnet = create_network_service();
+
+ /* Limit to AF_INET and AF_INET6. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr_family(limit, family, nitems(family));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0);
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET6, TEST_DOMAIN_0) == 0);
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, PF_LINK, TEST_DOMAIN_0) == ENOTCAPABLE);
+
+ /* Limit to AF_INET and AF_INET6. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr_family(limit, &family[0], 1);
+ cap_net_limit_name2addr_family(limit, &family[1], 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0);
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET6, TEST_DOMAIN_0) == 0);
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, PF_LINK, TEST_DOMAIN_0) == ENOTCAPABLE);
+
+ /* Limit to AF_INET6 only. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL);
+ cap_net_limit_name2addr_family(limit, family, 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET6, TEST_DOMAIN_0) == 0);
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, PF_LINK, TEST_DOMAIN_0) == ENOTCAPABLE);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_bind_mode);
+ATF_TC_HEAD(capnet__limits_bind_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_bind_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_BIND);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE);
+
+ test_extend_mode(capnet, CAPNET_ADDR2NAME);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_bind);
+ATF_TC_HEAD(capnet__limits_bind, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_bind, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ struct sockaddr_in ipv4;
+
+ capnet = create_network_service();
+
+ limit = cap_net_limit_init(capnet, CAPNET_BIND);
+ ATF_REQUIRE(limit != NULL);
+
+ memset(&ipv4, 0, sizeof(ipv4));
+ ipv4.sin_family = AF_INET;
+ inet_pton(AF_INET, TEST_BIND_IPV4, &ipv4.sin_addr);
+
+ cap_net_limit_bind(limit, (struct sockaddr *)&ipv4, sizeof(ipv4));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == 0);
+ ATF_REQUIRE(test_bind(capnet, "127.0.0.2") == ENOTCAPABLE);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_connect_mode);
+ATF_TC_HEAD(capnet__limits_connect_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_connect_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECT);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE);
+
+ test_extend_mode(capnet, CAPNET_ADDR2NAME);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_connect_dns_mode);
+ATF_TC_HEAD(capnet__limits_connect_dns_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_connect_dns_mode, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+
+ capnet = create_network_service();
+
+ /* LIMIT */
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECT | CAPNET_CONNECTDNS);
+ ATF_REQUIRE(limit != NULL);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ /* ALLOWED */
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(
+ test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE);
+ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) ==
+ ENOTCAPABLE);
+ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE);
+
+ test_extend_mode(capnet, CAPNET_ADDR2NAME);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_connect);
+ATF_TC_HEAD(capnet__limits_connect, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_connect, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ struct sockaddr_in ipv4;
+
+ capnet = create_network_service();
+
+ /* Limit only to TEST_IPV4 on port 80 and 443. */
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECT);
+ ATF_REQUIRE(limit != NULL);
+ memset(&ipv4, 0, sizeof(ipv4));
+ ipv4.sin_family = AF_INET;
+ ipv4.sin_port = htons(80);
+ inet_pton(AF_INET, TEST_IPV4, &ipv4.sin_addr);
+ cap_net_limit_connect(limit, (struct sockaddr *)&ipv4, sizeof(ipv4));
+
+ ipv4.sin_port = htons(443);
+ cap_net_limit_connect(limit, (struct sockaddr *)&ipv4, sizeof(ipv4));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == 0);
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 80) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 443) == 0);
+
+ /* Limit only to TEST_IPV4 on port 443. */
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECT);
+ cap_net_limit_connect(limit, (struct sockaddr *)&ipv4, sizeof(ipv4));
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 433) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 80) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE);
+ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 443) == 0);
+
+ /* Unable to set empty limits. Empty limits means full access. */
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECT);
+ ATF_REQUIRE(cap_net_limit(limit) != 0);
+
+ cap_close(capnet);
+}
+
+ATF_TC(capnet__limits_connecttodns);
+ATF_TC_HEAD(capnet__limits_connecttodns, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_connecttodns, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ struct addrinfo hints, *capres, *res;
+ int family[] = { AF_INET };
+ int error;
+
+ capnet = create_network_service();
+
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECTDNS |
+ CAPNET_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_IPV4, "80");
+ cap_net_limit_name2addr_family(limit, family, 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE);
+ ATF_REQUIRE(cap_getaddrinfo(capnet, TEST_IPV4, "80", &hints, &capres) ==
+ 0);
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE);
+
+ for (res = capres; res != NULL; res = res->ai_next) {
+ int s;
+
+ ATF_REQUIRE(res->ai_family == AF_INET);
+ ATF_REQUIRE(res->ai_socktype == SOCK_STREAM);
+
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ ATF_REQUIRE(s >= 0);
+
+ error = cap_connect(capnet, s, res->ai_addr,
+ res->ai_addrlen);
+ if (error != 0 && errno != ENOTCAPABLE)
+ atf_tc_skip("unable to connect: %s", strerror(errno));
+ ATF_REQUIRE(error == 0);
+ ATF_REQUIRE(close(s) == 0);
+ }
+
+ freeaddrinfo(capres);
+ cap_close(capnet);
+}
+
+
+ATF_TC(capnet__limits_deprecated_connecttodns);
+ATF_TC_HEAD(capnet__limits_deprecated_connecttodns, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(capnet__limits_deprecated_connecttodns, tc)
+{
+ cap_channel_t *capnet;
+ cap_net_limit_t *limit;
+ struct hostent *caphp;
+ struct in_addr ipaddr;
+ struct sockaddr_in connaddr;
+ int family[] = { AF_INET };
+ int error, i;
+
+ capnet = create_network_service();
+
+ limit = cap_net_limit_init(capnet, CAPNET_CONNECTDNS |
+ CAPNET_DEPRECATED_NAME2ADDR);
+ ATF_REQUIRE(limit != NULL);
+ cap_net_limit_name2addr(limit, TEST_IPV4, NULL);
+ cap_net_limit_name2addr_family(limit, family, 1);
+ ATF_REQUIRE(cap_net_limit(limit) == 0);
+
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ inet_pton(AF_INET, TEST_IPV4, &ipaddr);
+
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE);
+ caphp = cap_gethostbyname2(capnet, TEST_IPV4, AF_INET);
+ ATF_REQUIRE(caphp != NULL);
+ ATF_REQUIRE(caphp->h_addrtype == AF_INET);
+ ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE);
+
+ for (i = 0; caphp->h_addr_list[i] != NULL; i++) {
+ int s;
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ ATF_REQUIRE(s >= 0);
+
+ memset(&connaddr, 0, sizeof(connaddr));
+ connaddr.sin_family = AF_INET;
+ memcpy((char *)&connaddr.sin_addr.s_addr,
+ (char *)caphp->h_addr_list[i], caphp->h_length);
+ connaddr.sin_port = htons(80);
+
+ error = cap_connect(capnet, s, (struct sockaddr *)&connaddr,
+ sizeof(connaddr));
+ if (error != 0 && errno != ENOTCAPABLE)
+ atf_tc_skip("unable to connect: %s", strerror(errno));
+ ATF_REQUIRE(error == 0);
+ ATF_REQUIRE(close(s) == 0);
+ }
+
+ cap_close(capnet);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, capnet__connect);
+ ATF_TP_ADD_TC(tp, capnet__bind);
+ ATF_TP_ADD_TC(tp, capnet__getnameinfo);
+ ATF_TP_ADD_TC(tp, capnet__getaddrinfo);
+ ATF_TP_ADD_TC(tp, capnet__gethostbyname);
+ ATF_TP_ADD_TC(tp, capnet__gethostbyaddr);
+
+ ATF_TP_ADD_TC(tp, capnet__getnameinfo_buffer);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_addr2name_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_addr2name_family);
+ ATF_TP_ADD_TC(tp, capnet__limits_addr2name);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_addr2name_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_addr2name_family);
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_addr2name);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_name2addr_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_name2addr_hosts);
+ ATF_TP_ADD_TC(tp, capnet__limits_name2addr_hosts_servnames_strict);
+ ATF_TP_ADD_TC(tp, capnet__limits_name2addr_hosts_servnames_mix);
+ ATF_TP_ADD_TC(tp, capnet__limits_name2addr_family);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_name2addr_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_name2addr_hosts);
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_name2addr_family);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_bind_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_bind);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_connect_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_connect_dns_mode);
+ ATF_TP_ADD_TC(tp, capnet__limits_connect);
+
+ ATF_TP_ADD_TC(tp, capnet__limits_connecttodns);
+ ATF_TP_ADD_TC(tp, capnet__limits_deprecated_connecttodns);
+
+ return (atf_no_error());
+}