Skip to main content

ptrclassify

ptrclassify is a small, dependency-free Python library and CLI that infers likely IP usage from reverse-DNS PTR hostnames.

It is intentionally heuristic and multi-label. PTR naming is operator-controlled and is not authoritative evidence of how an address is actually used. The output therefore includes a confidence score, the text that matched, and the rule IDs that produced each label.

Examples of orthogonal labels:

  • ptrclassify:allocation="dynamic", ptrclassify:allocation="static", ptrclassify:allocation="reserved"
  • ptrclassify:access="residential", ptrclassify:access="business", ptrclassify:access="mobile", ...
  • ptrclassify:translation="nat", ptrclassify:translation="cgnat"
  • ptrclassify:role="customer", ptrclassify:role="router", ptrclassify:role="broadband-aggregation", ...
  • ptrclassify:hosting="cloud", ptrclassify:hosting="datacenter", ptrclassify:hosting="hosting", ptrclassify:hosting="cdn"
  • ptrclassify:network="anycast", ptrclassify:network="dedicated-internet"
  • ptrclassify:organization="education", ptrclassify:organization="government", ptrclassify:organization="military"
  • ptrclassify:provider="amazon-aws", ptrclassify:provider="google-cloud", ...
  • ptrclassify:naming="ip-encoded", ptrclassify:naming="generic-reverse"

Install

python -m pip install .

Or install the published package from PyPI:

python -m pip install ptrclassify

For development:

python -m pip install -e .

Hyperscan is available as an optional high-throughput matching engine:

python -m pip install '.[hyperscan]'
ptrclassify --engine hyperscan 'ec2-3-151-166-120.us-east-2.compute.amazonaws.com.'

The default re engine has no third-party dependencies. The Hyperscan engine compiles all rule expressions into a single database and returns the same labels and evidence as the default engine.

API service

Install the API dependencies and start the FastAPI service:

python -m pip install '.[api]'
ptrclassify-api

The interactive Swagger UI is available at http://localhost:8000/docs, and FastAPI serves the OpenAPI document at http://localhost:8000/openapi.json. The same document is checked into this repository as openapi.json.

Classify one or more hostnames or complete PTR record lines in one request:

curl -X POST http://localhost:8000/lookup \
  -H 'content-type: application/json' \
  -d '{"records":["ec2-3-151-166-120.us-east-2.compute.amazonaws.com.","188.147.228.101.nat.umts.dynamic.t-mobile.pl."]}'

Library API

from ptrclassify import classify, PTRClassifier

labels = classify("188.147.228.101.nat.umts.dynamic.t-mobile.pl.")
for label in labels:
    print(label.value, label.confidence)

classifier = PTRClassifier()  # engine="re" (the default) or engine="hyperscan"
result = classifier.classify(
    "101.228.147.188.in-addr.arpa. PTR 188.147.228.101.nat.umts.dynamic.t-mobile.pl."
)
print(result.values())
print(result.to_dict())

Expected high-confidence labels include:

ptrclassify:allocation="dynamic"
ptrclassify:access="mobile"
ptrclassify:translation="nat"

CLI

Single hostname:

ptrclassify 'ec2-3-151-166-120.us-east-2.compute.amazonaws.com.'

Complete DNS record:

ptrclassify '120.166.151.3.in-addr.arpa. PTR ec2-3-151-166-120.us-east-2.compute.amazonaws.com.'

File / JSONL:

ptrclassify --file tests/data/sample.ptr --json > classifications.jsonl

Just labels:

ptrclassify --values-only '86-45-50-202-dynamic.agg1.cab.bdt-fng.eircom.net.'

Rule model

Built-in rules live in ptrclassify/data/rules.json. Rules are regular-expression based and have this shape:

{
  "id": "access.mobile",
  "category": "access",
  "label": "mobile",
  "confidence": 0.98,
  "patterns": ["(?:^|[._-])mobile(?:[._-]|$)", "(?:^|[._-])umts(?:[._-]|$)"]
}

You can add private/local rules without modifying the package:

from ptrclassify import PTRClassifier

classifier = PTRClassifier(extra_rules=[{
    "id": "myisp.cgn",
    "category": "translation",
    "label": "cgnat",
    "confidence": 0.99,
    "patterns": [r"\\.cgn\\.example\\.net$"],
}])

Benchmark

After installing the optional dependency, compare steady-state lookup time on the bundled sample data with:

python benchmarks/lookup.py

Use --iterations, --repeat, or --file to change the workload. Classifier construction is deliberately excluded from the timed section so the result measures lookup throughput rather than one-time expression compilation.

Design notes

The design follows the same general idea used by Internet-topology work such as CAIDA Hoiho: operator naming conventions can be mined as evidence, but should be treated as inference rather than truth. This package focuses on usage/allocation/service classes instead of primarily extracting router geolocation.

Provider-specific rules are intentionally separated from generic tokens. This avoids dangerous inferences such as classifying every softbank... hostname as mobile simply because SoftBank also operates mobile networks.

For production enrichment, PTR classification is best combined with ASN/RDAP, BGP prefix data, geofeeds, known cloud/hosting prefixes, forward-confirmed reverse DNS (FCrDNS), and active/service observations.

References / prior art

  • RFC 8501, Reverse DNS in IPv6 for Internet Service Providers: discusses static, dynamic and dynamically generated reverse names and warns against over-interpreting PTR data.
  • CAIDA Hoiho / ITDK: learns operator-specific regular expressions from router hostnames for infrastructure/geolocation inference; this project borrows the explainable-regex philosophy for a different taxonomy.
  • AWS EC2 public hostname documentation: documents the ec2-A-B-C-D.<region>.compute.amazonaws.com form used by the provider-specific rules.

The classifier emits labels in MISP machine-tag form (ptrclassify:predicate="value"). A MISP taxonomy definition suitable for validation or import is provided in misp-taxonomy/machinetag.json.

The built-in taxonomy is not claimed to be an Internet standard. It is designed as a practical, extensible CTI/network-enrichment taxonomy with orthogonal namespaces instead of a single mutually-exclusive class.

Publishing

Releases are published by the Publish to PyPI GitHub Actions workflow. Before the first release, configure a PyPI trusted publisher for this repository with workflow name publish.yml and environment name pypi; no long-lived PyPI API token is required.

To publish a new version, update project.version in pyproject.toml, merge the change, and publish a GitHub release. The workflow builds both the source and wheel distributions, validates them, and publishes them to the ptrclassify PyPI project. It can also be started manually from the Actions tab when a release job needs to be retried.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ptrclassify-0.1.0.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ptrclassify-0.1.0-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file ptrclassify-0.1.0.tar.gz.

File metadata

  • Download URL: ptrclassify-0.1.0.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ptrclassify-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d9080fdf38f9474de46b63d06c9a34917356625d48f1a71616c26e34ebc41e32
MD5 7900929cb2d9295d9fec68b0f6363182
BLAKE2b-256 542b2ac6b122973220bd40ca425284ad927aa96806f8f1f36a72a6965b76eb51

See more details on using hashes here.

Provenance

The following attestation bundles were made for ptrclassify-0.1.0.tar.gz:

Publisher: publish.yml on adulau/ptrclassify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ptrclassify-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: ptrclassify-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ptrclassify-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 31a76cc64ed1aa1fb6f6a898c9090e9b07843ed50e966ffdf84986755d6a2ddc
MD5 4172852d30994d0416994202a1898f36
BLAKE2b-256 42d3490dbdbf5f05a0bff25175217b45d85e978a0125d4f66df25d0e99574180

See more details on using hashes here.

Provenance

The following attestation bundles were made for ptrclassify-0.1.0-py3-none-any.whl:

Publisher: publish.yml on adulau/ptrclassify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page