fix: scope ISP credential lookup to its connection target - #3
Open
rimuln wants to merge 1 commit into
Open
Conversation
get_internet_config() searched the whole of ar7.cfg for username/passwd with
re.search(), so it returned whichever pair appeared first in the file. On a
FRITZ!Box 7590 running FRITZ!OS 154.08.25 that is ar7cfg > serialcfg, a
disabled mobile dial-up block holding vendor placeholders, which surfaced as
serial_username/serial_password "ppp"/"ppp" while the real provider login was
never reported at all. Output that looks like a credential pair but is not one
leaves the user no signal that the actual one was missed.
The credentials live in ar7cfg > targets > local. AVM writes repeated entries
as one block name followed by several brace-delimited bodies, as in
"targets { ...internet... } { ...voip... }", and only the target named
"internet" carries the provider login, so the lookup has to be scoped to a
single entry rather than to the file.
Add brace-depth-aware block traversal, read the credentials from the matching
target, and report the originating target name as pppoe_target. Keep the
pppoeuser/pppoepwd/ppppasswd key names as a fallback for firmware generations
that use them. Report serial_username/serial_password only when serialcfg is
enabled, so inactive vendor defaults stay out of the output.
Verified against a real password-protected 7590 export: the provider login and
password now come from targets > local, the placeholders are gone, and VoIP,
WLAN, phonebook, user and device extraction are unchanged.
Refs lucatze#2
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rimuln
force-pushed
the
fix/block-scoped-isp-credentials
branch
from
July 31, 2026 13:33
b7263c4 to
7782935
Compare
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2.
The problem
get_internet_config()looked up the ISP credentials with an unscopedre.search()over the whole ofar7.cfg, so it returned whicheverusername/passwdpair came first in the file. On a FRITZ!Box 7590 running FRITZ!OS 154.08.25 that isar7cfg > serialcfg— a disabled mobile dial-up block whose stock APN entry decrypts to the placeholderpppfor both fields.The result was
serial_username: "ppp"/serial_password: "ppp"in the output, with the real provider login never reported. Because the output still contains something that looks like a credential pair, there is no signal that the actual one was missed — that is the part which makes this worse than a plain missing field.Where the credentials actually are
ar7cfg > targets > local. AVM writes repeated entries as one block name followed by several brace-delimited bodies:Only the target named
internetcarries the provider login, so the lookup has to be scoped to a single entry.What this changes
_iter_block_entries()— brace-depth traversal yielding each body of a repeatedname { … } { … }construct. Regular expressions cannot track nesting, which is why the existing_extract_blocks()cannot express this. That helper is currently unused, so I left it untouched._get_nested_block()— the first body of a named block, brace-aware._get_isp_credentials()— walks thetargetsentries, prefers the one namedinternet, and falls back to the first entry carrying a non-empty username. It also returns the originating target name, exposed as a newpppoe_targetkey so it is clear which target a credential came from.get_internet_config()— uses the scoped lookup; keepspppoeuser/pppoepwd/ppppasswdas a fallback for firmware generations that use those names; and reportsserial_username/serial_passwordonly whenserialcfgis actually enabled (mode != serialmode_off), read from that block rather than from the whole file.Existing key names are unchanged, so anything parsing the JSON keeps working.
pppoe_targetis purely additive.Verification
Tested against a real password-protected 7590 export (FRITZ!OS 154.08.25, VDSL,
active_provider = "other"), comparingf540572against this branch. The expected lengths below come from an independent manual decrypt of the same file.pppoe_usernamepppoe_passwordpppoe_targetinternet✓serial_usernameppp(3 chars)serial_passwordppp(3 chars)No regressions: VoIP accounts 2, WLAN networks 3, phonebook 52, users 4, devices 2 — identical on both builds. All 149 encrypted values in that export decrypt with zero MD5 integrity failures.
I cannot contribute the export itself as a fixture, for the obvious reason. If it would help, I am happy to add a synthetic
ar7.cfgfragment with the same block shape and dummy$$$$values as a regression test.Note on scope
The same unscoped-first-match pattern applies to
_get_cfg_value()/_get_cfg_encrypted()in general. The export used here holds 31usernameand 12passwdkeys spread acrossserialcfg,targets > local,ddns > accounts,webui,TR_064,emailnotifyand 20 entries underapps > apps, so which one wins depends on file ordering. I deliberately kept this PR to the internet-config path; the helpers added here would make the remaining call sites straightforward to scope in a follow-up if you want that.