ipmg 3.2.0__tar.gz → 4.0.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.
Files changed (107) hide show
  1. ipmg-4.0.0/PKG-INFO +254 -0
  2. ipmg-4.0.0/README.md +202 -0
  3. {ipmg-3.2.0 → ipmg-4.0.0}/pyproject.toml +20 -12
  4. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/__init__.py +1 -1
  5. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/cli/commands.py +6 -1
  6. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/cli/parser.py +20 -3
  7. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/ui.py +8 -3
  8. ipmg-4.0.0/src/ipmg/web/network.py +242 -0
  9. ipmg-4.0.0/src/ipmg/web/server.py +164 -0
  10. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/index.html +2 -2
  11. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/js/app.js +2 -2
  12. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/js/views.js +11 -3
  13. ipmg-4.0.0/src/ipmg.egg-info/PKG-INFO +254 -0
  14. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg.egg-info/SOURCES.txt +2 -0
  15. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg.egg-info/requires.txt +0 -2
  16. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_commands.py +1 -0
  17. ipmg-4.0.0/tests/test_web_network.py +263 -0
  18. ipmg-3.2.0/PKG-INFO +0 -1093
  19. ipmg-3.2.0/README.md +0 -1040
  20. ipmg-3.2.0/src/ipmg/web/server.py +0 -117
  21. ipmg-3.2.0/src/ipmg.egg-info/PKG-INFO +0 -1093
  22. {ipmg-3.2.0 → ipmg-4.0.0}/LICENSE +0 -0
  23. {ipmg-3.2.0 → ipmg-4.0.0}/setup.cfg +0 -0
  24. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/__main__.py +0 -0
  25. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/cli/__init__.py +0 -0
  26. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/cli/completion.py +0 -0
  27. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/cli/config.py +0 -0
  28. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/__init__.py +0 -0
  29. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/cron.py +0 -0
  30. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/diff.py +0 -0
  31. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/discovery.py +0 -0
  32. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/engine.py +0 -0
  33. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/health.py +0 -0
  34. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/httpcheck.py +0 -0
  35. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/neighbours.py +0 -0
  36. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/ping.py +0 -0
  37. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/portscan.py +0 -0
  38. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/security.py +0 -0
  39. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/core/wake.py +0 -0
  40. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/data/oui.tsv.gz +0 -0
  41. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/exceptions.py +0 -0
  42. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/infrastructure/__init__.py +0 -0
  43. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/infrastructure/database.py +0 -0
  44. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/infrastructure/file_io.py +0 -0
  45. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/infrastructure/incremental.py +0 -0
  46. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/infrastructure/notify.py +0 -0
  47. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/infrastructure/retention.py +0 -0
  48. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/__init__.py +0 -0
  49. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/diff_report.py +0 -0
  50. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/frames.py +0 -0
  51. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/live.py +0 -0
  52. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/machine.py +0 -0
  53. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/metrics.py +0 -0
  54. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/reporting/summary.py +0 -0
  55. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/services/__init__.py +0 -0
  56. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/services/history_service.py +0 -0
  57. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/services/scan_service.py +0 -0
  58. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/utils/__init__.py +0 -0
  59. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/utils/helpers.py +0 -0
  60. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/__init__.py +0 -0
  61. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/app.py +0 -0
  62. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/db.py +0 -0
  63. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/manager.py +0 -0
  64. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/scheduler.py +0 -0
  65. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/schemas.py +0 -0
  66. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/css/app.css +0 -0
  67. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/js/api.js +0 -0
  68. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/js/charts.js +0 -0
  69. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg/web/static/js/demo.js +0 -0
  70. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg.egg-info/dependency_links.txt +0 -0
  71. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg.egg-info/entry_points.txt +0 -0
  72. {ipmg-3.2.0 → ipmg-4.0.0}/src/ipmg.egg-info/top_level.txt +0 -0
  73. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_api_contract.py +0 -0
  74. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_completion.py +0 -0
  75. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_config.py +0 -0
  76. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_contrib.py +0 -0
  77. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_database_history.py +0 -0
  78. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_diff.py +0 -0
  79. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_diff_report.py +0 -0
  80. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_discover.py +0 -0
  81. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_engine.py +0 -0
  82. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_file_io.py +0 -0
  83. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_health.py +0 -0
  84. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_history_service.py +0 -0
  85. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_httpcheck.py +0 -0
  86. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_incremental.py +0 -0
  87. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_ipv6.py +0 -0
  88. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_live.py +0 -0
  89. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_machine_output.py +0 -0
  90. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_metrics.py +0 -0
  91. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_neighbours.py +0 -0
  92. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_notify.py +0 -0
  93. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_parser.py +0 -0
  94. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_ping.py +0 -0
  95. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_ping_command.py +0 -0
  96. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_portscan.py +0 -0
  97. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_retention.py +0 -0
  98. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_scan_service.py +0 -0
  99. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_schedules.py +0 -0
  100. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_tcp_probe.py +0 -0
  101. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_ui.py +0 -0
  102. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_utils.py +0 -0
  103. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_wake.py +0 -0
  104. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_web_api.py +0 -0
  105. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_web_db.py +0 -0
  106. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_web_manager.py +0 -0
  107. {ipmg-3.2.0 → ipmg-4.0.0}/tests/test_web_server.py +0 -0
