#include "ldns/ldns.h"
-/** default port to listen for queries, passed to getaddrinfo */
-#define UNBOUND_DNS_PORT "53"
+/** default port for DNS traffic. */
+#define UNBOUND_DNS_PORT 53
])
AC_CONFIG_FILES([Makefile])
printf(" start unbound daemon DNS resolver.\n");
printf("-h this help\n");
printf("-c file config file to read, unbound.conf(5).\n");
- printf("-p port the port to listen on\n");
printf("-v verbose (multiple times increase verbosity)\n");
- printf("-f ip set forwarder address\n");
- printf("-z port set forwarder port\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
}
+/**
+ * Run the daemon.
+ * @param cfgfile: the config file name.
+ * @param cmdline_verbose: verbosity resulting from commandline -v.
+ * These increase verbosity as specified in the config file.
+ */
+static void run_daemon(const char* cfgfile, int cmdline_verbose)
+{
+ struct worker* worker = NULL;
+ struct config_file *cfg = NULL;
+
+ if(!(cfg = config_create())) {
+ fprintf(stderr, "Could not init config defaults.");
+ exit(1);
+ }
+ if(cfgfile) {
+ if(!config_read(cfg, cfgfile)) {
+ config_delete(cfg);
+ exit(1);
+ }
+ verbosity = cmdline_verbose + cfg->verbosity;
+ }
+ log_info("Start of %s.", PACKAGE_STRING);
+
+ /* setup */
+ worker = worker_init(cfg, BUFSZ);
+ if(!worker) {
+ fatal_exit("could not initialize");
+ }
+
+ /* drop user priviliges and chroot if needed */
+ log_info("start of service (%s).", PACKAGE_STRING);
+ worker_work(worker);
+
+ /* cleanup */
+ verbose(VERB_ALGO, "Exit cleanup.");
+ worker_delete(worker);
+}
+
/** getopt global, in case header files fail to declare it. */
extern int optind;
/** getopt global, in case header files fail to declare it. */
int
main(int argc, char* argv[])
{
- struct worker* worker = NULL;
- int do_ip4=1, do_ip6=1, do_udp=1, do_tcp=1;
- size_t numports=3;
- int baseport=10000;
- const char* port = UNBOUND_DNS_PORT;
int c;
- const char* fwd = "127.0.0.1";
- const char* fwdport = UNBOUND_DNS_PORT;
const char* cfgfile = NULL;
- struct config_file *cfg = NULL;
+ int cmdline_verbose = 0;
log_init();
/* parse the options */
- while( (c=getopt(argc, argv, "c:f:hvp:z:")) != -1) {
+ while( (c=getopt(argc, argv, "c:hv")) != -1) {
switch(c) {
case 'c':
cfgfile = optarg;
break;
- case 'f':
- fwd = optarg;
- break;
- case 'z':
- fwdport = optarg;
- break;
- case 'p':
- if(!atoi(optarg))
- fatal_exit("invalid port '%s'", optarg);
- port = optarg;
- baseport = atoi(optarg)+2000;
- verbose(VERB_ALGO, "using port: %s", port);
- break;
case 'v':
- verbosity ++;
+ cmdline_verbose ++;
+ verbosity++;
break;
case '?':
case 'h':
return 1;
}
- if(!(cfg = config_create())) {
- fprintf(stderr, "Could not init config defaults.");
- return 1;
- }
- if(cfgfile) {
- if(!config_read(cfg, cfgfile)) {
- config_delete(cfg);
- return 1;
- }
- }
- log_info("Start of %s.", PACKAGE_STRING);
-
- /* setup */
- worker = worker_init(port, do_ip4, do_ip6, do_udp, do_tcp, BUFSZ,
- numports, baseport);
- if(!worker) {
- fatal_exit("could not initialize");
- }
- if(!worker_set_fwd(worker, fwd, fwdport)) {
- worker_delete(worker);
- fatal_exit("could not set forwarder address");
- }
-
- /* drop user priviliges and chroot if needed */
- log_info("start of service (%s).", PACKAGE_STRING);
- worker_work(worker);
-
- /* cleanup */
- verbose(VERB_ALGO, "Exit cleanup.");
- worker_delete(worker);
+ run_daemon(cfgfile, cmdline_verbose);
return 0;
}
#include "util/net_help.h"
#include "daemon/worker.h"
#include "util/netevent.h"
+#include "util/config_file.h"
#include "services/listen_dnsport.h"
#include "services/outside_network.h"
}
struct worker*
-worker_init(const char* port, int do_ip4, int do_ip6, int do_udp, int do_tcp,
- size_t buffer_size, size_t numports, int base_port)
+worker_init(struct config_file *cfg, size_t buffer_size)
{
struct worker* worker = (struct worker*)calloc(1,
sizeof(struct worker));
worker_delete(worker);
return NULL;
}
- worker->front = listen_create(worker->base, 0, NULL, port,
- do_ip4, do_ip6, do_udp, do_tcp, buffer_size,
- worker_handle_request, worker);
+ worker->front = listen_create(worker->base, 0, NULL, cfg->port,
+ cfg->do_ip4, cfg->do_ip6, cfg->do_udp, cfg->do_tcp,
+ buffer_size, worker_handle_request, worker);
if(!worker->front) {
log_err("could not create listening sockets");
worker_delete(worker);
return NULL;
}
worker->back = outside_network_create(worker->base,
- buffer_size, numports, NULL, 0, do_ip4, do_ip6, base_port);
+ buffer_size, (size_t)cfg->outgoing_num_ports, NULL, 0,
+ cfg->do_ip4, cfg->do_ip6, cfg->outgoing_base_port);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);
worker_delete(worker);
return NULL;
}
+ /* set forwarder address */
+ if(cfg->fwd_address && cfg->fwd_address[0]) {
+ if(!worker_set_fwd(worker, cfg->fwd_address, cfg->fwd_port)) {
+ worker_delete(worker);
+ fatal_exit("could not set forwarder address");
+ }
+ }
return worker;
}
}
int
-worker_set_fwd(struct worker* worker, const char* ip, const char* port)
+worker_set_fwd(struct worker* worker, const char* ip, int port)
{
uint16_t p;
log_assert(worker && ip);
- if(port)
- p = (uint16_t)atoi(port);
- else p = (uint16_t)atoi(UNBOUND_DNS_PORT);
- if(!p) {
- log_err("Bad port number %s", port?port:"default_port");
- return 0;
- }
+ p = (uint16_t) port;
if(str_is_ip6(ip)) {
struct sockaddr_in6* sa =
(struct sockaddr_in6*)&worker->fwd_addr;
#include "util/netevent.h"
struct listen_dnsport;
struct outside_network;
+struct config_file;
/** size of table used for random numbers. large to be more secure. */
#define RND_STATE_SIZE 256
/**
* Initialize worker.
* Allocates event base, listens to ports
- * @param port: the port number to bind to.
- * @param do_ip4: listen to ip4 queries.
- * @param do_ip6: listen to ip6 queries.
- * @param do_udp: listen to udp queries.
- * @param do_tcp: listen to tcp queries.
+ * @param cfg: configuration settings.
* @param buffer_size: size of datagram buffer.
- * @param numports: number of outgoing ports.
- * @param base_port: -1 or specify base of outgoing port range.
* @return: The worker, or NULL on error.
*/
-struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
- int do_udp, int do_tcp, size_t buffer_size, size_t numports,
- int base_port);
+struct worker* worker_init(struct config_file *cfg, size_t buffer_size);
/**
* Make worker work.
* @param port: port on server or NULL for default 53.
* @return: false on error.
*/
-int worker_set_fwd(struct worker* worker, const char* ip, const char* port);
+int worker_set_fwd(struct worker* worker, const char* ip, int port);
#endif /* DAEMON_WORKER_H */
+22 February 2007: Wouter
+ - Have a config file. Removed commandline options, moved to config.
+ - tests use config file.
+
21 February 2007: Wouter
- put -c option in man page.
- minievent fd array capped by FD_SETSIZE.
--- /dev/null
+#
+# Example configuration file.
+#
+# See unbound.conf(5) man page.
+#
+# this is a comment.
+
+#Use this to include other text into the file.
+#include: "otherfile.conf"
+
+# The server clause sets the main parameters.
+server:
+ # whitespace is not necessary, but looks cleaner.
+
+ # verbosity number, 0 is least verbose.
+ verbosity: 2
+
+ # number of threads to create. 1 disables threading.
+ # num-threads: 1
+
+ # port to answer queries from
+ # port: 53
+
+ # unbound needs to send packets to authoritative nameservers.
+ # it uses a range of ports for that.
+ # the start number of the port range
+ # outgoing-port: 1053
+
+ # number of port to allocate per thread, determines the size of the
+ # port range. A larger port range gives more resistance to certain
+ # spoof attacks, as it gets harder to guess which port is used.
+ # But also takes more system resources (for open sockets).
+ # outgoing-range: 16
+
+ # Enable IPv4, "yes" or "no".
+ # do-ip4: yes
+
+ # Enable IPv6, "yes" or "no".
+ # do-ip6: yes
+
+ # Enable UDP, "yes" or "no".
+ # do-udp: yes
+
+ # Enable TCP, "yes" or "no".
+ # do-tcp: yes
+
+ # Set this to configure unbound to act as a forwarder. All queries are
+ # sent to the remote nameserver that will resolve them.
+ # Set to "" to disable forwarding, or give ip-address to enable.
+ # forward-to: ""
+
+ # The port number to send forwarded queries to.
+ # forward-to-port: 53
+
.Nm unbound
.Op Fl h
.Op Fl c Ar cfgfile
-.Op Fl p Ar port
-.Op Fl f Ar ip
-.Op Fl z Ar port
.Op Fl v
.Sh DESCRIPTION
described in
.Xr unbound.conf 5 .
-.It Fl p Ar port
-Start listening on the given port. Default is port 53(DNS).
-
-.It Fl f Ar ip
-Set forwarder address. DNS queries will be forwarded to this server.
-
-.It Fl z Ar ip
-Set forwarder port. DNS queries will be forwarded to this port.
-
.It Fl v
Increase verbosity. If given multiple times, more information is logged.
+This is in addition to the verbosity (if any) from the config file.
.El
.Sh SEE ALSO
output per query. Level 3 gives algorithm level information.
.It \fBnum-threads:\fR <number>
The number of threads to create to serve clients. Use 1 for no threading.
+.It \fBport:\fR <port number>
+The port number, default 53, on which the server responds to queries.
+.It \fBoutgoing-port:\fR <port number>
+The starting port number where the outgoing query port range is allocated.
+Default is 1053.
+.It \fBoutgoing-range:\fR <number>
+Number of ports to open. This number is opened per thread for every outgoing
+query interface. Must be at least 1. Default is 16.
+Larger numbers give more protection against spoofing attempts, but need
+extra resources from the operating system.
+.It \fBdo-ip4:\fR <yes or no>
+Enable or disable whether ip4 queries are answered. Default is yes.
+.It \fBdo-ip6:\fR <yes or no>
+Enable or disable whether ip6 queries are answered. Default is yes.
+.It \fBdo-udp:\fR <yes or no>
+Enable or disable whether UDP queries are answered. Default is yes.
+.It \fBdo-tcp:\fR <yes or no>
+Enable or disable whether TCP queries are answered. Default is yes.
+.It \fBforward-to:\fR <ip address>
+If set (not "") then forwarder mode is enabled. Default is "" (disabled).
+The ip address is used to forward all DNS queries to.
+.It \fBforward-to-port:\fR <port number>
+The port on which the remote server is running that answers forwarded queries.
+Default is 53.
.Sh FILES
.Bl -tag -width indent
struct listen_dnsport*
listen_create(struct comm_base* base, int num_ifs, const char* ifs[],
- const char* port, int do_ip4, int do_ip6, int do_udp, int do_tcp,
+ int port, int do_ip4, int do_ip6, int do_udp, int do_tcp,
size_t bufsize, comm_point_callback_t* cb, void *cb_arg)
{
struct addrinfo hints;
int i;
+ char portbuf[10];
struct listen_dnsport* front = (struct listen_dnsport*)
malloc(sizeof(struct listen_dnsport));
if(!front)
return NULL;
+ snprintf(portbuf, sizeof(portbuf), "%d", port);
front->cps = NULL;
front->udp_buff = ldns_buffer_new(bufsize);
if(!front->udp_buff) {
if(num_ifs == 0) {
if(do_ip6) {
hints.ai_family = AF_INET6;
- if(!listen_create_if(NULL, front, base, port,
+ if(!listen_create_if(NULL, front, base, portbuf,
do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) {
listen_delete(front);
return NULL;
}
if(do_ip4) {
hints.ai_family = AF_INET;
- if(!listen_create_if(NULL, front, base, port,
+ if(!listen_create_if(NULL, front, base, portbuf,
do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) {
listen_delete(front);
return NULL;
if(!do_ip6)
continue;
hints.ai_family = AF_INET6;
- if(!listen_create_if(ifs[i], front, base, port,
+ if(!listen_create_if(ifs[i], front, base, portbuf,
do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) {
listen_delete(front);
return NULL;
if(!do_ip4)
continue;
hints.ai_family = AF_INET;
- if(!listen_create_if(ifs[i], front, base, port,
+ if(!listen_create_if(ifs[i], front, base, portbuf,
do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) {
listen_delete(front);
return NULL;
* @return: the malloced listening structure, ready for use. NULL on error.
*/
struct listen_dnsport* listen_create(struct comm_base* base,
- int num_ifs, const char* ifs[], const char* port,
+ int num_ifs, const char* ifs[], int port,
int do_ip4, int do_ip6, int do_udp, int do_tcp,
size_t bufsize, comm_point_callback_t* cb, void* cb_arg);
struct listen_dnsport*
listen_create(struct comm_base* base, int ATTR_UNUSED(num_ifs),
- const char* ATTR_UNUSED(ifs[]), const char* ATTR_UNUSED(port),
+ const char* ATTR_UNUSED(ifs[]), int ATTR_UNUSED(port),
int ATTR_UNUSED(do_ip4), int ATTR_UNUSED(do_ip6),
int ATTR_UNUSED(do_udp), int ATTR_UNUSED(do_tcp),
size_t bufsize, comm_point_callback_t* cb, void* cb_arg)
/* the defaults if no config is present */
cfg->verbosity = 1;
cfg->num_threads = 1;
+ cfg->port = UNBOUND_DNS_PORT;
+ cfg->do_ip4 = 1;
+ cfg->do_ip6 = 1;
+ cfg->do_udp = 1;
+ cfg->do_tcp = 1;
+ cfg->outgoing_base_port = cfg->port + 1000;
+ cfg->outgoing_num_ports = 16;
+ cfg->fwd_address = strdup("");
+ if(!cfg->fwd_address) {
+ free(cfg);
+ return NULL;
+ }
+ cfg->fwd_port = UNBOUND_DNS_PORT;
return cfg;
}
/** number of threads to create */
int num_threads;
+ /** port on which queries are answered. */
+ int port;
+ /** do ip4 query support. */
+ int do_ip4;
+ /** do ip6 query support. */
+ int do_ip6;
+ /** do udp query support. */
+ int do_udp;
+ /** do tcp query support. */
+ int do_tcp;
+
+ /** outgoing port range base number */
+ int outgoing_base_port;
+ /** outgoing port range number of ports (per thread, per if) */
+ int outgoing_num_ports;
+
/** forwarder address. string. If not NULL fwder mode is enabled. */
char* fwd_address;
/** forwarder port */
server{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;}
num-threads{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NUM_THREADS;}
verbosity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;}
+port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PORT;}
+outgoing-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_PORT;}
+outgoing-range{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_RANGE;}
+do-ip4{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;}
+do-ip6{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;}
+do-udp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_UDP;}
+do-tcp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_TCP;}
+forward-to{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_FORWARD_TO;}
+forward-to-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_FORWARD_TO_PORT;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */
%token SPACE LETTER NEWLINE COMMENT COLON ANY ZONESTR
%token <str> STRING
-%token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS
+%token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT
+%token VAR_OUTGOING_PORT VAR_OUTGOING_RANGE
+%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP
+%token VAR_FORWARD_TO VAR_FORWARD_TO_PORT
+
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
}
;
contents_server: contents_server content_server | ;
-content_server: server_num_threads | server_verbosity;
+content_server: server_num_threads | server_verbosity | server_port |
+ server_outgoing_port | server_outgoing_range | server_do_ip4 |
+ server_do_ip6 | server_do_udp | server_do_tcp | server_forward_to |
+ server_forward_to_port;
server_num_threads: VAR_NUM_THREADS STRING
{
OUTYY(("P(server_num_threads:%s)\n", $2));
free($2);
}
;
-
+server_port: VAR_PORT STRING
+ {
+ OUTYY(("P(server_port:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->port = atoi($2);
+ free($2);
+ }
+ ;
+server_outgoing_port: VAR_OUTGOING_PORT STRING
+ {
+ OUTYY(("P(server_outgoing_port:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->outgoing_base_port = atoi($2);
+ free($2);
+ }
+ ;
+server_outgoing_range: VAR_OUTGOING_RANGE STRING
+ {
+ OUTYY(("P(server_outgoing_range:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->outgoing_num_ports = atoi($2);
+ free($2);
+ }
+ ;
+server_do_ip4: VAR_DO_IP4 STRING
+ {
+ OUTYY(("P(server_do_ip4:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_ip4 = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_ip6: VAR_DO_IP6 STRING
+ {
+ OUTYY(("P(server_do_ip6:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_ip6 = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_udp: VAR_DO_UDP STRING
+ {
+ OUTYY(("P(server_do_udp:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_udp = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_tcp: VAR_DO_TCP STRING
+ {
+ OUTYY(("P(server_do_tcp:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_tcp = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_forward_to: VAR_FORWARD_TO STRING
+ {
+ OUTYY(("P(server_forward_to:%s)\n", $2));
+ free(cfg_parser->cfg->fwd_address);
+ cfg_parser->cfg->fwd_address = $2;
+ }
+ ;
+server_forward_to_port: VAR_FORWARD_TO_PORT STRING
+ {
+ OUTYY(("P(server_forward_to_port:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->fwd_port = atoi($2);
+ free($2);
+ }
+ ;
%%
/* parse helper routines could be here */