pax_global_header00006660000000000000000000000064137321703230014513gustar00rootroot0000000000000052 comment=7ff5a0e84593dad6fbd50551343618d7956b3c71 cidranger-1.0.2/000077500000000000000000000000001373217032300134515ustar00rootroot00000000000000cidranger-1.0.2/.gitignore000066400000000000000000000000141373217032300154340ustar00rootroot00000000000000vendor .ideacidranger-1.0.2/.travis.yml000066400000000000000000000004251373217032300155630ustar00rootroot00000000000000language: go go: - 1.13.x - 1.14.x - tip before_install: - travis_retry go get github.com/mattn/goveralls script: - go test -v -covermode=count -coverprofile=coverage.out ./... - travis_retry $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci cidranger-1.0.2/Gopkg.lock000066400000000000000000000017711373217032300154000ustar00rootroot00000000000000# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. [[projects]] digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39" name = "github.com/davecgh/go-spew" packages = ["spew"] pruneopts = "UT" revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" [[projects]] digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" packages = ["difflib"] pruneopts = "UT" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] digest = "1:f85e109eda8f6080877185d1c39e98dd8795e1780c08beca28304b87fd855a1c" name = "github.com/stretchr/testify" packages = ["assert"] pruneopts = "UT" revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" version = "v1.2.1" [solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = ["github.com/stretchr/testify/assert"] solver-name = "gps-cdcl" solver-version = 1 cidranger-1.0.2/Gopkg.toml000066400000000000000000000013451373217032300154200ustar00rootroot00000000000000# Gopkg.toml example # # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md # for detailed Gopkg.toml documentation. # # required = ["github.com/user/thing/cmd/thing"] # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] # # [[constraint]] # name = "github.com/user/project" # version = "1.0.0" # # [[constraint]] # name = "github.com/user/project2" # branch = "dev" # source = "github.com/myfork/project2" # # [[override]] # name = "github.com/x/y" # version = "2.4.0" # # [prune] # non-go = false # go-tests = true # unused-packages = true [[constraint]] name = "github.com/stretchr/testify" version = "1.2.1" [prune] go-tests = true unused-packages = true cidranger-1.0.2/LICENSE000066400000000000000000000020461373217032300144600ustar00rootroot00000000000000MIT License Copyright (c) 2017 Yulin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cidranger-1.0.2/README.md000066400000000000000000000125121373217032300147310ustar00rootroot00000000000000# cidranger Fast IP to CIDR block(s) lookup using trie in Golang, inspired by [IPv4 route lookup linux](https://vincent.bernat.im/en/blog/2017-ipv4-route-lookup-linux). Possible use cases include detecting if a IP address is from published cloud provider CIDR blocks (e.g. 52.95.110.1 is contained in published AWS Route53 CIDR 52.95.110.0/24), IP routing rules, etc. [![GoDoc Reference](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/yl2chen/cidranger) [![Build Status](https://img.shields.io/travis/yl2chen/cidranger.svg?branch=master&style=flat-square)](https://travis-ci.org/yl2chen/cidranger) [![Coverage Status](https://img.shields.io/coveralls/yl2chen/cidranger.svg?branch=master&style=flat-square)](https://coveralls.io/github/yl2chen/cidranger?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/yl2chen/cidranger?&style=flat-square)](https://goreportcard.com/report/github.com/yl2chen/cidranger) This is visualization of a trie storing CIDR blocks `128.0.0.0/2` `192.0.0.0/2` `200.0.0.0/5` without path compression, the 0/1 number on the path indicates the bit value of the IP address at specified bit position, hence the path from root node to a child node represents a CIDR block that contains all IP ranges of its children, and children's children.

Visualization of trie storing same CIDR blocks with path compression, improving both lookup speed and memory footprint.

