Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Sep 2002 14:34:29 -0700
From:      Lars Eggert <larse@ISI.EDU>
To:        current <current@FreeBSD.ORG>
Subject:   Comments requested: rc_ng per-location config script
Message-ID:  <3D8259E5.7020601@isi.edu>

next in thread | raw e-mail | index | archive | help
This is a cryptographically signed message in MIME format.

--------------ms000000080503080805000209
Content-Type: multipart/mixed;
 boundary="------------060906060609030902080004"

This is a multi-part message in MIME format.
--------------060906060609030902080004
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Hi,

I'm slowly porting some local rc scripts we've been using for a few
years on -STABLE to rc_ng and -CURRENT. Some of them may be useful to 
others, and I'd appreciate any comments.

The attached script changes a machine's /etc configuration based on 
auto-probed network locations. It's mostly useful for laptops that you 
move between a few well-known locations (office, home, Starbucks.)

Please see the script itself for a more detailed explanation.

Under -STABLE, we have a local /etc/netstop and an extended 
/etc/netstart that I've not yet ported. With these two, I can do 
"/etc/netstop && location && /etc/netstart" when I move between 
locations, without rebooting. They're also hacked into apm.conf, so the 
location detection happens on standby/resume. I'll hopefully get around 
to port this sometime - or maybe this script'll make others help out :-)

Lars

PS: I'll be away from email until Sunday, so if I you send comments, 
chances are I won't reply until then.
-- 
Lars Eggert <larse@isi.edu>           USC Information Sciences Institute

--------------060906060609030902080004
Content-Type: text/plain;
 name="location"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="location"

#!/bin/sh
#

# PROVIDE: location
# REQUIRE: root
# BEFORE:  mountcritlocal
# KEYWORD: FreeBSD

# This script changes the machine configuration under /etc based on
# "known network locations" (KNL). Each KNL has a set of files and directories
# associated with it. If the scripts detects that the machine is connected
# to a KNL, it will create symlinks for all files and directories for the KNL
# under /etc.
#
# To detect a KNL, the script will use a variety of network probes to detect a
# well-known peer machine for the given KNL on the LAN. This well-known peer
# can be any directly-connected (i.e. no router hop) machine at a location.
# The script will probe for KNLs on all network interfaces.
#
# Location-specific configurations files are kept under in subdirectories 
# under /etc/locations/<KNL>/, where <KNL> is the IP address of the well-known
# peer at that KNL. If no KNL is detected, the default configuration will
# be symlinked into place.
#
# The script will pay attention to location-specific configuration files
# that may be required for the probes to succeed. For example, it will make
# sure to execute start_if.* scripts before probing, etc. The script will
# also make sure to not remove files under /etc that are not location-specific.
#
# Example: This example uses two KNLs, "home" with a well-known peer
#	   of 10.0.0.1, and "work" with a well-known peer of 192.168.123.254,
#	   each with several configuration files. Also present is the 
#	   fallback default configuration.
#	   
#	   /etc/
#		  locations/
#			  10.0.0.1/
#				  rc.conf
#				  printcap
#				  hosts
#	
#			  192.168.123.254/
#				  rc.conf
#				  start_if.an0
#				  dhclient.conf
#	
#			  unknown
#				  rc.conf
#
#	   Suppose the machine has two interfaces, xl0 and an0. Upon execution,
#	   this script would first probe for location "home" looking for the
#	   well-known peer 10.0.0.1 on both interfaces. If the probes fail,
#	   it would then probe for location "work", looking for well-known
#	   peer 192.168.123.254. Should that probe also fail, it would pick
#	   the default configuration.
#
#	   Assuming the probe for 192.168.123.254 succeeded, the script would
#	   create symlinks for rc.conf, start_if.an0 and dhclient.conf under
#	   /etc, and then exit.
#
# Comments to Lars Eggert <larse@isi.edu>, please.

. /etc/rc.subr

name="location"
rcvar=`set_rcvar`
start_cmd="probe_location"


# XXX local configuration variables, they should move to rc.conf eventually
location_dir="/etc/locations"
probe_ip="10.11.12.13"
probe_count=1
default="unknown"
start_if_delay=1
probes="dhcp arping ping"

# set after a probe has successfully detected a known location
found_loc=""
found_iface=""
found_probe=""

configure_location() {
	# Create symlinks in /etc for each file or directory under $loc,
	# unless the symlink would overwrite an existing file or directory.
	# (Symlinks from an earlier invocatrion of this script will have
	# been removed before this function is called.)

	local loc=$1

	# link location files into place
	echo -n "Configuring for $loc:"
	for file in `ls -A $location_dir/$loc`; do
		# check if we would overwrite an existing file under /etc
		if [ -f /etc/$file ]; then
			echo -n " (skipped $file, would overwrite existing)"
			continue
		fi

		# create symlink
		ln -s $location_dir/$loc/$file /etc/$file
		echo -n " $file"
	done
	echo
}



probe_ping () {
	# This probe sends some ICMP ping requests to the representative
	# address for the location that is currently probed for. The TTL
	# of the pings is set to 1, so it will only probe the local LAN.
	# The IP source address of the pings is fake (inside RFC 1918 space).

	local loc=$1
	local iface=$2

	# assign fake, temporary RFC 1918 to the interface and route though it
	ifconfig $iface $probe_ip/24 up
	route -q add default -interface $iface

	# do the probe
	traceroute -i $iface -P icmp -M 1 -m 1 -n -q $probe_count $loc \
		2> /dev/null | grep "$loc.*ms" > /dev/null

	# did we detect the location?
	if [ "$?" -eq "0" ]; then
		# yes, we did
		found_iface=$iface
		found_loc=$loc
	fi

	# remove temporary IP address and route
	route -q delete default
	ifconfig $iface delete $probe_ip
}


probe_arping () {
	# This probe uses the net/arping port to generate ARP lookups for the
	# representative address of the location currently probed. The IP
	# source address of the ARP queries is fake (inside RFC 1918 space).
	
        local loc=$1
        local iface=$2

	# since arping is a port, only proceed if it's installed
	if [ -x /usr/local/sbin/arping ]; then
		# assign temporary RFC 1918 to interface and route though it
        	ifconfig $iface $probe_ip/24 up
	        route -q add default -interface $iface

		# do the probe
		arping -i $iface -S $probe_ip -c $probe_count $loc > /dev/null

		# did we detect the location?
	        if [ "$?" -eq "0" ]; then
			# yes, we did
	                found_iface=$iface
	                found_loc=$loc
	        fi

		# remove temporary IP address and route
	        route -q delete default
	        ifconfig $iface delete $probe_ip
	fi
}


probe_dhcp () {
	# This probe will try to acquire an IP address via DHCP on the
	# interface in question. If DHCP succeeds, the IP address of the
	# DHCP server that allocated the address and the IP address of the
	# default gateway DHCP gave us are checked against the location.
	# (This means that the name of the location directory must be
	# one or the other for this probe to work.)

        local loc=$1
        local iface=$2

	# shorthands
	leases="/var/db/dhclient.leases"
	pid="/var/run/dhclient.probe.pid"

	# save existing leases
	if [ -f $leases ]; then
		mv -f $leases $leases.bak
	fi

	# use the dhclient.conf for the given location, or a global one
	conf=""
	if [ -f $loc_dir/$loc/dhclient.conf ]; then
		conf="-cf $loc_dir/$loc/dhclient.conf"
	elif [ -f /etc/dhclient.conf ]; then
		conf="-cf /etc/dhclient.conf"
	fi

	# start dhclient
	rm -f $pid
	dhclient $conf -pf $pid $iface &

	# probe each second if we got an address
	try=0
	while [ 1 ]; do
		# give dhclient some time to run
		sleep 2

		# see if we got a lease
		for field in dhcp-server-identifier routers; do
			# XXX pattern match this is sed or awk?
			for ip in `grep "option $field " $leases | \
				   sort | uniq | cut -d' ' -f5 | \
				   cut -d';' -f1`; do

				# did we detect the location?
				if [ "$ip" = "$loc" ]; then
					# yes, we did, stop the loop
			                found_iface=$iface
			                found_loc=$loc
					break 3
				fi
			done
		done

		# stop the loop after a number of tries
		try=`expr $try + 1`
		if [ "$try" -gt "$probe_count" ]; then
			break
		fi
	done

	# kill dhclient
	if [ -f $pid ]; then
		kill `cat $pid`
		rm -f $pid
	fi

	# restore existing leases
        if [ -f $leases.bak ]; then
                mv -f $leases.bak $leases
        fi
}


