Skip to content

Instantly share code, notes, and snippets.

@rfairburn
Last active November 8, 2022 03:16
Show Gist options
  • Save rfairburn/b078be55f0be255add27 to your computer and use it in GitHub Desktop.
Save rfairburn/b078be55f0be255add27 to your computer and use it in GitHub Desktop.
Mac OS X command-line VPN Helpers
#!/bin/bash
# Source this file in your .bash_profile e.g.:
#
# source ~/gitcheckouts/vpn_heplers/.vpn_helpers.sh
#
# Note: This script works best with NOPASSWD: ALL configured in your sudoers file:
# /etc/sudoers:
# %admin ALL=(ALL) NOPASSWD: ALL
#
# Usage:
#
# vpn_connect - Connect to VPN and force DNS into place
# vpn_disconnect - Disconnect and reset DNS to defaults
# update_resolver - Force VPN DNS into place (good for already established connections)
# update_resolver delete - Reset DNS to defaults (good if VPN is already disconnected)
function obtain_service_ids {
scutil <<<"list" | awk -F/ '/DNS$/ { if (length($(NF-1)) == 36 ) { print $(NF-1) } }' | sort -u
}
function obtain_service_id {
scutil <<EOF | awk -F' : ' '/PrimaryService/ { print $2 }'
open
get State:/Network/Global/IPv4
d.show
quit
EOF
}
function modify_scutil_dns {
declare -a DOMAINS=("${!1}")
shift
local RESOLVERS=$@
sudo scutil <<EOF
open
d.init
d.add ServerAddresses * ${RESOLVERS}
$(for DOMAIN in ${DOMAINS[@]}; do echo d.add DomainName ${DOMAIN}; done)
set State:/Network/Service/${SERVICE_ID}/DNS
quit
EOF
}
function modify_networksetup_dns {
declare -a DOMAINS=("${!1}")
shift
local RESOLVERS=$@
local INTERFACE="${NETWORK_INTERFACE}"
sudo networksetup -setsearchdomains "${INTERFACE}" ${DOMAINS[@]}
sudo networksetup -setdnsservers "${INTERFACE}" ${RESOLVERS}
}
function obtain_scutil_dns {
scutil <<EOF | awk -F' : ' 'BEGIN { resolvers = ""}; { if ($1 ~ "[0-9]$") { resolvers = resolvers OFS $2 }}; END { print resolvers }'
open
get State:/Network/Service/${SERVICE_ID}/DNS
d.show
quit
EOF
}
function update_resolver {
if [ "$1" == "delete" ]; then
local RESOLVERS="${DEFAULT_DNS}"
local DOMAINS=("${DEFAULT_SEARCH_DOMAINS[@]}")
else
local DOMAINS=("${OFFICE_SEARCH_DOMAINS[@]}")
local ADD_RESOLVER=${OFFICE_DNS}
local SCUTIL_RESOLVERS="$(obtain_scutil_dns)"
local RESOLVERS="${ADD_RESOLVER} ${SCUTIL_RESOLVERS/${WORK_RESOLVER}/}"
fi
# modify_scutil_dns ${RESOLVERS}
modify_networksetup_dns DOMAINS[@] ${RESOLVERS}
}
function vpn_disconnect {
scutil --nc stop "${OFFICE_VPN_NAME}"
update_resolver delete
}
function vpn_connect {
vpn_disconnect
scutil -t 30 --nc start "${OFFICE_VPN_NAME}"
COUNT=0
while true; do
STATUS="$(scutil --nc status "${OFFICE_VPN_NAME}" | head -n1 | awk '{ print $1 }')"
if [ "${STATUS}" == "Connected" ]; then
break
elif [ "${COUNT}" -eq "30" ]; then
echo "Too many attempts, exiting."
break
else
echo "VPN is ${STATUS}."
fi
((COUNT++))
sleep 1
done
update_resolver
}
# Set these to "empty" for DHCP
export DEFAULT_DNS="empty"
# Use a bash array to support multiple search domains
export DEFAULT_SEARCH_DOMAINS=( empty )
# Used in the scripts above
export SERVICE_ID=$(obtain_service_id)
# Configure these for your settings
export OFFICE_DNS="192.168.5.50"
export OFFICE_VPN_NAME="Office VPN"
# Use a bash style array for OFFICE_SEARCH_DOMAINS
export OFFICE_SEARCH_DOMAINS=( c2fo.com corp.c2fo.com )
export NETWORK_INTERFACE="Wi-Fi"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment