mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-28 09:32:51 +08:00
676 lines
28 KiB
Markdown
676 lines
28 KiB
Markdown
# SafeShield
|
|
|
|
[](https://github.com/Junatum/safeshield/actions/workflows/lint-shell.yml)
|
|

|
|

|
|
|
|
SafeShield is a lightweight DNS protection engine for OpenWrt and the core network-protection component used by **SmartSafeHub**. It blocks advertising, tracking, and phishing domains at the router through dnsmasq, so connected devices can benefit without installing a separate client application.
|
|
|
|
For most users, the recommended way to run SafeShield is through the **SmartSafeHub firmware and Web UI**. The standalone `luci-app-safeshield` package remains available for users who want a dedicated SafeShield-only LuCI interface, but current product UI development is focused on [`luci-app-smartsafehub`](https://github.com/Junatum/luci-app-smartsafehub).
|
|
|
|
- SmartSafeHub: https://www.smartsafehub.com/
|
|
- Firmware downloads: https://www.smartsafehub.com/firmware/
|
|
- Installation guide: https://www.smartsafehub.com/docs/installation/
|
|
|
|
## Features
|
|
|
|
- DNS-based blocking of ads, tracking, and phishing domains
|
|
- Fully compatible with **dnsmasq**
|
|
- Lightweight design suitable for **low-resource OpenWrt devices**
|
|
- Integrated management through the actively developed **SmartSafeHub Web UI**
|
|
- Optional standalone management through `luci-app-safeshield`
|
|
- Automatic blocklist download and refresh
|
|
- Multiple Hub artifact sources with independent block/allow actions and checksum verification
|
|
- Support for **custom allowlist and blocklist**
|
|
- Modular shell-based architecture for easy customization and maintenance
|
|
- Lean runtime surface with regression coverage guarding retired/unused shell helpers from returning
|
|
|
|
## Package versions
|
|
|
|
The badges below show the versions currently published to each repository channel.
|
|
|
|
| Package | Stable | Beta |
|
|
| --- | --- | --- |
|
|
| SafeShield | [](https://repo.smartsafehub.com/stable/versions.json) | [](https://repo.smartsafehub.com/beta/versions.json) |
|
|
| SmartSafeHub UI | [](https://repo.smartsafehub.com/stable/versions.json) | [](https://repo.smartsafehub.com/beta/versions.json) |
|
|
| Standalone SafeShield UI | [](https://repo.smartsafehub.com/stable/versions.json) | [](https://repo.smartsafehub.com/beta/versions.json) |
|
|
|
|
`luci-app-smartsafehub` is the primary user-facing UI and the focus of current product development. `luci-app-safeshield` is retained as an optional standalone SafeShield interface and is not the primary target for new product UI work.
|
|
|
|
## How it works
|
|
|
|
SafeShield provides DNS-level protection by automatically applying the
|
|
appropriate **dnsmasq**-compatible blocklist for each device.
|
|
|
|
It helps block ads, trackers, and phishing domains with scheduled updates
|
|
and optional local allow/block overrides.
|
|
|
|
### Hub artifact source contract
|
|
|
|
SafeShield accepts both the legacy single-artifact response and the preferred
|
|
multi-source response from the SmartSafeHub Hub API. Existing deployments can
|
|
continue returning `artifact.download_url`.
|
|
|
|
For multiple independently licensed or managed datasets, the Hub should return
|
|
`artifact.sources`:
|
|
|
|
```json
|
|
{
|
|
"artifact": {
|
|
"tier": "pro",
|
|
"version": "20260830T120000Z",
|
|
"sources": [
|
|
{
|
|
"id": "hagezi-pro",
|
|
"action": "block",
|
|
"download_url": "https://example.invalid/hagezi-pro.txt",
|
|
"sha256": "..."
|
|
},
|
|
{
|
|
"id": "smartsafehub-pro",
|
|
"action": "block",
|
|
"download_url": "https://example.invalid/smartsafehub-pro.txt",
|
|
"sha256": "..."
|
|
},
|
|
{
|
|
"id": "smartsafehub-allow",
|
|
"action": "allow",
|
|
"download_url": "https://example.invalid/smartsafehub-allow.txt",
|
|
"sha256": "..."
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
Each source is downloaded, checksum-verified, normalized, and retained as an
|
|
independent runtime cache file. SafeShield merges all block and allow sources
|
|
only on the router when generating the active dnsmasq configuration. This keeps
|
|
the Hub artifacts separate while preserving override precedence as `local allow`
|
|
> `local block` > `Hub allow` > `Hub block`.
|
|
|
|
SafeShield also sends a canonical `device.device_code` with Hub resolve requests.
|
|
SmartSafeHub firmware is authoritative when `/usr/share/smartsafehub/firmware.json`
|
|
contains a valid `device_code`. Standalone SafeShield installations fall back only
|
|
to exact OpenWrt board-name mappings for officially recognized hardware; unknown
|
|
hardware sends an empty `device_code` instead of guessing from vendor, model,
|
|
architecture, or memory. `device.device_code_source` reports
|
|
`smartsafehub_firmware`, `board`, or `unknown` for diagnostics. The same values
|
|
are exposed through `ubus call safeshield status`.
|
|
|
|
## System Requirements
|
|
|
|
SafeShield requires the following environment:
|
|
|
|
- **OpenWrt 25.12 or later**
|
|
- **dnsmasq 2.93 or later** (the SafeShield dnsmasq extension enables cumulative statistics; stock dnsmasq falls back to standard block rules with statistics disabled)
|
|
- At least **16 MB free flash storage**
|
|
- Internet access for downloading blocklists
|
|
|
|
## Installation
|
|
|
|
### Recommended: SmartSafeHub firmware
|
|
|
|
For supported hardware, the recommended installation path is a complete **SmartSafeHub OpenWrt firmware image**. This gives users the integrated SmartSafeHub Web UI together with SafeShield and the firmware-specific integration expected by the product.
|
|
|
|
Download firmware without signing in:
|
|
|
|
https://www.smartsafehub.com/firmware/
|
|
|
|
The firmware page currently provides releases for supported devices including:
|
|
|
|
- **ipTIME AX3000SM**
|
|
- **ipTIME AX3000SE**
|
|
- **ipTIME A3004T**
|
|
- **GL.iNet GL-MT300N-V2**
|
|
- **Xiaomi Router AX3000T (International version)**
|
|
|
|
Choose the image type that matches your installation method:
|
|
|
|
- **Initramfs** — for temporarily booting SmartSafeHub/OpenWrt in RAM during an initial installation or recovery process.
|
|
- **Factory** — for installing SmartSafeHub/OpenWrt from the vendor firmware or through a device-specific recovery process.
|
|
- **Sysupgrade** — for upgrading a router that already runs SmartSafeHub/OpenWrt.
|
|
|
|
Not every image type is available for every device. Follow the installation guide for your router and use only the image type provided for that installation method.
|
|
Always verify the exact hardware model and follow the device-specific installation guide before flashing. Installing an image for a different model can prevent the router from booting.
|
|
|
|
See the installation guide for the current procedure:
|
|
|
|
https://www.smartsafehub.com/docs/installation/
|
|
|
|
### Advanced: install SafeShield packages on OpenWrt
|
|
|
|
SafeShield is also published through the SmartSafeHub OpenWrt package repository for advanced users, development environments, and compatible custom OpenWrt installations. OpenWrt 25.12 uses the `apk` package manager.
|
|
|
|
Add the SmartSafeHub signing key and Stable repository, replacing `<architecture>` with the target package architecture such as `aarch64_cortex-a53`, `mipsel_24kc`, or `x86_64`:
|
|
|
|
```sh
|
|
mkdir -p /etc/apk/keys /etc/apk/repositories.d
|
|
|
|
uclient-fetch -O /etc/apk/keys/smartsafehub.pem \
|
|
https://repo.smartsafehub.com/stable/packages/<architecture>/smartsafehub/smartsafehub.pem
|
|
|
|
printf '%s\n' \
|
|
'https://repo.smartsafehub.com/stable/packages/<architecture>/smartsafehub/packages.adb' \
|
|
> /etc/apk/repositories.d/smartsafehub.list
|
|
|
|
apk update
|
|
```
|
|
|
|
Install SafeShield with the primary SmartSafeHub UI:
|
|
|
|
```sh
|
|
apk add safeshield luci-app-smartsafehub
|
|
```
|
|
|
|
If you specifically want the older standalone SafeShield-only LuCI interface, it remains available as an optional package:
|
|
|
|
```sh
|
|
apk add luci-app-safeshield
|
|
```
|
|
|
|
The standalone UI is not the primary target for new product UI development. New dashboard, device-management, firmware-update, and broader SmartSafeHub features are developed in `luci-app-smartsafehub`.
|
|
|
|
After installation, restart the relevant services if they are not already restarted by the package lifecycle:
|
|
|
|
```sh
|
|
/etc/init.d/rpcd restart
|
|
/etc/init.d/uhttpd restart
|
|
/etc/init.d/safeshield restart
|
|
```
|
|
|
|
Verify SafeShield:
|
|
|
|
```sh
|
|
ubus call safeshield status
|
|
/etc/init.d/safeshield status
|
|
logread | grep -i safeshield
|
|
```
|
|
|
|
## Build from source
|
|
|
|
SafeShield is built as an OpenWrt package. Build it inside an OpenWrt buildroot or SDK that matches your target device and OpenWrt version.
|
|
|
|
### Build with OpenWrt buildroot
|
|
|
|
Clone OpenWrt and prepare feeds:
|
|
|
|
```sh
|
|
git clone -b production https://github.com/Junatum/openwrt.git
|
|
cd openwrt
|
|
|
|
./scripts/feeds update -a
|
|
./scripts/feeds install -a
|
|
```
|
|
|
|
Add SafeShield under the OpenWrt `package/` directory:
|
|
|
|
```sh
|
|
git clone https://github.com/Junatum/safeshield package/safeshield
|
|
```
|
|
|
|
If you also want the current SmartSafeHub product UI, add
|
|
`luci-app-smartsafehub`:
|
|
|
|
```sh
|
|
git clone https://github.com/Junatum/luci-app-smartsafehub package/luci-app-smartsafehub
|
|
```
|
|
|
|
The standalone `luci-app-safeshield` repository is still available, but it is not the primary target for new UI development. Clone it only when you intentionally need the dedicated SafeShield-only interface.
|
|
|
|
Select your target device:
|
|
|
|
```sh
|
|
make menuconfig
|
|
```
|
|
|
|
For example, for MediaTek Filogic devices such as ipTIME AX3000SM:
|
|
|
|
```text
|
|
Target System ---> MediaTek Ralink ARM
|
|
Subtarget ---> Filogic 8x0
|
|
Target Profile ---> your device profile
|
|
```
|
|
|
|
Enable SafeShield as a module:
|
|
|
|
```sh
|
|
cat >> .config <<'EOF'
|
|
CONFIG_PACKAGE_safeshield=m
|
|
CONFIG_PACKAGE_luci-app-smartsafehub=m
|
|
EOF
|
|
|
|
make defconfig
|
|
```
|
|
|
|
Build the packages:
|
|
|
|
```sh
|
|
make package/safeshield/clean V=s
|
|
make package/safeshield/compile V=s
|
|
|
|
make package/luci-app-smartsafehub/clean V=s
|
|
make package/luci-app-smartsafehub/compile V=s
|
|
```
|
|
|
|
Find the generated packages:
|
|
|
|
```sh
|
|
find bin -type f \( \
|
|
-name 'safeshield*.apk' \
|
|
-o -name 'luci-app-smartsafehub*.apk' \
|
|
\) -print
|
|
```
|
|
|
|
Depending on the OpenWrt version and package location, the output can appear
|
|
under one of these paths:
|
|
|
|
```text
|
|
bin/targets/<target>/<subtarget>/packages/
|
|
bin/packages/<architecture>/<feed-name>/
|
|
```
|
|
|
|
For example, a MediaTek Filogic `apk` build may generate packages under:
|
|
|
|
```text
|
|
bin/targets/mediatek/filogic/packages/
|
|
```
|
|
|
|
### Build with OpenWrt SDK
|
|
|
|
You can also build SafeShield with the OpenWrt SDK for your target. This is
|
|
faster when you only need package artifacts.
|
|
|
|
```sh
|
|
tar xf openwrt-sdk-*.tar.*
|
|
cd openwrt-sdk-*
|
|
|
|
./scripts/feeds update -a
|
|
./scripts/feeds install -a
|
|
|
|
git clone https://github.com/Junatum/safeshield package/safeshield
|
|
git clone https://github.com/Junatum/luci-app-smartsafehub package/luci-app-smartsafehub
|
|
|
|
cat >> .config <<'EOF'
|
|
CONFIG_PACKAGE_safeshield=m
|
|
CONFIG_PACKAGE_luci-app-smartsafehub=m
|
|
EOF
|
|
|
|
make defconfig
|
|
|
|
make package/safeshield/compile V=s
|
|
make package/luci-app-smartsafehub/compile V=s
|
|
```
|
|
|
|
### Install local build artifacts
|
|
|
|
For OpenWrt `apk` based builds, copy the generated artifacts to the
|
|
device:
|
|
|
|
```sh
|
|
find bin -type f \( -name 'safeshield-*.apk' -o -name 'luci-app-smartsafehub-*.apk' \) -print
|
|
|
|
scp path/to/safeshield-*.apk root@192.168.1.1:/tmp/
|
|
scp path/to/luci-app-smartsafehub-*.apk root@192.168.1.1:/tmp/
|
|
```
|
|
|
|
Install them on the device:
|
|
|
|
```sh
|
|
ssh root@192.168.1.1
|
|
|
|
apk add --allow-untrusted /tmp/safeshield-*.apk
|
|
apk add --allow-untrusted /tmp/luci-app-smartsafehub-*.apk
|
|
|
|
/etc/init.d/rpcd restart
|
|
/etc/init.d/uhttpd restart
|
|
/etc/init.d/safeshield restart
|
|
```
|
|
|
|
Verify the installation:
|
|
|
|
```sh
|
|
ubus call safeshield status
|
|
/etc/init.d/safeshield status
|
|
logread | grep -i safeshield
|
|
```
|
|
|
|
## Development linting
|
|
|
|
SafeShield uses the same shell lint entrypoint locally and in GitHub Actions:
|
|
|
|
```sh
|
|
sh scripts/lint.sh
|
|
```
|
|
|
|
The lint script runs `shfmt -d -ci`, ShellCheck, and `sh -n` against tracked shell files. Install `shfmt` and `shellcheck` on the development machine before running it.
|
|
ShellSpec support helpers are linted by the same command; mocks consumed by dynamically sourced production functions are exported explicitly so the test harness remains ShellCheck-clean without changing runtime behavior.
|
|
|
|
Run the regression suite separately when changing runtime, statistics, HTTP transport, or rpcd behavior:
|
|
|
|
```sh
|
|
REQUIRE_UCODE=1 shellspec
|
|
```
|
|
|
|
The suite includes full refresh/local-rule rollback state machines, refresh lock contention, init lifecycle transitions, artifact retry/size/SHA-256 integrity checks, refreshd scheduling, OpenWrt `uclient-fetch` authenticated POST handling, statistics uploader recovery/state transitions, artifact resolve identity payloads, and direct rpcd runtime/status-store validation paths.
|
|
The refresh-lock regression uses a test-only portable lock shim, so the suite does not require a host `flock(1)` binary on macOS; production SafeShield continues to use OpenWrt's `flock`.
|
|
|
|
To enable the repository pre-commit hook, install `pre-commit` and register the hook once:
|
|
|
|
```sh
|
|
pre-commit install
|
|
```
|
|
|
|
After that, `git commit` runs the shell lint automatically. You can also check the whole repository manually:
|
|
|
|
```sh
|
|
pre-commit run --all-files
|
|
```
|
|
|
|
## Internal rpcd ucode layout
|
|
|
|
SafeShield keeps the rpcd registration entrypoint intentionally small and loads feature modules from `/usr/share/rpcd/ucode/safeshield/`:
|
|
|
|
```text
|
|
/usr/share/rpcd/ucode/safeshield.uc
|
|
/usr/share/rpcd/ucode/safeshield/
|
|
├── core.uc
|
|
├── runtime.uc
|
|
├── status.uc
|
|
├── config.uc
|
|
├── refresh.uc
|
|
├── rules.uc
|
|
├── license.uc
|
|
└── statistics.uc
|
|
```
|
|
|
|
The entrypoint prepends `/usr/share/rpcd/ucode/safeshield/*.uc` to ucode's `REQUIRE_SEARCH_PATH`, so the private RPC modules stay colocated with the rpcd plugin instead of using the global `/usr/share/ucode` tree.
|
|
|
|
The public ubus contract remains exposed through the single `safeshield` object; the module split is an internal implementation detail.
|
|
|
|
## SafeShield ubus API
|
|
|
|
The `safeshield` package owns the public management API used by LuCI and
|
|
SmartSafeHub clients. The API keeps UCI mutations, service lifecycle,
|
|
refresh scheduling and local rule files behind one ubus object.
|
|
|
|
Available methods:
|
|
|
|
```text
|
|
safeshield.status
|
|
safeshield.config
|
|
safeshield.statistics
|
|
safeshield.config_update
|
|
safeshield.set_enabled
|
|
safeshield.refresh
|
|
safeshield.rules_list
|
|
safeshield.rule_add
|
|
safeshield.rule_delete
|
|
safeshield.license_get
|
|
safeshield.license_update
|
|
```
|
|
|
|
Read the current public configuration:
|
|
|
|
```sh
|
|
ubus call safeshield config
|
|
```
|
|
|
|
Read lightweight local DNS statistics:
|
|
|
|
```sh
|
|
ubus call safeshield statistics
|
|
/etc/init.d/safeshield statistics
|
|
```
|
|
|
|
Statistics are collected from dnsmasq cumulative SafeShield UBus counters. Raw queried domains
|
|
are never written to the statistics state. Loopback (`127.0.0.0/8` and `::1`)
|
|
queries are excluded so SafeShield's own DNS health checks do not inflate user
|
|
query or blocked counters. In addition to global hourly query/block counters,
|
|
SafeShield keeps per-device totals and per-device hourly buckets locally. DHCP
|
|
clients are identified by MAC address using the dnsmasq lease file, with the
|
|
current IP and hostname included for the local UI. The collector also retains a
|
|
non-MAC-derived DHCP client-id when one is available. IPv4 clients can be
|
|
resolved through the kernel ARP table, while IPv6 clients combine the kernel NDP
|
|
neighbor cache (`ip -6 neigh show`) with odhcpd `ipv6leases` DUID metadata. A
|
|
stable DHCP client-id or DHCPv6 DUID therefore moves retained history from an
|
|
older private/randomized MAC to the currently observed MAC instead of exposing
|
|
both MACs as separate devices. Identified clients include these stable identifiers
|
|
in the Hub statistics payload as `identities[]` entries (`dhcp_client_id`,
|
|
`dhcpv6_duid`, and `mac`) so the backend can preserve one canonical network
|
|
client across later MAC rotations.
|
|
|
|
For older retained data that predates those strong identifiers, SafeShield uses
|
|
a conservative hostname fallback only when exactly one active MAC advertises a
|
|
non-generic hostname and a matching historical MAC is no longer active. Generic
|
|
names such as `iPhone`, `Android`, `phone`, or `laptop` are never merged by
|
|
hostname alone. Unresolved IP-only identities remain separate internally for a
|
|
short reconciliation window, but the public statistics JSON serializes them as
|
|
one `unknown` device so IPv6 privacy addresses do not create a device record per
|
|
address. IP-only entries with no stable DHCP identity are compacted into that
|
|
local unknown bucket after six hours. Device statistics remain capped at 128
|
|
active retained identities to bound memory use on low-end routers.
|
|
|
|
Each retained statistics dataset has a stable `generation_id`. `started_at` is
|
|
the creation time of that retained dataset and is restored together with the
|
|
generation when the collector restarts. `session_started_at` is the start time
|
|
of the current collector process and therefore changes on every collector
|
|
restart. `snapshot_seq` is monotonically increasing within the generation and
|
|
is the ordering/idempotency key for Hub ingestion; wall-clock `updated_at` is
|
|
kept only as event metadata. Persistence-enabled devices reserve sequence
|
|
ranges ahead in `/etc/safeshield/statistics-sequence.tsv`, so a reboot can skip
|
|
unconsumed values instead of reusing a sequence already observed by Hub. This
|
|
distinction lets cloud ingestion reject duplicate or out-of-order snapshots
|
|
without treating a process restart as a new dataset.
|
|
|
|
When statistics are enabled, a separate uploader can synchronize the aggregate
|
|
statistics with the SmartSafeHub Hub at `/api/v1/statistics`. Cloud upload is an
|
|
entitlement-controlled feature: the Hub currently grants it to eligible PRO and
|
|
ULTIMATE licenses in ACTIVE or TRIAL status and returns `statistics: null` for
|
|
free, unlicensed, expired, or revoked devices. SafeShield treats that Hub response as the
|
|
authoritative entitlement, disables network upload when it is absent, and keeps
|
|
collecting local statistics normally. A device with no configured license key is
|
|
blocked locally without making a statistics credential request.
|
|
|
|
For an entitled device, the uploader gets a device-scoped bearer credential from
|
|
the existing `/api/v1/licenses/resolve` response and keeps that credential only
|
|
under `/tmp/safeshield/statistics/`; it is never written to flash or included in
|
|
status output. Routine uploads run every 30 minutes and contain a consistent
|
|
two-hour projection of the local hourly data. A full retained snapshot is sent
|
|
on initial synchronization, after a failed upload has recovered, and periodically
|
|
(approximately every 12 hours) to reconcile any missed window.
|
|
|
|
The uploader preserves the exact pending JSON across network retries. If the Hub
|
|
committed a request but the HTTP acknowledgement was lost, retrying the same
|
|
`generation_id` and `snapshot_seq` is therefore idempotent. An HTTP 401 clears
|
|
the cached credential and resolves the license again. If the refreshed response
|
|
no longer grants statistics upload, SafeShield discards the cloud pending payload
|
|
and stops statistics POST requests. While a license key remains configured, a
|
|
denied entitlement is rechecked at most once every 12 hours so a server-side
|
|
reactivation can recover without waiting for the normal artifact refresh cycle.
|
|
Changing or clearing the key through `license_update` immediately clears cached
|
|
entitlement, credentials, pending payloads, and upload progress; the next granted
|
|
entitlement therefore resumes with a full reconciliation. Local collection is
|
|
independent of upload entitlement and upload success, so a free license, WAN
|
|
outage, or Hub outage never interrupts on-router statistics.
|
|
|
|
The collector implementation is split into focused AWK modules under
|
|
`/usr/lib/safeshield/statistics/` for common helpers, recovery, client identity,
|
|
aggregation, persistence, output, and the collector lifecycle. `safeshield-statsd`
|
|
loads the modules together as one AWK program, preserving the single collector
|
|
process used on resource-constrained routers.
|
|
|
|
Hot statistics live under `/tmp/safeshield/statistics/` and are retained for up
|
|
to 168 hourly buckets. Supported profiles additionally persist aggregate state
|
|
with a compact base snapshot plus hourly journal, while constrained profiles
|
|
may stay tmpfs-only. The collector no longer follows dnsmasq query logs. It
|
|
polls dnsmasq's cumulative SafeShield UBus counters at the effective snapshot
|
|
interval and calculates deltas in RAM. `instance_id` identifies the current
|
|
dnsmasq counter epoch so a dnsmasq restart can be distinguished from a normal
|
|
counter increment.
|
|
|
|
The default statistics settings are:
|
|
|
|
```text
|
|
statistics_enabled=1
|
|
statistics_snapshot_interval_s=60
|
|
statistics_retention_hours=168
|
|
```
|
|
|
|
When statistics are enabled, SafeShield calls `ubus call dnsmasq
|
|
safeshield_stats` through a small ucode poll helper. The helper accepts only
|
|
schema version 1 snapshots with a valid `instance_id`, cumulative totals, and
|
|
client array; malformed or incompatible replies are treated as poll failures
|
|
instead of silently becoming zero counters. No `log-queries` or `log-async`
|
|
setting is required. Existing pre-0.3.20-r2 statistics logging configuration is
|
|
removed once during upgrade. SafeShield persists aggregate counters only; raw
|
|
DNS query names are never collected.
|
|
|
|
`statistics_enabled` is the configured user preference. Runtime availability is
|
|
reported separately through `effective_enabled` and `collector_running`. If the
|
|
SafeShield dnsmasq extension is unavailable, SafeShield keeps the configured
|
|
preference intact, stops only the statistics runtime, and automatically resumes
|
|
collection after a compatible dnsmasq becomes available. Disabling Statistics
|
|
or SafeShield creates a rebaseline marker so the first snapshot after re-enable
|
|
is used only as a new cumulative-counter baseline; traffic from the disabled
|
|
period is not backfilled.
|
|
|
|
When the SafeShield dnsmasq extension is available, SafeShield emits block rules
|
|
as `safeshield-block=/domain/`. Only these SafeShield-owned rules increment the
|
|
dnsmasq blocked counter. If the extension is unavailable, SafeShield defensively
|
|
uses standard `address=/domain/#` rules so DNS protection remains available
|
|
without installing an unsupported directive. The statistics source also exposes
|
|
dnsmasq's `instance_id`, `transport_scope`, client-table capacity,
|
|
tracked-client count, `untracked_queries`, and `untracked_blocked`. The OpenWrt 25.12 dnsmasq integration reports `transport_scope=udp+tcp`, so both UDP and TCP DNS requests are included in the cumulative SafeShield counters.
|
|
|
|
Update writable configuration values. `enabled` and `license_key` are
|
|
intentionally excluded and have dedicated methods:
|
|
|
|
```sh
|
|
ubus call safeshield config_update '{
|
|
"values": {
|
|
"refresh_interval_s": 28800,
|
|
"refresh_on_boot": true,
|
|
"require_wan": true,
|
|
"apply_local_overrides": true,
|
|
"statistics_enabled": true,
|
|
"statistics_snapshot_interval_s": 60,
|
|
"statistics_retention_hours": 168
|
|
}
|
|
}'
|
|
```
|
|
|
|
Enable or disable SafeShield. This method commits the desired UCI value and
|
|
requests the full SafeShield enable/disable lifecycle. Runtime convergence is
|
|
asynchronous under procd, so a successful response reports the accepted target
|
|
state instead of returning a potentially stale status snapshot:
|
|
|
|
```sh
|
|
ubus call safeshield set_enabled '{"enabled":true}'
|
|
```
|
|
|
|
A successful response has this shape:
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"changed": true,
|
|
"accepted": true,
|
|
"target_enabled": true,
|
|
"reconciled": false
|
|
}
|
|
```
|
|
|
|
Clients should poll `safeshield.status` until runtime state converges. For an
|
|
enable request, wait for `enabled=true`, `active=true` and
|
|
`runtime.refreshd_running=true`. For a disable request, wait for
|
|
`enabled=false`, `active=false` and `runtime.refreshd_running=false`.
|
|
|
|
Request an immediate refresh:
|
|
|
|
```sh
|
|
ubus call safeshield refresh
|
|
```
|
|
|
|
List local allow/block overrides:
|
|
|
|
```sh
|
|
ubus call safeshield rules_list
|
|
ubus call safeshield rules_list '{"action":"allow"}'
|
|
ubus call safeshield rules_list '{"action":"block"}'
|
|
```
|
|
|
|
Add or delete a local rule. Rule changes request an asynchronous refresh by
|
|
default so the active dnsmasq blocklist is rebuilt. For bulk edits, pass
|
|
`"refresh":false` on intermediate mutations and invoke `safeshield.refresh`
|
|
after the last mutation.
|
|
|
|
```sh
|
|
ubus call safeshield rule_add '{
|
|
"action": "block",
|
|
"domain": "example.com"
|
|
}'
|
|
|
|
ubus call safeshield rule_delete '{
|
|
"action": "block",
|
|
"domain": "example.com"
|
|
}'
|
|
```
|
|
|
|
### Local rule fast apply
|
|
|
|
`rule_add` and `rule_delete` keep the public SafeShield API unchanged, but their automatic apply path no longer performs a full Hub artifact refresh. SafeShield retains the normalized Hub domains in `/tmp/safeshield/api.block.txt`, rebuilds only the local allow/block inputs, merges them atomically, restarts dnsmasq, and verifies runtime DNS. The local apply worker shares the normal refresh lock, so a rule edit made during a full refresh waits for that refresh and then reapplies the newest local state. If the cached Hub artifact is missing, SafeShield falls back to one normal full refresh.
|
|
|
|
Read the raw license key only when an authenticated management client explicitly
|
|
requests it. Normal `status`, `config` and `license_update` responses continue to
|
|
return only masked license metadata.
|
|
|
|
```sh
|
|
ubus call safeshield license_get
|
|
```
|
|
|
|
Update or clear the license key. Passing an empty string removes the configured
|
|
UCI option and immediately requests a SafeShield refresh so the device is resolved
|
|
as unlicensed/free again. SafeShield intentionally treats an absent `license_key`
|
|
option as the canonical unlicensed state; all runtime readers fall back to an empty
|
|
key when the option is not present.
|
|
|
|
```sh
|
|
ubus call safeshield license_update '{"license_key":"YOUR-LICENSE-KEY"}'
|
|
ubus call safeshield license_update '{"license_key":""}'
|
|
```
|
|
|
|
The package also installs an rpcd ACL named `safeshield`. Read access covers
|
|
`status`, `config` and `rules_list`; sensitive license access and mutating
|
|
methods are declared as write access.
|
|
|
|
## Contributors
|
|
|
|
<a href="https://github.com/Junatum/safeshield/graphs/contributors">
|
|
<img src="https://contrib.rocks/image?repo=Junatum/safeshield" alt="Contributors">
|
|
</a>
|
|
|
|
## Support
|
|
|
|
For product information, supported devices, installation guidance, and firmware downloads, visit:
|
|
|
|
https://www.smartsafehub.com/
|
|
|
|
For SafeShield source-code issues or feature requests, open an issue on GitHub:
|
|
|
|
https://github.com/Junatum/safeshield/issues
|
|
|
|
Bug reports and pull requests are welcome.
|
|
|
|
## Third-party blocklist data
|
|
|
|
SafeShield may install SmartSafeHub artifacts derived from third-party DNS
|
|
blocklists, including [HaGeZi's DNS Blocklists](https://github.com/hagezi/dns-blocklists).
|
|
HaGeZi-derived artifacts remain subject to GNU GPL v3.0. See
|
|
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) for the upstream project,
|
|
license, source inventory, and installed notice location.
|
|
|
|
## License
|
|
|
|
SafeShield is under the [GNU Public License version 3](https://www.gnu.org/licenses/gpl-3.0.html)
|