probe_location () {
	# This is the main function of this script. It will remove the exiting
	# per-location configuration, and then probe for each location on
	# each interface (unless the interface is loopback or has no carrier.)
	# If a known location is detected, its configuration is symlinked
	# into place. If no known configuration is detected, the default
	# configuration is symlinked into place.

        # first, remove all symlinks under /etc that point into /etc/locations
        for link in `find /etc -type l`; do
                ls -l $link | grep -- "-> $location_dir" > /dev/null
                if [ "$?" -eq "0" ]; then
                        rm -f $link
                fi
        done

	# create a list of known locations
	locations=""
	for loc in `ls $location_dir | \
		    awk '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/'`; do
		if [ ! -d $location_dir/$loc ]; then continue; fi
		locations="$loc $locations"
	done

	found_loc=$default
	for loc in $locations; do
		# find set of interfaces to probe at this location
		interfaces=""
		for iface in `ifconfig -l`; do
			# don't probe on loopback
	                case $iface in
	                	lo*)	continue
					;;
	                	*)
					;;
	                esac
 
			# if a start_if.$iface script exists, run it
			if [ -r $location_dir/$loc/start_if.$iface ]; then
				. $location_dir/$loc/start_if.$iface
				# XXX delay a bit (e.g. wireless NICs need
				# some time to associate)
				sleep $start_if_delay
			else
				# pull the interface up
				ifconfig $iface up
			fi

        	        # don't probe on interfaces that have no carrier
	       	        status=`ifconfig $iface | grep status: | cut -d: -f2`
        	        if [ "$status" != " no carrier" ]; then
				# interface is a candidate, include in list
				interfaces="$iface $interfaces"
                	fi

	                # XXX weed out more interfaces? gif, ng, tun, stf?

                        # if a stop_if.$iface script exists, run it
                        if [ -r $location_dir/$loc/stop_if.$iface ]; then
                                . $location_dir/$loc/stop_if.$iface
                        fi

			# pull the interface down
			ifconfig $iface down
		done

		# we now either have a set of interfaces to probe for the
		# current location, or we don't
		if [ "$interfaces" ]; then
			# we have some candidate interfaces, so probe
			echo -n "Probing for $loc on "
			for iface in $interfaces; do
				echo -n "$iface "
				# try all probes
				for probe in $probes; do
					probe_$probe $loc $iface
					if [ "$found_loc" ]; then
						echo "- found via $probe."
						found_probe=$probe
						break 3
					fi
				done
			done
			
			# if we get here, we couldn't detect the location
			echo "- not found."
		fi
	done

	# create the symlinks
	configure_location $found_loc

	# save current location info (XXX probe this first next time)
	echo "$found_loc $found_iface $found_probe" > /var/run/location
}


load_rc_config $name
run_rc_command "$1"

--------------060906060609030902080004--

--------------ms000000080503080805000209
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
Content-Description: S/MIME Cryptographic Signature

MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJtjCC
AzgwggKhoAMCAQICEGZFcrfMdPXPY3ZFhNAukQEwDQYJKoZIhvcNAQEEBQAwgdExCzAJBgNV
BAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgG
A1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vydmlj
ZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkG
CSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTAeFw0wMDA4MzAwMDAw
MDBaFw0wNDA4MjcyMzU5NTlaMIGSMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBD
YXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUQ2Vy
dGlmaWNhdGUgU2VydmljZXMxKDAmBgNVBAMTH1BlcnNvbmFsIEZyZWVtYWlsIFJTQSAyMDAw
LjguMzAwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN4zMqZjxwklRT7SbngnZ4HF2ogZ
gpcO40QpimM1Km1wPPrcrvfudG8wvDOQf/k0caCjbZjxw0+iZdsN+kvx1t1hpfmFzVWaNRqd
knWoJ67Ycvm6AvbXsJHeHOmr4BgDqHxDQlBRh4M88Dm0m1SKE4f/s5udSWYALQmJ7JRr6aFp
AgMBAAGjTjBMMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFQcml2YXRlTGFiZWwxLTI5NzAS
BgNVHRMBAf8ECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQQFAAOBgQAxsUtH
XfkBceX1U2xdedY9mMAmE2KBIqcS+CKV6BtJtyd7BDm6/ObyJOuR+r3sDSo491BVqGz3Da1M
G7wD9LXrokefbKIMWI0xQgkRbLAaadErErJAXWr5edDqLiXdiuT82w0fnQLzWtvKPPZE6iZp
h39Ins6ln+eE2MliYq0FxjCCAzkwggKioAMCAQICAwglQTANBgkqhkiG9w0BAQQFADCBkjEL
MAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
MQ8wDQYDVQQKEwZUaGF3dGUxHTAbBgNVBAsTFENlcnRpZmljYXRlIFNlcnZpY2VzMSgwJgYD
VQQDEx9QZXJzb25hbCBGcmVlbWFpbCBSU0EgMjAwMC44LjMwMB4XDTAyMDgyNDE4NTMzOVoX
DTAzMDgyNDE4NTMzOVowVDEPMA0GA1UEBBMGRWdnZXJ0MQ0wCwYDVQQqEwRMYXJzMRQwEgYD
VQQDEwtMYXJzIEVnZ2VydDEcMBoGCSqGSIb3DQEJARYNbGFyc2VAaXNpLmVkdTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBANI2Rrt4ggaQ/IrOsDeOm2H4/R5FRIL6JjDY3StE
aogp1r23WKniQ1Vj98Nu5WxlaZ3Iam3Jen5T66H8u7rtMNpK4qAeAGoBsVeyVr1+CTFeuv+m
xCh7BvBJwhLdm0zDaoDT05YKYZaqtsT+F286FWJQg31Xtf+vTKLVVrHcsafnteyal2NEt7Ac
yZZfjsVLwxp2Lq3cwYfRQRoo7/yCVzS7HsgM6jmbO4taEMo4yC2rpnUbWEUCDTaCYgpAXzAl
oiNk7GDh0wz2s5ZSnHRvNSBMAjCmpNtSYHfXFI1ANwrrrHIJ7Ei83+XN32PWY4OPzO3iown9
VR+vM+8lNx9OX28CAwEAAaNWMFQwKgYFK2UBBAEEITAfAgEAMBowGAIBBAQTTDJ1TXlmZkJO
VWJOSkpjZFoyczAYBgNVHREEETAPgQ1sYXJzZUBpc2kuZWR1MAwGA1UdEwEB/wQCMAAwDQYJ
KoZIhvcNAQEEBQADgYEAXcrIlKmPLM/r8r3oz2ZLPLaT1AyMjYTZY2qq/R7SUtFa9BNlTIFh
DG78QKfJ9lo2LMzTPQqMZgNLmj95GbNPI8P8OIq2K6MeCZWz08ROackqTFP6xWbIFIfXcBVR
1dZnDDyDKBBh05KkvyTPawSQyOBUeNBfQUyO4TE+3o58U8UwggM5MIICoqADAgECAgMIJUEw
DQYJKoZIhvcNAQEEBQAwgZIxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx
EjAQBgNVBAcTCUNhcGUgVG93bjEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZp
Y2F0ZSBTZXJ2aWNlczEoMCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDIwMDAuOC4z
MDAeFw0wMjA4MjQxODUzMzlaFw0wMzA4MjQxODUzMzlaMFQxDzANBgNVBAQTBkVnZ2VydDEN
MAsGA1UEKhMETGFyczEUMBIGA1UEAxMLTGFycyBFZ2dlcnQxHDAaBgkqhkiG9w0BCQEWDWxh
cnNlQGlzaS5lZHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSNka7eIIGkPyK
zrA3jpth+P0eRUSC+iYw2N0rRGqIKda9t1ip4kNVY/fDbuVsZWmdyGptyXp+U+uh/Lu67TDa
SuKgHgBqAbFXsla9fgkxXrr/psQoewbwScIS3ZtMw2qA09OWCmGWqrbE/hdvOhViUIN9V7X/
r0yi1Vax3LGn57XsmpdjRLewHMmWX47FS8Madi6t3MGH0UEaKO/8glc0ux7IDOo5mzuLWhDK
OMgtq6Z1G1hFAg02gmIKQF8wJaIjZOxg4dMM9rOWUpx0bzUgTAIwpqTbUmB31xSNQDcK66xy
CexIvN/lzd9j1mODj8zt4qMJ/VUfrzPvJTcfTl9vAgMBAAGjVjBUMCoGBStlAQQBBCEwHwIB
ADAaMBgCAQQEE0wydU15ZmZCTlViTkpKY2RaMnMwGAYDVR0RBBEwD4ENbGFyc2VAaXNpLmVk
dTAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBBAUAA4GBAF3KyJSpjyzP6/K96M9mSzy2k9QM
jI2E2WNqqv0e0lLRWvQTZUyBYQxu/ECnyfZaNizM0z0KjGYDS5o/eRmzTyPD/DiKtiujHgmV
s9PETmnJKkxT+sVmyBSH13AVUdXWZww8gygQYdOSpL8kz2sEkMjgVHjQX0FMjuExPt6OfFPF
MYIDJzCCAyMCAQEwgZowgZIxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx
EjAQBgNVBAcTCUNhcGUgVG93bjEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZp
Y2F0ZSBTZXJ2aWNlczEoMCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDIwMDAuOC4z
MAIDCCVBMAkGBSsOAwIaBQCgggFhMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZI
hvcNAQkFMQ8XDTAyMDkxMzIxMzQzMFowIwYJKoZIhvcNAQkEMRYEFCQ2bqoExuhTzxYJaZMG
7QhVMTxBMFIGCSqGSIb3DQEJDzFFMEMwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0G
CCqGSIb3DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMIGtBgsqhkiG9w0BCRACCzGB
naCBmjCBkjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
Q2FwZSBUb3duMQ8wDQYDVQQKEwZUaGF3dGUxHTAbBgNVBAsTFENlcnRpZmljYXRlIFNlcnZp
Y2VzMSgwJgYDVQQDEx9QZXJzb25hbCBGcmVlbWFpbCBSU0EgMjAwMC44LjMwAgMIJUEwDQYJ
KoZIhvcNAQEBBQAEggEAn6u6MSlrQECXzRgJywLuoNBiPPtmBTTTTdNXpqZ0Aw8nvj535Q2o
Z9IKEn8EWxfo1J8iQuWq1CYGIOp7zCsNV1KvyqgI0RULZCL8t6kIHCvvaCKE37Atxm8WxeMo
VPOUYPXNw5NktG+/IePtizP93Y0qhxxMpNXaAl5si93lpBEJbHAEJVMF3D930pPAvek70Jkf
yKNM7/y/9x/7Sn8VjKfG2AVZYXnBFNelRj+Py0sbmKJFqaPPSr8FyD4riM17m+Is3F8kU2/y
XnhhjTxnN4yXoeByaIqBqQ2gPjqO1ZXshBmpSkCr2EpYTSLF831QXE+DYlSPZrafM4wlvZZz
ngAAAAAAAA==
--------------ms000000080503080805000209--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3D8259E5.7020601>