Anonymous FTP server under Solaris

Setting up an anonymous FTP server under Solaris, when using the built-in in.ftpd daemon, is a little bit different than setting it up under GNU/Linux using WUftpd.

First, let’s create the ftp user and ftp group. Then, let’s create the home directory for the ftp user:

mkdir -p /export/home/ftp
groupadd -g 99 ftp
useradd -u 99 -g 99 -s /bin/false -d /export/home/ftp
chgrp ftp:ftp /export/home/ftp

If you want anonymous users to upload files under /pub, add the following line to /etc/ftpd/ftpaccess:

upload          class=anonusers /export/home/ftp /pub yes ftp ftp 0600 nodirs

Next, copy the minimal set of dynamic libraries and binaries to make possible browse and list files for anonymous users:

mkdir -p ~ftp/bin
mkdir -p ~ftp/usr/bin
ln -s ../bin ~ftp/usr/bin
cp /usr/lib/{ld,libc,libdl,libgen}.so.1 ~ftp/usr/lib
cp /bin/ls ~ftp/bin

To enable the FTP server, uncomment the following line in /etc/inetd.conf:

ftp     stream  tcp6    nowait  root    /usr/sbin/in.ftpd       in.ftpd -a

and notify the inetd daemon of the change by sending the HUP signal to it:

pkill -1 inetd

Mac OS X, Bluetooth and Motorola UMTS phones

NOTE: This post is a based on Mac OS X, Bluetooth and Nokia UMTS phones that I wrote some days ago, but adapted to Motorola 3G phones.

This brief post explains how to pair Mac OS X with a Motorola 3G/UMTS phone in order to access the Internet via a data packet connection. In my case, I’m using a Motorola RAZR V3xx phone but any other Motorola 3G phone should work.

Before you start, please make sure that your phone is properly configured and that you can browse the Web via a GPRS/UMTS connection. Also, make sure that Bluetooth support in your phone is configured and activated and, for phones that have temporary visibility (are only visible via Bluetooth for a limited period of time), make sure to enable Bluetooth just before the pairing process.

Initial configuration

First, download the Motorola 3G Modem Scripts for Mac OS X from Ross Barkman’s Home Page (the official site) or from here.

Second, uncompress the file and copy the files named “Motorola 3G CID1” and “Motorola 3G CID2” into “/Library/Modem Scripts“.

Next, pair your Mac OS X computer with the Motorola phone by clicking on the Bluetooth icon in the menu bar and then Set up Bluetooth Device…. When pairing make you sure you choose Use a direct, higher speed connection to reach your Internet Service Provider *GPRS, 1xRTT).

Enter guest as the Username, guest as the Password, the APN (CID String or Telephone number) and make sure Motorola 3G CID1 is selected as the Modem Script. For example:

For a detailed list of possible combinations of username, password and APN CID for a lot of providers around the world visit Ross Barkman’s GPRS Info Page.

Dialing out

To dial out, open Internet Connect, browse to the Bluetooth tab and make sure the right entry is selected from the drop down menu. Then click Connect. Mac OS X will authenticate to the remote PPP server and a new dynamic PPP subinterface should be configured:

$ ifconfig ppp0
ppp0: flags=8051 mtu 1500
        inet 10.142.15.9 --> 10.6.6.6 netmask 0xffffff00

In my case, browsing speed is very good (around 384Kbps), but it might vary according to placement, coverage, whether you are moving and so on (by the way, UMTS network planning, deployment and coverage is something not trivial).

Troubleshooting

Make sure all the information for the connection have been entered correctly, specially the APN/Telephone number. If it doesn’t work, try using Motorola 3G CID2 as the Modem Script instead.

Mac OS X, Bluetooth and Nokia UMTS phones

This brief post explains how to pair Mac OS X with a Nokia 3G/UMTS phone in order to access the Internet via a data packet connection. In my case, I’m using a Nokia 6234 phone but any other Nokia phone should work.

Before you start, please make sure that your phone is properly configured and that you can browse the Web via a GPRS/UMTS connection. Also, make sure that Bluetooth support in your phone is configured and activated and, for phones that have temporary visibility (are only visible via Bluetooth for a limited period of time), make sure to enable Bluetooth just before the pairing process.

Initial configuration

First, download the Nokia 3G Modem Scripts for Mac OS X from Ross Barkman’s Home Page (the official site) or from here.

Second, uncompress the file and copy the files named “Nokia 3G CID1” and “Nokia 3G CID2” into “/Library/Modem Scripts“.

