Archive for February, 2009

Your own PHP DNS daemon

After my initial announcement of a PHP DNS Daemon, and some performance tests, and since it has been widely reported over internet (Zend DevZone, and today on Nexen which is deeply involved with French php community), I finally found the strength to write a guide on “how to get started with DNSd”.

Basically, you’ll need subversion, gcc, make and most prerequisites for PHP (ICU, etc). This supposed you already have some knowledge in system administration.

The first step will be to fetch the latest SVN code somewhere in your Linux box (I usually put that in /usr/local).

$ cd /usr/local
$ svn co http://ookoo.org/svn/pinetd2/trunk pinetd2
(checkout lines)
$ cd pinetd2/php
$ ./do_php.sh
(will download & compile PHP 5.3.0, and maybe complain about missing stuff,
 just install whatever is missing, if you need help, post the last error
 lines here or contact me)
$ cd ..
$ ./start.sh
Please edit config.xml and remove the line containing this text

Arrived at this point, a file config.xml has been created and needs to be edited. I added comments inside it to help you. You’ll need to do a few things:

  1. Remove the <RemoveMe> tag, and edit the <Name> tag to include your machine’s name.
  2. Change the storage engine to use SQLite3. PInetd’s MySQL driver is not compatible yet with DNSd. You can copy the line from the example, but remember that if your zone file is in /tmp, it might get erased at startup (depends on your linux distribution).
  3. There is an empty <DNSd> tag, fill it with the second choice in the comment (the <PeersArray> one). Change the Signature, peer name, etc to fit your needs for the Type=”control” line : this is the definition of “who will be able to create/remove records on this DNS server”.
  4. At the end of the file, remove all processes that do not have Daemon=”DNSd”. There sould only be 3 remaining processes.
    If you are not root, set PortOffset to an arbitrary value greater than 1024, like for example 10000.

Once you’ve reached this point, you should be ready to go. Try starting the daemon.

[2009-02-19 10:10:33:30945] DEBUG: pinetd v2.0.0alpha running on...
[2009-02-19 10:10:33:30945] WARN: SUID security level is defined...
[2009-02-19 10:10:33:30945] WARN: Warning: Chroot security level...
[2009-02-19 10:10:33:30945] DEBUG: My name: localhost
[2009-02-19 10:10:33:30947] INFO: Loading Daemon\DNSd\UDP on port 10053, bound to ip 127.0.0.1
[2009-02-19 10:10:33:30948] INFO: Loading Daemon\DNSd\TCP on port 10053, bound to ip 127.0.0.1
[2009-02-19 10:10:33:30949] INFO: Loading process Daemon\DNSd\Process

As you can see, I am not root, so PInetd will complain about the impossibility of chroot()ing or setuid()ing, however it’s just for testing, so we don’t really care.

At this point, if you configured the DNS daemon like me with a PortOffset of 10000, with a peer named “MyPeer” and a secret of “qwerty”, running “dnsd_test.php” in the “test” directory will create an “example.com” domain.

$ php dnsd_test.php
Connected to localhost

Now, you can test it:

$ dig +short -p10053 @localhost example.com
127.0.0.1

Of course the PHP DNS Daemon is not completed yet (fixed a potential denial of service yesterday) and probably still have many bugs, so I strongly advice against using it on any production system yet.
Yes, I am using it for this blog, and for another ~200 domains, to find bugs and make the solution more stable, however if you wish to contribute by testing on a production system too, make sure you are ready to have all your websites becoming down and your server taking fire.

The next step for you is to look in test directory at the “dnsd_test.php” script, and make your own pages using DNSd. You do not need to use PHP 5.3.0 to use this class, so you can basically use it anywhere. PHP 5.3.0 is only required for the DNS daemon itself.

If you have any question, feel free to leave a comment, I’ll try to complete this article as problems are raised by people who use this.

Tags: , , ,

PHP DNS Daemon: performances

Many people seems to have taken interest into my weird idea to write a PHP DNS daemon in PHP, so I decided to run some experiments. The first one was to setup ~200 domains to this dns server (including my blog’s one), the second one is to run queryperf against it, and against bind9 running on the same host, with the same configuration (ie. same domain list, no recursion, etc).

First, the host:

  • CPU: 2x Intel Xeon E5405 (2GHz) ; a total of 8 cores
  • RAM: 8GB RAM (4x 2GB DDR2 @667Mhz)
  • Hard Disk: 2x1TB HDD (RAID 1, 3ware Inc 7xxx/8xxx-series PATA/SATA-RAID) ; total of 1TB usable
  • OS: Linux Gentoo 64bits 2008.0 (multilib) with Linux Kernel 2.6.27-gentoo-r2

The test itself will be a 1 million random queries generated by gen-data-queryperf.py with 40% of random domains.

Some words on results

First, I’d like to say that pinetd2 is still under development, some parts are still not implemented (the DNS server is able to act as a DNS server, that’s the important part for me), and also some optimizations weren’t done yet (for example a query will always cause the same SQL statements to be run, I could prepare those).
The fact I’m running SQLite means the SQL server isn’t able to cache results (the db file might be modified by anyone, anytime, however I don’t know the exact internals of SQLite), and I don’t cache anything either.

When I started writing DNSd, I didn’t especially try to go on performances, features were importants, and realtime was too. Many improvements to speed can still be done (I’m thinking “prepared statments” right now, but also caching domains list, etc) and would help to get those numbers closer to ISC BIND.

The fact DNSd is 1/4 the speed of BIND (2531.89 queries/sec instead of 10071.2 queries/seq, my dns server is runnnin at 25.14% the speed of bind) is impressive. I guess we’ll need more tests, with different backends (MySQL is also supported, in theory) and different hosts, but I was supposing the database overhead would be bigger than that (well, SQLite is fast, but I wasn’t expecting that fast).

To tell you the truth, I am surprised by those results, however these are results on a real host, really running domains (like my blog’s domain), which makes me believe those results are the closest I could get from DNSd performances on a real host.

Now, the raw test results with both bind and PHP DNSd, running from the same host (to avoid network latency, and since I got 8 cores with almost no CPU usage as it’s morning in France, it shouldn’t make a big difference).

Other test results with other hardwares are welcome. I’ll try running the same kind of tests on less powerful hardware too, just to see what I get.

Read the rest of this entry »

Tags: , , ,

PHP DNS Daemon

As the subject suggests, I just wrote an opensource DNS daemon in PHP. I already know what any sane person is thinking right now:

[18:25:06] <Derick> MT`AwAy: you’re mad

Now that it’s said, let’s move on ; if you want to tell me I’m crazy, you can post it in a comment here, it makes me happy. I had some reasons to dislike bind9 which finally made me write my own DNS daemon, and I’ll explain that here.

My need was to have a stable dynamic DNS server working in most environnements, with an easy to configure master/slave relationship (with realtime synchronisation), and a way to change records instantly from PHP…

For those who already played with bind9, there’s a feature called dlz which basically allows to ask bind to get data from an SQL server. I could just configure another MySQL per slave, and put replication there, but it’s not that fast and I had some stability issues (both with MySQL replication, and with bind crashing in some weird cases).

So, instead of trying to fix bind9′s code (which would also include fixing MySQL replication – or trying newer MySQL’s row-based replication) or searching for another solution (there are zillions of dns servers around there, but they all have features I’ll never need), I decided to write my own DNS server (built on top of PInetd, my PHP networking framework for PHP 5.3.0), with only the features I needed.

So here are some of the features of this DNS daemon:

  • Supports RFC 1035, and some others too (IPv6 AAAA records, and DNS OPT, with the goal of supporting DNSSEC at some point).
  • Does NOT support AXFR nor IXFR, I have no need for the standard zone transfer protocol
  • Data can be updated realtime with a provided client class, connecting to the server via a shared secret authentication (client computes checksum of his name, timestamp and secret, server replies with the same kind of data). Once authentication is finished data is sent cleartext, but adding SSL encoding wouldn’t be that hard (just need to create a “STARTTLS” function, that’s on the TODO list).
  • Slave stays connected to master (keepalive packet sent every 15 minutes), and gets updates realtime.
  • On first connection, slave will get all zones/domains/records from the master. If it gets disconnected later and reconnect, it will search for his last update, and will ask only for newer data from the master.
  • Slave synchronisation is done in a separate process, meaning that even when processing a lot of updates, service is available.

As a test, I ran AFNIC’s zonecheck on a virtual zone I created on the server, and it works!

dig @dyndns1.ookoo.org version.dnsd ch txt

If you want to test this, I got a test domain with a record creation page, however I won’t post it here (or it might get abused) so if you want to test, feel free to contact me.

And finally the conclusion is simple: php can do anything you want to do, and even things you never wanted to.

PS: I’m looking for someone to look after PInetd‘s website, like removing this lipsum news, etc… (I don’t have time for that).

Tags: , ,

Using SSL keys for client authentification

As you may have seen on services such as MyOpenId, you can either login on your account with a password, or you can generate a client identification SSL certificate and let your users identify with one of the most secure way (as long as they don’t get their keys stolen).

SSL identification?

The idea is pretty simple. Usually communications between a SSL client and server are done via a public/private key system. While I never checked in depth, I assume it’s pretty much like for mails: the client generates a client certificate, connects to the server, gets the server’s public key, sends its public key to the server, then use its own private key and the server’s public key to exchange data.
SSL identification happens there: instead of generating a key, the client will use a previously generated private key, and send its public key alongside a certificate previously obtained from the server. The server will be able to check the certificate, which proves that the client’s key has been signed by the server CA (another private certificate held by the server, only used to make client certificates).

This way, the server will know that the key used by the client was signed by him and can be trusted.

How did this happen? Who gave its key to the client? How can you do the same on your website with PHP? What? Why are you talking about PHP 5.3.1?

Read the rest of this entry »

Tags: , , , ,