Commit 908b0140 authored by Daniel Salzman's avatar Daniel Salzman

Add host skeleton

refs #2137
parent ea0147d2
......@@ -49,3 +49,4 @@ m4/ltversion.m4
m4/lt~obsolete.m4
src/unittests-xfr
INSTALL
khost
ACLOCAL_AMFLAGS = -I ../m4
libexec_PROGRAMS = knot-zcompile unittests unittests-zcompile unittests-xfr
libexec_PROGRAMS = knot-zcompile unittests unittests-zcompile unittests-xfr khost
sbin_PROGRAMS = knotc knotd
dist_man_MANS = knot.conf.5 knotc.8 knotd.8
......@@ -19,7 +19,7 @@ BUILT_SOURCES = \
libknotd_la-cf-parse.h
CLEANFILES = \
tests/sample_conf.rc \
tests/sample_conf.rc \
zparser.h \
zparser.c \
zlexer.c \
......@@ -30,6 +30,18 @@ CLEANFILES = \
knotc_SOURCES = \
knot/ctl/knotc_main.c
khost_SOURCES = \
utils/common/msg.h \
utils/common/params.c \
utils/common/params.h \
utils/common/resolv.c \
utils/common/resolv.h \
utils/host/host_main.c \
utils/host/host_params.c \
utils/host/host_params.h \
utils/host/host_exec.c \
utils/host/host_exec.h
knot_zcompile_SOURCES = \
zcompile/zcompile_main.c \
zcompile/zcompile-error.c \
......@@ -78,7 +90,7 @@ unittests_zcompile_SOURCES = \
zcompile/tests/unittests_zp_main.c
unittests_xfr_SOURCES = \
tests/xfr_tests.c \
tests/xfr_tests.c \
tests/xfr_tests.h
nodist_unittests_SOURCES = \
......@@ -210,10 +222,10 @@ libknots_la_SOURCES = \
common/log.h
libknotd_la_SOURCES = \
knot/stat/gatherer.c \
knot/stat/stat.c \
knot/stat/gatherer.h \
knot/stat/stat.h \
knot/stat/gatherer.c \
knot/stat/stat.c \
knot/stat/gatherer.h \
knot/stat/stat.h \
knot/common.h \
knot/other/debug.h \
knot/conf/cf-parse.y \
......@@ -228,29 +240,29 @@ libknotd_la_SOURCES = \
knot/ctl/remote.h \
knot/server/dthreads.c \
knot/server/journal.c \
knot/server/socket.c \
knot/server/server.c \
knot/server/udp-handler.c \
knot/server/tcp-handler.c \
knot/server/xfr-handler.c \
knot/server/zones.c \
knot/server/socket.h \
knot/server/udp-handler.h \
knot/server/tcp-handler.h \
knot/server/xfr-handler.h \
knot/server/socket.c \
knot/server/server.c \
knot/server/udp-handler.c \
knot/server/tcp-handler.c \
knot/server/xfr-handler.c \
knot/server/zones.c \
knot/server/socket.h \
knot/server/udp-handler.h \
knot/server/tcp-handler.h \
knot/server/xfr-handler.h \
knot/server/dthreads.h \
knot/server/journal.h \
knot/server/zones.h \
knot/server/notify.h \
knot/server/notify.c \
knot/server/zones.h \
knot/server/zones.h \
knot/server/notify.h \
knot/server/notify.c \
knot/server/zones.h \
knot/zone/zone-load.c \
knot/zone/zone-load.h \
knot/zone/semantic-check.c \
knot/zone/semantic-check.h \
knot/zone/zone-dump.c \
knot/zone/zone-dump-text.c \
knot/zone/zone-dump-text.h \
knot/zone/zone-dump-text.c \
knot/zone/zone-dump-text.h \
knot/zone/zone-dump.h \
knot/server/server.h
......@@ -258,6 +270,7 @@ libknotd_la_LIBADD = libknot.la libknots.la @LIBOBJS@
libknots_la_LIBADD = @LIBOBJS@
knotd_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
knotc_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
khost_LDADD = libknotd.la libknot.la libknots.la @LIBOBJS@
knot_zcompile_LDADD = libknots.la libknot.la libknotd.la @LIBOBJS@
unittests_LDADD = libknotd.la libknots.la @LIBOBJS@
unittests_zcompile_LDADD = libknot.la libknots.la libknotd.la @LIBOBJS@
......
/* 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/>.
*/
#ifndef _UTILS__MSG_H_
#define _UTILS__MSG_H_
#include <stdio.h> // printf
#define ERROR_ "Error: "
#define WARNING_ "Warning: "
#define ERR(m...) printf(ERROR_ m)
#define WARN(m...) printf(WARNING_ m)
#endif // _UTILS__MSG_H_
/* 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 "utils/common/params.h"
#include <stdlib.h> // free
#include <arpa/inet.h> // inet_pton
#include <sys/socket.h> // AF_INET (BSD)
#include <netinet/in.h> // in_addr (BSD)
#include "common/errcode.h" // KNOT_EOK
#include "libknot/util/descriptor.h" // KNOT_RRTYPE
#include "utils/common/msg.h" // WARN
#define IPV4_REVERSE_DOMAIN "in-addr.arpa."
#define IPV6_REVERSE_DOMAIN "ip6.arpa."
#define ASCII_0 48
query_t* create_query(const char *name, const uint16_t type)
{
// Create output structure.
query_t *query = calloc(1, sizeof(query_t));
// Check output.
if (query == NULL) {
return NULL;
}
// Fill output.
query->name = strdup(name);
query->type = type;
return query;
}
void query_free(query_t *query)
{
if (query == NULL) {
return;
}
free(query->name);
free(query);
}
int parse_class(const char *class, uint16_t *class_num)
{
*class_num = knot_rrclass_from_string(class);
return KNOT_EOK;
}
int parse_type(const char *type, int32_t *type_num, int64_t *ixfr_serial)
{
size_t param_pos = strcspn(type, "=");
// There is no additional parameter.
if (param_pos == strlen(type)) {
*type_num = knot_rrtype_from_string(type);
// IXFR requires serial parameter.
if (*type_num == KNOT_RRTYPE_IXFR) {
ERR("required SOA serial for IXFR type\n");
return KNOT_ERROR;
}
} else {
char *type_char = strndup(type, param_pos);
*type_num = knot_rrtype_from_string(type_char);
free(type_char);
// Additional parameter is acceptet for IXFR only.
if (*type_num == KNOT_RRTYPE_IXFR) {
const char *param_str = type + 1 + param_pos;
char *end;
// Convert string to serial.
unsigned long serial = strtoul(param_str, &end, 10);
// Check for bad serial string.
if (end == param_str || *end != '\0' ||
serial > UINT32_MAX) {
ERR("bad SOA serial\n");
return KNOT_ERROR;
}
*ixfr_serial = serial;
} else {
char buf[64] = "";
knot_rrtype_to_string(*type_num, buf, sizeof(buf));
ERR("type %s can't have a parameter\n", buf);
return KNOT_ERROR;
}
}
return KNOT_EOK;
}
char* get_reverse_name(const char *name)
{
struct in_addr addr4;
struct in6_addr addr6;
char buf[128] = "\0";
// Check name for IPv4 address, IPv6 address or other.
if (inet_pton(AF_INET, name, &addr4) == 1) {
uint32_t num = ntohl(addr4.s_addr);
// Create IPv4 reverse FQD name.
sprintf(buf, "%u.%u.%u.%u.%s",
(num >> 0) & 0xFF, (num >> 8) & 0xFF,
(num >> 16) & 0xFF, (num >> 24) & 0xFF,
IPV4_REVERSE_DOMAIN);
return strdup(buf);
} else if (inet_pton(AF_INET6, name, &addr6) == 1) {
char *pos = buf;
uint8_t left, right;
// Create IPv6 reverse name.
for (int i = 15; i >= 0; i--) {
left = ((addr6.s6_addr)[i] & 0xF0) >> 4;
right = (addr6.s6_addr)[i] & 0x0F;
pos += sprintf(pos, "%x.%x.", right, left);
}
// Add IPv6 reverse domain.
strcat(buf, IPV6_REVERSE_DOMAIN);
return strdup(buf);
} else {
return NULL;
}
}
/* 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 host_params.h
*
* \author Daniel Salzman <daniel.salzman@nic.cz>
*
* \brief Host command line parameters.
*
* \addtogroup utils
* @{
*/
#ifndef _UTILS__PARAMS_H_
#define _UTILS__PARAMS_H_
#include <stdbool.h>
#include <stdint.h>
#include "common/lists.h" // node
#define DEFAULT_UDP_SIZE 512
#define MAX_PACKET_SIZE 65535
/*! \brief Structure containing basic parameters for DNS query. */
typedef struct {
/*!< List node (for list container). */
node n;
/*!< Name to query on. */
char *name;
/*!< Type number to query on. */
uint16_t type;
} query_t;
typedef enum {
IP_ALL,
IP_4,
IP_6
} ip_version_t;
typedef enum {
PROTO_ALL,
PROTO_TCP,
PROTO_UDP
} protocol_t;
query_t* create_query(const char *name, const uint16_t type);
void query_free(query_t *query);
int parse_class(const char *class, uint16_t *class_num);
int parse_type(const char *type, int32_t *type_num, int64_t *ixfr_serial);
char* get_reverse_name(const char *name);
#endif // _UTILS__PARAMS_H_
/*! @} */
/* 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 "utils/common/resolv.h"
#include <stdio.h> // fopen
#include <stdlib.h> // free
#include "common/errcode.h" // KNOT_ENOENT
#include "common/lists.h" // list
#define RESOLV_FILE "/etc/resolv.conf"
#define SEP_CHARS "\n\t "
server_t* create_server(const char *name, const char *service)
{
// Create output structure.
server_t *server = calloc(1, sizeof(server_t));
// Check output.
if (server == NULL) {
return NULL;
}
// Fill output.
server->name = strdup(name);
server->service = strdup(service);
// Return result.
return server;
}
server_t* parse_nameserver(const char *nameserver)
{
char addr[128];
char port[64];
// Fill nameserver address and port.
strncpy(addr, nameserver, sizeof(addr));
addr[sizeof(addr) - 1] = '\0';
strcpy(port, DEFAULT_DNS_PORT);
// OpenBSD address + port notation: nameserver [address]:port
if (nameserver[0] == '[') {
char *start = (char *)nameserver + 1;
char *end = index(nameserver, ']');
// Missing closing bracket -> stop processing.
if (end == NULL) {
return NULL;
}
// Fill enclosed address.
strncpy(addr, start, end - start);
addr[end - start] = '\0';
// Find possible port.
start = index(end, ':') + 1;
// Check port occurence.
if (start != NULL) {
// Check port string length.
if (strlen(start) >= sizeof(port)) {
return NULL;
}
// Fill port part.
strcpy(port, start);
}
}
return create_server(addr, port);
}
static int get_resolv_nameservers(list *servers)
{
char line[512];
// Open config file.
FILE *f = fopen(RESOLV_FILE, "r");
// Check correct open.
if (f == NULL) {
return KNOT_ENOENT;
}
// Read lines from config file.
while (fgets(line, sizeof(line), f) != NULL) {
size_t len;
char *pos = line;
char *option, *value;
// Find leading white characters.
len = strspn(pos, SEP_CHARS);
pos += len;
// Start of the first token.
option = pos;
// Find length of the token.
len = strcspn(pos, SEP_CHARS);
pos += len;
// Check if the token is not empty.
if (len <= 0) {
continue;
}
// Find separating white characters.
len = strspn(pos, SEP_CHARS);
pos += len;
// Check if there is a separation between tokens.
if (len <= 0) {
continue;
}
// Copy of the second token.
value = strndup(pos, strcspn(pos, SEP_CHARS));
// Process value with respect to option name.
if (strncmp(option, "nameserver", strlen("nameserver")) == 0) {
server_t *server = parse_nameserver(value);
// If value is correct, add nameserver to the list.
if (server != NULL) {
add_tail(servers, (node *)server);
}
}
// Drop value string.
free(value);
}
// Close config file.
fclose(f);
// Return number of servers.
return list_size(servers);
}
int get_nameservers(list *servers)
{
int ret;
// Initialize list of servers.
init_list(servers);
// Read nameservers from resolv file.
ret = get_resolv_nameservers(servers);
// If found nameservers or error.
if (ret != 0) {
return ret;
// If no nameservers.
} else {
server_t *server;
// Add default ipv6 nameservers.
server = create_server(DEFAULT_IPV6_NAME, DEFAULT_DNS_PORT);
if (server != NULL) {
add_tail(servers, (node *)server);
}
// Add default ipv4 nameservers.
server = create_server(DEFAULT_IPV4_NAME, DEFAULT_DNS_PORT);
if (server != NULL) {
add_tail(servers, (node *)server);
}
return list_size(servers);
}
}
void server_free(server_t *server)
{
free(server->name);
free(server->service);
free(server);
}
/* 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 resolv.h
*
* \author Daniel Salzman <daniel.salzman@nic.cz>
*
* \brief resolv.conf processing.
*
* \addtogroup utils
* @{
*/
#ifndef _UTILS__RESOLV_H_
#define _UTILS__RESOLV_H_
#include "common/lists.h" // node
#define DEFAULT_IPV4_NAME "127.0.0.1"
#define DEFAULT_IPV6_NAME "::1"
#define DEFAULT_DNS_PORT "53"
/*! \brief Structure containing nameserver information. */
typedef struct {
/*!< List node (for list container). */
node n;
/*!< Name or address of the server. */
char *name;
/*!< Name or numbers of the service. */
char *service;
} server_t;
server_t* create_server(const char *name, const char *service);
void server_free(server_t *server);
server_t* parse_nameserver(const char *nameserver);
int get_nameservers(list *servers);
#endif // _UTILS__RESOLV_H_
/*! @} */
/* 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 "utils/host/host_exec.h"
#include <stdlib.h> // free
#include <fcntl.h> // fcntl
#include <netdb.h> // addrinfo
#include <sys/socket.h> // AF_INET (BSD)
#include "common/lists.h" // list
#include "common/errcode.h" // KNOT_EOK
#include "libknot/util/wire.h" // knot_wire_set_rd
#include "libknot/util/descriptor.h" // KNOT_CLASS_IN
#include "libknot/packet/packet.h" // packet_t
#include "libknot/packet/query.h" // knot_query_init
#include "utils/common/msg.h" // WARN
#include "utils/common/resolv.h" // server_t
#include "utils/host/host_params.h" // host_params_t
static bool use_tcp(const host_params_t *params, const uint16_t type)
{
switch (params->protocol) {
case PROTO_TCP:
return true;
case PROTO_UDP:
if (type == KNOT_RRTYPE_AXFR || type == KNOT_RRTYPE_IXFR) {
WARN("using UDP for zone transfer\n");
}
return false;
default:
if (type == KNOT_RRTYPE_AXFR || type == KNOT_RRTYPE_IXFR) {
return true;
} else {
return false;
}
}
}
static bool use_recursion(const host_params_t *params, const uint16_t type)
{
if (type == KNOT_RRTYPE_AXFR || type == KNOT_RRTYPE_IXFR) {
return false;
} else {
if (params->recursion == true) {
return true;
} else {
return false;
}
}
}
static knot_packet_t* create_query_packet(const host_params_t *params,
const query_t *query)
{
knot_question_t q;
// Create packet skeleton.
knot_packet_t *packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
if (packet == NULL) {
return NULL;
}
// Set packet buffer size.
if (use_tcp(params, query->type) == true) {
// For TCP maximal dns packet size.
knot_packet_set_max_size(packet, MAX_PACKET_SIZE);
} else {
// For UDP default or specified EDNS size.
knot_packet_set_max_size(packet, params->udp_size);
}
// Set random sequence id.
knot_packet_set_random_id(packet);
// Initialize query packet.
knot_query_init(packet);
// Set recursion bit to wireformat.
if (use_recursion(params, query->type) == true) {
knot_wire_set_rd(packet->wireformat);
} else {
knot_wire_flags_clear_rd(packet->wireformat);
}
// Fill auxiliary question structure.
q.qclass = params->class_num;
q.qtype = query->type;
q.qname = knot_dname_new_from_str(query->name, strlen(query->name), 0);
if (q.qname == NULL) {
knot_dname_release(q.qname);
knot_packet_free(&packet);
return NULL;
}
// Set packet question.
if (knot_query_set_question(packet, &q) != KNOT_EOK) {
knot_dname_release(q.qname);
knot_packet_free(&packet);
return NULL;
}
// For IXFR add authority section.
if (query->type == KNOT_RRTYPE_IXFR) {
// knot_node_t *node = knot_node_new(q.qname, NULL, 0);
// const knot_rrset_t *soa = knot_node_rrset(node, KNOT_RRTYPE_SOA);
const knot_rrset_t *soa = knot_rrset_new(q.qname, KNOT_RRTYPE_SOA, params->class_num, 0);
knot_query_add_rrset_authority(packet, soa);
}
knot_dname_release(q.qname);
return packet;
}
static int process_query(const host_params_t *params, const query_t *query)
{
uint8_t *buf = NULL;
size_t buflen = 0;
node *server = NULL;
knot_packet_t *packet = create_query_packet