FTL v6.6.1#2863
Merged
Merged
Conversation
Signed-off-by: darkexplosiveqwx <101737077+darkexplosiveqwx@users.noreply.github.com>
… items Signed-off-by: DL6ER <dl6er@dl6er.de>
…config items as read-only Signed-off-by: Dominik <dl6er@dl6er.de>
Move all API-related tests (HTTP endpoints, config validation, auth, search, history, lists, Lua pages, OpenAPI spec validation) from BATS shell tests to pytest. BATS retains DNS, regex, CLI, and system-level tests. The auth test suite now removes the password at the end, leaving no net state change. Fix ResponseVerifyer to respect the OpenAPI "required" field: optional properties absent from FTL's response are silently skipped instead of flagged as errors. The required list is propagated through all recursive calls (top-level objects, allOf, nested objects, array items). Add a set_config() helper that changes FTL configuration via the API instead of shelling out to the CLI. The API PATCH is synchronous, so no log polling or sleeps are needed. Add build.sh test-api target to run only the pytest API tests (skips BATS and perf tests). Test migration mapping (25 BATS tests removed, all covered in pytest): | # | Removed BATS test | Pytest counterpart | |---|---|---| | 1 | HTTP server responds with JSON error 404 to unknown API path | TestHTTPErrors::test_api_404_returns_json | | 2 | HTTP server responds with error 404 to path outside /admin | TestHTTPErrors::test_non_admin_path_returns_404 | | 3 | Config validation working on the API (type-based checking) | TestConfigValidationAPIType (2 tests) | | 4 | Config validation working on the API (validator-based checking) | TestConfigValidationAPIValidator (4 tests) | | 5 | Changing a config option set forced by ENVVAR is not possible via the API | TestEnvvarProtectedConfig::test_api_rejects_envvar_override | | 6 | API domain search: Non-existing domain | TestDomainSearch::test_nonexistent_domain | | 7 | API domain search: antigravity.ftl | TestDomainSearch::test_antigravity_domain | | 8 | API domain search: Internationalized/partially capital domain | TestDomainSearch::test_punycode_normalization | | 9 | API history: Returns full 24 hours | TestHistory::test_history_returns_24h | | 10 | API history/clients: Returns full 24 hours | TestHistory::test_history_clients_returns_24h | | 11 | Check /api/lists?type=block | TestLists::test_block_lists_only | | 12 | Check /api/lists?type=allow | TestLists::test_allow_lists_only | | 13 | Check /api/lists without type parameter | TestLists::test_all_lists_includes_both_types | | 14 | API: No UNKNOWN reply in API | TestQueries::test_no_unknown_reply | | 15 | API: No UNKNOWN status in API | TestQueries::test_no_unknown_status | | 16 | Lua server page outside /admin is not served by default | TestLuaServerPages::test_lua_page_outside_admin_not_served_by_default | | 17 | Lua server page is generating proper backtrace | TestLuaServerPages::test_lua_page_generates_proper_backtrace | | 18 | Lua server page outside of webhome is served without login | TestLuaServerPages::test_lua_page_outside_webhome_served_without_login | | 19 | API validation (checkAPI.py) | TestEndpointCoverage (3 tests) + TestEndpointResponses + TestTeleporter | | 20 | API authorization (without password): No login required | TestAuthWorkflow::test_01_no_password_means_session_valid | | 21 | Create, set, and use application password | TestAuthWorkflow::test_02 + test_03 + test_04 | | 22 | CLI password file is as expected | TestAuthWorkflow::test_04b_cli_password_file | | 23 | API authorization: Setting password | TestAuthWorkflow::test_05_set_password | | 24 | API authorization (with password): Incorrect password is rejected | TestAuthWorkflow::test_06_incorrect_password_rejected | | 25 | API authorization (with password): Correct password is accepted | TestAuthWorkflow::test_07_correct_password_accepted | New tests without a BATS predecessor: - TestAuthWorkflow::test_08_rate_limiting_enforced - TestAuthWorkflow::test_09_remove_password - TestAuthWorkflow::test_10_no_password_after_removal Final count: 192 BATS + 38 pytest = 230 total (was 216 BATS). No tests lost, 14 net new. Signed-off-by: Dominik <dl6er@dl6er.de>
Move all API-related tests (HTTP errors, config validation, auth,
search, history, lists, Lua pages, OpenAPI spec validation) from BATS
to pytest. BATS retains DNS, regex, CLI, and system-level tests.
The test run order is now:
1. BATS test_suite.bats (186 tests) — DNS, regex, CLI, config
2. pytest test/api/ (38 tests) — API endpoints, OpenAPI, auth
3. BATS test_final.bats (6 tests) — log validation, config
rotation counts, FTL termination
Key changes:
- Fix ResponseVerifyer to respect the OpenAPI "required" field so
optional properties absent from FTL's response are silently skipped
instead of reported as errors (already committed in prior commit).
- Auth tests (test_z_auth.py) set and remove the password, leaving
no net state change. Password hashing (BALLOON-SHA256) is fully
synchronous — no sleeps or retries needed after setting a password.
- Teleporter import triggers an internal FTL restart (exit code 22,
gravity database reload). The test waits for FTL to come back so
subsequent auth tests have a working API.
- All API tests use a shared requests.Session (api_session fixture)
that authenticates once via X-FTL-SID header. No per-request
_get_session_header() calls.
- Config changes in pytest use set_config() which PATCHes the API
instead of shelling out to the CLI. The API PATCH is synchronous
so no log polling or sleeps are needed.
- Log validation (WARNING/ERROR/CRIT/DB) moved from test_suite.bats
to test_final.bats so it runs after both BATS and pytest, catching
messages from the entire run.
- gdb attachment is now opt-in (GDB=1) instead of always-on.
Files added:
test/api/conftest.py — shared fixtures (api_session, openapi, ftl)
test/api/pytest.ini — pytest configuration
test/api/test_api.py — HTTP errors, config validation, search,
history, lists, queries, Lua pages
test/api/test_openapi.py — OpenAPI spec validation, teleporter
test/api/test_z_auth.py — auth workflow (app password, login,
rate limiting, password removal)
test/test_final.bats — log validation, config rotation counts,
FTL termination
Files modified:
build.sh — remove test-api target (pytest needs
BATS seeding data)
test/run.sh — run BATS then pytest then test_final,
gdb opt-in via GDB=1
test/test_suite.bats — remove API tests (moved to pytest),
remove log validation (moved to
test_final.bats), add CLI password
set/remove test with wait-for
Test migration (25 BATS tests removed, all covered in pytest):
| # | Removed BATS test | Pytest counterpart |
|---|---|---|
| 1 | HTTP server responds with JSON error 404 to unknown API path | TestHTTPErrors::test_api_404_returns_json |
| 2 | HTTP server responds with error 404 to path outside /admin | TestHTTPErrors::test_non_admin_path_returns_404 |
| 3 | Config validation working on the API (type-based checking) | TestConfigValidationAPIType (2 tests) |
| 4 | Config validation working on the API (validator-based checking) | TestConfigValidationAPIValidator (4 tests) |
| 5 | Changing a config option set forced by ENVVAR is not possible via the API | TestEnvvarProtectedConfig::test_api_rejects_envvar_override |
| 6 | API domain search: Non-existing domain | TestDomainSearch::test_nonexistent_domain |
| 7 | API domain search: antigravity.ftl | TestDomainSearch::test_antigravity_domain |
| 8 | API domain search: Internationalized/partially capital domain | TestDomainSearch::test_punycode_normalization |
| 9 | API history: Returns full 24 hours | TestHistory::test_history_returns_24h |
| 10 | API history/clients: Returns full 24 hours | TestHistory::test_history_clients_returns_24h |
| 11 | Check /api/lists?type=block | TestLists::test_block_lists_only |
| 12 | Check /api/lists?type=allow | TestLists::test_allow_lists_only |
| 13 | Check /api/lists without type parameter | TestLists::test_all_lists_includes_both_types |
| 14 | API: No UNKNOWN reply in API | TestQueries::test_no_unknown_reply |
| 15 | API: No UNKNOWN status in API | TestQueries::test_no_unknown_status |
| 16 | Lua server page outside /admin is not served by default | TestLuaServerPages::test_lua_page_outside_admin_not_served_by_default |
| 17 | Lua server page is generating proper backtrace | TestLuaServerPages::test_lua_page_generates_proper_backtrace |
| 18 | Lua server page outside of webhome is served without login | TestLuaServerPages::test_lua_page_outside_webhome_served_without_login |
| 19 | API validation (checkAPI.py) | TestEndpointCoverage (3) + TestEndpointResponses + TestTeleporter |
| 20 | API authorization (without password): No login required | TestAuthWorkflow::test_01_no_password_means_session_valid |
| 21 | Create, set, and use application password | TestAuthWorkflow::test_02 + test_03 + test_04 |
| 22 | CLI password file is as expected | TestAuthWorkflow::test_04b_cli_password_file |
| 23 | API authorization: Setting password | TestAuthWorkflow::test_05_set_password |
| 24 | API authorization: Incorrect password is rejected | TestAuthWorkflow::test_06_incorrect_password_rejected |
| 25 | API authorization: Correct password is accepted | TestAuthWorkflow::test_07_correct_password_accepted |
New tests without a BATS predecessor:
- TestAuthWorkflow::test_08_rate_limiting_enforced
- TestAuthWorkflow::test_09_remove_password
- TestAuthWorkflow::test_10_no_password_after_removal
Log validation tests moved from test_suite.bats to test_final.bats:
- No WARNING messages in FTL.log
- No ERROR messages in FTL.log
- No CRIT messages in FTL.log
- No "DB not available" messages in FTL.log
- Expected number of config file rotations
- FTL terminates with message
Final count: 186 BATS + 38 pytest + 6 final BATS = 230 total
(was 216 BATS). No tests lost, 14 net new.
Signed-off-by: Dominik <dl6er@dl6er.de>
Add the pytest test files and final BATS suite that were described
in the previous commit but not yet included.
New files:
test/api/conftest.py — shared fixtures (api_session, openapi, ftl)
test/api/pytest.ini — pytest configuration
test/api/test_api.py — HTTP errors, config validation, search,
history, lists, queries, Lua pages
test/api/test_openapi.py — OpenAPI spec validation, teleporter
test/api/test_z_auth.py — auth workflow (app password, login,
rate limiting, password removal)
test/test_final.bats — log validation, config rotation counts,
FTL termination
Signed-off-by: Dominik <dl6er@dl6er.de>
…TLenv Add pytest tests for all previously untested GET API endpoints: dns/blocking, domains (all type/kind combinations and single lookup), groups, stats/summary, stats/top_domains, stats/top_clients, stats/upstreams, stats/query_types, stats/recent_blocked, stats/database (error handling), dhcp/leases, endpoints, info/ftl, info/login, info/version, info/messages, info/client, info/database, info/system, network/devices, network/interfaces, logs (dnsmasq, ftl, webserver), and padd. All assertions use exact expected values derived from the deterministic BATS DNS query seeding (137 total queries, 49 blocked, 47 forwarded, 41 cached, 11 active clients, 8 gravity domains). On failure, the full JSON response is dumped to /tmp/ftl_test_*.json for easy inspection. Fix double-free bug in printFTLenv() (src/config/env.c): when printFTLenv() was called more than once (e.g. after config reload triggered by the CLI password test), it would free item->error a second time because neither the pointer nor the error_allocated flag were reset after the first free. This produced "Trying to free NULL pointer in printFTLenv()" warnings. Fix: set item->error = NULL and item->error_allocated = false after freeing. Files modified: src/config/env.c — reset error/error_allocated after free test/api/test_api.py — add 34 new endpoint tests (22 -> 56 total) Signed-off-by: Dominik <dl6er@dl6er.de>
… on this platform. Signed-off-by: Dominik <dl6er@dl6er.de>
Co-authored-by: Adam Warner <me@adamwarner.co.uk> Signed-off-by: Dominik <DL6ER@users.noreply.github.com>
test_openapi.py: Store auth_method per endpoint alongside errors so the assertion message shows the correct auth method for each failing endpoint instead of the last loop iteration's value. run.sh: Update comment to reflect that BATS no longer terminates FTL (termination was moved to test_final.bats). Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
…ilure test_network_devices expects ip-127.0.0.1 in the network devices list, but this mock-hwaddr entry is only created when parse_neighbor_cache() runs in the database thread. That function fires after a DBinterval (60s) elapses. On 32-bit emulated builds, the timing race is lost and the entry doesn't exist yet when the test runs. Send RT signal 5 (PARSE_NEIGHBOR_CACHE) to FTL before starting pytest so the network table is populated regardless of elapsed time. Signed-off-by: Dominik <dl6er@dl6er.de>
Replace SKIP_PERF_TEST=1 (opt-out) with RUN_PERF_TEST=1 (opt-in). Standard `./build.sh test` no longer runs the slow --perf suite; use `./build.sh test-perf` to include it. Increase CI retry timeouts for QEMU-emulated builds (especially RISC-V): build 15→30 min, test 10→20 min. Signed-off-by: Dominik <dl6er@dl6er.de>
The test schema had drifted from the real /etc/pihole/gravity.db: - domainlist/adlist used single-column UNIQUE instead of composite UNIQUE(domain,type) / UNIQUE(address,type), causing silent SQL failures on INSERT ... ON CONFLICT - adlist column order had `type` in wrong position - client table had `NOL NULL` typo (should be `NOT NULL`) - *_by_group tables were missing ON DELETE CASCADE and WITHOUT ROWID - info table was missing WITHOUT ROWID - vw_gravity had extra `AND adlist.type = 0` filter not in production - vw_adlist was missing `type` column in SELECT - domainlist views had ORDER BY clauses not present in production - Three indexes were missing (idx_adlist_by_group_gid, idx_domainlist_by_group_gid, idx_gravity) Signed-off-by: Dominik <dl6er@dl6er.de>
api_list_write() unconditionally returned 200/201 even when gravityDB_addToTable() failed for every item (e.g., SQL prepare errors). The error details were captured in the processed.errors array but the HTTP status code indicated success. Now returns 400 with a database_error when no items were successfully added. Partial failures in batch operations still return 200 with the processed object detailing which items succeeded and which failed. Also adds the database_error example to the PUT 400 response specs for groups, clients, and lists (domains already had it). Signed-off-by: Dominik <dl6er@dl6er.de>
Add ~80 new pytest API integration tests covering previously untested endpoints and HTTP methods: - DELETE 204/404 for groups, domains, clients, lists, config array items, network devices, and info messages - PUT create/replace round-trips for groups, domains, clients, lists - PUT error cases (missing body, invalid domain type) - Batch delete (POST :batchDelete) for groups, domains, clients, lists - DNS blocking toggle (POST disable + re-enable) - Auth session logout (DELETE /api/auth) and delete-by-ID - GET endpoints: clients, config, network gateway/routes, info host/sensors/metrics, query filters (domain, client_ip, upstream, blocklist pseudo-upstream), query suggestions, query cursor pagination, stats database with time ranges, history database with time ranges - Search with partial matching - TOTP credential suggestion (GET /api/auth/totp) - Config PATCH round-trip (bool and integer, change + verify + restore) - NTP server protocol-level test (UDP NTPv4 request/response) - Update test_final.bats known-warning patterns and config write counts Signed-off-by: Dominik <dl6er@dl6er.de>
When addr2line was absent from the runtime system, popen() succeeded but produced no output, leaving func as an empty string. The check `strcmp(func, "??")` did not match "", so the code fell through to the success branch and logged only bare frame numbers (#0, #1, ...) with no addresses or symbols. Fix the condition to also check for empty func, so the dladdr() and /proc/self/maps fallbacks execute correctly. Additionally, when any frame cannot be resolved, print the addr2line commands the user can run manually after installing binutils in case the tool was missing. Signed-off-by: Dominik <dl6er@dl6er.de>
Sync master back into development
Signed-off-by: Dominik <dl6er@dl6er.de>
Add new `GET /api/config/_properties` endpoint
Bumps the npm-dependencies group with 1 update: [openapi-examples-validator](https://github.com/codekie/openapi-examples-validator). Updates `openapi-examples-validator` from 6.0.3 to 7.0.0 - [Changelog](https://github.com/codekie/openapi-examples-validator/blob/main/CHANGELOG.md) - [Commits](codekie/openapi-examples-validator@v6.0.3...v7.0.0) --- updated-dependencies: - dependency-name: openapi-examples-validator dependency-version: 7.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: npm-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Dominik <dl6er@dl6er.de>
…in the latest base images Signed-off-by: Dominik <dl6er@dl6er.de>
Two API handlers stored direct pointers into the shared memory strings buffer (via cJSON_CreateStringReference), released the SHM lock, and then serialized the JSON - dereferencing those pointers after the lock was no longer held. Between unlock and serialization, another thread (DNS processing, GC, or another civetweb worker) can call realloc_shm() which invokes mremap(..., MREMAP_MAYMOVE), moving the entire strings buffer to a new virtual address and leaving dangling pointers in the JSON tree. This caused SIGSEGV crashes in civetweb-worker threads, always while the dashboard was open. Symptoms included NULL dereferences (unmapped old region) and faulting addresses containing domain string fragments (stale data at the former buffer location). Affected handlers: - api_history_clients(): client_name from getstr() stored as reference, lock released before JSON_SEND_OBJECT serialization - api_stats_recent_blocked(): domain from getDomainString() stored as reference, lock released before serialization Fix: replace JSON_REF_STR_IN_OBJECT/ARRAY with JSON_COPY_STR_TO_OBJECT/ ARRAY, which copy the string into cJSON-owned heap memory while the lock is still held. Also correct the misleading comment in history.c claiming shared memory strings are "idempotent". Closes #2786 Signed-off-by: Dominik <dl6er@dl6er.de>
When CAP_CHOWN is missing (e.g. in Docker with cap_drop), init_FTL_log() could fail to open the log file and set config.files.log.ftl.v.s = NULL. This NULL value was then persisted as an empty string when the TOML config was rewritten shortly after during readFTLconf(). The empty path remained even after restoring CAP_CHOWN, permanently breaking file logging. Use a separate static flag to track log file availability instead of clobbering the config value, so the configured path survives fopen failures and is correctly written back to pihole.toml. Fixes: #2827 Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
pi_hole_extra_headers is a global char[1024] buffer written by API handlers and read/cleared by civetweb's send_additional_header(), but civetweb runs up to 50 worker threads concurrently. When multiple threads handle authenticated requests in parallel, one thread can overwrite or clear another's header data, causing wrong Set-Cookie headers to be sent to wrong clients or cookies to be dropped entirely. Make pi_hole_extra_headers _Thread_local so each worker thread gets its own buffer. This is safe because civetweb handles each request entirely within a single thread. The auth_data session array has a similar race: concurrent threads read/modify sessions without synchronization. Add a pthread mutex protecting all auth_data access, using AUTOLOCK/AUTOUNLOCK macros based on __attribute__((cleanup)) for RAII-style auto-unlock — ensuring the mutex is released on every exit path, including hidden returns inside JSON macros that do `return 500` on allocation failure. Change api->session from a pointer into auth_data to an embedded struct copy so downstream API handlers read from a per-request snapshot rather than shared state. Use JSON_COPY_STR_TO_OBJECT for auth_data strings so the JSON tree owns its own copies after the lock is released. Fixes: #2824 Signed-off-by: Dominik <dl6er@dl6er.de>
Add test/api/test_s_auth_stress.py exercising the auth subsystem under concurrent load (12 threads, kept below max_sessions=16). Sessions are created sequentially (respecting FTL's 3-attempts/s rate limit with retry-on-429 backoff), then concurrency targets the thread-safety surfaces: - Parallel session validation (concurrent GET /api/auth with SIDs) - Concurrent logout with cross-session isolation checks (logout half, verify other half survives) - Mixed session check/logout operations from a shared session pool - Concurrent wrong-password rejection (verifies no SIGSEGV; runs last since it intentionally triggers rate-limiting) Every test cleans up its sessions to avoid exhausting max_sessions across test boundaries. Bump expected config rotation count in test_final.bats from 14 to 16 for the stress test's password set/remove cycle. Also add test/libs/ to .gitignore per review feedback — the directory is populated at test time by test/run.sh cloning bats-core. See alse: #2835 Signed-off-by: Dominik <dl6er@dl6er.de>
Agent-Logs-Url: https://github.com/pi-hole/FTL/sessions/f711f6f8-1f54-48c8-9d99-661803762c38 Co-authored-by: DL6ER <16748619+DL6ER@users.noreply.github.com>
find_device_by_hwaddr() returned DB_NODATA without querying the database when resolver.macNames was false. This caused all three callers (parse_neighbor_cache, add_FTL_clients_to_network_table, add_local_interfaces_to_network_table) to treat every device as new and attempt INSERT on each periodic run, hitting the UNIQUE constraint on network.hwaddr every ~60 seconds. The macNames setting controls name resolution from MAC addresses, not device tracking — the early return was conflating the two. The other two uses of the flag (getNameFromMAC and the gravity-db MAC lookup) correctly gate name resolution only and are unaffected. Closes #2844 Signed-off-by: Dominik <dl6er@dl6er.de>
Improve shutdown diagnostics to identify SIGTERM source
Resolve empty backtraces when addr2line is not installed
…. When multiple civetweb workers called /api/search/{domain} concurrently, each call to gravityDB_readTable() would overwrite the shared read_stmt via sqlite3_prepare_v2(), corrupting other threads'in-progress queries. This caused sqlite3_column_name() to dereference invalid memory -> SIGSEGV.
fix: replaced the shared static read_stmt with a caller-owned sqlite3_stmt* passed through the function signatures. Each API request now gets its own prepared statement, eliminating the race condition.
Signed-off-by: Dominik <dl6er@dl6er.de>
Two API handlers created cJSON string references to config struct strings (via cJSON_CreateStringReference / JSON_REF_STR_IN_OBJECT) that could be freed by a concurrent config change. When another civetweb worker handles a PATCH /api/config request, apply_config() replaces the global config struct and frees the old one - including all its dynamically allocated strings. Any in-flight GET request that still holds a reference into the old struct then dereferences freed memory during JSON serialization. Affected: - config.c:addJSONConfValue(): CONF_STRING/CONF_STRING_ALLOCATED values returned as cJSON_CreateStringReference(val->s) - 2fa.c:generateTOTP(): config.webserver.domain.v.s stored as JSON_REF_STR_IN_OBJECT Fix: use cJSON_CreateString / JSON_COPY_STR_TO_OBJECT to copy the string into cJSON-owned heap memory before the config can change. Signed-off-by: Dominik <dl6er@dl6er.de>
Tests: auto-detect upstream DNSSEC state for query-count assertions
Signed-off-by: Dominik <dl6er@dl6er.de>
Bumps the npm-dependencies group with 1 update: [openapi-examples-validator](https://github.com/codekie/openapi-examples-validator). Updates `openapi-examples-validator` from 7.0.0 to 7.1.0 - [Changelog](https://github.com/codekie/openapi-examples-validator/blob/main/CHANGELOG.md) - [Commits](codekie/openapi-examples-validator@v7.0.0...v7.1.0) --- updated-dependencies: - dependency-name: openapi-examples-validator dependency-version: 7.1.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
…pdates Bumps the github_action-dependencies group with 3 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact), [softprops/action-gh-release](https://github.com/softprops/action-gh-release) and [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request). Updates `actions/upload-artifact` from 7.0.0 to 7.0.1 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@bbbca2d...043fb46) Updates `softprops/action-gh-release` from 2.6.1 to 3.0.0 - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](softprops/action-gh-release@153bb8e...b430933) Updates `peter-evans/create-pull-request` from 8.1.0 to 8.1.1 - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](peter-evans/create-pull-request@c0f553f...5f6978f) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github_action-dependencies - dependency-name: softprops/action-gh-release dependency-version: 3.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github_action-dependencies - dependency-name: peter-evans/create-pull-request dependency-version: 8.1.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github_action-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
…opment-github_action-dependencies-3b7f5c993f Bump the github_action-dependencies group across 1 directory with 3 updates
…ment-npm-dependencies-201d9e89b8 Bump openapi-examples-validator from 7.0.0 to 7.1.0 in the npm-dependencies group across 1 directory
Improve thread-safety for concurrent API requests
Don't skip device lookup when resolver.macNames is disabled
Compiling Pi-hole FTL w/o optimization (release type "DEBUG") results in the following error during linking: ''' x86_64-buildroot-linux-uclibc/bin/ld: tools/CMakeFiles/tools.dir/dhcp-discover.c.o: in function `create_dhcp_socket': /home/data/buildroot.experimental/build/pihole-ftl-6.6/src/tools/dhcp-discover.c:88:(.text+0xac): undefined reference to `start_lock' x86_64-buildroot-linux-uclibc/bin/ld: /home/data/buildroot.experimental/build/pihole-ftl-6.6/src/tools/dhcp-discover.c:90:(.text+0xe9): undefined reference to `end_lock' [...] x86_64-buildroot-linux-uclibc/bin/ld: tools/CMakeFiles/tools.dir/dhcpv6-discover.c.o: in function `recv_adv': /home/data/buildroot.experimental/build/pihole-ftl-6.6/src/tools/dhcpv6-discover.c:706:(.text+0x137f): undefined reference to `start_lock' x86_64-buildroot-linux-uclibc/bin/ld: /home/data/buildroot.experimental/build/pihole-ftl-6.6/src/tools/dhcpv6-discover.c:709:(.text+0x13b1): undefined reference to `end_lock' [...] ''' When generating code without optimization, gcc ignores the inline directive. Code for this function is generated once, but not marked as global (because the extern keyword is missing), which results in the observed linker error for all other compilation units. Change the function definition to static inline, which will force the compiler to include a static copy of the function in every compilation unit, if the function is not inlined. Signed-off-by: Andreas Ziegler <15275159+aeolio@users.noreply.github.com>
Fix linker error when compiling w/o optimization
Clarify `dns.blockESNI` wording
Bumps the github_action-dependencies group with 1 update in the / directory: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 4.35.1 to 4.35.2 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@c10b806...95e58e9) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github_action-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
…opment-github_action-dependencies-f3e34333ea Bump github/codeql-action from 4.35.1 to 4.35.2 in the github_action-dependencies group across 1 directory
…failure Preserve log file path config when fopen fails
The PID file path was previously user-configurable via files.pid in
pihole.toml. Service hook scripts executed as root read this value
without validation and used it in privileged file operations, enabling
local privilege escalation by a pihole user with direct write access
to pihole.toml.
Remove files.pid from the config system entirely and replace all
usages with the compile-time constant FTL_PID_FILE ("/run/pihole-FTL.pid")
defined in config.h. The PID file path has no good reason to be
user-configurable.
See: GHSA-6w8x-p785-6pm4
Signed-off-by: yubiuser <github@yubiuser.dev>
Co-authored-by: Adam Warner <me@adamwarner.co.uk> Signed-off-by: yubiuser <github@yubiuser.dev>
Hardcode PID file location to /run/pihole-FTL.pid
Update DNS interface validation to prevent newlines in `dns.interface`
dschaper
approved these changes
Apr 24, 2026
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.
What's Changed
GET /api/config/_propertiesendpoint by @DL6ER in Add newGET /api/config/_propertiesendpoint #2356dns.blockESNIwording by @darkexplosiveqwx in Clarifydns.blockESNIwording #2784New Contributors
dns.blockESNIwording #2784Full Changelog: v6.6...v6.6.1