{"id":51463730,"url":"https://github.com/aredoff/ip2provider","last_synced_at":"2026-07-06T08:30:54.554Z","repository":{"id":353573971,"uuid":"1145105536","full_name":"aredoff/ip2provider","owner":"aredoff","description":"Python library for detect provider by ip","archived":false,"fork":false,"pushed_at":"2026-04-24T12:55:59.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-24T14:37:58.971Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aredoff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-29T12:37:23.000Z","updated_at":"2026-04-24T12:55:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aredoff/ip2provider","commit_stats":null,"previous_names":["aredoff/ip2provider"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/aredoff/ip2provider","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aredoff%2Fip2provider","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aredoff%2Fip2provider/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aredoff%2Fip2provider/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aredoff%2Fip2provider/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aredoff","download_url":"https://codeload.github.com/aredoff/ip2provider/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aredoff%2Fip2provider/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35184015,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-06T08:30:53.069Z","updated_at":"2026-07-06T08:30:54.548Z","avatar_url":"https://github.com/aredoff.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IP2Provider\n\nPython library to guess a **hosting provider id** from hints you already have (IP, hostname, RDAP-style network fields, DNS) or from a **target string** after live resolution (DNS + RDAP).\n\n## Installation\n\n```bash\npip install ip2provider\n```\n\nRuntime dependencies: `dnspython`, `ipwhois`, `tldextract` (see `pyproject.toml`).\n\n## Matching API (`find`)\n\nLoad rules (default: bundled `ip2provider/data/provider.json`), then score every known provider and return the one with **highest total confidence** (sum of matching rule weights).\n\n```python\nfrom ip2provider import IP2Provider\n\nprovider = IP2Provider()\n\nresult = provider.find(\n    ip=\"192.168.1.1\",\n    fqdn=\"server.example.com\",\n    network_name=\"EXAMPLE-NET\",\n    network_contact_email=\"abuse@example.com\",\n    ns_server=\"ns1.example.com\",\n    asn=\"24940\",\n    asname=\"SOME-AS, US\",\n    organization=\"Example Org\",\n)\n\nif result:\n    print(result[\"provider\"], result[\"confidence\"])\n```\n\nAll arguments are optional; pass any subset. Plural forms (`ips`, `fqdns`, `network_contact_emails`, `ns_servers`, `asns`, `asnames`, `organizations`) let you pass several values; the matcher stops after the first hit per rule group where that is defined.\n\n**Inputs and rule types in `provider.json`:**\n\n| `find(...)` argument(s) | Signal key in rules | Match style |\n|-------------------------|---------------------|-------------|\n| `network_name` | `netname` | regex on netname (RDAP/WHOIS) |\n| `fqdn`, `fqdns` | `ptr` | regex on host / PTR name |\n| `network_contact_email(s)` | `netmail` | regex on e-mail(s) from RDAP |\n| `ip`, `ips` | `ip` | exact string |\n| `ns_server`, `ns_servers` | `ns` | regex on NS hostnames |\n| `asn`, `asns` | `asn` | exact **numeric AS** (JSON keys are digit strings, e.g. `\"24940\"`) |\n| `asname`, `asnames` | `asname` | regex on AS description (same idea as `asn_description` in RDAP) |\n| `organization(s)` | `org` | regex on organisation string from RDAP |\n\n## Resolution API (`collect_evidence`, `resolve_and_find`)\n\nFor a user-supplied **IP or hostname**, the library can gather evidence (PTR, A/AAAA, NS, RDAP: netname, e-mails, ASN, AS name, org) and then call `find` with the right kwargs.\n\n```python\nfrom ip2provider import IP2Provider, collect_evidence, resolve_and_find\n\nprov = IP2Provider()\nev = collect_evidence(\"8.8.8.8\", dns_timeout=5.0)\nprint(ev.to_find_kwargs())\n\nout = resolve_and_find(\n    prov,\n    \"example.com\",\n    dns_timeout=5.0,\n    min_agreeing_signals=2,\n    require_verified=False,\n)\n# out: provider, confidence, evidence, per_signal, agreement, verified, errors\n```\n\n`resolve_and_find` returns how many **signal groups** (ip, fqdn, network name, e-mail, ns, asn, asname, org) agree on the winning provider, so you can require multiple independent matches.\n\n## Custom rules file\n\n```python\nIP2Provider(rules_path=\"/path/to/provider.json\")\n```\n\nThe file must be **v1** JSON:\n\n- `version` must be `1`.\n- `providers` is a non-empty array; each item has `name` (id returned as `result[\"provider\"]`) and `signals` (a map of signal name → map of `pattern` → **integer weight**).\n\nRegex signals use Python `re` with `re.IGNORECASE`. Exact maps are used for `ip` and `asn` (only digit keys for `asn`).\n\nExample (abbreviated):\n\n```json\n{\n  \"version\": 1,\n  \"providers\": [\n    {\n      \"name\": \"example.com\",\n      \"signals\": {\n        \"netname\": { \".*EXAMPLE.*\": 100 },\n        \"ptr\": { \".*\\\\.example\\\\.com$\": 100 },\n        \"netmail\": { \"@example.com\": 40 },\n        \"ns\": { \".*ns\\\\.example\\\\..*\": 30 },\n        \"asn\": { \"12345\": 50 },\n        \"asname\": { \".*EXAMPLE-AS.*\": 40 },\n        \"org\": { \".*Example Inc.*\": 20 }\n      }\n    }\n  ]\n}\n```\n\nOptional: set `\"$schema\": \"./provider.v1.schema.json\"` next to a copy of [ip2provider/data/provider.v1.schema.json](ip2provider/data/provider.v1.schema.json) for editor validation.\n\nA one-off migrator for the old root-object format lives at `scripts/migrate_provider_json_v1.py`.\n\n## Development\n\n```bash\npip install -e \".[dev]\"\npytest\n```\n\n`jsonschema` (dev) validates the bundled `provider.json` against `provider.v1.schema.json` in tests.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faredoff%2Fip2provider","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faredoff%2Fip2provider","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faredoff%2Fip2provider/lists"}