From e5c4279d1bafffc1a0ca6d24943c195eeb1a5bb1 Mon Sep 17 00:00:00 2001 From: Marek Vavrusa <marek.vavrusa@nic.cz> Date: Fri, 31 Aug 2012 14:11:44 +0200 Subject: [PATCH] Working remote control configuration and reading from socket. refs #2035 --- src/knot/conf/cf-lex.l | 4 +++ src/knot/conf/cf-parse.y | 52 +++++++++++++++++++++------ src/knot/ctl/remote.c | 77 ++++++++++++++++++++++++++++++++++++++++ src/knot/ctl/remote.h | 43 ++++++++++++++++++++++ src/knot/main.c | 16 +++++++-- 5 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 src/knot/ctl/remote.c create mode 100644 src/knot/ctl/remote.h diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l index 58d1f4b961..caf07828f1 100644 --- a/src/knot/conf/cf-lex.l +++ b/src/knot/conf/cf-lex.l @@ -97,6 +97,10 @@ address { lval.t = yytext; return ADDRESS; } port { lval.t = yytext; return PORT; } via { lval.t = yytext; return VIA; } +control { lval.t = yytext; return CONTROL; } +allow { lval.t = yytext; return ALLOW; } +listen-on { lval.t = yytext; return LISTEN_ON; } + log { lval.t = yytext; return LOG; } any { lval.t = yytext; lval.i = LOG_ANY; return LOG_SRC; } diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index 69a5415350..7a54f54207 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -28,7 +28,7 @@ static conf_log_t *this_log = 0; static conf_log_map_t *this_logmap = 0; //#define YYERROR_VERBOSE 1 -static void conf_start_iface(void *scanner, char* ifname) +static void conf_init_iface(void *scanner, char* ifname) { this_iface = malloc(sizeof(conf_iface_t)); if (this_iface == NULL) { @@ -38,6 +38,11 @@ static void conf_start_iface(void *scanner, char* ifname) memset(this_iface, 0, sizeof(conf_iface_t)); this_iface->name = ifname; this_iface->port = CONFIG_DEFAULT_PORT; +} + +static void conf_start_iface(void *scanner, char* ifname) +{ + conf_init_iface(scanner, ifname); add_tail(&new_config->ifaces, &this_iface->n); ++new_config->ifaces_count; } @@ -49,7 +54,8 @@ static void conf_start_remote(void *scanner, char *remote) cf_error(scanner, "not enough memory when allocating remote"); return; } - memset(this_remote, 0, sizeof(conf_iface_t)); + +memset(this_remote, 0, sizeof(conf_iface_t)); this_remote->name = remote; add_tail(&new_config->remotes, &this_remote->n); sockaddr_init(&this_remote->via, -1); @@ -274,6 +280,8 @@ static int conf_mask(void* scanner, int nval, int prefixlen) { %token <tok> IPA6 %token <tok> VIA +%token <tok> CONTROL ALLOW LISTEN_ON + %token <tok> LOG %token <tok> LOG_DEST %token <tok> LOG_SRC @@ -294,10 +302,10 @@ interface_start: | LOG_SRC { conf_start_iface(scanner, strdup($1.t)); } | LOG { conf_start_iface(scanner, strdup($1.t)); } | LOG_LEVEL { conf_start_iface(scanner, strdup($1.t)); } + | CONTROL { conf_start_iface(scanner, strdup($1.t)); } ; interface: - interface_start '{' | interface PORT NUM ';' { if (this_iface->port != CONFIG_DEFAULT_PORT) { cf_error(scanner, "only one port definition is allowed in interface section\n"); @@ -351,7 +359,7 @@ interface: interfaces: INTERFACES '{' - | interfaces interface '}' { + | interfaces interface_start '{' interface '}' { if (this_iface->address == 0) { char buf[512]; snprintf(buf, sizeof(buf), "interface '%s' has no defined address", this_iface->name); @@ -463,10 +471,10 @@ remote_start: | LOG_SRC { conf_start_remote(scanner, strdup($1.t)); } | LOG { conf_start_remote(scanner, strdup($1.t)); } | LOG_LEVEL { conf_start_remote(scanner, strdup($1.t)); } + | CONTROL { conf_start_remote(scanner, strdup($1.t)); } ; remote: - remote_start '{' | remote PORT NUM ';' { if (this_remote->port != 0) { cf_error(scanner, "only one port definition is allowed in remote section\n"); @@ -562,7 +570,7 @@ remote: remotes: REMOTES '{' - | remotes remote '}' { + | remotes remote_start '{' remote '}' { if (this_remote->address == 0) { char buf[512]; snprintf(buf, sizeof(buf), "remote '%s' has no defined address", this_remote->name); @@ -591,16 +599,15 @@ zone_acl_item: | LOG_SRC { conf_acl_item(scanner, strdup($1.t)); } | LOG { conf_acl_item(scanner, strdup($1.t)); } | LOG_LEVEL { conf_acl_item(scanner, strdup($1.t)); } + | CONTROL { conf_acl_item(scanner, strdup($1.t)); } ; zone_acl_list: - zone_acl_start | zone_acl_list zone_acl_item ',' | zone_acl_list zone_acl_item ';' ; zone_acl: - zone_acl_start '{' | zone_acl TEXT ';' { /* Find existing node in remotes. */ node* r = 0; conf_iface_t* found = 0; @@ -637,6 +644,7 @@ zone_start: | LOG_SRC { conf_zone_start(scanner, strdup($1.t)); } | LOG { conf_zone_start(scanner, strdup($1.t)); } | LOG_LEVEL { conf_zone_start(scanner, strdup($1.t)); } + | CONTROL { conf_zone_start(scanner, strdup($1.t)); } | NUM '/' TEXT { if ($1.i < 0 || $1.i > 255) { char buf[256] = ""; @@ -661,8 +669,8 @@ zone_start: zone: zone_start '{' - | zone zone_acl '}' - | zone zone_acl_list + | zone zone_acl_start '{' zone_acl '}' + | zone zone_acl_start zone_acl_list | zone FILENAME TEXT ';' { this_zone->file = $3.t; } | zone BUILD_DIFFS BOOL ';' { this_zone->build_diffs = $3.i; } | zone SEMANTIC_CHECKS BOOL ';' { this_zone->enable_checks = $3.i; } @@ -801,8 +809,30 @@ log_start: log: LOG '{' log_start log_end; +ctl_listen_start: + LISTEN_ON { conf_init_iface(scanner, NULL); } + ; + +ctl_allow_start: + ALLOW { + this_list = &new_config->ctl.allow; + } + ; + +control: + CONTROL '{' + | control ctl_listen_start '{' interface '}' { + if (this_iface->address == 0) { + cf_error(scanner, "control interface has no defined address"); + } else { + new_config->ctl.iface = this_iface; + } + } + | control ctl_allow_start '{' zone_acl '}' + | control ctl_allow_start zone_acl_list + ; -conf: ';' | system '}' | interfaces '}' | keys '}' | remotes '}' | zones '}' | log '}'; +conf: ';' | system '}' | interfaces '}' | keys '}' | remotes '}' | zones '}' | log '}' | control '}'; %% diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c new file mode 100644 index 0000000000..e0e2ccf156 --- /dev/null +++ b/src/knot/ctl/remote.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "remote.h" +#include "common/log.h" +#include "common/fdset.h" +#include "knot/conf/conf.h" +#include "knot/other/error.h" +#include "knot/server/socket.h" +#include "knot/server/tcp-handler.h" + +int remote_bind(conf_iface_t *desc) +{ + if (desc == NULL) { + return -1; + } + + /* Create new socket. */ + int s = socket_create(desc->family, SOCK_STREAM); + if (s < 0) { + log_server_error("Couldn't create socket for remote " + "control interface - %s", + knotd_strerror(s)); + return -1; + } + + /* Bind to interface and start listening. */ + int r = socket_bind(s, desc->family, desc->address, desc->port); + if (r == KNOTD_EOK) { + r = socket_listen(s, TCP_BACKLOG_SIZE); + } + + if (r != KNOTD_EOK) { + socket_close(s); + log_server_error("Could not bind to " + "remote control interface %s port %d.\n", + desc->address, desc->port); + return -1; + } + + return s; +} + +int remote_unbind(int r) +{ + if (r < 0) { + return KNOTD_EINVAL; + } + + return socket_close(r); +} + +int remote_poll(int r) +{ + if (r < 0) { + return -1; + } + + /* Wait for events. */ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(r, &rfds); + return fdset_pselect(r + 1, &rfds, NULL, NULL, NULL, NULL); +} diff --git a/src/knot/ctl/remote.h b/src/knot/ctl/remote.h new file mode 100644 index 0000000000..91c5f776b5 --- /dev/null +++ b/src/knot/ctl/remote.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file remote.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Functions for remote control interface. + * + * \addtogroup ctl + * @{ + */ + +#ifndef _KNOTD_REMOTE_H_ +#define _KNOTD_REMOTE_H_ + +#include "knot/conf/conf.h" + +int remote_bind(conf_iface_t *desc); +int remote_unbind(int r); +int remote_poll(int r); + +// encrypted comm +// remote_accept (r, key) +// remote_send (r, key) + + +#endif // _KNOTD_REMOTE_H_ + +/*! @} */ diff --git a/src/knot/main.c b/src/knot/main.c index dade8a3283..9fcd4191d3 100644 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -304,7 +304,13 @@ int main(int argc, char **argv) pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL); /* Bind to control interface. */ - int remote = remote_bind(conf()->ctl.iface); + conf_iface_t *ctl_if = conf()->ctl.iface; + if (ctl_if != NULL) { + log_server_info("Binding remote control interface " + "to %s port %d.\n", + ctl_if->address, ctl_if->port); + } + int remote = remote_bind(ctl_if); /* Run event loop. */ for(;;) { @@ -356,6 +362,7 @@ int main(int argc, char **argv) /* Events. */ if (ret > 0) { + fprintf(stderr, "remote: accepting..\n"); int c = tcp_accept(remote); if (c < 0) { continue; @@ -367,18 +374,23 @@ int main(int argc, char **argv) sockaddr_t addr; sockaddr_init(&addr, AF_INET); - int r = tcp_recv(c, buf, buflen, &addr); + fprintf(stderr, "remote: reading..\n"); + int r = recv(c, buf, buflen, MSG_WAITALL); if (r < 0) { + perror("tcp_recv"); + fprintf(stderr, "remote: read shit..\n"); close(c); continue; } + getpeername(c, addr.ptr, &addr.len); char straddr[SOCKADDR_STRLEN]; sockaddr_tostr(&addr, straddr, sizeof(straddr)); fprintf(stderr, "remote: accepted %d bytes from %s:%d\n", r, straddr, sockaddr_portnum(&addr)); close(c); + fprintf(stderr, "remote: i'm so done with this\n"); } } pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL); -- GitLab