Yesterday after I moved to another laboratory for some time, I've written a script to detect network configuration automagically, because I got tired of re-configuring network interfaces manually (there are some labs here that don't have DHCP).
Here is the list of network configurations I need to detect:
- Wired network at home. My router has "standard" address (192.168.1.1) and it has DHCP server built-in. Our provider requires additional PPPoE connection to be started for me to have access to some internal resources.
- Wired network at my main workplace. In our lab, we do have DHCP, so it can be detected by IP address (mask 192.168.11.0/24) or gateway. Additionally, http intercepting must be enabled, so no proxy configuration is needed for most programs to access the Internet.
- Wired network at any other lab with DHCP. This is the same as previous, so it can count as the very same configuration.
- Wired network at one of two labs with no DHCP. Different IP addresses, different gateways. Intercepting must be enabled too.
First, I've configured my eth0 as DCHP-only in /etc/network/interfaces:
iface eth0 inet dhcp
Second, I've set up my dhclient to call custom script on some events (/etc/dhcp3/dhclient-exit-hooks.d/conf-interfaces):
case $reason in
BOUND)
/etc/network/conf-interfaces up
;;
RELEASE)
/etc/network/conf-interfaces down
;;
FAIL)
/etc/network/conf-interfaces up-fail
;;
esac
BOUND is called when dhclient got a reply from DHCP server with lease information. RELEASE is called just before interface goes down. FAIL is called when no DHCP reply is received.
Third, I've writted a configuration script (/etc/network/conf-interfaces):
#!/bin/bash
if=eth0
ip_addr=$(/sbin/ifconfig $if | sed -n -e '/^.*inet addr:\([.[:digit:]]*\).*/{s//\1/;p;q;}')
do_configure_intercepting()
{
iptables -t nat -A OUTPUT -p tcp -m tcp --dport 80 -m owner --gid-owner proxy -j ACCEPT
iptables -t nat -A OUTPUT -p tcp -m tcp --dport 80 -j DNAT --to-destination $ip_addr:3129
/etc/init.d/squid3 start || /etc/init.d/squid start || true
}
do_deconfigure_intercepting()
{
# iptables -t nat -D OUTPUT -p tcp -m tcp --dport 80 -m owner --gid-owner proxy -j ACCEPT
# iptables -t nat -D OUTPUT -p tcp -m tcp --dport 80 -j DNAT --to-destination $ip_addr:3129
/etc/init.d/squid3 stop || /etc/init.d/squid stop || true
}
do_configure_ppp()
{
ifup ppp9; echo PPPoE configured
}
do_deconfigure_ppp()
{
ifdown ppp9; echo PPPoE deconfigured
}
case "$1" in
up)
echo $ip_addr > /var/run/$if-up-ip
iptables -t nat -F || true
iptables -t mangle -F || true
iptables -t filter -F || true
[[ $ip_addr =~ 192\.168\.11\..* ]] && do_deconfigure_ppp && do_configure_intercepting && exit
[[ $ip_addr =~ 192\.168\.1\..* ]] && do_deconfigure_intercepting && do_configure_ppp && exit
true
;;
down)
ip_addr=$(cat /var/run/$if-up-ip)
iptables -t nat -F || true
iptables -t mangle -F || true
iptables -t filter -F || true
[[ $ip_addr =~ 192\.168\.11\..* ]] && do_deconfigure_intercepting && exit
[[ $ip_addr =~ 192\.168\.1\..* ]] && do_deconfigure_ppp && exit
true
;;
up-fail)
addrs=$(grep -v "#" /etc/network/dhcp-fail | tr ' ' '\t' | tr -s '\t' | cut -f 1)
gw=''
for addr in $addrs ; do
reachable=$(arping -D -c 4 $addr |grep response|cut -f 2 -d " ")
logger -t arping "Got $reachable replies from $addr"
test "$reachable" -ne 0 && gw=$addr && break
done
dhclient3 -pf /var/run/dhclient.$if.pid -lf /var/lib/dhcp3/dhclient.$if.leases -x $if
if test -z $gw ; then exit ; fi
line=$(grep -v "#" /etc/network/dhcp-fail | tr ' ' '\t' | tr -s '\t' | grep -G ^$gw)
ip_addr=$(echo "$line" | cut -f 2)
netmask=$(echo "$line" | cut -f 3)
gw=$(echo "$line" | cut -f 4)
dns1=$(echo "$line" | cut -f 5)
dns2=$(echo "$line" | cut -f 6)
domain=$(echo "$line" | cut -f 7)
echo $ip_addr > /var/run/$if-up-ip
iptables -t nat -F || true
iptables -t mangle -F || true
iptables -t filter -F || true
ifconfig $if $ip_addr netmask $netmask
route del default || route add default gw $gw
echo nameserver $dns1 > /etc/resolv.conf
echo nameserver $dns2 >> /etc/resolv.conf
echo domain $domain >> /etc/resolv.conf
echo search $domain >> /etc/resolv.conf
do_configure_intercepting
exit
esac
In this script, first what we do is IP address detection. This is used later. Of course, when called with up-fail this can be empty, but in that case we just ignore it.
When being called with up, we save IP address we got, so we can use it when bringing interface down (though I had some problems with it). Next, we clean netfilter tables, so no duplicate rules will be there. Of course, this could be made more elegant, but as I don't have many interfaces, this quick'n'dirty solution works perfectly. And then we configure PPP and/or intercepting depending on what IP address we got. Pretty easy.
Almost the same if down procedure.
The up-fail is more complicated. Here we try to check if we have some hosts as neighbours. I've made a file, /etc/network/dhcp-fail. It's a list of hosts we need to check together with network configurations for each situatiuon:
# "what to arping" ip netmask gw dns1 dns2 domain
192.168.11.1 192.168.11.94 255.255.255.0 192.168.11.1 192.168.11.9 192.168.251.2 evm
192.168.11.225 192.168.11.238 255.255.255.224 192.168.11.225 192.168.11.9 192.168.251.2 evm
Field separators are either tabs or spaces.
We use arping to detect presence of hosts. arping sends ARP request for specific IP address, and waits for replies from the host owns that address. This works in the same physical segment only --- and that's what we need here.
We go through the list, and arping hosts listed there. If we get any reply, we stop arpinging, and start configuring the interface accordingly to the dhcp-fail file. The important thing is to kill dhclient3 so it won't deconfigure our interface accidentally.