Skip to content

fix: sanitize DNS inputs and guard AWG s3/s4#31

Closed
hawkff wants to merge 2 commits into
mainfrom
feat/sanitize-dns-awg-s3s4
Closed

fix: sanitize DNS inputs and guard AWG s3/s4#31
hawkff wants to merge 2 commits into
mainfrom
feat/sanitize-dns-awg-s3s4

Conversation

@hawkff

@hawkff hawkff commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • sanitize direct/remote DNS settings to strip hidden control characters before saving and config generation
  • stop emitting unsupported AmneziaWG s3/s4 UAPI keys while keeping fields importable/storable

Validation

  • CodeRabbit CLI review: 0 findings
  • JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew :app:compileOssDebugKotlin

Greptile Summary

This PR adds two targeted fixes: DNS inputs are sanitized at both the UI layer (SettingsPreferenceFragment) and the config-generation layer (ConfigBuilder) by stripping ISO control characters, and the AmneziaWG outbound builder stops emitting s3/s4 UAPI keys that the bundled amneziawg-go v1.0.4 core does not yet understand.

  • DNS sanitization (UI layer): dnsReloadListener sanitizes multi-line DNS text line-by-line, persists the clean value via preference.text = sanitizedValue, calls needReload(), and returns false to prevent Android from re-persisting the raw string — correct flow.
  • DNS sanitization (config layer): sanitizeDnsEntry in ConfigBuilder.kt provides defence-in-depth for values arriving via import or programmatic paths that bypass the UI listener.
  • AmneziaWG s3/s4 guard: The buildSingBoxOutboundAmneziaWGBean function now skips the two UAPI assignments with an explanatory comment; the bean continues to store and round-trip the fields so imported profiles lose no data.

Confidence Score: 5/5

Safe to merge — both changes are additive guards with no regressions on existing behavior.

The DNS sanitization is applied correctly at two independent layers (UI persistence and config generation), using standard Kotlin stdlib APIs with no off-by-one or bypass risk. The AmneziaWG s3/s4 removal matches the documented limitation of the bundled core library and preserves round-trip fidelity for imported profiles. No existing paths are broken.

No files require special attention.

Important Files Changed

Filename Overview
app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt Adds sanitizeDnsPreferenceValue (line-by-line ISO control char strip + trim) and wires dnsReloadListener for remoteDns/directDns; correctly persists the sanitized value via preference.text before returning false to block Android from re-persisting the raw string.
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt Adds sanitizeDnsEntry (strips ISO control chars + trims) and applies it to remoteDns/directDns split entries — a safe, defence-in-depth layer that covers programmatic/import paths not gated by the UI listener.
app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGFmt.kt Removes s3/s4 emission to the UAPI, replacing two live assignments with a comment explaining the amneziawg-go v1.0.4 limitation; beans still store/import the fields, so no data loss on round-trip.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User edits remoteDns / directDns in UI] --> B[dnsReloadListener called]
    B --> C{newValue is String?}
    C -- No --> D[delegate to reloadListener\nneedReload + return true]
    C -- Yes --> E[sanitizeDnsPreferenceValue\nstrip ISO control chars per-line]
    E --> F{sanitized != raw?}
    F -- No --> G[needReload\nreturn true\nAndroid persists raw value]
    F -- Yes --> H{preference is\nEditTextPreference?}
    H -- Yes --> I[preference.text = sanitizedValue\npersistString called internally]
    H -- No --> J[no persist\nsilently discards edit]
    I --> K[needReload\nreturn false\nblock Android raw-persist]
    J --> K
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[User edits remoteDns / directDns in UI] --> B[dnsReloadListener called]
    B --> C{newValue is String?}
    C -- No --> D[delegate to reloadListener\nneedReload + return true]
    C -- Yes --> E[sanitizeDnsPreferenceValue\nstrip ISO control chars per-line]
    E --> F{sanitized != raw?}
    F -- No --> G[needReload\nreturn true\nAndroid persists raw value]
    F -- Yes --> H{preference is\nEditTextPreference?}
    H -- Yes --> I[preference.text = sanitizedValue\npersistString called internally]
    H -- No --> J[no persist\nsilently discards edit]
    I --> K[needReload\nreturn false\nblock Android raw-persist]
    J --> K
Loading

Reviews (2): Last reviewed commit: "fix: reject sanitized DNS fallback safel..." | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three small fixes: a sanitizeDnsEntry helper is added to ConfigBuilder and applied when parsing directDNS lines to strip ISO control characters; matching sanitization logic and a dnsReloadListener are added to SettingsPreferenceFragment to clean DNS text at preference-save time; and s3/s4 field emission is removed from buildSingBoxOutboundAmneziaWGBean with a comment explaining the bundled amneziawg-go UAPI does not yet accept them.

Changes

DNS Input Sanitization

Layer / File(s) Summary
DNS sanitization helpers
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt, app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt
sanitizeDnsEntry is added to ConfigBuilder to remove ISO control characters and trim strings. sanitizeDnsPreferenceValue and dnsReloadListener are added to SettingsPreferenceFragment to perform the same normalization on multiline preference text and write the sanitized value back to the preference before triggering reload.
Wiring sanitization into parsing and preference setup
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt, app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt
directDNS list parsing in ConfigBuilder now calls sanitizeDnsEntry(...) instead of plain trim(). onCreatePreferences replaces the generic reloadListener on remoteDns and directDns with the new dnsReloadListener.

AmneziaWG s3/s4 Emission Removal

Layer / File(s) Summary
Remove s3/s4 UAPI emission
app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGFmt.kt
Removes the two lines that emitted s3 and s4 to the UAPI config in buildSingBoxOutboundAmneziaWGBean, replacing them with an inline comment stating these fields are not yet accepted by the bundled amneziawg-go v1.0.4 UAPI.

Sequence Diagram

sequenceDiagram
  participant User
  participant SettingsPreferenceFragment
  participant EditTextPreference
  participant ConfigBuilder
  User->>SettingsPreferenceFragment: enters DNS text with control chars
  SettingsPreferenceFragment->>SettingsPreferenceFragment: sanitizeDnsPreferenceValue(newValue)
  SettingsPreferenceFragment->>EditTextPreference: write sanitized text back if changed
  SettingsPreferenceFragment->>ConfigBuilder: trigger reload
  ConfigBuilder->>ConfigBuilder: sanitizeDnsEntry(dns) per directDNS line
  ConfigBuilder-->>SettingsPreferenceFragment: reload complete
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit hops through lines of code,
Snipping control chars off the road,
DNS entries now clean and neat,
s3 and s4? Not yet — delete!
With tidy preferences saved just right,
The config builds without a fright. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the two main changes: DNS input sanitization and AmneziaWG s3/s4 key handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description accurately describes the changes in the changeset, covering both DNS sanitization and AmneziaWG s3/s4 UAPI key handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@hawkff

hawkff commented Jun 19, 2026

Copy link
Copy Markdown
Owner Author

Superseded by split PRs: #32 for DNS sanitization and #33 for AmneziaWG s3/s4 guard.

@hawkff hawkff closed this Jun 19, 2026
@hawkff hawkff deleted the feat/sanitize-dns-awg-s3s4 branch June 23, 2026 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant