Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
74391b1
Add root DNS hijacker daemon
Mainkill1 Jun 26, 2026
a59a399
Persist DNS daemon query logs
Mainkill1 Jun 26, 2026
b6b2d6b
Add DNS daemon diagnostics controls
Mainkill1 Jun 26, 2026
27e3d87
Add DNS blocklist import support
Mainkill1 Jun 26, 2026
fefbd85
Add DNS live query viewer
Mainkill1 Jun 26, 2026
2c5a007
Improve DNS daemon cache stats
Mainkill1 Jun 26, 2026
3ebc121
Add DNS boot persistence
Mainkill1 Jun 26, 2026
12314e3
Add DNS protection repair action
Mainkill1 Jun 26, 2026
e6b22df
Add temporary DNS query rules
Mainkill1 Jun 26, 2026
c1284ef
Add DNS daemon health probe
Mainkill1 Jun 26, 2026
b94537b
Add scheduled DNS blocklist updates
Mainkill1 Jun 26, 2026
fa03dda
Add profile DNS policy overrides
Mainkill1 Jun 26, 2026
47ff948
Add DNS upstream benchmarking
Mainkill1 Jun 26, 2026
7298b8d
Add DNS split upstream routes
Mainkill1 Jun 26, 2026
6bf58e8
Add per-app DNS redirect policy
Mainkill1 Jun 26, 2026
54bc515
Add per-network DNS redirect policy
Mainkill1 Jun 26, 2026
46b8dd9
Add configurable DNS cache size
Mainkill1 Jun 26, 2026
8e81ebb
Index exact DNS rules in daemon
Mainkill1 Jun 26, 2026
df19908
Add suffix trie DNS rule lookup
Mainkill1 Jun 26, 2026
fb09f4f
Harden DNS daemon watchdog recovery
Mainkill1 Jun 26, 2026
6c25dae
Report DNS daemon resource stats
Mainkill1 Jun 26, 2026
d59fd9c
Add DNS query history search
Mainkill1 Jun 26, 2026
f379738
Export displayed DNS queries
Mainkill1 Jun 26, 2026
ed41abb
Add DNS blocklist paste import
Mainkill1 Jun 26, 2026
e50550e
Add DNS blocklist JSON bundle import
Mainkill1 Jun 26, 2026
ecd05c3
Retry truncated DNS upstream replies over TCP
Mainkill1 Jun 26, 2026
14dbaf4
Improve DNS daemon negative cache stats
Mainkill1 Jun 26, 2026
7298c4f
Add DNS blocklist presets
Mainkill1 Jun 26, 2026
9ea247d
Report DNS blocklist update metadata
Mainkill1 Jun 26, 2026
647a599
Add DNS protection dashboard summary
Mainkill1 Jun 26, 2026
55bfad9
Add DNS upstream protocol selection
Mainkill1 Jun 26, 2026
f00bab1
Expand DNS query log metadata
Mainkill1 Jun 26, 2026
d0358ab
Add DNS bootstrap upstream resolution
Mainkill1 Jun 26, 2026
0b371ce
Move DNS log persistence off request loop
Mainkill1 Jun 27, 2026
f151b97
Add DNS query logging controls
Mainkill1 Jun 27, 2026
acbffca
Add nftables DNS redirect fallback
Mainkill1 Jun 27, 2026
0e7ce25
Scale DNS daemon rule storage
Mainkill1 Jun 27, 2026
30f1128
Harden DNS daemon regex rule loading
Mainkill1 Jun 27, 2026
3e291e6
Harden DNS daemon supervisor readiness
Mainkill1 Jun 27, 2026
3740a4d
Add DNS daemon heartbeat watchdog
Mainkill1 Jun 27, 2026
3c4b6c2
Honor DNS cache TTL aging
Mainkill1 Jun 27, 2026
4eda645
Use LRU DNS cache eviction
Mainkill1 Jun 27, 2026
48c52d1
Precompile DNS upstream addresses
Mainkill1 Jun 27, 2026
17557ad
Reuse DNS upstream UDP sockets
Mainkill1 Jun 27, 2026
c605b54
Bound DNS daemon client stalls
Mainkill1 Jun 27, 2026
c10c5dd
Drain DNS UDP bursts
Mainkill1 Jun 27, 2026
66e976e
Preserve DNS cache across reloads
Mainkill1 Jun 27, 2026
10c5a8f
Add DNS SafeSearch enforcement
Mainkill1 Jun 27, 2026
5fffc60
Scope DNS cache reload preservation
Mainkill1 Jun 27, 2026
9068709
Add DNS dashboard quick actions
Mainkill1 Jun 27, 2026
a765706
Validate DNS upstream schemes
Mainkill1 Jun 27, 2026
24611bb
Add DNS query source logging
Mainkill1 Jun 27, 2026
f01acb0
Add DNS query UID attribution
Mainkill1 Jun 27, 2026
6265f0e
Show apps in DNS query viewer
Mainkill1 Jun 27, 2026
537aea9
Add DNS query decision details
Mainkill1 Jun 27, 2026
6c45e03
Add per-app DNS exact rules
Mainkill1 Jun 27, 2026
8cf52f3
Add per-app DNS wildcard rules
Mainkill1 Jun 27, 2026
1e7372b
Probe full DNS cache table
Mainkill1 Jun 27, 2026
8c9043c
Add DNS config validation status
Mainkill1 Jun 27, 2026
1d400c3
Track DNS reload validation failures
Mainkill1 Jun 27, 2026
e40c59f
Report DNS listener readiness
Mainkill1 Jun 27, 2026
2a59331
Serve stale DNS cache on upstream failure
Mainkill1 Jun 27, 2026
b7e54a2
Track DNS upstream runtime stats
Mainkill1 Jun 27, 2026
b64bec0
Persist DNS cache snapshots
Mainkill1 Jun 27, 2026
8d1e59e
Honor temporary DNS blocks before allowlists
Mainkill1 Jun 27, 2026
91fb7f5
Reject missing DNS rule files on reload
Mainkill1 Jun 27, 2026
9dc1064
Reject invalid DNS upstream config
Mainkill1 Jun 27, 2026
31c164d
Add DNSSEC-aware upstream forwarding
Mainkill1 Jun 27, 2026
42824e1
Improve DNS service lifecycle handling
Mainkill1 Jun 27, 2026
23b5640
Align DNSSEC upstream probes
Mainkill1 Jun 27, 2026
ba56c4b
Add per-network DNS hijack rules
Mainkill1 Jun 27, 2026
9e7a83b
Add DNS upstream backoff
Mainkill1 Jun 27, 2026
ee440cb
Add DNSSEC authenticated upstream mode
Mainkill1 Jun 27, 2026
c9d4812
Add daily DNS dashboard counters
Mainkill1 Jun 27, 2026
ea4e06e
Add DNS service lifecycle cleanup
Mainkill1 Jun 27, 2026
76c9fa3
Expand DNS dashboard health stats
Mainkill1 Jun 27, 2026
51daedd
Show DNS redirect rule health
Mainkill1 Jun 27, 2026
9acfb5d
Add per-app DNS capture actions
Mainkill1 Jun 27, 2026
70886c6
Expand DNS daemon validation diagnostics
Mainkill1 Jun 27, 2026
94d11f3
Improve DNS blocklist import compatibility
Mainkill1 Jun 27, 2026
b590c99
Stage DNS blocklist activation safely
Mainkill1 Jun 27, 2026
9f83acb
Validate DNS blocklists before daemon reload
Mainkill1 Jun 27, 2026
bdc20dd
Add DNS profile presets
Mainkill1 Jun 27, 2026
4a0ddb5
Add DNS diagnostics export
Mainkill1 Jun 27, 2026
f3c2082
Add DNS upstream provider presets
Mainkill1 Jun 27, 2026
6bd57a1
Bridge DNS service logs into app diagnostics
Mainkill1 Jun 27, 2026
7b15bb9
Summarize DNS service readiness in dashboard
Mainkill1 Jun 27, 2026
84b2e63
Verify nft DNS redirect rules in dashboard health
Mainkill1 Jun 27, 2026
7375472
Verify iptables DNS redirect targets in health
Mainkill1 Jun 27, 2026
624619d
Surface root DNS capture bypass caveat
Mainkill1 Jun 27, 2026
a8f502e
Bind DNS daemon listeners per address family
Mainkill1 Jun 27, 2026
446b433
Fix nft fallback restore script generation
Mainkill1 Jun 27, 2026
1cbb7ff
Expose DNS service power settings
Mainkill1 Jun 27, 2026
3cd74f4
Expose Private DNS compatibility settings
Mainkill1 Jun 27, 2026
b353dad
Verify DNS redirect backend installation
Mainkill1 Jun 27, 2026
a647713
Honor IPv6 setting during DNS boot restore
Mainkill1 Jun 27, 2026
882f8d4
Apply DNS redirect setting changes immediately
Mainkill1 Jun 27, 2026
d6d7945
Bridge root DNS service logs into app logs
Mainkill1 Jun 27, 2026
19328fb
Use daemon socket marks for DNS bypass
Mainkill1 Jun 27, 2026
afce3e3
Gate DNS mark bypass on daemon status
Mainkill1 Jun 27, 2026
2e657eb
Allow root DNS daemon upstream traffic
Mainkill1 Jun 27, 2026
a783f4a
Log root command stderr on failures
Mainkill1 Jun 27, 2026
ecf0878
Add DNS capture runtime probe
Mainkill1 Jun 27, 2026
047ab15
Harden root DNS service recovery
Mainkill1 Jun 27, 2026
5d7d707
Align DNS control token validation
Mainkill1 Jun 27, 2026
4ae279a
Add ADB DNS diagnostics mode
Mainkill1 Jun 27, 2026
9c89580
Add ADB DNS control helper
Mainkill1 Jun 27, 2026
954ac6d
Add ADB DNS control TCP fallback
Mainkill1 Jun 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ proguard/
# native binaries
libs/
obj/
dnsdaemon/libs/
dnsdaemon/obj/

# IDE related
.idea/
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@
<activity
android:name=".activity.LogHubActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|locale|screenLayout"></activity>
<activity
android:name=".activity.DnsQueriesActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|locale|screenLayout"></activity>
<activity
android:name=".activity.ApplicationErrorsActivity"
android:configChanges="orientation|keyboardHidden|screenSize|keyboard|locale|screenLayout"></activity>
Expand Down Expand Up @@ -224,6 +227,9 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver
android:name=".broadcast.DnsBlocklistUpdateReceiver"
android:exported="false" />
<receiver
android:name=".broadcast.PackageBroadcast"
android:exported="true">
Expand Down
Binary file added app/src/main/assets/dnsd/arm64-v8a/afwall_dnsd
Binary file not shown.
Binary file not shown.
Binary file added app/src/main/assets/dnsd/x86/afwall_dnsd
Binary file not shown.
Binary file added app/src/main/assets/dnsd/x86_64/afwall_dnsd
Binary file not shown.
15 changes: 12 additions & 3 deletions app/src/main/java/dev/ukanth/ufirewall/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
import dev.ukanth.ufirewall.MainActivity.GetAppList;
import dev.ukanth.ufirewall.customrules.CustomRule;
import dev.ukanth.ufirewall.customrules.CustomRule_Table;
import dev.ukanth.ufirewall.dns.DnsHijackManager;
import dev.ukanth.ufirewall.log.Log;
import dev.ukanth.ufirewall.log.LogData;
import dev.ukanth.ufirewall.log.LogData_Table;
Expand Down Expand Up @@ -1173,6 +1174,10 @@ private static boolean applyIptablesRulesImpl(final Context ctx, RuleDataSet rul
cmds.add("-t nat -I OUTPUT 1 -j " + chainName);
}

// DNS redirect must be built in the same root batch as firewall apply so stale root
// grants fail through normal apply logging instead of leaving half-installed redirects.
DnsHijackManager.appendApplyCommands(ctx, cmds, ipv6);

// custom rules in afwall-{3g,wifi,reject} supersede everything else
addCustomRules(Api.PREF_CUSTOMSCRIPT, cmds, ipv6);

Expand Down Expand Up @@ -1348,7 +1353,6 @@ private static void iptablesCommands(List<String> in, List<String> out, boolean
}
boolean firstLit = true;
for (String s : in) {
s = s + waitTime;
if (s.matches("#LITERAL# .*")) {
if (firstLit) {
// export vars for the benefit of custom scripts
Expand All @@ -1359,11 +1363,12 @@ private static void iptablesCommands(List<String> in, List<String> out, boolean
+ "export IPV6=" + (ipv6 ? "1" : "0") + "; "
+ "true");
}
// Literal commands may be supervisor/control scripts and must not inherit iptables flags.
out.add(s.replaceFirst("^#LITERAL# ", ""));
} else if (s.matches("#NOCHK# .*")) {
out.add(s.replaceFirst("^#NOCHK# ", "#NOCHK# " + ipPath + " "));
out.add(s.replaceFirst("^#NOCHK# ", "#NOCHK# " + ipPath + " ") + waitTime);
} else {
out.add(ipPath + " " + s);
out.add(ipPath + " " + s + waitTime);
}
}
}
Expand Down Expand Up @@ -1800,6 +1805,9 @@ public static void purgeIptables(Context ctx, boolean showErrors, RootCommand ca
} else {
cmdsv4.add("#NOCHK# -D OUTPUT -j " + chainName);
}
// Purging firewall rules must also remove DNS capture, otherwise the root daemon can keep
// receiving traffic after the user thinks protection has been disabled.
DnsHijackManager.appendPurgeCommands(ctx, cmds, false);

//make sure reset the OUTPUT chain to accept state.
cmds.add("-P OUTPUT ACCEPT");
Expand Down Expand Up @@ -1828,6 +1836,7 @@ public static void purgeIptables(Context ctx, boolean showErrors, RootCommand ca
cmdsv6.add("-F " + chainName + s);
}
cmdsv6.add("#NOCHK# -D OUTPUT -j " + chainName);
DnsHijackManager.appendPurgeCommands(ctx, cmdsv6, true);
cmdsv6.add("-P OUTPUT ACCEPT");
if (G.enableInbound()) {
cmdsv6.add("-D INPUT -j " + chainName + "-input");
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/java/dev/ukanth/ufirewall/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import dev.ukanth.ufirewall.activity.CustomScriptActivity;
import dev.ukanth.ufirewall.activity.HelpActivity;
import dev.ukanth.ufirewall.activity.LogHubActivity;
import dev.ukanth.ufirewall.dns.DnsHijackManager;
import dev.ukanth.ufirewall.log.Log;
import dev.ukanth.ufirewall.preferences.PreferencesActivity;
import dev.ukanth.ufirewall.profiles.ProfileData;
Expand Down Expand Up @@ -1080,10 +1081,36 @@ public void onItemSelected(AdapterView<?> parent, View view, int position, long
showOrLoadApplications();
if (G.applyOnSwitchProfiles()) {
applyOrSaveRules();
} else {
refreshDnsProfilePolicyAfterSwitch();
}
}
}

private void refreshDnsProfilePolicyAfterSwitch() {
if (!G.enableDnsHijack() || !G.dnsHijackUseProfilePolicy()) {
return;
}
Api.setRulesUpToDate(false);
ApplicationErrorLog.add(this, "DNS profile policy changed; refreshing DNS service for active profile: "
+ G.activeDnsHijackPolicyProfile());
DnsHijackManager.repairDnsProtection(this, new RootCommand.Callback() {
@Override
public void cbFunc(RootCommand state) {
if (state.exitCode == 0) {
ApplicationErrorLog.add(MainActivity.this,
"DNS profile policy refresh completed for active profile: "
+ G.activeDnsHijackPolicyProfile());
} else {
ApplicationErrorLog.add(MainActivity.this,
"DNS profile policy refresh failed after profile switch");
runOnUiThread(() -> Api.toast(MainActivity.this,
getString(R.string.dns_hijack_redirect_settings_failed)));
}
}
});
}

@Override
public void onNothingSelected(AdapterView<?> parent) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import dev.ukanth.ufirewall.Api;
import dev.ukanth.ufirewall.R;
import dev.ukanth.ufirewall.dns.DnsHijackManager;
import dev.ukanth.ufirewall.util.ApplicationErrorLog;
import dev.ukanth.ufirewall.util.G;
import dev.ukanth.ufirewall.util.ThemeHelper;
Expand Down Expand Up @@ -76,6 +77,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
}

private void refreshData() {
DnsHijackManager.syncServiceLogsToAppLog(this);
String errors = ApplicationErrorLog.get(this);
content.setText(errors.trim().isEmpty() ? getString(R.string.application_errors_empty) : errors);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.os.Bundle;

import dev.ukanth.ufirewall.R;
import dev.ukanth.ufirewall.dns.DnsHijackManager;
import dev.ukanth.ufirewall.log.Log;

public class ApplicationLogActivity extends RulesActivity {
Expand All @@ -19,6 +20,7 @@ protected void onCreate(Bundle savedInstanceState) {
protected void populateData(final Context ctx) {
result = new StringBuilder();
updateLoadingState(getString(R.string.loading));
DnsHijackManager.syncServiceLogsToAppLog(ctx);
writeHeading(result, false, "Logcat");
result.append(Log.getApplicationLog());
updateLoadingState(getString(R.string.ready));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ private String detectSectionType(String line) {
return "ifconfig";
} else if (trimmed.contains("System info")) {
return "system";
} else if (trimmed.equals(getString(R.string.dns_diagnostics_title))) {
return "dns";
} else if (trimmed.contains("Preferences")) {
return "preferences";
} else if (trimmed.equals(getString(R.string.application_errors_title))) {
Expand Down Expand Up @@ -266,6 +268,17 @@ private void processSectionContent(String sectionType, String content) {
systemCard.setVisibility(View.VISIBLE);
systemContent.setText(trimmedContent);
break;

case "dns":
systemCard.setVisibility(View.VISIBLE);
String existingSystem = systemContent.getText().toString();
String dnsContent = getString(R.string.dns_diagnostics_title) + "\n" + trimmedContent;
if (!existingSystem.isEmpty()) {
systemContent.setText(existingSystem + "\n\n" + dnsContent);
} else {
systemContent.setText(dnsContent);
}
break;

case "preferences":
preferencesCard.setVisibility(View.VISIBLE);
Expand Down
Loading