AWS-IP

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

lib/AWS/IP.pm
LICENSE
Makefile.PL
MANIFEST			This list of files
README.pod
t/aws.t
t/ip-ranges.json
META.yml                                 Module YAML meta-data (added by MakeMaker)
META.json                                Module JSON meta-data (added by MakeMaker)

README.pod  view on Meta::CPAN

=head2 SYNOPSIS

  use AWS::IP;

  my $aws = AWS::IP->new(600, '/tmp/aws_ip_cache');

  # get the raw data as a Perl reference
  my $aws_ip_data = $aws->get_raw_data;

  # check if an ip address is AWS
  if ($aws->is_aws_ip('50.0.0.1')
  {
    ..
  }

  # get a list of all AWS cidrs
  my $cidrs = $aws->get_cidrs;

README.pod  view on Meta::CPAN


  my $ec2_cidrs = $aws->get_cidrs_by_service('EC2');
  my $aws_ec2_set = Net::CIDR::Set->new( @$ec2_cidrs );

  if ($aws_ec2_set->contains($ip)
  {
    ...
  }

  # time passes, cache has expired
  $aws_ip_data = $aws->get_raw_data; # auto refreshes

=head2 DESCRIPTION

AWS L<publish|https://ip-ranges.amazonaws.com/ip-ranges.json> their IP ranges, which periodically change. This module downloads and serializes the IP ranges into a Perl data hash reference. It caches the data, and if the cache expires, re-downloads a...

=head2 new ($cache_timeout_secs, [$cache_path])

Creates a new AWS::IP object and sets up the cache. Requires an number for the cache timeout seconds. Optionally takes a cache path argument. If no cache path is supplied, AWS::IP will use a random temp directory. If you want to reuse the cache over ...


=cut

=head2 ip_is_aws ($ip, [$service])

Boolean method to test if an ip address is from AWS. Optionally takes a service name (AMAZON|EC2|CLOUDFRONT|ROUTE53|ROUTE53_HEALTHCHECKS) and restricts the check to AWS ip addresses for that service.

If you are checking more than one ip address, it's more efficient to pull the CIDRs you want, then use L<Net::CIDR::Set> to test if the ips are present in the CIDRs (see example in SYNOPSIS).


=cut

=head2 get_raw_data

Returns the entire raw IP dataset as a Perl data structure.


=cut

=head2 get_cidrs

Returns an arrayref of the L<CIDRs|http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing> in the AWS IP address data.


=cut

=head2 get_cidrs_by_region ($region)

Returns an arrayref of CIDRs matching the provided region.


=cut

=head2 get_cidrs_by_service ($service)

Returns an arrayref of CIDRs matching the provided service (AMAZON|EC2|CLOUDFRONT|ROUTE53|ROUTE53_HEALTHCHECKS).


=cut

=head2 get_regions

Returns an arrayref of the regions in the AWS IP address data.


=cut

=head2 get_services

Returns an arrayref of the services (Amazon, EC2 etc) in the AWS IP address data.


=cut

=head2 SEE ALSO

L<AWS::Networks> - is similar to this module but does not provide cacheing.

Amazon's L<page|http://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html> on AWS IP ranges.

lib/AWS/IP.pm  view on Meta::CPAN

our $VERSION = 0.04;

# ABSTRACT: Get and search AWS IP ranges in a caching, auto-refreshing way

=head2 SYNOPSIS

  use AWS::IP;

  my $aws = AWS::IP->new(600, '/tmp/aws_ip_cache');

  # get the raw data as a Perl reference
  my $aws_ip_data = $aws->get_raw_data;

  # check if an ip address is AWS
  if ($aws->is_aws_ip('50.0.0.1')
  {
    ..
  }

  # get a list of all AWS cidrs
  my $cidrs = $aws->get_cidrs;

lib/AWS/IP.pm  view on Meta::CPAN


  my $ec2_cidrs = $aws->get_cidrs_by_service('EC2');
  my $aws_ec2_set = Net::CIDR::Set->new( @$ec2_cidrs );

  if ($aws_ec2_set->contains($ip)
  {
    ...
  }

  # time passes, cache has expired
  $aws_ip_data = $aws->get_raw_data; # auto refreshes

=head2 DESCRIPTION

AWS L<publish|https://ip-ranges.amazonaws.com/ip-ranges.json> their IP ranges, which periodically change. This module downloads and serializes the IP ranges into a Perl data hash reference. It caches the data, and if the cache expires, re-downloads a...

=head2 new ($cache_timeout_secs, [$cache_path])

Creates a new AWS::IP object and sets up the cache. Requires an number for the cache timeout seconds. Optionally takes a cache path argument. If no cache path is supplied, AWS::IP will use a random temp directory. If you want to reuse the cache over ...

=cut

sub new
{
  croak 'Incorrect number of args passed to AWS::IP->new()' unless @_ >= 2 && @_ <= 3;

lib/AWS/IP.pm  view on Meta::CPAN

sub ip_is_aws
{
  my ($self, $ip, $service) = @_;

  croak 'Error must supply an ip address' unless $ip;

  my $ip_ranges;

  if ($service)
  {
    $ip_ranges = Net::CIDR::Set->new( map { $_->{ip_prefix} } grep { $_->{service} eq $service } @{$self->get_raw_data->{prefixes}});
  }
  else
  {
    $ip_ranges = Net::CIDR::Set->new( map { $_->{ip_prefix} } @{$self->get_raw_data->{prefixes}} );
  }
  $ip_ranges->contains($ip);
}


=head2 get_raw_data

Returns the entire raw IP dataset as a Perl data structure.

=cut

sub get_raw_data
{
  my ($self) = @_;

  my $entry = $self->{cache}->entry(CACHE_KEY);

  if ($entry->exists)
  {
    decode_json($entry->get());
  }
  else
  {
    decode_json($self->_refresh_cache);
  }
}

=head2 get_cidrs

Returns an arrayref of the L<CIDRs|http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing> in the AWS IP address data.

=cut

sub get_cidrs
{
  my ($self) = @_;
  [ map { $_->{ip_prefix} } @{$self->get_raw_data->{prefixes}} ];
}

=head2 get_cidrs_by_region ($region)

Returns an arrayref of CIDRs matching the provided region.

=cut

sub get_cidrs_by_region
{
  my ($self, $region) = @_;

  croak 'Error must provide region' unless $region;
  [ map { $_->{ip_prefix} } grep { $_->{region} eq $region } @{$self->get_raw_data->{prefixes}} ];
}

=head2 get_cidrs_by_service ($service)

Returns an arrayref of CIDRs matching the provided service (AMAZON|EC2|CLOUDFRONT|ROUTE53|ROUTE53_HEALTHCHECKS).

=cut

sub get_cidrs_by_service
{
  my ($self, $service) = @_;

  croak 'Error must provide service' unless $service;
  [ map { $_->{ip_prefix} } grep { $_->{service} eq $service } @{$self->get_raw_data->{prefixes}} ];
}

=head2 get_regions

Returns an arrayref of the regions in the AWS IP address data.

=cut

sub get_regions
{
  my ($self) = @_;
  my %regions;
  for (@{$self->get_raw_data->{prefixes}})
  {
    $regions{ $_->{region} } = 1;
  }
  [ keys %regions ];
}

=head2 get_services

Returns an arrayref of the services (Amazon, EC2 etc) in the AWS IP address data.

=cut

sub get_services
{
  my ($self) = @_;
  my %services;
  for (@{$self->get_raw_data->{prefixes}})
  {
    $services{ $_->{service} } = 1;
  }
  [ keys %services ];
}

=head2 SEE ALSO

L<AWS::Networks> - is similar to this module but does not provide cacheing.

lib/AWS/IP.pm  view on Meta::CPAN

{
  my ($self) = @_;

  my $response = HTTP::Tiny->new->get('https://ip-ranges.amazonaws.com/ip-ranges.json');

  if ($response->{success})
  {
    my $entry = $self->{cache}->entry(CACHE_KEY);
    $entry->set($response->{content});

    # return the data
    $response->{content};
  }
  else
  {
    croak "Error requesting $response->{url} $response->{code} $response->{reason}";
  }
}

sub _refresh_cache_from_string
{
  my ($self, $data) = @_;

  my $entry = $self->{cache}->entry(CACHE_KEY);
  $entry->set($data);

  # return the data
  $data;
}
1;

t/aws.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;

my $test_data = do {
  open my $test_fh, '<', 't/ip-ranges.json' or die $!;
  local $/;
  <$test_fh>;
};

# loads ok
use_ok('AWS::IP', 'load module');
ok my $aws = AWS::IP->new(600), 'constructor';
ok $aws->_refresh_cache_from_string($test_data), 'refresh cache';

# ip range checks
ok $aws->ip_is_aws('50.19.0.1'), 'ip 50.19.0.1 is found in AWS range';
ok $aws->ip_is_aws('54.239.98.0', 'AMAZON'), 'ip 54.239.98.0 is found in AMAZON AWS range';
ok !$aws->ip_is_aws('54.239.98.0', 'EC2'), 'ip 54.239.98.0 is not found in EC2 AWS range';

# counts
is 383, @{$aws->get_cidrs}, '383 CIDRs are present';
is 5, @{$aws->get_services}, '5 services are present';
is 12, @{$aws->get_regions}, '12 regions are present';

# cache expiry
ok my $aws_2 = AWS::IP->new(1), 'constructor with 1 second cache';
ok $aws->_refresh_cache_from_string($test_data), 'refresh cache';
sleep(2); # let cache expire
ok !$aws_2->{cache}->entry('AWS_IPS')->exists, 'Entry no longer exists';
ok !$aws_2->{cache}->entry('AWS_IPS')->get, 'Data is no longer cached';

done_testing;



( run in 0.309 second using v1.01-cache-2.11-cpan-8d75d55dd25 )