lanfence 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lanfence-0.1.0/CHANGELOG.md +67 -0
- lanfence-0.1.0/CONTRIBUTING.md +75 -0
- lanfence-0.1.0/DISTRIBUTING.md +62 -0
- lanfence-0.1.0/LICENSE +21 -0
- lanfence-0.1.0/MANIFEST.in +4 -0
- lanfence-0.1.0/PKG-INFO +272 -0
- lanfence-0.1.0/README.md +239 -0
- lanfence-0.1.0/lanfence/__init__.py +6 -0
- lanfence-0.1.0/lanfence/alerts.py +134 -0
- lanfence-0.1.0/lanfence/allowlist.py +101 -0
- lanfence-0.1.0/lanfence/cli.py +394 -0
- lanfence-0.1.0/lanfence/config.py +130 -0
- lanfence-0.1.0/lanfence/data/oui_vendors.txt +148 -0
- lanfence-0.1.0/lanfence/data/rogue_signatures.yaml +106 -0
- lanfence-0.1.0/lanfence/db.py +182 -0
- lanfence-0.1.0/lanfence/engine.py +202 -0
- lanfence-0.1.0/lanfence/fingerprint.py +164 -0
- lanfence-0.1.0/lanfence/fsutil.py +45 -0
- lanfence-0.1.0/lanfence/logging_config.py +48 -0
- lanfence-0.1.0/lanfence/models.py +128 -0
- lanfence-0.1.0/lanfence/netutil.py +49 -0
- lanfence-0.1.0/lanfence/report.py +189 -0
- lanfence-0.1.0/lanfence/sanitize.py +48 -0
- lanfence-0.1.0/lanfence/scanner.py +243 -0
- lanfence-0.1.0/lanfence/vendor.py +52 -0
- lanfence-0.1.0/lanfence.egg-info/PKG-INFO +272 -0
- lanfence-0.1.0/lanfence.egg-info/SOURCES.txt +41 -0
- lanfence-0.1.0/lanfence.egg-info/dependency_links.txt +1 -0
- lanfence-0.1.0/lanfence.egg-info/entry_points.txt +2 -0
- lanfence-0.1.0/lanfence.egg-info/requires.txt +10 -0
- lanfence-0.1.0/lanfence.egg-info/top_level.txt +1 -0
- lanfence-0.1.0/pyproject.toml +63 -0
- lanfence-0.1.0/setup.cfg +4 -0
- lanfence-0.1.0/tests/test_allowlist.py +77 -0
- lanfence-0.1.0/tests/test_cli.py +91 -0
- lanfence-0.1.0/tests/test_config.py +72 -0
- lanfence-0.1.0/tests/test_db.py +100 -0
- lanfence-0.1.0/tests/test_engine.py +114 -0
- lanfence-0.1.0/tests/test_fingerprint.py +80 -0
- lanfence-0.1.0/tests/test_netutil.py +39 -0
- lanfence-0.1.0/tests/test_report.py +53 -0
- lanfence-0.1.0/tests/test_scanner.py +61 -0
- lanfence-0.1.0/tests/test_vendor.py +33 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright (c) 2026-present Stable State Consulting Ltd
|
|
3
|
+
SPDX-License-Identifier: MIT
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Changelog
|
|
7
|
+
|
|
8
|
+
All notable changes to LAN Fence are recorded here.
|
|
9
|
+
|
|
10
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
11
|
+
and this project aims to follow [Semantic Versioning](https://semver.org/).
|
|
12
|
+
Each release is also published to
|
|
13
|
+
[PyPI](https://pypi.org/project/lanfence/) and tagged on
|
|
14
|
+
[GitHub](https://github.com/rosscooney/lanfence/releases).
|
|
15
|
+
|
|
16
|
+
## [Unreleased]
|
|
17
|
+
|
|
18
|
+
## [0.1.0] - 2026-09-11
|
|
19
|
+
|
|
20
|
+
Initial release. MVP scope: ARP scanning (active + passive), MAC tracking, an
|
|
21
|
+
allowlist, basic device fingerprinting, CLI + JSON output, and syslog/email/
|
|
22
|
+
webhook alerting.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `lanfence scan` - one-time active ARP sweep of the local subnet (auto-
|
|
27
|
+
detected, or `--interface`/`--subnet`); records every device to a
|
|
28
|
+
persistent SQLite database and prints a device table plus any findings.
|
|
29
|
+
- `lanfence monitor` - continuous watch: repeats an active ARP sweep on an
|
|
30
|
+
interval (`scan.scan_interval_seconds`) and, in parallel, passively sniffs
|
|
31
|
+
ARP traffic between sweeps for lower-latency detection of a device that
|
|
32
|
+
joins mid-interval. Runs until interrupted (Ctrl+C).
|
|
33
|
+
- `lanfence allow <mac>` / `--list` / `--remove` - manage a YAML allowlist of
|
|
34
|
+
devices you trust; findings about an allowlisted device are downgraded to
|
|
35
|
+
`info` instead of alerting every time it reconnects.
|
|
36
|
+
- `lanfence report --since <30m|24h|7d>` - summarizes connect/disconnect/
|
|
37
|
+
reappear events and findings recorded in the database over a time window,
|
|
38
|
+
for scheduled (cron/systemd-timer) daily or weekly reports.
|
|
39
|
+
- `lanfence check` - verifies the host can run LAN Fence: root/raw-socket
|
|
40
|
+
access, whether `scapy` is installed, interface/subnet auto-detection, and
|
|
41
|
+
that the database path is writable.
|
|
42
|
+
- Device lifecycle tracking (`new_device` / `reappeared` / `disconnected`)
|
|
43
|
+
persisted to SQLite, keyed by MAC address.
|
|
44
|
+
- Built-in device fingerprinting: a curated offline OUI → vendor table
|
|
45
|
+
(`lanfence/data/oui_vendors.txt`) plus a rogue-device signature set
|
|
46
|
+
(`lanfence/data/rogue_signatures.yaml`) covering Espressif (ESP32/ESP8266 -
|
|
47
|
+
common in DIY hidden cameras and Wi-Fi implants), Raspberry Pi hardware,
|
|
48
|
+
USB-Ethernet gadget chipsets, and hostname signatures for Pwnagotchi, Hak5
|
|
49
|
+
Bash Bunny/LAN Turtle/WiFi Pineapple, Flipper Zero and O.MG Cable. Both
|
|
50
|
+
files are extensible via `vendor_file:` / `rogue_signatures_file:` in
|
|
51
|
+
config. A locally-administered (randomized/spoofed) MAC is flagged on its
|
|
52
|
+
own as a low-grade signal.
|
|
53
|
+
- Plain-language findings with `high` / `medium` / `info` severity, a
|
|
54
|
+
rationale, a recommendation, and supporting evidence lines.
|
|
55
|
+
- Alert dispatch to syslog, email (SMTP) and/or a webhook (JSON POST), gated
|
|
56
|
+
by `alerts.min_severity`; `--alert` on `scan`/`monitor` triggers dispatch.
|
|
57
|
+
- JSON export (`--format json`) on `scan` and `report`, and
|
|
58
|
+
`--fail-on-findings` exit codes (`0`/`10`/`20` for info/medium/high) for CI
|
|
59
|
+
use.
|
|
60
|
+
- YAML configuration (`--config`) for scan settings, alert channels, database
|
|
61
|
+
path, allowlist path, and extra vendor/signature files.
|
|
62
|
+
- No telemetry and no calls to any third-party service; every network
|
|
63
|
+
destination (syslog target, SMTP host, webhook URL) is one the operator
|
|
64
|
+
configures themselves.
|
|
65
|
+
|
|
66
|
+
[Unreleased]: https://github.com/rosscooney/lanfence/compare/v0.1.0...HEAD
|
|
67
|
+
[0.1.0]: https://github.com/rosscooney/lanfence/releases/tag/v0.1.0
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Contributing to LAN Fence
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving LAN Fence. Contributions are welcome via
|
|
4
|
+
pull requests at <https://github.com/rosscooney/lanfence>.
|
|
5
|
+
|
|
6
|
+
## Licensing of contributions
|
|
7
|
+
|
|
8
|
+
- LAN Fence is distributed under the [MIT License](LICENSE).
|
|
9
|
+
- Contributions submitted to the project are expected to be distributed under
|
|
10
|
+
the MIT License as part of LAN Fence.
|
|
11
|
+
- Contributors retain copyright in their own contributions unless separately
|
|
12
|
+
agreed in writing.
|
|
13
|
+
- By submitting a pull request, you confirm that you have the right to submit
|
|
14
|
+
the code under the MIT License, and that you are licensing your contribution
|
|
15
|
+
under the MIT License.
|
|
16
|
+
|
|
17
|
+
There is **no** Contributor Licence Agreement or copyright assignment to sign.
|
|
18
|
+
|
|
19
|
+
## What not to submit
|
|
20
|
+
|
|
21
|
+
- Proprietary or confidential code.
|
|
22
|
+
- Code copied from third-party projects under licences incompatible with MIT
|
|
23
|
+
distribution (for example GPL/AGPL/SSPL source code copied into LAN Fence).
|
|
24
|
+
- Significant new dependencies whose licences are incompatible with the
|
|
25
|
+
project's MIT distribution model. If a change adds a new runtime dependency,
|
|
26
|
+
note its licence in the pull request description.
|
|
27
|
+
- A full copy of the IEEE OUI registry or similarly large generated data files.
|
|
28
|
+
`lanfence/data/oui_vendors.txt` is a small curated subset on purpose (see
|
|
29
|
+
the comment at the top of that file) - keep additions targeted.
|
|
30
|
+
|
|
31
|
+
## Scope and non-goals
|
|
32
|
+
|
|
33
|
+
LAN Fence is an **observation-only, defensive** tool. It scans, records and
|
|
34
|
+
reports; it never sends anything beyond a standard ARP request, never joins,
|
|
35
|
+
deauthenticates, spoofs, blocks, or otherwise touches another device on the
|
|
36
|
+
network. Please do not propose features that add active exploitation, packet
|
|
37
|
+
injection/deauth, DHCP/ARP spoofing, network blocking or throttling, or any
|
|
38
|
+
other offensive capability against devices LAN Fence discovers - such pull
|
|
39
|
+
requests will be closed.
|
|
40
|
+
|
|
41
|
+
LAN Fence cannot prove a device is malicious or that a MAC address is genuine
|
|
42
|
+
- vendor OUIs and hostnames are trivially spoofed. It surfaces evidence and
|
|
43
|
+
heuristics for a human to judge. Keep documentation and finding wording
|
|
44
|
+
consistent with that (a "finding" is a lead, not a verdict).
|
|
45
|
+
|
|
46
|
+
## Development setup
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
python3 -m venv .venv && . .venv/bin/activate
|
|
50
|
+
pip install -e ".[dev,scan]"
|
|
51
|
+
pytest
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Active/passive scanning itself needs root (or `CAP_NET_RAW`) and a real
|
|
55
|
+
network interface, so most of the test suite exercises the scanning code with
|
|
56
|
+
the network layer mocked - `lanfence/scanner.py` is intentionally the one
|
|
57
|
+
thin module that talks to raw sockets.
|
|
58
|
+
|
|
59
|
+
## Before opening a pull request
|
|
60
|
+
|
|
61
|
+
- Add or update tests for behaviour changes.
|
|
62
|
+
- Run the test suite: `pytest`.
|
|
63
|
+
- Keep changes focused; describe the motivation in the PR description.
|
|
64
|
+
- Add the source-file header to any **new** original source files:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# Copyright (c) 2026-present Stable State Consulting Ltd
|
|
68
|
+
# SPDX-License-Identifier: MIT
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Reporting bugs and security issues
|
|
72
|
+
|
|
73
|
+
- Normal bugs: open a GitHub issue.
|
|
74
|
+
- Security vulnerabilities in LAN Fence itself: open a GitHub issue marked
|
|
75
|
+
`security`, or email contributors@lanfence.dev.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright (c) 2026-present Stable State Consulting Ltd
|
|
3
|
+
SPDX-License-Identifier: MIT
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Distributing LAN Fence
|
|
7
|
+
|
|
8
|
+
LAN Fence is MIT-licensed. The distribution model is deliberately
|
|
9
|
+
**low-friction**: this project ships **only its own MIT code**, plus a small
|
|
10
|
+
curated OUI vendor table and a handful of rogue-device fingerprint signatures
|
|
11
|
+
(both plain-text/YAML data files, not compiled artifacts), and never
|
|
12
|
+
redistributes a prebuilt operating-system image. Users install onto their own
|
|
13
|
+
stock Raspberry Pi OS / Debian, so the GPL/LGPL parts of the OS come straight
|
|
14
|
+
from Raspberry Pi Ltd and Debian - this project is not in that supply chain.
|
|
15
|
+
|
|
16
|
+
> Not legal advice. If you redistribute at scale, have a solicitor review your
|
|
17
|
+
> final artifact and its notices.
|
|
18
|
+
|
|
19
|
+
## Supported ways to install
|
|
20
|
+
|
|
21
|
+
### 1. pipx (recommended)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pipx install lanfence
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Isolated from system Python, and puts the `lanfence` launcher on your `PATH`.
|
|
28
|
+
|
|
29
|
+
### 2. pip / venv (any Debian/Ubuntu/RPi OS host)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python3 -m venv ~/.venvs/lanfence
|
|
33
|
+
~/.venvs/lanfence/bin/pip install 'lanfence[scan]'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`scapy` (its own licence, GPL-2.0 - see below) is an optional extra
|
|
37
|
+
(`lanfence[scan]`) because it is only needed for the actual ARP scanning code
|
|
38
|
+
path; everything else (config, allowlist, database, reporting) has no GPL
|
|
39
|
+
dependency.
|
|
40
|
+
|
|
41
|
+
## A note on `scapy`
|
|
42
|
+
|
|
43
|
+
`scapy` is licensed GPL-2.0-only. LAN Fence's own code is MIT and calls scapy
|
|
44
|
+
as an ordinary, unmodified, independently-installed library dependency (an
|
|
45
|
+
`import`, not vendored source) - this is the same relationship any Python tool
|
|
46
|
+
has with a GPL library it depends on via PyPI. If your organisation's
|
|
47
|
+
licence policy treats "depends on a GPL library at runtime" differently from
|
|
48
|
+
"redistributes GPL source", get your own legal read before shipping a
|
|
49
|
+
downstream product built on LAN Fence; LAN Fence's own source and the code it
|
|
50
|
+
directly redistributes (`lanfence/data/*`) remain MIT regardless.
|
|
51
|
+
|
|
52
|
+
## Publishing checklist (maintainers)
|
|
53
|
+
|
|
54
|
+
See [RELEASING.md](RELEASING.md) for the full step-by-step. In short:
|
|
55
|
+
|
|
56
|
+
- [ ] `python -m build` → `twine check dist/*` passes
|
|
57
|
+
- [ ] `pip install dist/*.whl` in a clean venv; `lanfence --version` works
|
|
58
|
+
- [ ] `CHANGELOG.md` has a dated section for this version
|
|
59
|
+
- [ ] tag `vX.Y.Z`; publish to PyPI as `lanfence`
|
|
60
|
+
- [ ] `LICENSE`, `CONTRIBUTING.md`, `CHANGELOG.md`, `DISTRIBUTING.md` present in
|
|
61
|
+
the sdist (`LICENSE` via `license-files` in `pyproject.toml`; the rest
|
|
62
|
+
via [`MANIFEST.in`](MANIFEST.in)) - check with `tar tzf dist/*.tar.gz`
|
lanfence-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present Stable State Consulting Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lanfence-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lanfence
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Defensive LAN device monitor - detect and alert on unauthorized devices joining your network
|
|
5
|
+
Author-email: Stable State Consulting Ltd <contributors@lanfence.dev>
|
|
6
|
+
Maintainer-email: Stable State Consulting Ltd <contributors@lanfence.dev>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/rosscooney/lanfence
|
|
9
|
+
Project-URL: Source, https://github.com/rosscooney/lanfence
|
|
10
|
+
Project-URL: Issues, https://github.com/rosscooney/lanfence/issues
|
|
11
|
+
Keywords: network,security,defensive,arp,raspberry-pi,monitoring
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Classifier: Topic :: System :: Networking :: Monitoring
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: typer>=0.12
|
|
25
|
+
Requires-Dist: pydantic>=2.6
|
|
26
|
+
Requires-Dist: PyYAML>=6.0
|
|
27
|
+
Requires-Dist: rich>=13.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
30
|
+
Provides-Extra: scan
|
|
31
|
+
Requires-Dist: scapy>=2.5; extra == "scan"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# LAN Fence
|
|
35
|
+
|
|
36
|
+
**LAN Fence is an open-source defensive network device monitor for Linux**
|
|
37
|
+
(developed and tested on Raspberry Pi OS / Debian, and reasonably portable to
|
|
38
|
+
other Debian/Ubuntu systems).
|
|
39
|
+
|
|
40
|
+
- Source & downloads: <https://github.com/rosscooney/lanfence>
|
|
41
|
+
([releases](https://github.com/rosscooney/lanfence/releases))
|
|
42
|
+
- Package: [`lanfence` on PyPI](https://pypi.org/project/lanfence/)
|
|
43
|
+
|
|
44
|
+
LAN Fence runs on a small Linux box (a Raspberry Pi is the common case) sitting
|
|
45
|
+
on your network. It continuously scans for connected devices via ARP,
|
|
46
|
+
maintains an allowlist of devices you already trust, and alerts in
|
|
47
|
+
plain language when something unknown joins - a rogue device, unauthorized
|
|
48
|
+
hardware, or a supply-chain implant on your LAN.
|
|
49
|
+
|
|
50
|
+
LAN Fence **only observes**. It sends nothing beyond a standard ARP "who-has"
|
|
51
|
+
request (the same thing every device on your LAN does routinely) and never
|
|
52
|
+
touches, blocks, deauthenticates or spoofs anything.
|
|
53
|
+
|
|
54
|
+
> ⚠️ LAN Fence **cannot prove a device is malicious, or that a MAC address is
|
|
55
|
+
> genuine.** MAC vendor prefixes and hostnames are trivially spoofed by anyone
|
|
56
|
+
> deliberately trying to blend in. A finding is a lead worth checking by hand,
|
|
57
|
+
> not a verdict - use it as one input to your own judgement.
|
|
58
|
+
|
|
59
|
+
## How it works
|
|
60
|
+
|
|
61
|
+
1. **Active scanning** - LAN Fence periodically ARP-sweeps your subnet
|
|
62
|
+
(`lanfence scan` for one sweep, or on an interval inside `lanfence
|
|
63
|
+
monitor`), collecting every MAC/IP that answers.
|
|
64
|
+
2. **Passive monitoring** - between active sweeps, `lanfence monitor` also
|
|
65
|
+
listens for ARP traffic on the wire, so a device that joins mid-interval is
|
|
66
|
+
caught sooner rather than waiting for the next sweep.
|
|
67
|
+
3. Every sighting is folded into a persistent **SQLite database** keyed by MAC
|
|
68
|
+
address, which tracks each device's lifecycle: `new_device` the first time
|
|
69
|
+
it's ever seen, `reappeared` if it had gone offline and came back, and
|
|
70
|
+
`disconnected` when an active sweep no longer sees it.
|
|
71
|
+
4. Each device is **fingerprinted**: an offline OUI → vendor lookup, a set of
|
|
72
|
+
built-in rogue-device signatures (see below), and a check of whether its
|
|
73
|
+
MAC is locally administered (randomized/spoofed rather than
|
|
74
|
+
vendor-assigned).
|
|
75
|
+
5. Each device is checked against your **allowlist**
|
|
76
|
+
(`lanfence allow <mac>`). A brand-new or reappearing device not on the
|
|
77
|
+
allowlist produces a plain-language **finding** with a severity
|
|
78
|
+
(`high`/`medium`/`info`), a rationale, and a recommendation; an allowlisted
|
|
79
|
+
device is downgraded to `info` so your own hardware stops shouting every
|
|
80
|
+
time it reconnects.
|
|
81
|
+
6. Findings can be dispatched to **syslog, email, or a webhook**, and
|
|
82
|
+
everything is available as a CLI table or JSON for automation.
|
|
83
|
+
|
|
84
|
+
## Built-in rogue-device signatures
|
|
85
|
+
|
|
86
|
+
Heuristics, not proof - a match is a lead to check by hand:
|
|
87
|
+
|
|
88
|
+
| Signal | Category | Why it matters |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| Vendor: Espressif | `esp32_esp8266` | ESP32/ESP8266 - the chipset behind most cheap DIY hidden cameras, rogue APs, and ESP32-based Wi-Fi implants (as well as plenty of legitimate IoT). |
|
|
91
|
+
| Vendor: Raspberry Pi | `raspberry_pi` | Legitimate everywhere, but also the common hardware basis for rogue network-tap / implant projects (P4wnP1, home-built taps). |
|
|
92
|
+
| Vendor: ASIX Electronics | `usb_ethernet_gadget` | USB-Ethernet chipset used both by ordinary dongles and by BadUSB tools (Bash Bunny, LAN Turtle, O.MG cable) presenting as a network adapter. |
|
|
93
|
+
| Hostname contains `pwnagotchi` | `pwnagotchi` | Pwnagotchi's distinctive default hostname. |
|
|
94
|
+
| Hostname contains `bashbunny` / `lanturtle` / `pineapple` / `omg-cable` | Hak5/O.MG tooling | Default hostnames of common commercial implant/pentest hardware. |
|
|
95
|
+
| Hostname contains `flipper` | `flipper_zero` | Flipper Zero (via its Wi-Fi dev board). |
|
|
96
|
+
| Locally administered MAC | `locally_administered_mac` | No vendor OUI - common for privacy MAC-randomization on phones/laptops, but also for spoofed or gadget hardware. |
|
|
97
|
+
|
|
98
|
+
Extend or override these with your own `rogue_signatures_file:` (same YAML
|
|
99
|
+
shape as `lanfence/data/rogue_signatures.yaml`) and `vendor_file:` (same
|
|
100
|
+
tab-separated shape as `lanfence/data/oui_vendors.txt`) in config.
|
|
101
|
+
|
|
102
|
+
## Install
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pipx install lanfence # isolated, recommended
|
|
106
|
+
# active/passive scanning needs the `scan` extra (scapy):
|
|
107
|
+
pipx inject lanfence 'lanfence[scan]'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
or
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
python3 -m venv ~/.venvs/lanfence
|
|
114
|
+
~/.venvs/lanfence/bin/pip install 'lanfence[scan]'
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Scanning needs raw-socket access, so `scan`/`monitor` typically need `sudo`
|
|
118
|
+
(or `CAP_NET_RAW` on the interpreter). `allow`, `report` and `check` do not.
|
|
119
|
+
|
|
120
|
+
## Commands
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
lanfence scan # one-time active ARP scan; table + findings
|
|
124
|
+
lanfence scan --format json # same, machine-readable
|
|
125
|
+
lanfence monitor # continuous: active sweeps + passive sniffing
|
|
126
|
+
lanfence allow <MAC> --name X # trust a device; its findings become info
|
|
127
|
+
lanfence allow --list # show the allowlist
|
|
128
|
+
lanfence allow --remove <MAC> # untrust a device
|
|
129
|
+
lanfence report --since 24h # summarize events/findings from the database
|
|
130
|
+
lanfence check # verify permissions, scapy, interface, storage
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Example: an unknown device joins
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
$ sudo lanfence scan
|
|
137
|
+
|
|
138
|
+
Devices seen (4)
|
|
139
|
+
┌───────────────────┬──────────────┬──────────────┬────────────────────┬────────┬─────────┐
|
|
140
|
+
│ MAC │ IP │ Hostname │ Vendor │ Status │ Trusted │
|
|
141
|
+
├───────────────────┼──────────────┼──────────────┼────────────────────┼────────┼─────────┤
|
|
142
|
+
│ b8:27:eb:12:34:56 │ 192.168.1.10 │ nas.local │ Raspberry Pi │ online │ yes (NAS)│
|
|
143
|
+
│ 52:8a:1c:99:f4:2d │ 192.168.1.47 │ [unknown] │ [unknown] │ online │ no │
|
|
144
|
+
└───────────────────┴──────────────┴──────────────┴────────────────────┴────────┴─────────┘
|
|
145
|
+
|
|
146
|
+
Findings (1)
|
|
147
|
+
|
|
148
|
+
MEDIUM Unknown device connected
|
|
149
|
+
MAC: 52:8a:1c:99:f4:2d
|
|
150
|
+
The vendor bit pattern indicates a locally administered address rather
|
|
151
|
+
than one assigned by a hardware vendor. Common causes: MAC-randomization
|
|
152
|
+
privacy features on modern phones/laptops, virtual machines/containers,
|
|
153
|
+
or a device deliberately spoofing its address.
|
|
154
|
+
Recommendation: Verify this device belongs on your network. If it's
|
|
155
|
+
yours, run `lanfence allow 52:8a:1c:99:f4:2d` to stop future alerts.
|
|
156
|
+
• MAC: 52:8a:1c:99:f4:2d
|
|
157
|
+
• IP: 192.168.1.47
|
|
158
|
+
• Hostname: [unknown]
|
|
159
|
+
• Vendor: [unknown]
|
|
160
|
+
• mac = 52:8a:1c:99:f4:2d (U/L bit set, no vendor OUI match)
|
|
161
|
+
|
|
162
|
+
Overall: 1 finding(s), highest severity: medium
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Running unattended
|
|
166
|
+
|
|
167
|
+
LAN Fence does not ship its own scheduler; use `systemd` (recommended on a
|
|
168
|
+
Pi) or `cron`.
|
|
169
|
+
|
|
170
|
+
**Continuous monitoring** - `/etc/systemd/system/lanfence.service`:
|
|
171
|
+
|
|
172
|
+
```ini
|
|
173
|
+
[Unit]
|
|
174
|
+
Description=LAN Fence continuous monitoring
|
|
175
|
+
After=network-online.target
|
|
176
|
+
Wants=network-online.target
|
|
177
|
+
|
|
178
|
+
[Service]
|
|
179
|
+
ExecStart=/usr/local/bin/lanfence monitor --config /etc/lanfence/config.yaml
|
|
180
|
+
Restart=on-failure
|
|
181
|
+
User=root
|
|
182
|
+
|
|
183
|
+
[Install]
|
|
184
|
+
WantedBy=multi-user.target
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
sudo systemctl enable --now lanfence
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Daily report** - a cron entry (`sudo crontab -e`):
|
|
192
|
+
|
|
193
|
+
```cron
|
|
194
|
+
0 7 * * * /usr/local/bin/lanfence report --since 24h --format json > /var/log/lanfence/daily.json
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Configuration
|
|
198
|
+
|
|
199
|
+
All settings are optional; everything has a sensible default. Pass
|
|
200
|
+
`--config path/to/config.yaml` to any command.
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
scan:
|
|
204
|
+
interface: null # null = auto-detect
|
|
205
|
+
subnet: null # null = derive from the interface's own address
|
|
206
|
+
scan_interval_seconds: 60 # how often `monitor` repeats an active sweep
|
|
207
|
+
active_scan_timeout_seconds: 3
|
|
208
|
+
passive: true # also sniff ARP traffic between sweeps
|
|
209
|
+
resolve_hostnames: true # try reverse DNS for each device
|
|
210
|
+
dns_timeout_seconds: 1
|
|
211
|
+
|
|
212
|
+
alerts:
|
|
213
|
+
min_severity: medium # info | medium | high - dispatch threshold
|
|
214
|
+
syslog:
|
|
215
|
+
enabled: false
|
|
216
|
+
address: /dev/log
|
|
217
|
+
facility: user
|
|
218
|
+
email:
|
|
219
|
+
enabled: false
|
|
220
|
+
smtp_host: localhost
|
|
221
|
+
smtp_port: 587
|
|
222
|
+
use_tls: true
|
|
223
|
+
username: null
|
|
224
|
+
password: null
|
|
225
|
+
from_addr: null
|
|
226
|
+
to_addrs: []
|
|
227
|
+
webhook:
|
|
228
|
+
enabled: false
|
|
229
|
+
url: null
|
|
230
|
+
timeout_seconds: 5
|
|
231
|
+
|
|
232
|
+
db_path: ~/.local/share/lanfence/lanfence.db
|
|
233
|
+
allowlist_file: ~/.config/lanfence/allowlist.yaml
|
|
234
|
+
vendor_file: null # extra OUI table, merged with the packaged one
|
|
235
|
+
rogue_signatures_file: null # extra signatures, merged with the packaged ones
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Exit codes (`--fail-on-findings`)
|
|
239
|
+
|
|
240
|
+
`scan` and `report` accept `--fail-on-findings` for CI/scripting use:
|
|
241
|
+
|
|
242
|
+
| Highest severity in the result | Exit code |
|
|
243
|
+
|---|---|
|
|
244
|
+
| none / info | 0 |
|
|
245
|
+
| medium | 10 |
|
|
246
|
+
| high | 20 |
|
|
247
|
+
|
|
248
|
+
## Privacy and security
|
|
249
|
+
|
|
250
|
+
- **No telemetry, no external calls.** LAN Fence never phones home. The only
|
|
251
|
+
network destinations it ever contacts are ones *you* configure: your own
|
|
252
|
+
syslog daemon, your own SMTP relay, or your own webhook URL.
|
|
253
|
+
- The vendor and signature databases are bundled, offline, and static -
|
|
254
|
+
nothing is fetched to "keep them fresh".
|
|
255
|
+
- The device database and allowlist are written atomically and are
|
|
256
|
+
owner-readable only where the platform supports it.
|
|
257
|
+
|
|
258
|
+
## Development
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
python3 -m venv .venv && . .venv/bin/activate
|
|
262
|
+
pip install -e ".[dev,scan]"
|
|
263
|
+
pytest
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for scope and pull-request guidelines,
|
|
267
|
+
and [DISTRIBUTING.md](DISTRIBUTING.md) for licensing notes on the optional
|
|
268
|
+
`scapy` (GPL-2.0) dependency.
|
|
269
|
+
|
|
270
|
+
## License
|
|
271
|
+
|
|
272
|
+
MIT - see [LICENSE](LICENSE).
|