NAME
VPNDetection - the official Perl client for the VPNDetection API
SYNOPSIS
use VPNDetection;
my $client = VPNDetection->new;
my $result = $client->lookup('45.83.91.1');
say 'VPN' if $result->is_vpn;
DESCRIPTION
Classifies an IP address as VPN infrastructure, a residential, datacenter or mobile proxy, a Tor node, a hosting provider, a CDN or a privacy relay.
Which fields come back is decided by the plan behind your key. An absent field means "not in your plan" and is not the same as false; see "ABSENT IS NOT FALSE" in VPNDetection::Result, which is the one thing to read before writing an if.
METHODS
new
my $client = VPNDetection->new(%options);
- api_key
-
Your API key. Omit it for the free tier, which answers
ipandis_vpnand allows 1000 requests per day per source address. - base_url
-
Defaults to
https://api.vpndetection.io. - cache_size
-
Addresses held in this client's cache. Defaults to 10000; 0 disables caching.
- cache_ttl
-
How long an answer stays fresh, in seconds. Defaults to 3600.
- concurrency
-
Requests in flight during a batch. Defaults to 8, and is overridable per call.
- retries
-
Attempts after a retryable failure. Defaults to 2, and is overridable per call.
- timeout
-
Per-request timeout in seconds. Defaults to 30, and is overridable per call. It bounds each attempt, so a retried call can take longer in total, and it is lifted for a dataset transfer.
- ua
-
Your own Mojo::UserAgent, for a proxy or custom TLS settings. The client sets
max_redirectsto 0 on whichever agent it is given: the database download endpoint answers302and that redirect is the answer, so following it would pull a multi-gigabyte dataset into memory.
The cache belongs to the client instance and is never shared. Two clients holding different keys are on different plans and entitled to different fields, so a shared cache would serve one of them the other's shape.
lookup
my $result = $client->lookup($ip, %options);
Returns a VPNDetection::Result, or dies with a VPNDetection::Error. retries and timeout are the per-call options, as they are on my_ip and my_entitlement.
my_ip
my $me = $client->my_ip;
Classifies the address this client is calling from, returning a VPNDetection::Result.
The same answer lookup would give for that address, at the same cost against your allowance. The address is the one our edge observed, so a call made through a proxy or a VPN reports the exit it left through - usually the point of asking.
Deliberately not cached. The cache is keyed by address, and which address this is IS the question: a machine that moves between networks would otherwise be told where it used to be.
my_entitlement
my $ent = $client->my_entitlement;
printf "%d of %d\n", $ent->{usage}{requests}, $ent->{usage}{quota};
What this client's API key is entitled to, and how much of it has been used, as a hash reference with org_id, apikey, plan and usage keys.
Named for what it answers rather than me, which sits one letter from my_ip and means something quite different: one is which address you are calling FROM, the other is what the key you are calling WITH may spend.
Unlike a lookup there is no useful unauthenticated answer, so a client built without an API key gets an unauthorized error rather than a partial one.
Usage counts against the allowance window - the anniversary of the subscription, not the calendar month and not the billing period - and it is the same number a lookup is gated on. hard_limit is undef when we never stop serving, which is not the same as a limit of zero.
Deliberately not cached: the whole point is what has been spent, and a cached answer is a wrong one within seconds of the next request.
lookup_batch
my $answers = $client->lookup_batch(\@ips, %options);
Returns a hash reference keyed by address. Duplicates in @ips collapse to one request, bogons never reach the network, and an address that failed carries its VPNDetection::Error as its value instead of failing the batch. retries, concurrency and timeout are the per-call options, and the timeout bounds each chunk.
There is no cap on how many addresses one call takes: everything not answered locally goes out in chunks of up to 1000, the most one request carries.
Perl hashes have no insertion order, so iterate your own list if order matters:
for my $ip (@ips) {
my $answer = $answers->{$ip};
}
is_bogon
$client->is_bogon('10.0.0.1'); # 1
Also exportable, for code with no client to hand:
use VPNDetection 'is_bogon';
is_bogon('10.0.0.1');
database
my $databases = $client->database->list;
The licensed dataset downloads. See VPNDetection::Database.
oauth
my $device = $client->oauth->device_authorization('your-client-id');
Signs a person in on their own machine with the OAuth device flow, so a program can be handed one of their API keys instead of asking for it. See VPNDetection::Oauth.
NON-BLOCKING USE
Every call has a _p twin returning a Mojo::Promise: lookup_p, lookup_batch_p, and the same on VPNDetection::Database and VPNDetection::Oauth. The blocking forms are those promises plus a wait, so nothing is duplicated and both paths retry, cache and short-circuit identically.
$client->lookup_p('45.83.91.1')
->then(sub { say shift->is_vpn })
->catch(sub { warn shift })
->wait;
Inside an already running Mojo::IOLoop - a Mojolicious application, say - the blocking forms cannot work and croak saying so. Use the _p forms there.
SEE ALSO
VPNDetection::Result, VPNDetection::Error, VPNDetection::Database, VPNDetection::Oauth.
LICENSE
MIT. Copyright Mslm Dev.