diff --git a/src/core/capsicum.c b/src/core/capsicum.c index a0375077..99f7ff0f 100644 --- a/src/core/capsicum.c +++ b/src/core/capsicum.c @@ -31,6 +31,9 @@ #include #include +#define OPCODE_CONNECT 1 +#define OPCODE_GETHOSTBYNAME 2 + static int symbiontfds[2]; gboolean capsicum_enabled(void) @@ -55,6 +58,7 @@ int capsicum_net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) /* Send request to the symbiont. */ nvl = nvlist_create(0); + nvlist_add_number(nvl, "opcode", OPCODE_CONNECT); nvlist_add_binary(nvl, "ip", ip, sizeof(*ip)); nvlist_add_number(nvl, "port", port); if (my_ip != NULL) { @@ -86,12 +90,139 @@ int capsicum_net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) return sock; } +int capsicum_net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) +{ + nvlist_t *nvl; + IPADDR *received_ip4, *received_ip6; + int error, ret, saved_errno; + + /* Send request to the symbiont. */ + nvl = nvlist_create(0); + nvlist_add_number(nvl, "opcode", OPCODE_GETHOSTBYNAME); + nvlist_add_string(nvl, "addr", addr); + error = nvlist_send(symbiontfds[1], nvl); + nvlist_destroy(nvl); + if (error != 0) { + g_warning("nvlist_send: %s", strerror(errno)); + return -1; + } + + /* Receive response. */ + nvl = nvlist_recv(symbiontfds[1], 0); + if (nvl == NULL) { + g_warning("nvlist_recv: %s", strerror(errno)); + return -1; + } + + received_ip4 = nvlist_get_binary(nvl, "ip4", NULL); + received_ip6 = nvlist_get_binary(nvl, "ip6", NULL); + memcpy(ip4, received_ip4, sizeof(*ip4)); + memcpy(ip6, received_ip6, sizeof(*ip6)); + + ret = nvlist_get_number(nvl, "ret"); + saved_errno = nvlist_get_number(nvl, "errno"); + nvlist_destroy(nvl); + errno = saved_errno; + + return ret; +} + +nvlist_t *symbiont_connect(const nvlist_t *request) +{ + nvlist_t *response; + IPADDR *ip, *my_ip; + int port, saved_errno, sock; + + ip = nvlist_get_binary(request, "ip", NULL); + port = (int)nvlist_get_number(request, "port"); + if (nvlist_exists(request, "my_ip")) + my_ip = nvlist_get_binary(request, "my_ip", NULL); + else + my_ip = NULL; + + /* Connect. */ + sock = net_connect_ip_handle(ip, port, my_ip); + saved_errno = errno; + + /* Send back the socket fd. */ + response = nvlist_create(0); + + if (sock != -1) + nvlist_move_descriptor(response, "sock", sock); + nvlist_add_number(response, "errno", saved_errno); + + return (response); +} + +nvlist_t *symbiont_gethostbyname(const nvlist_t *request) +{ + nvlist_t *response; + IPADDR ip4, ip6; + const char *addr; + int ret, saved_errno; + + addr = nvlist_get_string(request, "addr"); + + /* Connect. */ + ret = net_gethostbyname(addr, &ip4, &ip6); + saved_errno = errno; + + /* Send back the IPs. */ + response = nvlist_create(0); + + nvlist_add_number(response, "ret", ret); + nvlist_add_number(response, "errno", saved_errno); + nvlist_add_binary(response, "ip4", &ip4, sizeof(ip4)); + nvlist_add_binary(response, "ip6", &ip6, sizeof(ip6)); + + return (response); +} + +/* + * Child process, running outside the Capsicum sandbox. + */ +_Noreturn static void symbiont(void) +{ + nvlist_t *request, *response; + int error, opcode; + + setproctitle("capsicum symbiont"); + close(symbiontfds[1]); + close(0); + close(1); + close(2); + + for (;;) { + /* Receive parameters from the main irssi process. */ + request = nvlist_recv(symbiontfds[0], 0); + if (request == NULL) + exit(1); + + opcode = nvlist_get_number(request, "opcode"); + switch (opcode) { + case OPCODE_CONNECT: + response = symbiont_connect(request); + break; + case OPCODE_GETHOSTBYNAME: + response = symbiont_gethostbyname(request); + break; + default: + exit(1); + } + + /* Send back the response. */ + error = nvlist_send(symbiontfds[0], response); + if (error != 0) + exit(1); + nvlist_destroy(request); + nvlist_destroy(response); + } +} + static int start_symbiont(void) { + int childfd, error; pid_t pid; - nvlist_t *nvl; - IPADDR *ip, *my_ip; - int childfd, error, port, saved_errno, sock; error = socketpair(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, symbiontfds); if (error != 0) { @@ -110,40 +241,8 @@ static int start_symbiont(void) return 0; } - /* We're the child, running outside the Capsicum sandbox. */ - setproctitle("capsicum symbiont"); - close(symbiontfds[1]); - close(0); - close(1); - close(2); - for (;;) { - /* Receive parameters from the main irssi process. */ - nvl = nvlist_recv(symbiontfds[0], 0); - if (nvl == NULL) - exit(1); - ip = nvlist_get_binary(nvl, "ip", NULL); - port = (int)nvlist_get_number(nvl, "port"); - if (nvlist_exists(nvl, "my_ip")) - my_ip = nvlist_get_binary(nvl, "my_ip", NULL); - else - my_ip = NULL; - - /* Connect. */ - sock = net_connect_ip_handle(ip, port, my_ip); - saved_errno = errno; - - /* Send back the socket fd. */ - nvlist_destroy(nvl); - nvl = nvlist_create(0); - - if (sock != -1) - nvlist_move_descriptor(nvl, "sock", sock); - nvlist_add_number(nvl, "errno", saved_errno); - error = nvlist_send(symbiontfds[0], nvl); - if (error != 0) - exit(1); - nvlist_destroy(nvl); - } + symbiont(); + /* NOTREACHED */ } static void cmd_capsicum(const char *data, SERVER_REC *server, void *item) diff --git a/src/core/capsicum.h b/src/core/capsicum.h index f8cec28e..2733c1ea 100644 --- a/src/core/capsicum.h +++ b/src/core/capsicum.h @@ -3,6 +3,7 @@ gboolean capsicum_enabled(void); int capsicum_net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip); +int capsicum_net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6); void capsicum_init(void); void capsicum_deinit(void); diff --git a/src/core/network.c b/src/core/network.c index b182d19f..2954af54 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -406,6 +406,11 @@ int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) struct addrinfo hints, *ai, *ailist; int ret, count_v4, count_v6, use_v4, use_v6; +#ifdef HAVE_CAPSICUM + if (capsicum_enabled()) + return (capsicum_net_gethostbyname(addr, ip4, ip6)); +#endif + g_return_val_if_fail(addr != NULL, -1); memset(ip4, 0, sizeof(IPADDR));