#include <stdlib.h>
#include <err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysmacros.h>
#include <errno.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <net/pfkeyv2.h>
#include <net/pfpolicy.h>
typedef struct {
const char *me_desc;
int me_domain;
int me_type;
int me_proto;
int me_value;
int me_level;
int me_sockopt;
int me_errno;
} minttl_err_test_t;
static const minttl_err_test_t minttl_err_tests[] = {
{
.me_desc = "IP_MINTTL: UDS SOCK_STREAM not supported",
.me_domain = PF_UNIX,
.me_type = SOCK_STREAM,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL: UDS SOCK_DGRAM not supported",
.me_domain = PF_UNIX,
.me_type = SOCK_DGRAM,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL: UDS SOCK_SEQPACKET not supported",
.me_domain = PF_UNIX,
.me_type = SOCK_SEQPACKET,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL: PF_ROUTE IPv4 not supported",
.me_domain = PF_ROUTE,
.me_type = SOCK_RAW,
.me_proto = AF_INET,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL: PF_ROUTE IPv6 not supported",
.me_domain = PF_ROUTE,
.me_type = SOCK_RAW,
.me_proto = AF_INET6,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL: PF_POLICY not supported",
.me_domain = PF_POLICY,
.me_type = SOCK_RAW,
.me_proto = PF_POLICY_V1,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL: PF_KEY not supported",
.me_domain = PF_KEY,
.me_type = SOCK_RAW,
.me_proto = PF_KEY_V2,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: UDS SOCK_STREAM not supported",
.me_domain = PF_UNIX,
.me_type = SOCK_STREAM,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: UDS SOCK_DGRAM not supported",
.me_domain = PF_UNIX,
.me_type = SOCK_DGRAM,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: UDS SOCK_SEQPACKET not supported",
.me_domain = PF_UNIX,
.me_type = SOCK_SEQPACKET,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: PF_ROUTE IPv4 not supported",
.me_domain = PF_ROUTE,
.me_type = SOCK_RAW,
.me_proto = AF_INET,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: PF_ROUTE IPv6 not supported",
.me_domain = PF_ROUTE,
.me_type = SOCK_RAW,
.me_proto = AF_INET6,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: PF_POLICY not supported",
.me_domain = PF_POLICY,
.me_type = SOCK_RAW,
.me_proto = PF_POLICY_V1,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IPV6_MINHOPCOUNT: PF_KEY not supported",
.me_domain = PF_KEY,
.me_type = SOCK_RAW,
.me_proto = PF_KEY_V2,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = ENOPROTOOPT
}, {
.me_desc = "IP_MINTTL can't be set on IPv6 TCP socket",
.me_domain = PF_INET6,
.me_type = SOCK_STREAM,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = EINVAL
}, {
.me_desc = "IP_MINTTL can't be set on IPv6 UDP socket",
.me_domain = PF_INET6,
.me_type = SOCK_DGRAM,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = EINVAL
}, {
.me_desc = "IP_MINTTL can't be set on IPv6 SCTP socket",
.me_domain = PF_INET6,
.me_type = SOCK_STREAM,
.me_proto = IPPROTO_SCTP,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = EINVAL
}, {
.me_desc = "IPV6_MINHOPCOUNT can't be set on IPv4 TCP socket",
.me_domain = PF_INET,
.me_type = SOCK_STREAM,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = EINVAL
}, {
.me_desc = "IPV6_MINHOPCOUNT can't be set on IPv4 UDP socket",
.me_domain = PF_INET,
.me_type = SOCK_DGRAM,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = EINVAL
}, {
.me_desc = "IPV6_MINHOPCOUNT can't be set on IPv4 SCTP socket",
.me_domain = PF_INET,
.me_type = SOCK_STREAM,
.me_proto = IPPROTO_SCTP,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = EINVAL
}, {
.me_desc = "IP_MINTTL: negative value rejected",
.me_domain = PF_INET,
.me_type = SOCK_STREAM,
.me_value = -1,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = EINVAL
}, {
.me_desc = "IP_MINTTL: larger value rejected",
.me_domain = PF_INET,
.me_type = SOCK_STREAM,
.me_value = 256,
.me_level = IPPROTO_IP,
.me_sockopt = IP_MINTTL,
.me_errno = EINVAL
}, {
.me_desc = "IPV6_MINHOPCOUNT: negative value rejected",
.me_domain = PF_INET6,
.me_type = SOCK_STREAM,
.me_value = -1,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = EINVAL
}, {
.me_desc = "IPV6_MINHOPCOUNT: larger value rejected",
.me_domain = PF_INET6,
.me_type = SOCK_STREAM,
.me_value = 256,
.me_level = IPPROTO_IPV6,
.me_sockopt = IPV6_MINHOPCOUNT,
.me_errno = EINVAL
}
};
static bool
minttl_err_one(const minttl_err_test_t *test)
{
int sock = -1, val;
bool ret = false;
sock = socket(test->me_domain, test->me_type, test->me_proto);
if (sock < 0) {
warn("TEST FAILED: %s: failed to create socket", test->me_desc);
goto out;
}
val = test->me_value;
if (setsockopt(sock, test->me_level, test->me_sockopt, &val,
sizeof (val)) != -1) {
warnx("TEST FAILED: %s: setsockopt incorrectly passed",
test->me_desc);
} else if (errno != test->me_errno) {
int e = errno;
warnx("TEST FAILED: %s: expected errno %s, found %s",
test->me_desc, strerrorname_np(test->me_errno),
strerrorname_np(e));
} else {
(void) printf("TEST PASSED: %s\n", test->me_desc);
ret = true;
}
out:
if (sock > -1)
(void) close(sock);
return (ret);
}
int
main(void)
{
int ret = EXIT_SUCCESS;
for (size_t i = 0; i < ARRAY_SIZE(minttl_err_tests); i++) {
if (!minttl_err_one(&minttl_err_tests[i])) {
ret = EXIT_FAILURE;
}
}
if (ret == EXIT_SUCCESS) {
(void) printf("All tests completed successfully\n");
}
return (ret);
}