ipmg-4.0.0/PKG-INFO ADDED
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: ipmg
3
+ Version: 4.0.0
4
+ Summary: Network discovery and change detection: ping sweeps, scan history, and reports for what changed on your network
5
+ Author: Sameer Alam
6
+ Maintainer-email: Sameer Alam <sameeralam3127@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://sameeralam3127.github.io/ipmg/
9
+ Project-URL: Documentation, https://github.com/sameeralam3127/ipmg#readme
10
+ Project-URL: Repository, https://github.com/sameeralam3127/ipmg
11
+ Project-URL: Issues, https://github.com/sameeralam3127/ipmg/issues
12
+ Project-URL: Changelog, https://github.com/sameeralam3127/ipmg/releases
13
+ Keywords: ip,network,ping,monitoring,cli,port-scan,network-scanner,ping-sweep,subnet-scanner,homelab,sysadmin
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Internet
22
+ Classifier: Topic :: System :: Networking
23
+ Classifier: Topic :: System :: Monitoring
24
+ Classifier: Intended Audience :: System Administrators
25
+ Classifier: Intended Audience :: Information Technology
26
+ Classifier: Operating System :: OS Independent
27
+ Classifier: Environment :: Console
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: openpyxl>=3.1
32
+ Requires-Dist: rich>=13.0
33
+ Requires-Dist: tomli>=2.0.1; python_version < "3.11"
34
+ Provides-Extra: web
35
+ Requires-Dist: fastapi>=0.110; extra == "web"
36
+ Requires-Dist: pydantic>=2.7; extra == "web"
37
+ Requires-Dist: uvicorn>=0.27; extra == "web"
38
+ Requires-Dist: websockets>=12; extra == "web"
39
+ Requires-Dist: python-multipart>=0.0.9; extra == "web"
40
+ Provides-Extra: all
41
+ Requires-Dist: ipmg[web]; extra == "all"
42
+ Provides-Extra: dev
43
+ Requires-Dist: ipmg[web]; extra == "dev"
44
+ Requires-Dist: pytest>=7.4; extra == "dev"
45
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
46
+ Requires-Dist: ruff>=0.4; extra == "dev"
47
+ Requires-Dist: pre-commit>=3.5.0; extra == "dev"
48
+ Requires-Dist: python-semantic-release>=10.5.3; extra == "dev"
49
+ Requires-Dist: httpx>=0.27; extra == "dev"
50
+ Requires-Dist: httpx2>=2.0; extra == "dev"
51
+ Dynamic: license-file
52
+
53
+ # IPMG — IP Management & Ping Monitoring Tool
54
+
55
+ [![PyPI](https://img.shields.io/pypi/v/ipmg)](https://pypi.org/project/ipmg/)
56
+ ![Python Version](https://img.shields.io/badge/python-3.10%2B-blue)
57
+ ![License](https://img.shields.io/badge/license-MIT-green)
58
+ [![Publish](https://github.com/sameeralam3127/ipmg/actions/workflows/publish.yml/badge.svg)](https://github.com/sameeralam3127/ipmg/actions/workflows/publish.yml)
59
+
60
+ **Know what changed on your network since the last scan.**
61
+
62
+ IPMG scans IPs, CIDR blocks, and ranges in parallel, keeps a history of every
63
+ scan, and tells you what moved between two of them: hosts that went offline or
64
+ appeared, IP addresses, hostnames, and MAC addresses that changed, latency that
65
+ shifted, web services that started failing. Every change carries a severity,
66
+ so only the ones that matter reach Slack, Teams, a webhook, or email, or fail a
67
+ cron job or CI step. Use it from the command line or from IPMG Web, a local
68
+ dashboard that works offline.
69
+
70
+ <p align="center">
71
+ <img src="https://raw.githubusercontent.com/sameeralam3127/ipmg/main/docs/assets/ipmg-compare.gif" alt="ipmg scans 13 hosts with --stream, printing each one as it answers; a new address is added to the target file; a second scan with --compare reports it as a new host (warning) against the first" width="820">
72
+ </p>
73
+
74
+ ```bash
75
+ curl -sSL https://raw.githubusercontent.com/sameeralam3127/ipmg/main/install.sh | bash
76
+ ipmg --discover # scan the network you are on, right now
77
+ ipmg --discover --compare # later: scan again and see what changed
78
+ ipmg web --lan # open the dashboard from any machine on your network
79
+ ```
80
+
81
+ > **Please read:** only scan networks you are authorized to scan. Unauthorized
82
+ > scanning may violate your organization's policies or the law.
83
+
84
+ **Website:** [sameeralam3127.github.io/ipmg](https://sameeralam3127.github.io/ipmg/) ·
85
+ **Live demo:** [IPMG Web with sample data](https://sameeralam3127.github.io/ipmg/demo/) ·
86
+ **Command builder:** [pick what you want, copy the command](https://sameeralam3127.github.io/ipmg/#builder) ·
87
+ **Docs:** [everything else](#documentation)
88
+
89
+ ---
90
+
91
+ ## What it does
92
+
93
+ - **Scans fast, without root.** IPv4 and IPv6, CIDR blocks, ranges, and
94
+ target files (text, CSV, Excel, JSON), `--threads` hosts at a time, using
95
+ your system's own `ping`.
96
+ - **Finds hosts that block ping** with TCP probes (`--probe icmp,tcp`), and
97
+ checks web services (`--http-check`: status, response time, TLS, certificate
98
+ expiry).
99
+ - **Identifies devices** by reverse DNS name and, on your LAN, by MAC address
100
+ and vendor (`--mac`). Wakes them with Wake-on-LAN (`ipmg wake`).
101
+ - **Remembers every scan** and reports what changed, with severities and
102
+ alerts to Slack, Teams, webhooks, or email.
103
+ - **Fits into automation:** exit codes for cron and CI, a GitHub Action,
104
+ `--json` for scripts, systemd and launchd templates, Prometheus metrics.
105
+ - **IPMG Web**, a local dashboard: live scans, history, changes, inventory,
106
+ and scheduled scans.
107
+ - **Reports** in Excel, CSV, JSON, JSON Lines, and Markdown, written as the
108
+ scan runs, so an interrupted scan keeps its results and can be resumed.
109
+
110
+ [How it compares](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMPARISON.md)
111
+ with nmap, fping, and Uptime Kuma.
112
+
113
+ ---
114
+
115
+ ## Install
116
+
117
+ **Linux and macOS**, on any distribution, with no Python needed:
118
+
119
+ ```bash
120
+ curl -sSL https://raw.githubusercontent.com/sameeralam3127/ipmg/main/install.sh | bash
121
+ ```
122
+
123
+ **Windows** (PowerShell, no administrator rights):
124
+
125
+ ```powershell
126
+ irm https://raw.githubusercontent.com/sameeralam3127/ipmg/main/install.ps1 | iex
127
+ ```
128
+
129
+ **Homebrew:** `brew install sameeralam3127/tap/ipmg` ·
130
+ **uv:** `uv tool install --python ">=3.10" "ipmg[web]"` ·
131
+ **pipx:** `pipx install "ipmg[web]"` ·
132
+ **Docker:** `docker run --rm ghcr.io/sameeralam3127/ipmg --input 10.0.0.0/24`
133
+
134
+ IPMG needs Python 3.10 or newer (the installers bring their own) and the
135
+ system `ping` command. Minimal images, version pinning, upgrading from 3.x,
136
+ tab completion, and the systems CI verifies are in the
137
+ [install guide](https://github.com/sameeralam3127/ipmg/blob/main/docs/INSTALL.md).
138
+
139
+ ---
140
+
141
+ ## Your first scan
142
+
143
+ ```bash
144
+ ipmg --input 192.168.1.0/24 --stream # each host as it answers
145
+ ```
146
+
147
+ ```text
148
+ ipmg X.Y.Z · scan
149
+ ICMP probes only — scan only networks you are authorized to scan.
150
+
151
+ Source 192.168.1.0/24
152
+ Targets 254 hosts
153
+ Config 50 threads · 2s timeout · 1 ping
154
+
155
+ Results
156
+ ● Active 12 ━─────────────────────── 4.7%
157
+ ● Timeout 242 ━━━━━━━━━━━━━━━━━━━━━━━━ 95.3%
158
+
159
+ 254 hosts · 4.7% active · 3.1 ms avg · 5.21s · 2026-10-18 09:15:02
160
+
161
+ Saved results_20261018_091502.xlsx
162
+ ```
163
+
164
+ Every scan is stored in a local history (`~/.ipmg/dashboard.db`). Scan again
165
+ with `--compare` to see what changed, or open IPMG Web to browse it.
166
+
167
+ ---
168
+
169
+ ## Common tasks
170
+
171
+ | I want to… | Command |
172
+ | --- | --- |
173
+ | Scan the network I am on | `ipmg --discover` |
174
+ | Scan hosts listed in a file, plus a few more | `ipmg --input targets.txt 10.0.0.5` |
175
+ | See what changed since last time | `ipmg --input targets.txt --compare` |
176
+ | Get alerted when something changes | `ipmg --input targets.txt --interval 15 --notify-slack` |
177
+ | Find hosts that block ping | `ipmg --input 10.0.0.0/24 --probe icmp,tcp` |
178
+ | Know which device each address is | `ipmg --discover --resolve --mac` |
179
+ | Check that a web service works | `ipmg --http-check https://intranet.example.com/` |
180
+ | See which services are listening | `ipmg --input targets.txt --scan-ports` |
181
+ | Get a report I can send to someone | `ipmg --input targets.txt --formats md csv` |
182
+ | Pipe the results into a script | `ipmg --input targets.txt --json \| jq .` |
183
+ | Fail a cron job or CI step when hosts are down | `ipmg --input servers.txt --fail-on-down` |
184
+ | Wake a machine | `ipmg wake AA:BB:CC:DD:EE:FF` |
185
+ | Use the dashboard from another machine | `ipmg web --lan` |
186
+ | Keep it running after logout and reboots | [systemd and launchd templates](https://github.com/sameeralam3127/ipmg/blob/main/docs/SERVICES.md) |
187
+ | See every option | `ipmg --help`, or the [command reference](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMMANDS.md) |
188
+
189
+ ---
190
+
191
+ ## IPMG Web
192
+
193
+ ```bash
194
+ ipmg web # this machine: opens http://127.0.0.1:8080 in your browser
195
+ ipmg web --lan # any machine on your network: prints the link to open
196
+ ```
197
+
198
+ With `--lan`, IPMG Web prints the link with this machine's address and access
199
+ token, checks the firewall, and tells you the exact command that opens the
200
+ port if it is blocked (`sudo ipmg web --open-firewall` opens it only while
201
+ IPMG Web runs). Every request needs the token in that link.
202
+
203
+ <p align="center">
204
+ <img src="https://raw.githubusercontent.com/sameeralam3127/ipmg/main/docs/assets/ipmg-web.png" alt="IPMG Web dashboard: scan totals, a status donut of 16 active, 1 timeout and 1 inactive host, a latency trend chart, and a list of recent scans" width="820">
205
+ </p>
206
+
207
+ Dashboard, live monitor, history, changes, inventory with Wake-on-LAN, and
208
+ scheduled scans; see the
209
+ [IPMG Web guide](https://github.com/sameeralam3127/ipmg/blob/main/docs/WEB.md).
210
+ Try it first with the [live demo](https://sameeralam3127.github.io/ipmg/demo/).
211
+
212
+ ---
213
+
214
+ ## Documentation
215
+
216
+ | Guide | What is in it |
217
+ | --- | --- |
218
+ | [Install](https://github.com/sameeralam3127/ipmg/blob/main/docs/INSTALL.md) | Installers, Docker, pip, Python versions, upgrading from 3.x, tab completion, verified systems |
219
+ | [Command reference](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMMANDS.md) | Every command and flag with examples: targets, probes, HTTP checks, reports, history, change detection, notifications, `ipmg.toml`, exit codes |
220
+ | [IPMG Web](https://github.com/sameeralam3127/ipmg/blob/main/docs/WEB.md) | The dashboard, opening it from other machines, the firewall, scheduled scans, Prometheus metrics |
221
+ | [Web API](https://github.com/sameeralam3127/ipmg/blob/main/docs/API.md) | Scripting IPMG Web over HTTP and WebSocket |
222
+ | [Running as a service](https://github.com/sameeralam3127/ipmg/blob/main/docs/SERVICES.md) | systemd and launchd templates for scheduled scans and IPMG Web |
223
+ | [GitHub Action](https://github.com/sameeralam3127/ipmg/blob/main/docs/GITHUB-ACTION.md) | Reachability checks in CI, before a deploy or on a schedule |
224
+ | [How it compares](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMPARISON.md) | IPMG next to nmap, fping, and Uptime Kuma |
225
+ | [Troubleshooting](https://github.com/sameeralam3127/ipmg/blob/main/docs/TROUBLESHOOTING.md) and [FAQ](https://github.com/sameeralam3127/ipmg/blob/main/docs/FAQ.md) | Install errors, timeouts, slow scans, empty MAC addresses, common questions |
226
+ | [Architecture](https://github.com/sameeralam3127/ipmg/blob/main/docs/ARCHITECTURE.md) | How the code fits together, for contributors |
227
+
228
+ ---
229
+
230
+ ## Security
231
+
232
+ IPMG runs `ping` as a direct process call with no shell, validates every
233
+ target first, and needs no root. IPMG Web listens on `127.0.0.1` unless you
234
+ pass `--lan`, serves everything locally, and requires its access token on
235
+ every request, behind a strict Content-Security-Policy. The only outbound
236
+ requests IPMG makes are the notifications and HTTP checks you ask for. Found a
237
+ vulnerability? See
238
+ [SECURITY.md](https://github.com/sameeralam3127/ipmg/blob/main/.github/SECURITY.md).
239
+
240
+ ---
241
+
242
+ ## Contributing
243
+
244
+ Contributions are welcome.
245
+ [CONTRIBUTING.md](https://github.com/sameeralam3127/ipmg/blob/main/.github/CONTRIBUTING.md)
246
+ covers the development setup, the tests, and the commit format that drives
247
+ releases, and
248
+ [ARCHITECTURE.md](https://github.com/sameeralam3127/ipmg/blob/main/docs/ARCHITECTURE.md)
249
+ explains the code. Everyone taking part is expected to follow the
250
+ [Code of Conduct](https://github.com/sameeralam3127/ipmg/blob/main/.github/CODE_OF_CONDUCT.md).
251
+
252
+ ## License
253
+
254
+ MIT — free for commercial and personal use.
ipmg-4.0.0/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # IPMG — IP Management & Ping Monitoring Tool
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/ipmg)](https://pypi.org/project/ipmg/)
4
+ ![Python Version](https://img.shields.io/badge/python-3.10%2B-blue)
5
+ ![License](https://img.shields.io/badge/license-MIT-green)
6
+ [![Publish](https://github.com/sameeralam3127/ipmg/actions/workflows/publish.yml/badge.svg)](https://github.com/sameeralam3127/ipmg/actions/workflows/publish.yml)
7
+
8
+ **Know what changed on your network since the last scan.**
9
+
10
+ IPMG scans IPs, CIDR blocks, and ranges in parallel, keeps a history of every
11
+ scan, and tells you what moved between two of them: hosts that went offline or
12
+ appeared, IP addresses, hostnames, and MAC addresses that changed, latency that
13
+ shifted, web services that started failing. Every change carries a severity,
14
+ so only the ones that matter reach Slack, Teams, a webhook, or email, or fail a
15
+ cron job or CI step. Use it from the command line or from IPMG Web, a local
16
+ dashboard that works offline.
17
+
18
+ <p align="center">
19
+ <img src="https://raw.githubusercontent.com/sameeralam3127/ipmg/main/docs/assets/ipmg-compare.gif" alt="ipmg scans 13 hosts with --stream, printing each one as it answers; a new address is added to the target file; a second scan with --compare reports it as a new host (warning) against the first" width="820">
20
+ </p>
21
+
22
+ ```bash
23
+ curl -sSL https://raw.githubusercontent.com/sameeralam3127/ipmg/main/install.sh | bash
24
+ ipmg --discover # scan the network you are on, right now
25
+ ipmg --discover --compare # later: scan again and see what changed
26
+ ipmg web --lan # open the dashboard from any machine on your network
27
+ ```
28
+
29
+ > **Please read:** only scan networks you are authorized to scan. Unauthorized
30
+ > scanning may violate your organization's policies or the law.
31
+
32
+ **Website:** [sameeralam3127.github.io/ipmg](https://sameeralam3127.github.io/ipmg/) ·
33
+ **Live demo:** [IPMG Web with sample data](https://sameeralam3127.github.io/ipmg/demo/) ·
34
+ **Command builder:** [pick what you want, copy the command](https://sameeralam3127.github.io/ipmg/#builder) ·
35
+ **Docs:** [everything else](#documentation)
36
+
37
+ ---
38
+
39
+ ## What it does
40
+
41
+ - **Scans fast, without root.** IPv4 and IPv6, CIDR blocks, ranges, and
42
+ target files (text, CSV, Excel, JSON), `--threads` hosts at a time, using
43
+ your system's own `ping`.
44
+ - **Finds hosts that block ping** with TCP probes (`--probe icmp,tcp`), and
45
+ checks web services (`--http-check`: status, response time, TLS, certificate
46
+ expiry).
47
+ - **Identifies devices** by reverse DNS name and, on your LAN, by MAC address
48
+ and vendor (`--mac`). Wakes them with Wake-on-LAN (`ipmg wake`).
49
+ - **Remembers every scan** and reports what changed, with severities and
50
+ alerts to Slack, Teams, webhooks, or email.
51
+ - **Fits into automation:** exit codes for cron and CI, a GitHub Action,
52
+ `--json` for scripts, systemd and launchd templates, Prometheus metrics.
53
+ - **IPMG Web**, a local dashboard: live scans, history, changes, inventory,
54
+ and scheduled scans.
55
+ - **Reports** in Excel, CSV, JSON, JSON Lines, and Markdown, written as the
56
+ scan runs, so an interrupted scan keeps its results and can be resumed.
57
+
58
+ [How it compares](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMPARISON.md)
59
+ with nmap, fping, and Uptime Kuma.
60
+
61
+ ---
62
+
63
+ ## Install
64
+
65
+ **Linux and macOS**, on any distribution, with no Python needed:
66
+
67
+ ```bash
68
+ curl -sSL https://raw.githubusercontent.com/sameeralam3127/ipmg/main/install.sh | bash
69
+ ```
70
+
71
+ **Windows** (PowerShell, no administrator rights):
72
+
73
+ ```powershell
74
+ irm https://raw.githubusercontent.com/sameeralam3127/ipmg/main/install.ps1 | iex
75
+ ```
76
+
77
+ **Homebrew:** `brew install sameeralam3127/tap/ipmg` ·
78
+ **uv:** `uv tool install --python ">=3.10" "ipmg[web]"` ·
79
+ **pipx:** `pipx install "ipmg[web]"` ·
80
+ **Docker:** `docker run --rm ghcr.io/sameeralam3127/ipmg --input 10.0.0.0/24`
81
+
82
+ IPMG needs Python 3.10 or newer (the installers bring their own) and the
83
+ system `ping` command. Minimal images, version pinning, upgrading from 3.x,
84
+ tab completion, and the systems CI verifies are in the
85
+ [install guide](https://github.com/sameeralam3127/ipmg/blob/main/docs/INSTALL.md).
86
+
87
+ ---
88
+
89
+ ## Your first scan
90
+
91
+ ```bash
92
+ ipmg --input 192.168.1.0/24 --stream # each host as it answers
93
+ ```
94
+
95
+ ```text
96
+ ipmg X.Y.Z · scan
97
+ ICMP probes only — scan only networks you are authorized to scan.
98
+
99
+ Source 192.168.1.0/24
100
+ Targets 254 hosts
101
+ Config 50 threads · 2s timeout · 1 ping
102
+
103
+ Results
104
+ ● Active 12 ━─────────────────────── 4.7%
105
+ ● Timeout 242 ━━━━━━━━━━━━━━━━━━━━━━━━ 95.3%
106
+
107
+ 254 hosts · 4.7% active · 3.1 ms avg · 5.21s · 2026-10-18 09:15:02
108
+
109
+ Saved results_20261018_091502.xlsx
110
+ ```
111
+
112
+ Every scan is stored in a local history (`~/.ipmg/dashboard.db`). Scan again
113
+ with `--compare` to see what changed, or open IPMG Web to browse it.
114
+
115
+ ---
116
+
117
+ ## Common tasks
118
+
119
+ | I want to… | Command |
120
+ | --- | --- |
121
+ | Scan the network I am on | `ipmg --discover` |
122
+ | Scan hosts listed in a file, plus a few more | `ipmg --input targets.txt 10.0.0.5` |
123
+ | See what changed since last time | `ipmg --input targets.txt --compare` |
124
+ | Get alerted when something changes | `ipmg --input targets.txt --interval 15 --notify-slack` |
125
+ | Find hosts that block ping | `ipmg --input 10.0.0.0/24 --probe icmp,tcp` |
126
+ | Know which device each address is | `ipmg --discover --resolve --mac` |
127
+ | Check that a web service works | `ipmg --http-check https://intranet.example.com/` |
128
+ | See which services are listening | `ipmg --input targets.txt --scan-ports` |
129
+ | Get a report I can send to someone | `ipmg --input targets.txt --formats md csv` |
130
+ | Pipe the results into a script | `ipmg --input targets.txt --json \| jq .` |
131
+ | Fail a cron job or CI step when hosts are down | `ipmg --input servers.txt --fail-on-down` |
132
+ | Wake a machine | `ipmg wake AA:BB:CC:DD:EE:FF` |
133
+ | Use the dashboard from another machine | `ipmg web --lan` |
134
+ | Keep it running after logout and reboots | [systemd and launchd templates](https://github.com/sameeralam3127/ipmg/blob/main/docs/SERVICES.md) |
135
+ | See every option | `ipmg --help`, or the [command reference](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMMANDS.md) |
136
+
137
+ ---
138
+
139
+ ## IPMG Web
140
+
141
+ ```bash
142
+ ipmg web # this machine: opens http://127.0.0.1:8080 in your browser
143
+ ipmg web --lan # any machine on your network: prints the link to open
144
+ ```
145
+
146
+ With `--lan`, IPMG Web prints the link with this machine's address and access
147
+ token, checks the firewall, and tells you the exact command that opens the
148
+ port if it is blocked (`sudo ipmg web --open-firewall` opens it only while
149
+ IPMG Web runs). Every request needs the token in that link.
150
+
151
+ <p align="center">
152
+ <img src="https://raw.githubusercontent.com/sameeralam3127/ipmg/main/docs/assets/ipmg-web.png" alt="IPMG Web dashboard: scan totals, a status donut of 16 active, 1 timeout and 1 inactive host, a latency trend chart, and a list of recent scans" width="820">
153
+ </p>
154
+
155
+ Dashboard, live monitor, history, changes, inventory with Wake-on-LAN, and
156
+ scheduled scans; see the
157
+ [IPMG Web guide](https://github.com/sameeralam3127/ipmg/blob/main/docs/WEB.md).
158
+ Try it first with the [live demo](https://sameeralam3127.github.io/ipmg/demo/).
159
+
160
+ ---
161
+
162
+ ## Documentation
163
+
164
+ | Guide | What is in it |
165
+ | --- | --- |
166
+ | [Install](https://github.com/sameeralam3127/ipmg/blob/main/docs/INSTALL.md) | Installers, Docker, pip, Python versions, upgrading from 3.x, tab completion, verified systems |
167
+ | [Command reference](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMMANDS.md) | Every command and flag with examples: targets, probes, HTTP checks, reports, history, change detection, notifications, `ipmg.toml`, exit codes |
168
+ | [IPMG Web](https://github.com/sameeralam3127/ipmg/blob/main/docs/WEB.md) | The dashboard, opening it from other machines, the firewall, scheduled scans, Prometheus metrics |
169
+ | [Web API](https://github.com/sameeralam3127/ipmg/blob/main/docs/API.md) | Scripting IPMG Web over HTTP and WebSocket |
170
+ | [Running as a service](https://github.com/sameeralam3127/ipmg/blob/main/docs/SERVICES.md) | systemd and launchd templates for scheduled scans and IPMG Web |
171
+ | [GitHub Action](https://github.com/sameeralam3127/ipmg/blob/main/docs/GITHUB-ACTION.md) | Reachability checks in CI, before a deploy or on a schedule |
172
+ | [How it compares](https://github.com/sameeralam3127/ipmg/blob/main/docs/COMPARISON.md) | IPMG next to nmap, fping, and Uptime Kuma |
173
+ | [Troubleshooting](https://github.com/sameeralam3127/ipmg/blob/main/docs/TROUBLESHOOTING.md) and [FAQ](https://github.com/sameeralam3127/ipmg/blob/main/docs/FAQ.md) | Install errors, timeouts, slow scans, empty MAC addresses, common questions |
174
+ | [Architecture](https://github.com/sameeralam3127/ipmg/blob/main/docs/ARCHITECTURE.md) | How the code fits together, for contributors |
175
+
176
+ ---
177
+
178
+ ## Security
179
+
180
+ IPMG runs `ping` as a direct process call with no shell, validates every
181
+ target first, and needs no root. IPMG Web listens on `127.0.0.1` unless you
182
+ pass `--lan`, serves everything locally, and requires its access token on
183
+ every request, behind a strict Content-Security-Policy. The only outbound
184
+ requests IPMG makes are the notifications and HTTP checks you ask for. Found a
185
+ vulnerability? See
186
+ [SECURITY.md](https://github.com/sameeralam3127/ipmg/blob/main/.github/SECURITY.md).
187
+
188
+ ---
189
+
190
+ ## Contributing
191
+
192
+ Contributions are welcome.
193
+ [CONTRIBUTING.md](https://github.com/sameeralam3127/ipmg/blob/main/.github/CONTRIBUTING.md)
194
+ covers the development setup, the tests, and the commit format that drives
195
+ releases, and
196
+ [ARCHITECTURE.md](https://github.com/sameeralam3127/ipmg/blob/main/docs/ARCHITECTURE.md)
197
+ explains the code. Everyone taking part is expected to follow the
198
+ [Code of Conduct](https://github.com/sameeralam3127/ipmg/blob/main/.github/CODE_OF_CONDUCT.md).
199
+
200
+ ## License
201
+
202
+ MIT — free for commercial and personal use.
@@ -13,10 +13,10 @@ build-backend = "setuptools.build_meta"
13
13
 
14
14
  [project]
15
15
  name = "ipmg"
16
- version = "3.2.0" # Managed automatically by semantic-release
16
+ version = "4.0.0" # Managed automatically by semantic-release
17
17
  description = "Network discovery and change detection: ping sweeps, scan history, and reports for what changed on your network"
18
18
  readme = "README.md"
19
- requires-python = ">=3.9"
19
+ requires-python = ">=3.10"
20
20
  license = "MIT"
21
21
  license-files = ["LICENSE"]
22
22
 
@@ -33,7 +33,6 @@ keywords = ["ip", "network", "ping", "monitoring", "cli", "port-scan", "network-
33
33
  classifiers = [
34
34
  "Programming Language :: Python :: 3",
35
35
  "Programming Language :: Python :: 3 :: Only",
36
- "Programming Language :: Python :: 3.9",
37
36
  "Programming Language :: Python :: 3.10",
38
37
  "Programming Language :: Python :: 3.11",
39
38
  "Programming Language :: Python :: 3.12",
@@ -84,10 +83,10 @@ dev = [
84
83
  "pre-commit>=3.5.0",
85
84
  "python-semantic-release>=10.5.3",
86
85
  # The TestClient's HTTP client. Starlette 1.x wants httpx2 and warns
87
- # about httpx; the Starlette releases Python 3.9 and the lowest-deps job
88
- # resolve to predate httpx2 and need httpx.
86
+ # about httpx; the older Starlette the lowest-deps job resolves to
87
+ # predates httpx2 and needs httpx.
89
88
  "httpx>=0.27",
90
- "httpx2>=2.0; python_version >= '3.10'",
89
+ "httpx2>=2.0",
91
90
  ]
92
91
 
93
92
  [project.scripts]
@@ -107,10 +106,10 @@ dev = [
107
106
  "pre-commit>=3.5.0",
108
107
  "python-semantic-release>=10.5.3",
109
108
  # The TestClient's HTTP client. Starlette 1.x wants httpx2 and warns
110
- # about httpx; the Starlette releases Python 3.9 and the lowest-deps job
111
- # resolve to predate httpx2 and need httpx.
109
+ # about httpx; the older Starlette the lowest-deps job resolves to
110
+ # predates httpx2 and needs httpx.
112
111
  "httpx>=0.27",
113
- "httpx2>=2.0; python_version >= '3.10'",
112
+ "httpx2>=2.0",
114
113
  ]
115
114
 
116
115
 
@@ -121,7 +120,6 @@ dev = [
121
120
  # Publishing is done by the workflow (pypa/gh-action-pypi-publish), not by
122
121
  # semantic-release itself.
123
122
  [tool.semantic_release]
124
- branch = "main"
125
123
  version_toml = ["pyproject.toml:project.version"]
126
124
  version_variables = ["src/ipmg/__init__.py:__version__"]
127
125
  tag_format = "v{version}"
@@ -129,6 +127,16 @@ commit_message = "chore(release): {version}"
129
127
  build_command = "python -m build"
130
128
  major_on_zero = false
131
129
 
130
+ # main releases; v4 releases betas (4.0.0-beta.N) until it merges into main.
131
+ [tool.semantic_release.branches.main]
132
+ match = "^main$"
133
+ prerelease = false
134
+
135
+ [tool.semantic_release.branches.v4]
136
+ match = "^v4$"
137
+ prerelease = true
138
+ prerelease_token = "beta"
139
+
132
140
  [tool.semantic_release.changelog.default_templates]
133
141
  changelog_file = ".github/CHANGELOG.md"
134
142
 
@@ -178,7 +186,7 @@ fail_under = 90
178
186
 
179
187
  [tool.ruff]
180
188
  line-length = 100
181
- target-version = "py39"
189
+ target-version = "py310"
182
190
 
183
191
  [tool.ruff.lint]
184
192
  select = ["E", "F", "W", "I", "C90"]
@@ -195,4 +203,4 @@ known-first-party = ["ipmg"]
195
203
 
196
204
  [tool.black]
197
205
  line-length = 100
198
- target-version = ["py39"]
206
+ target-version = ["py310"]
@@ -2,4 +2,4 @@
2
2
  ipmg - IP Management & Ping Monitoring Tool
3
3
  """
4
4
 
5
- __version__ = "3.2.0"
5
+ __version__ = "4.0.0"
@@ -40,6 +40,9 @@ WEB_EXTRA_MISSING = (
40
40
  " pip install 'ipmg[web]'"
41
41
  )
42
42
 
43
+ #: Where ``ipmg web --lan`` listens; only ever used when asked for with --lan.
44
+ ALL_INTERFACES = "0.0.0.0" # nosec B104
45
+
43
46
  EXIT_OK = 0
44
47
  EXIT_ERROR = 1
45
48
  EXIT_CHANGES_DETECTED = 2
@@ -96,13 +99,15 @@ def _web_command(argv: List[str]) -> int:
96
99
  raise
97
100
  raise IPMGError(WEB_EXTRA_MISSING) from exc
98
101
 
102
+ host = args.host or (ALL_INTERFACES if args.lan or args.open_firewall else "127.0.0.1")
99
103
  run_dashboard(
100
- host=args.host,
104
+ host=host,
101
105
  port=args.port,
102
106
  open_browser=not args.no_browser,
103
107
  db_path=args.db,
104
108
  metrics_sources=max(args.metrics_sources, 1) if args.metrics else None,
105
109
  max_scans=max(args.max_scans, 1),
110
+ open_firewall=args.open_firewall,
106
111
  )
107
112
  return EXIT_OK
108
113
 
@@ -571,10 +571,19 @@ def build_web_parser() -> argparse.ArgumentParser:
571
571
  "ipmg web",
572
572
  description="Start IPMG Web, the local browser UI.",
573
573
  )
574
- parser.add_argument(
574
+ where = parser.add_mutually_exclusive_group()
575
+ where.add_argument(
575
576
  "--host",
576
- default="127.0.0.1",
577
- help="Interface to bind (default: 127.0.0.1, local only).",
577
+ default=None,
578
+ help="Interface to bind (default: 127.0.0.1, this machine only).",
579
+ )
580
+ where.add_argument(
581
+ "--lan",
582
+ action="store_true",
583
+ help=(
584
+ "Let other machines open IPMG Web: listen on every interface (as --host "
585
+ "0.0.0.0) and print the link with this machine's network address."
586
+ ),
578
587
  )
579
588
  parser.add_argument(
580
589
  "--port",
@@ -582,6 +591,14 @@ def build_web_parser() -> argparse.ArgumentParser:
582
591
  default=8080,
583
592
  help="Port to listen on (default: 8080).",
584
593
  )
594
+ parser.add_argument(
595
+ "--open-firewall",
596
+ action="store_true",
597
+ help=(
598
+ "Open the port in firewalld or ufw while IPMG Web runs, and close it again "
599
+ "when it stops (needs root; implies --lan)."
600
+ ),
601
+ )
585
602
  parser.add_argument(
586
603
  "--no-browser",
587
604
  action="store_true",
@@ -121,13 +121,18 @@ def heading(title: str) -> None:
121
121
  console.print(Text(INDENT + title, style="ipmg.heading"))
122
122
 
123
123
 
124
- def field(label: str, value: object, value_style: str = "ipmg.value") -> None:
125
- """One aligned ``label value`` line."""
124
+ def field(label: str, value: object, value_style: str = "ipmg.value", wrap: bool = True) -> None:
125
+ """One aligned ``label value`` line.
126
+
127
+ ``wrap=False`` keeps the value on one line however narrow the terminal,
128
+ for a URL or a command someone will copy: a line break rich inserted
129
+ would end up in the pasted text.
130
+ """
126
131
  text = Text(INDENT)
127
132
  # A label as long as the column still gets one space before its value.
128
133
  text.append(f"{label:<{LABEL_WIDTH - 1}} ", style="ipmg.label")
129
134
  text.append(str(value), style=value_style)
130
- console.print(text)
135
+ console.print(text, soft_wrap=not wrap)
131
136
 
132
137
 
133
138
  def fields(pairs: Iterable[Tuple[str, object]]) -> None: