ukanth / afwall

AFWall+ (Android Firewall +) - iptables based firewall for Android
GNU General Public License v3.0
2.68k stars 447 forks source link

[ISSUE] AFWall+ 3.6 and OpenVPN Connect fails Android 11+ Private DNS #1355

Open resolutecake opened 8 months ago

resolutecake commented 8 months ago

Describe the bug When on Android 11+ using OpenVPN Connect with Private DNS set to other than Off or Automatic and AFWall+ is enabled, DNS fails to function until the VPN is disconnected — root cause is a race timing issue — works for some fast local VPNs, but not for those slower public ones

Symptoms: —a The exclamation mark superimposed on the statusbar LTE or Wi-Fi icon should go away within 1 second, it stays put —b Within 11 seconds: pling and notification: Network has no internet access Private DNS server cannot be accessed —c the Private DNS menu selection has text below: Couldn’t connect —d Android apps fails with ERR_NAME_NOT_RESOLVED

GETAROUND: Ensure that unencrypted DNS is always allowed for root inside the vpn tunnel:

Use a custom script ./data/dnsgoogle (should work for all DNS providers) Write file /data/dnsgoogle:

#!/system/bin/sh
# License: ISC
# /data/data/com.termux/files/usr/bin/nano /data/dnsgoogle
# Android 11+ Private DNS dns.google to work with AFWall+ 3.6
# if not present: statusbar has bars-with-question-mark, pling, Private DNS: Can’t Connect
# and Android apps errors: ERR_NAME_NOT_RESOLVED
# Only required for Private DNS Setting other than Off or Automatic
unset RULE CHAIN
# Allow regular DNS udp/53 inside vpn AT ALL TIMES
RULE=(--match owner --uid-owner 0 --out-interface tun0 --protocol udp --destination-port 53 --jump ACCEPT)
CHAIN=OUTPUT
if ! iptables --check $CHAIN "${RULE[@]}"; then
  iptables --insert $CHAIN "${RULE[@]}"
fi
unset RULE CHAIN

ls -l /data/dnsgoogle -rwxr-xr-x 1 u0_a252 u0_a252 764 Sep 19 16:14 /data/dnsgoogle — executable by root

root user access must be allowed in AFWall+ for any interface to be used

Firewall Logs N/A

Smartphone (please complete the following information): Pixel 3 Android 12 October 5, 2021 SP1A.210812.016.C2

Additional context Likely, AFWall+ is busy rebuilding its configuration and while that is ongoing traffic is blocked. DNS resolution of Private DNS server like dns.google is not retried

For Android settings Private DNS: Off or Automatic, regular unencrypted DNS is used on troubles. Only the option with a set provider is full privacy

The most optimal DNS is: DNS-over-HTTP/3 DoH3 udp port 443 packet-loss resilient, Android 11+ DoQ — DNS-over-TLS (DoT) incurs overhead for every DNS request: tcp port 853 https://security.googleblog.com/2022/07/dns-over-http3-in-android.html

There are others: DNS-over-TLS (DoT) tcp port 853 DoQ udp port 8853 packet-loss resilient DNS-over-HTTPS (DoH) tcp port 443 DNS-over-HTTP/3 DoH3 udp port 443 packet-loss resilient, Android 11+ https://help.nextdns.io/t/x2hmvas/what-is-dns-over-tls-dot-dns-over-quic-doq-and-dns-over-https-doh-doh3

resolutecake commented 8 months ago

Additionally, due to AFWall+ 3.6 design, initial packets may be delayed by up to 15 s due to temporary blocking of vpn and dns while AFWall+ is working. Because AFWall+ also blocks your apps, it’s difficult to benefit from the instant DNS

The following updated script enhances that: — vpn is never blocked either, if you can design a good rule for your vpn — regular DNS and Private DNS is never blocked, for how dns.google works, likely also others — no need to unblock root in AFWall+, which is known to cause excessive traffick from Google apps

#!/system/bin/sh
# License: ISC
# /data/data/com.termux/files/usr/bin/nano /data/dnsgoogle
# Android 11+ Private DNS dns.google to work with AFWall+ 3.6
# if not present: statusbar has bars-with-question-mark, pling, Private DNS: Couldn’t Connect
# and Android apps errors: ERR_NAME_NOT_RESOLVED
# Only required for Private DNS Setting other than Off or Automatic
# Version: 230920 03:39
#
# UID for VPN Android app
VPNUID=10249
CHAIN=GDNS
CHAIN0=OUTPUT
#
unset RULE
iptables --new $CHAIN 2>/dev/null || :
RULE=($CHAIN0 --match owner --uid-owner 0 --out-interface tun0 --jump $CHAIN)
R="-A OUTPUT -o tun0 -m owner --uid-owner 0 -j $CHAIN"
# ensure at top
if [ "$(iptables --list-rules $CHAIN0 1)" != "$R" ] ;then
  iptables --delete "${RULE[@]}" 2>/dev/null || :
  iptables --insert "${RULE[@]}"
fi
#
# ensure vpn is never blocked 230920 02:31
# second position to be ahead of afwall rule
P=2
RULE=(--match owner --uid-owner $VPNUID --jump ACCEPT)
R="-A $CHAIN0 -m owner --uid-owner $VPNUID -j ACCEPT"
if [ "$(iptables --list-rules $CHAIN0 $P)" != "$R" ] ;then
  iptables --delete $CHAIN0 "${RULE[@]}" 2>/dev/null || :
  iptables --insert $CHAIN0 $P "${RULE[@]}"
fi
#
# Allow regular DNS udp/53 inside vpn AT ALL TIMES
RULE=(--protocol udp --destination-port 53 --jump ACCEPT)
if ! iptables --check $CHAIN "${RULE[@]}" 2>/dev/null; then
  iptables --insert $CHAIN "${RULE[@]}"
fi
# DoH3 udp/443
RULE=(--protocol udp --destination-port 443 --jump ACCEPT)
if ! iptables --check $CHAIN "${RULE[@]}" 2>/dev/null; then
  iptables --insert $CHAIN "${RULE[@]}"
fi
# DoT tcp/853
RULE=(--protocol tcp --destination-port 853 --jump ACCEPT)
if ! iptables --check $CHAIN "${RULE[@]}" 2>/dev/null; then
  iptables --insert $CHAIN "${RULE[@]}"
fi
unset RULE CHAIN CHAIN0 R P
echo at end of dnsgoogle

The resulting iptables:

for a in $(seq 1 3); do iptables --list-rules OUTPUT $a; done && iptables --list-rules GDNS
-A OUTPUT -o tun0 -m owner --uid-owner 0 -j GDNS
-A OUTPUT -m owner --uid-owner 10249 -j ACCEPT
-A OUTPUT -j afwall
-N GDNS
-A GDNS -p tcp -m tcp --dport 853 -j ACCEPT
-A GDNS -p udp -m udp --dport 443 -j ACCEPT
-A GDNS -p udp -m udp --dport 53 -j ACCEPT
resolutecake commented 8 months ago

This works on all my Androids

The requirements on AFWall+ to avoid — up to 15 s network outages caused by AFWall+ and — temporary DNS failures and permanent failure of Private DNS until the next network change is for AFWall+ to never block, for no matter how short the time period: — The VPN Android App in use — Inside the vpn tunnel, DNS access by user 0 root over udp/53 udp/443 tcp/853