dnsmasq-webconf 0.2.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.
- dnsmasq_webconf-0.2.0/.gitignore +135 -0
- dnsmasq_webconf-0.2.0/LICENSE +21 -0
- dnsmasq_webconf-0.2.0/PKG-INFO +264 -0
- dnsmasq_webconf-0.2.0/README.ja.md +233 -0
- dnsmasq_webconf-0.2.0/README.md +233 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/__init__.py +7 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/__main__.py +10 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/app.py +403 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/auth.py +142 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/config.py +339 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/static/main.js +457 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/static/vendor/MANIFEST.txt +20 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/static/vendor/bootstrap.bundle.min.js +7 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/static/vendor/bootstrap.min.css +7 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/static/vendor/jquery.min.js +2 -0
- dnsmasq_webconf-0.2.0/dnsmasq_webconf/views/main.html.j2 +163 -0
- dnsmasq_webconf-0.2.0/pyproject.toml +65 -0
- dnsmasq_webconf-0.2.0/tests/test_app.py +269 -0
- dnsmasq_webconf-0.2.0/tests/test_auth.py +65 -0
- dnsmasq_webconf-0.2.0/tests/test_config.py +223 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
./conf
|
|
2
|
+
|
|
3
|
+
# Byte-compiled / optimized / DLL files
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
.Python
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
pip-wheel-metadata/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
MANIFEST
|
|
31
|
+
|
|
32
|
+
# PyInstaller
|
|
33
|
+
# Usually these files are written by a python script from a template
|
|
34
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
35
|
+
*.manifest
|
|
36
|
+
*.spec
|
|
37
|
+
|
|
38
|
+
# Installer logs
|
|
39
|
+
pip-log.txt
|
|
40
|
+
pip-delete-this-directory.txt
|
|
41
|
+
|
|
42
|
+
# Unit test / coverage reports
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
.coverage
|
|
47
|
+
.coverage.*
|
|
48
|
+
.cache
|
|
49
|
+
nosetests.xml
|
|
50
|
+
coverage.xml
|
|
51
|
+
*.cover
|
|
52
|
+
*.py,cover
|
|
53
|
+
.hypothesis/
|
|
54
|
+
.pytest_cache/
|
|
55
|
+
|
|
56
|
+
# Translations
|
|
57
|
+
*.mo
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
# Django stuff:
|
|
61
|
+
*.log
|
|
62
|
+
local_settings.py
|
|
63
|
+
db.sqlite3
|
|
64
|
+
db.sqlite3-journal
|
|
65
|
+
|
|
66
|
+
# Flask stuff:
|
|
67
|
+
instance/
|
|
68
|
+
.webassets-cache
|
|
69
|
+
|
|
70
|
+
# Scrapy stuff:
|
|
71
|
+
.scrapy
|
|
72
|
+
|
|
73
|
+
# Sphinx documentation
|
|
74
|
+
docs/_build/
|
|
75
|
+
|
|
76
|
+
# PyBuilder
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
.python-version
|
|
88
|
+
|
|
89
|
+
# pipenv
|
|
90
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
91
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
92
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
93
|
+
# install all needed dependencies.
|
|
94
|
+
#Pipfile.lock
|
|
95
|
+
|
|
96
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
97
|
+
__pypackages__/
|
|
98
|
+
|
|
99
|
+
# Celery stuff
|
|
100
|
+
celerybeat-schedule
|
|
101
|
+
celerybeat.pid
|
|
102
|
+
|
|
103
|
+
# SageMath parsed files
|
|
104
|
+
*.sage.py
|
|
105
|
+
|
|
106
|
+
# Environments
|
|
107
|
+
.env
|
|
108
|
+
.venv
|
|
109
|
+
env/
|
|
110
|
+
venv/
|
|
111
|
+
ENV/
|
|
112
|
+
env.bak/
|
|
113
|
+
venv.bak/
|
|
114
|
+
|
|
115
|
+
# Spyder project settings
|
|
116
|
+
.spyderproject
|
|
117
|
+
.spyproject
|
|
118
|
+
|
|
119
|
+
# Rope project settings
|
|
120
|
+
.ropeproject
|
|
121
|
+
|
|
122
|
+
# mkdocs documentation
|
|
123
|
+
/site
|
|
124
|
+
|
|
125
|
+
# mypy
|
|
126
|
+
.mypy_cache/
|
|
127
|
+
.dmypy.json
|
|
128
|
+
dmypy.json
|
|
129
|
+
|
|
130
|
+
# Pyre type checker
|
|
131
|
+
.pyre/
|
|
132
|
+
cables.json
|
|
133
|
+
|
|
134
|
+
.DS_Store
|
|
135
|
+
*.bkp
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019-2026 Akiva Miura
|
|
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.
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dnsmasq-webconf
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Lightweight web UI for editing dnsmasq static DHCP reservations, without rewriting your config
|
|
5
|
+
Project-URL: Homepage, https://github.com/akivajp/dnsmasq-webconf
|
|
6
|
+
Project-URL: Repository, https://github.com/akivajp/dnsmasq-webconf
|
|
7
|
+
Project-URL: Issues, https://github.com/akivajp/dnsmasq-webconf/issues
|
|
8
|
+
Author-email: Akiva Miura <akiva.miura@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: dhcp,dns,dnsmasq,network,self-hosted,web-ui
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Web Environment
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: System :: Networking
|
|
23
|
+
Classifier: Topic :: System :: Systems Administration
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Requires-Dist: bottle>=0.12
|
|
26
|
+
Requires-Dist: jinja2>=3.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: webtest>=3.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Dnsmasq WebConf
|
|
33
|
+
|
|
34
|
+
[](https://github.com/akivajp/dnsmasq-webconf/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/dnsmasq-webconf/)
|
|
36
|
+
[](https://pypi.org/project/dnsmasq-webconf/)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
A small web UI for managing **static DHCP reservations** in dnsmasq — without taking
|
|
40
|
+
ownership of your config file.
|
|
41
|
+
|
|
42
|
+
[日本語版 README はこちら](README.ja.md)
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
## Why this exists
|
|
47
|
+
|
|
48
|
+
Most dnsmasq front-ends (Pi-hole, router firmwares, config generators) **own** the
|
|
49
|
+
configuration: they generate `dnsmasq.conf` from their own database, and your
|
|
50
|
+
hand-written directives either get moved somewhere else or are lost.
|
|
51
|
+
|
|
52
|
+
`dnsmasq-webconf` does the opposite. It reads your existing config file, and when you
|
|
53
|
+
save, it **rewrites only the `dhcp-host=` lines you actually changed**. Every other
|
|
54
|
+
line — your `dhcp-range=`, your `dhcp-option=`, your comments, your ordering — is
|
|
55
|
+
preserved byte-for-byte.
|
|
56
|
+
|
|
57
|
+
That makes it useful in one specific situation: you already run dnsmasq, you want to
|
|
58
|
+
keep managing it as a text file, but you'd rather not hand-edit MAC addresses every
|
|
59
|
+
time a new device shows up.
|
|
60
|
+
|
|
61
|
+
If you want an all-in-one DNS/DHCP/ad-blocking appliance, use
|
|
62
|
+
[Pi-hole](https://pi-hole.net/) instead — it is far more capable, and this tool does
|
|
63
|
+
not try to compete with it. See [Alternatives](#alternatives) below.
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
- **Static DHCP reservations** — add, edit, reorder, comment out, and delete
|
|
68
|
+
`dhcp-host=` entries.
|
|
69
|
+
- **One-click reservation from a live lease** — see a device in the DHCP lease table,
|
|
70
|
+
press *Add Static*, and it becomes a fixed reservation.
|
|
71
|
+
- **Blocklist management** — mark a MAC as `ignore` so dnsmasq refuses to serve it.
|
|
72
|
+
- **Per-host notes** — comments are round-tripped as `#` comments in the config file,
|
|
73
|
+
so they stay readable when you edit by hand.
|
|
74
|
+
- **Read-only views** of the DHCP lease table and the system `hosts` file.
|
|
75
|
+
- **Optional reload hook** — run `systemctl reload dnsmasq` (or anything else) after a
|
|
76
|
+
successful save.
|
|
77
|
+
- **No database, no build step, no JavaScript toolchain.** Two Python dependencies,
|
|
78
|
+
and all CSS/JS is bundled — it works on an isolated network with no internet access.
|
|
79
|
+
|
|
80
|
+
## Installation
|
|
81
|
+
|
|
82
|
+
### From PyPI (recommended)
|
|
83
|
+
|
|
84
|
+
```shell
|
|
85
|
+
pipx install dnsmasq-webconf
|
|
86
|
+
# or: uv tool install dnsmasq-webconf
|
|
87
|
+
# or, inside a virtualenv: pip install dnsmasq-webconf
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> On modern Debian/Ubuntu/Raspberry Pi OS, `pip install --user` is blocked by
|
|
91
|
+
> [PEP 668](https://peps.python.org/pep-0668/). Use `pipx` or `uv tool` instead.
|
|
92
|
+
|
|
93
|
+
### With Docker
|
|
94
|
+
|
|
95
|
+
```shell
|
|
96
|
+
docker build -t dnsmasq-webconf .
|
|
97
|
+
docker run --rm -p 8080:8080 \
|
|
98
|
+
--user "$(id -u):$(id -g)" \
|
|
99
|
+
-e DNSMASQ_WEBCONF_AUTH='admin:secret' \
|
|
100
|
+
-v /etc/dnsmasq.more.conf:/etc/dnsmasq.more.conf \
|
|
101
|
+
-v /var/lib/misc/dnsmasq.leases:/var/lib/misc/dnsmasq.leases:ro \
|
|
102
|
+
dnsmasq-webconf
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### From source
|
|
106
|
+
|
|
107
|
+
```shell
|
|
108
|
+
git clone https://github.com/akivajp/dnsmasq-webconf.git
|
|
109
|
+
cd dnsmasq-webconf
|
|
110
|
+
pip install -e .
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
```shell
|
|
116
|
+
dnsmasq-webconf --config /etc/dnsmasq.more.conf
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then open <http://127.0.0.1:8080>.
|
|
120
|
+
|
|
121
|
+
By default the server listens on **loopback only**. To expose it on your LAN you must
|
|
122
|
+
also set credentials:
|
|
123
|
+
|
|
124
|
+
```shell
|
|
125
|
+
dnsmasq-webconf --host 0.0.0.0 --auth admin:secret \
|
|
126
|
+
--config /etc/dnsmasq.more.conf \
|
|
127
|
+
--reload "systemctl reload dnsmasq"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
To avoid putting the password in your shell history or in `ps` output, use the
|
|
131
|
+
environment variable instead of `--auth`:
|
|
132
|
+
|
|
133
|
+
```shell
|
|
134
|
+
DNSMASQ_WEBCONF_AUTH='admin:secret' dnsmasq-webconf --host 0.0.0.0 ...
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Run `dnsmasq-webconf --help` for the full option list.
|
|
138
|
+
|
|
139
|
+
### Recommended dnsmasq setup
|
|
140
|
+
|
|
141
|
+
Point the tool at a dedicated include file rather than your main `dnsmasq.conf`, so
|
|
142
|
+
that a mistake can never take down DNS resolution:
|
|
143
|
+
|
|
144
|
+
```conf
|
|
145
|
+
# /etc/dnsmasq.conf
|
|
146
|
+
conf-file=/etc/dnsmasq.more.conf
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```shell
|
|
150
|
+
sudo touch /etc/dnsmasq.more.conf
|
|
151
|
+
dnsmasq-webconf --config /etc/dnsmasq.more.conf
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Running as a service
|
|
155
|
+
|
|
156
|
+
```ini
|
|
157
|
+
# /etc/systemd/system/dnsmasq-webconf.service
|
|
158
|
+
[Unit]
|
|
159
|
+
Description=Dnsmasq WebConf
|
|
160
|
+
After=network.target
|
|
161
|
+
|
|
162
|
+
[Service]
|
|
163
|
+
# Needs write access to the config file; adjust to suit your setup.
|
|
164
|
+
User=root
|
|
165
|
+
Environment=DNSMASQ_WEBCONF_AUTH=admin:secret
|
|
166
|
+
ExecStart=/usr/local/bin/dnsmasq-webconf 8080 \
|
|
167
|
+
--host 0.0.0.0 \
|
|
168
|
+
--config /etc/dnsmasq.more.conf \
|
|
169
|
+
--reload "systemctl reload dnsmasq"
|
|
170
|
+
Restart=on-failure
|
|
171
|
+
|
|
172
|
+
[Install]
|
|
173
|
+
WantedBy=multi-user.target
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Security
|
|
177
|
+
|
|
178
|
+
This tool edits the configuration of your network's DHCP server. Anyone who can write
|
|
179
|
+
to it can hand out arbitrary IP addresses, gateways and DNS servers to every device on
|
|
180
|
+
your LAN. Please treat access to it accordingly.
|
|
181
|
+
|
|
182
|
+
- **Authentication is off by default, and so is network exposure.** The server binds to
|
|
183
|
+
`127.0.0.1` unless you pass `--host`. Binding to a non-loopback address without
|
|
184
|
+
`--auth` is refused outright (override with `--allow-no-auth` only if you know the
|
|
185
|
+
port is protected some other way).
|
|
186
|
+
- **HTTP Basic auth is not encrypted.** On an untrusted network, put the tool behind a
|
|
187
|
+
reverse proxy with TLS, or reach it over a VPN / SSH tunnel:
|
|
188
|
+
`ssh -L 8080:127.0.0.1:8080 your-server`.
|
|
189
|
+
- **Writes are CSRF-protected** by an `Origin` check, because browsers attach Basic
|
|
190
|
+
auth credentials automatically.
|
|
191
|
+
- **`--reload-command` runs through a shell.** It is only ever the string you supply on
|
|
192
|
+
the command line, but do not build it from untrusted input.
|
|
193
|
+
- Use `--read-only` if you only want the dashboard views.
|
|
194
|
+
|
|
195
|
+
### Reporting a vulnerability
|
|
196
|
+
|
|
197
|
+
Please open a [security advisory](https://github.com/akivajp/dnsmasq-webconf/security/advisories/new)
|
|
198
|
+
rather than a public issue.
|
|
199
|
+
|
|
200
|
+
> **Upgrading from v0.1.x?** The default listen address changed from `0.0.0.0` to
|
|
201
|
+
> `127.0.0.1`, and v0.1.x had **no authentication at all** on its save endpoint. If you
|
|
202
|
+
> ran it on a LAN, assume the config was writable by anyone who could reach the port.
|
|
203
|
+
> See [CHANGELOG.md](CHANGELOG.md).
|
|
204
|
+
|
|
205
|
+
## How saving works
|
|
206
|
+
|
|
207
|
+
1. The browser sends back only the entries you touched, each tagged with the line
|
|
208
|
+
number it came from and the **original text of that line**.
|
|
209
|
+
2. The server re-reads the config file and, for each changed entry, checks that the
|
|
210
|
+
line still matches what the browser saw.
|
|
211
|
+
3. If it matches, that single line is replaced. If it doesn't — because you edited the
|
|
212
|
+
file by hand, or another session saved first — the write is **skipped and reported**
|
|
213
|
+
back to you rather than silently overwriting.
|
|
214
|
+
4. The result is written to a temporary file in the same directory and moved into place
|
|
215
|
+
with `os.replace()`, so an interrupted write cannot corrupt your config. The previous
|
|
216
|
+
contents are kept as `<config>.bak` (disable with `--no-backup`).
|
|
217
|
+
|
|
218
|
+
Deleted entries are written as `##dhcp-host=...` rather than being removed, so you can
|
|
219
|
+
always recover them by hand.
|
|
220
|
+
|
|
221
|
+
## Scope and limitations
|
|
222
|
+
|
|
223
|
+
This tool deliberately covers a small surface. It **only** parses and edits
|
|
224
|
+
`dhcp-host=` directives.
|
|
225
|
+
|
|
226
|
+
Not supported: `dhcp-range`, `dhcp-option`, DNS records (`address=`, `cname=`), IPv6
|
|
227
|
+
reservations, query logs, statistics, and multi-user access control. Lines it does not
|
|
228
|
+
understand are preserved untouched, so you can manage them by hand alongside it.
|
|
229
|
+
|
|
230
|
+
## Alternatives
|
|
231
|
+
|
|
232
|
+
| Project | Best for |
|
|
233
|
+
|---|---|
|
|
234
|
+
| [Pi-hole](https://pi-hole.net/) | An all-in-one DNS/DHCP appliance with ad-blocking. Note that since v6 it generates `dnsmasq.conf` itself and does not read hand-written ones. |
|
|
235
|
+
| [OpenWrt LuCI](https://openwrt.org/docs/guide-user/luci/luci.essentials) / pfSense / OPNsense | You're already running a router OS — it's built in. |
|
|
236
|
+
| [dnsmasq-manager](https://github.com/gringolito/dnsmasq-manager) | A REST API (no UI) for scripting static leases, with JWT auth and distro packages. |
|
|
237
|
+
| [dnsmasq-leases-ui](https://github.com/fschlag/dnsmasq-leases-ui) | Just viewing the lease table, in a container. |
|
|
238
|
+
| [nexus-dnsmasq-mgr](https://github.com/brainchillz/nexus-dnsmasq-mgr) | A much broader feature set (DNS overrides, PXE boot, `dnsmasq --test` validation). |
|
|
239
|
+
|
|
240
|
+
## Development
|
|
241
|
+
|
|
242
|
+
```shell
|
|
243
|
+
git clone https://github.com/akivajp/dnsmasq-webconf.git
|
|
244
|
+
cd dnsmasq-webconf
|
|
245
|
+
uv venv && uv pip install -e '.[dev]'
|
|
246
|
+
uv run pytest
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
To refresh the bundled jQuery/Bootstrap files and their checksum manifest:
|
|
250
|
+
|
|
251
|
+
```shell
|
|
252
|
+
scripts/update-vendor.sh
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Contributions are welcome — please keep the "don't rewrite lines the user didn't
|
|
256
|
+
change" guarantee intact, and add a test for it.
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT — see [LICENSE](LICENSE).
|
|
261
|
+
|
|
262
|
+
Bundled third-party assets (jQuery, Bootstrap) are MIT licensed; see
|
|
263
|
+
[`dnsmasq_webconf/static/vendor/MANIFEST.txt`](dnsmasq_webconf/static/vendor/MANIFEST.txt)
|
|
264
|
+
for their versions, origins and checksums.
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Dnsmasq WebConf
|
|
2
|
+
|
|
3
|
+
[](https://github.com/akivajp/dnsmasq-webconf/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/dnsmasq-webconf/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
dnsmasq の**静的 DHCP 予約**を管理する軽量 Web UI です。
|
|
8
|
+
設定ファイルの所有権を奪わないことを最大の特徴としています。
|
|
9
|
+
|
|
10
|
+
[English README](README.md)
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
## このツールの位置づけ
|
|
15
|
+
|
|
16
|
+
dnsmasq のフロントエンドの多く (Pi-hole、ルーター用ファームウェア、各種設定ジェネレーター) は、
|
|
17
|
+
設定ファイルを**自ら生成・所有**します。`dnsmasq.conf` は独自データベースから出力されるため、
|
|
18
|
+
手書きしたディレクティブは別の場所へ移動させられるか、失われます。
|
|
19
|
+
|
|
20
|
+
`dnsmasq-webconf` は逆のアプローチを取ります。既存の設定ファイルをそのまま読み込み、
|
|
21
|
+
保存時には**実際に変更した `dhcp-host=` 行だけを書き換えます**。
|
|
22
|
+
それ以外の行 — `dhcp-range=`、`dhcp-option=`、コメント、行の並び順 — は
|
|
23
|
+
1 バイトも変更されません。
|
|
24
|
+
|
|
25
|
+
そのため、次のような状況に向いています。
|
|
26
|
+
|
|
27
|
+
> すでに dnsmasq を運用していて、今後もテキストファイルとして管理したい。
|
|
28
|
+
> ただし、新しい端末が増えるたびに MAC アドレスを手で書き足すのは避けたい。
|
|
29
|
+
|
|
30
|
+
DNS・DHCP・広告ブロックを一体で提供するアプライアンスが欲しい場合は、
|
|
31
|
+
[Pi-hole](https://pi-hole.net/) を使ってください。機能面では比較にならないほど高機能であり、
|
|
32
|
+
本ツールはそこと competing する意図を持ちません。[代替ツール](#代替ツール)も参照してください。
|
|
33
|
+
|
|
34
|
+
## 機能
|
|
35
|
+
|
|
36
|
+
- **静的 DHCP 予約の管理** — `dhcp-host=` エントリの追加・編集・並べ替え・
|
|
37
|
+
コメントアウト・削除
|
|
38
|
+
- **リースからワンクリックで予約化** — DHCP リース一覧に現れた端末の *Add Static* を押すだけで
|
|
39
|
+
固定予約に変換
|
|
40
|
+
- **ブロックリスト管理** — MAC を `ignore` 指定し、dnsmasq に応答させないようにする
|
|
41
|
+
- **ホストごとのメモ** — コメントは設定ファイル中の `#` コメントとして往復するため、
|
|
42
|
+
手で開いたときにも読める
|
|
43
|
+
- **閲覧専用ビュー** — DHCP リース一覧とシステムの `hosts` ファイル
|
|
44
|
+
- **保存後のリロード** — `systemctl reload dnsmasq` などを任意に実行可能
|
|
45
|
+
- **データベース・ビルド手順・JS ツールチェーン不要** — Python の依存は 2 つだけ。
|
|
46
|
+
CSS/JS はすべて同梱しているため、インターネットに接続できない閉域ネットワークでも動作します
|
|
47
|
+
|
|
48
|
+
## インストール
|
|
49
|
+
|
|
50
|
+
### PyPI から (推奨)
|
|
51
|
+
|
|
52
|
+
```shell
|
|
53
|
+
pipx install dnsmasq-webconf
|
|
54
|
+
# または: uv tool install dnsmasq-webconf
|
|
55
|
+
# 仮想環境内なら: pip install dnsmasq-webconf
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> 近年の Debian / Ubuntu / Raspberry Pi OS では
|
|
59
|
+
> [PEP 668](https://peps.python.org/pep-0668/) により `pip install --user` が拒否されます。
|
|
60
|
+
> `pipx` または `uv tool` を利用してください。
|
|
61
|
+
|
|
62
|
+
### Docker を使う場合
|
|
63
|
+
|
|
64
|
+
```shell
|
|
65
|
+
docker build -t dnsmasq-webconf .
|
|
66
|
+
docker run --rm -p 8080:8080 \
|
|
67
|
+
--user "$(id -u):$(id -g)" \
|
|
68
|
+
-e DNSMASQ_WEBCONF_AUTH='admin:secret' \
|
|
69
|
+
-v /etc/dnsmasq.more.conf:/etc/dnsmasq.more.conf \
|
|
70
|
+
-v /var/lib/misc/dnsmasq.leases:/var/lib/misc/dnsmasq.leases:ro \
|
|
71
|
+
dnsmasq-webconf
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### ソースから
|
|
75
|
+
|
|
76
|
+
```shell
|
|
77
|
+
git clone https://github.com/akivajp/dnsmasq-webconf.git
|
|
78
|
+
cd dnsmasq-webconf
|
|
79
|
+
pip install -e .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 使い方
|
|
83
|
+
|
|
84
|
+
```shell
|
|
85
|
+
dnsmasq-webconf --config /etc/dnsmasq.more.conf
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
ブラウザで <http://127.0.0.1:8080> を開きます。
|
|
89
|
+
|
|
90
|
+
既定では**ループバックのみ**を待ち受けます。LAN へ公開する場合は認証の設定が必須です。
|
|
91
|
+
|
|
92
|
+
```shell
|
|
93
|
+
dnsmasq-webconf --host 0.0.0.0 --auth admin:secret \
|
|
94
|
+
--config /etc/dnsmasq.more.conf \
|
|
95
|
+
--reload "systemctl reload dnsmasq"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
シェル履歴や `ps` の出力にパスワードを残さないため、`--auth` の代わりに
|
|
99
|
+
環境変数を使うことを推奨します。
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
DNSMASQ_WEBCONF_AUTH='admin:secret' dnsmasq-webconf --host 0.0.0.0 ...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
全オプションは `dnsmasq-webconf --help` で確認できます。
|
|
106
|
+
|
|
107
|
+
### 推奨する dnsmasq 側の構成
|
|
108
|
+
|
|
109
|
+
メインの `dnsmasq.conf` ではなく、専用の include ファイルを対象にすることを推奨します。
|
|
110
|
+
万一設定を壊しても名前解決そのものを止めずに済みます。
|
|
111
|
+
|
|
112
|
+
```conf
|
|
113
|
+
# /etc/dnsmasq.conf
|
|
114
|
+
conf-file=/etc/dnsmasq.more.conf
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```shell
|
|
118
|
+
sudo touch /etc/dnsmasq.more.conf
|
|
119
|
+
dnsmasq-webconf --config /etc/dnsmasq.more.conf
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### サービスとして常駐させる
|
|
123
|
+
|
|
124
|
+
```ini
|
|
125
|
+
# /etc/systemd/system/dnsmasq-webconf.service
|
|
126
|
+
[Unit]
|
|
127
|
+
Description=Dnsmasq WebConf
|
|
128
|
+
After=network.target
|
|
129
|
+
|
|
130
|
+
[Service]
|
|
131
|
+
# 設定ファイルへの書き込み権限が必要。環境に合わせて調整すること。
|
|
132
|
+
User=root
|
|
133
|
+
Environment=DNSMASQ_WEBCONF_AUTH=admin:secret
|
|
134
|
+
ExecStart=/usr/local/bin/dnsmasq-webconf 8080 \
|
|
135
|
+
--host 0.0.0.0 \
|
|
136
|
+
--config /etc/dnsmasq.more.conf \
|
|
137
|
+
--reload "systemctl reload dnsmasq"
|
|
138
|
+
Restart=on-failure
|
|
139
|
+
|
|
140
|
+
[Install]
|
|
141
|
+
WantedBy=multi-user.target
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## セキュリティ
|
|
145
|
+
|
|
146
|
+
本ツールはネットワークの DHCP サーバーの設定を書き換えます。
|
|
147
|
+
書き込み権限を得た者は、LAN 上のあらゆる端末に任意の IP アドレス・ゲートウェイ・
|
|
148
|
+
DNS サーバーを配布できます。アクセス権はそれに見合った扱いをしてください。
|
|
149
|
+
|
|
150
|
+
- **認証もネットワーク公開も既定では無効です。** `--host` を指定しない限り
|
|
151
|
+
`127.0.0.1` を待ち受けます。`--auth` なしで非ループバックアドレスへ公開しようとすると
|
|
152
|
+
起動を拒否します (他の手段でポートを保護している場合のみ `--allow-no-auth` で解除可能)。
|
|
153
|
+
- **BASIC 認証は暗号化されません。** 信頼できないネットワークでは TLS 終端する
|
|
154
|
+
リバースプロキシの背後に置くか、VPN / SSH トンネル経由で利用してください。
|
|
155
|
+
例: `ssh -L 8080:127.0.0.1:8080 your-server`
|
|
156
|
+
- **書き込みは CSRF 対策済みです。** ブラウザが BASIC 認証の資格情報を自動送信するため、
|
|
157
|
+
`Origin` ヘッダによる同一オリジン検証を併用しています。
|
|
158
|
+
- **`--reload-command` はシェル経由で実行されます。** 実行されるのは管理者が
|
|
159
|
+
コマンドラインで指定した文字列のみですが、信頼できない入力から組み立てないでください。
|
|
160
|
+
- ダッシュボードとしてのみ使う場合は `--read-only` を利用してください。
|
|
161
|
+
|
|
162
|
+
### 脆弱性の報告
|
|
163
|
+
|
|
164
|
+
公開 Issue ではなく
|
|
165
|
+
[セキュリティアドバイザリ](https://github.com/akivajp/dnsmasq-webconf/security/advisories/new)
|
|
166
|
+
からご連絡ください。
|
|
167
|
+
|
|
168
|
+
> **v0.1.x からの移行についての注意**
|
|
169
|
+
> 既定の待ち受けアドレスが `0.0.0.0` から `127.0.0.1` に変更されました。
|
|
170
|
+
> また v0.1.x の保存 API には**認証が一切ありませんでした**。
|
|
171
|
+
> LAN 上で運用していた場合、そのポートに到達できる者は誰でも設定を書き換えられた状態でした。
|
|
172
|
+
> 詳細は [CHANGELOG.md](CHANGELOG.md) を参照してください。
|
|
173
|
+
|
|
174
|
+
## 保存処理の仕組み
|
|
175
|
+
|
|
176
|
+
1. ブラウザは変更したエントリのみを、**取得元の行番号**と**その行の原文**を添えて送信します。
|
|
177
|
+
2. サーバーは設定ファイルを読み直し、変更対象の各エントリについて、
|
|
178
|
+
該当行がブラウザの見ていた内容と一致するかを検証します。
|
|
179
|
+
3. 一致すればその 1 行だけを置き換えます。一致しない場合 (手動で編集した、
|
|
180
|
+
別のセッションが先に保存した等) は、**黙って上書きせず、スキップして結果を通知**します。
|
|
181
|
+
4. 書き込みは同一ディレクトリの一時ファイルへ行い、`os.replace()` で差し替えます。
|
|
182
|
+
そのため書き込みが中断されても設定ファイルは破損しません。
|
|
183
|
+
直前の内容は `<config>.bak` として保存されます (`--no-backup` で無効化可)。
|
|
184
|
+
|
|
185
|
+
削除したエントリは行を消すのではなく `##dhcp-host=...` として残すため、
|
|
186
|
+
後から手作業で復元できます。
|
|
187
|
+
|
|
188
|
+
## 対応範囲と制限
|
|
189
|
+
|
|
190
|
+
本ツールは意図的に対象を絞っており、`dhcp-host=` ディレクティブ**のみ**を解析・編集します。
|
|
191
|
+
|
|
192
|
+
非対応: `dhcp-range`、`dhcp-option`、DNS レコード (`address=`、`cname=`)、
|
|
193
|
+
IPv6 予約、クエリログ、統計、複数ユーザーのアクセス制御。
|
|
194
|
+
|
|
195
|
+
解釈できない行はそのまま保持されるため、それらは手作業で併用管理できます。
|
|
196
|
+
|
|
197
|
+
## 代替ツール
|
|
198
|
+
|
|
199
|
+
| プロジェクト | 向いている用途 |
|
|
200
|
+
|---|---|
|
|
201
|
+
| [Pi-hole](https://pi-hole.net/) | 広告ブロック込みの DNS/DHCP 統合アプライアンス。ただし v6 以降は `dnsmasq.conf` を自ら生成するため、手書きの設定ファイルは読みません |
|
|
202
|
+
| [OpenWrt LuCI](https://openwrt.org/docs/guide-user/luci/luci.essentials) / pfSense / OPNsense | すでにルーター OS を運用している場合。標準機能として内蔵されています |
|
|
203
|
+
| [dnsmasq-manager](https://github.com/gringolito/dnsmasq-manager) | UI ではなく REST API で静的リースを自動化したい場合。JWT 認証とディストリビューション向けパッケージあり |
|
|
204
|
+
| [dnsmasq-leases-ui](https://github.com/fschlag/dnsmasq-leases-ui) | リース一覧の閲覧のみをコンテナで行いたい場合 |
|
|
205
|
+
| [nexus-dnsmasq-mgr](https://github.com/brainchillz/nexus-dnsmasq-mgr) | DNS オーバーライド、PXE ブート、`dnsmasq --test` による検証など、より広範な機能が必要な場合 |
|
|
206
|
+
|
|
207
|
+
## 開発
|
|
208
|
+
|
|
209
|
+
```shell
|
|
210
|
+
git clone https://github.com/akivajp/dnsmasq-webconf.git
|
|
211
|
+
cd dnsmasq-webconf
|
|
212
|
+
uv venv && uv pip install -e '.[dev]'
|
|
213
|
+
uv run pytest
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
同梱している jQuery / Bootstrap とチェックサムのマニフェストを更新する場合:
|
|
217
|
+
|
|
218
|
+
```shell
|
|
219
|
+
scripts/update-vendor.sh
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
コントリビューションを歓迎します。
|
|
223
|
+
「ユーザーが変更していない行は書き換えない」という保証を壊さないようにし、
|
|
224
|
+
その点を検証するテストを添えてください。
|
|
225
|
+
|
|
226
|
+
## ライセンス
|
|
227
|
+
|
|
228
|
+
MIT — [LICENSE](LICENSE) を参照してください。
|
|
229
|
+
|
|
230
|
+
同梱しているサードパーティアセット (jQuery、Bootstrap) は MIT ライセンスです。
|
|
231
|
+
バージョン・取得元・チェックサムは
|
|
232
|
+
[`dnsmasq_webconf/static/vendor/MANIFEST.txt`](dnsmasq_webconf/static/vendor/MANIFEST.txt)
|
|
233
|
+
に記録しています。
|