There's no support for the "dns" and "tls" kinds (for now).
Tested briefly:
> modules = { 'http' }
> net.listen('/tmp/kresd-socket', nil, { kind = 'webmgmt' })
$ socat TCP-LISTEN:5555,reuseaddr,fork UNIX-CLIENT:/tmp/kresd-socket
$ xdg-open http://127.0.0.1:5555
Improvements
------------
- DNS-over-HTTPS: answers include `access-control-allow-origin: *` (!823)
+- support named AF_UNIX stream sockets for the http module (again)
Bugfixes
--------
#ifdef TCP_DEFER_ACCEPT
val = KR_CONN_RTT_MAX/1000;
if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val))) {
- kr_log_error("[ io ] tcp_bind (defer_accept): %s\n", strerror(errno));
+ kr_log_error("[ io ] listen TCP (defer_accept): %s\n", strerror(errno));
}
#endif
val = 1; /* Accepts on/off */
#endif
if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &val, sizeof(val))) {
- kr_log_error("[ io ] tcp_bind (fastopen): %s\n", strerror(errno));
+ kr_log_error("[ io ] listen TCP (fastopen): %s\n", strerror(errno));
}
#endif
}
/** Just convert addresses to file-descriptors; clear *addrs on success.
+ * @note AF_UNIX is supported (starting with '/').
* @return zero or exit code for main()
*/
static int bind_sockets(addr_array_t *addrs, bool tls, flagged_fd_array_t *fds)
{
+ bool has_error = false;
for (size_t i = 0; i < addrs->len; ++i) {
+ /* Get port and separate address string. */
uint16_t port = tls ? KR_DNS_TLS_PORT : KR_DNS_PORT;
- char addr_str[INET6_ADDRSTRLEN + 1];
- int ret = kr_straddr_split(addrs->at[i], addr_str, &port);
+ char addr_buf[INET6_ADDRSTRLEN + 1];
+ int ret;
+ const char *addr_str;
+ const int family = kr_straddr_family(addrs->at[i]);
+ if (family == AF_UNIX) {
+ ret = 0;
+ addr_str = addrs->at[i];
+ } else { /* internet socket (or garbage) */
+ ret = kr_straddr_split(addrs->at[i], addr_buf, &port);
+ addr_str = addr_buf;
+ }
+ /* Get sockaddr. */
struct sockaddr *sa = NULL;
if (ret == 0) {
sa = kr_straddr_socket(addr_str, port, NULL);
if (!sa) ret = kr_error(EINVAL); /* could be ENOMEM but unlikely */
}
flagged_fd_t ffd = { .flags = { .tls = tls } };
- if (ret == 0 && !tls) {
+ if (ret == 0 && !tls && family != AF_UNIX) {
+ /* AF_UNIX can do SOCK_DGRAM, but let's not support that *here*. */
ffd.fd = io_bind(sa, SOCK_DGRAM);
if (ffd.fd < 0)
ret = ffd.fd;
else if (array_push(*fds, ffd) < 0)
ret = kr_error(ENOMEM);
}
- if (ret == 0) { /* common for TCP and TLS */
+ if (ret == 0) { /* common for TCP and TLS, including AF_UNIX cases */
ffd.fd = io_bind(sa, SOCK_STREAM);
if (ffd.fd < 0)
ret = ffd.fd;
}
free(sa);
if (ret != 0) {
- kr_log_error("[system] bind to '%s' %s%s\n",
- addrs->at[i], tls ? "(TLS) " : "", kr_strerror(ret));
- return EXIT_FAILURE;
+ kr_log_error("[system] bind to '%s'%s: %s\n",
+ addrs->at[i], tls ? " (TLS)" : "", kr_strerror(ret));
+ has_error = true;
}
}
array_clear(*addrs);
- return kr_ok();
+ return has_error ? EXIT_FAILURE : kr_ok();
}
static int start_listening(struct network *net, flagged_fd_array_t *fds) {
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#include <unistd.h>
-#include <assert.h>
-#include "daemon/bindings/impl.h"
#include "daemon/network.h"
-#include "daemon/worker.h"
+
+#include "daemon/bindings/impl.h"
#include "daemon/io.h"
#include "daemon/tls.h"
+#include "daemon/worker.h"
+
+#include <assert.h>
+#include <sys/un.h>
+#include <unistd.h>
void network_init(struct network *net, uv_loop_t *loop, int tcp_backlog)
{
static void endpoint_close(struct network *net, struct endpoint *ep, bool force)
{
assert(!ep->handle != !ep->flags.kind);
+ if (ep->family == AF_UNIX) { /* The FS name would be left behind. */
+ /* Extract local address for this socket. */
+ struct sockaddr_un sa;
+ sa.sun_path[0] = '\0'; /*< probably only for lint:scan-build */
+ socklen_t addr_len = sizeof(sa);
+ if (getsockname(ep->fd, (struct sockaddr *)&sa, &addr_len)
+ || unlink(sa.sun_path)) {
+ kr_log_error("error (ignored) when closing unix socket (fd = %d): %s\n",
+ ep->fd, strerror(errno));
+ return;
+ }
+ }
+
if (ep->flags.kind) { /* Special endpoint. */
if (ep->engaged) {
endpoint_close_lua_cb(net, ep);
/* .engaged seems not really meaningful with .kind == NULL, but... */
}
+ if (ep->family == AF_UNIX) {
+ /* Some parts of connection handling would need more work,
+ * so let's support AF_UNIX only with .kind != NULL for now. */
+ kr_log_error("[system] AF_UNIX only supported with set { kind = '...' }\n");
+ return kr_error(EAFNOSUPPORT);
+ /*
+ uv_pipe_t *ep_handle = malloc(sizeof(uv_pipe_t));
+ */
+ }
+
if (ep->flags.sock_type == SOCK_DGRAM) {
if (ep->flags.tls) {
assert(!EINVAL);
static int create_endpoint(struct network *net, const char *addr_str,
struct endpoint *ep, const struct sockaddr *sa)
{
- /* Bind interfaces */
int ret = open_endpoint(net, ep, sa, addr_str);
if (ret == 0) {
ret = insert_endpoint(net, addr_str, ep);
.fd = fd,
};
/* Extract address string and port. */
- char addr_str[INET6_ADDRSTRLEN]; /* https://tools.ietf.org/html/rfc4291 */
- if (ss.ss_family == AF_INET) {
- uv_ip4_name((const struct sockaddr_in*)&ss, addr_str, sizeof(addr_str));
+ char addr_buf[INET6_ADDRSTRLEN]; /* https://tools.ietf.org/html/rfc4291 */
+ const char *addr_str;
+ switch (ep.family) {
+ case AF_INET:
+ ret = uv_ip4_name((const struct sockaddr_in*)&ss, addr_buf, sizeof(addr_buf));
+ addr_str = addr_buf;
ep.port = ntohs(((struct sockaddr_in *)&ss)->sin_port);
- } else if (ss.ss_family == AF_INET6) {
- uv_ip6_name((const struct sockaddr_in6*)&ss, addr_str, sizeof(addr_str));
+ break;
+ case AF_INET6:
+ ret = uv_ip6_name((const struct sockaddr_in6*)&ss, addr_buf, sizeof(addr_buf));
+ addr_str = addr_buf;
ep.port = ntohs(((struct sockaddr_in6 *)&ss)->sin6_port);
- } else {
- return kr_error(EAFNOSUPPORT);
+ break;
+ case AF_UNIX:
+ /* No SOCK_DGRAM with AF_UNIX support, at least for now. */
+ ret = flags.sock_type == SOCK_STREAM ? kr_ok() : kr_error(EAFNOSUPPORT);
+ addr_str = ((struct sockaddr_un *)&ss)->sun_path;
+ break;
+ default:
+ ret = kr_error(EAFNOSUPPORT);
}
+ if (ret) return ret;
/* always create endpoint for supervisor supplied fd
* even if addr+port is not unique */
}
/* Parse address. */
- int ret = 0;
- union inaddr sa;
- if (strchr(addr, ':') != NULL) {
- ret = uv_ip6_addr(addr, port, &sa.ip6);
- } else {
- ret = uv_ip4_addr(addr, port, &sa.ip4);
- }
- if (ret != 0) {
- return ret;
+ const struct sockaddr *sa = kr_straddr_socket(addr, port, NULL);
+ if (!sa) {
+ return kr_error(EINVAL);
}
struct endpoint ep = {
.flags = flags,
.fd = -1,
.port = port,
- .family = sa.ip.sa_family,
+ .family = sa->sa_family,
};
- return create_endpoint(net, addr, &ep, &sa.ip);
+ int ret = create_endpoint(net, addr, &ep, sa);
+ free_const(sa);
+ return ret;
}
int network_close(struct network *net, const char *addr, int port)
* There are two types: normal have handle, special have flags.kind (and never both).
*
* LATER: .family might be unexpected for IPv4-in-IPv6 addresses.
+ * ATM AF_UNIX is only supported with flags.kind != NULL
*/
struct endpoint {
uv_handle_t *handle; /**< uv_udp_t or uv_tcp_t; NULL in case flags.kind != NULL */
int fd; /**< POSIX file-descriptor; always used. */
- int family; /**< AF_INET or AF_INET6 or (in future) AF_UNIX */
+ int family; /**< AF_INET or AF_INET6 or AF_UNIX */
uint16_t port; /**< TCP/UDP port. Meaningless with AF_UNIX. */
bool engaged; /**< to some module or internally */
endpoint_flags_t flags;
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <arpa/inet.h>
-#include <sys/time.h>
-#include <contrib/cleanup.h>
-#include <contrib/ccan/asprintf/asprintf.h>
-#include <ucw/mempool.h>
-#include <gnutls/gnutls.h>
-#include <libknot/descriptor.h>
-#include <libknot/dname.h>
-#include <libknot/rrtype/rrsig.h>
-#include <libknot/rrset-dump.h>
-#include <libknot/version.h>
-#include <uv.h>
+#include "lib/utils.h"
+#include "contrib/ccan/asprintf/asprintf.h"
+#include "contrib/cleanup.h"
+#include "contrib/ucw/mempool.h"
#include "kresconfig.h"
#include "lib/defines.h"
-#include "lib/utils.h"
#include "lib/generic/array.h"
-#include "lib/nsrep.h"
#include "lib/module.h"
+#include "lib/nsrep.h"
#include "lib/resolve.h"
+#include <gnutls/gnutls.h>
+#include <libknot/descriptor.h>
+#include <libknot/dname.h>
+#include <libknot/rrset-dump.h>
+#include <libknot/rrtype/rrsig.h>
+#include <libknot/version.h>
+#include <uv.h>
+
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/un.h>
/* Always compile-in log symbols, even if disabled. */
#undef kr_verbose_status
switch (addr->sa_family) {
case AF_INET: return sizeof(struct sockaddr_in);
case AF_INET6: return sizeof(struct sockaddr_in6);
+ case AF_UNIX: return sizeof(struct sockaddr_un);
default: return kr_error(EINVAL);
}
}
if (!addr) {
return kr_error(EINVAL);
}
+ if (addr[0] == '/') {
+ return AF_UNIX;
+ }
if (strchr(addr, ':')) {
return AF_INET6;
}
return NULL;
}
}
+ case AF_UNIX: {
+ struct sockaddr_un *res;
+ const size_t alen = strlen(addr) + 1;
+ if (alen > sizeof(res->sun_path)) {
+ return NULL;
+ }
+ res = mm_alloc(pool, sizeof(*res));
+ res->sun_family = AF_UNIX;
+ memcpy(res->sun_path, addr, alen);
+ return (struct sockaddr *)res;
+ }
default:
assert(!EINVAL);
return NULL;
KR_EXPORT KR_CONST
int kr_family_len(int family);
-/** Create a sockaddr* from string+port representation (also accepts IPv6 link-local). */
+/** Create a sockaddr* from string+port representation.
+ * Also accepts IPv6 link-local and AF_UNIX starting with "/" (ignoring port) */
KR_EXPORT
struct sockaddr * kr_straddr_socket(const char *addr, int port, knot_mm_t *pool);
* \param port[out] written in case it's specified in instr
* \return error code
* \note Typically you follow this by kr_straddr_socket().
+ * \note Only internet addresses are supported, i.e. no AF_UNIX sockets.
*/
KR_EXPORT
int kr_straddr_split(const char *instr, char ipaddr[static restrict (INET6_ADDRSTRLEN + 1)],