A lightweight API service for TCP reachability checks against a domain/IP and port.
The service accepts a target (hostname, IPv4, or IPv6) plus port, resolves DNS when needed, applies IP policy checks, and then attempts TCP connections.
- Single-file application:
main.py - Config file + env override:
config.json - API endpoint:
POST /reachprobeapi/v1 - Health endpoint:
GET /healthz - Optional API key auth (
X-API-Key) - Built-in in-memory rate limiting
- IP policy filtering for resolved addresses
- Bounded probe behavior to avoid long-running requests
.
├── main.py
├── config.json
├── requirements.txt
└── tests/
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtpython3 main.pyDefault listen address is 0.0.0.0:8899.
pm2 start main.py --interpreter python3 --name reachprobeapiRequest body:
{
"target": "dns.google",
"port": 443
}Response body:
{
"target": "dns.google",
"port": 443,
"resolved_addresses": ["8.8.8.8", "8.8.4.4"],
"reachable": true,
"attempts": 3,
"successful_connects": 2,
"duration_ms": 137
}{
"status": "ok"
}curl -sS -X POST "http://127.0.0.1:8899/reachprobeapi/v1" \
-H "Content-Type: application/json" \
-d '{"target":"dns.google","port":53}'curl -sS -X POST "http://127.0.0.1:8899/reachprobeapi/v1" \
-H "Content-Type: application/json" \
-d '{"target":"example.com","port":443}'curl -sS -X POST "http://127.0.0.1:8899/reachprobeapi/v1" \
-H "Content-Type: application/json" \
-d '{"target":"1.1.1.1","port":443}'curl -sS -X POST "http://127.0.0.1:8899/reachprobeapi/v1" \
-H "Content-Type: application/json" \
-d '{"target":"2606:4700:4700::1111","port":443}'curl -sS -X POST "http://127.0.0.1:8899/reachprobeapi/v1" \
-H "Content-Type: application/json" \
-H "X-API-Key: change_me" \
-d '{"target":"example.com","port":443}'curl -sS -X POST "http://127.0.0.1:8899/reachprobeapi/v1" \
-H "Content-Type: application/json" \
-d '{"target":"dns.google","port":443}' | jq '{target, reachable, successful_connects, duration_ms}'The app loads config in this order:
- Defaults in code
config.json- Environment variables (highest priority)
You can point to another config file:
export IPTOOLS_CONFIG_FILE=/path/to/config.json| config.json key | env var | default | notes |
|---|---|---|---|
telnet_count |
TELNET_COUNT |
3 |
probe rounds, range 1..10 |
telnet_timeout_sec |
TELNET_TIMEOUT_SEC |
1 |
per connect timeout, range 1..5 |
max_resolved_addresses |
MAX_RESOLVED_ADDRESSES |
4 |
max DNS answers used, range 1..16 |
probe_time_budget_sec |
PROBE_TIME_BUDGET_SEC |
10 |
hard request probe budget, range 1..60 |
require_api_key |
REQUIRE_API_KEY |
false |
require X-API-Key header |
api_key |
API_KEY |
null |
API key value |
rate_limit_requests |
RATE_LIMIT_REQUESTS |
30 |
request limit |
rate_limit_window_sec |
RATE_LIMIT_WINDOW_SEC |
60 |
limit window |
allow_private_ip |
ALLOW_PRIVATE_IP |
false |
allow private IPs |
allow_loopback_ip |
ALLOW_LOOPBACK_IP |
false |
allow loopback IPs |
allow_multicast_ip |
ALLOW_MULTICAST_IP |
false |
allow multicast IPs |
allow_reserved_ip |
ALLOW_RESERVED_IP |
false |
allow reserved IPs |
server_host |
SERVER_HOST |
0.0.0.0 |
bind host |
server_port |
SERVER_PORT |
8899 |
bind port |
export REQUIRE_API_KEY=true
export API_KEY='replace_with_strong_key'
export RATE_LIMIT_REQUESTS=20
export RATE_LIMIT_WINDOW_SEC=60
export TELNET_COUNT=2
export TELNET_TIMEOUT_SEC=1
export MAX_RESOLVED_ADDRESSES=4
export PROBE_TIME_BUDGET_SEC=8- Keep
ALLOW_PRIVATE_IP=falseandALLOW_LOOPBACK_IP=falseunless you fully trust callers. - Enable API key auth before exposing the endpoint.
- Put this service behind a gateway/reverse proxy (TLS termination, WAF, IP allowlist).
- Restrict outbound egress at network level if possible.
- Use process-level limits and monitoring (CPU, memory, restart policy, request logs).