Archive - January, 2010

gethostbyname in C

As a comparison to my earlier post. Doing this in C is much more efficient. This code prints out 2 (of the 3) A records for test.poller.se.

#include <stdio.h>
#include <netdb.h>
 
struct hostent *he;
struct in_addr **hosts;
 
main(void) {
        he = gethostbyname("test.poller.se");
 
        hosts = (struct in_addr **)he-&gt;h_addr_list;
 
        printf("%s\n", inet_ntoa(*hosts[0]));
        printf("%s\n", inet_ntoa(*hosts[1]));
 
        return 0;
}

This is much faster then the perl approach.

$ time for i in `seq 1 1000`; do ./gethostbyname > /dev/null; done
real    0m10.393s
user    0m0.764s
sys     0m9.065s

Net::DNS and gethostbyname

I was trying out DNS resolvers for perl and made these two scripts. test.poller.se returns 3 A records, the scripts print out 2 of them.

netdns.pl

#!/usr/bin/perl
 
use warnings;
use strict;
 
use Net::DNS;
 
my $resolver = new Net::DNS::Resolver;
my $query = $resolver->query("test.poller.se", "A", "IN");
 
my @hosts;
my $rr;
foreach $rr ($query->answer) {
        push(@hosts, $rr->address);
}
 
print $hosts[0] . "\n";
print $hosts[1] . "\n";

gethostbyname.pl

#!/usr/bin/perl
 
use warnings;
use strict;
 
use Socket;
 
my @hosts;
my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname("test.poller.se");
$hosts[0] = inet_ntoa($addrs[0]);
$hosts[1] = inet_ntoa($addrs[1]);
 
print $hosts[0] . "\n";
print $hosts[1] . "\n";

Performance difference for the two is quite big. Of course, Net::DNS is more then just a simple resolver.

$ time for i in `seq 1 1000`; do ./netdns.pl > /dev/null; done
real	1m18.185s
user	0m46.203s
sys	0m29.418s

$ time for i in `seq 1 1000`; do ./gethostbyname.pl > /dev/null; done
real	0m26.886s
user	0m7.784s
sys	0m17.969s

Bubble sort

Bubble sort is a simple sorting algorithm working by stepping through all unsorted objects one by one, comparing them to the next one and swapping them if they are in the wrong order. Then doing this over and over again, until no objects are swapped.

This is one of the worst performing sorting algorithms, but implementation is very simple. Here’s a sample PHP block that does the trick.

// array $a contains unsorted objects
 
do {
    $swapped = false;
    for($i = 0; $i < count($a) - 1; $i++) {
        if($a[$i] > $a[$i+1]) {
            list($a[$i], $a[$i+1]) = array($a[$i+1], $a[$i]);
            $swapped = true;
        }
    }
} while($swapped);

PHP’s internal sort() function, which uses Quicksort, is around 1 000 times faster then this code when sorting 1 000 objects. When sorting 10 000 objects, PHP’s Quicksort is over 10 000 times faster.

Encrypted root filesystem with FreeBSD 7.0 and GELI

This guide is from June 2008, written by me. Should probably work well on newer FreeBSD with some minor adjustments.

The following is my approch to encrypting the root filesystem of a FreeBSD 7.0 box. This is much like Marc Fritsche’s guide (link broken), but with FreeBSD 7.0 and cd boot instead of usb boot.

Using a cd instead of a usb memory has two big advantages. First, not all motherboards support it. Second, using a cd iso is good for booting a server that has a remote access card with virtual media capabilites. Just mount your iso (with the encryption keys) over the network when you need to reboot your machine. This way, the keys are never stored with your system.

The following hardware will be used

ar0: Raid device used for our system
ad14: SATA HDD used for our initial setup, won’t be needed when we’re done

We’ll partition the guide into several steps.

  • Installing FreeBSD on ad14 and booting it up
  • Building the geli crypto layer on ar0
  • Building FreeBSD on our crypto device
  • Making our CD

Installing FreeBSD on ad14 and booting it up
Install with all the sources, will be needed later.

Building the geli crypto layer on ar0
Now the fun part, we’ll start by creating our keys.

# mkdir /boot/keys
# dd if=/dev/urandom of=/boot/keys/ar0.key bs=128k count=1

The dd command creates the key ar0.key using 128k of random data.

Now we need to erase the data on the drive, if you’re using new drives (or if you’re not that paranoid) this isn’t required.

# dd if=/dev/urandom of=/dev/ar0 bs=1m

Telling dd to use a blocksize of 1m speed things up a lot.

Then we need to initialize the device.

# geli init -b -K /boot/keys/ar0.key -s 4096 -l 256 /dev/ar0

Parameters are as follows. -b tells geli that we’re going to need a password prompt for this filesystem at boot, since it’s our root filesystem. -K is the keyfile we created earlier. -s 4096 sets the sector size to 4096, this is good for performance. -l 256 tells geli to use AES 256 encryption.

You’ll be asked for your secret passphrase, make sure it’s strong!

Now let’s attach our new device.

# geli attach -k /boot/keys/ar0.key /dev/ar0

Enter your passphrase and we’re done. A new device named /dev/ar0.eli is now created.