Next, pair your Mac OS X computer with the Nokia phone by clicking on the Bluetooth icon in the menu bar and then Set up Bluetooth Device…. When pairing make you sure you choose Use a direct, higher speed connection to reach your Internet Service Provider *GPRS, 1xRTT).

Enter guest as the Username, guest as the Password, the APN (CID String or Telephone number) and make sure Nokia 3G CID1 is selected as the Modem Script. For example:

For a detailed list of possible combinations of username, password and APN CID for a lot of providers around the world visit Ross Barkman’s GPRS Info Page.

Dialing out

To dial out, open Internet Connect, browse to the Bluetooth tab and make sure the right entry is selected from the drop down menu. Then click Connect. Mac OS X will authenticate to the remote PPP server and a new dynamic PPP subinterface should be configured:

$ ifconfig ppp0
ppp0: flags=8051 mtu 1500
        inet 10.142.15.9 --> 10.6.6.6 netmask 0xffffff00

In my case, browsing speed is very good (around 384Kbps), but it might vary according to placement, coverage, whether you are moving and so on (by the way, UMTS network planning, deployment and coverage is something not trivial).

Troubleshooting

Make sure all the information for the connection have been entered correctly, specially the APN/Telephone number. If it doesn’t work, try using Nokia 3G CID2 as the Modem Script instead.

Xen network configuration and multiple VLANs

Xen networking is powerful enough to allow for extreme customization. Although the default networking configuration is usually more than enough for simple scenarios, it can fall short when trying to support multiple guests standing on different VLANs.

In this short article, I describe the steps needed to configure Xen to attach itself to multiple VLANs using a one-bridge-per-VLAN network interface mapping, then attaching each Xen domainU on as many VLANs as needed.

In the sample scenario, we will use a Cisco Catalyst 3560G-24TS switch carrying traffic from five different VLANs:

  • VLAN2 is the administrative VLAN used to administer all the networking gear and boxes.
  • VLAN10 carries Internet traffic coming from the first ISP.
  • VLAN20 carries Internet traffic coming from the second ISP.
  • VLAN100 carries the access network traffic.
  • VLAN200 carries the core network traffic.

The final Xen configuration will provide five bridging network interfaces, one per VLAN. Each Xen domainU can freely attach to any of these bridging network interfaces in order to gain access to the traffic being carried by each VLAN.

The bridging interface, |brname| is named after the following convention: xenbr|vlan|:

  • xenbr2 is the bridging interface standing on VLAN2.
  • xenbr10 is the bridging interface standing on VLAN10.
  • xenbr20 is the bridging interface standing on VLAN20.
  • xenbr100 is the bridging interface standing on VLAN100.
  • xenbr200 is the bridging interface standing on VLAN200.

Also, Xen creates an manages several virtual network interfaces, named in the form of vif|X|.|Y|, where |X| equals the Xen domain numeric ID and |Y| is a sequential interface index. Thus, starting up a Xen domainU given the following virtual network interface definition:

vif = [ 'mac=00:16:3e:00:00:44, bridge=xenbr10',
        'mac=00:16:e3:00:00:45, bridge=xenbr20' ]

Will cause the Xen domain to get assigned, let’s say, a domain ID of 2, and two virtual network interfaces named vif2.0 — attached to xenbr10 — and vif2.1 — attached to xenbr20.

Setting up the bridging interfaces:

This can be done manually, by invoking brctl addbr |brname| in order to create a new bridging interface.

For example, the following commands will create five bridging interfaces, one for each supported VLAN:

brctl addbr xenbr2
brctl addbr xenbr10
brctl addbr xenbr20
brctl addbr xenbr100
brctl addbr xenbr200

or else can be automated to get done during system startup, by creating a file named /etc/sysconfig/network-scripts/ifcfg-|brname|, where |brname| is the name assigned to the bridging interface, like /etc/sysconfig/network-scripts/ifcfg-xenbr2 (the configuration file for the bridging interface standing on VLAN2):

DEVICE=xenbr2
BOOTPROTO=static
IPADDR=192.168.0.10
NETMASK=255.255.0.0
ONBOOT=yes
TYPE=Bridge

Setting up the VLAN interfaces and add them up to the existing bridging interfaces:

This can be done manually, by invoking vconfig add |ifname| |vlan| to configure VLAN number |vlan| by using 802.1q tagging on interface |ifname|. This will active a virtual interface named |ifname|.|vlan|:

  • Any traffic sent to this interface will get tagged for VLAN |vlan|.
  • Any traffic received from interface |ifname| carrying an 802.1q VLAN tag matching |vlan| will be untagged and received by this interface.
