Skip to content

Instantly share code, notes, and snippets.

@cemysce
Last active October 25, 2024 15:00
Show Gist options
  • Save cemysce/090e077763ccced25275d9586253ce18 to your computer and use it in GitHub Desktop.
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 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'
@p1r473
Copy link

p1r473 commented Oct 25, 2024

Thank you SO MUCH for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment