Using qemu to lock down tetrinetx server

Rusty Russell

Note: the mentioned files are available in tetrinet.tar.gz.
Hi all,

	I recently set up a tetrinet server inside a qemu image, for a
layer of additional security.  The image is under 2MB, and below is a
mini-howto in setting up such a server in case anyone else is
interested.

You will need:

1) A qemu-compatible disk image: I have a simple script to make one,
  (see file 'make_fs.sh').

2) The "vl" binary, and a qemu-compatible kernel bzImage.
   I used qemu 0.4.3, modified with the -tun-fd patch and the closed
   stdin patch.  If you use the softmm version of qemu, any kernel
   bzImage should work.

3) The root-running version of the tundev program (see file 'tundev.c')

Steps:
1) Mount the filesystem.  If you've already prepended a partition
   table, use
	losetup -o $((63 * 512)) /dev/loop0 
	mount /dev/loop0 /mnt/qemu
   Otherwise you can just do:
	mount -o loop  /mnt/qemu

2) Remove unneccessary files, add files you need, and lock down
   directories.  This is best done by creating an oldroot dir and
   moving things into that.  For tetrinet, I ended up under 2MB
   (see file 'tetrinet-in-qemu-ls-R')

3) I wanted the filesystem to be read-only (too bad about the tetrinet
   high scores file: I don't care), but I wanted the logs, so I made
   /var/log/tetrinetx/game.log a symlink to /dev/ttyS0, and allowed
   the games group to write to it.

4) I wrote a simply launcher program called run to avoid the need for
   a shell (see file 'run.c')

5) Unmount the qemu image.  Once I'd trimmed out most of the code, I
   created a new smaller one one, mounted that, and used tar to
   transfer everything across.

6) My startup script looks like so:

	#! /bin/sh
	# Set up forwarding and masquerading, and make sure tun module is loaded.

	set -e

	INTERFACE=`./tundev games /var/log/qemu-tetrinet ./vl -hda tetrinet-filesystem bzImage root=/dev/hda1 ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe init=/run`

	ifdown $INTERFACE 2>/dev/null || true
	ifup $INTERFACE

   You need to reconfigure the tun devices everytime they get opened,
   hence the ifdown/ifup stuff.

8) You will also need to forward incoming connections to the server.
   In this case, the server makes no outgoing connections, so this
   works:

   iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 31457 -j DNAT --to 192.168.1.2
   iptables -A FORWARD -o tun0 -m state --state NEW,INVALID -j DROP
   iptables -N LOGDROP
   iptables -A LOGDROP -j LOG
   iptables -A LOGDROP -j DROP
   iptables -A FORWARD -i tun0 -m state --state NEW,INVALID -j LOGDROP

Good luck!
Rusty.