Commit b8abaab8 authored by Daniel Salzman's avatar Daniel Salzman

remote: remove INET socket support

parent ec172db4
......@@ -22,7 +22,6 @@
#include "knot/conf/scheme.h"
#include "knot/conf/tools.h"
#include "knot/common/log.h"
#include "knot/ctl/remote.h"
#include "knot/server/rrl.h"
#include "knot/updates/acl.h"
#include "libknot/rrtype/opt.h"
......@@ -52,7 +51,6 @@ const knot_lookup_t acl_actions[] = {
{ ACL_ACTION_NOTIFY, "notify" },
{ ACL_ACTION_TRANSFER, "transfer" },
{ ACL_ACTION_UPDATE, "update" },
{ ACL_ACTION_CONTROL, "control" },
{ 0, NULL }
};
......@@ -98,6 +96,21 @@ static const yp_item_t desc_server[] = {
{ NULL }
};
static const yp_item_t desc_control[] = {
{ C_LISTEN, YP_TSTR, YP_VSTR = { "knot.sock" } },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL }
};
static const yp_item_t desc_log[] = {
{ C_TARGET, YP_TSTR, YP_VNONE },
{ C_SERVER, YP_TOPT, YP_VOPT = { log_severities, 0 } },
{ C_ZONE, YP_TOPT, YP_VOPT = { log_severities, 0 } },
{ C_ANY, YP_TOPT, YP_VOPT = { log_severities, 0 } },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL }
};
static const yp_item_t desc_key[] = {
{ C_ID, YP_TDNAME, YP_VNONE },
{ C_ALG, YP_TOPT, YP_VOPT = { key_algs, DNSSEC_TSIG_UNKNOWN } },
......@@ -117,13 +130,6 @@ static const yp_item_t desc_acl[] = {
{ NULL }
};
static const yp_item_t desc_control[] = {
{ C_LISTEN, YP_TADDR, YP_VADDR = { REMOTE_PORT, REMOTE_SOCKET } },
{ C_ACL, YP_TREF, YP_VREF = { C_ACL }, YP_FMULTI, { check_ref } },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL }
};
static const yp_item_t desc_remote[] = {
{ C_ID, YP_TSTR, YP_VNONE },
{ C_ADDR, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI },
......@@ -169,21 +175,12 @@ static const yp_item_t desc_zone[] = {
{ NULL }
};
static const yp_item_t desc_log[] = {
{ C_TARGET, YP_TSTR, YP_VNONE },
{ C_SERVER, YP_TOPT, YP_VOPT = { log_severities, 0 } },
{ C_ZONE, YP_TOPT, YP_VOPT = { log_severities, 0 } },
{ C_ANY, YP_TOPT, YP_VOPT = { log_severities, 0 } },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL }
};
const yp_item_t conf_scheme[] = {
{ C_SRV, YP_TGRP, YP_VGRP = { desc_server } },
{ C_CTL, YP_TGRP, YP_VGRP = { desc_control } },
{ C_LOG, YP_TGRP, YP_VGRP = { desc_log }, YP_FMULTI },
{ C_KEY, YP_TGRP, YP_VGRP = { desc_key }, YP_FMULTI, { check_key } },
{ C_ACL, YP_TGRP, YP_VGRP = { desc_acl }, YP_FMULTI, { check_acl } },
{ C_CTL, YP_TGRP, YP_VGRP = { desc_control } },
{ C_RMT, YP_TGRP, YP_VGRP = { desc_remote }, YP_FMULTI, { check_remote } },
/* MODULES */
{ C_MOD_SYNTH_RECORD, YP_TGRP, YP_VGRP = { scheme_mod_synth_record }, YP_FMULTI,
......
This diff is collapsed.
......@@ -900,56 +900,32 @@ static int remote_c_conf_unset(server_t *s, remote_cmdargs_t *a)
}
}
/*!
* \brief Prepare and send error response.
* \param c Client fd.
* \param buf Query buffer.
* \param buflen Query size.
* \return number of bytes sent
*/
static int remote_senderr(int c, uint8_t *qbuf, size_t buflen)
int remote_bind(const char *path)
{
rcu_read_lock();
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval timeout = { conf_int(val), 0 };
rcu_read_unlock();
knot_wire_set_qr(qbuf);
knot_wire_set_rcode(qbuf, KNOT_RCODE_REFUSED);
return net_dns_tcp_send(c, qbuf, buflen, &timeout);
}
/* Public APIs. */
int remote_bind(struct sockaddr_storage *addr)
{
if (addr == NULL) {
if (path == NULL) {
return KNOT_EINVAL;
}
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), addr);
log_info("remote control, binding to '%s'", addr_str);
log_info("remote control, binding to '%s'", path);
/* Create new socket. */
int sock = net_bound_socket(SOCK_STREAM, addr, 0);
if (sock == KNOT_EADDRNOTAVAIL) {
sock = net_bound_socket(SOCK_STREAM, addr, NET_BIND_NONLOCAL);
if (sock >= 0) {
log_warning("remote control, address '%s' is not available",
addr_str);
}
/* Prepare socket address. */
struct sockaddr_storage addr;
int ret = sockaddr_set(&addr, AF_UNIX, path, 0);
if (ret != KNOT_EOK) {
return ret;
}
/* Create new socket. */
int sock = net_bound_socket(SOCK_STREAM, &addr, 0);
if (sock < 0) {
log_error("remote control, failed to bind to '%s' (%s)",
addr_str, knot_strerror(sock));
path, knot_strerror(sock));
return sock;
}
/* Start listening. */
if (listen(sock, TCP_BACKLOG_SIZE) != 0) {
log_error("remote control, failed to listen on '%s'", addr_str);
log_error("remote control, failed to listen on '%s'", path);
close(sock);
return knot_map_errno();
}
......@@ -957,20 +933,24 @@ int remote_bind(struct sockaddr_storage *addr)
return sock;
}
int remote_unbind(struct sockaddr_storage *addr, int sock)
void remote_unbind(int sock)
{
if (addr == NULL || sock < 0) {
return KNOT_EINVAL;
if (sock < 0) {
return;
}
/* Remove control socket file. */
if (addr->ss_family == AF_UNIX) {
/* Remove the control socket file. */
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
if (getsockname(sock, (struct sockaddr *)&addr, &addr_len) == 0) {
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), addr);
unlink(addr_str);
if (sockaddr_tostr(addr_str, sizeof(addr_str), &addr) > 0) {
(void)unlink(addr_str);
}
}
return close(sock);
/* Close the socket. */
(void)close(sock);
}
int remote_poll(int sock, const sigset_t *sigmask)
......@@ -987,20 +967,13 @@ int remote_poll(int sock, const sigset_t *sigmask)
return pselect(sock + 1, &rfds, NULL, NULL, NULL, sigmask);
}
int remote_recv(int sock, struct sockaddr_storage *addr, uint8_t *buf,
size_t *buflen)
int remote_recv(int sock, uint8_t *buf, size_t *buflen)
{
int c = tcp_accept(sock);
if (c < 0) {
return c;
}
socklen_t addrlen = sizeof(*addr);
if (getpeername(c, (struct sockaddr *)addr, &addrlen) != 0) {
close(c);
return KNOT_ECONNREFUSED;
}
/* Receive data. */
int n = net_dns_tcp_recv(c, buf, *buflen, NULL);
*buflen = n;
......@@ -1176,124 +1149,15 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt)
return ret;
}
static int zones_verify_tsig_query(const knot_pkt_t *query,
const knot_tsig_key_t *key,
uint16_t *rcode, uint16_t *tsig_rcode,
uint64_t *tsig_prev_time_signed)
{
assert(query != NULL);
assert(key != NULL);
assert(rcode != NULL);
assert(tsig_rcode != NULL);
if (query->tsig_rr == NULL) {
log_info("TSIG, key required, query REFUSED");
*rcode = KNOT_RCODE_REFUSED;
return KNOT_TSIG_EBADKEY;
}
/*
* 1) Check if we support the requested algorithm.
*/
dnssec_tsig_algorithm_t alg = knot_tsig_rdata_alg(query->tsig_rr);
if (alg == DNSSEC_TSIG_UNKNOWN) {
log_info("TSIG, unsupported algorithm, query NOTAUTH");
/*! \todo [TSIG] It is unclear from RFC if I
* should treat is as a bad key
* or some other error.
*/
*rcode = KNOT_RCODE_NOTAUTH;
*tsig_rcode = KNOT_TSIG_ERR_BADKEY;
return KNOT_TSIG_EBADKEY;
}
const knot_dname_t *kname = query->tsig_rr->owner;
assert(kname != NULL);
/*
* 2) Find the particular key used by the TSIG.
* Check not only name, but also the algorithm.
*/
if (!(key && kname && knot_dname_cmp(key->name, kname) == 0 &&
key->algorithm == alg)) {
*rcode = KNOT_RCODE_NOTAUTH;
*tsig_rcode = KNOT_TSIG_ERR_BADKEY;
return KNOT_TSIG_EBADKEY;
}
/*
* 3) Validate the query with TSIG.
*/
/* Prepare variables for TSIG */
/*! \todo These need to be saved to the response somehow. */
//size_t tsig_size = tsig_wire_maxsize(key);
size_t digest_max_size = dnssec_tsig_algorithm_size(alg);
//size_t digest_size = 0;
//uint64_t tsig_prev_time_signed = 0;
//uint8_t *digest = (uint8_t *)malloc(digest_max_size);
//memset(digest, 0 , digest_max_size);
//const uint8_t* mac = tsig_rdata_mac(tsig_rr);
size_t mac_len = knot_tsig_rdata_mac_length(query->tsig_rr);
int ret = KNOT_EOK;
if (mac_len > digest_max_size) {
*rcode = KNOT_RCODE_FORMERR;
log_info("TSIG, MAC length %zu exceeds maximum size %zu",
mac_len, digest_max_size);
return KNOT_EMALF;
} else {
//memcpy(digest, mac, mac_len);
//digest_size = mac_len;
/* Check query TSIG. */
ret = knot_tsig_server_check(query->tsig_rr,
query->wire,
query->size, key);
switch(ret) {
case KNOT_EOK:
*rcode = KNOT_RCODE_NOERROR;
break;
case KNOT_TSIG_EBADKEY:
*tsig_rcode = KNOT_TSIG_ERR_BADKEY;
*rcode = KNOT_RCODE_NOTAUTH;
break;
case KNOT_TSIG_EBADSIG:
*tsig_rcode = KNOT_TSIG_ERR_BADSIG;
*rcode = KNOT_RCODE_NOTAUTH;
break;
case KNOT_TSIG_EBADTIME:
*tsig_rcode = KNOT_TSIG_ERR_BADTIME;
// store the time signed from the query
*tsig_prev_time_signed = knot_tsig_rdata_time_signed(query->tsig_rr);
*rcode = KNOT_RCODE_NOTAUTH;
break;
case KNOT_EMALF:
*rcode = KNOT_RCODE_FORMERR;
break;
default:
*rcode = KNOT_RCODE_SERVFAIL;
}
}
return ret;
}
int remote_process(server_t *s, struct sockaddr_storage *ctl_addr, int sock,
uint8_t *buf, size_t buflen)
int remote_process(server_t *server, int sock, uint8_t *buf, size_t buflen)
{
knot_pkt_t *pkt = knot_pkt_new(buf, buflen, NULL);
if (pkt == NULL) {
return KNOT_ENOMEM;
}
/* Initialize remote party address. */
struct sockaddr_storage ss;
memset(&ss, 0, sizeof(struct sockaddr_storage));
/* Accept incoming connection and read packet. */
int client = remote_recv(sock, &ss, pkt->wire, &buflen);
int client = remote_recv(sock, pkt->wire, &buflen);
if (client < 0) {
knot_pkt_free(&pkt);
return client;
......@@ -1303,62 +1167,16 @@ int remote_process(server_t *s, struct sockaddr_storage *ctl_addr, int sock,
/* Parse packet and answer if OK. */
int ret = remote_parse(pkt);
if (ret == KNOT_EOK && ctl_addr->ss_family != AF_UNIX) {
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), &ss);
/* Prepare tsig parameters. */
knot_tsig_key_t tsig = { 0 };
if (pkt->tsig_rr) {
tsig.name = pkt->tsig_rr->owner;
tsig.algorithm = knot_tsig_rdata_alg(pkt->tsig_rr);
}
/* Check ACL. */
rcu_read_lock();
conf_val_t acl = conf_get(conf(), C_CTL, C_ACL);
bool allowed = acl_allowed(&acl, ACL_ACTION_CONTROL, &ss, &tsig);
rcu_read_unlock();
if (!allowed) {
log_warning("remote control, ACL, denied, remote '%s', "
"no matching ACL", addr_str);
remote_senderr(client, pkt->wire, pkt->size);
ret = KNOT_EACCES;
goto finish;
}
/* Check TSIG. */
if (tsig.name != NULL) {
uint16_t ts_rc = 0;
uint16_t ts_trc = 0;
uint64_t ts_tmsigned = 0;
ret = zones_verify_tsig_query(pkt, &tsig, &ts_rc,
&ts_trc, &ts_tmsigned);
if (ret != KNOT_EOK) {
log_warning("remote control, ACL, denied, "
"remote '%s', key verification (%s)",
addr_str, knot_strerror(ret));
remote_senderr(client, pkt->wire, pkt->size);
ret = KNOT_EACCES;
goto finish;
}
}
}
/* Answer packet. */
if (ret == KNOT_EOK) {
ret = remote_answer(client, s, pkt);
ret = remote_answer(client, server, pkt);
}
finish:
knot_pkt_free(&pkt);
close(client);
return ret;
}
knot_pkt_t* remote_query(const char *query, const knot_tsig_key_t *key)
knot_pkt_t* remote_query(const char *query)
{
if (!query) {
return NULL;
......@@ -1370,7 +1188,6 @@ knot_pkt_t* remote_query(const char *query, const knot_tsig_key_t *key)
}
knot_wire_set_id(pkt->wire, dnssec_random_uint16_t());
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(key));
/* Question section. */
char *qname = strcdup(query, KNOT_CTL_REALM_EXT);
......@@ -1392,26 +1209,6 @@ knot_pkt_t* remote_query(const char *query, const knot_tsig_key_t *key)
return pkt;
}
int remote_query_sign(uint8_t *wire, size_t *size, size_t maxlen,
const knot_tsig_key_t *key)
{
if (!wire || !size || !key) {
return KNOT_EINVAL;
}
size_t dlen = dnssec_tsig_algorithm_size(key->algorithm);
uint8_t *digest = malloc(dlen);
if (!digest) {
return KNOT_ENOMEM;
}
int ret = knot_tsig_sign(wire, size, maxlen, NULL, 0, digest, &dlen,
key, 0, 0);
free(digest);
return ret;
}
int remote_build_rr(knot_rrset_t *rr, const char *owner, uint16_t type)
{
if (!rr || !owner) {
......
......@@ -29,32 +29,24 @@
#include "libknot/libknot.h"
#include "knot/server/server.h"
/*! \brief Default connection control parameters. */
#define REMOTE_PORT 5533
#define REMOTE_SOCKET "knot.sock"
/*!
* \brief Bind RC interface.
*
* \param addr Interface descriptor (address, port).
* \param path Control UNIX socket path.
*
* \retval socket if passed.
* \retval knot_error else.
*/
int remote_bind(struct sockaddr_storage *addr);
int remote_bind(const char *path);
/*!
* \brief Unbind from RC interface and close socket.
*
* \note Breaks all pending connections.
*
* \param addr Interface descriptor (address, port).
* \param socket Interface socket
*
* \retval KNOT_EOK on success.
* \retval knot_error else.
* \param socket Interface socket.
*/
int remote_unbind(struct sockaddr_storage *addr, int sock);
void remote_unbind(int sock);
/*!
* \brief Poll new events on RC socket.
......@@ -70,15 +62,13 @@ int remote_poll(int sock, const sigset_t *sigmask);
* \brief Start a RC connection with remote.
*
* \param r RC interface socket.
* \param a Destination for remote party address (or NULL if not interested).
* \param buf Buffer for RC command.
* \param buflen Maximum buffer size.
*
* \return client TCP socket if success.
* \return KNOT_ECONNREFUSED if fails to receive command.
*/
int remote_recv(int sock, struct sockaddr_storage *addr, uint8_t *buf,
size_t *buflen);
int remote_recv(int sock, uint8_t *buf, size_t *buflen);
/*!
* \brief Parse a RC command.
......@@ -109,8 +99,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt);
*
* \note This should be used as a high-level API for workers.
*
* \param s Server instance.
* \param ctl_addr Control interface address.
* \param server Server instance.
* \param sock RC interface socket.
* \param buf Buffer for commands/responses.
* \param buflen Maximum buffer size.
......@@ -118,37 +107,19 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt);
* \retval KNOT_EOK on success.
* \retval knot_error else.
*/
int remote_process(server_t *s, struct sockaddr_storage *ctl_addr, int sock,
uint8_t *buf, size_t buflen);
int remote_process(server_t *server, int sock, uint8_t *buf, size_t buflen);
/* Functions for creating RC packets. */
/*!
* \brief Build a RC command packet, TSIG key is optional.
*
* \note This doesn't sign packet, see remote_query_sign().
* \brief Build a RC command packet.
*
* \param query Command name, f.e. 'reload'.
* \param key TSIG key for space reservation (or NULL).
*
* \retval KNOT_EOK on success.
* \retval knot_error else.
*/
knot_pkt_t* remote_query(const char *query, const knot_tsig_key_t *key);
/*!
* \brief Sign a RC command packet using TSIG key.
*
* \param wire RC packet in wire format.
* \param size RC packet size.
* \param maxlen Maximum buffer size.
* \param key TSIG key.
*
* \retval KNOT_EOK on success.
* \retval knot_error else.
*/
int remote_query_sign(uint8_t *wire, size_t *size, size_t maxlen,
const knot_tsig_key_t *key);
knot_pkt_t* remote_query(const char *query);
/*!
* \brief Initialize a rrset with the given name and type.
......
......@@ -203,22 +203,23 @@ static void event_loop(server_t *server)
conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR);
char *rundir = conf_abs_path(&rundir_val, NULL);
struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
char *listen = conf_abs_path(&listen_val, rundir);
free(rundir);
/* Bind to control interface (error logging is inside the function. */
int remote = remote_bind(&addr);
/* Bind to control socket (error logging is inside the function. */
int sock = remote_bind(listen);
free(listen);
sigset_t empty;
(void)sigemptyset(&empty);
/* Run event loop. */
for (;;) {
int ret = remote_poll(remote, &empty);
int ret = remote_poll(sock, &empty);
/* Events. */
if (ret > 0) {
ret = remote_process(server, &addr, remote, buf, buflen);
ret = remote_process(server, sock, buf, buflen);
if (ret == KNOT_CTL_STOP) {
break;
}
......@@ -234,8 +235,8 @@ static void event_loop(server_t *server)
}
}
/* Close remote control interface. */
remote_unbind(&addr, remote);
/* Close control socket. */
remote_unbind(sock);
}
static void print_help(void)
......
......@@ -36,8 +36,7 @@ typedef enum {
ACL_ACTION_NONE = 0,
ACL_ACTION_NOTIFY = 1,
ACL_ACTION_TRANSFER = 2,
ACL_ACTION_UPDATE = 3,
ACL_ACTION_CONTROL = 4
ACL_ACTION_UPDATE = 3
} acl_action_t;
/*!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment