接上回的 在MBP苏醒时执行自动任务 ,继续说。
今次的重点在于网络切换。
这个任务,要被细分为很多细节,不过并没那么难,都很容易找到恰当的办法。
使用 macOS 的 “位置”
首先,经验告诉我们,在多种场所切换不同的网络配置,最佳方案是“位置 / Location”:
所以,如图所示,首先设定两个位置,一个是Home,一个是办公室。Home设置只有WIFI,IP地址是预分配的:192.168.0.71;办公室呢,WIFI被加入设施列表,但设置为关闭状态,此外Wireless被加入设置列表,作为主要的网络接口,办公室也是DHCP预分配的,WIFI为192.168.0.172,Wireless为192.168.0.72,网关为 192.168.0.254。
为什么不把HOME IP设置的和办公室一样呢?其实也是可以的,因为办公室和家里的网关不同,可以用于区别。我这里设置的不一样更多是一个历史缘由,可以忽略。
macOS的位置功能,允许你将全部网络设施选择性地配置到不同的位置。所以我花了不少时间来试验和选择出了最佳的组合方案,当然,下一次增加更多位置时就简单了,我想我会很快搞的定。
脚本操作
全局变量
PAC='http://127.0.0.1:9050/pac' BYPASS='127.0.0.1 localhost test.local 163.com sina.com.cn' WIFI=Wi-Fi LOC_WIFI='HOME' IP_WIFI='192.168.0.71' WIRELESS='Thunderbolt Bridge' LOC_WIRELESS='SUWEI-OFFICE' IP_WIRELESS='192.168.0.72' IP_WIRELESS_wifi='192.168.0.172' TD=NONE pac_url=NONE loc=$(c-location) ip=$(c-ip)
操作网络位置:
c-location(){ networksetup -getcurrentlocation; } c-new-location(){ local loc=${1:-$LOC_WIFI} networksetup -switchtolocation $loc say="Using New Location: $loc ($ip).\n$(c-print-autoproxy)" echo "New Location: $loc" }
当前IP
c-ip(){ local ip=$(ifconfig|grep inet|grep -Eiv '127.0.0.1|::'|grep -o ' 192\.168\.[^ ]* ') ip=$(echo $ip) echo $ip }
测试网关
is-office() { ping -c 1 192.168.0.254 >/dev/null; } is-home() { ping -c 1 192.168.0.1 >/dev/null; }
自动代理
c-set-autoproxy(){ pac_url=${pac_url:-$(networksetup -getautoproxyurl "$TD")} echo "Using new autoproxy: '$TD' '$pac_url'" networksetup -setautoproxyurl "$TD" "$pac_url" # networksetup -getproxybypassdomains "$TD" networksetup -setproxybypassdomains "$TD" $BYPASS say="${say} [P]" } c-print-autoproxy(){ scutil --proxy }
隧道或者代理
c-set-tunnel(){ killall cow launchctl start homebrew.mxcl.cow say="${say} [COW]" }
这里自己编制了一个 cow 的服务并做好了配置,放在后面不管了。
say=’…’ 都可以忽略,echo … 都可以忽略。
好,下面是入口代码以及判定代码:
入口代码
echo "---" location=$(c-location) ip=$(c-ip) TD=NONE pac_url=NONE case $1 in print|info) c-info ;; reset|reload|restart|--reload|--restart|--reset) c-set-tunnel sleep 5 c-print-autoproxy lsof -Pni :1080 lsof -Pni :9050 ;; office) x-set-office sleep 5 echo; c-info ;; home) x-set-home sleep 5 echo; c-info ;; *) x-set | tee /tmp/switch-location.log ;; esac
判定、以及其他
headline() { printf "\e[0;1m$@\e[0m:\n"; } headline-begin() { printf "\e[0;1m"; } headline-end() { printf "\e[0m:\n"; } c-info(){ echo "Location: $(c-location)" c-print-autoproxy lsof -Pni :1080 && echo lsof -Pni :9050 && echo } x-set(){ # networksetup -listallnetworkservices say="location: $location. IP: $ip."; # echo $say; echo c-choose-location && { c-set-autoproxy sleep 3; #c-print-autoproxy c-set-tunnel # cd /usr/local/bin && echo -e "#!/bin/bash\n/usr/bin/osascript -e \"display notification \\\"\$*\\\"\"" > notify && chmod +x notify;cd - # say "network changed." # echo $say /usr/bin/osascript -e "display notification \"$say\" with title \"Network Changed\"" # say $say } || : } x-set-home(){ TD=$WIFI location=$LOC_WIFI pac_url=$PAC c-new-location $location c-set-autoproxy sleep 5 c-set-tunnel } x-set-office(){ TD=$WIRELESS location=$LOC_WIRELESS pac_url=$PAC c-new-location $location c-set-autoproxy sleep 5 c-set-tunnel } c-choose-location(){ headline "Choosing new location" if [[ $ip == $IP_WIFI ]]; then if is-home; then if [[ $location != $LOC_WIFI ]]; then TD=$WIFI c-new-location $LOC_WIFI echo " choosed 1: '$TD'" else echo "skip 1" c-print-autoproxy; false fi elif is-office; then if [[ $location == $LOC_WIFI ]]; then TD=$WIRELESS c-new-location $LOC_WIRELESS echo " choosed 1-1: '$TD'" else echo "skip 1.1" c-print-autoproxy; false fi else echo "skip 1.2" c-print-autoproxy; false fi elif [[ $ip == $IP_WIRELESS ]]; then if [[ $location != $LOC_WIRELESS ]]; then TD=$WIRELESS c-new-location $LOC_WIRELESS echo " choosed 2: '$TD'" else echo "skip 2" c-print-autoproxy;false fi elif [[ $ip == $IP_WIRELESS_wifi ]]; then if is-office; then if [[ $location != $LOC_WIFI ]]; then echo "skip 3" c-print-autoproxy;false else TD=$WIRELESS c-new-location $LOC_WIRELESS echo " choosed 2: '$TD'" fi elif is-home; then if [[ $location != $LOC_WIFI ]]; then TD=$WIFI c-new-location $LOC_WIFI echo " choosed 3: '$TD'" else echo "skip 3.1" c-print-autoproxy;false fi else echo "skip 3.1" c-print-autoproxy;false fi else if [[ $ip == '' ]]; then echo "no ip, set home and wifi and waiting 8s..." x-set-home sleep 8 if is-office; then x-set-office elif is-home; then x-set-home else c-print-autoproxy;false fi else echo "skip 4" c-print-autoproxy;false fi fi }
判定算法虽长,但是逻辑很工整、而且也不复杂。
不过这个博客贴脚本一向很弱智,稍后再考虑要不要改进。
整合到一起
上面脚本已经有了,所以在 ~/.wakeup 中加入到该脚本的指向就完成了。
实际经过了若干天的来回测试,确认了能够有效工作。
不过,判定部分是没有通用解决方案的,因为这取决于你如何依据不同场所来编制自己的位置。