Skip to content
Snippets Groups Projects
Commit 908b0140 authored by Daniel Salzman's avatar Daniel Salzman
Browse files

Add host skeleton

refs #2137
parent ea0147d2
No related branches found
No related tags found
No related merge requests found
......@@ -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(params, (query_t *)query);
if (packet == NULL) {
printf("NULL");
}
knot_packet_to_wire(packet, &buf, &buflen);
WALK_LIST(server, params->servers) {
server_t *srv = (server_t *)server;
struct addrinfo hints, *res;
int sockfd;
memset(&hints, 0, sizeof hints);
if (params->ip == IP_4) {
hints.ai_family = AF_INET;
} else if (params->ip == IP_6) {
hints.ai_family = AF_INET6;
} else {
hints.ai_family = AF_UNSPEC;
}
if (use_tcp(params, query->type) == true) {
hints.ai_socktype = SOCK_STREAM;
} else {
hints.ai_socktype = SOCK_DGRAM;
}
if (getaddrinfo(srv->name, srv->service, &hints, &res) != 0) {
WARN("can't use nameserver %s(%s)\n",
srv->name, srv->service);
continue;
}
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) {
WARN("can't create socket for nameserver %s(%s)\n",
srv->name, srv->service);
continue;
}
fcntl(sockfd, F_SETFL, O_NONBLOCK);
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == -1 &&
errno != EINPROGRESS) {
WARN("can't connect to nameserver %s(%s) - %s\n",
srv->name, srv->service, strerror(errno));
continue;
}
fd_set wfds;
struct timeval tv;
FD_ZERO(&wfds);
FD_SET(sockfd, &wfds);
tv.tv_sec = DEFAULT_WAIT_INTERVAL;
tv.tv_usec = 0;
int retval = select(sockfd + 1, NULL, &wfds, NULL, &tv);
if (retval == -1 || !FD_ISSET(sockfd, &wfds)) {
WARN("can't connect to %s\n", srv->name);
fflush(stdout);
shutdown(sockfd, 2);
continue;
}
int n = send(sockfd, buf, buflen, 0);
if (n != buflen) {
WARN("can't send query\n");
}
shutdown(sockfd, 2);
}
knot_packet_free(&packet);
return KNOT_EOK;
}
int host_exec(const host_params_t *params)
{
node *query = NULL;
if (params == NULL) {
return KNOT_EINVAL;
}
switch (params->mode) {
case HOST_MODE_DEFAULT:
WALK_LIST(query, params->queries) {
process_query(params, (query_t *)query);
}
break;
case HOST_MODE_LIST_SERIALS:
break;
}
return KNOT_EOK;
}
/* 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_exec.h
*
* \author Daniel Salzman <daniel.salzman@nic.cz>
*
* \brief
*
* \addtogroup knot_utils
* @{
*/
#ifndef _HOST__HOST_EXEC_H_
#define _HOST__HOST_EXEC_H_
#include <stdbool.h> // bool
#include <stdint.h> // uint16_t
#include "utils/host/host_params.h"
int host_exec(const host_params_t *params);
#endif // _HOST__HOST_EXEC_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 <stdlib.h> // EXIT_FAILURE
#include "common/errcode.h" // KNOT_EOK
#include "utils/host/host_params.h" // host_params_t
#include "utils/host/host_exec.h" // host_exec
int main(int argc, char *argv[])
{
host_params_t params;
if (host_params_parse(&params, argc, argv) != KNOT_EOK) {
return EXIT_FAILURE;
}
host_exec(&params);
host_params_clean(&params);
return EXIT_SUCCESS;
}
/* 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_params.h"
#include <string.h> // strncmp
#include <stdio.h> // printf
#include <getopt.h> // getopt
#include <stdlib.h> // free
#include "common/lists.h" // list
#include "common/errcode.h" // KNOT_EOK
#include "libknot/util/descriptor.h" // KNOT_CLASS_IN
#include "utils/common/msg.h" // WARN
#include "utils/common/params.h" // parse_class
#include "utils/common/resolv.h" // get_nameservers
static void host_params_init(host_params_t *params)
{
memset(params, 0, sizeof(*params));
// Read default nameservers.
if (get_nameservers(&params->servers) <= 0) {
WARN("can't read any default nameservers\n");
}
// Initialize list of queries.
init_list(&params->queries);
// Default values.
params->mode = HOST_MODE_DEFAULT;
params->ip = IP_ALL;
params->protocol = PROTO_ALL;
params->udp_size = DEFAULT_UDP_SIZE;
params->class_num = KNOT_CLASS_IN;
params->type_num = -1;
params->ixfr_serial = -1;
params->recursion = true;
params->retries = 1;
params->wait = DEFAULT_WAIT_INTERVAL;
params->servfail_stop = false;
params->verbose = false;
}
void host_params_clean(host_params_t *params)
{
node *n = NULL, *nxt = NULL;
if (params == NULL) {
return;
}
// Clean up server list.
WALK_LIST_DELSAFE(n, nxt, params->servers) {
server_free((server_t *)n);
}
// Clean up query list.
WALK_LIST_DELSAFE(n, nxt, params->queries) {
query_free((query_t *)n);
}
// Clean up the structure.
memset(params, 0, sizeof(*params));
}
static void host_params_flag_all(host_params_t *params)
{
params->type_num = KNOT_RRTYPE_ANY;
params->verbose = true;
}
static void host_params_flag_soa(host_params_t *params)
{
params->type_num = KNOT_RRTYPE_SOA;
params->mode = HOST_MODE_LIST_SERIALS;
}
static void host_params_flag_axfr(host_params_t *params)
{
params->type_num = KNOT_RRTYPE_AXFR;
}
static void host_params_flag_nonrecursive(host_params_t *params)
{
params->recursion = false;
}
static void host_params_flag_tcp(host_params_t *params)
{
params->protocol = PROTO_TCP;
}
static void host_params_flag_ipv4(host_params_t *params)
{
params->ip = IP_4;
}
static void host_params_flag_ipv6(host_params_t *params)
{
params->ip = IP_6;
}
static void host_params_flag_servfail(host_params_t *params)
{
params->servfail_stop = true;
}
static void host_params_flag_verbose(host_params_t *params)
{
params->verbose = true;
}
static void host_params_flag_nowait(host_params_t *params)
{
params->wait = 0;
}
static int host_params_parse_retries(const char *value, uint32_t *retries)
{
char *end;
// Convert string to number.
unsigned long num = strtoul(value, &end, 10);
// Check for bad string.
if (end == value || *end != '\0' || num > UINT32_MAX) {
ERR("bad retries value\n");
return KNOT_ERROR;
}
*retries = num;
return KNOT_EOK;
}
static int host_params_parse_wait(const char *value, uint32_t *wait)
{
char *end;
// Convert string to number.
unsigned long num = strtoul(value, &end, 10);
// Check for bad string.
if (end == value || *end != '\0' || num > UINT32_MAX) {
ERR("bad wait value\n");
return KNOT_ERROR;
}
*wait = num;
return KNOT_EOK;
}
static int host_params_parse_name(host_params_t *params, const char *name)
{
char *reverse = get_reverse_name(name);
query_t *query;
// RR type is known.
if (params->type_num >= 0) {
if (params->type_num == KNOT_RRTYPE_PTR) {
// Check for correct address.
if (reverse == NULL) {
ERR("invalid IPv4 or IPv6 address");
return KNOT_EINVAL;
}
// Add reverse query for address.
query = create_query(reverse, params->type_num);
if (query == NULL) {
free(reverse);
return KNOT_ENOMEM;
}
add_tail(&params->queries, (node *)query);
} else {
// Add query for name and specified type.
query = create_query(name, params->type_num);
if (query == NULL) {
free(reverse);
return KNOT_ENOMEM;
}
add_tail(&params->queries, (node *)query);
}
// RR type is unknown, use defaults.
} else {
if (reverse == NULL) {
// Add query for name and type A.
query = create_query(name, KNOT_RRTYPE_A);
if (query == NULL) {
return KNOT_ENOMEM;
}
add_tail(&params->queries, (node *)query);
// Add query for name and type AAAA.
query = create_query(name, KNOT_RRTYPE_AAAA);
if (query == NULL) {
return KNOT_ENOMEM;
}
add_tail(&params->queries, (node *)query);
// Add query for name and type MX.
query = create_query(name, KNOT_RRTYPE_MX);
if (query == NULL) {
return KNOT_ENOMEM;
}
add_tail(&params->queries, (node *)query);
} else {
// Add reverse query for address.
query = create_query(reverse, KNOT_RRTYPE_PTR);
if (query == NULL) {
free(reverse);
return KNOT_ENOMEM;
}
add_tail(&params->queries, (node *)query);
}
}
// Dealloc possible reverse name.
free(reverse);
return KNOT_EOK;
}
static int host_params_parse_server(host_params_t *params, const char *name)
{
node *n = NULL, *nxt = NULL;
// Remove default nameservers.
WALK_LIST_DELSAFE(n, nxt, params->servers) {
server_free((server_t *)n);
}
// Initialize blank server list.
init_list(&params->servers);
// Add specified nameserver.
server_t *server = parse_nameserver(name);
if (server == NULL) {
return KNOT_ENOMEM;
}
add_tail(&params->servers, (node *)server);
return KNOT_EOK;
}
static void host_params_help(int argc, char *argv[])
{
// Not updated!
printf("Usage: %s [-aCdvlrT] [-4] [-6] [-c class] [-t type] {name} [server]\n", argv[0]);
}
int host_params_parse(host_params_t *params, int argc, char *argv[])
{
int opt = 0;
if (params == NULL || argv == NULL) {
return KNOT_EINVAL;
}
host_params_init(params);
// Command line options processing.
while ((opt = getopt(argc, argv, "aClrT46swR:W:c:t:dv")) != -1) {
switch (opt) {
case 'a':
host_params_flag_all(params);
break;
case 'C':
host_params_flag_soa(params);
break;
case 'l':
host_params_flag_axfr(params);
break;
case 'r':
host_params_flag_nonrecursive(params);
break;
case 'T':
host_params_flag_tcp(params);
break;
case '4':
host_params_flag_ipv4(params);
break;
case '6':
host_params_flag_ipv6(params);
break;
case 's':
host_params_flag_servfail(params);
break;
case 'w':
host_params_flag_nowait(params);
break;
case 'R':
if (host_params_parse_retries(optarg,
&(params->retries))
!= KNOT_EOK) {
return KNOT_EINVAL;
}
break;
case 'W':
if (host_params_parse_wait(optarg, &(params->wait))
!= KNOT_EOK) {
return KNOT_EINVAL;
}
break;
case 'c':
if (parse_class(optarg, &(params->class_num))
!= KNOT_EOK) {
return KNOT_EINVAL;
}
break;
case 't':
if (parse_type(optarg, &(params->type_num),
&(params->ixfr_serial))
!= KNOT_EOK) {
return KNOT_EINVAL;
}
break;
case 'd':
case 'v': // Fall through.
host_params_flag_verbose(params);
break;
default:
host_params_help(argc, argv);
return KNOT_ENOTSUP;
}
}
// Process non-option parameters.
switch (argc - optind) {
case 2:
if (host_params_parse_server(params, argv[optind + 1])
!= KNOT_EOK) {
return KNOT_EINVAL;
}
case 1: // Fall through.
if (host_params_parse_name(params, argv[optind])
!= KNOT_EOK) {
return KNOT_EINVAL;
}
break;
default:
host_params_help(argc, argv);
return KNOT_ENOTSUP;
}
return KNOT_EOK;
}
/* 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 knot_utils
* @{
*/
#ifndef _HOST__HOST_PARAMS_H_
#define _HOST__HOST_PARAMS_H_
#include <stdbool.h>
#include <stdint.h>
#include "common/lists.h" // list
#include "utils/common/params.h" // protocol_t
#define DEFAULT_WAIT_INTERVAL 1
/*! \brief Types of host operation mode. */
typedef enum {
/*!< Classic query for name-class-type. */
HOST_MODE_DEFAULT,
/*!< Query for NS and all authoritative SOA records. */
HOST_MODE_LIST_SERIALS,
} host_mode_t;
/*! \brief Structure containing parameters for host. */
typedef struct {
/*!< List of nameservers to query to. */
list servers;
/*!< List of DNS queries to process. */
list queries;
/*!< Operation mode. */
host_mode_t mode;
/*!< Version of ip protocol to use. */
ip_version_t ip;
/*!< Type (TCP, UDP) protocol to use. */
protocol_t protocol;
/*!< Default class number. */
uint16_t class_num;
/*!< Default type number (16unsigned + -1 uninitialized). */
int32_t type_num;
/*!< SOA serial for IXFR query (32unsigned + -1 uninitialized). */
int64_t ixfr_serial;
/*!< Use recursion. */
bool recursion;
/*!< UDP buffer size. */
uint32_t udp_size;
/*!< Number of UDP retries. */
uint32_t retries;
/*!< Wait for reply in seconds (0 means forever). */
uint32_t wait;
/*!< Stop quering if servfail. */
bool servfail_stop;
/*!< Verbose mode. */
bool verbose;
} host_params_t;
int host_params_parse(host_params_t *params, int argc, char *argv[]);
void host_params_clean(host_params_t *params);
#endif // _HOST__HOST_PARAMS_H_
/*! @} */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment