Last active
October 25, 2024 15:00
-
-
Save cemysce/090e077763ccced25275d9586253ce18 to your computer and use it in GitHub Desktop.
Termux .bashrc snippet to override resolv.conf with Wi-Fi DHCP DNS config
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is to help address this Termux/Android issue: | |
# https://github.com/termux/termux-packages/issues/1174 | |
function _getAndroidAllDNS() | |
{ | |
local -n dnsMapRef=$1 | |
local -n domainMapRef=$2 | |
# The logic here is from experimentation based on: | |
# https://www.reddit.com/r/termux/comments/1249mqx/use_dhcp_provided_dns_in_resolveconf/ | |
# This is currently an oversimplification. Each network has a complicated | |
# "Score" field which seems to govern which network is used, and it is | |
# totally ignored here. | |
local connectivityDump=$(/system/bin/dumpsys connectivity) | |
if [[ $? -ne 0 ]]; then | |
echo 'ERROR: Failed to get connectivity dump!' >&2 | |
return 1 | |
fi | |
local re='\<android\.permission\.DUMP\>' | |
if [[ ${connectivityDump} =~ ${re} ]]; then | |
echo 'ERROR: Termux needs permission to dump connectivity; run on adb client:' >&2 | |
echo ' adb shell pm grant com.termux android.permission.DUMP' >&2 | |
echo ' If desired, can be undone using "revoke" instead of "grant".' >&2 | |
return 1 | |
fi | |
local line | |
re='\<NetworkAgentInfo\>.*\<ni *\{ *([^ \{\}]+) *CONNECTED *extra: *([^ \{\}]*) *\}.*\<DnsAddresses: *\[ *([^][ ]*) *\].*\<Domains: *([^ ]*)' | |
local name | |
local -A networks | |
local -a dnsList | |
local dns | |
while IFS= read line; do | |
if [[ ${line} =~ ${re} ]]; then | |
name=${BASH_REMATCH[1]} | |
[[ -n ${BASH_REMATCH[2]} ]] && name+=".${BASH_REMATCH[2]}" | |
if [[ -v networks[${name}] ]]; then | |
echo "ERROR: Duplicate network \"${name}\"!" >&2 | |
return 1 | |
fi | |
networks[${name}]= | |
dnsList=() | |
for dns in ${BASH_REMATCH[3]//,/ }; do | |
if [[ ${dns} == /* ]]; then | |
dnsList+=("${dns#/}") | |
fi | |
done | |
if [[ ${#dnsList[@]} -gt 0 ]]; then | |
dnsMapRef[${name}]=${dnsList[*]} | |
fi | |
if [[ -n ${BASH_REMATCH[4]} && ${BASH_REMATCH[4]} != 'null' ]]; then | |
domainMapRef[${name}]=${BASH_REMATCH[4]//,/ } | |
fi | |
fi | |
done <<<"${connectivityDump}" | |
} | |
function _prettyPrintAndroidAllDNS() | |
{ | |
local -A dnsMap domainMap | |
local name | |
_getAndroidAllDNS dnsMap domainMap || return $? | |
for name in ${!dnsMap[@]}; do | |
echo "${name} DNS Servers: ${dnsMap[${name}]}" | |
if [[ -v domainMap[${name}] ]]; then | |
echo "${name} Domains: ${domainMap[${name}]}" | |
fi | |
done | |
} | |
function _getAndroidWiFiDNS() | |
{ | |
local -n dnsListRef=$1 | |
local -n domainListRef=$2 | |
# The logic here is just based on some experimentation. | |
local -A dnsMap domainMap | |
_getAndroidAllDNS dnsMap domainMap || return $? | |
if [[ ! -v dnsMap[WIFI] ]]; then | |
return 1 | |
fi | |
dnsListRef=(${dnsMap[WIFI]}) | |
if [[ -v domainMap[WIFI] ]]; then | |
domainListRef=(${domainMap[WIFI]}) | |
fi | |
} | |
function _backupResolvConfIfNotAlready() | |
{ | |
[[ -f "${HOME}/.backup.etc.resolv.conf" ]] && return | |
[[ ! -e "${HOME}/.backup.etc.resolv.conf" ]] || return $? | |
cp -a "${PREFIX}/etc/resolv.conf" "${HOME}/.backup.etc.resolv.conf" | |
} | |
function _restoreResolvConf() | |
{ | |
[[ ! -f "${HOME}/.backup.etc.resolv.conf" ]] && return | |
mv "${HOME}/.backup.etc.resolv.conf" "${PREFIX}/etc/resolv.conf" | |
} | |
function _replaceOrRestoreResolvConfAccordingToWiFi() | |
{ | |
local -a wiFiDNS wiFiDomains | |
_getAndroidWiFiDNS wiFiDNS wiFiDomains | |
if [[ $? -eq 0 && ${#wiFiDNS[@]} -gt 0 ]]; then | |
echo "DNS servers found for Wi-Fi network, will override Termux's resolv.conf." | |
if ! _backupResolvConfIfNotAlready; then | |
echo 'ERROR: Failed to backup resolv.conf!' >&2 | |
return 1 | |
fi | |
( | |
echo "# Generated by ~/.bashrc using Wi-Fi network's DNS config:" | |
if [[ ${#wiFiDomains[@]} -gt 0 ]]; then | |
echo -n 'search' | |
for domain in "${wiFiDomains[@]}"; do | |
echo -n " ${domain}" | |
done | |
echo | |
fi | |
for dns in "${wiFiDNS[@]:0:3}"; do # resolv.conf can have max 3 nameservers | |
echo "nameserver ${dns}" | |
done | |
) >"${PREFIX}/etc/resolv.conf" | |
else | |
echo "No DNS servers found for Wi-Fi network, will use Termux's resolv.conf." | |
if ! _restoreResolvConf; then | |
echo 'ERROR: Failed to restore resolv.conf!' >&2 | |
return 1 | |
fi | |
fi | |
} | |
# NOTE: There's nothing intrinsically correct about doing this, it's just a choice. | |
_replaceOrRestoreResolvConfAccordingToWiFi | |
function _resolvWarnRun() | |
{ | |
local sep=$(printf '%.0s*' $(seq "${COLUMNS}")) | |
echo "${sep}" >&2 | |
echo "WARNING: $1 uses Termux's static ${PREFIX}/etc/resolv.conf" >&2 | |
echo " instead of Android's DNS!" >&2 | |
echo "${sep}" >&2 | |
echo >&2 | |
command "$@" | |
} | |
alias dig='_resolvWarnRun dig' | |
alias host='_resolvWarnRun host' | |
alias nmap='_resolvWarnRun nmap' | |
alias nslookup='_resolvWarnRun nslookup' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you SO MUCH for this.