Building FreeBSD on our crypto device
First off we’ll need some partitions on our new geli device.

# bsdlabel -w /dev/ar0.eli
# bsdlabel -e /dev/ar0.eli

-w creates a astandard label on our device and -e will bring up our favorite editor vi and lets us edit the partition table.

If your raid device is 80G, it could look something like this to start with.

# /dev/ar0.eli:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a: 19537677        2    unused        0     0
  c: 19537679        0    unused        0     0         # "raw" part, don't edit

19537679 is 80G (19537679 / 1024 / 1024 * 4096 (4096 is the sector size we specified erlier)).

Lets say we want 4G of swap space and the rest (around 76G) for our / partition. 4G is 4096M wich is 1048576 (4096 / 4096 * 1024 * 1024). Our / will be 18489103 (19537679 – 1048576).

The result will look something like this.

# /dev/ar0.eli:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a: 18489103        0    4.2BSD        0     0
  b:  1048576        *      swap
  c: 19537679        0    unused        0     0         # "raw" part, don't edit

* tells bsdlabel to calculate the right offset by itself, 4.2BSD is the fstype we’re using for our / partiton.

Thats good and all, now it’s time to create our new filesystem.

# newfs -O2 -U /dev/ar0.elia

-O2 tells newfs to use UFS2 instead of UFS1 and -U enables soft updates.

Mount our new filesystem.

# mount /dev/ar0.elia /mnt

Now lets build our new system.

# cd /usr/src
# make world DESTDIR=/mnt
# make distribution DESTDIR=/mnt

This will install your FreeBSD system (without the kernel) in /mnt. make world took about 2 hours on my single core amd64.

The kdbmux kernel device and geli doesn’t play very well together. So in order to get this up and running we need a custom kernel without the kdbmux device. Compiling a custom kernel is very simple and is described in the freebsd handbook.

In short, do this.

# cd /usr/src/sys/amd64/conf
# cp GENERIC GELI
# vi GELI

Find the line containing device kbdmux and comment it out. If you need SMP support, don’t forget to add it now. Then build and install the kernel.

# cd /usr/src
# make buildkernel KERNCONF=GELI
# make installkernel KERNCONF=GELI DESTDIR=/mnt

We’re now done with the OS install on our encrypted device.

Making our CD
Lets start by making a directory.

# mkdir /root/bootcd

Then we need a fstab file.

# mkdir /root/bootcd/etc
# vi /root/bootcd/etc/fstab

Something like this will do fine for our setup.

# Device       Mountpoint  FStype Options   Dump Pass
/dev/ar0.elia  /           ufs    rw        1    1
/dev/ar0.elib  none        swap   sw        0    0

Lets put this file on our “real” system as well.

# cp /root/bootcd/etc/fstab /mnt/etc/

We also need our new kernel on the cdrom.

# cp -Rp /mnt/boot /root/bootcd

Then we need a loader.conf file that loads the geli kernel module at boot, and we also need to tell it where to find the encryption keys.

# vi /root/bootcd/boot/loader.conf

A file like this will be good.

geom_eli_load="YES"
geli_ar0_keyfile0_load="YES"
geli_ar0_keyfile0_type="ar0:geli_keyfile0"
geli_ar0_keyfile0_name="/boot/keys/ar0.key"

Now it’s time to make the iso, the mkisofs tool is quite useful (sysutils/mkisofs).

# mkisofs -no-emul-boot -b boot/cdboot -o /root/bootcd.iso /root/bootcd

-b boot/cdboot tells mkisofs which boot record to use, -o specifies where to save the iso file. -no-emul-boot is needed because the cdboot-image is not a regular floppy image. Now burn the iso with your favorite applikation (burncd, perhaps?).

# burncd -f /dev/acd0 data /root/bootcd.iso fixate

ad14 still contans your encryption key, you probably should wipe it.

Store your iso in a safe place, in case your cd becomes unusable.

Rackspace Cloud vs. Amazon EC2

Rackspace Cloud, or Amazon EC2, which is best? This is just a quick performance comparison using SysBench. The following products where tested.

Product CPU Memory Disk Price
EC2 Small Instance 1 virtual core 1,7GB 160GB $0.085 per hour
Rackspace 256MB 4 virtual cores 256MB 10GB $0.015 per hour
Rackspace 1024MB 4 virtual cores 1GB 40GB $0.065 per hour

Servers where running Ubuntu 9.10 i386, tests where performed on two different occasions, average scores where used. Here’s the results, less is good.

Product SysBench CPU Sysbench Memory Sysbench File I/O
EC2 Small Instance 29.7s 491.3s 28.6s
Rackspace 256MB 5.6s 219.1s 26.4s
Rackspace 1024MB 4.1s 196.1s 17.8s

The following commands where used to do the benching, interesting values was the total time to run the test.

sysbench --num-threads=4 --test=cpu run
sysbench --num-threads=4 --test=memory run
sysbench --num-threads=4 --test=fileio --file-test-mode=rndrw prepare
sysbench --num-threads=4 --test=fileio --file-test-mode=rndrw run

Conclusion

According to SysBench, Rackspace Cloud is much faster then EC2 in general, and cheaper as well. EC2 however comes with more memory and disk.

Page 1 of 3123»