## Getting Started Configure imports. ```go import ( "net" "github.com/yl2chen/cidranger" ) ``` Create a new ranger implemented using Path-Compressed prefix trie. ```go ranger := NewPCTrieRanger() ``` Inserts CIDR blocks. ```go _, network1, _ := net.ParseCIDR("192.168.1.0/24") _, network2, _ := net.ParseCIDR("128.168.1.0/24") ranger.Insert(NewBasicRangerEntry(*network1)) ranger.Insert(NewBasicRangerEntry(*network2)) ``` To attach any additional value(s) to the entry, simply create custom struct storing the desired value(s) that implements the RangerEntry interface: ```go type RangerEntry interface { Network() net.IPNet } ``` The prefix trie can be visualized as: ``` 0.0.0.0/0 (target_pos:31:has_entry:false) | 1--> 128.0.0.0/1 (target_pos:30:has_entry:false) | | 0--> 128.168.1.0/24 (target_pos:7:has_entry:true) | | 1--> 192.168.1.0/24 (target_pos:7:has_entry:true) ``` To test if given IP is contained in constructed ranger, ```go contains, err = ranger.Contains(net.ParseIP("128.168.1.0")) // returns true, nil contains, err = ranger.Contains(net.ParseIP("192.168.2.0")) // returns false, nil ``` To get all the networks given is contained in, ```go containingNetworks, err = ranger.ContainingNetworks(net.ParseIP("128.168.1.0")) ``` To get all networks in ranger, ```go entries, err := ranger.CoveredNetworks(*AllIPv4) // for IPv4 entries, err := ranger.CoveredNetworks(*AllIPv6) // for IPv6 ``` ## Benchmark Compare hit/miss case for IPv4/IPv6 using PC trie vs brute force implementation, Ranger is initialized with published AWS ip ranges (889 IPv4 CIDR blocks and 360 IPv6) ```go // Ipv4 lookup hit scenario BenchmarkPCTrieHitIPv4UsingAWSRanges-4 5000000 353 ns/op BenchmarkBruteRangerHitIPv4UsingAWSRanges-4 100000 13719 ns/op // Ipv6 lookup hit scenario, counter-intuitively faster then IPv4 due to less IPv6 CIDR // blocks in the AWS dataset, hence the constructed trie has less path splits and depth. BenchmarkPCTrieHitIPv6UsingAWSRanges-4 10000000 143 ns/op BenchmarkBruteRangerHitIPv6UsingAWSRanges-4 300000 5178 ns/op // Ipv4 lookup miss scenario BenchmarkPCTrieMissIPv4UsingAWSRanges-4 20000000 96.5 ns/op BenchmarkBruteRangerMissIPv4UsingAWSRanges-4 50000 24781 ns/op // Ipv6 lookup miss scenario BenchmarkPCTrieHMissIPv6UsingAWSRanges-4 10000000 115 ns/op BenchmarkBruteRangerMissIPv6UsingAWSRanges-4 100000 10824 ns/op ``` ## Example of IPv6 trie: ``` ::/0 (target_pos:127:has_entry:false) | 0--> 2400::/14 (target_pos:113:has_entry:false) | | 0--> 2400:6400::/22 (target_pos:105:has_entry:false) | | | 0--> 2400:6500::/32 (target_pos:95:has_entry:false) | | | | 0--> 2400:6500::/39 (target_pos:88:has_entry:false) | | | | | 0--> 2400:6500:0:7000::/53 (target_pos:74:has_entry:false) | | | | | | 0--> 2400:6500:0:7000::/54 (target_pos:73:has_entry:false) | | | | | | | 0--> 2400:6500:0:7000::/55 (target_pos:72:has_entry:false) | | | | | | | | 0--> 2400:6500:0:7000::/56 (target_pos:71:has_entry:true) | | | | | | | | 1--> 2400:6500:0:7100::/56 (target_pos:71:has_entry:true) | | | | | | | 1--> 2400:6500:0:7200::/56 (target_pos:71:has_entry:true) | | | | | | 1--> 2400:6500:0:7400::/55 (target_pos:72:has_entry:false) | | | | | | | 0--> 2400:6500:0:7400::/56 (target_pos:71:has_entry:true) | | | | | | | 1--> 2400:6500:0:7500::/56 (target_pos:71:has_entry:true) | | | | | 1--> 2400:6500:100:7000::/54 (target_pos:73:has_entry:false) | | | | | | 0--> 2400:6500:100:7100::/56 (target_pos:71:has_entry:true) | | | | | | 1--> 2400:6500:100:7200::/56 (target_pos:71:has_entry:true) | | | | 1--> 2400:6500:ff00::/64 (target_pos:63:has_entry:true) | | | 1--> 2400:6700:ff00::/64 (target_pos:63:has_entry:true) | | 1--> 2403:b300:ff00::/64 (target_pos:63:has_entry:true) ``` cidranger-1.0.2/brute.go000066400000000000000000000070261373217032300151260ustar00rootroot00000000000000package cidranger import ( "net" rnet "github.com/yl2chen/cidranger/net" ) // bruteRanger is a brute force implementation of Ranger. Insertion and // deletion of networks is performed on an internal storage in the form of // map[string]net.IPNet (constant time operations). However, inclusion tests are // always performed linearly at no guaranteed traversal order of recorded networks, // so one can assume a worst case performance of O(N). The performance can be // boosted many ways, e.g. changing usage of net.IPNet.Contains() to using masked // bits equality checking, but the main purpose of this implementation is for // testing because the correctness of this implementation can be easily guaranteed, // and used as the ground truth when running a wider range of 'random' tests on // other more sophisticated implementations. type bruteRanger struct { ipV4Entries map[string]RangerEntry ipV6Entries map[string]RangerEntry } // newBruteRanger returns a new Ranger. func newBruteRanger() Ranger { return &bruteRanger{ ipV4Entries: make(map[string]RangerEntry), ipV6Entries: make(map[string]RangerEntry), } } // Insert inserts a RangerEntry into ranger. func (b *bruteRanger) Insert(entry RangerEntry) error { network := entry.Network() key := network.String() if _, found := b.ipV4Entries[key]; !found { entries, err := b.getEntriesByVersion(entry.Network().IP) if err != nil { return err } entries[key] = entry } return nil } // Remove removes a RangerEntry identified by given network from ranger. func (b *bruteRanger) Remove(network net.IPNet) (RangerEntry, error) { networks, err := b.getEntriesByVersion(network.IP) if err != nil { return nil, err } key := network.String() if networkToDelete, found := networks[key]; found { delete(networks, key) return networkToDelete, nil } return nil, nil } // Contains returns bool indicating whether given ip is contained by any // network in ranger. func (b *bruteRanger) Contains(ip net.IP) (bool, error) { entries, err := b.getEntriesByVersion(ip) if err != nil { return false, err } for _, entry := range entries { network := entry.Network() if network.Contains(ip) { return true, nil } } return false, nil } // ContainingNetworks returns all RangerEntry(s) that given ip contained in. func (b *bruteRanger) ContainingNetworks(ip net.IP) ([]RangerEntry, error) { entries, err := b.getEntriesByVersion(ip) if err != nil { return nil, err } results := []RangerEntry{} for _, entry := range entries { network := entry.Network() if network.Contains(ip) { results = append(results, entry) } } return results, nil } // CoveredNetworks returns the list of RangerEntry(s) the given ipnet // covers. That is, the networks that are completely subsumed by the // specified network. func (b *bruteRanger) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) { entries, err := b.getEntriesByVersion(network.IP) if err != nil { return nil, err } var results []RangerEntry testNetwork := rnet.NewNetwork(network) for _, entry := range entries { entryNetwork := rnet.NewNetwork(entry.Network()) if testNetwork.Covers(entryNetwork) { results = append(results, entry) } } return results, nil } // Len returns number of networks in ranger. func (b *bruteRanger) Len() int { return len(b.ipV4Entries) + len(b.ipV6Entries) } func (b *bruteRanger) getEntriesByVersion(ip net.IP) (map[string]RangerEntry, error) { if ip.To4() != nil { return b.ipV4Entries, nil } if ip.To16() != nil { return b.ipV6Entries, nil } return nil, ErrInvalidNetworkInput } cidranger-1.0.2/brute_test.go000066400000000000000000000124731373217032300161670ustar00rootroot00000000000000package cidranger import ( "net" "sort" "testing" "github.com/stretchr/testify/assert" ) func TestInsert(t *testing.T) { ranger := newBruteRanger().(*bruteRanger) _, networkIPv4, _ := net.ParseCIDR("0.0.1.0/24") _, networkIPv6, _ := net.ParseCIDR("8000::/96") entryIPv4 := NewBasicRangerEntry(*networkIPv4) entryIPv6 := NewBasicRangerEntry(*networkIPv6) ranger.Insert(entryIPv4) ranger.Insert(entryIPv6) assert.Equal(t, 1, len(ranger.ipV4Entries)) assert.Equal(t, entryIPv4, ranger.ipV4Entries["0.0.1.0/24"]) assert.Equal(t, 1, len(ranger.ipV6Entries)) assert.Equal(t, entryIPv6, ranger.ipV6Entries["8000::/96"]) } func TestInsertError(t *testing.T) { bRanger := newBruteRanger().(*bruteRanger) _, networkIPv4, _ := net.ParseCIDR("0.0.1.0/24") networkIPv4.IP = append(networkIPv4.IP, byte(4)) err := bRanger.Insert(NewBasicRangerEntry(*networkIPv4)) assert.Equal(t, ErrInvalidNetworkInput, err) } func TestRemove(t *testing.T) { ranger := newBruteRanger().(*bruteRanger) _, networkIPv4, _ := net.ParseCIDR("0.0.1.0/24") _, networkIPv6, _ := net.ParseCIDR("8000::/96") _, notInserted, _ := net.ParseCIDR("8000::/96") insertIPv4 := NewBasicRangerEntry(*networkIPv4) insertIPv6 := NewBasicRangerEntry(*networkIPv6) ranger.Insert(insertIPv4) deletedIPv4, err := ranger.Remove(*networkIPv4) assert.NoError(t, err) ranger.Insert(insertIPv6) deletedIPv6, err := ranger.Remove(*networkIPv6) assert.NoError(t, err) entry, err := ranger.Remove(*notInserted) assert.NoError(t, err) assert.Nil(t, entry) assert.Equal(t, insertIPv4, deletedIPv4) assert.Equal(t, 0, len(ranger.ipV4Entries)) assert.Equal(t, insertIPv6, deletedIPv6) assert.Equal(t, 0, len(ranger.ipV6Entries)) } func TestRemoveError(t *testing.T) { r := newBruteRanger().(*bruteRanger) _, invalidNetwork, _ := net.ParseCIDR("0.0.1.0/24") invalidNetwork.IP = append(invalidNetwork.IP, byte(4)) _, err := r.Remove(*invalidNetwork) assert.Equal(t, ErrInvalidNetworkInput, err) } func TestContains(t *testing.T) { r := newBruteRanger().(*bruteRanger) _, network, _ := net.ParseCIDR("0.0.1.0/24") _, network1, _ := net.ParseCIDR("8000::/112") r.Insert(NewBasicRangerEntry(*network)) r.Insert(NewBasicRangerEntry(*network1)) cases := []struct { ip net.IP contains bool err error name string }{ {net.ParseIP("0.0.1.255"), true, nil, "IPv4 should contain"}, {net.ParseIP("0.0.0.255"), false, nil, "IPv4 houldn't contain"}, {net.ParseIP("8000::ffff"), true, nil, "IPv6 shouldn't contain"}, {net.ParseIP("8000::1:ffff"), false, nil, "IPv6 shouldn't contain"}, {append(net.ParseIP("8000::1:ffff"), byte(0)), false, ErrInvalidNetworkInput, "Invalid IP"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { contains, err := r.Contains(tc.ip) if tc.err != nil { assert.Equal(t, tc.err, err) } else { assert.NoError(t, err) assert.Equal(t, tc.contains, contains) } }) } } func TestContainingNetworks(t *testing.T) { r := newBruteRanger().(*bruteRanger) _, network1, _ := net.ParseCIDR("0.0.1.0/24") _, network2, _ := net.ParseCIDR("0.0.1.0/25") _, network3, _ := net.ParseCIDR("8000::/112") _, network4, _ := net.ParseCIDR("8000::/113") entry1 := NewBasicRangerEntry(*network1) entry2 := NewBasicRangerEntry(*network2) entry3 := NewBasicRangerEntry(*network3) entry4 := NewBasicRangerEntry(*network4) r.Insert(entry1) r.Insert(entry2) r.Insert(entry3) r.Insert(entry4) cases := []struct { ip net.IP containingNetworks []RangerEntry err error name string }{ {net.ParseIP("0.0.1.255"), []RangerEntry{entry1}, nil, "IPv4 should contain"}, {net.ParseIP("0.0.1.127"), []RangerEntry{entry1, entry2}, nil, "IPv4 should contain both"}, {net.ParseIP("0.0.0.127"), []RangerEntry{}, nil, "IPv4 should contain none"}, {net.ParseIP("8000::ffff"), []RangerEntry{entry3}, nil, "IPv6 should constain"}, {net.ParseIP("8000::7fff"), []RangerEntry{entry3, entry4}, nil, "IPv6 should contain both"}, {net.ParseIP("8000::1:7fff"), []RangerEntry{}, nil, "IPv6 should contain none"}, {append(net.ParseIP("8000::1:7fff"), byte(0)), nil, ErrInvalidNetworkInput, "Invalid IP"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { networks, err := r.ContainingNetworks(tc.ip) if tc.err != nil { assert.Equal(t, tc.err, err) } else { assert.NoError(t, err) assert.Equal(t, len(tc.containingNetworks), len(networks)) for _, network := range tc.containingNetworks { assert.Contains(t, networks, network) } } }) } } func TestCoveredNetworks(t *testing.T) { for _, tc := range coveredNetworkTests { t.Run(tc.name, func(t *testing.T) { ranger := newBruteRanger() for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := ranger.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } var expectedEntries []string for _, network := range tc.networks { expectedEntries = append(expectedEntries, network) } sort.Strings(expectedEntries) _, snet, _ := net.ParseCIDR(tc.search) networks, err := ranger.CoveredNetworks(*snet) assert.NoError(t, err) var results []string for _, result := range networks { net := result.Network() results = append(results, net.String()) } sort.Strings(results) assert.Equal(t, expectedEntries, results) }) } } cidranger-1.0.2/cidranger.go000066400000000000000000000052301373217032300157360ustar00rootroot00000000000000/* Package cidranger provides utility to store CIDR blocks and perform ip inclusion tests against it. To create a new instance of the path-compressed trie: ranger := NewPCTrieRanger() To insert or remove an entry (any object that satisfies the RangerEntry interface): _, network, _ := net.ParseCIDR("192.168.0.0/24") ranger.Insert(NewBasicRangerEntry(*network)) ranger.Remove(network) If you desire for any value to be attached to the entry, simply create custom struct that satisfies the RangerEntry interface: type RangerEntry interface { Network() net.IPNet } To test whether an IP is contained in the constructed networks ranger: // returns bool, error containsBool, err := ranger.Contains(net.ParseIP("192.168.0.1")) To get a list of CIDR blocks in constructed ranger that contains IP: // returns []RangerEntry, error entries, err := ranger.ContainingNetworks(net.ParseIP("192.168.0.1")) To get a list of all IPv4/IPv6 rangers respectively: // returns []RangerEntry, error entries, err := ranger.CoveredNetworks(*AllIPv4) entries, err := ranger.CoveredNetworks(*AllIPv6) */ package cidranger import ( "fmt" "net" ) // ErrInvalidNetworkInput is returned upon invalid network input. var ErrInvalidNetworkInput = fmt.Errorf("Invalid network input") // ErrInvalidNetworkNumberInput is returned upon invalid network input. var ErrInvalidNetworkNumberInput = fmt.Errorf("Invalid network number input") // AllIPv4 is a IPv4 CIDR that contains all networks var AllIPv4 = parseCIDRUnsafe("0.0.0.0/0") // AllIPv6 is a IPv6 CIDR that contains all networks var AllIPv6 = parseCIDRUnsafe("0::0/0") func parseCIDRUnsafe(s string) *net.IPNet { _, cidr, _ := net.ParseCIDR(s) return cidr } // RangerEntry is an interface for insertable entry into a Ranger. type RangerEntry interface { Network() net.IPNet } type basicRangerEntry struct { ipNet net.IPNet } func (b *basicRangerEntry) Network() net.IPNet { return b.ipNet } // NewBasicRangerEntry returns a basic RangerEntry that only stores the network // itself. func NewBasicRangerEntry(ipNet net.IPNet) RangerEntry { return &basicRangerEntry{ ipNet: ipNet, } } // Ranger is an interface for cidr block containment lookups. type Ranger interface { Insert(entry RangerEntry) error Remove(network net.IPNet) (RangerEntry, error) Contains(ip net.IP) (bool, error) ContainingNetworks(ip net.IP) ([]RangerEntry, error) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) Len() int } // NewPCTrieRanger returns a versionedRanger that supports both IPv4 and IPv6 // using the path compressed trie implemention. func NewPCTrieRanger() Ranger { return newVersionedRanger(newPrefixTree) } cidranger-1.0.2/cidranger_test.go000066400000000000000000000220361373217032300170000ustar00rootroot00000000000000package cidranger import ( "encoding/json" "io/ioutil" "math/rand" "net" "testing" "time" "github.com/stretchr/testify/assert" rnet "github.com/yl2chen/cidranger/net" ) /* ****************************************************************** Test Contains/ContainingNetworks against basic brute force ranger. ****************************************************************** */ func TestContainsAgainstBaseIPv4(t *testing.T) { testContainsAgainstBase(t, 100000, randIPv4Gen) } func TestContainingNetworksAgaistBaseIPv4(t *testing.T) { testContainingNetworksAgainstBase(t, 100000, randIPv4Gen) } func TestCoveredNetworksAgainstBaseIPv4(t *testing.T) { testCoversNetworksAgainstBase(t, 100000, randomIPNetGenFactory(ipV4AWSRangesIPNets)) } // IPv6 spans an extremely large address space (2^128), randomly generated IPs // will often fall outside of the test ranges (AWS public CIDR blocks), so it // it more meaningful for testing to run from a curated list of IPv6 IPs. func TestContainsAgaistBaseIPv6(t *testing.T) { testContainsAgainstBase(t, 100000, curatedAWSIPv6Gen) } func TestContainingNetworksAgaistBaseIPv6(t *testing.T) { testContainingNetworksAgainstBase(t, 100000, curatedAWSIPv6Gen) } func TestCoveredNetworksAgainstBaseIPv6(t *testing.T) { testCoversNetworksAgainstBase(t, 100000, randomIPNetGenFactory(ipV6AWSRangesIPNets)) } func testContainsAgainstBase(t *testing.T, iterations int, ipGen ipGenerator) { if testing.Short() { t.Skip("Skipping memory test in `-short` mode") } rangers := []Ranger{NewPCTrieRanger()} baseRanger := newBruteRanger() for _, ranger := range rangers { configureRangerWithAWSRanges(t, ranger) } configureRangerWithAWSRanges(t, baseRanger) for i := 0; i < iterations; i++ { nn := ipGen() expected, err := baseRanger.Contains(nn.ToIP()) assert.NoError(t, err) for _, ranger := range rangers { actual, err := ranger.Contains(nn.ToIP()) assert.NoError(t, err) assert.Equal(t, expected, actual) } } } func testContainingNetworksAgainstBase(t *testing.T, iterations int, ipGen ipGenerator) { if testing.Short() { t.Skip("Skipping memory test in `-short` mode") } rangers := []Ranger{NewPCTrieRanger()} baseRanger := newBruteRanger() for _, ranger := range rangers { configureRangerWithAWSRanges(t, ranger) } configureRangerWithAWSRanges(t, baseRanger) for i := 0; i < iterations; i++ { nn := ipGen() expected, err := baseRanger.ContainingNetworks(nn.ToIP()) assert.NoError(t, err) for _, ranger := range rangers { actual, err := ranger.ContainingNetworks(nn.ToIP()) assert.NoError(t, err) assert.Equal(t, len(expected), len(actual)) for _, network := range actual { assert.Contains(t, expected, network) } } } } func testCoversNetworksAgainstBase(t *testing.T, iterations int, netGen networkGenerator) { if testing.Short() { t.Skip("Skipping memory test in `-short` mode") } rangers := []Ranger{NewPCTrieRanger()} baseRanger := newBruteRanger() for _, ranger := range rangers { configureRangerWithAWSRanges(t, ranger) } configureRangerWithAWSRanges(t, baseRanger) for i := 0; i < iterations; i++ { network := netGen() expected, err := baseRanger.CoveredNetworks(network.IPNet) assert.NoError(t, err) for _, ranger := range rangers { actual, err := ranger.CoveredNetworks(network.IPNet) assert.NoError(t, err) assert.Equal(t, len(expected), len(actual)) for _, network := range actual { assert.Contains(t, expected, network) } } } } /* ****************************************************************** Benchmarks. ****************************************************************** */ func BenchmarkPCTrieHitIPv4UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("52.95.110.1"), NewPCTrieRanger()) } func BenchmarkBruteRangerHitIPv4UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("52.95.110.1"), newBruteRanger()) } func BenchmarkPCTrieHitIPv6UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("2620:107:300f::36b7:ff81"), NewPCTrieRanger()) } func BenchmarkBruteRangerHitIPv6UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("2620:107:300f::36b7:ff81"), newBruteRanger()) } func BenchmarkPCTrieMissIPv4UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("123.123.123.123"), NewPCTrieRanger()) } func BenchmarkBruteRangerMissIPv4UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("123.123.123.123"), newBruteRanger()) } func BenchmarkPCTrieHMissIPv6UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("2620::ffff"), NewPCTrieRanger()) } func BenchmarkBruteRangerMissIPv6UsingAWSRanges(b *testing.B) { benchmarkContainsUsingAWSRanges(b, net.ParseIP("2620::ffff"), newBruteRanger()) } func BenchmarkPCTrieHitContainingNetworksIPv4UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("52.95.110.1"), NewPCTrieRanger()) } func BenchmarkBruteRangerHitContainingNetworksIPv4UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("52.95.110.1"), newBruteRanger()) } func BenchmarkPCTrieHitContainingNetworksIPv6UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("2620:107:300f::36b7:ff81"), NewPCTrieRanger()) } func BenchmarkBruteRangerHitContainingNetworksIPv6UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("2620:107:300f::36b7:ff81"), newBruteRanger()) } func BenchmarkPCTrieMissContainingNetworksIPv4UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("123.123.123.123"), NewPCTrieRanger()) } func BenchmarkBruteRangerMissContainingNetworksIPv4UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("123.123.123.123"), newBruteRanger()) } func BenchmarkPCTrieHMissContainingNetworksIPv6UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("2620::ffff"), NewPCTrieRanger()) } func BenchmarkBruteRangerMissContainingNetworksIPv6UsingAWSRanges(b *testing.B) { benchmarkContainingNetworksUsingAWSRanges(b, net.ParseIP("2620::ffff"), newBruteRanger()) } func benchmarkContainsUsingAWSRanges(tb testing.TB, nn net.IP, ranger Ranger) { configureRangerWithAWSRanges(tb, ranger) for n := 0; n < tb.(*testing.B).N; n++ { ranger.Contains(nn) } } func benchmarkContainingNetworksUsingAWSRanges(tb testing.TB, nn net.IP, ranger Ranger) { configureRangerWithAWSRanges(tb, ranger) for n := 0; n < tb.(*testing.B).N; n++ { ranger.ContainingNetworks(nn) } } /* ****************************************************************** Helper methods and initialization. ****************************************************************** */ type ipGenerator func() rnet.NetworkNumber func randIPv4Gen() rnet.NetworkNumber { return rnet.NetworkNumber{rand.Uint32()} } func randIPv6Gen() rnet.NetworkNumber { return rnet.NetworkNumber{rand.Uint32(), rand.Uint32(), rand.Uint32(), rand.Uint32()} } func curatedAWSIPv6Gen() rnet.NetworkNumber { randIdx := rand.Intn(len(ipV6AWSRangesIPNets)) // Randomly generate an IP somewhat near the range. network := ipV6AWSRangesIPNets[randIdx] nn := rnet.NewNetworkNumber(network.IP) ones, bits := network.Mask.Size() zeros := bits - ones nnPartIdx := zeros / rnet.BitsPerUint32 nn[nnPartIdx] = rand.Uint32() return nn } type networkGenerator func() rnet.Network func randomIPNetGenFactory(pool []*net.IPNet) networkGenerator { return func() rnet.Network { return rnet.NewNetwork(*pool[rand.Intn(len(pool))]) } } type AWSRanges struct { Prefixes []Prefix `json:"prefixes"` IPv6Prefixes []IPv6Prefix `json:"ipv6_prefixes"` } type Prefix struct { IPPrefix string `json:"ip_prefix"` Region string `json:"region"` Service string `json:"service"` } type IPv6Prefix struct { IPPrefix string `json:"ipv6_prefix"` Region string `json:"region"` Service string `json:"service"` } var awsRanges *AWSRanges var ipV4AWSRangesIPNets []*net.IPNet var ipV6AWSRangesIPNets []*net.IPNet func loadAWSRanges() *AWSRanges { file, err := ioutil.ReadFile("./testdata/aws_ip_ranges.json") if err != nil { panic(err) } var ranges AWSRanges err = json.Unmarshal(file, &ranges) if err != nil { panic(err) } return &ranges } func configureRangerWithAWSRanges(tb testing.TB, ranger Ranger) { for _, prefix := range awsRanges.Prefixes { _, network, err := net.ParseCIDR(prefix.IPPrefix) assert.NoError(tb, err) ranger.Insert(NewBasicRangerEntry(*network)) } for _, prefix := range awsRanges.IPv6Prefixes { _, network, err := net.ParseCIDR(prefix.IPPrefix) assert.NoError(tb, err) ranger.Insert(NewBasicRangerEntry(*network)) } } func init() { awsRanges = loadAWSRanges() for _, prefix := range awsRanges.IPv6Prefixes { _, network, _ := net.ParseCIDR(prefix.IPPrefix) ipV6AWSRangesIPNets = append(ipV6AWSRangesIPNets, network) } for _, prefix := range awsRanges.Prefixes { _, network, _ := net.ParseCIDR(prefix.IPPrefix) ipV4AWSRangesIPNets = append(ipV4AWSRangesIPNets, network) } rand.Seed(time.Now().Unix()) } cidranger-1.0.2/example/000077500000000000000000000000001373217032300151045ustar00rootroot00000000000000cidranger-1.0.2/example/custom-ranger-asn.go000066400000000000000000000040341373217032300210010ustar00rootroot00000000000000/* Example of how to extend github.com/yl2chen/cidranger This adds ASN as a string field, along with methods to get the ASN and the CIDR as strings Thank you to yl2chen for his assistance and work on this library */ package main import ( "fmt" "net" "os" "github.com/yl2chen/cidranger" ) // custom structure that conforms to RangerEntry interface type customRangerEntry struct { ipNet net.IPNet asn string } // get function for network func (b *customRangerEntry) Network() net.IPNet { return b.ipNet } // get function for network converted to string func (b *customRangerEntry) NetworkStr() string { return b.ipNet.String() } // get function for ASN func (b *customRangerEntry) Asn() string { return b.asn } // create customRangerEntry object using net and asn func newCustomRangerEntry(ipNet net.IPNet, asn string) cidranger.RangerEntry { return &customRangerEntry{ ipNet: ipNet, asn: asn, } } // entry point func main() { // instantiate NewPCTrieRanger ranger := cidranger.NewPCTrieRanger() // Load sample data using our custom function _, network, _ := net.ParseCIDR("192.168.1.0/24") ranger.Insert(newCustomRangerEntry(*network, "0001")) _, network, _ = net.ParseCIDR("128.168.1.0/24") ranger.Insert(newCustomRangerEntry(*network, "0002")) // Check if IP is contained within ranger contains, err := ranger.Contains(net.ParseIP("128.168.1.7")) if err != nil { fmt.Println("ranger.Contains()", err.Error()) os.Exit(1) } fmt.Println("Contains:", contains) // request networks containing this IP ip := "192.168.1.42" entries, err := ranger.ContainingNetworks(net.ParseIP(ip)) if err != nil { fmt.Println("ranger.ContainingNetworks()", err.Error()) os.Exit(1) } fmt.Printf("Entries for %s:\n", ip) for _, e := range entries { // Cast e (cidranger.RangerEntry to struct customRangerEntry entry, ok := e.(*customRangerEntry) if !ok { continue } // Get network (converted to string by function) n := entry.NetworkStr() // Get ASN a := entry.Asn() // Display fmt.Println("\t", n, a) } } cidranger-1.0.2/go.mod000066400000000000000000000001311373217032300145520ustar00rootroot00000000000000module github.com/yl2chen/cidranger go 1.13 require github.com/stretchr/testify v1.4.0 cidranger-1.0.2/go.sum000066400000000000000000000017101373217032300146030ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= cidranger-1.0.2/net/000077500000000000000000000000001373217032300142375ustar00rootroot00000000000000cidranger-1.0.2/net/ip.go000066400000000000000000000156611373217032300152070ustar00rootroot00000000000000/* Package net provides utility functions for working with IPs (net.IP). */ package net import ( "encoding/binary" "fmt" "math" "net" ) // IPVersion is version of IP address. type IPVersion string // Helper constants. const ( IPv4Uint32Count = 1 IPv6Uint32Count = 4 BitsPerUint32 = 32 BytePerUint32 = 4 IPv4 IPVersion = "IPv4" IPv6 IPVersion = "IPv6" ) // ErrInvalidBitPosition is returned when bits requested is not valid. var ErrInvalidBitPosition = fmt.Errorf("bit position not valid") // ErrVersionMismatch is returned upon mismatch in network input versions. var ErrVersionMismatch = fmt.Errorf("Network input version mismatch") // ErrNoGreatestCommonBit is an error returned when no greatest common bit // exists for the cidr ranges. var ErrNoGreatestCommonBit = fmt.Errorf("No greatest common bit") // NetworkNumber represents an IP address using uint32 as internal storage. // IPv4 usings 1 uint32, while IPv6 uses 4 uint32. type NetworkNumber []uint32 // NewNetworkNumber returns a equivalent NetworkNumber to given IP address, // return nil if ip is neither IPv4 nor IPv6. func NewNetworkNumber(ip net.IP) NetworkNumber { if ip == nil { return nil } coercedIP := ip.To4() parts := 1 if coercedIP == nil { coercedIP = ip.To16() parts = 4 } if coercedIP == nil { return nil } nn := make(NetworkNumber, parts) for i := 0; i < parts; i++ { idx := i * net.IPv4len nn[i] = binary.BigEndian.Uint32(coercedIP[idx : idx+net.IPv4len]) } return nn } // ToV4 returns ip address if ip is IPv4, returns nil otherwise. func (n NetworkNumber) ToV4() NetworkNumber { if len(n) != IPv4Uint32Count { return nil } return n } // ToV6 returns ip address if ip is IPv6, returns nil otherwise. func (n NetworkNumber) ToV6() NetworkNumber { if len(n) != IPv6Uint32Count { return nil } return n } // ToIP returns equivalent net.IP. func (n NetworkNumber) ToIP() net.IP { ip := make(net.IP, len(n)*BytePerUint32) for i := 0; i < len(n); i++ { idx := i * net.IPv4len binary.BigEndian.PutUint32(ip[idx:idx+net.IPv4len], n[i]) } if len(ip) == net.IPv4len { ip = net.IPv4(ip[0], ip[1], ip[2], ip[3]) } return ip } // Equal is the equality test for 2 network numbers. func (n NetworkNumber) Equal(n1 NetworkNumber) bool { if len(n) != len(n1) { return false } if n[0] != n1[0] { return false } if len(n) == IPv6Uint32Count { return n[1] == n1[1] && n[2] == n1[2] && n[3] == n1[3] } return true } // Next returns the next logical network number. func (n NetworkNumber) Next() NetworkNumber { newIP := make(NetworkNumber, len(n)) copy(newIP, n) for i := len(newIP) - 1; i >= 0; i-- { newIP[i]++ if newIP[i] > 0 { break } } return newIP } // Previous returns the previous logical network number. func (n NetworkNumber) Previous() NetworkNumber { newIP := make(NetworkNumber, len(n)) copy(newIP, n) for i := len(newIP) - 1; i >= 0; i-- { newIP[i]-- if newIP[i] < math.MaxUint32 { break } } return newIP } // Bit returns uint32 representing the bit value at given position, e.g., // "128.0.0.0" has bit value of 1 at position 31, and 0 for positions 30 to 0. func (n NetworkNumber) Bit(position uint) (uint32, error) { if int(position) > len(n)*BitsPerUint32-1 { return 0, ErrInvalidBitPosition } idx := len(n) - 1 - int(position/BitsPerUint32) // Mod 31 to get array index. rShift := position & (BitsPerUint32 - 1) return (n[idx] >> rShift) & 1, nil } // LeastCommonBitPosition returns the smallest position of the preceding common // bits of the 2 network numbers, and returns an error ErrNoGreatestCommonBit // if the two network number diverges from the first bit. // e.g., if the network number diverges after the 1st bit, it returns 131 for // IPv6 and 31 for IPv4 . func (n NetworkNumber) LeastCommonBitPosition(n1 NetworkNumber) (uint, error) { if len(n) != len(n1) { return 0, ErrVersionMismatch } for i := 0; i < len(n); i++ { mask := uint32(1) << 31 pos := uint(31) for ; mask > 0; mask >>= 1 { if n[i]&mask != n1[i]&mask { if i == 0 && pos == 31 { return 0, ErrNoGreatestCommonBit } return (pos + 1) + uint(BitsPerUint32)*uint(len(n)-i-1), nil } pos-- } } return 0, nil } // Network represents a block of network numbers, also known as CIDR. type Network struct { net.IPNet Number NetworkNumber Mask NetworkNumberMask } // NewNetwork returns Network built using given net.IPNet. func NewNetwork(ipNet net.IPNet) Network { return Network{ IPNet: ipNet, Number: NewNetworkNumber(ipNet.IP), Mask: NetworkNumberMask(NewNetworkNumber(net.IP(ipNet.Mask))), } } // Masked returns a new network conforming to new mask. func (n Network) Masked(ones int) Network { mask := net.CIDRMask(ones, len(n.Number)*BitsPerUint32) return NewNetwork(net.IPNet{ IP: n.IP.Mask(mask), Mask: mask, }) } // Contains returns true if NetworkNumber is in range of Network, false // otherwise. func (n Network) Contains(nn NetworkNumber) bool { if len(n.Mask) != len(nn) { return false } if nn[0]&n.Mask[0] != n.Number[0] { return false } if len(nn) == IPv6Uint32Count { return nn[1]&n.Mask[1] == n.Number[1] && nn[2]&n.Mask[2] == n.Number[2] && nn[3]&n.Mask[3] == n.Number[3] } return true } // Contains returns true if Network covers o, false otherwise func (n Network) Covers(o Network) bool { if len(n.Number) != len(o.Number) { return false } nMaskSize, _ := n.IPNet.Mask.Size() oMaskSize, _ := o.IPNet.Mask.Size() return n.Contains(o.Number) && nMaskSize <= oMaskSize } // LeastCommonBitPosition returns the smallest position of the preceding common // bits of the 2 networks, and returns an error ErrNoGreatestCommonBit // if the two network number diverges from the first bit. func (n Network) LeastCommonBitPosition(n1 Network) (uint, error) { maskSize, _ := n.IPNet.Mask.Size() if maskSize1, _ := n1.IPNet.Mask.Size(); maskSize1 < maskSize { maskSize = maskSize1 } maskPosition := len(n1.Number)*BitsPerUint32 - maskSize lcb, err := n.Number.LeastCommonBitPosition(n1.Number) if err != nil { return 0, err } return uint(math.Max(float64(maskPosition), float64(lcb))), nil } // Equal is the equality test for 2 networks. func (n Network) Equal(n1 Network) bool { return n.String() == n1.String() } func (n Network) String() string { return n.IPNet.String() } // NetworkNumberMask is an IP address. type NetworkNumberMask NetworkNumber // Mask returns a new masked NetworkNumber from given NetworkNumber. func (m NetworkNumberMask) Mask(n NetworkNumber) (NetworkNumber, error) { if len(m) != len(n) { return nil, ErrVersionMismatch } result := make(NetworkNumber, len(m)) result[0] = m[0] & n[0] if len(m) == IPv6Uint32Count { result[1] = m[1] & n[1] result[2] = m[2] & n[2] result[3] = m[3] & n[3] } return result, nil } // NextIP returns the next sequential ip. func NextIP(ip net.IP) net.IP { return NewNetworkNumber(ip).Next().ToIP() } // PreviousIP returns the previous sequential ip. func PreviousIP(ip net.IP) net.IP { return NewNetworkNumber(ip).Previous().ToIP() } cidranger-1.0.2/net/ip_test.go000066400000000000000000000350401373217032300162370ustar00rootroot00000000000000package net import ( "math" "net" "testing" "github.com/stretchr/testify/assert" ) func TestNewNetworkNumber(t *testing.T) { cases := []struct { ip net.IP nn NetworkNumber name string }{ {nil, nil, "nil input"}, {net.IP([]byte{1, 1, 1, 1, 1}), nil, "bad input"}, {net.ParseIP("128.0.0.0"), NetworkNumber([]uint32{2147483648}), "IPv4"}, { net.ParseIP("2001:0db8::ff00:0042:8329"), NetworkNumber([]uint32{536939960, 0, 65280, 4358953}), "IPv6", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.nn, NewNetworkNumber(tc.ip)) }) } } func TestNetworkNumberAssertion(t *testing.T) { cases := []struct { ip NetworkNumber to4 NetworkNumber to6 NetworkNumber name string }{ {NetworkNumber([]uint32{1}), NetworkNumber([]uint32{1}), nil, "is IPv4"}, {NetworkNumber([]uint32{1, 1, 1, 1}), nil, NetworkNumber([]uint32{1, 1, 1, 1}), "is IPv6"}, {NetworkNumber([]uint32{1, 1}), nil, nil, "is invalid"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.to4, tc.ip.ToV4()) assert.Equal(t, tc.to6, tc.ip.ToV6()) }) } } func TestNetworkNumberBit(t *testing.T) { cases := []struct { ip NetworkNumber ones map[uint]bool name string }{ {NewNetworkNumber(net.ParseIP("128.0.0.0")), map[uint]bool{31: true}, "128.0.0.0"}, {NewNetworkNumber(net.ParseIP("1.1.1.1")), map[uint]bool{0: true, 8: true, 16: true, 24: true}, "1.1.1.1"}, {NewNetworkNumber(net.ParseIP("8000::")), map[uint]bool{127: true}, "8000::"}, {NewNetworkNumber(net.ParseIP("8000::8000")), map[uint]bool{127: true, 15: true}, "8000::8000"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { for i := uint(0); i < uint(len(tc.ip)*BitsPerUint32); i++ { bit, err := tc.ip.Bit(i) assert.NoError(t, err) if _, isOne := tc.ones[i]; isOne { assert.Equal(t, uint32(1), bit) } else { assert.Equal(t, uint32(0), bit) } } }) } } func TestNetworkNumberBitError(t *testing.T) { cases := []struct { ip NetworkNumber position uint err error name string }{ {NewNetworkNumber(net.ParseIP("128.0.0.0")), 0, nil, "IPv4 index in bound"}, {NewNetworkNumber(net.ParseIP("128.0.0.0")), 31, nil, "IPv4 index in bound"}, {NewNetworkNumber(net.ParseIP("128.0.0.0")), 32, ErrInvalidBitPosition, "IPv4 index out of bounds"}, {NewNetworkNumber(net.ParseIP("8000::")), 0, nil, "IPv6 index in bound"}, {NewNetworkNumber(net.ParseIP("8000::")), 127, nil, "IPv6 index in bound"}, {NewNetworkNumber(net.ParseIP("8000::")), 128, ErrInvalidBitPosition, "IPv6 index out of bounds"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, err := tc.ip.Bit(tc.position) assert.Equal(t, tc.err, err) }) } } func TestNetworkNumberEqual(t *testing.T) { cases := []struct { n1 NetworkNumber n2 NetworkNumber equals bool name string }{ {NetworkNumber{math.MaxUint32}, NetworkNumber{math.MaxUint32}, true, "IPv4 equals"}, {NetworkNumber{math.MaxUint32}, NetworkNumber{math.MaxUint32 - 1}, false, "IPv4 does not equal"}, {NetworkNumber{1, 1, 1, 1}, NetworkNumber{1, 1, 1, 1}, true, "IPv6 equals"}, {NetworkNumber{1, 1, 1, 1}, NetworkNumber{1, 1, 1, 2}, false, "IPv6 does not equal"}, {NetworkNumber{1}, NetworkNumber{1, 2, 3, 4}, false, "Version mismatch"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.equals, tc.n1.Equal(tc.n2)) }) } } func TestNetworkNumberNext(t *testing.T) { cases := []struct { ip string next string name string }{ {"0.0.0.0", "0.0.0.1", "IPv4 basic"}, {"0.0.0.255", "0.0.1.0", "IPv4 rollover"}, {"0.255.255.255", "1.0.0.0", "IPv4 consecutive rollover"}, {"8000::0", "8000::1", "IPv6 basic"}, {"0::ffff", "0::1:0", "IPv6 rollover"}, {"0:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "1::", "IPv6 consecutive rollover"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { ip := NewNetworkNumber(net.ParseIP(tc.ip)) expected := NewNetworkNumber(net.ParseIP(tc.next)) assert.Equal(t, expected, ip.Next()) }) } } func TestNeworkNumberPrevious(t *testing.T) { cases := []struct { ip string previous string name string }{ {"0.0.0.1", "0.0.0.0", "IPv4 basic"}, {"0.0.1.0", "0.0.0.255", "IPv4 rollover"}, {"1.0.0.0", "0.255.255.255", "IPv4 consecutive rollover"}, {"8000::1", "8000::0", "IPv6 basic"}, {"0::1:0", "0::ffff", "IPv6 rollover"}, {"1::0", "0:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "IPv6 consecutive rollover"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { ip := NewNetworkNumber(net.ParseIP(tc.ip)) expected := NewNetworkNumber(net.ParseIP(tc.previous)) assert.Equal(t, expected, ip.Previous()) }) } } func TestLeastCommonBitPositionForNetworks(t *testing.T) { cases := []struct { ip1 NetworkNumber ip2 NetworkNumber position uint err error name string }{ { NetworkNumber([]uint32{2147483648}), NetworkNumber([]uint32{3221225472, 0, 0, 0}), 0, ErrVersionMismatch, "Version mismatch", }, { NetworkNumber([]uint32{2147483648}), NetworkNumber([]uint32{3221225472}), 31, nil, "IPv4 31st position", }, { NetworkNumber([]uint32{2147483648}), NetworkNumber([]uint32{2147483648}), 0, nil, "IPv4 0th position", }, { NetworkNumber([]uint32{2147483648}), NetworkNumber([]uint32{1}), 0, ErrNoGreatestCommonBit, "IPv4 diverge at first bit", }, { NetworkNumber([]uint32{2147483648, 0, 0, 0}), NetworkNumber([]uint32{3221225472, 0, 0, 0}), 127, nil, "IPv6 127th position", }, { NetworkNumber([]uint32{2147483648, 1, 1, 1}), NetworkNumber([]uint32{2147483648, 1, 1, 1}), 0, nil, "IPv6 0th position", }, { NetworkNumber([]uint32{2147483648, 0, 0, 0}), NetworkNumber([]uint32{0, 0, 0, 1}), 0, ErrNoGreatestCommonBit, "IPv6 diverge at first bit", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { pos, err := tc.ip1.LeastCommonBitPosition(tc.ip2) assert.Equal(t, tc.err, err) assert.Equal(t, tc.position, pos) }) } } func TestNewNetwork(t *testing.T) { _, ipNet, _ := net.ParseCIDR("192.128.0.0/24") n := NewNetwork(*ipNet) assert.Equal(t, *ipNet, n.IPNet) assert.Equal(t, NetworkNumber{3229614080}, n.Number) assert.Equal(t, NetworkNumberMask{math.MaxUint32 - uint32(math.MaxUint8)}, n.Mask) } func TestNetworkMasked(t *testing.T) { cases := []struct { network string mask int maskedNetwork string }{ {"192.168.0.0/16", 16, "192.168.0.0/16"}, {"192.168.0.0/16", 14, "192.168.0.0/14"}, {"192.168.0.0/16", 18, "192.168.0.0/18"}, {"192.168.0.0/16", 8, "192.0.0.0/8"}, {"8000::/128", 96, "8000::/96"}, {"8000::/128", 128, "8000::/128"}, {"8000::/96", 112, "8000::/112"}, {"8000:ffff::/96", 16, "8000::/16"}, } for _, testcase := range cases { _, network, _ := net.ParseCIDR(testcase.network) _, expected, _ := net.ParseCIDR(testcase.maskedNetwork) n1 := NewNetwork(*network) e1 := NewNetwork(*expected) assert.True(t, e1.String() == n1.Masked(testcase.mask).String()) } } func TestNetworkEqual(t *testing.T) { cases := []struct { n1 string n2 string equal bool name string }{ {"192.128.0.0/24", "192.128.0.0/24", true, "IPv4 equals"}, {"192.128.0.0/24", "192.128.0.0/23", false, "IPv4 not equals"}, {"8000::/24", "8000::/24", true, "IPv6 equals"}, {"8000::/24", "8000::/23", false, "IPv6 not equals"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, ipNet1, _ := net.ParseCIDR(tc.n1) _, ipNet2, _ := net.ParseCIDR(tc.n2) assert.Equal(t, tc.equal, NewNetwork(*ipNet1).Equal(NewNetwork(*ipNet2))) }) } } func TestNetworkContains(t *testing.T) { cases := []struct { network string firstIP string lastIP string name string }{ {"192.168.0.0/24", "192.168.0.0", "192.168.0.255", "192.168.0.0/24 contains"}, {"8000::0/120", "8000::0", "8000::ff", "8000::0/120 contains"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, net1, _ := net.ParseCIDR(tc.network) network := NewNetwork(*net1) ip := NewNetworkNumber(net.ParseIP(tc.firstIP)) lastIP := NewNetworkNumber(net.ParseIP(tc.lastIP)) assert.False(t, network.Contains(ip.Previous())) assert.False(t, network.Contains(lastIP.Next())) for ; !ip.Equal(lastIP.Next()); ip = ip.Next() { assert.True(t, network.Contains(ip)) } }) } } func TestNetworkContainsVersionMismatch(t *testing.T) { cases := []struct { network string ip string name string }{ {"192.168.0.0/24", "8000::0", "IPv6 in IPv4 network"}, {"8000::0/120", "192.168.0.0", "IPv4 in IPv6 network"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, net1, _ := net.ParseCIDR(tc.network) network := NewNetwork(*net1) assert.False(t, network.Contains(NewNetworkNumber(net.ParseIP(tc.ip)))) }) } } func TestNetworkCovers(t *testing.T) { cases := []struct { network string covers string result bool name string }{ {"10.0.0.0/24", "10.0.0.1/25", true, "contains"}, {"10.0.0.0/24", "11.0.0.1/25", false, "not contains"}, {"10.0.0.0/16", "10.0.0.0/15", false, "prefix false"}, {"10.0.0.0/15", "10.0.0.0/16", true, "prefix true"}, {"10.0.0.0/15", "10.0.0.0/15", true, "same"}, {"10::0/15", "10.0.0.0/15", false, "ip version mismatch"}, {"10::0/15", "10::0/16", true, "ipv6"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, n, _ := net.ParseCIDR(tc.network) network := NewNetwork(*n) _, n, _ = net.ParseCIDR(tc.covers) covers := NewNetwork(*n) assert.Equal(t, tc.result, network.Covers(covers)) }) } } func TestNetworkLeastCommonBitPosition(t *testing.T) { cases := []struct { cidr1 string cidr2 string expectedPos uint expectedErr error name string }{ {"0.0.1.0/24", "0.0.0.0/24", uint(9), nil, "IPv4 diverge before mask pos"}, {"0.0.0.0/24", "0.0.0.0/24", uint(8), nil, "IPv4 diverge after mask pos"}, {"0.0.0.128/24", "0.0.0.0/16", uint(16), nil, "IPv4 different mask pos"}, {"128.0.0.0/24", "0.0.0.0/24", 0, ErrNoGreatestCommonBit, "IPv4 diverge at 1st pos"}, {"8000::/96", "8000::1:0:0/96", uint(33), nil, "IPv6 diverge before mask pos"}, {"8000::/96", "8000::8:0/96", uint(32), nil, "IPv6 diverge after mask pos"}, {"8000::/96", "8000::/95", uint(33), nil, "IPv6 different mask pos"}, {"ffff::0/24", "0::1/24", 0, ErrNoGreatestCommonBit, "IPv6 diverge at 1st pos"}, } for _, c := range cases { _, cidr1, err := net.ParseCIDR(c.cidr1) assert.NoError(t, err) _, cidr2, err := net.ParseCIDR(c.cidr2) assert.NoError(t, err) n1 := NewNetwork(*cidr1) pos, err := n1.LeastCommonBitPosition(NewNetwork(*cidr2)) if c.expectedErr != nil { assert.Equal(t, c.expectedErr, err) } else { assert.Equal(t, c.expectedPos, pos) } } } func TestMask(t *testing.T) { cases := []struct { mask NetworkNumberMask ip NetworkNumber masked NetworkNumber err error name string }{ {NetworkNumberMask{math.MaxUint32}, NetworkNumber{math.MaxUint32}, NetworkNumber{math.MaxUint32}, nil, "nop IPv4 mask"}, {NetworkNumberMask{math.MaxUint32 - math.MaxUint16}, NetworkNumber{math.MaxUint16 + 1}, NetworkNumber{math.MaxUint16 + 1}, nil, "nop IPv4 mask"}, {NetworkNumberMask{math.MaxUint32 - math.MaxUint16}, NetworkNumber{math.MaxUint32}, NetworkNumber{math.MaxUint32 - math.MaxUint16}, nil, "IPv4 masked"}, {NetworkNumberMask{math.MaxUint32, 0, 0, 0}, NetworkNumber{math.MaxUint32, 0, 0, 0}, NetworkNumber{math.MaxUint32, 0, 0, 0}, nil, "nop IPv6 mask"}, {NetworkNumberMask{math.MaxUint32 - math.MaxUint16, 0, 0, 0}, NetworkNumber{math.MaxUint16 + 1, 0, 0, 0}, NetworkNumber{math.MaxUint16 + 1, 0, 0, 0}, nil, "nop IPv6 mask"}, {NetworkNumberMask{math.MaxUint32 - math.MaxUint16, 0, 0, 0}, NetworkNumber{math.MaxUint32, 0, 0, 0}, NetworkNumber{math.MaxUint32 - math.MaxUint16, 0, 0, 0}, nil, "IPv6 masked"}, {NetworkNumberMask{math.MaxUint32}, NetworkNumber{math.MaxUint32, 0}, nil, ErrVersionMismatch, "Version mismatch"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { masked, err := tc.mask.Mask(tc.ip) assert.Equal(t, tc.masked, masked) assert.Equal(t, tc.err, err) }) } } func TestNextIP(t *testing.T) { cases := []struct { ip string next string name string }{ {"0.0.0.0", "0.0.0.1", "IPv4 basic"}, {"0.0.0.255", "0.0.1.0", "IPv4 rollover"}, {"0.255.255.255", "1.0.0.0", "IPv4 consecutive rollover"}, {"8000::0", "8000::1", "IPv6 basic"}, {"0::ffff", "0::1:0", "IPv6 rollover"}, {"0:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "1::", "IPv6 consecutive rollover"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, net.ParseIP(tc.next), NextIP(net.ParseIP(tc.ip))) }) } } func TestPreviousIP(t *testing.T) { cases := []struct { ip string next string name string }{ {"0.0.0.1", "0.0.0.0", "IPv4 basic"}, {"0.0.1.0", "0.0.0.255", "IPv4 rollover"}, {"1.0.0.0", "0.255.255.255", "IPv4 consecutive rollover"}, {"8000::1", "8000::0", "IPv6 basic"}, {"0::1:0", "0::ffff", "IPv6 rollover"}, {"1::0", "0:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "IPv6 consecutive rollover"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, net.ParseIP(tc.next), PreviousIP(net.ParseIP(tc.ip))) }) } } /* ********************************* Benchmarking ip manipulations. ********************************* */ func BenchmarkNetworkNumberBitIPv4(b *testing.B) { benchmarkNetworkNumberBit(b, "52.95.110.1", 6) } func BenchmarkNetworkNumberBitIPv6(b *testing.B) { benchmarkNetworkNumberBit(b, "2600:1ffe:e000::", 44) } func BenchmarkNetworkNumberEqualIPv4(b *testing.B) { benchmarkNetworkNumberEqual(b, "52.95.110.1", "52.95.110.1") } func BenchmarkNetworkNumberEqualIPv6(b *testing.B) { benchmarkNetworkNumberEqual(b, "2600:1ffe:e000::", "2600:1ffe:e000::") } func BenchmarkNetworkContainsIPv4(b *testing.B) { benchmarkNetworkContains(b, "52.95.110.0/24", "52.95.110.1") } func BenchmarkNetworkContainsIPv6(b *testing.B) { benchmarkNetworkContains(b, "2600:1ffe:e000::/40", "2600:1ffe:f000::") } func benchmarkNetworkNumberBit(b *testing.B, ip string, pos uint) { nn := NewNetworkNumber(net.ParseIP(ip)) for n := 0; n < b.N; n++ { nn.Bit(pos) } } func benchmarkNetworkNumberEqual(b *testing.B, ip1 string, ip2 string) { nn1 := NewNetworkNumber(net.ParseIP(ip1)) nn2 := NewNetworkNumber(net.ParseIP(ip2)) for n := 0; n < b.N; n++ { nn1.Equal(nn2) } } func benchmarkNetworkContains(b *testing.B, cidr string, ip string) { nn := NewNetworkNumber(net.ParseIP(ip)) _, ipNet, _ := net.ParseCIDR(cidr) network := NewNetwork(*ipNet) for n := 0; n < b.N; n++ { network.Contains(nn) } } cidranger-1.0.2/testdata/000077500000000000000000000000001373217032300152625ustar00rootroot00000000000000cidranger-1.0.2/testdata/aws_ip_ranges.json000066400000000000000000004074701373217032300210120ustar00rootroot00000000000000{ "syncToken": "1502143334", "createDate": "2017-08-07-22-02-14", "prefixes": [ { "ip_prefix": "13.32.0.0/15", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "13.54.0.0/15", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "13.56.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "13.57.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "13.58.0.0/15", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "13.112.0.0/14", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "13.124.0.0/16", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "13.125.0.0/16", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "13.126.0.0/15", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "13.209.0.0/16", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "13.210.0.0/15", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "13.228.0.0/15", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "13.230.0.0/15", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "13.232.0.0/14", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "13.236.0.0/14", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "13.250.0.0/15", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "18.194.0.0/15", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "18.196.0.0/15", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "18.216.0.0/14", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "18.220.0.0/14", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "18.231.0.0/16", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "23.20.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "27.0.0.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "34.192.0.0/12", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "34.208.0.0/12", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "34.224.0.0/12", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "34.240.0.0/13", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "34.248.0.0/13", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "35.154.0.0/16", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "35.155.0.0/16", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "35.156.0.0/14", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "35.160.0.0/13", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "35.168.0.0/13", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "35.176.0.0/15", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "35.178.0.0/15", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "35.180.0.0/15", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "35.182.0.0/15", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "43.250.192.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "43.250.193.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "46.51.128.0/18", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "46.51.192.0/20", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "46.51.216.0/21", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "46.51.224.0/19", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "46.137.0.0/17", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "46.137.128.0/18", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "46.137.192.0/19", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "46.137.224.0/19", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "50.16.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "50.18.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "50.19.0.0/16", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "50.112.0.0/16", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.0.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.2.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.4.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.8.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.9.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.10.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.12.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.14.0.0/16", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.15.0.0/16", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.16.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.18.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.20.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.24.0.0/14", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.28.0.0/16", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.29.0.0/16", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.30.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.32.0.0/14", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.36.0.0/14", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.40.0.0/14", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.44.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.46.0.0/18", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "52.46.64.0/20", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.46.80.0/21", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.46.88.0/22", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.46.92.0/22", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.47.0.0/16", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.48.0.0/14", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.52.0.0/15", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.54.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.56.0.0/16", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.57.0.0/16", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.58.0.0/15", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.60.0.0/16", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.61.0.0/16", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.62.0.0/15", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.64.0.0/17", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.64.128.0/17", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.65.0.0/16", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.66.0.0/16", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.67.0.0/16", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.68.0.0/15", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.70.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.72.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.74.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.76.0.0/17", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.76.128.0/17", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.77.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.78.0.0/16", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.79.0.0/16", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.80.0.0/16", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "52.82.187.0/24", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.82.188.0/22", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.82.196.0/22", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.82.200.0/25", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.82.204.0/23", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.82.208.0/20", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.83.0.0/16", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.84.0.0/15", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "52.86.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.88.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.90.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.92.0.0/20", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.92.16.0/20", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.92.32.0/22", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.92.39.0/24", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.92.40.0/21", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.92.48.0/22", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.92.52.0/22", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.92.56.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.92.60.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.92.64.0/22", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.92.68.0/22", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.92.72.0/22", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.92.76.0/22", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.92.80.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.92.84.0/22", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.92.88.0/22", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.92.248.0/22", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.92.252.0/22", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.93.0.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.93.1.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.93.2.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.93.3.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.93.4.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.93.5.0/24", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.93.8.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.93.16.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.0.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.4.0/24", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.94.5.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.6.0/24", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.94.7.0/24", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.8.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.94.9.0/24", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.10.0/24", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.11.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.94.12.0/24", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.13.0/24", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.94.14.0/24", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.15.0/24", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.16.0/24", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.94.17.0/24", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.20.0/24", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.94.24.0/23", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.26.0/23", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.28.0/23", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.30.0/23", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.32.0/20", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.48.0/20", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.64.0/22", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.72.0/22", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.80.0/20", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.96.0/20", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.112.0/22", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.192.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.196.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.197.0/24", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.198.0/28", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.16/28", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.32/28", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.48/28", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.64/28", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.94.198.80/28", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.96/28", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.112/28", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.94.198.128/28", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.198.144/28", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.199.0/24", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.94.200.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.94.204.0/23", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.206.0/23", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.208.0/21", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.216.0/21", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.224.0/20", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.240.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.244.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.0/28", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.16/28", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.32/28", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.48/28", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.64/28", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.94.248.80/28", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.96/28", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.248.112/28", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.128/28", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.144/28", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.160/28", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.94.248.176/28", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.94.248.192/28", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.248.208/28", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.94.248.224/28", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.249.0/28", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "52.94.249.16/28", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "52.94.249.32/28", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.94.249.64/28", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.94.249.80/28", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.94.252.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.94.254.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.0.0/20", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.95.16.0/21", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.95.24.0/22", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.95.28.0/24", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.95.30.0/23", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.34.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.35.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.36.0/22", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.40.0/24", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.95.48.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.56.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.60.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.61.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.62.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.63.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.64.0/20", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.95.80.0/20", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.95.96.0/22", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.95.100.0/22", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.104.0/22", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.108.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.110.0/24", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "52.95.111.0/24", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.112.0/20", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.128.0/21", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.136.0/23", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.138.0/24", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.142.0/23", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.144.0/24", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.145.0/24", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.95.146.0/23", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.95.148.0/23", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.95.150.0/24", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.95.154.0/23", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.95.156.0/24", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.95.192.0/20", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.212.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.240.0/24", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.241.0/24", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.242.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.243.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.244.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.245.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.246.0/24", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.247.0/24", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.95.248.0/24", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.95.249.0/24", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.95.250.0/24", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "52.95.251.0/24", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.95.252.0/24", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.253.0/24", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "52.95.254.0/24", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "52.95.255.0/28", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.16/28", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "52.95.255.32/28", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.48/28", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.64/28", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.80/28", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.96/28", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.112/28", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.95.255.128/28", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.95.255.144/28", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "52.119.160.0/20", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.119.176.0/21", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.119.184.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.119.188.0/22", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.119.192.0/22", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.119.196.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.119.206.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.119.208.0/23", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.119.212.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.119.214.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.119.216.0/21", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.119.224.0/21", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.119.232.0/21", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.192.0.0/15", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.196.0.0/14", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.200.0.0/13", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.208.0.0/13", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.216.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "52.218.0.0/17", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "52.218.128.0/17", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "52.219.0.0/20", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.219.16.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.219.20.0/22", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.219.24.0/21", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "52.219.32.0/21", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.219.40.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.219.44.0/22", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.219.56.0/22", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.219.60.0/23", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "52.219.62.0/23", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.219.64.0/22", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "52.219.68.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "52.219.72.0/22", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "52.219.76.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.219.80.0/20", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "52.220.0.0/15", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "52.222.0.0/17", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "52.222.128.0/17", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.64.0.0/15", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.66.0.0/16", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.67.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.68.0.0/14", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.72.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.74.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.76.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.78.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.79.0.0/16", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.80.0.0/13", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.88.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.92.0.0/17", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.92.128.0/17", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.93.0.0/16", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "54.94.0.0/16", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.95.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.144.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.148.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.150.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.151.0.0/17", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.151.128.0/17", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.152.0.0/16", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.153.0.0/17", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.153.128.0/17", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.154.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.155.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.156.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.160.0.0/13", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.168.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.169.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.170.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.172.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.174.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.176.0.0/15", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.178.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.179.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.182.0.0/16", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.183.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.184.0.0/13", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.192.0.0/16", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.193.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.194.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.196.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.198.0.0/16", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.199.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.200.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.202.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.204.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.206.0.0/16", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.207.0.0/16", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.208.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.210.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.212.0.0/15", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.214.0.0/16", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.215.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.216.0.0/15", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.218.0.0/16", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.219.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.220.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.221.0.0/16", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.222.0.0/19", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.222.48.0/22", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.222.57.0/24", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.222.58.0/28", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.222.128.0/17", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.223.0.0/16", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.224.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.226.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.228.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.229.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.230.0.0/16", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.231.0.0/17", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.231.128.0/19", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.231.160.0/19", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.231.192.0/20", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "54.231.224.0/21", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.231.232.0/21", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.231.240.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.231.244.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.231.248.0/22", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.231.252.0/24", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.231.253.0/24", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.232.0.0/16", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.233.0.0/18", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.233.64.0/18", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.233.128.0/17", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.234.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.236.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.238.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.0/28", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.16/28", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.32/28", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.239.0.48/28", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.64/28", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.80/28", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.96/28", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.112/28", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.239.0.128/28", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.144/28", "region": "cn-north-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.160/28", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.176/28", "region": "cn-northwest-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.192/28", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "54.239.0.208/28", "region": "ap-south-1", "service": "AMAZON" }, { "ip_prefix": "54.239.0.224/28", "region": "us-east-2", "service": "AMAZON" }, { "ip_prefix": "54.239.0.240/28", "region": "eu-west-2", "service": "AMAZON" }, { "ip_prefix": "54.239.1.0/28", "region": "ca-central-1", "service": "AMAZON" }, { "ip_prefix": "54.239.1.16/28", "region": "eu-west-3", "service": "AMAZON" }, { "ip_prefix": "54.239.2.0/23", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.239.4.0/22", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "54.239.8.0/21", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.16.0/20", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.32.0/21", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.239.48.0/22", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.239.52.0/23", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.239.54.0/23", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "54.239.56.0/21", "region": "eu-central-1", "service": "AMAZON" }, { "ip_prefix": "54.239.96.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.239.98.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.99.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.239.100.0/23", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.239.104.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.108.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.239.116.0/22", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "54.239.120.0/21", "region": "ap-northeast-2", "service": "AMAZON" }, { "ip_prefix": "54.239.128.0/18", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.239.192.0/19", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.240.128.0/18", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "54.240.192.0/22", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.240.196.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.197.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.240.198.0/24", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.240.199.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.240.200.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.240.202.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.203.0/24", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.240.204.0/22", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.240.208.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.212.0/22", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.240.216.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.220.0/22", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.240.225.0/24", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.240.226.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.240.227.0/24", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.240.228.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.230.0/23", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.240.232.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.244.0/22", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "54.240.248.0/21", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.241.0.0/16", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "54.242.0.0/15", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.244.0.0/16", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.245.0.0/16", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "54.246.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.247.0.0/16", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "54.248.0.0/15", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.250.0.0/16", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "54.251.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.252.0.0/16", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.253.0.0/16", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "54.254.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "54.255.0.0/16", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "67.202.0.0/18", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "72.21.192.0/19", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "72.44.32.0/19", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "75.101.128.0/17", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "79.125.0.0/17", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "87.238.80.0/21", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "96.127.0.0/17", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "103.4.8.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "103.4.12.0/22", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "103.8.172.0/22", "region": "ap-southeast-2", "service": "AMAZON" }, { "ip_prefix": "103.246.148.0/23", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "103.246.150.0/23", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "107.20.0.0/14", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "122.248.192.0/18", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "172.96.97.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "172.96.98.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "174.129.0.0/16", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "175.41.128.0/18", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "175.41.192.0/18", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "176.32.64.0/19", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "176.32.96.0/21", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "176.32.104.0/21", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "176.32.112.0/21", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "176.32.120.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "176.32.125.0/25", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "176.34.0.0/19", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "176.34.32.0/19", "region": "ap-northeast-1", "service": "AMAZON" }, { "ip_prefix": "176.34.64.0/18", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "176.34.128.0/17", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "177.71.128.0/17", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "177.72.240.0/21", "region": "sa-east-1", "service": "AMAZON" }, { "ip_prefix": "178.236.0.0/20", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "184.72.0.0/18", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "184.72.64.0/18", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "184.72.128.0/17", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "184.73.0.0/16", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "184.169.128.0/17", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "185.48.120.0/22", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "185.143.16.0/24", "region": "eu-west-1", "service": "AMAZON" }, { "ip_prefix": "203.83.220.0/22", "region": "ap-southeast-1", "service": "AMAZON" }, { "ip_prefix": "204.236.128.0/18", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "204.236.192.0/18", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "204.246.160.0/22", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "204.246.164.0/22", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "204.246.168.0/22", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "204.246.174.0/23", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "204.246.176.0/20", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "205.251.192.0/19", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "205.251.224.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "205.251.228.0/22", "region": "us-west-1", "service": "AMAZON" }, { "ip_prefix": "205.251.232.0/22", "region": "us-west-2", "service": "AMAZON" }, { "ip_prefix": "205.251.236.0/22", "region": "us-gov-west-1", "service": "AMAZON" }, { "ip_prefix": "205.251.240.0/22", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "205.251.244.0/23", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "205.251.247.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "205.251.248.0/24", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "205.251.249.0/24", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "205.251.250.0/23", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "205.251.252.0/23", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "205.251.254.0/24", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "207.171.160.0/20", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "207.171.176.0/20", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "216.137.32.0/19", "region": "GLOBAL", "service": "AMAZON" }, { "ip_prefix": "216.182.224.0/20", "region": "us-east-1", "service": "AMAZON" }, { "ip_prefix": "54.183.255.128/26", "region": "us-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.228.16.0/26", "region": "eu-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.232.40.64/26", "region": "sa-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.241.32.64/26", "region": "us-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.243.31.192/26", "region": "us-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.244.52.192/26", "region": "us-west-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.245.168.0/26", "region": "us-west-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.248.220.0/26", "region": "ap-northeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.250.253.192/26", "region": "ap-northeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.251.31.128/26", "region": "ap-southeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.252.79.128/26", "region": "ap-southeast-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.252.254.192/26", "region": "ap-southeast-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "54.255.254.192/26", "region": "ap-southeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "107.23.255.0/26", "region": "us-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "176.34.159.192/26", "region": "eu-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "177.71.207.128/26", "region": "sa-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ip_prefix": "52.82.188.0/22", "region": "cn-northwest-1", "service": "S3" }, { "ip_prefix": "52.92.0.0/20", "region": "ap-northeast-2", "service": "S3" }, { "ip_prefix": "52.92.16.0/20", "region": "us-east-1", "service": "S3" }, { "ip_prefix": "52.92.32.0/22", "region": "us-west-2", "service": "S3" }, { "ip_prefix": "52.92.39.0/24", "region": "sa-east-1", "service": "S3" }, { "ip_prefix": "52.92.40.0/21", "region": "eu-west-1", "service": "S3" }, { "ip_prefix": "52.92.48.0/22", "region": "us-west-1", "service": "S3" }, { "ip_prefix": "52.92.52.0/22", "region": "ap-southeast-2", "service": "S3" }, { "ip_prefix": "52.92.56.0/22", "region": "ap-southeast-1", "service": "S3" }, { "ip_prefix": "52.92.60.0/22", "region": "ap-northeast-1", "service": "S3" }, { "ip_prefix": "52.92.64.0/22", "region": "sa-east-1", "service": "S3" }, { "ip_prefix": "52.92.68.0/22", "region": "eu-central-1", "service": "S3" }, { "ip_prefix": "52.92.72.0/22", "region": "sa-east-1", "service": "S3" }, { "ip_prefix": "52.92.76.0/22", "region": "us-east-2", "service": "S3" }, { "ip_prefix": "52.92.80.0/22", "region": "ap-northeast-1", "service": "S3" }, { "ip_prefix": "52.92.84.0/22", "region": "ca-central-1", "service": "S3" }, { "ip_prefix": "52.92.88.0/22", "region": "eu-west-2", "service": "S3" }, { "ip_prefix": "52.92.248.0/22", "region": "ap-south-1", "service": "S3" }, { "ip_prefix": "52.92.252.0/22", "region": "us-gov-west-1", "service": "S3" }, { "ip_prefix": "52.95.128.0/21", "region": "ap-southeast-2", "service": "S3" }, { "ip_prefix": "52.95.136.0/23", "region": "sa-east-1", "service": "S3" }, { "ip_prefix": "52.95.138.0/24", "region": "sa-east-1", "service": "S3" }, { "ip_prefix": "52.95.142.0/23", "region": "us-gov-west-1", "service": "S3" }, { "ip_prefix": "52.95.144.0/24", "region": "us-gov-west-1", "service": "S3" }, { "ip_prefix": "52.95.145.0/24", "region": "ca-central-1", "service": "S3" }, { "ip_prefix": "52.95.146.0/23", "region": "ca-central-1", "service": "S3" }, { "ip_prefix": "52.95.148.0/23", "region": "eu-west-2", "service": "S3" }, { "ip_prefix": "52.95.150.0/24", "region": "eu-west-2", "service": "S3" }, { "ip_prefix": "52.95.154.0/23", "region": "eu-west-3", "service": "S3" }, { "ip_prefix": "52.95.156.0/24", "region": "eu-west-3", "service": "S3" }, { "ip_prefix": "52.216.0.0/15", "region": "us-east-1", "service": "S3" }, { "ip_prefix": "52.218.0.0/17", "region": "eu-west-1", "service": "S3" }, { "ip_prefix": "52.218.128.0/17", "region": "us-west-2", "service": "S3" }, { "ip_prefix": "52.219.0.0/20", "region": "ap-northeast-1", "service": "S3" }, { "ip_prefix": "52.219.16.0/22", "region": "ap-northeast-1", "service": "S3" }, { "ip_prefix": "52.219.20.0/22", "region": "us-west-1", "service": "S3" }, { "ip_prefix": "52.219.24.0/21", "region": "us-west-1", "service": "S3" }, { "ip_prefix": "52.219.32.0/21", "region": "ap-southeast-1", "service": "S3" }, { "ip_prefix": "52.219.40.0/22", "region": "ap-southeast-1", "service": "S3" }, { "ip_prefix": "52.219.44.0/22", "region": "eu-central-1", "service": "S3" }, { "ip_prefix": "52.219.56.0/22", "region": "ap-northeast-2", "service": "S3" }, { "ip_prefix": "52.219.60.0/23", "region": "ap-northeast-2", "service": "S3" }, { "ip_prefix": "52.219.62.0/23", "region": "ap-south-1", "service": "S3" }, { "ip_prefix": "52.219.64.0/22", "region": "ap-south-1", "service": "S3" }, { "ip_prefix": "52.219.68.0/22", "region": "ap-northeast-1", "service": "S3" }, { "ip_prefix": "52.219.72.0/22", "region": "eu-central-1", "service": "S3" }, { "ip_prefix": "52.219.76.0/22", "region": "ap-southeast-1", "service": "S3" }, { "ip_prefix": "52.219.80.0/20", "region": "us-east-2", "service": "S3" }, { "ip_prefix": "54.222.20.0/22", "region": "cn-north-1", "service": "S3" }, { "ip_prefix": "54.222.48.0/22", "region": "cn-north-1", "service": "S3" }, { "ip_prefix": "54.231.0.0/17", "region": "us-east-1", "service": "S3" }, { "ip_prefix": "54.231.128.0/19", "region": "eu-west-1", "service": "S3" }, { "ip_prefix": "54.231.160.0/19", "region": "us-west-2", "service": "S3" }, { "ip_prefix": "54.231.192.0/20", "region": "eu-central-1", "service": "S3" }, { "ip_prefix": "54.231.224.0/21", "region": "ap-northeast-1", "service": "S3" }, { "ip_prefix": "54.231.232.0/21", "region": "us-west-1", "service": "S3" }, { "ip_prefix": "54.231.240.0/22", "region": "ap-southeast-1", "service": "S3" }, { "ip_prefix": "54.231.248.0/22", "region": "ap-southeast-2", "service": "S3" }, { "ip_prefix": "54.231.252.0/24", "region": "ap-southeast-2", "service": "S3" }, { "ip_prefix": "54.231.253.0/24", "region": "sa-east-1", "service": "S3" }, { "ip_prefix": "13.54.0.0/15", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "13.56.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "13.57.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "13.58.0.0/15", "region": "us-east-2", "service": "EC2" }, { "ip_prefix": "13.112.0.0/14", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "13.124.0.0/16", "region": "ap-northeast-2", "service": "EC2" }, { "ip_prefix": "13.125.0.0/16", "region": "ap-northeast-2", "service": "EC2" }, { "ip_prefix": "13.126.0.0/15", "region": "ap-south-1", "service": "EC2" }, { "ip_prefix": "13.209.0.0/16", "region": "ap-northeast-2", "service": "EC2" }, { "ip_prefix": "13.210.0.0/15", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "13.228.0.0/15", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "13.230.0.0/15", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "13.232.0.0/14", "region": "ap-south-1", "service": "EC2" }, { "ip_prefix": "13.236.0.0/14", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "13.250.0.0/15", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "18.194.0.0/15", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "18.196.0.0/15", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "18.216.0.0/14", "region": "us-east-2", "service": "EC2" }, { "ip_prefix": "18.220.0.0/14", "region": "us-east-2", "service": "EC2" }, { "ip_prefix": "18.231.0.0/16", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "23.20.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "34.192.0.0/12", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "34.208.0.0/12", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "34.224.0.0/12", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "34.240.0.0/13", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "34.248.0.0/13", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "35.154.0.0/16", "region": "ap-south-1", "service": "EC2" }, { "ip_prefix": "35.155.0.0/16", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "35.156.0.0/14", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "35.160.0.0/13", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "35.168.0.0/13", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "35.176.0.0/15", "region": "eu-west-2", "service": "EC2" }, { "ip_prefix": "35.178.0.0/15", "region": "eu-west-2", "service": "EC2" }, { "ip_prefix": "35.180.0.0/15", "region": "ca-central-1", "service": "EC2" }, { "ip_prefix": "35.182.0.0/15", "region": "ca-central-1", "service": "EC2" }, { "ip_prefix": "46.51.128.0/18", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "46.51.192.0/20", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "46.51.216.0/21", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "46.51.224.0/19", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "46.137.0.0/17", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "46.137.128.0/18", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "46.137.192.0/19", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "46.137.224.0/19", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "50.16.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "50.18.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "50.19.0.0/16", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "50.112.0.0/16", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.0.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.2.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.4.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.8.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "52.9.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "52.10.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.12.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.14.0.0/16", "region": "us-east-2", "service": "EC2" }, { "ip_prefix": "52.15.0.0/16", "region": "us-east-2", "service": "EC2" }, { "ip_prefix": "52.16.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.18.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.20.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.24.0.0/14", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.28.0.0/16", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "52.29.0.0/16", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "52.30.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.32.0.0/14", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.36.0.0/14", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.40.0.0/14", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.44.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.47.0.0/16", "region": "eu-west-3", "service": "EC2" }, { "ip_prefix": "52.48.0.0/14", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.52.0.0/15", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "52.54.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.56.0.0/16", "region": "eu-west-2", "service": "EC2" }, { "ip_prefix": "52.57.0.0/16", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "52.58.0.0/15", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "52.60.0.0/16", "region": "ca-central-1", "service": "EC2" }, { "ip_prefix": "52.61.0.0/16", "region": "us-gov-west-1", "service": "EC2" }, { "ip_prefix": "52.62.0.0/15", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "52.64.0.0/17", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "52.64.128.0/17", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "52.65.0.0/16", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "52.66.0.0/16", "region": "ap-south-1", "service": "EC2" }, { "ip_prefix": "52.67.0.0/16", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "52.68.0.0/15", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "52.70.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.72.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.74.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.76.0.0/17", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.76.128.0/17", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.77.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.78.0.0/16", "region": "ap-northeast-2", "service": "EC2" }, { "ip_prefix": "52.79.0.0/16", "region": "ap-northeast-2", "service": "EC2" }, { "ip_prefix": "52.80.0.0/16", "region": "cn-north-1", "service": "EC2" }, { "ip_prefix": "52.83.0.0/16", "region": "cn-northwest-1", "service": "EC2" }, { "ip_prefix": "52.86.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.88.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.90.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.95.240.0/24", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "52.95.241.0/24", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "52.95.242.0/24", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.95.243.0/24", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "52.95.244.0/24", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.95.245.0/24", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.95.246.0/24", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "52.95.247.0/24", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.95.248.0/24", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "52.95.249.0/24", "region": "ap-south-1", "service": "EC2" }, { "ip_prefix": "52.95.250.0/24", "region": "ca-central-1", "service": "EC2" }, { "ip_prefix": "52.95.251.0/24", "region": "us-east-2", "service": "EC2" }, { "ip_prefix": "52.95.252.0/24", "region": "ap-northeast-2", "service": "EC2" }, { "ip_prefix": "52.95.253.0/24", "region": "eu-west-2", "service": "EC2" }, { "ip_prefix": "52.95.254.0/24", "region": "eu-west-3", "service": "EC2" }, { "ip_prefix": "52.95.255.0/28", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "52.95.255.16/28", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "52.95.255.32/28", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.95.255.48/28", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "52.95.255.64/28", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.95.255.80/28", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.95.255.96/28", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "52.95.255.112/28", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "52.95.255.128/28", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "52.95.255.144/28", "region": "cn-north-1", "service": "EC2" }, { "ip_prefix": "52.192.0.0/15", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "52.196.0.0/14", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "52.200.0.0/13", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.208.0.0/13", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "52.220.0.0/15", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "52.222.0.0/17", "region": "us-gov-west-1", "service": "EC2" }, { "ip_prefix": "54.64.0.0/15", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.66.0.0/16", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "54.67.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.68.0.0/14", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.72.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.74.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.76.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.78.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.79.0.0/16", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "54.80.0.0/13", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.88.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.92.0.0/17", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.92.128.0/17", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.93.0.0/16", "region": "eu-central-1", "service": "EC2" }, { "ip_prefix": "54.94.0.0/16", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "54.95.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.144.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.148.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.150.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.151.0.0/17", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.151.128.0/17", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "54.152.0.0/16", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.153.0.0/17", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.153.128.0/17", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "54.154.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.155.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.156.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.160.0.0/13", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.168.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.169.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "54.170.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.172.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.174.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.176.0.0/15", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.178.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.179.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "54.183.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.184.0.0/13", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.193.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.194.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.196.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.198.0.0/16", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.199.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.200.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.202.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.204.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.206.0.0/16", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "54.207.0.0/16", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "54.208.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.210.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.212.0.0/15", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.214.0.0/16", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.215.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.216.0.0/15", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.218.0.0/16", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.219.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.220.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.221.0.0/16", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.222.128.0/17", "region": "cn-north-1", "service": "EC2" }, { "ip_prefix": "54.223.0.0/16", "region": "cn-north-1", "service": "EC2" }, { "ip_prefix": "54.224.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.226.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.228.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.229.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.232.0.0/16", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "54.233.0.0/18", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "54.233.64.0/18", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "54.233.128.0/17", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "54.234.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.236.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.238.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.241.0.0/16", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "54.242.0.0/15", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "54.244.0.0/16", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.245.0.0/16", "region": "us-west-2", "service": "EC2" }, { "ip_prefix": "54.246.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.247.0.0/16", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "54.248.0.0/15", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.250.0.0/16", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "54.251.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "54.252.0.0/16", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "54.253.0.0/16", "region": "ap-southeast-2", "service": "EC2" }, { "ip_prefix": "54.254.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "54.255.0.0/16", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "67.202.0.0/18", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "72.44.32.0/19", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "75.101.128.0/17", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "79.125.0.0/17", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "96.127.0.0/17", "region": "us-gov-west-1", "service": "EC2" }, { "ip_prefix": "103.4.8.0/22", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "103.4.12.0/22", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "107.20.0.0/14", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "122.248.192.0/18", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "174.129.0.0/16", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "175.41.128.0/18", "region": "ap-southeast-1", "service": "EC2" }, { "ip_prefix": "175.41.192.0/18", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "176.32.64.0/19", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "176.34.0.0/19", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "176.34.32.0/19", "region": "ap-northeast-1", "service": "EC2" }, { "ip_prefix": "176.34.64.0/18", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "176.34.128.0/17", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "177.71.128.0/17", "region": "sa-east-1", "service": "EC2" }, { "ip_prefix": "184.72.0.0/18", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "184.72.64.0/18", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "184.72.128.0/17", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "184.73.0.0/16", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "184.169.128.0/17", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "185.48.120.0/22", "region": "eu-west-1", "service": "EC2" }, { "ip_prefix": "204.236.128.0/18", "region": "us-west-1", "service": "EC2" }, { "ip_prefix": "204.236.192.0/18", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "216.182.224.0/20", "region": "us-east-1", "service": "EC2" }, { "ip_prefix": "52.95.110.0/24", "region": "GLOBAL", "service": "ROUTE53" }, { "ip_prefix": "205.251.192.0/21", "region": "GLOBAL", "service": "ROUTE53" }, { "ip_prefix": "13.32.0.0/15", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "13.54.63.128/26", "region": "ap-southeast-2", "service": "CLOUDFRONT" }, { "ip_prefix": "13.59.250.0/26", "region": "us-east-2", "service": "CLOUDFRONT" }, { "ip_prefix": "13.113.203.0/24", "region": "ap-northeast-1", "service": "CLOUDFRONT" }, { "ip_prefix": "13.228.69.0/24", "region": "ap-southeast-1", "service": "CLOUDFRONT" }, { "ip_prefix": "34.195.252.0/24", "region": "us-east-1", "service": "CLOUDFRONT" }, { "ip_prefix": "34.226.14.0/24", "region": "us-east-1", "service": "CLOUDFRONT" }, { "ip_prefix": "35.158.136.0/24", "region": "eu-central-1", "service": "CLOUDFRONT" }, { "ip_prefix": "35.162.63.192/26", "region": "us-west-2", "service": "CLOUDFRONT" }, { "ip_prefix": "35.167.191.128/26", "region": "us-west-2", "service": "CLOUDFRONT" }, { "ip_prefix": "52.15.127.128/26", "region": "us-east-2", "service": "CLOUDFRONT" }, { "ip_prefix": "52.46.0.0/18", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "52.52.191.128/26", "region": "us-west-1", "service": "CLOUDFRONT" }, { "ip_prefix": "52.56.127.0/25", "region": "eu-west-2", "service": "CLOUDFRONT" }, { "ip_prefix": "52.57.254.0/24", "region": "eu-central-1", "service": "CLOUDFRONT" }, { "ip_prefix": "52.66.194.128/26", "region": "ap-south-1", "service": "CLOUDFRONT" }, { "ip_prefix": "52.78.247.128/26", "region": "ap-northeast-2", "service": "CLOUDFRONT" }, { "ip_prefix": "52.84.0.0/15", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "52.199.127.192/26", "region": "ap-northeast-1", "service": "CLOUDFRONT" }, { "ip_prefix": "52.212.248.0/26", "region": "eu-west-1", "service": "CLOUDFRONT" }, { "ip_prefix": "52.220.191.0/26", "region": "ap-southeast-1", "service": "CLOUDFRONT" }, { "ip_prefix": "52.222.128.0/17", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "54.182.0.0/16", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "54.192.0.0/16", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "54.230.0.0/16", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "54.233.255.128/26", "region": "sa-east-1", "service": "CLOUDFRONT" }, { "ip_prefix": "54.239.128.0/18", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "54.239.192.0/19", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "54.240.128.0/18", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "204.246.164.0/22", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "204.246.168.0/22", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "204.246.174.0/23", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "204.246.176.0/20", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "205.251.192.0/19", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "205.251.249.0/24", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "205.251.250.0/23", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "205.251.252.0/23", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "205.251.254.0/24", "region": "GLOBAL", "service": "CLOUDFRONT" }, { "ip_prefix": "216.137.32.0/19", "region": "GLOBAL", "service": "CLOUDFRONT" } ], "ipv6_prefixes": [ { "ipv6_prefix": "2400:6500:0:7000::/56", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:0:7100::/56", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:0:7200::/56", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:0:7400::/56", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:0:7500::/56", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:100:7100::/56", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:100:7200::/56", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:ff00::/64", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2400:6700:ff00::/64", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2403:b300:ff00::/64", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:da00:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:da00:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da00:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da00:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da00:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:da00:ff00::/64", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da12::/36", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:da14::/36", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da18::/36", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da1a::/36", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:da1c::/36", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daa0:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daa0:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daa0:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daa0:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daa0:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf8:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf8:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf8:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf8:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf8:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf9:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf9:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf9:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf9:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daf9:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafa:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafa:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafa:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafa:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafa:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafc:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafc:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafc:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafc:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafc:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafe:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafe:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafe:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafe:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:dafe:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daff:2000::/40", "region": "ap-northeast-2", "service": "AMAZON" }, { "ipv6_prefix": "2406:daff:4000::/40", "region": "ap-northeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daff:8000::/40", "region": "ap-southeast-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daff:a000::/40", "region": "ap-south-1", "service": "AMAZON" }, { "ipv6_prefix": "2406:daff:c000::/40", "region": "ap-southeast-2", "service": "AMAZON" }, { "ipv6_prefix": "240f:8000:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:8000:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:8014::/36", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:8018::/36", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80a0:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80a0:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80f8:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80f8:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80f9:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80f9:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80fa:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80fa:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80fc:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80fc:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80fe:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80fe:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80ff:4000::/40", "region": "cn-northwest-1", "service": "AMAZON" }, { "ipv6_prefix": "240f:80ff:8000::/40", "region": "cn-north-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f00:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f11::/36", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f12::/36", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f14::/35", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f16::/36", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f18::/33", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f1c::/36", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1f1e::/36", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fa0:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff8:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ff9:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffa:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffc:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1ffe:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:1000::/40", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:2000::/40", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:4000::/40", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:6000::/40", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:8000::/40", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:c000::/40", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:1fff:e000::/40", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2600:9000::/28", "region": "GLOBAL", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:300f::/64", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:5::/64", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:7000::/56", "region": "us-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:7100::/56", "region": "us-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:7200::/56", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:7400::/56", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:7700::/56", "region": "us-east-2", "service": "AMAZON" }, { "ipv6_prefix": "2620:107:4000:7800::/56", "region": "ca-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2620:108:7000::/44", "region": "us-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2620:108:d000::/44", "region": "us-gov-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2804:800:0:7000::/56", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2804:800:ff00::/64", "region": "sa-east-1", "service": "AMAZON" }, { "ipv6_prefix": "2a01:578:0:7000::/56", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a01:578:0:7100::/56", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a01:578:0:7200::/56", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a01:578:3::/64", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a01:578:13::/64", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d000:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d000:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d000:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d000:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d012::/36", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d014::/36", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d018::/36", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d01c::/36", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d050:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d050:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d050:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d050:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d078:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d078:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d078:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d078:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d079:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d079:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d079:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d079:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07a:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07a:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07a:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07a:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07c:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07c:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07c:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07c:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07e:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07e:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07e:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07e:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07f:2000::/40", "region": "eu-west-3", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07f:4000::/40", "region": "eu-central-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07f:8000::/40", "region": "eu-west-1", "service": "AMAZON" }, { "ipv6_prefix": "2a05:d07f:c000::/40", "region": "eu-west-2", "service": "AMAZON" }, { "ipv6_prefix": "2400:6500:ff00::36fb:1f80/122", "region": "ap-southeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2400:6500:ff00::36ff:fec0/122", "region": "ap-southeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2400:6700:ff00::36f8:dc00/122", "region": "ap-northeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2400:6700:ff00::36fa:fdc0/122", "region": "ap-northeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2403:b300:ff00::36fc:4f80/122", "region": "ap-southeast-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2403:b300:ff00::36fc:fec0/122", "region": "ap-southeast-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da00:ff00::36f3:1fc0/122", "region": "us-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da00:ff00::6b17:ff00/122", "region": "us-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da14:7ff:f800::/53", "region": "ap-northeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da14:fff:f800::/53", "region": "ap-northeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da18:7ff:f800::/53", "region": "ap-southeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da18:fff:f800::/53", "region": "ap-southeast-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da1c:7ff:f800::/53", "region": "ap-southeast-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:da1c:fff:f800::/53", "region": "ap-southeast-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f14:7ff:f800::/53", "region": "us-west-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f14:fff:f800::/53", "region": "us-west-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f18:3fff:f800::/53", "region": "us-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f18:7fff:f800::/53", "region": "us-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f1c:7ff:f800::/53", "region": "us-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f1c:fff:f800::/53", "region": "us-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f1e:7ff:f800::/53", "region": "sa-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2600:1f1e:fff:f800::/53", "region": "sa-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2620:107:300f::36b7:ff80/122", "region": "us-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2620:107:300f::36f1:2040/122", "region": "us-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2620:108:700f::36f4:34c0/122", "region": "us-west-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2620:108:700f::36f5:a800/122", "region": "us-west-2", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2804:800:ff00::36e8:2840/122", "region": "sa-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2804:800:ff00::b147:cf80/122", "region": "sa-east-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2a01:578:3::36e4:1000/122", "region": "eu-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2a01:578:3::b022:9fc0/122", "region": "eu-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2a05:d018:7ff:f800::/53", "region": "eu-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2a05:d018:fff:f800::/53", "region": "eu-west-1", "service": "ROUTE53_HEALTHCHECKS" }, { "ipv6_prefix": "2406:daa0:2000::/40", "region": "ap-northeast-2", "service": "S3" }, { "ipv6_prefix": "2406:daa0:4000::/40", "region": "ap-northeast-1", "service": "S3" }, { "ipv6_prefix": "2406:daa0:8000::/40", "region": "ap-southeast-1", "service": "S3" }, { "ipv6_prefix": "2406:daa0:a000::/40", "region": "ap-south-1", "service": "S3" }, { "ipv6_prefix": "2406:daa0:c000::/40", "region": "ap-southeast-2", "service": "S3" }, { "ipv6_prefix": "2406:daf8:2000::/40", "region": "ap-northeast-2", "service": "S3" }, { "ipv6_prefix": "2406:daf8:4000::/40", "region": "ap-northeast-1", "service": "S3" }, { "ipv6_prefix": "2406:daf8:8000::/40", "region": "ap-southeast-1", "service": "S3" }, { "ipv6_prefix": "2406:daf8:a000::/40", "region": "ap-south-1", "service": "S3" }, { "ipv6_prefix": "2406:daf8:c000::/40", "region": "ap-southeast-2", "service": "S3" }, { "ipv6_prefix": "2406:daf9:2000::/40", "region": "ap-northeast-2", "service": "S3" }, { "ipv6_prefix": "2406:daf9:4000::/40", "region": "ap-northeast-1", "service": "S3" }, { "ipv6_prefix": "2406:daf9:8000::/40", "region": "ap-southeast-1", "service": "S3" }, { "ipv6_prefix": "2406:daf9:a000::/40", "region": "ap-south-1", "service": "S3" }, { "ipv6_prefix": "2406:daf9:c000::/40", "region": "ap-southeast-2", "service": "S3" }, { "ipv6_prefix": "2406:dafa:2000::/40", "region": "ap-northeast-2", "service": "S3" }, { "ipv6_prefix": "2406:dafa:4000::/40", "region": "ap-northeast-1", "service": "S3" }, { "ipv6_prefix": "2406:dafa:8000::/40", "region": "ap-southeast-1", "service": "S3" }, { "ipv6_prefix": "2406:dafa:a000::/40", "region": "ap-south-1", "service": "S3" }, { "ipv6_prefix": "2406:dafa:c000::/40", "region": "ap-southeast-2", "service": "S3" }, { "ipv6_prefix": "240f:80a0:4000::/40", "region": "cn-northwest-1", "service": "S3" }, { "ipv6_prefix": "240f:80a0:8000::/40", "region": "cn-north-1", "service": "S3" }, { "ipv6_prefix": "240f:80f8:4000::/40", "region": "cn-northwest-1", "service": "S3" }, { "ipv6_prefix": "240f:80f8:8000::/40", "region": "cn-north-1", "service": "S3" }, { "ipv6_prefix": "240f:80f9:4000::/40", "region": "cn-northwest-1", "service": "S3" }, { "ipv6_prefix": "240f:80f9:8000::/40", "region": "cn-north-1", "service": "S3" }, { "ipv6_prefix": "240f:80fa:4000::/40", "region": "cn-northwest-1", "service": "S3" }, { "ipv6_prefix": "240f:80fa:8000::/40", "region": "cn-north-1", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:1000::/40", "region": "ca-central-1", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:2000::/40", "region": "us-gov-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:4000::/40", "region": "us-west-2", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:6000::/40", "region": "us-east-2", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:8000::/40", "region": "us-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:c000::/40", "region": "us-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1fa0:e000::/40", "region": "sa-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:1000::/40", "region": "ca-central-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:2000::/40", "region": "us-gov-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:4000::/40", "region": "us-west-2", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:6000::/40", "region": "us-east-2", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:8000::/40", "region": "us-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:c000::/40", "region": "us-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff8:e000::/40", "region": "sa-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:1000::/40", "region": "ca-central-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:2000::/40", "region": "us-gov-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:4000::/40", "region": "us-west-2", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:6000::/40", "region": "us-east-2", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:8000::/40", "region": "us-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:c000::/40", "region": "us-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1ff9:e000::/40", "region": "sa-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:1000::/40", "region": "ca-central-1", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:2000::/40", "region": "us-gov-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:4000::/40", "region": "us-west-2", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:6000::/40", "region": "us-east-2", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:8000::/40", "region": "us-east-1", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:c000::/40", "region": "us-west-1", "service": "S3" }, { "ipv6_prefix": "2600:1ffa:e000::/40", "region": "sa-east-1", "service": "S3" }, { "ipv6_prefix": "2a05:d050:2000::/40", "region": "eu-west-3", "service": "S3" }, { "ipv6_prefix": "2a05:d050:4000::/40", "region": "eu-central-1", "service": "S3" }, { "ipv6_prefix": "2a05:d050:8000::/40", "region": "eu-west-1", "service": "S3" }, { "ipv6_prefix": "2a05:d050:c000::/40", "region": "eu-west-2", "service": "S3" }, { "ipv6_prefix": "2a05:d078:2000::/40", "region": "eu-west-3", "service": "S3" }, { "ipv6_prefix": "2a05:d078:4000::/40", "region": "eu-central-1", "service": "S3" }, { "ipv6_prefix": "2a05:d078:8000::/40", "region": "eu-west-1", "service": "S3" }, { "ipv6_prefix": "2a05:d078:c000::/40", "region": "eu-west-2", "service": "S3" }, { "ipv6_prefix": "2a05:d079:2000::/40", "region": "eu-west-3", "service": "S3" }, { "ipv6_prefix": "2a05:d079:4000::/40", "region": "eu-central-1", "service": "S3" }, { "ipv6_prefix": "2a05:d079:8000::/40", "region": "eu-west-1", "service": "S3" }, { "ipv6_prefix": "2a05:d079:c000::/40", "region": "eu-west-2", "service": "S3" }, { "ipv6_prefix": "2a05:d07a:2000::/40", "region": "eu-west-3", "service": "S3" }, { "ipv6_prefix": "2a05:d07a:4000::/40", "region": "eu-central-1", "service": "S3" }, { "ipv6_prefix": "2a05:d07a:8000::/40", "region": "eu-west-1", "service": "S3" }, { "ipv6_prefix": "2a05:d07a:c000::/40", "region": "eu-west-2", "service": "S3" }, { "ipv6_prefix": "2400:6500:ff00::/64", "region": "ap-southeast-1", "service": "EC2" }, { "ipv6_prefix": "2400:6700:ff00::/64", "region": "ap-northeast-1", "service": "EC2" }, { "ipv6_prefix": "2403:b300:ff00::/64", "region": "ap-southeast-2", "service": "EC2" }, { "ipv6_prefix": "2406:da00:2000::/40", "region": "ap-northeast-2", "service": "EC2" }, { "ipv6_prefix": "2406:da00:4000::/40", "region": "ap-northeast-1", "service": "EC2" }, { "ipv6_prefix": "2406:da00:8000::/40", "region": "ap-southeast-1", "service": "EC2" }, { "ipv6_prefix": "2406:da00:a000::/40", "region": "ap-south-1", "service": "EC2" }, { "ipv6_prefix": "2406:da00:c000::/40", "region": "ap-southeast-2", "service": "EC2" }, { "ipv6_prefix": "2406:da00:ff00::/64", "region": "us-east-1", "service": "EC2" }, { "ipv6_prefix": "2406:da12::/36", "region": "ap-northeast-2", "service": "EC2" }, { "ipv6_prefix": "2406:da14::/36", "region": "ap-northeast-1", "service": "EC2" }, { "ipv6_prefix": "2406:da18::/36", "region": "ap-southeast-1", "service": "EC2" }, { "ipv6_prefix": "2406:da1a::/36", "region": "ap-south-1", "service": "EC2" }, { "ipv6_prefix": "2406:da1c::/36", "region": "ap-southeast-2", "service": "EC2" }, { "ipv6_prefix": "2406:daff:2000::/40", "region": "ap-northeast-2", "service": "EC2" }, { "ipv6_prefix": "2406:daff:4000::/40", "region": "ap-northeast-1", "service": "EC2" }, { "ipv6_prefix": "2406:daff:8000::/40", "region": "ap-southeast-1", "service": "EC2" }, { "ipv6_prefix": "2406:daff:a000::/40", "region": "ap-south-1", "service": "EC2" }, { "ipv6_prefix": "2406:daff:c000::/40", "region": "ap-southeast-2", "service": "EC2" }, { "ipv6_prefix": "240f:8000:4000::/40", "region": "cn-northwest-1", "service": "EC2" }, { "ipv6_prefix": "240f:8000:8000::/40", "region": "cn-north-1", "service": "EC2" }, { "ipv6_prefix": "240f:8014::/36", "region": "cn-northwest-1", "service": "EC2" }, { "ipv6_prefix": "240f:8018::/36", "region": "cn-north-1", "service": "EC2" }, { "ipv6_prefix": "240f:80ff:4000::/40", "region": "cn-northwest-1", "service": "EC2" }, { "ipv6_prefix": "240f:80ff:8000::/40", "region": "cn-north-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:1000::/40", "region": "ca-central-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:2000::/40", "region": "us-gov-west-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:4000::/40", "region": "us-west-2", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:6000::/40", "region": "us-east-2", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:8000::/40", "region": "us-east-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:c000::/40", "region": "us-west-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f00:e000::/40", "region": "sa-east-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f11::/36", "region": "ca-central-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f12::/36", "region": "us-gov-west-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f14::/35", "region": "us-west-2", "service": "EC2" }, { "ipv6_prefix": "2600:1f16::/36", "region": "us-east-2", "service": "EC2" }, { "ipv6_prefix": "2600:1f18::/33", "region": "us-east-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f1c::/36", "region": "us-west-1", "service": "EC2" }, { "ipv6_prefix": "2600:1f1e::/36", "region": "sa-east-1", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:1000::/40", "region": "ca-central-1", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:2000::/40", "region": "us-gov-west-1", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:4000::/40", "region": "us-west-2", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:6000::/40", "region": "us-east-2", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:8000::/40", "region": "us-east-1", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:c000::/40", "region": "us-west-1", "service": "EC2" }, { "ipv6_prefix": "2600:1fff:e000::/40", "region": "sa-east-1", "service": "EC2" }, { "ipv6_prefix": "2620:107:300f::/64", "region": "us-west-1", "service": "EC2" }, { "ipv6_prefix": "2620:108:700f::/64", "region": "us-west-2", "service": "EC2" }, { "ipv6_prefix": "2620:108:d00f::/64", "region": "us-gov-west-1", "service": "EC2" }, { "ipv6_prefix": "2804:800:ff00::/64", "region": "sa-east-1", "service": "EC2" }, { "ipv6_prefix": "2a01:578:3::/64", "region": "eu-west-1", "service": "EC2" }, { "ipv6_prefix": "2a01:578:13::/64", "region": "eu-central-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d000:2000::/40", "region": "eu-west-3", "service": "EC2" }, { "ipv6_prefix": "2a05:d000:4000::/40", "region": "eu-central-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d000:8000::/40", "region": "eu-west-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d000:c000::/40", "region": "eu-west-2", "service": "EC2" }, { "ipv6_prefix": "2a05:d012::/36", "region": "eu-west-3", "service": "EC2" }, { "ipv6_prefix": "2a05:d014::/36", "region": "eu-central-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d018::/36", "region": "eu-west-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d01c::/36", "region": "eu-west-2", "service": "EC2" }, { "ipv6_prefix": "2a05:d07f:2000::/40", "region": "eu-west-3", "service": "EC2" }, { "ipv6_prefix": "2a05:d07f:4000::/40", "region": "eu-central-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d07f:8000::/40", "region": "eu-west-1", "service": "EC2" }, { "ipv6_prefix": "2a05:d07f:c000::/40", "region": "eu-west-2", "service": "EC2" }, { "ipv6_prefix": "2600:9000::/28", "region": "GLOBAL", "service": "CLOUDFRONT" } ] } cidranger-1.0.2/trie.go000066400000000000000000000245511373217032300147520ustar00rootroot00000000000000package cidranger import ( "fmt" "net" "strings" rnet "github.com/yl2chen/cidranger/net" ) // prefixTrie is a path-compressed (PC) trie implementation of the // ranger interface inspired by this blog post: // https://vincent.bernat.im/en/blog/2017-ipv4-route-lookup-linux // // CIDR blocks are stored using a prefix tree structure where each node has its // parent as prefix, and the path from the root node represents current CIDR // block. // // For IPv4, the trie structure guarantees max depth of 32 as IPv4 addresses are // 32 bits long and each bit represents a prefix tree starting at that bit. This // property also guarantees constant lookup time in Big-O notation. // // Path compression compresses a string of node with only 1 child into a single // node, decrease the amount of lookups necessary during containment tests. // // Level compression dictates the amount of direct children of a node by // allowing it to handle multiple bits in the path. The heuristic (based on // children population) to decide when the compression and decompression happens // is outlined in the prior linked blog, and will be experimented with in more // depth in this project in the future. // // Note: Can not insert both IPv4 and IPv6 network addresses into the same // prefix trie, use versionedRanger wrapper instead. // // TODO: Implement level-compressed component of the LPC trie. type prefixTrie struct { parent *prefixTrie children []*prefixTrie numBitsSkipped uint numBitsHandled uint network rnet.Network entry RangerEntry size int // This is only maintained in the root trie. } // newPrefixTree creates a new prefixTrie. func newPrefixTree(version rnet.IPVersion) Ranger { _, rootNet, _ := net.ParseCIDR("0.0.0.0/0") if version == rnet.IPv6 { _, rootNet, _ = net.ParseCIDR("0::0/0") } return &prefixTrie{ children: make([]*prefixTrie, 2, 2), numBitsSkipped: 0, numBitsHandled: 1, network: rnet.NewNetwork(*rootNet), } } func newPathprefixTrie(network rnet.Network, numBitsSkipped uint) *prefixTrie { version := rnet.IPv4 if len(network.Number) == rnet.IPv6Uint32Count { version = rnet.IPv6 } path := newPrefixTree(version).(*prefixTrie) path.numBitsSkipped = numBitsSkipped path.network = network.Masked(int(numBitsSkipped)) return path } func newEntryTrie(network rnet.Network, entry RangerEntry) *prefixTrie { ones, _ := network.IPNet.Mask.Size() leaf := newPathprefixTrie(network, uint(ones)) leaf.entry = entry return leaf } // Insert inserts a RangerEntry into prefix trie. func (p *prefixTrie) Insert(entry RangerEntry) error { network := entry.Network() sizeIncreased, err := p.insert(rnet.NewNetwork(network), entry) if sizeIncreased { p.size++ } return err } // Remove removes RangerEntry identified by given network from trie. func (p *prefixTrie) Remove(network net.IPNet) (RangerEntry, error) { entry, err := p.remove(rnet.NewNetwork(network)) if entry != nil { p.size-- } return entry, err } // Contains returns boolean indicating whether given ip is contained in any // of the inserted networks. func (p *prefixTrie) Contains(ip net.IP) (bool, error) { nn := rnet.NewNetworkNumber(ip) if nn == nil { return false, ErrInvalidNetworkNumberInput } return p.contains(nn) } // ContainingNetworks returns the list of RangerEntry(s) the given ip is // contained in in ascending prefix order. func (p *prefixTrie) ContainingNetworks(ip net.IP) ([]RangerEntry, error) { nn := rnet.NewNetworkNumber(ip) if nn == nil { return nil, ErrInvalidNetworkNumberInput } return p.containingNetworks(nn) } // CoveredNetworks returns the list of RangerEntry(s) the given ipnet // covers. That is, the networks that are completely subsumed by the // specified network. func (p *prefixTrie) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) { net := rnet.NewNetwork(network) return p.coveredNetworks(net) } // Len returns number of networks in ranger. func (p *prefixTrie) Len() int { return p.size } // String returns string representation of trie, mainly for visualization and // debugging. func (p *prefixTrie) String() string { children := []string{} padding := strings.Repeat("| ", p.level()+1) for bits, child := range p.children { if child == nil { continue } childStr := fmt.Sprintf("\n%s%d--> %s", padding, bits, child.String()) children = append(children, childStr) } return fmt.Sprintf("%s (target_pos:%d:has_entry:%t)%s", p.network, p.targetBitPosition(), p.hasEntry(), strings.Join(children, "")) } func (p *prefixTrie) contains(number rnet.NetworkNumber) (bool, error) { if !p.network.Contains(number) { return false, nil } if p.hasEntry() { return true, nil } if p.targetBitPosition() < 0 { return false, nil } bit, err := p.targetBitFromIP(number) if err != nil { return false, err } child := p.children[bit] if child != nil { return child.contains(number) } return false, nil } func (p *prefixTrie) containingNetworks(number rnet.NetworkNumber) ([]RangerEntry, error) { results := []RangerEntry{} if !p.network.Contains(number) { return results, nil } if p.hasEntry() { results = []RangerEntry{p.entry} } if p.targetBitPosition() < 0 { return results, nil } bit, err := p.targetBitFromIP(number) if err != nil { return nil, err } child := p.children[bit] if child != nil { ranges, err := child.containingNetworks(number) if err != nil { return nil, err } if len(ranges) > 0 { if len(results) > 0 { results = append(results, ranges...) } else { results = ranges } } } return results, nil } func (p *prefixTrie) coveredNetworks(network rnet.Network) ([]RangerEntry, error) { var results []RangerEntry if network.Covers(p.network) { for entry := range p.walkDepth() { results = append(results, entry) } } else if p.targetBitPosition() >= 0 { bit, err := p.targetBitFromIP(network.Number) if err != nil { return results, err } child := p.children[bit] if child != nil { return child.coveredNetworks(network) } } return results, nil } func (p *prefixTrie) insert(network rnet.Network, entry RangerEntry) (bool, error) { if p.network.Equal(network) { sizeIncreased := p.entry == nil p.entry = entry return sizeIncreased, nil } bit, err := p.targetBitFromIP(network.Number) if err != nil { return false, err } existingChild := p.children[bit] // No existing child, insert new leaf trie. if existingChild == nil { p.appendTrie(bit, newEntryTrie(network, entry)) return true, nil } // Check whether it is necessary to insert additional path prefix between current trie and existing child, // in the case that inserted network diverges on its path to existing child. lcb, err := network.LeastCommonBitPosition(existingChild.network) divergingBitPos := int(lcb) - 1 if divergingBitPos > existingChild.targetBitPosition() { pathPrefix := newPathprefixTrie(network, p.totalNumberOfBits()-lcb) err := p.insertPrefix(bit, pathPrefix, existingChild) if err != nil { return false, err } // Update new child existingChild = pathPrefix } return existingChild.insert(network, entry) } func (p *prefixTrie) appendTrie(bit uint32, prefix *prefixTrie) { p.children[bit] = prefix prefix.parent = p } func (p *prefixTrie) insertPrefix(bit uint32, pathPrefix, child *prefixTrie) error { // Set parent/child relationship between current trie and inserted pathPrefix p.children[bit] = pathPrefix pathPrefix.parent = p // Set parent/child relationship between inserted pathPrefix and original child pathPrefixBit, err := pathPrefix.targetBitFromIP(child.network.Number) if err != nil { return err } pathPrefix.children[pathPrefixBit] = child child.parent = pathPrefix return nil } func (p *prefixTrie) remove(network rnet.Network) (RangerEntry, error) { if p.hasEntry() && p.network.Equal(network) { entry := p.entry p.entry = nil err := p.compressPathIfPossible() if err != nil { return nil, err } return entry, nil } if p.targetBitPosition() < 0 { return nil, nil } bit, err := p.targetBitFromIP(network.Number) if err != nil { return nil, err } child := p.children[bit] if child != nil { return child.remove(network) } return nil, nil } func (p *prefixTrie) qualifiesForPathCompression() bool { // Current prefix trie can be path compressed if it meets all following. // 1. records no CIDR entry // 2. has single or no child // 3. is not root trie return !p.hasEntry() && p.childrenCount() <= 1 && p.parent != nil } func (p *prefixTrie) compressPathIfPossible() error { if !p.qualifiesForPathCompression() { // Does not qualify to be compressed return nil } // Find lone child. var loneChild *prefixTrie for _, child := range p.children { if child != nil { loneChild = child break } } // Find root of currnt single child lineage. parent := p.parent for ; parent.qualifiesForPathCompression(); parent = parent.parent { } parentBit, err := parent.targetBitFromIP(p.network.Number) if err != nil { return err } parent.children[parentBit] = loneChild // Attempts to furthur apply path compression at current lineage parent, in case current lineage // compressed into parent. return parent.compressPathIfPossible() } func (p *prefixTrie) childrenCount() int { count := 0 for _, child := range p.children { if child != nil { count++ } } return count } func (p *prefixTrie) totalNumberOfBits() uint { return rnet.BitsPerUint32 * uint(len(p.network.Number)) } func (p *prefixTrie) targetBitPosition() int { return int(p.totalNumberOfBits()-p.numBitsSkipped) - 1 } func (p *prefixTrie) targetBitFromIP(n rnet.NetworkNumber) (uint32, error) { // This is a safe uint boxing of int since we should never attempt to get // target bit at a negative position. return n.Bit(uint(p.targetBitPosition())) } func (p *prefixTrie) hasEntry() bool { return p.entry != nil } func (p *prefixTrie) level() int { if p.parent == nil { return 0 } return p.parent.level() + 1 } // walkDepth walks the trie in depth order, for unit testing. func (p *prefixTrie) walkDepth() <-chan RangerEntry { entries := make(chan RangerEntry) go func() { if p.hasEntry() { entries <- p.entry } childEntriesList := []<-chan RangerEntry{} for _, trie := range p.children { if trie == nil { continue } childEntriesList = append(childEntriesList, trie.walkDepth()) } for _, childEntries := range childEntriesList { for entry := range childEntries { entries <- entry } } close(entries) }() return entries } cidranger-1.0.2/trie_test.go000066400000000000000000000354721373217032300160150ustar00rootroot00000000000000package cidranger import ( "encoding/binary" "math/rand" "net" "runtime" "testing" "time" "github.com/stretchr/testify/assert" rnet "github.com/yl2chen/cidranger/net" ) func getAllByVersion(version rnet.IPVersion) *net.IPNet { if version == rnet.IPv6 { return AllIPv6 } return AllIPv4 } func TestPrefixTrieInsert(t *testing.T) { cases := []struct { version rnet.IPVersion inserts []string expectedNetworksInDepthOrder []string name string }{ {rnet.IPv4, []string{"192.168.0.1/24"}, []string{"192.168.0.1/24"}, "basic insert"}, { rnet.IPv4, []string{"1.2.3.4/32", "1.2.3.5/32"}, []string{"1.2.3.4/32", "1.2.3.5/32"}, "single ip IPv4 network insert", }, { rnet.IPv6, []string{"0::1/128", "0::2/128"}, []string{"0::1/128", "0::2/128"}, "single ip IPv6 network insert", }, { rnet.IPv4, []string{"192.168.0.1/16", "192.168.0.1/24"}, []string{"192.168.0.1/16", "192.168.0.1/24"}, "in order insert", }, { rnet.IPv4, []string{"192.168.0.1/32", "192.168.0.1/32"}, []string{"192.168.0.1/32"}, "duplicate network insert", }, { rnet.IPv4, []string{"192.168.0.1/24", "192.168.0.1/16"}, []string{"192.168.0.1/16", "192.168.0.1/24"}, "reverse insert", }, { rnet.IPv4, []string{"192.168.0.1/24", "192.168.1.1/24"}, []string{"192.168.0.1/24", "192.168.1.1/24"}, "branch insert", }, { rnet.IPv4, []string{"192.168.0.1/24", "192.168.1.1/24", "192.168.1.1/30"}, []string{"192.168.0.1/24", "192.168.1.1/24", "192.168.1.1/30"}, "branch inserts", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { trie := newPrefixTree(tc.version).(*prefixTrie) for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := trie.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } assert.Equal(t, len(tc.expectedNetworksInDepthOrder), trie.Len(), "trie size should match") allNetworks, err := trie.CoveredNetworks(*getAllByVersion(tc.version)) assert.Nil(t, err) assert.Equal(t, len(allNetworks), trie.Len(), "trie size should match") walk := trie.walkDepth() for _, network := range tc.expectedNetworksInDepthOrder { _, ipnet, _ := net.ParseCIDR(network) expected := NewBasicRangerEntry(*ipnet) actual := <-walk assert.Equal(t, expected, actual) } // Ensure no unexpected elements in trie. for network := range walk { assert.Nil(t, network) } }) } } func TestPrefixTrieString(t *testing.T) { inserts := []string{"192.168.0.1/24", "192.168.1.1/24", "192.168.1.1/30"} trie := newPrefixTree(rnet.IPv4).(*prefixTrie) for _, insert := range inserts { _, network, _ := net.ParseCIDR(insert) trie.Insert(NewBasicRangerEntry(*network)) } expected := `0.0.0.0/0 (target_pos:31:has_entry:false) | 1--> 192.168.0.0/23 (target_pos:8:has_entry:false) | | 0--> 192.168.0.0/24 (target_pos:7:has_entry:true) | | 1--> 192.168.1.0/24 (target_pos:7:has_entry:true) | | | 0--> 192.168.1.0/30 (target_pos:1:has_entry:true)` assert.Equal(t, expected, trie.String()) } func TestPrefixTrieRemove(t *testing.T) { cases := []struct { version rnet.IPVersion inserts []string removes []string expectedRemoves []string expectedNetworksInDepthOrder []string expectedTrieString string name string }{ { rnet.IPv4, []string{"192.168.0.1/24"}, []string{"192.168.0.1/24"}, []string{"192.168.0.1/24"}, []string{}, "0.0.0.0/0 (target_pos:31:has_entry:false)", "basic remove", }, { rnet.IPv4, []string{"192.168.0.1/32"}, []string{"192.168.0.1/24"}, []string{""}, []string{"192.168.0.1/32"}, `0.0.0.0/0 (target_pos:31:has_entry:false) | 1--> 192.168.0.1/32 (target_pos:-1:has_entry:true)`, "remove from ranger that contains a single ip block", }, { rnet.IPv4, []string{"1.2.3.4/32", "1.2.3.5/32"}, []string{"1.2.3.5/32"}, []string{"1.2.3.5/32"}, []string{"1.2.3.4/32"}, `0.0.0.0/0 (target_pos:31:has_entry:false) | 0--> 1.2.3.4/32 (target_pos:-1:has_entry:true)`, "single ip IPv4 network remove", }, { rnet.IPv4, []string{"0::1/128", "0::2/128"}, []string{"0::2/128"}, []string{"0::2/128"}, []string{"0::1/128"}, `0.0.0.0/0 (target_pos:31:has_entry:false) | 0--> ::1/128 (target_pos:-1:has_entry:true)`, "single ip IPv6 network remove", }, { rnet.IPv4, []string{"192.168.0.1/24", "192.168.0.1/25", "192.168.0.1/26"}, []string{"192.168.0.1/25"}, []string{"192.168.0.1/25"}, []string{"192.168.0.1/24", "192.168.0.1/26"}, `0.0.0.0/0 (target_pos:31:has_entry:false) | 1--> 192.168.0.0/24 (target_pos:7:has_entry:true) | | 0--> 192.168.0.0/26 (target_pos:5:has_entry:true)`, "remove path prefix", }, { rnet.IPv4, []string{"192.168.0.1/24", "192.168.0.1/25", "192.168.0.64/26", "192.168.0.1/26"}, []string{"192.168.0.1/25"}, []string{"192.168.0.1/25"}, []string{"192.168.0.1/24", "192.168.0.1/26", "192.168.0.64/26"}, `0.0.0.0/0 (target_pos:31:has_entry:false) | 1--> 192.168.0.0/24 (target_pos:7:has_entry:true) | | 0--> 192.168.0.0/25 (target_pos:6:has_entry:false) | | | 0--> 192.168.0.0/26 (target_pos:5:has_entry:true) | | | 1--> 192.168.0.64/26 (target_pos:5:has_entry:true)`, "remove path prefix with more than 1 children", }, { rnet.IPv4, []string{"192.168.0.1/24", "192.168.0.1/25"}, []string{"192.168.0.1/26"}, []string{""}, []string{"192.168.0.1/24", "192.168.0.1/25"}, `0.0.0.0/0 (target_pos:31:has_entry:false) | 1--> 192.168.0.0/24 (target_pos:7:has_entry:true) | | 0--> 192.168.0.0/25 (target_pos:6:has_entry:true)`, "remove non existent", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { trie := newPrefixTree(tc.version).(*prefixTrie) for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := trie.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } for i, remove := range tc.removes { _, network, _ := net.ParseCIDR(remove) removed, err := trie.Remove(*network) assert.NoError(t, err) if str := tc.expectedRemoves[i]; str != "" { _, ipnet, _ := net.ParseCIDR(str) expected := NewBasicRangerEntry(*ipnet) assert.Equal(t, expected, removed) } else { assert.Nil(t, removed) } } assert.Equal(t, len(tc.expectedNetworksInDepthOrder), trie.Len(), "trie size should match after revmoval") allNetworks, err := trie.CoveredNetworks(*getAllByVersion(tc.version)) assert.Nil(t, err) assert.Equal(t, len(allNetworks), trie.Len(), "trie size should match") walk := trie.walkDepth() for _, network := range tc.expectedNetworksInDepthOrder { _, ipnet, _ := net.ParseCIDR(network) expected := NewBasicRangerEntry(*ipnet) actual := <-walk assert.Equal(t, expected, actual) } // Ensure no unexpected elements in trie. for network := range walk { assert.Nil(t, network) } assert.Equal(t, tc.expectedTrieString, trie.String()) }) } } func TestToReplicateIssue(t *testing.T) { cases := []struct { version rnet.IPVersion inserts []string ip net.IP networks []string name string }{ { rnet.IPv4, []string{"192.168.0.1/32"}, net.ParseIP("192.168.0.1"), []string{"192.168.0.1/32"}, "basic containing network for /32 mask", }, { rnet.IPv6, []string{"a::1/128"}, net.ParseIP("a::1"), []string{"a::1/128"}, "basic containing network for /128 mask", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { trie := newPrefixTree(tc.version) for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := trie.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } expectedEntries := []RangerEntry{} for _, network := range tc.networks { _, net, _ := net.ParseCIDR(network) expectedEntries = append(expectedEntries, NewBasicRangerEntry(*net)) } contains, err := trie.Contains(tc.ip) assert.NoError(t, err) assert.True(t, contains) networks, err := trie.ContainingNetworks(tc.ip) assert.NoError(t, err) assert.Equal(t, expectedEntries, networks) }) } } type expectedIPRange struct { start net.IP end net.IP } func TestPrefixTrieContains(t *testing.T) { cases := []struct { version rnet.IPVersion inserts []string expectedIPs []expectedIPRange name string }{ { rnet.IPv4, []string{"192.168.0.0/24"}, []expectedIPRange{ {net.ParseIP("192.168.0.0"), net.ParseIP("192.168.1.0")}, }, "basic contains", }, { rnet.IPv4, []string{"192.168.0.0/24", "128.168.0.0/24"}, []expectedIPRange{ {net.ParseIP("192.168.0.0"), net.ParseIP("192.168.1.0")}, {net.ParseIP("128.168.0.0"), net.ParseIP("128.168.1.0")}, }, "multiple ranges contains", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { trie := newPrefixTree(tc.version) for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := trie.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } for _, expectedIPRange := range tc.expectedIPs { var contains bool var err error start := expectedIPRange.start for ; !expectedIPRange.end.Equal(start); start = rnet.NextIP(start) { contains, err = trie.Contains(start) assert.NoError(t, err) assert.True(t, contains) } // Check out of bounds ips on both ends contains, err = trie.Contains(rnet.PreviousIP(expectedIPRange.start)) assert.NoError(t, err) assert.False(t, contains) contains, err = trie.Contains(rnet.NextIP(expectedIPRange.end)) assert.NoError(t, err) assert.False(t, contains) } }) } } func TestPrefixTrieContainingNetworks(t *testing.T) { cases := []struct { version rnet.IPVersion inserts []string ip net.IP networks []string name string }{ { rnet.IPv4, []string{"192.168.0.0/24"}, net.ParseIP("192.168.0.1"), []string{"192.168.0.0/24"}, "basic containing networks", }, { rnet.IPv4, []string{"192.168.0.0/24", "192.168.0.0/25"}, net.ParseIP("192.168.0.1"), []string{"192.168.0.0/24", "192.168.0.0/25"}, "inclusive networks", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { trie := newPrefixTree(tc.version) for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := trie.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } expectedEntries := []RangerEntry{} for _, network := range tc.networks { _, net, _ := net.ParseCIDR(network) expectedEntries = append(expectedEntries, NewBasicRangerEntry(*net)) } networks, err := trie.ContainingNetworks(tc.ip) assert.NoError(t, err) assert.Equal(t, expectedEntries, networks) }) } } type coveredNetworkTest struct { version rnet.IPVersion inserts []string search string networks []string name string } var coveredNetworkTests = []coveredNetworkTest{ { rnet.IPv4, []string{"192.168.0.0/24"}, "192.168.0.0/16", []string{"192.168.0.0/24"}, "basic covered networks", }, { rnet.IPv4, []string{"192.168.0.0/24"}, "10.1.0.0/16", nil, "nothing", }, { rnet.IPv4, []string{"192.168.0.0/24", "192.168.0.0/25"}, "192.168.0.0/16", []string{"192.168.0.0/24", "192.168.0.0/25"}, "multiple networks", }, { rnet.IPv4, []string{"192.168.0.0/24", "192.168.0.0/25", "192.168.0.1/32"}, "192.168.0.0/16", []string{"192.168.0.0/24", "192.168.0.0/25", "192.168.0.1/32"}, "multiple networks 2", }, { rnet.IPv4, []string{"192.168.1.1/32"}, "192.168.0.0/16", []string{"192.168.1.1/32"}, "leaf", }, { rnet.IPv4, []string{"0.0.0.0/0", "192.168.1.1/32"}, "192.168.0.0/16", []string{"192.168.1.1/32"}, "leaf with root", }, { rnet.IPv4, []string{ "0.0.0.0/0", "192.168.0.0/24", "192.168.1.1/32", "10.1.0.0/16", "10.1.1.0/24", }, "192.168.0.0/16", []string{"192.168.0.0/24", "192.168.1.1/32"}, "path not taken", }, { rnet.IPv4, []string{ "192.168.0.0/15", }, "192.168.0.0/16", nil, "only masks different", }, } func TestPrefixTrieCoveredNetworks(t *testing.T) { for _, tc := range coveredNetworkTests { t.Run(tc.name, func(t *testing.T) { trie := newPrefixTree(tc.version) for _, insert := range tc.inserts { _, network, _ := net.ParseCIDR(insert) err := trie.Insert(NewBasicRangerEntry(*network)) assert.NoError(t, err) } var expectedEntries []RangerEntry for _, network := range tc.networks { _, net, _ := net.ParseCIDR(network) expectedEntries = append(expectedEntries, NewBasicRangerEntry(*net)) } _, snet, _ := net.ParseCIDR(tc.search) networks, err := trie.CoveredNetworks(*snet) assert.NoError(t, err) assert.Equal(t, expectedEntries, networks) }) } } func TestTrieMemUsage(t *testing.T) { if testing.Short() { t.Skip("Skipping memory test in `-short` mode") } numIPs := 100000 runs := 10 // Avg heap allocation over all runs should not be more than the heap allocation of first run multiplied // by threshold, picking 1% as sane number for detecting memory leak. thresh := 1.01 trie := newPrefixTree(rnet.IPv4) var baseLineHeap, totalHeapAllocOverRuns uint64 for i := 0; i < runs; i++ { t.Logf("Executing Run %d of %d", i+1, runs) // Insert networks. for n := 0; n < numIPs; n++ { trie.Insert(NewBasicRangerEntry(GenLeafIPNet(GenIPV4()))) } t.Logf("Inserted All (%d networks)", trie.Len()) assert.Less(t, 0, trie.Len(), "Len should > 0") assert.LessOrEqualf(t, trie.Len(), numIPs, "Len should <= %d", numIPs) allNetworks, err := trie.CoveredNetworks(*getAllByVersion(rnet.IPv4)) assert.Nil(t, err) assert.Equal(t, len(allNetworks), trie.Len(), "trie size should match") // Remove networks. _, all, _ := net.ParseCIDR("0.0.0.0/0") ll, _ := trie.CoveredNetworks(*all) for i := 0; i < len(ll); i++ { trie.Remove(ll[i].Network()) } t.Logf("Removed All (%d networks)", len(ll)) assert.Equal(t, 0, trie.Len(), "Len after removal should == 0") // Perform GC runtime.GC() // Get HeapAlloc stats. heapAlloc := GetHeapAllocation() totalHeapAllocOverRuns += heapAlloc if i == 0 { baseLineHeap = heapAlloc } } // Assert that heap allocation from first loop is within set threshold of avg over all runs. assert.Less(t, uint64(0), baseLineHeap) assert.LessOrEqual(t, float64(baseLineHeap), float64(totalHeapAllocOverRuns/uint64(runs))*thresh) } func GenLeafIPNet(ip net.IP) net.IPNet { return net.IPNet{ IP: ip, Mask: net.CIDRMask(32, 32), } } // GenIPV4 generates an IPV4 address func GenIPV4() net.IP { rand.Seed(time.Now().UnixNano()) nn := rand.Uint32() if nn < 4294967295 { nn++ } ip := make(net.IP, 4) binary.BigEndian.PutUint32(ip, uint32(nn)) return ip } func GetHeapAllocation() uint64 { var m runtime.MemStats runtime.ReadMemStats(&m) return m.HeapAlloc } cidranger-1.0.2/version.go000066400000000000000000000032151373217032300154660ustar00rootroot00000000000000package cidranger import ( "net" rnet "github.com/yl2chen/cidranger/net" ) type rangerFactory func(rnet.IPVersion) Ranger type versionedRanger struct { ipV4Ranger Ranger ipV6Ranger Ranger } func newVersionedRanger(factory rangerFactory) Ranger { return &versionedRanger{ ipV4Ranger: factory(rnet.IPv4), ipV6Ranger: factory(rnet.IPv6), } } func (v *versionedRanger) Insert(entry RangerEntry) error { network := entry.Network() ranger, err := v.getRangerForIP(network.IP) if err != nil { return err } return ranger.Insert(entry) } func (v *versionedRanger) Remove(network net.IPNet) (RangerEntry, error) { ranger, err := v.getRangerForIP(network.IP) if err != nil { return nil, err } return ranger.Remove(network) } func (v *versionedRanger) Contains(ip net.IP) (bool, error) { ranger, err := v.getRangerForIP(ip) if err != nil { return false, err } return ranger.Contains(ip) } func (v *versionedRanger) ContainingNetworks(ip net.IP) ([]RangerEntry, error) { ranger, err := v.getRangerForIP(ip) if err != nil { return nil, err } return ranger.ContainingNetworks(ip) } func (v *versionedRanger) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) { ranger, err := v.getRangerForIP(network.IP) if err != nil { return nil, err } return ranger.CoveredNetworks(network) } // Len returns number of networks in ranger. func (v *versionedRanger) Len() int { return v.ipV4Ranger.Len() + v.ipV6Ranger.Len() } func (v *versionedRanger) getRangerForIP(ip net.IP) (Ranger, error) { if ip.To4() != nil { return v.ipV4Ranger, nil } if ip.To16() != nil { return v.ipV6Ranger, nil } return nil, ErrInvalidNetworkNumberInput }