Другое решение - использовать LaunchDaemon для мониторинга определенного каталога и запуска внешнего скрипта всякий раз, когда в этом каталоге есть изменения. Библиотека разработчика Mac дает общее представление о таком сценарии (их пример отслеживает /etc/hostconfig
и запускает syslog -s -l notice "somebody touched /etc/hostconfig"
когда время изменения этого файла изменяется.)
Для наших целей мы отмечаем, что каждый раз, когда вы входите в VPN, каталог /Library/Preferences/SystemConfiguration
изменяется. Поэтому, если вы сохраните следующий файл plist в /Library/LaunchDaemons/vpn.connectscript.plist
, он будет смотреть этот каталог:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>vpn.connectscript</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/opt/local/bin/vpn_some_script.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Library/Preferences/SystemConfiguration</string>
</array>
</dict>
</plist>
Обратите внимание, что этот LaunchDaemon будет вызываться не только для вашего VPN-подключения (например, каждый раз, когда вы подключаетесь к Wi-Fi). Таким образом, ваш скрипт /opt/local/bin/vpn_some_script.sh
должен иметь проверку, что туннель действительно подключен, и сценарий не должен создавать проблем, если он запускается несколько раз подряд. (Поэтому, если вы монтируете общие ресурсы, вы можете проверить, что они еще не подключены).
Например, мой скрипт /opt/local/bin/vpn_some_script.sh
просто:
#!/bin/bash
# This only changes the routes table if utun0 exists.
# -n checks that `ifconfig utun0` returns something other than "" on STDOUT
# The 2> /dev/null redirects STDERR to null, to silence errors
if [[ -n `ifconfig utun0 2> /dev/null` ]] ; then
route -n add -net 10.0.0.0/8 -interface utun0
# Find the old default gateway
GATEWAY=`route -n get default -ifscope en0 | grep gateway | awk '{ print $2 }'`
# make everything (except blocks described above) go through old default gateway rather than VPN
route -n change default $GATEWAY
fi
который только добавляет маршрут к 10.0.0.0/8 через туннель, если я подключен к VPN-туннелю (и изменяю значение по умолчанию для перехода к маршрутизатору 192.168.1.1).
Когда вы сохраните файл plist, он будет автоматически загружен при следующей перезагрузке. Однако вы также можете загрузить его вручную:
sudo launchctl load -w /Library/LaunchDaemons/vpn.connectscript.plist
Обратите внимание: если вашему bash-скрипту требуются права суперпользователя (например, мой скрипт, который изменяет таблицу маршрутизации), вам необходимо сохранить его в /Library/LaunchDaemons/
(или /System/Library/LaunchDaemons
). Если ваш скрипт должен запускаться как обычный пользователь, вы должны сохранить его в ~/Library/LaunchAgents/
.
Если ваш скрипт запускается от имени пользователя root и не хочет подвергаться атакам повышения привилегий, вызываемый сценарий bash должен находиться в каталоге, например /opt/local/bin/
который может быть изменен только пользователем root. Если вы храните в скажем ~/bin
обычный пользователь может изменить скрипт (или переименовать файл / каталог и заменить его на файл, который он написал) и получить полный доступ к вашей системе.