Archive for the ‘Networking’ Category

Creating a dynamic DNS service using djbdns

December 7th, 2011 2 comments

Before some days I decided to create a dynamic DNS service for a domain I own. There are many dynamic DNS services, e.g. dyndns and FreeDNS, but none gives you the power I wanted. For example I needed custom records such as SSHFP but most services don’t allow you this type of entries. Also, many of them aren’t free, especially when you transfer your own domain.

So I went on to make my own service. I knew from the beginning that BIND wasn’t what I wanted. I wanted something small, fast and secure. So I chose djbdns. Unfortunately, the IPv6 support isn’t that good so I used dbndns, which is a djbdns with some patches, especially for IPv6. (Yes, the title says djbdns, but it’s the same, if you don’t like the debian patches I can tell you how to transform a line to make it djbdns compatible!)

The first part was to design the interface. I could make a fancy web page with buttons and nice images. However, since most of the users would like a simple command that they could insert at their crontab to update their IP, I decided to just get a number of parameters and return a status string. Much simpler, more functional and I get to  spend more time coding the core of the server!

And then it’s the functionalities. Which would be the supported entries? IPv4 and IPv6 are ok for the beginning. But would the user be able to choose whatever IP he wanted? What about the hostname? Most users want a dynamic DNS so they can connect to their home box using ssh. As I said at the first paragraph, SSHFP records should be supported. But other records such as TXT and SRV? That’s why I used privileges. Every user has a privilege, and the higher the privilege the more powers you have. For the moment the following are implemented:

  • Level 1: Simple user. You are allowed one hostname and the IP is the IP you had when you made your request.
  • Level 2: Simple user with IP selection. You are allowed one hostname but you have the option to select your IP. If you don’t supply one, the IP that made the request is used.
  • Level 3: Simple user with IP and hostname selection. You are allowed to also change your hostname. If you don’t supply one the default will be used. Also, this allows you to have multiple hostnames at the same time.
  • Level 10: Administrator. Higher level, you can add, change and remove users.

All levels have IPv4, IPv6 and SSHFP support. Other privilege levels (4 … 9) are reserved for future improvements.

What about privacy? It was very important for me that all entries would ‘disappear’ after some time. The user should leave no traces. The problem is that the entry should be updated many times and not just the first time you change your IP but that’s the price for privacy! And this is something that you don’t find at many dynamic DNS services out there.

So, we’ve got many users, with different usernames, passwords and privileges, different hostnames and IPs, A, AAAA and SSHFP records, expiration times and many many more. What’s missing? SQLite! I was already running a mysql server, but I just wanted something simple. And at the end I found out that it helped me a lot with the DNS data file update.

I ended up writing a simple PHP program that would take a number of input variables:

  • username: User’s username
  • password: User’s password
  • action: The action the user wants to commit

Valid actions with their arguments are:

  • update4: Update IPv4 address
    • ip: The new IP address (if you’re allowed to set it)
    • hostname: The hostname (if you’re allowed to set it)
  • update6: Update IPv6 address
    • ip: The new IP address (if you’re allowed to set it)
    • hostname: The hostname (if you’re allowed to set it)
  • list: List all IPv4, IPv6 and SSHFP entries.
  • delete4: Delete an IPv4 dns entry immediately (before it expires by itself)
    • hostname: The hostname (if you’re allowed to set it)
  • delete6: Delete an IPv6 dns entry immediately (before it expires by itself)
    • hostname: The hostname (if you’re allowed to set it)
  • setsshfp: Add an SSHFP record
    • hostname: The hostname (if you’re allowed to set it)
    • key: The key as you can find it at /etc/ssh/ and /etc/ssh/ Warning! If there are any ‘+’ in the key (very probable since it’s base64 encoded) you must escape them!
  • delsshfp: Delete an SSHFP record
    • hostname: The hostname (if you’re allowed to set it)
  • changepw: Change password
    • newpw: The new password
  • adduser: Add a new user (if you’re allowed to add one)
    • newuser: The new user’s username
    • newpw: The new user’s password
    • newpriv: The new user’s privilege level
    • newhostname: The new user’s default hostname
  • deluser: Delete a user (if you’re allowed to delete one)
    • deluser: The user to delete
  • edituser: Edit a user (if you’re allowed to edit one)
    • Any of the following options can be used
    • newpw: User’s new password
    • newpriv: User’s new privilege level
    • newhostname: User’s new default hostname
  • cleanup: Cleanup the database.
TIP: Use curl with the -F option, at least for the setsshfp (curl -F ‘</etc/ssh/’ …).

The server is almost finished! What’s missing is inserting all these into the data file for the dns server. I decided that I didn’t want to code a c/perl program and I would write a simple shellscript. Since the djbdns data file consists of values seperated by the ‘:’ character, with  a few sql commands to sqlite3 and the -separator ‘:’ argument the updated datafile is ready. But when should the file be regenerated? I thought of a cronjob but I really didn’t like the idea of waiting. And this is where the SQLite database idea came handy! Using inotifywait from the inotify-tools I wait for close events on the database and then I update the djbdns data file. I use the daemontools to run this shellscript and till now everything seems to work great!

You can download everything here:

  • The PHP file that contains the daemon. At the top you can see two configuration options, the location where the database file can be found and the duration of each entry. The file has a txt extension, of course you’ll have to rename it. Also remember that if you store your database under the document root you should deny access from the web!!!
  • An SQL dump file that your can use to generate a sample database. A user with username and password ‘admin’ has been created, remember to change the password or create a new admin and delete the old one!
  • The shellscript that regenerates the data file.
  • The run file for daemontools. It can be merged with the previous, but you may want to generate the datafile using another way, so I created a different file.
Remember that this is just a simple dynamic DNS service designed for a small number of users!
Please leave feedback and suggestions!
Categories: DNS, Linux, Networking Tags:

Setting default options and bindings for sockets.

October 10th, 2009 No comments

Recently one of the people I follow at twitter (yes, I have a twitter account, you can follow me!) asked if anyone knew an option for lynx which would make it bind to a certain interface. I searched the manual page but there was no such option. Some programs, like netkit telnet, have an option to bind to a certain address, which can be very useful and especially when you’ve joined a VPN.

The first thing that came to my mind is write a library which would automatically bind new sockets to a certain address and then use the environment variable LD_PRELOAD so that the runtime linker would load it when a new program was run. The library should overwrite the socket(2) function and replace it with one which would run the original function to create the socket and then immediately bind it to an address. This address would be taken from an environment variable. And since I wrote the wrapper for socket(2) I could add some extra functionality such as setting various options with setsockopt(2). I wanted the program to be very efficient so it shouldn’t lookup the old socket(2) function each time the wrapper was called. In order to do this I should store the original address of the function at some variable at the beginning. This could be done in a check in the wrapper function and if the address was equal to NULL, then all initialization would take place. However, that would mean an extra check at every call. So I created a constructor which would be called when the library was initially loaded. I used a very low priority so that the constructor was run before any other constructors which could open a socket.

The program is named sockopts and you can find it at my main page, under the programs section. For the moment I have tested it at my local box having one ethernet interface and an openvpn running with a tap interface. And it works great! If you have a feature request or you found that something is broken you can leave a comment here or just email me.

Categories: Networking, Programming Tags:
SEO Powered by Platinum SEO from Techblissonline

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.