diff --git a/Knot.files b/Knot.files index 594ce9af338f35156cb67dbdb03fdb8ea4fe5c9a..2bd8f946b67bc7b37c8e751d093dfea888f63ebe 100644 --- a/Knot.files +++ b/Knot.files @@ -116,14 +116,14 @@ src/knot/server/dthreads.c src/knot/server/dthreads.h src/knot/server/journal.c src/knot/server/journal.h +src/knot/server/net.c +src/knot/server/net.h src/knot/server/notify.c src/knot/server/notify.h src/knot/server/rrl.c src/knot/server/rrl.h src/knot/server/server.c src/knot/server/server.h -src/knot/server/socket.c -src/knot/server/socket.h src/knot/server/tcp-handler.c src/knot/server/tcp-handler.h src/knot/server/udp-handler.c diff --git a/src/Makefile.am b/src/Makefile.am index 6d851da7846a66176faef061982459b284a4cac6..44c073b1e479acc411353949a2fc4faece9d13f1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -232,8 +232,8 @@ libknotd_la_SOURCES = \ knot/server/rrl.h \ knot/server/server.c \ knot/server/server.h \ - knot/server/socket.c \ - knot/server/socket.h \ + knot/server/net.c \ + knot/server/net.h \ knot/server/tcp-handler.c \ knot/server/tcp-handler.h \ knot/server/udp-handler.c \ diff --git a/src/common/sockaddr.c b/src/common/sockaddr.c index 047d90a4bc32dd28ece156d0a001c4032a5d6d7e..fdf5273adfe38aba969ab07dc8505ee7b04a4fe5 100644 --- a/src/common/sockaddr.c +++ b/src/common/sockaddr.c @@ -18,7 +18,6 @@ #include <stdlib.h> #include <string.h> #include <netdb.h> -#include <unistd.h> #include "common/sockaddr.h" #include "common/errcode.h" @@ -38,6 +37,15 @@ int sockaddr_len(const struct sockaddr_storage *ss) } } +int sockaddr_cmp(const struct sockaddr_storage *k1, const struct sockaddr_storage *k2) +{ + if (k1->ss_family != k2->ss_family) { + return (int)k1->ss_family - (int)k2->ss_family; + } + + return memcmp(k1, k2, sockaddr_len(k1)); +} + int sockaddr_set(struct sockaddr_storage *ss, int family, const char *straddr, int port) { if (ss == NULL || straddr == NULL) { @@ -118,7 +126,7 @@ int sockaddr_tostr(const struct sockaddr_storage *ss, char *buf, size_t maxlen) sprintf(&buf[written], "%d", port); } - return KNOT_ERROR; + return KNOT_EOK; } int sockaddr_port(const struct sockaddr_storage *ss) diff --git a/src/common/sockaddr.h b/src/common/sockaddr.h index fd25ae44fe020ed090b032b6e0c339ac2c264ab2..b7fa648426b82d638d20e3a7f036d7510e74c498 100644 --- a/src/common/sockaddr.h +++ b/src/common/sockaddr.h @@ -38,6 +38,7 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <stdint.h> +#include <unistd.h> /* Subnet maximum prefix length. */ #define IPV4_PREFIXLEN 32 @@ -56,6 +57,13 @@ */ int sockaddr_len(const struct sockaddr_storage *ss); +/*! + * \brief Compare address storages. + * + * \return like memcmp(3) + */ +int sockaddr_cmp(const struct sockaddr_storage *k1, const struct sockaddr_storage *k2); + /*! * \brief Set address and port. * diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index b07196aca12d9ec93f21757e3ded4bba25fea24d..540044d93bee314ef8a817c7bddf0034dae79f2a 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -64,7 +64,7 @@ static conf_log_map_t *this_logmap = 0; #define SET_INT(out, in, name) SET_NUM(out, in, 0, INT_MAX, name); #define SET_SIZE(out, in, name) SET_NUM(out, in, 0, SIZE_MAX, name); -static void conf_init_iface(void *scanner, char* ifname, int port) +static void conf_init_iface(void *scanner, char* ifname) { this_iface = malloc(sizeof(conf_iface_t)); if (this_iface == NULL) { @@ -73,12 +73,11 @@ static void conf_init_iface(void *scanner, char* ifname, int port) } memset(this_iface, 0, sizeof(conf_iface_t)); this_iface->name = ifname; - this_iface->port = port; } static void conf_start_iface(void *scanner, char* ifname) { - conf_init_iface(scanner, ifname, -1); + conf_init_iface(scanner, ifname); add_tail(&new_config->ifaces, &this_iface->n); ++new_config->ifaces_count; } @@ -128,7 +127,7 @@ static void conf_remote_set_via(void *scanner, char *item) { if (!found) { cf_error(scanner, "interface '%s' is not defined", item); } else { - sockaddr_set(&this_remote->via, found->family, found->address, 0); + memcpy(&this_remote->via, &found->addr, sizeof(struct sockaddr_storage)); } } @@ -237,25 +236,26 @@ static bool set_remote_or_group(void *scanner, char *name, static void conf_acl_item_install(void *scanner, conf_iface_t *found) { - // silently skip duplicates - - conf_remote_t *remote; - WALK_LIST (remote, *this_list) { - if (remote->remote == found) { - return; - } - } // additional check for transfers - if ((this_list == &this_zone->acl.xfr_in || - this_list == &this_zone->acl.notify_out) && found->port == 0) + if ((this_list == &this_zone->acl.xfr_in || this_list == &this_zone->acl.notify_out) + && sockaddr_port(&found->addr) == 0) { cf_error(scanner, "remote specified for XFR/IN or " "NOTIFY/OUT needs to have valid port!"); return; } + // silently skip duplicates + + conf_remote_t *remote; + WALK_LIST (remote, *this_list) { + if (remote->remote == found) { + return; + } + } + // add into the list remote = malloc(sizeof(conf_remote_t)); @@ -510,60 +510,34 @@ interface_start: interface: | interface PORT NUM ';' { - if (this_iface->port > 0) { - cf_error(scanner, "only one port definition is allowed in interface section\n"); + if (this_iface->addr.ss_family == AF_UNSPEC) { + cf_error(scanner, "can't set port number before interface address\n"); } else { - SET_UINT16(this_iface->port, $3.i, "port"); + sockaddr_port_set(&this_iface->addr, $3.i); } } | interface ADDRESS IPA ';' { - if (this_iface->address != 0) { - cf_error(scanner, "only one address is allowed in interface section\n"); - } else { - this_iface->address = $3.t; - this_iface->family = AF_INET; - } + sockaddr_set(&this_iface->addr, AF_INET, $3.t, CONFIG_DEFAULT_PORT); + free($3.t); } | interface ADDRESS IPA '@' NUM ';' { - if (this_iface->address != 0) { - cf_error(scanner, "only one address is allowed in interface section\n"); - } else { - this_iface->address = $3.t; - this_iface->family = AF_INET; - if (this_iface->port > 0) { - cf_error(scanner, "only one port definition is allowed in interface section\n"); - } else { - SET_UINT16(this_iface->port, $5.i, "port"); - } - } + sockaddr_set(&this_iface->addr, AF_INET, $3.t, $5.i); + free($3.t); } | interface ADDRESS IPA6 ';' { - if (this_iface->address != 0) { - cf_error(scanner, "only one address is allowed in interface section\n"); - } else { - this_iface->address = $3.t; - this_iface->family = AF_INET6; - } + sockaddr_set(&this_iface->addr, AF_INET6, $3.t, CONFIG_DEFAULT_PORT); + free($3.t); } | interface ADDRESS IPA6 '@' NUM ';' { - if (this_iface->address != 0) { - cf_error(scanner, "only one address is allowed in interface section\n"); - } else { - this_iface->address = $3.t; - this_iface->family = AF_INET6; - if (this_iface->port > 0) { - cf_error(scanner, "only one port definition is allowed in interface section\n"); - } else { - SET_UINT16(this_iface->port, $5.i, "port"); - } - } + sockaddr_set(&this_iface->addr, AF_INET, $3.t, $5.i); + free($3.t); } ; interfaces: INTERFACES '{' | interfaces interface_start '{' interface '}' { - if (this_iface->address == 0) { + if (this_iface->addr.ss_family == AF_UNSPEC) { cf_error(scanner, "interface '%s' has no defined address", this_iface->name); } } @@ -713,75 +687,41 @@ remote_start: remote: | remote PORT NUM ';' { - if (this_remote->port != 0) { - cf_error(scanner, "only one port definition is allowed in remote section\n"); + if (this_remote->addr.ss_family == AF_UNSPEC) { + cf_error(scanner, "can't set port number before interface address\n"); } else { - SET_UINT16(this_remote->port, $3.i, "port"); + sockaddr_port_set(&this_remote->addr, $3.i); } } | remote ADDRESS IPA ';' { - if (this_remote->address != 0) { - cf_error(scanner, "only one address is allowed in remote section\n"); - } else { - this_remote->address = $3.t; - this_remote->prefix = IPV4_PREFIXLEN; - this_remote->family = AF_INET; - } + sockaddr_set(&this_remote->addr, AF_INET, $3.t, CONFIG_DEFAULT_PORT); + this_remote->prefix = IPV4_PREFIXLEN; + free($3.t); + } + | remote ADDRESS IPA '/' NUM ';' { + sockaddr_set(&this_remote->addr, AF_INET, $3.t, 0); + SET_NUM(this_remote->prefix, $5.i, 0, IPV4_PREFIXLEN, "prefix length"); + free($3.t); } - | remote ADDRESS IPA '/' NUM ';' { - if (this_remote->address != 0) { - cf_error(scanner, "only one address is allowed in remote section\n"); - } else { - this_remote->address = $3.t; - this_remote->family = AF_INET; - SET_NUM(this_remote->prefix, $5.i, 0, IPV4_PREFIXLEN, "prefix length"); - } - } | remote ADDRESS IPA '@' NUM ';' { - if (this_remote->address != 0) { - cf_error(scanner, "only one address is allowed in remote section\n"); - } else { - this_remote->address = $3.t; - this_remote->family = AF_INET; - this_remote->prefix = IPV4_PREFIXLEN; - if (this_remote->port != 0) { - cf_error(scanner, "only one port definition is allowed in remote section\n"); - } else { - SET_UINT16(this_remote->port, $5.i, "port"); - } - } + sockaddr_set(&this_remote->addr, AF_INET, $3.t, $5.i); + this_remote->prefix = IPV4_PREFIXLEN; + free($3.t); } | remote ADDRESS IPA6 ';' { - if (this_remote->address != 0) { - cf_error(scanner, "only one address is allowed in remote section\n"); - } else { - this_remote->address = $3.t; - this_remote->family = AF_INET6; - this_remote->prefix = IPV6_PREFIXLEN; - } + sockaddr_set(&this_remote->addr, AF_INET6, $3.t, CONFIG_DEFAULT_PORT); + this_remote->prefix = IPV6_PREFIXLEN; + free($3.t); + } + | remote ADDRESS IPA6 '/' NUM ';' { + sockaddr_set(&this_remote->addr, AF_INET6, $3.t, 0); + SET_NUM(this_remote->prefix, $5.i, 0, IPV6_PREFIXLEN, "prefix length"); + free($3.t); } - | remote ADDRESS IPA6 '/' NUM ';' { - if (this_remote->address != 0) { - cf_error(scanner, "only one address is allowed in remote section\n"); - } else { - this_remote->address = $3.t; - this_remote->family = AF_INET6; - SET_NUM(this_remote->prefix, $5.i, 0, IPV6_PREFIXLEN, "prefix length"); - } - } | remote ADDRESS IPA6 '@' NUM ';' { - if (this_remote->address != 0) { - cf_error(scanner, "only one address is allowed in remote section\n"); - } else { - this_remote->address = $3.t; - this_remote->family = AF_INET6; - this_remote->prefix = IPV6_PREFIXLEN; - if (this_remote->port != 0) { - cf_error(scanner, "only one port definition is allowed in remote section\n"); - } else { - SET_UINT16(this_remote->port, $5.i, "port"); - } - } + sockaddr_set(&this_remote->addr, AF_INET6, $3.t, $5.i); + this_remote->prefix = IPV6_PREFIXLEN; + free($3.t); } | remote KEY TEXT ';' { if (this_remote->key != 0) { @@ -808,7 +748,7 @@ remote: remotes: REMOTES '{' | remotes remote_start '{' remote '}' { - if (this_remote->address == 0) { + if (this_remote->addr.ss_family == AF_UNSPEC) { cf_error(scanner, "remote '%s' has no defined address", this_remote->name); } } @@ -1081,7 +1021,7 @@ log: LOG { new_config->logs_count = 0; } '{' log_start log_end ; ctl_listen_start: - LISTEN_ON { conf_init_iface(scanner, NULL, -1); } + LISTEN_ON { conf_init_iface(scanner, NULL); } ; ctl_allow_start: @@ -1093,17 +1033,16 @@ ctl_allow_start: control: CONTROL '{' { new_config->ctl.have = true; } | control ctl_listen_start '{' interface '}' { - if (this_iface->address == 0) { + if (this_iface->addr.ss_family == AF_UNSPEC) { cf_error(scanner, "control interface has no defined address"); } else { new_config->ctl.iface = this_iface; } } | control ctl_listen_start TEXT ';' { - this_iface->address = $3.t; - this_iface->family = AF_UNIX; - this_iface->port = 0; + sockaddr_set(&this_iface->addr, AF_UNIX, $3.t, 0); new_config->ctl.iface = this_iface; + free($3.t); } | control ctl_allow_start '{' zone_acl '}' | control ctl_allow_start zone_acl_list diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index 0deb8e9140f5bfdc91086cddf4596e5231e4031e..66a2df816d48b335b2465d8df1f0175073a93b5e 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -217,36 +217,36 @@ static int conf_process(conf_t *conf) conf->max_conn_reply = CONFIG_REPLY_WD; } - // Postprocess interfaces - conf_iface_t *cfg_if = NULL; - WALK_LIST(cfg_if, conf->ifaces) { - if (cfg_if->port <= 0) { - cfg_if->port = CONFIG_DEFAULT_PORT; - } - } - /* Default interface. */ conf_iface_t *ctl_if = conf->ctl.iface; if (!conf->ctl.have && ctl_if == NULL) { ctl_if = malloc(sizeof(conf_iface_t)); memset(ctl_if, 0, sizeof(conf_iface_t)); - ctl_if->family = AF_UNIX; - ctl_if->address = strdup("knot.sock"); + sockaddr_set(&ctl_if->addr, AF_UNIX, "knot.sock", 0); conf->ctl.iface = ctl_if; } /* Control interface. */ if (ctl_if) { - if (ctl_if->family == AF_UNIX) { - ctl_if->address = conf_abs_path(conf->rundir, - ctl_if->address); + if (ctl_if->addr.ss_family == AF_UNIX) { + char *full_path = malloc(SOCKADDR_STRLEN); + memset(full_path, 0, SOCKADDR_STRLEN); + sockaddr_tostr(&ctl_if->addr, full_path, SOCKADDR_STRLEN); + + /* Convert to absolute path. */ + full_path = conf_abs_path(conf->rundir, full_path); + if(full_path) { + sockaddr_set(&ctl_if->addr, AF_UNIX, full_path, 0); + free(full_path); + } + /* Check for ACL existence. */ if (!EMPTY_LIST(conf->ctl.allow)) { log_server_warning("Control 'allow' statement " "does not affect UNIX sockets.\n"); } - } else if (ctl_if->port <= 0) { - ctl_if->port = REMOTE_DPORT; + } else if (sockaddr_port(&ctl_if->addr) <= 0) { + sockaddr_port_set(&ctl_if->addr, REMOTE_DPORT); } } @@ -437,9 +437,7 @@ static int conf_process(conf_t *conf) conf_remote_t *r = NULL; WALK_LIST(r, conf->ctl.allow) { conf_iface_t *i = r->remote; - struct sockaddr_storage ss; - sockaddr_set(&ss, i->family, i->address, 0); - acl_insert(conf->ctl.acl, &ss, i->prefix, i->key); + acl_insert(conf->ctl.acl, &i->addr, i->prefix, i->key); } return ret; @@ -463,9 +461,8 @@ void __attribute__ ((constructor)) conf_init() /* Create default interface. */ conf_iface_t * iface = malloc(sizeof(conf_iface_t)); memset(iface, 0, sizeof(conf_iface_t)); + sockaddr_set(&iface->addr, AF_INET, "127.0.0.1", CONFIG_DEFAULT_PORT); iface->name = strdup("localhost"); - iface->address = strdup("127.0.0.1"); - iface->port = CONFIG_DEFAULT_PORT; add_tail(&s_config->ifaces, &iface->n); ++s_config->ifaces_count; @@ -1024,7 +1021,6 @@ void conf_free_iface(conf_iface_t *iface) } free(iface->name); - free(iface->address); free(iface); } diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index 90209c53f05500be9f3136df69f6e86cfecf8daa..82de8707f78a38a6456dc0dcfe44319b840f741f 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -66,13 +66,11 @@ */ typedef struct conf_iface_t { node_t n; - char *name; /*!< Internal name for the interface. */ - char *address; /*!< IP (IPv4/v6) address for this interface */ - unsigned prefix; /*!< IP subnet prefix. */ - int port; /*!< Port number for this interface */ - int family; /*!< Address family. */ - knot_tsig_key_t *key; /*!< TSIG key (only valid for remotes). */ - struct sockaddr_storage via; /*!< Used for remotes to specify qry endpoint.*/ + char *name; /*!< Internal name for the interface. */ + knot_tsig_key_t *key; /*!< TSIG key (only applic for remotes). */ + unsigned prefix; /*!< IP subnet prefix (only applic for remotes). */ + struct sockaddr_storage addr; /*!< Interface address. */ + struct sockaddr_storage via; /*!< Used for remotes to specify qry endpoint.*/ } conf_iface_t; /*! diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index ae6a82d6d4c15cf85d86e56d64e55967f58f04cd..627cd53b0264727e0fff81051b5455610d39d5a1 100644 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -32,7 +32,6 @@ #include "knot/ctl/remote.h" #include "knot/conf/conf.h" #include "knot/zone/zone-load.h" -#include "knot/server/socket.h" #include "knot/server/tcp-handler.h" #include "libknot/packet/wire.h" #include "knot/server/zone-load.h" @@ -184,7 +183,7 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[]) /* Check remote address. */ conf_iface_t *r = conf()->ctl.iface; - if (!r || !r->address) { + if (!r || r->addr.ss_family == AF_UNSPEC) { log_server_error("No remote address for '%s' configured.\n", cmd); return 1; @@ -234,28 +233,39 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[]) dbg_server("%s: sending query size %zu\n", __func__, pkt->size); - /* Send query. */ - int s = socket_create(r->family, SOCK_STREAM, 0); - int conn_state = socket_connect(s, r->family, r->address, r->port); - if (conn_state != KNOT_EOK || tcp_send(s, pkt->wire, pkt->size) <= 0) { - char portstr[32] = { '\0' }; - if (r->family != AF_UNIX) - snprintf(portstr, sizeof(portstr), "@%d", r->port); - log_server_error("Couldn't connect to remote host " - "%s%s\n", r->address, portstr); - rc = 1; + /* Connect to remote. */ + char addr_str[SOCKADDR_STRLEN] = {0}; + sockaddr_tostr(&r->addr, addr_str, sizeof(addr_str)); + + int s = net_connected_socket(SOCK_STREAM, &r->addr, &r->via); + if (s < 0) { + log_server_error("Couldn't connect to remote host '%s'.\n", addr_str); + knot_pkt_free(&pkt); + return 1; + } + + /* Wait for availability. */ + struct pollfd pfd = { s, POLLOUT, 0 }; + poll(&pfd, 1, conf()->max_conn_reply); + + /* Send and free packet. */ + int ret = tcp_send(s, pkt->wire, pkt->size); + knot_pkt_free(&pkt); + + /* Evaluate and wait for reply. */ + if (ret <= 0) { + log_server_error("Couldn't connect to remote host '%s'.\n", addr_str); + return 1; } /* Wait for reply. */ - if (rc == 0) { - int ret = KNOT_EOK; - while (ret == KNOT_EOK) { - ret = cmd_remote_reply(s); - if (ret != KNOT_EOK && ret != KNOT_ECONN) { - log_server_warning("Remote command reply: %s\n", - knot_strerror(ret)); - rc = 1; - } + ret = KNOT_EOK; + while (ret == KNOT_EOK) { + ret = cmd_remote_reply(s); + if (ret != KNOT_EOK && ret != KNOT_ECONN) { + log_server_warning("Remote command reply: %s\n", + knot_strerror(ret)); + rc = 1; } } @@ -265,8 +275,7 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[]) } /* Close connection. */ - socket_close(s); - knot_pkt_free(&pkt); + close(s); return rc; } @@ -530,25 +539,26 @@ int main(int argc, char **argv) /* Override from command line. */ if (r_addr) { - free(ctl_if->address); - ctl_if->address = strdup(r_addr); - ctl_if->family = AF_INET; - /* Check for v6 address. */ - if (strchr(r_addr, ':')) - ctl_if->family = AF_INET6; + int family = AF_INET; + if (strchr(r_addr, ':')) { + family = AF_INET6; + } /* Is a valid UNIX socket or at least contains slash ? */ struct stat st; bool has_slash = strchr(r_addr, '/') != NULL; bool is_file = stat(r_addr, &st) == 0; if (has_slash || (is_file && S_ISSOCK(st.st_mode))) { - ctl_if->family = AF_UNIX; - r_port = 0; /* Override. */ + family = AF_UNIX; } + sockaddr_set(&ctl_if->addr, family, r_addr, sockaddr_port(&ctl_if->addr)); + } + + if (r_port > 0) { + sockaddr_port_set(&ctl_if->addr, r_port); } - if (r_port > -1) ctl_if->port = r_port; /* Verbose mode. */ if (has_flag(flags, F_VERBOSE)) { diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c index 9c79cfb25bf2dd024ffdc29d3a21e605461bd0b5..ff2d2211f69bd41135ea8af76b86ff75e008c66a 100644 --- a/src/knot/ctl/remote.c +++ b/src/knot/ctl/remote.c @@ -21,7 +21,7 @@ #include "common/fdset.h" #include "knot/knot.h" #include "knot/conf/conf.h" -#include "knot/server/socket.h" +#include "knot/server/net.h" #include "knot/server/tcp-handler.h" #include "knot/server/zones.h" #include "libknot/packet/wire.h" @@ -399,71 +399,77 @@ static int remote_senderr(int c, uint8_t *qbuf, size_t buflen) int remote_bind(conf_iface_t *desc) { - if (!desc) { - return -1; + if (desc == NULL) { + return KNOT_EINVAL; } - /* Create new socket. */ - int s = socket_create(desc->family, SOCK_STREAM, 0); - if (s < 0) { - log_server_error("Couldn't create socket for remote " - "control interface - %s", knot_strerror(s)); - return KNOT_ERROR; - } + char addr_str[SOCKADDR_STRLEN] = {0}; + sockaddr_tostr(&desc->addr, addr_str, sizeof(addr_str)); + log_server_info("Binding remote control interface to '%s'.\n", addr_str); - /* Bind to interface and start listening. */ + /* Create new socket. */ mode_t old_umask = umask(KNOT_CTL_SOCKET_UMASK); - int r = socket_bind(s, desc->family, desc->address, desc->port); + int sock = net_bound_socket(SOCK_STREAM, &desc->addr); umask(old_umask); - if (r == KNOT_EOK) { - r = socket_listen(s, TCP_BACKLOG_SIZE); + if (sock < 0) { + return sock; } - if (r != KNOT_EOK) { - log_server_error("Could not bind to remote control interface.\n"); - socket_close(s); - return r; + + /* Start listening. */ + int ret = listen(sock, TCP_BACKLOG_SIZE); + if (ret < 0) { + log_server_error("Could not bind to '%s'.\n", addr_str); + close(sock); + return ret; } - return s; + return sock; } -int remote_unbind(int r) +int remote_unbind(conf_iface_t *desc, int sock) { - if (r < 0) { + if (desc == NULL || sock < 0) { return KNOT_EINVAL; } - return socket_close(r); + /* Remove control socket file. */ + if (desc->addr.ss_family == AF_UNIX) { + char addr_str[SOCKADDR_STRLEN] = {0}; + sockaddr_tostr(&desc->addr, addr_str, sizeof(addr_str)); + unlink(addr_str); + } + + return close(sock); } -int remote_poll(int r) +int remote_poll(int sock) { /* Wait for events. */ fd_set rfds; FD_ZERO(&rfds); - if (r > -1) { - FD_SET(r, &rfds); + if (sock > -1) { + FD_SET(sock, &rfds); } else { - r = -1; /* Make sure n == r + 1 == 0 */ + sock = -1; /* Make sure n == r + 1 == 0 */ } - return fdset_pselect(r + 1, &rfds, NULL, NULL, NULL, NULL); + return fdset_pselect(sock + 1, &rfds, NULL, NULL, NULL, NULL); } -int remote_recv(int r, struct sockaddr *a, uint8_t* buf, size_t *buflen) +int remote_recv(int sock, struct sockaddr *addr, uint8_t* buf, size_t *buflen) { - int c = tcp_accept(r); + int c = tcp_accept(sock); if (c < 0) { dbg_server("remote: couldn't accept incoming connection\n"); return c; } /* Receive data. */ - int n = tcp_recv(c, buf, *buflen, a); + int n = tcp_recv(c, buf, *buflen, addr); *buflen = n; if (n <= 0) { dbg_server("remote: failed to receive data\n"); - socket_close(c); + close(c); return KNOT_ECONNREFUSED; } @@ -518,9 +524,9 @@ failed: return ret; } -int remote_answer(int fd, server_t *s, knot_pkt_t *pkt) +int remote_answer(int sock, server_t *s, knot_pkt_t *pkt) { - if (fd < 0 || s == NULL || pkt == NULL) { + if (sock < 0 || s == NULL || pkt == NULL) { return KNOT_EINVAL; } @@ -583,12 +589,12 @@ int remote_answer(int fd, server_t *s, knot_pkt_t *pkt) unsigned p = 0; size_t chunk = 16384; for (; p + chunk < args->rlen; p += chunk) { - remote_send_chunk(fd, pkt, args->resp + p, chunk); + remote_send_chunk(sock, pkt, args->resp + p, chunk); } unsigned r = args->rlen - p; if (r > 0) { - remote_send_chunk(fd, pkt, args->resp + p, r); + remote_send_chunk(sock, pkt, args->resp + p, r); } free(args); @@ -620,7 +626,7 @@ int remote_process(server_t *s, conf_iface_t *ctl_if, int sock, /* Parse packet and answer if OK. */ int ret = remote_parse(pkt); - if (ret == KNOT_EOK && ctl_if->family != AF_UNIX) { + if (ret == KNOT_EOK && ctl_if->addr.ss_family != AF_UNIX) { /* Check ACL list. */ char addr_str[SOCKADDR_STRLEN] = {0}; @@ -675,7 +681,7 @@ int remote_process(server_t *s, conf_iface_t *ctl_if, int sock, finish: knot_pkt_free(&pkt); - socket_close(client); + close(client); return ret; } diff --git a/src/knot/ctl/remote.h b/src/knot/ctl/remote.h index 01666de713aa8f898808266ceb7b472ad95d1fbd..6c8389aa5aa1a803f9434094769ce7bcfe645f6b 100644 --- a/src/knot/ctl/remote.h +++ b/src/knot/ctl/remote.h @@ -38,6 +38,7 @@ /*! * \brief Bind RC interface according to configuration. + * * \param desc Interface descriptor (address, port). * * \retval socket if passed. @@ -50,20 +51,22 @@ int remote_bind(conf_iface_t *desc); * * \note Breaks all pending connections. * - * \param r RC interface socket + * \param desc Interface descriptor (address, port). + * \param socket Interface socket * * \retval KNOT_EOK on success. * \retval knot_error else. */ -int remote_unbind(int r); +int remote_unbind(conf_iface_t *desc, int sock); /*! * \brief Poll new events on RC socket. + * * \param r RC interface socket. * * \return number of polled events or -1 on error. */ -int remote_poll(int r); +int remote_poll(int sock); /*! * \brief Start a RC connection with remote. @@ -76,7 +79,7 @@ int remote_poll(int r); * \return client TCP socket if success. * \return KNOT_ECONNREFUSED if fails to receive command. */ -int remote_recv(int r, struct sockaddr *a, uint8_t* buf, size_t *buflen); +int remote_recv(int sock, struct sockaddr *addr, uint8_t* buf, size_t *buflen); /*! * \brief Parse a RC command. @@ -100,7 +103,7 @@ int remote_parse(knot_pkt_t* pkt); * \retval KNOT_EOK on success. * \retval knot_error else. */ -int remote_answer(int fd, server_t *s, knot_pkt_t *pkt); +int remote_answer(int sock, server_t *s, knot_pkt_t *pkt); /*! * \brief Accept new client, receive command, process it and send response. diff --git a/src/knot/main.c b/src/knot/main.c index 7ee129793342aeee34fad452fbeab4f1ab3cc14d..9dbae43e3171a0fef64a96cf66cf1c6b9f56e341 100644 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -339,18 +339,7 @@ int main(int argc, char **argv) /* Bind to control interface. */ uint8_t buf[KNOT_WIRE_MAX_PKTSIZE]; size_t buflen = sizeof(buf); - int remote = -1; - if (conf()->ctl.iface != NULL) { - conf_iface_t *ctl_if = conf()->ctl.iface; - memset(buf, 0, buflen); - if (ctl_if->port) - snprintf((char*)buf, buflen, "@%d", ctl_if->port); - /* Log control interface description. */ - log_server_info("Binding remote control interface " - "to %s%s\n", - ctl_if->address, (char*)buf); - remote = remote_bind(ctl_if); - } + int remote = remote_bind(conf()->ctl.iface); /* Run event loop. */ for(;;) { @@ -385,14 +374,7 @@ int main(int argc, char **argv) pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL); /* Close remote control interface */ - if (remote > -1) { - close(remote); - - /* Remove control socket. */ - conf_iface_t *ctl_if = conf()->ctl.iface; - if (ctl_if && ctl_if->family == AF_UNIX) - unlink(conf()->ctl.iface->address); - } + remote_unbind(conf()->ctl.iface, remote); if ((server_wait(&server)) != KNOT_EOK) { log_server_error("An error occured while " diff --git a/src/knot/server/net.c b/src/knot/server/net.c new file mode 100644 index 0000000000000000000000000000000000000000..b8d47b616abcb9dbe2654790884ec9668b6a78cc --- /dev/null +++ b/src/knot/server/net.c @@ -0,0 +1,144 @@ +/* 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 <config.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <netdb.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_NETINET_IN_SYSTM_H +#include <netinet/in_systm.h> +#endif +#include <sys/stat.h> +#include <assert.h> + +#include "knot/server/net.h" +#include "knot/knot.h" + +static int socket_create(int family, int type, int proto) +{ + /* Create socket. */ + int ret = socket(family, type, proto); + if (ret < 0) { + return knot_map_errno(EACCES, EINVAL, ENOMEM); + } + + return ret; +} + +int net_unbound_socket(int type, struct sockaddr_storage *ss) +{ + if (ss == NULL) { + return KNOT_EINVAL; + } + + /* Convert to string address format. */ + char addr_str[SOCKADDR_STRLEN] = {0}; + sockaddr_tostr(ss, addr_str, sizeof(addr_str)); + + /* Create socket. */ + int socket = socket_create(ss->ss_family, type, 0); + if (socket < 0) { + log_server_error("Could not create socket for '%s': %s\n", + addr_str, knot_strerror(socket)); + return socket; + } + + /* Make the socket IPv6 only to allow 'any' for IPv4 and IPv6 at the same time. */ + if (ss->ss_family == AF_INET6) { + /* Do not support mapping IPv4 in IPv6 sockets. */ + int flag = 1; + (void) setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, + &flag, sizeof(flag)); + } + + return socket; +} + +int net_bound_socket(int type, struct sockaddr_storage *ss) +{ + /* Create socket. */ + int socket = net_unbound_socket(type, ss); + if (socket < 0) { + return socket; + } + + /* Convert to string address format. */ + char addr_str[SOCKADDR_STRLEN] = {0}; + sockaddr_tostr(ss, addr_str, sizeof(addr_str)); + + /* Reuse old address if taken. */ + int flag = 1; + (void) setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + + /* Unlink UNIX socket if exists. */ + if (ss->ss_family == AF_UNIX) { + unlink(addr_str); + } + + /* Bind to specified address. */ + int ret = bind(socket, (struct sockaddr *)ss, sockaddr_len(ss)); + if (ret < 0) { + ret = knot_map_errno(EADDRINUSE, EINVAL, EACCES, ENOMEM); + log_server_error("Cannot bind to address '%s': %s\n", + addr_str, knot_strerror(ret)); + close(socket); + return ret; + } + + return socket; +} + +int net_connected_socket(int type, struct sockaddr_storage *dst_addr, + struct sockaddr_storage *src_addr) +{ + if (dst_addr == NULL) { + return KNOT_EINVAL; + } + + int socket = -1; + + /* Bind to specific source address - if set. */ + if (src_addr != NULL && src_addr->ss_family != AF_UNSPEC) { + socket = net_bound_socket(type, src_addr); + } else { + socket = net_unbound_socket(type, dst_addr); + } + if (socket < 0) { + return socket; + } + + /* Use non-blocking. */ + if (fcntl(socket, F_SETFL, O_NONBLOCK) < 0) + ; /* Go silently with blocking if it fails. */ + + + /* Connect to destination. */ + int ret = connect(socket, (struct sockaddr *)dst_addr, sockaddr_len(dst_addr)); + if (ret != 0 && errno != EINPROGRESS) { + close(socket); + return knot_map_errno(EACCES, EADDRINUSE, EAGAIN, + ECONNREFUSED, EISCONN); + } + + return socket; +} diff --git a/src/knot/server/net.h b/src/knot/server/net.h new file mode 100644 index 0000000000000000000000000000000000000000..08c86e8403315b2bc476756bacabff492c3306e5 --- /dev/null +++ b/src/knot/server/net.h @@ -0,0 +1,70 @@ +/* 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 net.h + * + * \author Marek Vavrusa <marek.vavusa@nic.cz> + * + * \brief Generic sockets APIs. + * + * This file provides higher-level API for creating connections and listeners. + * + * \addtogroup network + * @{ + */ + +#ifndef _KNOTD_NET_H_ +#define _KNOTD_NET_H_ + +/* POSIX only. */ +#include "common/sockaddr.h" + +/*! + * \brief Create unbound socket of given family and type. + * + * \param type Socket transport type (SOCK_STREAM, SOCK_DGRAM). + * \param ss Socket address storage. + * + * \return socket or error code + */ +int net_unbound_socket(int type, struct sockaddr_storage *ss); + +/*! + * \brief Create socket bound to given address. + * + * \param type Socket transport type (SOCK_STREAM, SOCK_DGRAM). + * \param ss Socket address storage. + * + * \return socket or error code + */ +int net_bound_socket(int type, struct sockaddr_storage *ss); + +/*! + * \brief Create socket connected (asynchronously) to destination address. + * + * \param type Socket transport type (SOCK_STREAM, SOCK_DGRAM). + * \param dst_addr Destination address. + * \param src_addr Source address (can be NULL). + * + * \return socket or error code + */ +int net_connected_socket(int type, struct sockaddr_storage *dst_addr, + struct sockaddr_storage *src_addr); + + +#endif // _KNOTD_NET_H_ + +/*! @} */ diff --git a/src/knot/server/server.c b/src/knot/server/server.c index 26370962e8696b5a9d8482ac98fd08f13b8940ed..9d8ac367e236ba72d11ac0a7f097fa5ef818eb49 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -94,7 +94,6 @@ static void server_remove_iface(iface_t *iface) } /* Free interface. */ - free(iface->addr); free(iface); } @@ -113,98 +112,47 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if) { /* Initialize interface. */ int ret = 0; - int sock = 0; - char errbuf[256] = {0}; memset(new_if, 0, sizeof(iface_t)); + memcpy(&new_if->addr, &cfg_if->addr, sizeof(struct sockaddr_storage)); - /* Create UDP socket. */ - ret = socket_create(cfg_if->family, SOCK_DGRAM, IPPROTO_UDP); - if (ret < 0) { - if (strerror_r(errno, errbuf, sizeof(errbuf)) == 0) { - log_server_error("Could not create UDP socket: %s.\n", - errbuf); - } - return ret; - } else { - sock = ret; - } - - /* Set socket options. */ - int flag = 1; - if (cfg_if->family == AF_INET6) { - /* Disable dual-stack for performance reasons. */ - if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) { - dbg_net("udp: failed to set IPV6_V6ONLY to socket, using default config\n"); - } - } + /* Convert to string address format. */ + char addr_str[SOCKADDR_STRLEN] = {0}; + sockaddr_tostr(&cfg_if->addr, addr_str, sizeof(addr_str)); - ret = socket_bind(sock, cfg_if->family, cfg_if->address, cfg_if->port); - if (ret < 0) { - socket_close(sock); - log_server_error("Could not bind to " - "UDP interface %s port %d.\n", - cfg_if->address, cfg_if->port); - return ret; + /* Create bound UDP socket. */ + int sock = net_bound_socket(SOCK_DGRAM, &cfg_if->addr); + if (sock < 0) { + return sock; } new_if->fd[IO_UDP] = sock; - new_if->type = cfg_if->family; - new_if->port = cfg_if->port; - new_if->addr = strdup(cfg_if->address); - /* Create TCP socket. */ - ret = socket_create(cfg_if->family, SOCK_STREAM, IPPROTO_TCP); - if (ret < 0) { - socket_close(new_if->fd[IO_UDP]); - if (strerror_r(errno, errbuf, sizeof(errbuf)) == 0) { - log_server_error("Could not create TCP socket: %s.\n", - errbuf); - } - return ret; - } else { - sock = ret; + /* Create bound TCP socket. */ + sock = net_bound_socket(SOCK_STREAM, &cfg_if->addr); + if (sock < 0) { + close(new_if->fd[IO_UDP]); + return sock; } - /* Set socket options. */ - if (cfg_if->family == AF_INET6) { - if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) { - dbg_net("tcp: failed to set IPV6_V6ONLY to socket, using default config\n"); - } + new_if->fd[IO_TCP] = sock; + + /* Listen for incoming connections. */ + ret = listen(sock, TCP_BACKLOG_SIZE); + if (ret < 0) { + close(new_if->fd[IO_UDP]); + close(new_if->fd[IO_TCP]); + log_server_error("Failed to listen on TCP interface '%s'.\n", addr_str); + return KNOT_ERROR; } /* accept() must not block */ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { - free(new_if->addr); - socket_close(new_if->fd[IO_UDP]); - socket_close(sock); - log_server_error("Failed to listen on %s@%d in non-blocking mode.\n", - cfg_if->address, cfg_if->port); + close(new_if->fd[IO_UDP]); + close(new_if->fd[IO_TCP]); + log_server_error("Failed to listen on '%s' in non-blocking mode.\n", addr_str); return KNOT_ERROR; } - ret = socket_bind(sock, cfg_if->family, cfg_if->address, cfg_if->port); - if (ret < 0) { - free(new_if->addr); - socket_close(new_if->fd[IO_UDP]); - socket_close(sock); - log_server_error("Could not bind to " - "TCP interface %s port %d.\n", - cfg_if->address, cfg_if->port); - return ret; - } - - ret = socket_listen(sock, TCP_BACKLOG_SIZE); - if (ret < 0) { - free(new_if->addr); - socket_close(new_if->fd[IO_UDP]); - socket_close(sock); - log_server_error("Failed to listen on " - "TCP interface %s port %d.\n", - cfg_if->address, cfg_if->port); - return ret; - } - - new_if->fd[IO_TCP] = sock; return KNOT_EOK; } @@ -213,10 +161,11 @@ static void remove_ifacelist(struct ref_t *p) ifacelist_t *ifaces = (ifacelist_t *)p; /* Remove deprecated interfaces. */ + char addr_str[SOCKADDR_STRLEN] = {0}; iface_t *n = NULL, *m = NULL; WALK_LIST_DELSAFE(n, m, ifaces->u) { - log_server_info("Removing interface %s port %d.\n", - n->addr, n->port); + sockaddr_tostr(&n->addr, addr_str, sizeof(addr_str)); + log_server_info("Removing interface '%s'.\n", addr_str); server_remove_iface(n); } WALK_LIST_DELSAFE(n, m, ifaces->l) { @@ -242,6 +191,7 @@ static int reconfigure_sockets(const struct conf_t *conf, server_t *s) rcu_read_lock(); /* Prepare helper lists. */ + char addr_str[SOCKADDR_STRLEN] = {0}; int bound = 0; iface_t *m = 0; ifacelist_t *newlist = malloc(sizeof(ifacelist_t)); @@ -266,11 +216,9 @@ static int reconfigure_sockets(const struct conf_t *conf, server_t *s) if (s->ifaces) { WALK_LIST(m, s->ifaces->u) { /* Matching port and address. */ - if (cfg_if->port == m->port) { - if (strcmp(cfg_if->address, m->addr) == 0) { - found_match = 1; - break; - } + if (sockaddr_cmp(&cfg_if->addr, &m->addr) == 0) { + found_match = 1; + break; } } } @@ -279,8 +227,8 @@ static int reconfigure_sockets(const struct conf_t *conf, server_t *s) if (found_match) { rem_node((node_t *)m); } else { - log_server_info("Binding to interface %s port %d.\n", - cfg_if->address, cfg_if->port); + sockaddr_tostr(&cfg_if->addr, addr_str, sizeof(addr_str)); + log_server_info("Binding to interface %s.\n", addr_str); /* Create new interface. */ m = malloc(sizeof(iface_t)); diff --git a/src/knot/server/server.h b/src/knot/server/server.h index 3b8dff33058579e3d863c8f6ebcc9323599fb8be..f92d6b8d6f15b1650adf9f161076eb62431be5b2 100644 --- a/src/knot/server/server.h +++ b/src/knot/server/server.h @@ -40,7 +40,7 @@ #include "common/lists.h" #include "knot/server/xfr-handler.h" #include "knot/server/dthreads.h" -#include "knot/server/socket.h" +#include "knot/server/net.h" #include "knot/server/rrl.h" #include "knot/zone/zonedb.h" @@ -77,9 +77,7 @@ typedef enum { typedef struct iface_t { struct node n; int fd[2]; - int type; - int port; /*!< \brief Socket port. */ - char* addr; /*!< \brief Socket address. */ + struct sockaddr_storage addr; } iface_t; /* Handler types. */ diff --git a/src/knot/server/socket.c b/src/knot/server/socket.c deleted file mode 100644 index 0c6963b1efc2a50975da627bf1d3d6745e8f7c01..0000000000000000000000000000000000000000 --- a/src/knot/server/socket.c +++ /dev/null @@ -1,123 +0,0 @@ -/* 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 <config.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <stdio.h> -#include <netdb.h> -#include <time.h> -#include <sys/types.h> -#include <sys/socket.h> -#ifdef HAVE_NETINET_IN_SYSTM_H -#include <netinet/in_systm.h> -#endif -#include <sys/stat.h> -#include <assert.h> - -#include "knot/knot.h" -#include "knot/server/socket.h" - -int socket_create(int family, int type, int proto) -{ - /* Create socket. */ - int ret = socket(family, type, proto); - if (ret < 0) { - return knot_map_errno(EACCES, EINVAL, ENOMEM); - } - - return ret; -} - -int socket_connect(int fd, int family, const char *addr, unsigned short port) -{ - struct sockaddr_storage ss; - int ret = sockaddr_set(&ss, family, addr, port); - if (ret != KNOT_EOK) { - return ret; - } - - ret = connect(fd, (struct sockaddr *)&ss, sockaddr_len(&ss)); - if (ret < 0) { - ret = knot_map_errno(EACCES, EADDRINUSE, EAGAIN, - ECONNREFUSED, EISCONN); - } - - return ret; -} - -int socket_bind(int socket, int family, const char *addr, unsigned short port) -{ - /* Check address family. */ - int flag = 1; - struct sockaddr_storage ss; - int ret = sockaddr_set(&ss, family, addr, port); - if (ret != KNOT_EOK) { - return ret; - } - - /* Make the socket IPv6 only to allow 'any' for IPv4 and IPv6 at the same time. */ - if (family == AF_INET6) { - /* Do not support mapping IPv4 in IPv6 sockets. */ - ret = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, - &flag, sizeof(flag)); - if (ret < 0) { - return KNOT_EINVAL; - } - } - - /* Unlink UNIX socket if exists. */ - if (family == AF_UNIX) { - unlink(addr); - } - - /* Reuse old address if taken. */ - ret = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); - if (ret < 0) { - return KNOT_EINVAL; - } - - /* Bind to specified address. */ - ret = bind(socket, (struct sockaddr *)&ss, sockaddr_len(&ss)); - if (ret < 0) { - ret = knot_map_errno(EADDRINUSE, EINVAL, EACCES, ENOMEM); - log_server_error("Cannot bind to socket: %s\n", knot_strerror(ret)); - } - - return ret; -} - -int socket_listen(int socket, int backlog_size) -{ - int ret = listen(socket, backlog_size); - if (ret < 0) { - return knot_map_errno(EADDRINUSE); - } - - return KNOT_EOK; -} - -int socket_close(int socket) -{ - if (close(socket) < 0) { - return KNOT_ERROR; - } - - return KNOT_EOK; -} diff --git a/src/knot/server/socket.h b/src/knot/server/socket.h deleted file mode 100644 index 0e8f336310d542f09088e3b83c74c376429933fc..0000000000000000000000000000000000000000 --- a/src/knot/server/socket.h +++ /dev/null @@ -1,113 +0,0 @@ -/* 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 socket.h - * - * \author Marek Vavrusa <marek.vavusa@nic.cz> - * - * \brief Generic sockets APIs. - * - * This file provides platform-independent sockets. - * Functions work on sockets created via system socket(2) functions. - * - * You can use standard I/O functions send(), sendto(), recv(), recvfrom() - * like you would with a normal sockets. - * - * \addtogroup network - * @{ - */ - -#ifndef _KNOTD_SOCKET_H_ -#define _KNOTD_SOCKET_H_ - -/* POSIX only. */ -#include "common/sockaddr.h" - -/*! - * \brief Create socket. - * - * \param family Socket family (PF_INET, PF_IPX, PF_PACKET, PF_UNIX). - * \param type Socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW). - * - * \retval new socket filedescriptor on success. - * \retval KNOT_EINVAL on invalid parameters. - * \retval KNOT_ENOMEM out of memory error. - * \retval KNOT_EACCES process does not have appropriate privileges. - * \retval KNOT_ERROR unspecified error. - */ -int socket_create(int family, int type, int proto); - -/*! - * \brief Connect to remote host. - * - * \param fd Socket filedescriptor. - * \param family Socket family. - * \param addr Requested address. - * \param port Requested port. - * - * \retval KNOT_EOK on success. - * \retval KNOT_EINVAL invalid parameters. - * \retval KNOT_EACCES process does not have appropriate privileges. - * \retval KNOT_EAGAIN lack of resources, try again. - * \retval KNOT_EADDRINUSE address already in use. - * \retval KNOT_ECONNREFUSED connection refused. - * \retval KNOT_EISCONN already connected. - * \retval KNOT_ERROR unspecified error. - */ -int socket_connect(int fd, int family, const char *addr, unsigned short port); - -/*! - * \brief Listen on given socket. - * - * \param fd Socket filedescriptor. - * \param family Socket family. - * \param addr Requested address. - * \param port Requested port. - * - * \retval KNOT_EOK on success. - * \retval KNOT_EINVAL invalid parameters. - * \retval KNOT_EACCES process does not have appropriate privileges. - * \retval KNOT_EADDRINUSE address already in use. - * \retval KNOT_ENOMEM out of memory error. - * \retval KNOT_ERROR unspecified error. - */ -int socket_bind(int fd, int family, const char *addr, unsigned short port); - -/*! - * \brief Listen on given TCP socket. - * - * \param fd Socket filedescriptor. - * \param backlog_size Requested TCP backlog size. - * - * \retval KNOT_EOK on success. - * \retval KNOT_EADDRINUSE address already in use. - * \retval KNOT_ERROR unspecified error. - */ -int socket_listen(int fd, int backlog_size); - -/*! - * \brief Close and deinitialize socket. - * - * \param fd Socket filedescriptor. - * - * \retval KNOT_EOK on success. - * \retval KNOT_EINVAL invalid parameters. - */ -int socket_close(int fd); - -#endif // _KNOTD_SOCKET_H_ - -/*! @} */ diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 82dbe17c4338865290493ffe9f2cd3451d4cf290..baa9f33e426cbf22068f24a69241f67fd266620a 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -88,7 +88,7 @@ static enum fdset_sweep_state tcp_sweep(fdset_t *set, int i, void *data) log_server_notice("Connection '%s' was terminated due to inactivity.\n", addr_str); - socket_close(fd); + close(fd); return FDSET_SWEEP; } @@ -277,7 +277,7 @@ static int tcp_event_accept(tcp_context_t *tcp, unsigned i) /* Assign to fdset. */ int next_id = fdset_add(&tcp->set, client, POLLIN, NULL); if (next_id < 0) { - socket_close(client); + close(client); return next_id; /* Contains errno. */ } @@ -344,7 +344,7 @@ static int tcp_wait_for_events(tcp_context_t *tcp) if (set->pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) { fdset_remove(set, i); - socket_close(fd); + close(fd); continue; /* Stay on the same index. */ } @@ -401,7 +401,7 @@ int tcp_master(dthread_t *thread) /* Cancel client connections. */ for (unsigned i = tcp.client_threshold; i < tcp.set.n; ++i) { - socket_close(tcp.set.pfd[i].fd); + close(tcp.set.pfd[i].fd); } ref_release(ref); diff --git a/src/knot/server/tcp-handler.h b/src/knot/server/tcp-handler.h index c67c7b8708afc2479b9211fcabbf594ce6024a7a..2265d60f8e4153e0b6b5b822e752d6c8fd0f6b06 100644 --- a/src/knot/server/tcp-handler.h +++ b/src/knot/server/tcp-handler.h @@ -33,7 +33,7 @@ #include <stdint.h> -#include "knot/server/socket.h" +#include "knot/server/net.h" #include "knot/server/server.h" #include "knot/server/dthreads.h" diff --git a/src/knot/server/udp-handler.h b/src/knot/server/udp-handler.h index 11e7d6eab62fd97c517fbe0dc7f1f23d22a2833b..67ef81e3cb23cab52bb20b255bb400fccc611ca9 100644 --- a/src/knot/server/udp-handler.h +++ b/src/knot/server/udp-handler.h @@ -31,7 +31,7 @@ #ifndef _KNOTD_UDPHANDLER_H_ #define _KNOTD_UDPHANDLER_H_ -#include "knot/server/socket.h" +#include "knot/server/net.h" #include "knot/server/server.h" #include "knot/server/dthreads.h" diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index 57386e9bca55ecdc8b151a5ee631bc8f16e17983..4253fe7fff56e1835f0297814922d10fac9b93f3 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -30,7 +30,7 @@ #include "knot/server/xfr-handler.h" #include "knot/server/server.h" -#include "knot/server/socket.h" +#include "knot/server/net.h" #include "knot/server/udp-handler.h" #include "knot/server/tcp-handler.h" #include "knot/updates/xfr-in.h" @@ -102,25 +102,13 @@ static int xfr_send_tcp(int fd, struct sockaddr *addr, uint8_t *msg, size_t msgl { return tcp_send(fd, msg, msglen); } static int xfr_send_udp(int fd, struct sockaddr *addr, uint8_t *msg, size_t msglen) -{ - struct sockaddr_storage *ss = (struct sockaddr_storage *)addr; - if (ss->ss_family == AF_INET) { - return sendto(fd, msg, msglen, 0, addr, sizeof(struct sockaddr_in)); - } - if (ss->ss_family == AF_INET6) { - return sendto(fd, msg, msglen, 0, addr, sizeof(struct sockaddr_in6)); - } - return KNOT_EINVAL; -} +{ return sendto(fd, msg, msglen, 0, addr, sockaddr_len((struct sockaddr_storage *)addr)); } static int xfr_recv_tcp(int fd, struct sockaddr *addr, uint8_t *buf, size_t buflen) { return tcp_recv(fd, buf, buflen, addr); } static int xfr_recv_udp(int fd, struct sockaddr *addr, uint8_t *buf, size_t buflen) -{ - socklen_t addrlen = sizeof(struct sockaddr_storage); - return recvfrom(fd, buf, buflen, 0, addr, &addrlen); -} +{ return recv(fd, buf, buflen, 0); } /*! \todo This should be obsoleted by the generic response parsing layer. */ static int parse_packet(knot_pkt_t *packet, knot_pkt_type_t *type) @@ -257,38 +245,16 @@ static int xfr_task_setsig(knot_ns_xfr_t *rq, knot_tsig_key_t *key) static int xfr_task_connect(knot_ns_xfr_t *rq) { /* Create socket by type. */ - int ret = 0; int stype = (rq->flags & XFR_FLAG_TCP) ? SOCK_STREAM : SOCK_DGRAM; - int fd = socket_create(rq->addr.ss_family, stype, 0); - if (fd < 0) { - return KNOT_ERROR; - } - - /* Bind to specific address - if set. */ - if (rq->saddr.ss_family != AF_UNSPEC) { - if (bind(fd, (struct sockaddr *)&rq->saddr, sizeof(rq->saddr)) < 0) { - socket_close(fd); - return KNOT_ERROR; - } - } - - /* Connect if TCP. */ - if (rq->flags & XFR_FLAG_TCP) { - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - ; /* Go silently with blocking if it fails. */ - - ret = connect(fd, (struct sockaddr *)&rq->addr, sizeof(rq->addr)); - if (ret != 0 && errno != EINPROGRESS) { - socket_close(fd); - return KNOT_ECONNREFUSED; - } + int ret = net_connected_socket(stype, &rq->addr, &rq->saddr); + if (ret < 0) { + return ret; } /* Set up for UDP as well to trigger 'send query' event. */ + rq->session = ret; rq->flags |= XFR_FLAG_CONNECTING; - /* Store new socket descriptor. */ - rq->session = fd; return KNOT_EOK; } @@ -945,7 +911,7 @@ static enum fdset_sweep_state xfr_sweep(fdset_t *set, int i, void *data) if (xfr_task_is_transfer(rq)) xfr_pending_decr(xfr); xfr_task_close(rq); - socket_close(set->pfd[i].fd); + close(set->pfd[i].fd); return FDSET_SWEEP; } @@ -1063,7 +1029,7 @@ int xfr_worker(dthread_t *thread) if (xfr_task_is_transfer(rq)) xfr_pending_decr(xfr); xfr_task_close(rq); - socket_close(set.pfd[i].fd); + close(set.pfd[i].fd); fdset_remove(&set, i); continue; /* Stay on the same index. */ } else { @@ -1093,7 +1059,7 @@ int xfr_worker(dthread_t *thread) /* Cancel existing connections. */ for (unsigned i = 0; i < set.n; ++i) { knot_ns_xfr_t *rq = (knot_ns_xfr_t *)set.ctx[i]; - socket_close(set.pfd[i].fd); + close(set.pfd[i].fd); if (xfr_task_is_transfer(rq)) xfr_pending_decr(xfr); xfr_task_free(rq); diff --git a/src/knot/server/xfr-handler.h b/src/knot/server/xfr-handler.h index 30f2cfe71732ff91dbe8850596adc0d8b2b64229..e79241535cb1775aacfdde77540edb05a6c35cc7 100644 --- a/src/knot/server/xfr-handler.h +++ b/src/knot/server/xfr-handler.h @@ -30,7 +30,7 @@ #include "common/fdset.h" #include "common/evsched.h" #include "knot/server/dthreads.h" -#include "knot/server/socket.h" +#include "knot/server/net.h" #include "libknot/packet/pkt.h" #include "knot/zone/zone.h" diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index dda05a8b0a4b62ec555b25eac4a5ff48f4b0287d..9dc89ab8ceef956fdc33ea90222f3afd1bfd6c40 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -1547,9 +1547,7 @@ int zones_schedule_notify(zone_t *zone, server_t *server) } /* Parse server address. */ - struct sockaddr_storage addr; - sockaddr_set(&addr, cfg_if->family, cfg_if->address, cfg_if->port); - xfr_task_setaddr(rq, &addr, &cfg_if->via); + xfr_task_setaddr(rq, &cfg_if->addr, &cfg_if->via); rq->data = (void *)((long)cfg->notify_retries); if (xfr_enqueue(server->xfr, rq) != KNOT_EOK) { log_zone_error("Failed to enqueue NOTIFY for '%s'.\n", diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c index ebfa51e0da0d8dcd0501e8fa36984d383b0dadd5..137341aa5f341b21b93700ad106807c2c077d73c 100644 --- a/src/knot/zone/zone.c +++ b/src/knot/zone/zone.c @@ -159,12 +159,8 @@ static int set_acl(acl_t **acl, list_t* acl_list) /* Load ACL rules. */ conf_remote_t *r = 0; WALK_LIST(r, *acl_list) { - /* Initialize address. */ - /*! Port matching disabled, port = 0. */ conf_iface_t *cfg_if = r->remote; - struct sockaddr_storage addr; - sockaddr_set(&addr, cfg_if->family, cfg_if->address, 0); - acl_insert(new_acl, &addr, cfg_if->prefix, cfg_if->key); + acl_insert(new_acl, &cfg_if->addr, cfg_if->prefix, cfg_if->key); } *acl = new_acl; @@ -186,8 +182,7 @@ static void set_xfrin_parameters(zone_t *zone, conf_zone_t *conf) conf_remote_t *master = HEAD(conf->acl.xfr_in); conf_iface_t *master_if = master->remote; - sockaddr_set(&zone->xfr_in.master, master_if->family, - master_if->address, master_if->port); + memcpy(&zone->xfr_in.master, &master_if->addr, sizeof(struct sockaddr_storage)); if (master_if->via.ss_family != AF_UNSPEC) { memcpy(&zone->xfr_in.via, &master_if->via, sizeof(struct sockaddr_storage)); } diff --git a/tests/conf.c b/tests/conf.c index b6e22be2fa013136cf2e48d2f50e91b05e8a472a..ec8737b4709780372dae1f1fe61bdecaf0947e3c 100644 --- a/tests/conf.c +++ b/tests/conf.c @@ -27,7 +27,7 @@ */ int main(int argc, char *argv[]) { - plan(21); + plan(19); // Test 1: Allocate new config const char *config_fn = "rc:/sample_conf"; @@ -48,15 +48,17 @@ int main(int argc, char *argv[]) // Test 4: Test interfaces (1-level depth) ok(!EMPTY_LIST(conf->ifaces), "configured interfaces exist"); - // Test 5,6,7,8: Interfaces content (2-level depth) + // Test 5,6: Interfaces content (2-level depth) struct node *n = HEAD(conf->ifaces); conf_iface_t *iface = (conf_iface_t*)n; - is_string("10.10.1.1", iface->address, "interface0 address check"); - is_int(53531, iface->port, "interface0 port check"); + struct sockaddr_storage addr_ref; + sockaddr_set(&addr_ref, AF_INET, "10.10.1.1", 53531); + is_int(0, sockaddr_cmp(&iface->addr, &addr_ref), "interface0 address check"); + n = n->next; iface = (conf_iface_t*)n; - is_string("::0", iface->address, "interface1 address check"); - is_int(53, iface->port, "interface1 default port check"); + sockaddr_set(&addr_ref, AF_INET6, "::0", 53); + is_int(0, sockaddr_cmp(&iface->addr, &addr_ref), "interface1 address check"); // Test 9,10: Check server key if(conf->key_count <= 0) {