vconfig add eth0 2
vconfig add eth0 10
vconfig add eth0 20
vconfig add eth0 100
vconfig add eth0 200

This will add five new VLAN interfaces, one for every supported VLAN.

Once the VLAN interfaces are ready, we add them to their corresponding bridging interfaces by using brctl addif |brname| |ifname|.|vlan|:

brctl addif xenbr2 eth0.2 brctl addif xenbr10 eth0.10 brctl addif xenbr20 eth0.20 brctl addif xenbr100 eth0.100 brctl addif xenbr200 eth0.200

The process of adding up a new VLAN interface and then adding it up to an existing bridging interface can be configured using a single configuration file named ifcfg-|ifname|.|vlan|, like /etc/sysconfig/network-scripts/ifcfg-eth0.2:

DEVICE=eth0.2 BOOTPROTO=none ONBOOT=yes TYPE=Ethernet VLAN=yes BRIDGE=xenbr2

Keeping Xen from reconfiguring the network:

Since we have already configured the network manually, we don’t want Xen to mess up with the configuration. In order to keep Xen from reconfiguring the network, simply make sure none of the following lines appear uncommented in the file /etc/xen/xend-config.sxp:

(network-script network-bridge)
(network-script network-route)
(network-script network-nat)

Additional notes:

I have been experiencing a very strange behavior on Xen domainU guests while using this network configuration: it seems that UDP traffic gets stuck at the network stack and does not flow through unless I load the ip_conntrack.ko kernel module.

Failing to load the ip_conntrack.ko kernel module, even with an unconfigured, empty firewall, allows ICMP and TCP traffic to flow from and to the guest network stack, but UDP traffic, like DNS queries, gets stuck and doesn’t even touch the physical network interface.

This is really strange, isn’t it?

Linksys, OpenWRT and multiple VLANs

The Cisco Linksys WRT54G/GS/GL is made up of a six-port configurable switch, a standard Ethernet controller (usually a Broadcom controller named eth0) and a Wireless controller (usually a Broadcom controller named eth1).

The following diagram tries to illustrate the different components that made up the Cisco Linksys and how are they interconnected:

                                            Linksys rear
 Trunk    Internet    1     2     3     4   port number
  ---        ---     ---   ---   ---   ---
  |5|        |4|     |3|   |2|   |1|   |0|  switch port number
  ---        ---     ---   ---   ---   ---
  |           |       |                 |
  |         vlan1     |----- vlan0 -----|
  |
  | Miniswitch
  ----------------------------------------
  | Linux
  |
  |           ---- vlan0 -> LAN
  |           |
  |----- eth0 -
              |
              ---- vlan1 -> Internet/WAN

The standard Ethernet controller is attached to the sixth port (port #5) of the switch and is configured as a 802.1q VLAN trunk port. This allows running several VLANs using a single connection to the switch.

By default, OpenWRT configures two per-VLAN network interfaces:

  • vlan0:

    stands on the VLAN0 (the Local Area Network which comprises the four ports labeled as 1, 2, 3 and 4 at the rear of the box).

  • vlan1:

    stands on the WAN network (the port labeled Internet at the rear of the box).

The VLAN configuration is controlled using NVRAM variables. The variable labeled vlan0ports defines which switch ports are assigned onto the VLAN0, while vlan1ports defines which switch ports are assigned onto the VLAN1.

This is the default NVRAM configuration:

nvram set vlan0ports="3 2 1 0 5*"
nvram set vlan0hwname=et0
nvram set vlan1ports="4 5"
nvram set vlan1hwname=et0
  • vlan0ports:

    states that ports #3, #2, #1 and #0 (the ports labeled as 1, 2, 3 and 4 at the rear of the box) are assigned onto VLAN0. Additionally, port #5 is also assigned onto VLAN0.

    The asterisk sitting besides the 5 means VLAN0 is the default, native VLAN for this port, so any untagged traffic is considered to belong to VLAN0.

  • vlan1ports:

    states that port #4 (the port labeled as Internet at the rear of the box) is assigned onto VLAN1. Additionally, port #5 is also assigned onto VLAN1 since it’s a trunk port.

    The lack of an asterisk means VLAN1 is not the default, native VLAN for this port.

NOTE: vlannhwname needs to have a value assigned to it, even when it’s value is never used by the init scripts. This value is usually et0.

NOTE: Care must be exercised as ports numbers are zero-based, as illustrated before, and the sixth-port (port #5) must be assigned to every VLAN, since it is an VLAN trunk port.

The following code snippet from /etc/init.d/S10boot shows how the init script tells the switch which ports are onto which VLANs:

# configure the switch based on nvram
[ -d /proc/switch/eth0 ] &ports)"
    [ -z "$vp" -o -z "$(nvram get vlan${nr}hwname)" ] || {
        echo "$vp" > /proc/switch/eth0/vlan/$nr/ports
    }
  done
}

