Networking and the Host


Now, let's move to a more conventional method of transferring data between machines. Pluggable block devices are cute and sometimes invaluable, but a network is more conventional, more flexible, and usually easier to use. We saw a bit of UML networking in the previous chapter, which showed that UML instances can be used to construct an isolated network. But the value of networking lies in accessing the outside world. Let's do this now.

We will plug a network interface into the UML as we did before, but we are going to use a different host mechanism to transfer the packets:

host% uml_mconsole debian config eth0=tuntap,,,192.168.0.254 OK


At this point, the IP addresses we use will be visible to the outside network, so choose ones that aren't used on your network. If you are using 192.168.0.254 already, change the uml_mconsole command to specify an unused IP address (or one that is already used by a different interface on the host, if IP addresses are scarce on your network). Inside the UML, you should see a message similar to this:

Netdevice 0 : TUN/TAP backend - IP = 192.168.0.254


If it doesn't appear on the main console, you will be able to see it by running dmesg. Some distributions don't have their logging configured so that kernel messages appear on the main console. In this case, running dmesg is the most convenient way to see the recent kernel log.

In this example, we are setting up a virtual network interface on the host that will be connected to the UML's eth0. There are a number of mechanisms for doing this, such as SLIP, PPP, Ethertap, and TUN/ TAP. TUN/TAP is the newest and most general-purpose one of the bunch. It provides a file that, when opened by a process, allows that process to receive and transmit Ethernet frames to the system's network stack.

Figure 5.1 shows an example of using TUN/TAP. Here we have a system with eth0, a wired Ethernet interface; eth1, a wireless interface; and tap0, a TUN/TAP interface. Frames that are routed to eth0 or eth1 are sent to a hub or switch, or to a wireless router, respectively, for delivery to their destination. In contrast, a frame that's routed to the tap0 device is sent to whatever process on the system opened the /dev/ net/tun file and associated that file descriptor with the tap0 interface.

Figure 5.1. TUN/TAP provides an interface for processes to receive and transmit network frames


This process may do anything with the frames it receives. UML will send the frames through its own network stack, which could do almost anything with them, including delivering the data to a local process, forwarding them to another host that it's connected to, or just dropping them.

UML isn't the only process that can attach itself to a TUN/TAP interfacevtund is another example. vtund is used to construct a Virtual Private Network (VPN)it will read frames from a TUN/TAP interface, encrypt them, and forward them to another vtund instance on a remote host. The remote vtund will decrypt the frames and inject them into the network on its host by writing them to its TUN/TAP interface. So, the TUN/TAP interface provides a general-purpose mechanism for processes to receive and transmit network traffic and do any sort of processing on it.

This is unlike the mcast transport we saw in the previous chapter in that frames sent to a TUN/TAP device are interpreted and routed by the host's network stack. With mcast, the frames were simply hunks of data to be sent from one process to another. Since frames sent to a TUN/TAP device are seen as network frames by the host, they will be routed to whatever host owns the frame's destination IP address. That could be the host itself, another machine on the local network, or a host on the Internet.

