|
1 | 1 | # Changelog |
2 | 2 |
|
| 3 | +## 1.3.0 — Themed UI, DRY consolidation, and a second correctness-hardening pass |
| 4 | + |
| 5 | +No CLI behavior is removed and no existing flag changes meaning; a script that worked against `1.2.0` still works. This pass focused on three things: a real terminal UI layer (colors driven by log level instead of hardcoded per call site), removing every remaining case of the same logic implemented two different ways across `nes.py`/`enum.py`/`das.py`, and a from-scratch re-audit of the whole `src/` tree that found and fixed a further round of real bugs beyond what `1.2.0`'s pass covered. |
| 6 | + |
| 7 | +### New capability |
| 8 | + |
| 9 | +- **Themed console output.** `src/core/theme.py` is now the single source of every ANSI color/style used anywhere in the tool. Console log lines get an automatic `[ DEBUG ]`/`[ INFO ]`/`[ FOUND ]`/`[ WARN ]`/`[ ERROR ]` tag, colored by level via a new `logging_config.ColorFormatter` — replacing the old convention of hardcoding escape codes and ad-hoc `[!]`/`[+]` string prefixes inline at each call site. A new custom `FOUND` log level (between `INFO` and `WARNING`) replaces the old `[+]` marker for "live host / valid extension found" results. Color auto-disables when `NO_COLOR` is set or stdout isn't a real terminal. |
| 10 | +- **New block-style startup banner**, colored through `theme.py`'s constants instead of raw escape codes baked into the banner string. |
| 11 | +- **Boxed run summaries.** Each module's final result line is now rendered as a bordered panel (`theme.panel()`) instead of a single unstyled log line. |
| 12 | +- **`TqdmLoggingHandler`** (`logging_config.py`) routes console logs through `tqdm.write()` instead of writing directly to stdout, so log lines during a scan no longer corrupt the live progress bar's line. |
| 13 | +- **SIP-ENUM blanket-rejection pre-check.** Before enumerating, ENUM now sends one probe per target with a random, guaranteed-nonexistent username; if the target responds 401/403 to it, ENUM warns that the server may be blanket-rejecting everything (e.g. modern PJSIP's default behavior — see F6 below), so the operator knows to treat results with suspicion instead of trusting a silent false-positive. |
| 14 | + |
| 15 | +### Architecture / DRY consolidation |
| 16 | + |
| 17 | +Per-module logic that had drifted into 2–4 different implementations of the same operation was consolidated to one: |
| 18 | + |
| 19 | +- `net_utils.read_lines()` / `net_utils.read_ip_list()` replace four divergent wordlist/`ip_list.txt`-reading implementations previously spread across `nes.py`, `enum.py`, and `das.py` (one of which silently skipped the `isalnum` filter the others applied). |
| 20 | +- `threadpool.confirm_bulk_run()` replaces near-identical copy-pasted "N packages will be generated, continue?" prompt-building code in `nes.py` and `enum.py`. |
| 21 | +- `net_utils._validate_dotted_quad()` replaces three separate copies of octet-range validation inside `check_ip_address()` (two of which were missing the `ValueError` guard the third had). |
| 22 | +- `net_utils.printResult()` now calls `decimal_to_octets()` instead of re-implementing the same int→dotted-IP conversion inline. |
| 23 | +- `nes.py`'s three copy-pasted target×user cross-product comprehensions were merged into one, computed once after `target_networks` is determined. |
| 24 | +- `net_utils.defineTargetType()` now calls `read_lines()` instead of manually re-implementing its split/filter logic (with a subtly different, unintended behavior — see Correctness fixes). |
| 25 | +- Dead `net_utils.readFile()` removed (its only caller was consolidated away). |
| 26 | +- New `net_utils.positive_int()` argparse validator for `--tc`/`--thread-count`. |
| 27 | +- `sip_packet._read_template()` caches `.message` template file reads (`functools.cache`) instead of re-opening the same file from disk on every `generate_packet()` call — the same class of redundant I/O already fixed for wordlists/`servers.txt` in `1.2.0` (F8/F16), just missed for the templates themselves. Matters most in DAS's flood loop, which calls this up to ~1e8 times at the default counter. |
| 28 | + |
| 29 | +### Correctness fixes |
| 30 | + |
| 31 | +- **The y/n confirmation prompt's `setraw`/`setcbreak` bug, actually fixed this time.** `1.2.0`'s changelog and the prior commit's message both claimed a switch from `tty.setraw()` to `tty.setcbreak()` to fix doubled/misaligned keypress output — but the code was never actually changed. `src/core/threadpool.py`'s `_read_single_char()` now genuinely calls `tty.setcbreak()`; verified live over a real controlling terminal (`setsid`/`TIOCSCTTY`) that a single `n` keypress renders correctly with no doubling. |
| 32 | +- **`net_utils.printResult()` no longer crashes on a malformed or incomplete SIP response.** `sip_packet.getResponse()` can return `{}` (unparseable status line), fall through to an implicit `None` (no headers past the status line), or store `None` for a header line with no `:`. `printResult()` used to index straight into `result["response"]["headers"]` and then `list(value)`, crashing with `KeyError`/`TypeError` on any of these — reachable from a single malformed reply during a live scan. Now guarded at every level. |
| 33 | +- **`--tc=0` (or negative) no longer hangs the tool forever.** `run_worker_pool()` starts `range(thread_count)` worker threads; a count below 1 meant no thread ever existed to drain the queue, so the run spun with no error message until manually killed. `--tc` now goes through the new `positive_int` validator. |
| 34 | +- **SIP-ENUM's single-username-wordlist off-by-one.** `if len(user_list) <= 1` rejected a wordlist containing exactly one valid entry as if it were empty, blocking the legitimate "enumerate exactly one extension" case. Now `if not user_list`. |
| 35 | +- **`logger.found()` no longer depends on import order.** The custom `FOUND` level is registered as an import-time side effect of `logging_config.py`; `net_utils.py` (which calls `logger.found()` in `printResult()`) now imports `logging_config` itself, so this works regardless of whether `cli.py` has already run first. |
| 36 | +- **`check_ip_address()`'s range and plain-IP branches now reject a non-numeric octet the same clean way the CIDR branch already did**, via the new shared `_validate_dotted_quad()` helper — previously they had no guard around `int(number)` (argparse's own exception handling happened to still produce a usable, if generic, error message, so this was never a raw crash, just an inconsistent one). |
| 37 | +- **`nes.py`'s file-vs-literal-value detection for `--from`/`--to` switched from a fragile `"txt" in value` substring check to `os.path.isfile(value)`.** The old check misclassified a literal username containing "txt" as a file, and a wordlist path without a literal `.txt` in it as a literal value. |
| 38 | +- **`net_utils.defineTargetType()`'s server-list matching now strips whitespace before filtering**, via the `read_lines()` consolidation above — the old manual re-implementation could silently drop a legitimate `servers.txt` entry with trailing whitespace or a stray `\r`. |
| 39 | +- **DAS: `-m` without `--il` now raises a clean error instead of a raw `TypeError`.** `args.manual_ip_list` defaults to `None`; `net_utils.read_ip_list(None)` used to call `open(None)` directly. |
| 40 | +- **DAS: `-s`/`--subnet` without a valid interface netmask now raises a clean error instead of crashing mid-flood.** A `client_netmask` of `None` used to reach `randomIPAddressFromNetwork()` and fail deep inside the send loop. |
| 41 | +- **DAS: promiscuous mode is now guaranteed to be turned back off**, via `try/finally`. It previously only ran on the `KeyboardInterrupt` path and after normal completion — any other exception (e.g. an empty `--il` list making `random.choice` raise `IndexError`) left the interface stuck in promiscuous mode. |
| 42 | + |
| 43 | +### Performance fixes |
| 44 | + |
| 45 | +- **`das.py`'s flood loop no longer recomputes a Scapy routing-table lookup (`IP(dst=...).src`) on every iteration.** `args.target_network` is invariant across the loop, and the value was discarded immediately whenever `-r`/`-s`/`-m` overrode it anyway — now computed once, up front. |
| 46 | +- **`run_worker_pool()` simplified back down to one completion-tracking mechanism.** An earlier iteration of this pass had it running `queue.join()` alongside a *second*, separate daemon thread polling `unfinished_tasks` every 50ms just to drive the progress bar — more machinery than needed, and the timeout-bounded teardown of that second thread had a small theoretical race with `pbar.close()`. Each worker now updates the (lock-guarded) progress bar itself right after finishing its own item; `queue.join()` alone decides when the function returns. |
| 47 | + |
| 48 | +### Testing |
| 49 | + |
| 50 | +~50 new pytest cases (`test_theme.py`, `test_logging_config.py`, `test_enum.py` are new files; `test_net_utils.py`, `test_threadpool.py`, `test_das.py`, `test_sip_packet.py` gained new cases), including regression tests for the `setcbreak` fix, the `printResult`/`check_ip_address`/`positive_int`/template-caching fixes above, and the blanket-rejection pre-check. 122 tests total; `ruff check src/ tests/ mr.sip.py` clean. |
| 51 | + |
| 52 | +### Known observation, not fixed |
| 53 | + |
| 54 | +SIP-ENUM's new blanket-rejection pre-check runs one synchronous probe per target *before* the bulk-confirmation prompt, unthreaded. For a single `--tn` target this is one extra packet; for a large `output/ip_list.txt` (e.g. a full `/24` from a prior SIP-NES run), it adds up to one sequential round-trip per host before the operator is even asked to confirm the run. Not incorrect, just a potential wait on large host lists - left as-is pending a decision on whether to thread it through `run_worker_pool()` or move it after confirmation. |
| 55 | + |
| 56 | +## 1.2.0 |
| 57 | + |
3 | 58 | Technical summary of the modular refactor and correctness/security hardening pass on top of upstream Mr.SIP `v1.1.0`. Baseline for comparison is commit `bdd98ad` ("Update OffzoneMoscow2019badge.svg") — the last commit before this work started. |
4 | 59 |
|
5 | 60 | No CLI behavior is removed and no existing flag changes meaning. Two new flags were added (`--mtu`, `--version`). Everything else is a bug fix, a hardening change, or an internal restructure; a script that worked before still works, generally with more accurate output. |
|
0 commit comments