We can also see that up to sixteen VLANs are supported by the switch.

Custom VLANs

The Linksys and OpenWRT combination is so flexible that we can configure additional VLANs. In fact, I was looking to add an additional administrative VLAN (VLAN2) granting me full access to the box while I could restrict access from the LAN and WAN to the minimum — for example, by using additional firewall rules.

This is depicted in the following figure:

                                            Linksys rear
 Trunk    Internet    1     2     3     4   port number
  ---        ---     ---   ---   ---   ---
  |5|        |4|     |3|   |2|   |1|   |0|  switch port number
  ---        ---     ---   ---   ---   ---
  |           |       |     |           |
  |         vlan1   vlan2   |-- vlan0 --|
  |
  | Linksys
  ----------------------------------------
  | Linux
  |
  |           ---- vlan0 -> LAN
  |           |
  |----- eth0 ---- vlan1 -> Internet/WAN
              |
              ---- vlan2 -> Administrative VLAN

To achieve this configuration, we need to remove port #3 (labeled as 1 at the rear of the box) from VLAN0 and assign it onto VLAN2. We also need to add port #5 to the VLAN2 since it is the VLAN trunk port used to carry the traffic from the switch to Linux through the standard Ethernet controller:

nvram set vlan0ports="2 1 0 5*"
nvram set vlan0hwname=et0
nvram set vlan1ports="4 5"
nvram set vlan1hwname=et0
nvram set vlan2ports="3 5"
nvram set vlan2hwname=et0

I’ve defined three custom NVRAM variables that will get used by an additional init script to configure the VLAN2 as an administrative VLAN, granting full access to the box:

  • adm_ifname:

    defines the Linux network interface name assigned to the administrative VLAN, in the form of vlann, where n is the VLAN number.

  • adm_ipaddr:

    defines the IP address for the administrative interface.

  • adm_netmask:

    defines the network mask for the administrative interface.

For example:

nvram set adm_ifname=vlan2
nvram set adm_ipaddr=192.168.0.100
nvram set adm_netmask=255.255.0.0

I’ve also coded up an additional init script, named /etc/init.d/S41network, used to bring up the administrative interface. I’ve decided not to fiddle with /etc/init.d/S40network to avoid breaking things and having problems during upgrades.

These are the contents of /etc/init.d/S41network:

