A CRON-driven Python utility that aggregates blocked-source IP addresses out of Radware AppWall WAFs and Radware DefensePro (DPRO) devices, deduplicates the combined list, optionally compresses /32 hosts into summary subnets to fit DPRO list-size limits, and pushes the resulting blocklist up to an upstream DefensePro device.
Effectively: downstream AppWall/DPRO appliances learn attacker IPs locally; this script rolls those learnings up into a single upstream DPRO blocklist on a schedule.
Dependencies: requests, json (stdlib for the rest: re, time,
ipaddress, csv, os.path, urllib3).
| File | Role |
|---|---|
dpwall.py |
Core library — all AppWall/DPRO I/O and config generation. Not meant to run directly. |
main.py |
Offline/file-based entrypoint. Parses DPRO config text dumps + pulls AppWall REST data, merges, writes add/del config files to disk. |
dump_appwall_to_dpro.py |
Live entrypoint. Talks directly to DPRO over SOAP (create/delete modes) — wipes existing APW_SCRIPT_* classes then re-creates them from current AppWall data. |
ipv4sorter.py |
Standalone subnet-summarization module — collapses many /32s into /24–/29 blocks to shrink the list. |
AppWall WAFs (REST /v2/config/aw/BlockedSources) ─┐
├─► dedupe (set) ─► gen DPRO config ─► SOAP append_Config ─► upstream DefensePro
DefensePro config dumps (text / SOAP get_Config) ─┘
get_appwall_info(apw_ip)/get_appwall_info_v2— GEThttps://{ip}/v2/config/aw/BlockedSources, basic auth,verify=False. Retries up to 3× with 10 s backoff. Returns list ofSourceIdIPs.get_soap_fullcfg(host)— SOAPget_Configagainsthttps://{host}/soap; returns full DPRO config text.put_soap(full_cfg_string, host)— SOAPappend_Config, chunked into batches of 250 lines per request (device limit).parse_dp_info_v2(raw_cfg)— regex-extracts existingclasses modify network create APW_SCRIPT_<n> <seq> -a <ip> -s <prefix>lines into a dict keyed by class name. Returns(dict, flat_array).gen_diff_dp_appwall(...)— removes IPs already present in DPRO from the AppWall list (delta only).gen_dp_dictv2(...)— bin-packs the diffed IP list into existing classes' free sequence slots (0–249 per class), then spills into newAPW_SCRIPT_<n>classes as needed.gen_dp_cfg(dict)— emits add/del CLI lines from an existing class dict.gen_brand_new_dp_cfg(iplist)— full rebuild: chunks IPs by 250, createsAPW_SCRIPT_0..Nclasses + blocklist tables. Splitsa.b.c.d/pinto address + prefix; assumes /32 when no mask present. Returns(add_str, del_str).
A binary-tree (Subnet class) recursively splits each candidate /24 down to /29,
counting how many blocklisted hosts fall in each subnet. reverse_walk() applies
a density rule_set (e.g. /24 needs ≥12.5% host coverage, /29 ≥40%) to decide
whether collapsing a block into a single CIDR is "worth it" vs. keeping /32s.
Goal: shrink the list toward DPRO's max (~30000 entries; dump_appwall_to_dpro.py
truncates to 30000) while avoiding over-broad blocks. Emits a STATS-*.csv report
of the reduction. (Comments are in Russian.)
- Designed to be wired into CRON to refresh upstream DPRO data periodically.
- DPRO class naming convention:
APW_SCRIPT_<n>, 250 networks per class. dump_appwall_to_dpro.pycurrently hardcodessys.argv = [..., "create"](line 7) — overriding any real CLI arg.createmode does a destructive delete-then-recreate of allAPW_SCRIPT_*classes.
- Hardcoded credentials in source:
dpwall.pycontains plaintext basic-auth creds —admin/P@ssw0rd!@#(line 21), andnspk-noc/P@ssw0rd!@#(line 105).put_soapuses placeholderusername/password. - Hardcoded internal IPs throughout (
10.6.32.xAppWalls,10.6.20.233/10.6.32.19xDPRO) —nspkin the SOAP cred hints at NSPK (Russian payment card operator) infrastructure. - TLS verification disabled (
verify=False) on every request. - These should be moved to env vars / a secrets store and
.gitignored before any wider sharing.