Thursday, November 22, 2007

HOWTO: Configuring A Linux Laptop For Roaming

I have a laptop for work and wanted a way to be able to get things to "just work" when moving between home, work and supporting roaming in places like hotels.

Goals:

  • Support an HTTP proxy for external access at work
  • No proxy away from work
  • Must be able to switch without restarting X
  • Support going into and out of hibernation
  • Automated approach with minimal manual intervention when relocating
  • Be able to have different custom settings for DHCP based on location
  • Support static IP addresses by location

Contents:

The solution is for ubuntu (I am using Xubuntu), but will work fine with debian. Other distributions may need some tweaking. I have broken this into three steps for each library:

  1. guessnet for location detection
  2. switchconf for location configuration differentiation
  3. squid for proxy support

guessnet

The first step is to be able to change our network settings by location. Being on a laptop, I have 2 Ethernet cards: eth0 which is wired and eth1 which is my wireless. I use WPA, WEP and open wireless connections, and wpa_supplicant allows me to use all of these.

Unlike other solutions, guessnet works with the ifupdown debian architecture. Other programs on ubuntu and debian expect this configuration. For this reason, I saw guessnet as the only viable solution. Other programs that I considered were:

  • laptop-net
  • laptop-netconf
  • whereami
  • divine
  • intuitively

Overview

We will be setting up /etc/network/interfaces to use the mapping configuration. Instead of just configuring eth0 and eth1, we will setup virtual interfaces for each location. I will be using "straight" guessnet for the wired interfaces and guessnet used with wpa_supplicant for the wireless interfaces.

Prerequisites

sudo aptitude install guessnet wpasupplicant wpagui ifplugd

Configuration

Setup wpa_supplicant

wpa_supplicant is easier to work with and have roaming supported (for wireless in restaurants, hotels, etc.) with a separate configuration file. You can have wpa information in the interfaces file, but I will show using the wpa_supplicant.conf file instead.

/etc/wpa_supplicant/wpa_supplicant.conf

ctrl_interface=/var/run/wpa_supplicant

# Example, WEP encryption at work
network={
  id_str="wpa_work"
  ssid="atwork"
  key_mgmt=NONE
  wep_key1=1234567890
  wep_tx_keyidx=1
  auth_alg=OPEN
}

# Example WPA encryption at home
# Use wpa_passphrase to generate the psk
network={
  id_str="wpa_home"
  ssid="athome"
  psk=3655222ca4387e672b9c0c9cb0eb325f536ed6d39d16c31c3e9228221bea9995
}

# Enable roaming here, just uncomment the lines below
#network={
#  key_mgmt=NONE
#}

The one thing that is not obvious here is the "id_str". This identifier will be used as the interface name to match in /etc/network/interfaces.

/etc/network/interfaces

Now we will setup the base configuration. We will be changing this file later when we add switchconf. My goal with this step is to just get guessnet and wpa_supplicant working.

auto lo eth0
iface lo inet loopback

allow-hotplug eth1

mapping eth0
  script guessnet-ifupdown
  map default: none
  #map timeout: 10
  #map verbose: true
  #map debug: true

iface eth1 inet manual
  wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
  wpa-roam-default-iface default-wparoam
  wpa-mapping-script guessnet-ifupdown
  wpa-map default: none

iface eth0-home inet dhcp
  test peer address 192.168.0.1 mac 01:02:03:04:05:06 source 192.168.0.2

iface eth0-work inet dhcp
  test peer address 10.1.1.1 mac 01:02:03:04:05:06 source 10.1.1.2

iface wpa_work inet dhcp
  test wireless essid atwork

iface wpa_home inet dhcp
  test wireless essid athome

iface none inet dhcp

iface default-wparoam inet dhcp

Okay, I don't want to write a book, so I will highlight details here only. Use the man pages for interfaces, wpa_supplicant and guessnet to get more information. The auto line specifies which interfaces to bring up automatically. I set the eth1 to hotplug. On my Dell, Latitude D630, I can turn the wireless radio on and off using a hard switch. The ifplugd will allow the eth1 to come up automatically when I turn the switch on. This should also configure my eth0 when I plug in the cord.

The mapping eth0 block sets up guessnet in ifupdown mode as the mapping script. guessnet will examine all the interfaces in the file, attempting to find a matching interface. See the guessnet man page for good documentation. In this example file, I have two virtual interfaces for eth0, named eth0-home and eth0-work (the names are not important, I just named them this for clarity). "none" is the default, so if the home and work fail, "none" will be used. The wireless will fail since I have a wireless test on those.

eth0-home and eth0-work each have a peer test. I found that the best candidate is the default gateway of the network as it is more likely to respond to a ping. I also have a MAC address specified so that if I go to another location that has a computer with the same IP address, I can avoid a collision. To get a MAC address for a server use arc:

$arp -i eth0 -a 192.168.0.1
computer.domain (192.168.0.1) at 01:02:03:04:05:06 [ether] on eth0

The wpa works pretty much in the same way except that the interface is determined by the wpa_supplicant.conf. The wireless test is not necessary, I only used it to have it not be used for eth0. As mentioned earlier, the iface name should be the same as the id_str from wpa_supplicant.conf.

Testing

To test to make sure it is working run this (from the guessnet FAQ):

cat /dev/null | guessnet --debug -i eth0

switchconf

There is nothing I need to say about this library as it is very simplistic. The examples for it show switching the /etc/network/interfaces file, but with guessnet, this is not needed or desired. I use it mostly for changing my proxy configuration, ntp servers and some details with my dhclient.conf. Feel free to use it for whatever you want. In its default configuration it simply maps files under a location to the standard locations. For example to configure my ntpdate at work I create /etc/switchconf/work/etc/default/ntpdate. When I call "switchconf work" /etc/default/ntpdate becomes a softlink to this file.

Put any scripts in /etc/switchconf/after.d to restart any daemons (for example, I restart squid)

Hooking it up

We can use the "pre-up" and "post-up" commands in the interfaces file to integrate guessnet and switchconf

auto lo eth0
iface lo inet loopback

allow-hotplug eth1

mapping eth0
  script guessnet-ifupdown
  map default: none
  #map timeout: 10
  #map verbose: true
  #map debug: true

iface eth1 inet manual
  wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
  wpa-roam-default-iface default-wparoam
  wpa-mapping-script guessnet-ifupdown
  wpa-map default: none

iface eth0-home inet dhcp
  test peer address 192.168.0.1 mac 01:02:03:04:05:06 source 192.168.0.2
  pre-up /usr/sbin/switchconf home || true

iface eth0-work inet dhcp
  test peer address 10.1.1.1 mac 01:02:03:04:05:06 source 10.1.1.2
  pre-up /usr/sbin/switchconf work || true

iface wpa_work inet dhcp
  test wireless essid atwork
  pre-up /usr/sbin/switchconf work || true

iface wpa_home inet dhcp
  test wireless essid athome
  pre-up /usr/sbin/switchconf home || true

iface none inet dhcp
  pre-up /usr/sbin/switchconf other || true

iface default-wparoam inet dhcp
  pre-up /usr/sbin/switchconf other || true

That should be pretty self-explanatory. I use pre-up instead of post-up because I switch the dhclient.conf in my configuration that contains DHCP information. You can add as many pre- and post-up commands per interface as desired. The " || true" ensures that ifupdown doesn't fail if the switchconf fails (like if squid failed to re-start for example).

squid

Overview

My work has a proxy, I don't use one anywhere else. Linux uses environment variables for proxy support and cannot be changed from in an existing X session, without restarting X. So I decided to run a local proxy that I always use, and based on my location, either use an upstream proxy (at work) or a direct connection.

I first tried tinyproxy as it is much easier to configure than squid, but I started having issues with it communicating to an upstream proxy, so I switched to squid.

Prerequisites

sudo aptitude install squid

Configuration

Since I now have switchconf, I can write two different configuration files, one for work and one for home/other.

Work example:

# Port of the server
http_port 3128

#ACLs
acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
acl to_localhost dst 127.0.0.0/8
acl WORK dstdomain .workdomain1.com
acl WORK dstdomain .workdomain2.com
acl purge method PURGE
acl CONNECT method CONNECT

# Caches
cache_peer work-proxy parent 80 0 no-query default name=atwork

#Specify caching rules:
# acl QUERY urlpath_regex cgi-bin \?
# cache deny QUERY
cache deny all

# Apache mod_gzip and mod_deflate known to be broken so don't trust
# Apache to signal ETag correctly on such responses
acl apache rep_header Server ^Apache
broken_vary_encoding allow apache

# log
access_log /var/log/squid/access.log squid
# access_log none

hosts_file /etc/hosts

http_access allow localhost
http_access deny all

#Special direction rules.  These state to only have the local server direct request
#to the oracle network.  Everything else should be handled by the parent.  In
#non-firewall cases, all request should be directed.
always_direct allow WORK
never_direct allow all

This shows using a direct connection for work domains and using the proxy for everything else. Home/other (comments removed see above for them):

http_port 3128
acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
acl purge method PURGE
acl CONNECT method CONNECT
cache deny all
acl apache rep_header Server ^Apache
broken_vary_encoding allow apache
access_log /var/log/squid/access.log squid
hosts_file /etc/hosts
http_access allow localhost
http_access deny all
always_direct allow all

This just has the proxy make every connection direct, basically turning it off.

Setup bash:

Add this to your ~/.bashrc to have your command-line apps use the local proxy:

export http_proxy="http://localhost:3128"
for VAR in proxy \
  HTTP_PROXY \
  https_proxy \
  HTTPS_PROXY \
  ftp_proxy; do
  export $VAR=$http_proxy
done

Don't forget to configure applications that don't use the environment. This may include skype, pidgin, firefox, thunderbird and your gnome or KDE global configuration.

Summary

Now you have a laptop that automatically detects its location, reconfigures its network and other programs and does not need to reconfigure proxy settings without ever having to run programs or scripts when you change location. By ensuring your hibernate scripts restart networking, your computer will adapt to its new location when it wakes up.


© Copyright 2006 - Andrew Robinson. Please feel free to use in your applications under the LGPL license (http://www.gnu.org/licenses/lgpl.html).

No comments: