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>