dnspb
Summary for the fast and furious
What is dnspb?
Dnspb is a proxy/balancer for DNS requests. It handles both UDP and
TCP operations.
Dnspb is based on my previous proof of concept program
dns-balance. The description is still
hosted at my site, read it if you want for an overview of concepts.
The improvement points that are listed at the bottom of the
dns-balance description have made it into the code base of dnspb.
Balancing
In general, here's what dnspb can do for you. If you have
multiple UDP and/or TCP back ends, then you can put dnspb "in front of
them" as a proxy/balancer. Clients contact dnspb to resolve names (or
to do other DNS-related operations), and dnspb forwards the requests
to the next-best back end it knows. This is the DNS server with the
least connections at that time. The request is resolved at the true
DNS server, upon which dnspb sends this answer to the client who had
requested the operation. This is basic
balancing: dnspb distributes
the traffic over all the back ends that are "behind" it.
Fail-over
When a back end goes down, then dnspb detects this, and takes it
out of rotation - i.e., it makes sure that next requests don't get
forwarded to that back end. However, dnspb periodically checks "dead"
back ends to see whether they've come alive. Once dnspb sees that such
a back end has awoken, then it's automatically added to the pool. This
is basic
fail-over: if you have more DNS servers and one dies,
then dnspb makes sure that clients don't suffer from it. (Live checks
are on by default, but they can be turned off.)
Transaction ID randomization
Every DNS requests has a transaction ID in it. This is a number that
the requesting client defines. Consecutive numbers (1, 2, 3 and so on)
make the domain name system susceptible for attacks, as was
illustrated by Dan Kaminski (google it if you want to know more, or
see
http://en.wikipedia.org/wiki/Dan_Kaminsky).
Dnspb randomizes these ID's in the traffic to the true DNS servers,
and in the case of UDP, randomizes the ports, which is also pretty
important. This makes Kaminski-style attacks much more difficult
(though the only real solution is to use dnssec).
Support of heterogenous dns
Normally your DNS back ends will be "equal" in the information that
they can provide. But in cases where one group of back ends knows
about one zone, and another group knows about another zone, dnspb can
be put in front of these servers to combine such heterogenous zones,
and to make them appear homogenous to clients. Dnspb does this by
simply re-querying a next DNS back end upon receipt of a "name error"
response. (This behavior can of course be turned on and off.)
Copyright and License
Dnspb is distributed in source form, as-is, licensed under GPLV3. See
the file LICENSE in the source archive. This basically means that
you're free to take dnspb and use it, you're free to modify it to suit
your needs, and you're free to redistribute it, as you see fit - but
only as long as you keep the licensing terms intact, and as long as
you redistribute dnspb with all sources. If you do modify dnspb, then
as a courtesy, I'd appreciate a note from you (if the modification is
generic enough, I'd include it in the sources and re-distribute,
including your name in the ChangeLog if you want).
Also, dnspb is distributed without explicit or implied warranty or fit
of purpose. Use it at your own pleasure and risk.
How to install and start dnspb?
- Obtain the source
archive
dnspb-0.06.tar.gz
.
- Unpack the archive in a 'sources' directory, e.g.
/usr/local/src/. The archive spills its contents into a new
subdirectory dnspb-version/.
- Change-dir into the new directory dnspb-version/ and type
make local
- If you want to run some tests before installing:
run
build/dnspb tcp://1.2.3.4 udp://1.2.3.4
You will have to do this as root, since dnspb binds to port 53
which is privileged.
Here, 1.2.3.4 are
the IP addresses of your DNS server. You can specify several TCP
back ends and several UDP back ends. Also you can put in a
flag -d to see debugging output. Let this run; in an other
window, run some lookups, such as
host www.google.com localhost
To test out TCP, run
host -T www.google.com localhost
Once you are done testing, just hit ^C in the window
that runs dnspb. Alternatively, you can run
dig www.google.com @localhost # UDP test
dig +tcp googleo.com @localhost # TCP test
- In order to install into /usr/sbin, run
make install
If you want to install into an other directory,
run
BINDIR=/where/ever make install
This installs two utilities:
- dnspb, the program itself;
- dnspbctl, a control script.
- Next copy etc/dnspb.cfg.sample to /etc/dnspb.cfg by
running:
cp etc/dnspb.cfg.sample /etc/dnspb.cfg
After this edit
/etc/dnspb.cfg to suit your needs, the configuration is pretty
self-explanatory. Or see below for a description.
- Finally fire up dnspb by running:
dnspbctl start
The worker dnspb
The actual balancer program dnspb can be started without using
dnsbpctl, just as httpd can be started without apachectl. The worker
supports the following options:
- Generic:
- --help, -h, -?: Shows usage information.
- --version, -v: Shows the version ID and stops.
- --log-debug, -d: This causes dnspb to generate verbose
(debugging) information. Dnspb sends this information to stdout,
which can be redirected to log files, or the system logger etc..
- --log-performance, -p: This causes dnspb to generate
performance-related information.
- --heterogenous-dns, -H: If your DNS back ends represent
separate zones, then with this flag, dnspb will continue asking
back ends for a resolution when it receives a "name error" answer.
- UDP-related:
- --idle-udp-timeout SEC, -i SEC: dnspb will wait for an UDP
answer from downstream servers for the stated number of
seconds, default is 2. When no answer is received within
the stated time, then dnspb considers the server to be down.
- --udp-port PORT, -u PORT: This defines the UDP port that
dnspb listens to. The default is 53. Setting this port to 0
causes dnspb not to start the UDP service.
- --udp-port-retries TRIES, -U TRIES: This is the number of
(re)tries that dnspb may take to find a local UDP port for the
connections with downstream DNS servers. Normally you don't have
to change this setting, the default is 40.000.
- --udp-recheck-time SEC, -r SEC: When dnspb detects that
downstream DNS servers are dead, then it will recheck each SEC
seconds to see whether the server(s) have awoken yet. Setting
this to 0 instructs dnspb not to check at all. The default is 1
sec.
- TCP-related:
- --idle-tcp-timeout SEC, -I SEC: dnspb will wait for the given
number of seconds before deciding that a TCP back end is dead.
The default is 120.
- --tcp-port PORT, -t PORT: This defines the TCP listen port.
The default is 53. Setting this value to 0 instructs dnspb not
to start the TCP service.
- --tcp-recheck-time SEC, -R SEC: When dnspb detects that
downstream TCP servers are dead, then it will recheck each SEC
seconds. Setting this value to 0 inhibits TCP server checks.
Following the flags, you must specify UDP and/or TCP back ends. UDP
back ends are required, unless the UDP listen-port is set to 0; TCP
back ends are required, unless the TCP listen-port is set to 0. Back
ends are always stated as
TYPE://IP-ADDRESS, optionally
followed by
/WEIGHT. The TYPE must be
udp or
tcp.
The IP address is the dotted-decimal address of the DNS servers that
dnspb will talk to. The weight is an optional specifier that tells
dnspb which back ends are "stronger": the bigger the weight, the more
traffic the back end will receive.
Any output of dnspb is prefixed with a timestamp (up to
millisecond resolution), a thread ID, a message type, and text. The
thread ID is mainly for debugging purposes (to see which thread did
what). The message type is something like "debug", "perf" or "info".
Warnings are shown with the message type "WARN".
Three important signals that dnspb listens to, are HUP, USR1 and
USR2. Signal HUP (1) causes dnspb to show the state of its back ends.
Signal USR1 (30) toggles performance logging output. Signal USR2 (31)
toggles debugging output.
The control script dnspbctl
Dnspbctl is a fairly simple Perl script that parses a configuration
file, prepares a command that fires up dnspb, and execs it. Once
dnspbctl starts the worker dnspb, it exits - it doesn't use up any
resources.
The configuration file that dnspbctl reads is /etc/dnspb.cfg. The
syntax of this configuration file is very simple and self-explanatory.
For reference an example is shown here.
# ########################################################################
# Configuration for dnspb (/etc/dnspb.cfg)
# Used by dnspbctl to control the main program dnspb.
# Syntax:
# Configurations are stated as "label = value"
# Some configurations have a default, some must be stated. See below.
# Comments are lines where the first character is a #
# Empty lines are allowed
# You can split long lines using a \ at the end. The next line may
# be indented.
# ########################################################################
# ########################################################################
# General section
# ########################################################################
# Should debugging information be generated? Can be toggled later in the
# running server using kill -USR2 or using dnspbctl toggledebug.
# Values may be false or true, default false.
# log-debug = false
# Should performance information be generated? Can be toggled later in
# the running server using kill -USR1 or using dnspbctl toggleperf.
# Default false.
log-performance = true
# Logging output. Use |program to send into a pipe, or >file to rewrite
# files each startup, or >>file to append to a file. There is no default,
# must be specified. A good setting is e.g.: |logger -t dnspb
# To get verbose output on console, do: (a) set above log-debug to true,
# (b) set log-output to |cat
log-output = | /usr/local/bin/loglimit /tmp/dnspb.log 10000 3
# If your DNS servers represent distinct zones, then set the following
# flag to true. Dnspb will then continue to query back ends when it
# receives a "name error" answer. If your back ends provide equivalent
# information, then leave this flag "false", which is the default.
# heterogenous-dns = false
# ########################################################################
# UDP service section
# ########################################################################
# UDP server port (0 to disable the UDP service). Default is 53.
# udp-port = 53
# UDP back ends. Specify as IP:PORT/WEIGHT, e.g. 1.2.3.4:53/1
# The default port is 53, the default weight is 1, you can leave those out
# to write e.g. 1.2.3.4. Bigger weights are bigger servers and get
# proportionally more traffic.
# There is no default, must be specified (unless you suppress the UDP
# service by saying udp-port = 0)
udp-backends = 10.124.237.66 10.51.223.77 \
8.8.8.8 8.8.4.4
# UDP timeout. When no answer arrives from a back end within the stated
# nr of secs, the back end is marked dead. Use 0 to suppress this state
# checks. Default is 2.
# udp-timeout = 2
# Rechecking of dead back ends. Once due to time outs back ends are
# marked dead, they will be rechecked every X secs to see whether they
# are online yet. Default is 1 sec. Set to 0 to suppress checks.
# udp-recheck-time = 1
# ########################################################################
# TCP service section
# ########################################################################
# TCP server port (0 to disable the TCP service). Default is 53.
# tcp-port = 53
# TCP back ends. Specify as IP:PORT/WEIGHT, e.g. 1.2.3.4:53/1
# The default port is 53, the default weight is 1, you can leave those out
# to write e.g. 1.2.3.4. Bigger weights are bigger servers and get
# proportionally more traffic.
# There is no default, must be specified (unless you suppress the TCP
# service by saying tcp-port = 0)
tcp-backends = 10.124.237.66 10.51.223.77 \
8.8.8.8 8.8.4.4
# TCP timeout. When no answer arrives from a back end within the stated
# nr of secs, the back end is marked dead. Use 0 to suppress this state
# checks. Default is 2 mins. This is much longer than UDP timeouts to allow
# for complex TCP zone operations etc..
# tcp-timeout = 120
# Rechecking of dead back ends. Once due to time outs back ends are
# marked dead, they will be rechecked every X secs to see whether they
# are online yet. Default is 3 sec. Set to 0 to suppress checks.
# tcp-recheck-time = 3
Dnspbctl supports the following options:
- -c CONF: Instructs dnspbctl to read the stated configuration
file, instead of /etc/dnspb.cfg.
- -v: Turns on script verbosity (for debugging).
Dnspbctl supports the following arguments:
- start, stop, restart: These are the typical control scripts
actions.
- status: Shows whether the DNS proxy/balancer is running, and if
yes, at which process ID.
- configtest: Verifies whether the configuration /etc/dnspb.cfg
is valid.
- commandline: Shows how dnspbctl would start dnspb given the
configuration.
- backends: Causes the underlying dnspb worker to send its back
end state to the log.
- toggledebug, toggleperf: Sends the signal USR1 or USR2 to dnspb
to toggle debugging or performance logging.