Cover V13, i01

Article
Figure 1
Figure 2
Figure 3
Figure 4

jan2004.tar

Emulating Networks Using User-Mode Linux

Ralf Spenneberg

When evaluating a new product or planning your firewall or VPN, it is always handy to be able to emulate your network virtually. Many people use VMware for this task and, although VMware does a very good job, it is quite cost-intensive. In this article, I'll describe how to use User-Mode Linux (UML) to model a network. UML is a Linux kernel capable of running on Linux. It offers networking, access to the host filesystem, jail, and honeypot features. Using virtual switches, you can combine several hosts to form a network. To use UML, you just need a Linux filesystem that the UML kernel can boot. I will also show how to use UML to emulate a testbed for a VPN solution.

Virtual private networks (VPNs) have been around for quite some time. Several protocols are available to implement VPN solutions. The most prominent protocols are the Point-to-Point-Tunneling-Protocol (PPTP) and the IP Security Protocols (IPsec). I have played around with both protocols during the past 5-6 years building both small and worldwide implementations. Most often I used open source operating systems like Linux or OpenBSD to implement the VPN gateways.

A lot of the time I spend working with VPNs is actually spent on testing new implementations and products -- testing the interoperability, robustness, and speed. So naturally I looked for ways to emulate and test new scenarios. In some cases, you have to use VMware. If you want to emulate and test a heterogeneous IPsec setup involving Microsoft Windows operating systems and Linux boxes on your Linux host, you will have to use VMware at least for the Windows part. Whenever possible, however, I use User-Mode Linux for its stability, reliability, and last but not least speed. In terms of speed, there are hosting companies around that offer a virtual server setup at a fraction of the cost of a dedicated server. They often use User-Mode Linux for this task.

Get the Source

When Jeff Dike started the User-Mode Linux project several years ago, he hosted it from the very start on SourceForge. You can download and access all the User-Mode Linux documentation at:

http://user-mode-linux.sourceforge.net/
Additionally, there is a UML-community site at:

http://usermodelinux.org

If you have any problems using User-Mode Linux, you can join the IRC channel #uml on irc.usermodelinux.org.

To get started with User-Mode Linux, you must first download the UML kernel patch and a vanilla Linux kernel from:

http://www.kernel.org
You can then patch and build the kernel by issuing the following commands:

tar xjf linux-<version>.tar.bz2
cd linux
bzcat ../uml-patch-<version>.bz2 | patch -p1
make ARCH=um xconfig
make ARCH=um linux
make ARCH=um modules
You may find it easier to compile a monolithic kernel without using modules. To do so, you can omit the last command. If you have problems building the kernel, you can download a pre-built kernel at the UML homepage. There you will also find additional UML utilities and filesystems that you need to download.

VPN Setup

Next, I will describe how to use the UML kernel to set up a testbed for the VPN shown in Figure 1. This figure shows two VPN gateways connected by a router. Behind both gateways there is an additional machine that will use the tunnel created by the gateways. The router will be implemented on the Linux host. All other machines, both gateways, and both private machines will be emulated.

In this case, we want to use the new IPsec features of the Linux kernel 2.6. For more information about these new features, you can read the September issue of Sys Admin magazine where I explained them in detail (http://www.samag.com/documents/s=8859/sam0309i/).

To begin, you'll need a UML kernel capable of using IPsec. Download a recent UML-patch from the UML homepage and the corresponding 2.6 Linux kernel from kernel.org. Then, extract the kernel and patch it as shown above. When configuring the kernel, disable "Loadable Module Support" and activate all options needed for IPsec (see Figures 2 and 3). Compile the kernel.

Download the uml_utilities from the UML homepage and compile and install them:

tar xjf uml_utilities-<version>.tar.bz2
make
make install
Additionally, you will need a UML filesystem. You can either download your filesystem from the UML homepage or create your own. I usually create my own filesystems, because I like to choose the distribution and packages to install. There are several utilities available to help you create a UML filesystem. The UML homepage lists mkrootfs, gBootRoot, rootstrap, and UML Builder. I usually use UML Builder -- it's a graphical tool capable of building filesystems based on all RPM-based Linux distributions such as Red Hat Linux.

Next, we must configure the host and the UML sessions to use the correct IP addresses. When starting the UML kernel, we can create virtual network interfaces. These network interfaces are either connected to the host or to a separate switch, which is just shared in between chosen UML instances. We want the private client and the corresponding VPN gateway to share a switch. Therefore, we need two switches: one for the left side and one for the right side. The switch is part of the UML utilities and is started using the command uml_switch. Because we need to start two switch instances, we must define the file that the switch uses to communicate with the UML kernel:

uml_switch -unix /tmp/left.ctl
uml_switch -unix /tmp/right.ctl
The uml_switch stays in the foreground. This is especially helpful in the beginning, because you can watch the clients connect to the switch. Later you can start the switch using:

uml_switch -unix /tmp/left.ctl &>/tmp/switch_left &
Now you can start the first private client. When starting the client, you must define the UML root filesystem to use and the switch to connect to. If you want to use a swap filesystem, you first need to create one like this:

dd if=/dev/zero of=swapfs count=128 size=1024k
/sbin/mkswap swapfs
Start the first UML instance:

linux umid="Left private client" root=6200 ubd0=rootfs_left \
  ubd7=swapfs_left eth0=daemon,10:00:01:02:00:00,,/tmp/left.ctl
Once the operating system is booted, it will spawn an xterm. The title of the xterm can be specified using the umid-Option. The UML-block-device ubd0 is the root filesystem. The ub7 is the swap filesystem. The eth0 definition tells the UML kernel how to emulate the UML Ethernet card. Here it will be connected to the uml_switch using /tmp/left.ctl and will use the specified MAC address. Once the client has started, you will see a login similar to the one in Figure 4.

Now start the second private client using:

linux umid="Right private client" root=6200 ubd0=rootfs_right \
  ubd7=swapfs_right eth0=daemon,10:00:02:02:00:00,,/tmp/right.ctl
Once both clients have been started, configure them to use the IP addresses shown in Figure 1. The left private client should use:

IP: 10.0.1.100
Netmask: 255.255.255.0
GW: 10.0.1.1
The right client should use:
IP: 10.0.2.100
Netmask: 255.255.255.0
GW: 10.0.2.1
Next, start the VPN gateways. These gateways both have two network cards. One card is used to connect to the private client using the UML switch. The other card is connected to the host being the router.

Start the first VPN gateway using:

linux umid="Left GW" root=6200 ubd0=rootfs_leftgw \
  ubd7=swapfs_leftgw eth0=tuntap,,,3.255.255.254  \
  eth1=daemon,10:00:01:01:00:00,,/tmp/left.ctl,
Here we define two network cards. The first will use a tap device to connect to the host. The tap0 device on the host will get the IP address 3.255.255.254. The second network card, eth1, will be connected to the switch. Make sure you use a different MAC address here or the switch will not work. As soon as the first VPN gateway has booted, configure the network cards:

eth0:
IP: 3.0.0.1
Netmask: 255.0.0.0
GW: 3.255.255.254
eth1:
IP:10.0.1.1
Netmask: 255.255.255.0
The tap0 interface on the host is configured automatically by the UML kernel:

# /sbin/ifconfig tap0
tap0      Protokoll:Ethernet  Hardware Adresse 00:FF:3C:71:26:13
          inet Adresse:3.255.255.254  Bcast:3.255.255.255  \
          Maske:255.255.255.255 \
          inet6 Adresse: fe80::2ff:3cff:fe71:2613/64 \
            Gltigkeitsbereich:Verbindung
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          Kollisionen:0 Sendewarteschlangenl‰nge:100
          RX bytes:168 (168.0 b)  TX bytes:460 (460.0 b)
Now start the second VPN gateway using:

linux umid="Right GW" root=6200 ubd0=rootfs_rightgw \
  ubd7=swapfs_rightgw eth0=tuntap,,,5.255.255.254 \
  eth1=daemon,10:00:02:01:00:00,,/tmp/right.ctl,
Configure the network cards of the second VPN gateway according to Figure 1. You must configure IP forwarding on both VPN gateways and configure routing on the host. To configure IP forwarding, enter on the VPN gateway:

sysctl -w net.ipv4.ip_forward=1
To configure the routing on the host, use the following commands on the host:

route add -net 10.0.1.0 netmask 255.255.255.0 gw 3.0.0.1
route add -net 10.0.2.0 netmask 255.255.255.0 gw 5.0.0.1
If you have no firewalling enabled, you should be able to log into the left private client and ping the right private client. Running tcpdump on the host should show non-encrypted packets passing back and forth.

To configure a VPN, create the following configuration file, /etc/setkey.conf, on the left gateway:

#!/usr/sbin/setkey -f

# Clear the SAD and SPD
flush;
spdflush;

# Create the IPsec SAs
add 5.0.0.1 3.0.0.1  esp 0x200 -m tunnel -E 3des-cbc 0x3f0b868ad03e68acc6e4e4644
  ac8bb80ecea3426d3d30ada -A hmac-md5 0xbf9a081e7ebdd4fa824c822ed94f5226;
add 3.0.0.1 5.0.0.1  esp 0x200 -m tunnel -E 3des-cbc 0x3f0b868ad03e68acc6e4e4644
  ac8bb80ecea3426d3d30ada -A hmac-md5 0xbf9a081e7ebdd4fa824c822ed94f5226; 

# Create the security policies for the networks
spdadd 10.0.1.0/24 10.0.2.0/24 any -P out ipsec
           esp/tunnel/3.0.0.1-5.0.0.1/require;

spdadd 10.0.2.0/24 10.0.1.0/24 any -P in ipsec
           esp/tunnel/5.0.0.1-3.0.0.1/require;
On the right gateway, use:

#!/usr/sbin/setkey -f

# Clear the SAD and SPD
flush;
spdflush;

# Create the IPsec SAs
add 5.0.0.1 3.0.0.1  esp 0x200 -m tunnel -E 3des-cbc \
  0x3f0b868ad03e68acc6e4e4644  ac8bb80ecea3426d3d30ada \
  -A hmac-md5 0xbf9a081e7ebdd4fa824c822ed94f5226;
add 3.0.0.1 5.0.0.1  esp 0x200 -m tunnel -E 3des-cbc \
  0x3f0b868ad03e68acc6e4e4644  ac8bb80ecea3426d3d30ada \
  -A hmac-md5 0xbf9a081e7ebdd4fa824c822ed94f5226;

# Create the security policies for the networks
spdadd 10.0.1.0/24 10.0.2.0/24 any -P in ipsec
           esp/tunnel/3.0.0.1-5.0.0.1/require;

spdadd 10.0.2.0/24 10.0.1.0/24 any -P out ipsec
           esp/tunnel/5.0.0.1-3.0.0.1/require;
Be aware that the directions (in/out) of the policies have changed. When calling the setkey command /sbin/setkey -f /etc/setkey.conf, these files will manually create the security associations and policies needed to set up an encrypted tunnel between the VPN gateways. When pinging, now tcpdump will see encrypted traffic between the gateways:

13:55:04.084453 3.0.0.1 > 5.0.0.1: ESP(spi=0x00000200,seq=0x1) (DF)
13:55:04.116751 5.0.0.1 > 3.0.0.1: ESP(spi=0x00000200,seq=0x1)
13:55:05.316298 3.0.0.1 > 5.0.0.1: ESP(spi=0x00000200,seq=0x2) (DF)
13:55:05.348958 5.0.0.1 > 3.0.0.1: ESP(spi=0x00000200,seq=0x2)
If your distribution does not provide the setkey command, you can download the ipsec-tools from the ipsec-tools homepage:

http://ipsec-tools.sourceforge.net
These ipsec-tools include the racoon-IKE-daemon, which can also be used to create IPsec tunnels. If you need more information about the ipsec-tools, refer to my IPsec article in the September 2003 issue of Sys Admin magazine.

Using UML, you can emulate any kind of network and test IPsec, Netfilter, IPv6, QoS, etc. Just make sure you include the needed capabilities when configuring and compiling the UML kernel. With UML, you can greatly speed up the testing phase, because you need less hardware and the network setup goes much faster. You can also demonstrate new features more easily because a simple notebook will suffice to demonstrate large networks. I have also used UML very successfully in talks and courses.

Ralf Spenneberg has used Linux since 1992 and worked as a systems administrator since 1994. During this time, he worked on numerous Windows, Linux, and Unix systems. He has been working as a freelancer in the Linux/Unix field for the past five years, mostly providing Linux/Unix training. His specialty is network administration and security (firewalling, VPNs, intrusion detection). He has developed several training classes used by Red Hat and other IT training companies in Germany. He has spoken at several SANS conferences and even more Unix/Linux-specific conferences. He was chosen to be member of the program committee of the Linux Kongress and the GUUG Frühjahrsfachgespräch. He has written two books, Intrusion Detection for Linux Server and VPN using Linux.