Start Blogaria Bored bsgen cconf Cookies CopyForward CyclicLog Dialwhatever DNSBalancer fch HammerServer jpeginfo kalk Lectures Microproxy msc Nasapics PGPkey SafeEdit Simple listserv Wallpapers
A little movie
An animation can't be properly rendered. You have probably a too old version of Flash player. |
DNS BalancerCrossroads, my pet open source project, is a balancer for TCP services, such as database connections, SMTP, HTTP. I've received many mails asking whether UDP balancing - and mainly for DNS - can be integrated into Crossroads. The answer was always: no, that's out of scope. My reasoning is that UDP is a totally different ballgame than TCP: it's connection-less, messages may arrive out of order, delivery is not guaranteed, there's no way to see whether your back end is alive, and so on. But does that mean that a DNS balancer is not feasible? Nah, of course it can be done, but IMHO it's more of a specific balancer, hand-crafted for the purpose, instead of a generic balancer, which Crossroads attempts to be. So just to test this hypothesis, I wrote a small DNS balancer, which is shown here.Download the sources!If you want to try it out: You can download all the code as dns-balance.tar.gz. Unpack the archive, cd into the unpacked directory dns-balance and hit make. You will need GNU Make and a C++ compiler on your system. A working DNS balancer is constructed as build/dns-balance. Fire it up as user root as:build/dns-balance -v IP1 IP2 IP3 ...where the IP's are IP addresses of your DNS servers. (If you just type build/dns-balance then you get some usage information.) You must start it as user root because the DNS balancer has to get control of port 53, which is a priviledged port. If you have only one DNS server in your network, just state one IP address. In that case the balancer actually becomes just a forwarder. The flag -v is included in this example so that the actions of dns-balance are shown. You wouldn't need this flag in a "production" setting. Once the balancer is running, start a second window and try it out, using: nslookup www.kubat.nl 127.0.0.1Here the extra argument 127.0.0.1 is the IP address of the DNS server that nslookup should use, which is of course the balancer. The code of the DNS balancer is distributed under the GPL V3 license. In short this means that there's no warranty and that you're free to do anything you like with it, provided that you redistribute the original sources, and if applicable: your modifications. If you do make modifications, I'd like to hear about it - just drop me a mail. The same of course applies incase you have questions or suggestions. ConceptsHow DNS lookups workWhen a client wants to resolve a host name, then it sends a UDP message to its name server, to port 53. Nothing spectacular so far. But here's the catch: since UDP is connection-less, there is no connection to get the response. The name server has no way of reporting back, unless the two (client and name server) use a trick. Here's the trick: When the client sends the request, it of course uses a local UDP port to connect to the remote DNS port which is 53. Let's say that the local port is 12345. Having sent the request, the client now starts listening to this same local port 12345. It becomes a server process. The trick is that the client expects that the DNS server will report back to the same port; which in fact means that "on the second leg" of the chitchat, the DNS server becomes a client process that connects to the original client which is now a server on port 12345. Huh? Maybe the following simple ASCII art will explain.
FIRST LEG: Client asks the DNS server
client DNS server
sending port 12345 -----------------------> listening port 53
"Look up a host for me"
SECOND LEG: DNS sever answers
client DNS server
listening port 12345 <---------------------- sending port 53
"It's at IP P.Q.R.S"
This in turn means that the DNS server must maintain a list of its
pending requests: which client IP requested what host, using which
client port? Using that information, the DNS server can determine the
"right" client to send a reply.
This approach also means that the client is responsible for error
discovery and recovery. If the DNS server fails to answer on the local
port 12345 within say 3 seconds, then the client assumes that this
request has been lost, and will retry. After a given number of retries
the client gives up. This is fortunately already a built-in feature of
clients.
How the DNS balancer should behaveWhen a DNS balancer is placed between the client and the DNS server, then the flow is of course in principle the same. The client will think that the balancer is the DNS server, and the DNS server will think that the balancer is the client. At the crossing point there is however more to think about. The above described "first leg" now consists of two sub-parts: the client asks the balancer, and the balancer asks the DNS server. Let's assume that the local port on the client is 12345, and that the balancer will use a local port 34567:
FIRST LEG: Request for look up
client A balancer DNS server X
sending port --------> listening sending port ------> listening
12345 port 53 34567 port 53
Once the balancer has forwarded the request to the DNS server, it's
already listening to two ports: 53 (the main DNS port which is open
for new requests), and 34567, on which the DNS server's reply is
expected. The trick is of course that once the response arrives, the
balancer must match it with the request. The approach is that the
balancer has a list of outstanding requests, which after the above
first leg states that a UDP message that is received on on port
34567, from DNS server X, should be forwarded to client A, port
12345. Once the DNS server's response arrives and the balancer
makes the match, the "second leg" looks as follows (read from right to
left):
SECOND LEG: Resolved address client A balancer DNS server X listening <----------- sending listening <---------- sending port 12345 port 53 port 34567 port 53Dns-balance in fact uses yet another security measure to match a DNS server's reply with a client's request: the transaction ID of DNS requests. Each UDP message that a client sends out, has a (random) 16-bits transaction ID in it. The DNS server's answer must match that ID. That's why it's a custom balancer!Balancing DNS requests over UDP will only work if the above scheme is strictly followed. The balancer must expect a resolution message on the same local port where the original request was sent (and hence: it must start a listener on that port after sending the request), and it must report back to the client over its local port 53 (the port where the client's request came in). All such features are not part of UDP itself, they are part of the DNS lookup scheme. That's why I think there is no generic UDP balancer. That's why I don't think that UDP balancing can be part of generic software, such as Crossroads.Onward to the code!The code in dns-balance.tar.gz is organized as follows: under src/ you will find all the sources that are required for the program. Classes are organized under their own subdirectory. E.g., there's a class Message that represents a UDP datagram. Its header file is src/message/message and the implementation is in src/message/*.cc.Used variables, constants and what they meanThe central include file src/dns-balance includes necessary system headers, and defines a few constants, which mean the following:
Function main()The function main() is contained in src/dns-balance.cc. It drives the entire process. The code is quite self-explanatory.Classes and methodsHere is a very basic overview of the balancer's classes and what they are for. Details are of course in the code - "use the source, Luke."
How good is this code?The code works in a proof of concept setting. It's "production ready", but has not been extensively tested. But it's a good starting point if you want to make this a production-grade DNS balancer. Here are some points for improvements:
|