#!/bin/sh
IFNAME=$(nvram get adm_ifname)
VLAN=${IFNAME##vlan}
IPADDR=$(nvram get adm_ipaddr)
NETMASK=$(nvram get adm_netmask)
vconfig add eth0 $VLAN
ifconfig vlan${VLAN} up ${IPADDR} netmask ${NETMASK}

Testing

To test this custom configuration, I recommend disabling the firewall, my removing the executable permission bit from /etc/init.d/S45firewall and /etc/init.d/S41network just to prevent being locked out from the box in case problems arise.

Firewalling

I’ve also replaced the firewalling init script, /etc/init.d/S45firewall, with my own version. This allows for a fine-grained and thighter configuration.

Since the box will act as a routing firewall, and since it has 3 VLANs, I wanted to apply the following policy:

  • Any traffic coming from or going to the administrative VLAN (VLAN2) is allowed:

    This rule allows administering the box from a computer attached to the VLAN2, while blocking administrative access from other VLANs.

  • Incoming ICMP Echo Requests and ICMP Time Exceeded control messages are allowed from any interface:

    This rule allows certain ICMP control messages to reach the box. ICMP Echo Request is needed in order for the box to respond to ping and ICMP Time Exceeded (TTL) so we don’t break the PMTU discovery algorithm.

  • Any other incoming traffic from the LAN is rejected:

    This rule rejects any other traffic which does not match previous rules. Traffic is explicitly rejected, so we avoid having clients blocked waiting for an RST TCP segment.

  • Any other incoming traffic from the WAN is dropped:

    This rule silently drops any traffic coming from the WAN which does not match any previous rule. This will make external scan attacks much slower.

  • Local DNS queries coming from the local box going to configured DNS servers are allowed:

    This rule allows the local machine to resolve DNS queries sent against configured DNS servers (those configured in the wan_dns NVRAM variable). This is rarely needed, but the ipkg command requires a working DNS name resolution.

  • HTTP traffic from the local machine to the WAN is allowed:

    This rule allows upgrading and installing packages using the ipkg command.

  • Outgoing ICMP Echo Requests and ICMP Time Exceeded control messages are allowed from any interface:

    This rule allows certain ICMP control messages to depart from the box. ICMP Echo Request is needed in order for the box to invoke ping and ICMP Time Exceeded (TTL) so we don’t break the PMTU discovery algorithm.

  • Forwarding SSH/NX traffic coming from WAN to the designated SSH/NX server in the LAN:

    This rule allows accesing the SSH/NX traffic from the WAN. In addition, I apply SNAT to make IP datagrams appear to come from the firewall box since I have multiple DSL links.

  • Forwarding HTTP and HTTP/S traffic coming from the LAN targeted to the WAN:

    This rule allows using HTTP and HTTP/S services from the LAN.

  • DNS queries coming from the LAN going to configured DNS servers are allowed:

    This rule allows the machines in the LAN to resolve DNS queries sent against configured DNS servers (those configured in the wan_dns NVRAM variable).

  • Forwarding ICMP Echo Requests coming from the LAN to the WAN:

    This allows pinging external hosts from the LAN. ICMP Time Exceeded, however, is not forwarded, since the firewall sits in the middle between the LAN and the WAN (and I do use SNAT and DNAT).

Here is the complete /etc/init.d/S45firewall script:

#!/bin/sh
IPTABLES=/usr/sbin/iptables
FW_INET_IFACE=$(nvram get wan_ifname)
FW_INET_IP=$(nvram get wan_ipaddr)
FW_PRIVATE_IFACE=$(nvram get lan_ifname)
FW_PRIVATE_IP=$(nvram get lan_ipaddr)
FW_ADM_IFACE=$(nvram get adm_ifname)
NX_IP=10.200.0.10

$IPTABLES -F
$IPTABLES -t nat -F

# Configure SNAT/DNAT/MASQUERADE
$IPTABLES -t nat -A PREROUTING -i ${FW_INET_IFACE} -p tcp 
                               -d ${FW_INET_IP} --dport 179 
                               -j DNAT --to-destination ${NX_IP}:22
$IPTABLES -t nat -A POSTROUTING -o ${FW_PRIVATE_IFACE} -p tcp 
                                -d ${NX_IP} --dport 22 
                                -j SNAT --to-source ${FW_PRIVATE_IP}
$IPTABLES -t nat -A POSTROUTING -o ${FW_INET_IFACE} -j MASQUERADE

# Configure input firewall filtering:
# Allow:
#   - Traffic flowing from the loopback interface
#   - Traffic coming from the administrative VLAN
#   - ICMP Echo Request coming from WAN
#   - ICMP Time Exceeded (TTL) coming from WAN
#   - Traffic from an already established or related connection
# Block:
#   - Any traffic coming from the WAN
# Reject:
#   - Any other traffic coming from the LAN
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A INPUT -i ${FW_ADM_IFACE} -j ACCEPT
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
$IPTABLES -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
$IPTABLES -A INPUT -i ${FW_INET_IFACE} -j DROP
$IPTABLES -A INPUT -j REJECT

# Configure output firewall filtering:
# Allow:
#   - Traffic flowing to the loopback interface
#   - HTTP traffic
#   - ICMP Echo Request going to WAN
#   - ICMP Time Exceeded (TTL) going to WAN
#   - DNS queries to configured WAN name servers
#   - Traffic from an already established or related connection
# Reject:
#   - Any other traffic
$IPTABLES -A OUTPUT -o lo -j ACCEPT
$IPTABLES -A OUTPUT -o ${FW_INET_IFACE} -p tcp -m tcp 
                     --dport 80 -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
$IPTABLES -A OUTPUT -p icmp --icmp-type time-exceeded -j ACCEPT
for ns in $(nvram get wan_dns); do
        $IPTABLES -A OUTPUT -o ${FW_INET_IFACE} -p udp -m udp 
                            -d "$ns" --dport 53 -j ACCEPT
        $IPTABLES -A OUTPUT -o ${FW_INET_IFACE} -p tcp -m tcp 
                            -d "$ns" --dport 53 -j ACCEPT
done
$IPTABLES -A OUTPUT -j REJECT

# Configure forward firewall filtering:
# Allow:
#   - Incoming SSH/NX traffic -> the filtering takes place after the
#     PREROUTING chain has been processed and, since DNAT has been already
#     being performed, the traffic is filtered accordingly to its final
#     destination (the SSH/NX server)
#   - Outgoing DNS queries to configured WAN name servers
#   - Outgoing HTTP and HTTP/S traffic
#   - ICMP Echo Request coming from LAN going to WAN
#   - Trafic from an already established or related connection
# Drop:
#   - Any other traffic
$IPTABLES -A FORWARD -i ${FW_INET_IFACE} -o ${FW_PRIVATE_IFACE} -p tcp -m tcp 
                     -d ${NX_IP} --dport 22 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i ${FW_PRIVATE_IFACE} -o ${FW_INET_IFACE} -p tcp -m tcp 
                     --dport 80 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i ${FW_PRIVATE_IFACE} -o ${FW_INET_IFACE} -p tcp -m tcp 
                     --dport 443 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A FORWARD -i ${FW_PRIVATE_IFACE} -o ${FW_INET_IFACE} 
                     -p icmp --icmp-type echo-request -j ACCEPT
for ns in $(nvram get wan_dns); do
        $IPTABLES -A FORWARD -i ${FW_PRIVATE_IFACE} -o ${FW_INET_IFACE} 
                             -p udp -m udp -d "$ns" --dport 53 -j ACCEPT
        $IPTABLES -A FORWARD -i ${FW_PRIVATE_IFACE} -o ${FW_INET_IFACE} 
                             -p tcp -m tcp -d "$ns" --dport 53 -j ACCEPT
done
$IPTABLES -A FORWARD -j DROP

Resetting Cisco IOS configuration

You can use the following Cisco IOS commands to reset the Cisco configuration back to factory defaults:

write erase

This will clear the startup-config and fill it up with factory defaults.

delete flash:vlan.dat

Most Cisco IOS switches keep VLAN configuration data — like VTP protocol data, active VLANs, and so on — in flash memory, in a file called vlan.dat.

QEMU and TUN/TAP networking

Using TUN/TAP networking with QEMU grant guest machines access to some or all networks reachable by the host machine. This also allows accessing services offered by guests machines from any other host.

To be able to use TUN/TAP network, instead of directly configuring the physical Ethernet network device — my Realtek 8169 Gigabit Ethernet, which in my computer it’s named eth1 –, we need to reconfigure the network in order to get a bridge device, named br0, with the physical Ethernet eth1 device attached to it. We can achieve this by editing /etc/network/interfaces to look like this:

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#auto eth1
#iface eth1 inet static

auto br0
iface br0 inet static
        address a.b.c.d
        netmask 255.255.255.128
        gateway v.w.x.y
        bridge_ports eth1
        bridge_fd 1
        bridge_hello 1
        bridge_stp off

The helper script /etc/qemu-ifup, which QEMU uses to bring up a TAP network interface used by the guest and bind it to the existing bridge br0, should look like this:

#!/bin/sh
echo "Executing /etc/qemu-ifup"
echo "Bringing up $1 for bridged mode..."
sudo /sbin/ifconfig $1 0.0.0.0 promisc up
echo "Adding $1 to br0..."
sudo /usr/sbin/brctl addif br0 $1
sleep 2

To allow running QEMU as an unprivileged user, we need to edit /etc/sudoers in order to grant access for running /sbin/ifconfig and /usr/sbin/brctl. It’s recommended to edit that file using visudo. The file should could look like this:

# Cmnd alias specification
Cmnd_Alias      QEMU=/sbin/ifconfig, \
                     /sbin/modprobe, \
                     /usr/sbin/brctl

# Defaults
Defaults        !lecture,tty_tickets,!fqdn,rootpw

# User privilege specification
root    ALL=(ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Grant access to Cmnd_Alias to user jdoe
jdoe ALL=NOPASSWD:QEMU

Now, we can launch qemu from the command line:

XLIB_SKIP_ARGB_VISUALS=1 \
qemu -hda hda -cdrom *iso -boot d \
-m 512 -localtime -net nic,vlan=0 \
-net tap,ifname=tap0,script=/etc/qemu-ifup \
-kernel-kqemu

Configuring WPA2 Enterprise with EAP-TLS in Mac OS X and Linux

Setting up the CA

Follow the steps on setting up a Certificate Authority (CA) using OpenSSL.

Issuing the client certificate and private key

Once the CA has been configured, we will generate a private key and an unsigned public key digital certificate.

# openssl req -new -days 365 -newkey rsa:1024
-keyout sslkey.pem -out unsigned.pem

The unsigned public key digital certificate, stored in a PEM-encoded file named unsigned.pem will be sent to the CA for signing:

# openssl ca -in unsigned.pem -out cert.pem

Installing the client certificate and private key

The next step consists in installing the private key, public key digital certificate and CA public key certificate.

Linux

The private key, public key digital certificate and CA certificate files should get installed into a location where only root and wpa_supplicant can access them, for example, /etc/wpa:

# mkdir /etc/wpa
# chown root.root /etc/wpa
# chmod 700 /etc/wpa

Mac OS X

Mac OS X can only import private keys in PKCS#12 so we need to export all the previous items to a suitable format:

# openssl pkcs12 -export -in cert.pem -inkey key.pem
-out client.p12 -name "host.domain"

Where "host.domain" denotes the FQDN of the host which this digital certificate and private key are intended for.

The output file client.p12 contains the private key and public key digital certificate. This bundle should get moved to the host using a secure distribution channel, like an SSH/SCP/SFTP session or a USB key. Also, the CA digital certificate, usually named cacert.pem, should also get copied to the host.

On Mac OS X, using the GUI, double click the cacert.pem file, and install the CA certificate into the X509Anchors keychain. This a system-wide keychain intended to store X.509 CA root digital certificates.

Next, using the GUI, double click on client.p12 file, supply the password that protects the private key stored in this file, and choose to install both the private key and public key into the login keychain. Next, make sure the private key has been installed:

Configuring the AirPort Express Wireless Access Point

Launch AirPort Admin Utility, select the desired base station and click the Configure icon from the toolbar:

Click the Change Wireless Security… button:

In this new window, fill in the information about the RADIUS server, like its IP address, shared secret and so on.

Configuring the Supplicant for WPA2 Enterprise

Linux

Create /etc/wpa_supplicant.conf using the following data:

ctrl_interface=/var/run/wpa_supplicant
ap_scan=2
network={
  scan_ssid=1
  ssid="iTunes"
  proto=WPA2
  key_mgmt=WPA-EAP
  pairwise=CCMP
  group=CCMP
  ca_cert="/etc/wpa/cacert.pem"
  client_cert="/etc/wpa/cert.pem"
  private_key="/etc/wpa/key.pem"
  eap=TLS
  identity="anonymous"
}

The identity directive is required, or else the EAP-TLS negotiation will fail.

ap_scan=2 and scan_ssid=1 are needed when the Wireless Acccess Point is configured to not broadcast the ESSID.

Mac OS X

Launch Internet Connect from the Wireless menu:

If no 802.1X icon appears on the toolbar, choose File -> New 802.1X Conection…. Click the 802.1X icon. The window will look like this:

From the Configuration drop-down, select Edit Configurations…:

A window like this will open:

Fill in both the “Description” and “Wireless Network” fields with the ESSID of the Wireless network. Leave “User Name” and “Password” blanked, since we are not using password-based authentication.

From the “Authentication” listbox, clear the checkbox for all the protocols except for TLS. Select the TLS protocol and click the Configure button. A new window will open for you to select the private key that will be used for the EAP-TLS authentication mechanism:

From the drop-down listbox, select the name of the private key that matches the name of the private key installed in the previous section.

Click the Connect button. The Supplicant will authenticate against the Wireless Access Point. At this point, it is possible that Mac OS X asks confirmation for accessing the private key stored in your keychain. It is recommended to “Always Allow” the Supplicant access to the private key.

Launch System Preferences -> Network and Configure… the AirPort interface:

Click the “+” button to add a Preferred network:

Just enter the ESSID of the Wireless network and choose WPA2 Enterprise from the Wireless Security drop-down listbox. Also, make sure the Configuration field shows the name of the 802.1X configuration we created previously using Internet Connect.

Leave the rest of the fields blank, since we are not using password-based authentication.

Managing multiple NICs in Linux

When running a Linux kernel 2.6, it’s very difficult to tell network interfaces apart when they use the same driver or chipset. This can also be confusing even on systems with multiple network interfaces using different chipsets or drivers. Which one is eth0? Which one is eth1? What’s even worse is that it seems udev doesn’t always assign the same name to each network interface between reboots, so the same card sometimes is named eth0, and sometimes eth2, for example.

Fortunately, there is a way to tie each network interface card with a fixed network interface name by using udev rules.

My system has four network interfaces:

  • 2 Ethernet 3Com 3C905 10/100, using the 3c59x linux driver.
  • 1 Ethernet SMC 9452TX 10/100/1000, using the skge linux driver.
  • 1 Wireless 802.11g SMC 2835W V3, using ndiswrapper.

Let’s suppose udev has given the name eth2 to the SMC 9452TX. Now, let’s suppose we want to rename this network interface to eth0 or a more meaningful name like lan or e1000. We can write a udev rule to perform the renaming, thus making a persistent device-name association.

To write this rule, first we need to use some attribute which is unique to the device. For network devices, we can use the MAC address. Using udevinfo we can retrieve all attributes for the eth2 device:

# udevinfo -a -p /sys/class/net/eth2 looking at class device '/sys/class/net/eth2': KERNEL=="eth2" SUBSYSTEM=="net" SYSFS{addr_len}=="6" SYSFS{address}=="00:13:AA:AA:AA:AA" SYSFS{broadcast}=="ff:ff:ff:ff:ff:ff" SYSFS{carrier}=="1" SYSFS{features}=="0x1023" SYSFS{flags}=="0x1003" SYSFS{ifindex}=="4" SYSFS{iflink}=="4" SYSFS{mtu}=="1500" SYSFS{tx_queue_len}=="1000" SYSFS{type}=="1" SYSFS{weight}=="64"

SYSFS{address}=="00:13:AA:AA:AA:AA" is the udev attribute used to refer to this network interface MAC address, the SMC 9452TX that is being named eth2 by default. We can repeat this step to retrieve the attribute for every network interface for which we want to write a udev rule.

Once we’ve got all the attributes, we can place the udev rules in a file named code>/etc/udev/rules.d/99-user.rules:

KERNEL=="eth*", SYSFS{address}=="00:13:AA:AA:AA:AA", NAME="e1000" KERNEL=="eth*", SYSFS{address}=="00:04:BB:BB:BB:BB", NAME="e100" KERNEL=="eth*", SYSFS{address}=="00:04:CC:CC:CC:CC", NAME="e10"

Now, the easiest way of making these changes take effect is rebooting. Next time, udev will rename the network interfaces to e1000, e100 and e10 instead of eth0, eth1 or eth2. What’s more, now it’s easier to tell the interfaces apart from each one.

QoS with OpenWRT

I use the following script for my Linksys WRT54GS Wireless router running OpenWRT White Russian -RC4 to setup a QoS firewall that uses Hierarchical Token Bucket (HTB) and Stochastic Fair Queueing (SFQ) to classify the traffic in three cathegories:

  1. Interactive, high priority traffic:
    This class is used for DNS traffic and SSH traffic.
  2. Interactive, normal priority traffic:
    This class is used for HTTP and HTTP/S traffic.
  3. Low priority traffic:
    This class is used for traffic which doesn’t fit any of the previous classes.

Each class is also subclassed with Stochastic Fair Queueing (SFQ) to distribute traffic utilization among the same class evenly.

To make the script run every time the router is powered up, save the script as /etc/init.d/S41qos and turn the executable bit on it.

#!/bin/ash # Executables GREP=/bin/grep INSMOD=/sbin/insmod TC=/usr/sbin/tc DEV=vlan1 # Load kernel modules $GREP -q ^sch_htb /proc/modules || $INSMOD /lib/modules/`uname -r`/sch_htb.o $GREP -q ^sch_sfq /proc/modules || $INSMOD /lib/modules/`uname -r`/sch_sfq.o $GREP -q ^cls_u32 /proc/modules || $INSMOD /lib/modules/`uname -r`/cls_u32.o # Hierarchical Token Bucket (HTB) $TC qdisc add dev $DEV root handle 1: htb default 30 $TC class add dev $DEV parent 1: classid 1:1 htb rate 1mbit burst 20k cburst 20k # HTB Classes $TC class add dev $DEV parent 1:1 classid 1:10 htb rate 768kbit ceil 1mbit burst 15k cburst 15k $TC class add dev $DEV parent 1:1 classid 1:20 htb rate 256kbit ceil 1mbit burst 20k cburst 20k $TC class add dev $DEV parent 1:1 classid 1:30 htb rate 128kbit ceil 512kbit burst 5k cburst 5k $TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10 $TC qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10 $TC qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10 # Filters $TC filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip dport 53 0xffff flowid 1:10 $TC filter add dev $DEV protocol ip parent 1:0 prio 2 u32 match ip dport 22 0xffff flowid 1:10 $TC filter add dev $DEV protocol ip parent 1:0 prio 10 u32 match ip dport 80 0xffff flowid 1:20 $TC filter add dev $DEV protocol ip parent 1:0 prio 10 u32 match ip dport 443 0xffff flowid 1:20