Metadata-Version: 2.4
Name: dicomrecon
Version: 0.1.0
Summary: DICOM recon toolkit — SCU clients, SCP server, and security assessment utilities
Home-page: https://github.com/Ben-ODea/dicomrecon
Author: Ben-ODea
Author-email: ben@benodea.com
License: Apache-2.0
Keywords: dicom pacs medical imaging security pentest recon scu scp pynetdicom
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: Security
Classifier: Topic :: System :: Networking
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pynetdicom>=2.1.0
Requires-Dist: pydicom>=2.4.0
Requires-Dist: colorama>=0.4.6
Requires-Dist: tabulate>=0.9.0
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# dicomrecon

A Python toolkit for interacting with and testing DICOM services. Provides SCU clients
(C-ECHO, C-STORE, C-FIND, C-MOVE, C-GET), a configurable multi-service SCP server, and
a suite of security and compliance testing utilities built on
[pynetdicom](https://pynetdicom.org/).

> **Use only on systems you own or have explicit written authorisation to test.**

---

## Installation

```bash
pip install dicomrecon
```

Python 3.12+ is required.

> **Compatibility note (2026-03-31):** Python 3.13 is supported for
> pure-Python usage (data generation, fuzzing, SCP/SCU configuration).
> However, pynetdicom ≥ 2.1.0 has known issues with the networking layer
> under Python 3.13 that can cause hangs or unexpected association failures
> during live DICOM operations (C-ECHO, C-STORE, C-FIND, etc.).
> **Python 3.12 is recommended for all network-dependent workflows** until
> pynetdicom publishes a 3.13-verified release.

---

## CLI quick-start

```bash
# Verify connectivity
dicomrecon ping PACS01@192.168.1.10:11112

# Query for all studies
dicomrecon find 192.168.1.10:11112

# Send a DICOM file
dicomrecon store 192.168.1.10:11112 scan.dcm

# Run a local SCP server
dicomrecon scp --port 11112 --store-dir ./received

# Discover DICOM services on a subnet
dicomrecon discover 192.168.1.0/24
```

All commands support `--help` for full option listings.

---

## Commands

### Standard DICOM

| Command | Description |
|---------|-------------|
| `ping` | C-ECHO — verify AE connectivity |
| `store` | C-STORE — send DICOM files to a Storage SCP |
| `find` | C-FIND — query a PACS or Modality Worklist |
| `move` | C-MOVE — request a PACS to push instances to an AE |
| `get` | C-GET — retrieve instances directly from a PACS |
| `scp` | Run a multi-service DICOM SCP server |

### Security / Compliance Testing

| Command | Description |
|---------|-------------|
| `discover` | Scan a subnet for DICOM services via C-ECHO probing |
| `aetbrute` | Brute-force called/calling AE title acceptance |
| `dump` | Hierarchical C-FIND walk: Patient → Study → Series → Image |
| `exfil` | Enumerate all studies and retrieve via C-GET |
| `fuzz` | C-STORE fuzzer — send malformed datasets and log responses |
| `simulate` | Rogue SCP pre-loaded with synthetic patient data |
| `storereject` | SCP that rejects C-STORE with configurable status codes |
| `wlpoison` | Modality Worklist SCP serving poisoned worklist items |

### Target syntax

```
[CALLED_AET@]host[:port]

Examples:
  192.168.1.10
  192.168.1.10:11112
  PACS01@192.168.1.10
  PACS01@192.168.1.10:11112
```

Port defaults to `104`. Called AE title defaults to `ANY-SCP`.

---

## Python API

```python
from dicomrecon.target import parse_target
from dicomrecon.scu.echo import c_echo
from dicomrecon.scu.find import c_find
from dicomrecon.scp.server import DicomSCP

target = parse_target("PACS01@192.168.1.10:11112", calling_aet="MYTOOL")

# C-ECHO
ok = c_echo(target)

# C-FIND
results = c_find(target, level="study", filters={"PatientID": "12345"})
for ds in results:
    print(ds.StudyInstanceUID, ds.StudyDate)

# Run an SCP
scp = DicomSCP(ae_title="TESTSCP", port=11112)
scp.enable_worklist = True
scp.load_worklist("worklist.json")
scp.start()  # blocks; Ctrl-C to stop
```

### Synthetic data & fuzzing

```python
from dicomrecon.pentest.generator import generate_dataset, make_worklist
from dicomrecon.pentest.fuzzer import generate_fuzz_cases

# 10 patients × 2 studies × 2 series × 3 instances
instances = generate_dataset(n_patients=10, modalities=["US", "CT"])

# Synthetic Modality Worklist items
worklist = make_worklist(20, modalities=["US"])

# ~100 malformed DICOM datasets for C-STORE fuzzing
cases = generate_fuzz_cases()
for case in cases:
    print(case._fuzz_label)
```

---

## Development

```bash
git clone https://github.com/Ben-ODea/dicomrecon.git
cd dicomrecon
python -m venv .venv && source .venv/bin/activate
pip install -e .
pytest tests/
```

---

## License

Copyright 2026 Ben-ODea

Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full text.