Similarly, if the IP address given to the UML is visible to the outside world (the ones we're using will be visible on the local net, but not to the Internet as a whole), people in the outside world will be able to make network connections to it. It will appear to be a perfectly normal network host.

A TUN/TAP device is very similar to a strand of Ethernet connecting the host and the UML. Each end of the strand plugs into a network device on one of the systems. As such, the device at each end needs an IP address, and the two ends need different IP addresses. The address we specified on the uml_mconsole command line, 192.168.0.254, is the address of the host end of the TUN/TAP device.

The fact that a TUN/TAP interface is like a strand of Ethernet has an important implication: The TUN/TAP interface and the UML eth0 form their own separate Ethernet broadcast domain, as shown in Figure 5.2. This means that any Ethernet broadcast protocols, such as ARP and DHCP, will be restricted to those two interfaces and the hosts they belong to. In contrast, the local Ethernet on which the host resides is a broadcast domain with many hosts on it. Without some extra work, protocols like ARP and DHCP can't cross between these two domains. This means that a UML instance can't use the DHCP server on your local network to acquire an IP address and that it can't use ARP to figure out the MACs of other hosts in order to communicate with them. In Chapter 7, we will discuss this problem in detail and see several methods for fixing it.

Figure 5.2. TUN/TAP interfaces form their own Ethernet networks


Returning to our exercise, the next step is to bring up the UML eth0, which is the other end of the strand, and to assign an IP address to it. Since it's a different system, it will need a different unused IP address. Here, I will use 192.168.0.253 :

UML# ifconfig eth0 192.168.0.253 up * modprobe tun * ifconfig tap0 192.168.0.254 netmask 255.255.255.255 up * bash -c echo 1 > /proc/sys/net/ipv4/ip_forward * route add -host 192.168.0.253 dev tap0 * bash -c echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp * arp -Ds 192.168.0.253 eth1 pub


Again, if the output above doesn't appear on your console, run dmesg to see it. The UML network driver is running a helper process on the host in order to set up the host side of the network, and this output shows what commands the helper is running. We will go into much more detail in Chapter 7, but, briefly, these are making sure that TUN/ TAP is available on the host, configuring the TUN/TAP interface, tap0, and setting up routing and proxy arp so that the instance will be visible on your local network.

At this point, we have the network running between the host and the UML instance, and you should be able to ping back and forth:

UML# ping 192.168.0.254 PING 192.168.0.254 (192.168.0.254): 56 data bytes 64 bytes from 192.168.0.254: icmp_seq=0 ttl=64 time=19.6 ms --- 192.168.0.254 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 19.6/19.6/19.6 ms host% ping 192.168.0.253 PING 192.168.0.253 (192.168.0.253) 56(84) bytes of data. 64 bytes from 192.168.0.253: icmp_seq=0 ttl=64 time=0.209 ms --- 192.168.0.253 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.209/0.209/0.209/0.000 ms, pipe 2


This is the most basic level of networking. The next step is to access the outside world. We need to do two thingsgive our UML instance a route to the outside, and give it a name server. First, look at the UML routing table:

UML# route -n Kernel IP routing table Destination     Gateway         Genmask         Flags Metric Ref \     Use Iface 192.168.0.0     0.0.0.0         255.255.2550    U     0      0   \     0 eth0


This tells us we have a route to the local network, but nothing else. So, we need a default route:

UML# route add default gw 192.168.0.254 UML# route -n Kernel IP routing table Destination     Gateway         Genmask         Flags Metric Ref \     Use Iface 192.168.0.0    0.0.0.0          255.255.255.0   U     0      0   \     0 eth0 0.0.0.0        192.168.0.254    0.0.0.0         UG    0      0   \     0 eth0


This new route just tells the UML network to send all packets it doesn't know what to do with (in this case, those not destined for the local network) to the host tap interface and let it deal with them. Presumably, the host has access to the Internet and knows how to route packets to it.

Second, we need to give the UML instance an /etc/ resolv.conf. This is normally set up by DHCP, but since we are setting up the network by hand, this must be done by hand, too. I normally just copy the host's /etc/resolv.conf:

UML# cat > /etc/resolv.conf ; generated by /sbin/dhclient-script search user-mode-linux.org nameserver 192.168.0.3


I just cut the host's resolv.conf from one xterm window and pasted it into another that has UML running in it. You should do something similar here. Definitely don't use my resolv.conf since that won't work on your network.

We need to set up one thing on the host. Since I am using the 192.168.x.x address block, the host will need to do masquerading for it. This address block and the 10.x.x.x one are nonroutable, so they can't be used by any machine that has direct access to the Internet. Masquerading, or Network Address Translation (NAT), on the host will solve this problem by having the host use its own address for outgoing UML network traffic.

If you are using normal, routable IP addresses, you don't need to worry about masquerading. But if you are using a nonroutable IP address for your instance, you need to NAT it. So, as root on the host, run:

host# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE


If eth0 is not the device used to access the Internet, change that part of the code to the correct device. For example, if you're a dialup user with Internet access through the ppp0 device, you would use ppp0 instead of eth0.

It is common for the firewall on the host to interfere with UML's ability to communicate with any machines other than the host. To see if your host has a potentially interfering firewall, run iptables -L as root. If you have no firewall, you will see this:

Chain INPUT   (policy ACCEPT) target     prot  opt  source              destination Chain   FORWARD (policy ACCEPT) target     prot  opt  source              destination Chain OUTPUT    (policy ACCEPT) target     prot  opt  source              destination Chain   RH-Firewall-1-INPUT (0 references) target     prot  opt  source              destination


If you see anything else, it's a good idea to poke a hole in the firewall for the UML instance's traffic like this, again as root:

host# iptables -I FORWARD -d 192.168.0.253 -j ACCEPT host# iptables -I FORWARD -s 192.168.0.253 -j ACCEPT


This tells the host to allow all traffic being forwarded to and from 192.168.0.253, the IP address that we've assigned to the UML instance, through the firewall. You might imagine that there are security implications to this, since a firewall is an important part of any network's security infrastructure, and there are. This means that any attacks aimed at the UML IP address will reach it. Whether they succeed is a different question altogether. But this is simply making a new host accessible to the outside network, including anything malicious out there.

If the host is masquerading the UML IP, that provides a degree of protection because it is invisible to the outside network, except for connections that it initiates itself. For example, if you ran a Web browser in the UML instance and loaded a Web page from a malicious Web site, the instance could be attacked by that site, through the browser. However, the instance is invisible to everything else, including worms and other malicious software scanning the network for victims. The downside of this is that it would be unusable as a server, since that would require that it be visible enough for outside clients to make connections to it.

The situation is somewhat different if you are using a real, routable IP for your UML. In this case, it is visible on the outside network and to whatever nasty things are scanning it.

In either case, you want the UML to be a full-fledged member of the network, so you need to take the same care with its security as you do with any physical machine. Make sure that the distribution you are booting in it is reasonably up to date and that you take the same precautions here as you take elsewhere.

With masquerading set up, and a hole poked in the host firewall if necessary, the UML should now be a full member of your network. We can do another simple test to make sure the UML has name service:

UML# host www.user-mode-linux.org www.user-mode-linux.org A       66.59.111.166


Now that this works, we can check that we have full Internet access by pinging http://www.user-mode-linux.org:

UML# ping www.user-mode-linux.org PING www.user-mode-linux.org (66.59.111.166): 56 data bytes 64 bytes from 66.59.111.166: icmp_seq=0 ttl=52 time=223.7 ms 64 bytes from 66.59.111.166: icmp_seq=1 ttl=52 time=38.9 ms --- www.user-mode-linux.org ping statistics --- 3 packets transmitted, 2 packets received, 33% packet loss round-trip min/avg/max = 38.9/131.3/223.7 ms


At this point, we can start playing with the UML from the outside. There should be an Apache running inside it, and you should now be able to access it at http://192.168.0.253 with your favorite browser. This is what wget shows from the host:

host% wget http://192.168.0.253 --16:40:43--  http://192.168.0.253/            => `index.html' Connecting to 192.168.0.253:80... connected. HTTP request sent, awaiting response... 200 OK Length: 4,110 [text/html] 100%[====================================>] 4,110 3.92M//s \     ETA 00:00 16:40:43 (3.92 MB/s) - `index.html' saved [4110/4110]


This is the default Apache install page. You can now turn your UML instance into a Web server by installing some real content into Apache's html directory. You can figure out where this is by finding httpd.conf under either /etc/apache or /etc/httpd and looking at how it defines DocumentRoot:

UML# grep DocumentRoot /etc/apache/conf/httpd.conf # DocumentRoot: The directory out of which you will serve your DocumentRoot /var/www # This should be changed to whatever you set DocumentRoot to. #    DocumentRoot /www/docs/host.some_domain.com


In this case, Apache expects HTML content to be put in /var/www. If you put some Web pages there, they would be visible in your browser on the host.

The next thing many people like to do is remotely log in to their instance. ssh is the usual way to do this, and it works exactly as you'd expect:

host% ssh root@192.168.0.253 Password: Last login: Mon May 23 19:56:28 2005


Here, I logged in as root since that's how I normally log in to a UML instances. If you create an account for yourself and put your ssh public key in it, you'll be able to log in to your instance as yourself, without needing a password, just as you do with any physical machine.

Obviously ssh in the other direction will work just as well. I continue this session by logging back in on the host as myself:

UML# ssh jdike@192.168.0.254 jdike@192.168.0.254's password: host%


You'll want to substitute your own username for mine in the ssh command line.

With Web and ssh access working, it should be clear that the network is operating just as it does with any Linux machine. Now, let's look at another use of the network, X, and how it can be virtualized.

First, let's see that X clients running inside UML can be displayed on the host display. There are several authorization mechanisms in use by X and Xlib to ensure that X applications can connect only to displays they're allowed on. The two most common are xhost and Xauthority. Xauthority authorization relies on a secret (a magic cookie) stored in ~/.Xauthority by the session manager when you log in. A client is expected to read that file; if it can, that is considered evidence that it has sufficient permissions to connect to your display. It presents the contents of the file to the X server, which checks that it really is the contents of your. Xauthority file.

The other mechanism is xhost, which is a simple access control list (ACL) naming remote machines that are allowed to connect to your display. This is less fine-grained than Xauthority since it would allow someone else logged in to a remote machine in your xhost list to open windows on your display. Despite this disadvantage, I will use xhost authorization here.

First, on whatever machine you're sitting in front of (which may not be the UML host, as it is not for me), run xhost:

X-host% xhost access control enabled, only authorized clients can connect


This tells us that xhost access is enabled, which is good, and that no one has xhost access to this display. So, let's give access to the UML:

X-host% xhost 192.168.0.253 192.168.0.253 being added to access control list X-host% xhost access control enabled, only authorized clients can connect INET:192.168.0.253


Your X server may be configured to not accept remote connections. You can check this by running ps to see the full X server command line:

X-host% ps uax | grep X root       4215 1.6  2.4  59556 12672 ?      S 10:29      7:44 \     /usr/X11R6/bin/X :0  -audit 0 -auth /var/gdm/:0.Xauth \     -nolisten tcp vt7


-nolisten tcp causes any attempts to make X client connections fail with "connection refused." This causes the X server to accept local connections only by accepting them through a UNIX-domain socket. It is not listening to a TCP socket, and it is inaccessible to the network.

To change this, I ran gdmsetup, selected the Security tab, and turned off the "Always disallow TCP connections to X server" option. Other display managers, such as xdm or the KDE display manager, probably have similar setup applications. Then, it's necessary to restart the X server. Logging out usually suffices. You should recheck the X command line after logging back in to see that -nolisten has disappeared. If it hasn't, it may be necessary to kill the display manager to force it to restart.

Now, we need to set our DISPLAY environment variable inside UML to point at our display:

UML# export DISPLAY=192.168.0.254:0


Here I'm assuming that the machine you're using is the UML host and that you chose the IP address we assigned to the host end of the tap device. Any IP address associated with that host, or its name, would work equally well.

Now you should be able to run any X client on the UML and see it display on your screen. Starting with xdpyinfo or xload to see that it basically works is a good idea. What's more fun is xterm. This gives you a terminal on the UML without needing to log into it anymore.

Now that we have X working between the UML and the rest of the world, let's introduce a new sort of virtualization, in keeping with the spirit of this book. It is possible to virtualize X by running a process that appears to be an X server to X clients, and a client to an X server. This application is called Xnest, [1] and its name pretty well describes it. It creates a window on its own X server, which is its own root window, then accepts connections from other clients, displaying their windows on this root window.

[1] You likely don't have Xnest (or other X packages) installed in your UML filesystem. On Fedora, Xnest comes in the xorg-x11-Xnest package and requires the fonts-xorg-75dpi package, which doesn't get pulled in automatically because of a missing dependency. You also will likely want the xorg-x11-tools package, which has the common X11 utilities in it.

This little root window is a totally different display from the main one. There can and generally will be separate session and window managers running on it. They will be completely confined to that window and will not be able to tell that there's anything outside it.

Xnest has nothing to do with UML, but it's easy to draw parallels between them. A good one is between this little root window inside the main one, on the one hand, and the UML filesystem in a host file on the host filesystem, on the other. In both cases, the host sees something, either a file or a window, that, unbeknownst to it, contains a full universe, either the filesystem run by UML or the X session run by Xnest.

Running Xnest is simple:

UML# Xnest :0 & [2] 1785


:0 tells Xnest to become display 0 on the UML instance. On a physical machine with a display already attached to it, you would normally use display 1 or greater. The instance has no incumbent displays, so Xnest can use display 0.

You should now see a largish blank window on your screen. This is the new virtual display. Next, set the DISPLAY environment variable inside UML to use the Xnest display:

UML# export DISPLAY=:0


At this point, you can run some X clients, and you will see their windows appear within this virtual X display. You will also notice that they have no borders and can't be moved, resized, or otherwise adjusted. The thing to do now is run a window manager so that these windows become controllable. Here, I'm using fvwm, a lightweight, minority window manager:

UML# fvwm & [5] 2067


Now you should see borders around the windows within the Xnest display, and you should be able to move them around just as on your normal display.

To get a bit surreal, let's run an X client on the host, displaying over the network to the UML Xnest, which is displaying back over the network to the host. First, we need to do the same X security things inside the UML instance as we did on the host earlier. For this step, make sure there is some X client attached to the Xnest display through the entire process. The X server reinitializes itself whenever the last client disconnects, and this reinitialization includes resetting the xhost list. This is a problem because xhost itself is a client, and if it is the only one, when it disconnects, it triggers this reinitialization, which unfortunately throws out the permission changes it added.

Running xhost on the UML now shows:

UML# xhost access control enabled, only authorized clients can connect INET:192.168.0.253 LOCAL:


So, right now, the UML allows connections from local clients, either connecting over a UNIX domain socket (LOCAL:) or over a local TCP connection. We need to add the host from which we will be running clients and to which we will be ultimately displaying them back:

UML# xhost 192.168.0.254 192.168.0.254 being added to access control list UML# xhost access control enabled, only authorized clients can connect INET:192.168.0.254 INET:192.168.0.253 LOCAL:


Now, if we go back to the host and display to the UML display 0, we should see those clients within the virtual X display:

host% export DISPLAY=192.168.0.253:0 host% xhost access control enabled, only authorized clients can connect INET:192.168.0.254 INET:192.168.0.253 LOCAL: host%  xterm & [1] 7535 host% fvwm & [2] 7654


Now, as expected, we have a host window manager and xterm window displaying within the virtual X display running on the UML. Figure 5.3 shows a partial screenshot of a display with an Xnest running from a UML instance. I have xhost set up as described earlier, and the xterm window inside the Xnest is running over the network from a third host. There is also a local xload window and window manager running inside the Xnest.

Figure 5.3. UML running Xnest


Now, strictly speaking, none of this Xnest stuff required UML. Everything we just did could have been done on the host, with Xnest providing a second display that happens to be shown on part of the first. However, it is a nice example of providing a virtual machine with a new piece of virtualized hardware that behaves just like the equivalent piece of physical hardware. It also shows another instance of constructing this virtual device with part of the equivalent physical hardware. As I pointed out earlier, the analogy of Xnest with other UML devices is more than skin deep. Xnest does have a role to play with UML, even if it was created independent of and earlier than UML, and even if it is rarely required for day-to-day work.



User Mode Linux
User Mode Linux
ISBN: 0131865056
EAN: 2147483647
Year: N/A
Pages: 116
Authors: Jeff Dike

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net