maxmind-geoip2 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +114 -0
- data/README.dev.md +1 -1
- data/README.md +26 -6
- data/Rakefile +1 -0
- data/lib/maxmind/geoip2/client.rb +18 -9
- data/lib/maxmind/geoip2/model/anonymous_plus.rb +46 -0
- data/lib/maxmind/geoip2/model/city.rb +5 -6
- data/lib/maxmind/geoip2/model/connection_type.rb +3 -2
- data/lib/maxmind/geoip2/model/enterprise.rb +2 -3
- data/lib/maxmind/geoip2/model/insights.rb +3 -5
- data/lib/maxmind/geoip2/reader.rb +26 -1
- data/lib/maxmind/geoip2/record/location.rb +3 -3
- data/lib/maxmind/geoip2/record/traits.rb +40 -28
- data/lib/maxmind/geoip2/version.rb +8 -0
- data/maxmind-geoip2.gemspec +11 -6
- data/test/data/LICENSE-APACHE +202 -0
- data/test/data/LICENSE-MIT +17 -0
- data/test/data/MaxMind-DB-spec.md +1 -2
- data/test/data/README.md +8 -1
- data/test/data/cmd/write-test-data/main.go +68 -0
- data/test/data/go.mod +13 -0
- data/test/data/go.sum +16 -0
- data/test/data/pkg/writer/decoder.go +178 -0
- data/test/data/pkg/writer/geoip2.go +184 -0
- data/test/data/pkg/writer/ip.go +39 -0
- data/test/data/pkg/writer/maxmind.go +246 -0
- data/test/data/pkg/writer/nestedstructures.go +73 -0
- data/test/data/pkg/writer/writer.go +61 -0
- data/test/data/source-data/GeoIP-Anonymous-Plus-Test.json +175 -0
- data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +6 -0
- data/test/data/source-data/GeoIP2-City-Test.json +392 -5
- data/test/data/source-data/GeoIP2-Connection-Type-Test.json +15 -10
- data/test/data/source-data/GeoIP2-Country-Test.json +99 -25
- data/test/data/source-data/GeoIP2-Domain-Test.json +5 -0
- data/test/data/source-data/GeoIP2-Enterprise-Test.json +371 -6
- data/test/data/source-data/GeoIP2-IP-Risk-Test.json +31 -0
- data/test/data/source-data/GeoIP2-Precision-Enterprise-Sandbox-Test.json +296 -0
- data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +1159 -175
- data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +15 -0
- data/test/data/source-data/GeoIP2-User-Count-Test.json +18 -0
- data/test/data/source-data/GeoLite2-City-Test.json +168 -3
- data/test/data/source-data/GeoLite2-Country-Test.json +92 -3
- data/test/data/test-data/GeoIP-Anonymous-Plus-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
- data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
- data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-IP-Risk-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
- data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
- data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
- data/test/data/test-data/GeoLite2-City-Test.mmdb +0 -0
- data/test/data/test-data/GeoLite2-Country-Test.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
- data/test/data/test-data/MaxMind-DB-test-pointer-decoder.mmdb +0 -0
- data/test/data/test-data/README.md +28 -12
- data/test/test_client.rb +18 -2
- data/test/test_reader.rb +42 -1
- metadata +25 -13
- data/test/data/LICENSE +0 -4
- data/test/data/perltidyrc +0 -12
- data/test/data/source-data/README +0 -15
- data/test/data/test-data/write-test-data.pl +0 -695
@@ -1,695 +0,0 @@
|
|
1
|
-
#!/usr/bin/env perl
|
2
|
-
|
3
|
-
use strict;
|
4
|
-
use warnings;
|
5
|
-
use autodie;
|
6
|
-
use utf8;
|
7
|
-
|
8
|
-
use Cwd qw( abs_path );
|
9
|
-
use File::Basename qw( dirname );
|
10
|
-
use File::Slurper qw( read_binary write_binary );
|
11
|
-
use Cpanel::JSON::XS 4.16 qw( decode_json );
|
12
|
-
use Math::Int128 qw( MAX_UINT128 string_to_uint128 uint128 );
|
13
|
-
use MaxMind::DB::Writer::Serializer 0.100004;
|
14
|
-
use MaxMind::DB::Writer::Tree 0.100004;
|
15
|
-
use MaxMind::DB::Writer::Util qw( key_for_data );
|
16
|
-
use Net::Works::Network ();
|
17
|
-
use Test::MaxMind::DB::Common::Util qw( standard_test_metadata );
|
18
|
-
|
19
|
-
my $Dir = dirname( abs_path($0) );
|
20
|
-
|
21
|
-
sub main {
|
22
|
-
my @sizes = ( 24, 28, 32 );
|
23
|
-
my @ipv4_range = ( '1.1.1.1', '1.1.1.32' );
|
24
|
-
|
25
|
-
my @ipv4_subnets = Net::Works::Network->range_as_subnets(@ipv4_range);
|
26
|
-
for my $record_size (@sizes) {
|
27
|
-
write_test_db(
|
28
|
-
$record_size,
|
29
|
-
\@ipv4_subnets,
|
30
|
-
{ ip_version => 4 },
|
31
|
-
'ipv4',
|
32
|
-
);
|
33
|
-
}
|
34
|
-
|
35
|
-
write_broken_pointers_test_db(
|
36
|
-
24,
|
37
|
-
\@ipv4_subnets,
|
38
|
-
{ ip_version => 4 },
|
39
|
-
'broken-pointers',
|
40
|
-
);
|
41
|
-
|
42
|
-
write_broken_search_tree_db(
|
43
|
-
24,
|
44
|
-
\@ipv4_subnets,
|
45
|
-
{ ip_version => 4 },
|
46
|
-
'broken-search-tree',
|
47
|
-
);
|
48
|
-
|
49
|
-
my @ipv6_subnets = Net::Works::Network->range_as_subnets(
|
50
|
-
'::1:ffff:ffff',
|
51
|
-
'::2:0000:0059'
|
52
|
-
);
|
53
|
-
|
54
|
-
for my $record_size (@sizes) {
|
55
|
-
write_test_db(
|
56
|
-
$record_size,
|
57
|
-
\@ipv6_subnets,
|
58
|
-
{ ip_version => 6 },
|
59
|
-
'ipv6',
|
60
|
-
);
|
61
|
-
|
62
|
-
write_test_db(
|
63
|
-
$record_size,
|
64
|
-
[
|
65
|
-
@ipv6_subnets,
|
66
|
-
Net::Works::Network->range_as_subnets( @ipv4_range, 6 ),
|
67
|
-
],
|
68
|
-
{ ip_version => 6 },
|
69
|
-
'mixed',
|
70
|
-
);
|
71
|
-
}
|
72
|
-
|
73
|
-
write_decoder_test_db();
|
74
|
-
write_pointer_decoder_test_db();
|
75
|
-
write_deeply_nested_structures_db();
|
76
|
-
|
77
|
-
write_geoip2_dbs();
|
78
|
-
write_broken_geoip2_city_db();
|
79
|
-
write_invalid_node_count();
|
80
|
-
|
81
|
-
write_no_ipv4_tree_db();
|
82
|
-
|
83
|
-
write_no_map_db( \@ipv4_subnets );
|
84
|
-
|
85
|
-
write_test_serialization_data();
|
86
|
-
|
87
|
-
write_db_with_metadata_pointers();
|
88
|
-
}
|
89
|
-
|
90
|
-
sub write_broken_pointers_test_db {
|
91
|
-
no warnings 'redefine';
|
92
|
-
|
93
|
-
my $orig_store_data = MaxMind::DB::Writer::Serializer->can('store_data');
|
94
|
-
|
95
|
-
# This breaks the value of the record for the 1.1.1.32 network, causing it
|
96
|
-
# to point outside the database.
|
97
|
-
local *MaxMind::DB::Writer::Serializer::store_data = sub {
|
98
|
-
my $data_pointer = shift->$orig_store_data(@_);
|
99
|
-
my $value = $_[1];
|
100
|
-
if ( ref($value) eq 'HASH'
|
101
|
-
&& exists $value->{ip}
|
102
|
-
&& $value->{ip} eq '1.1.1.32' ) {
|
103
|
-
|
104
|
-
$data_pointer += 100_000;
|
105
|
-
}
|
106
|
-
return $data_pointer;
|
107
|
-
};
|
108
|
-
|
109
|
-
# The next hack will poison the data section for the 1.1.16/28 subnet
|
110
|
-
# value. It's value will be a pointer that resolves to an offset outside
|
111
|
-
# the database.
|
112
|
-
|
113
|
-
my $key_to_poison = key_for_data( { ip => '1.1.1.16' } );
|
114
|
-
|
115
|
-
my $orig_position_for_data
|
116
|
-
= MaxMind::DB::Writer::Serializer->can('_position_for_data');
|
117
|
-
local *MaxMind::DB::Writer::Serializer::_position_for_data = sub {
|
118
|
-
my $key = $_[1];
|
119
|
-
|
120
|
-
if ( $key eq $key_to_poison ) {
|
121
|
-
return 1_000_000;
|
122
|
-
}
|
123
|
-
else {
|
124
|
-
return shift->$orig_position_for_data(@_);
|
125
|
-
}
|
126
|
-
};
|
127
|
-
|
128
|
-
write_test_db(@_);
|
129
|
-
|
130
|
-
return;
|
131
|
-
}
|
132
|
-
|
133
|
-
sub write_broken_search_tree_db {
|
134
|
-
my $filename = ( write_test_db(@_) )[1];
|
135
|
-
|
136
|
-
my $content = read_binary($filename);
|
137
|
-
|
138
|
-
# This causes the right record of the first node to be 0, meaning it
|
139
|
-
# points back to the top of the tree. This should never happen in a
|
140
|
-
# database that follows the spec.
|
141
|
-
substr( $content, 5, 1 ) = "\0";
|
142
|
-
write_binary( $filename, $content );
|
143
|
-
|
144
|
-
return;
|
145
|
-
}
|
146
|
-
|
147
|
-
sub write_test_db {
|
148
|
-
my $record_size = shift;
|
149
|
-
my $subnets = shift;
|
150
|
-
my $metadata = shift;
|
151
|
-
my $ip_version_name = shift;
|
152
|
-
|
153
|
-
my $writer = MaxMind::DB::Writer::Tree->new(
|
154
|
-
ip_version => $subnets->[0]->version(),
|
155
|
-
record_size => $record_size,
|
156
|
-
alias_ipv6_to_ipv4 => ( $subnets->[0]->version() == 6 ? 1 : 0 ),
|
157
|
-
map_key_type_callback => sub { 'utf8_string' },
|
158
|
-
standard_test_metadata(),
|
159
|
-
%{$metadata},
|
160
|
-
);
|
161
|
-
|
162
|
-
for my $subnet ( @{$subnets} ) {
|
163
|
-
$writer->insert_network(
|
164
|
-
$subnet,
|
165
|
-
{ ip => $subnet->first()->as_string() }
|
166
|
-
);
|
167
|
-
}
|
168
|
-
|
169
|
-
my $filename = sprintf(
|
170
|
-
"$Dir/MaxMind-DB-test-%s-%i.mmdb",
|
171
|
-
$ip_version_name,
|
172
|
-
$record_size,
|
173
|
-
);
|
174
|
-
open my $fh, '>', $filename;
|
175
|
-
|
176
|
-
$writer->write_tree($fh);
|
177
|
-
|
178
|
-
close $fh;
|
179
|
-
|
180
|
-
return ( $writer, $filename );
|
181
|
-
}
|
182
|
-
|
183
|
-
{
|
184
|
-
# We will store this once for each subnet so we will also be testing
|
185
|
-
# pointers, since the serializer will generate a pointer to this
|
186
|
-
# structure.
|
187
|
-
my %all_types = (
|
188
|
-
utf8_string => 'unicode! ☯ - ♫',
|
189
|
-
double => 42.123456,
|
190
|
-
bytes => pack( 'N', 42 ),
|
191
|
-
uint16 => 100,
|
192
|
-
uint32 => 2**28,
|
193
|
-
int32 => -1 * ( 2**28 ),
|
194
|
-
uint64 => uint128(1) << 60,
|
195
|
-
uint128 => uint128(1) << 120,
|
196
|
-
array => [ 1, 2, 3, ],
|
197
|
-
map => {
|
198
|
-
mapX => {
|
199
|
-
utf8_stringX => 'hello',
|
200
|
-
arrayX => [ 7, 8, 9 ],
|
201
|
-
},
|
202
|
-
},
|
203
|
-
boolean => 1,
|
204
|
-
float => 1.1,
|
205
|
-
);
|
206
|
-
|
207
|
-
my %all_types_0 = (
|
208
|
-
utf8_string => q{},
|
209
|
-
double => 0,
|
210
|
-
bytes => q{},
|
211
|
-
uint16 => 0,
|
212
|
-
uint32 => 0,
|
213
|
-
int32 => 0,
|
214
|
-
uint64 => uint128(0),
|
215
|
-
uint128 => uint128(0),
|
216
|
-
array => [],
|
217
|
-
map => {},
|
218
|
-
boolean => 0,
|
219
|
-
float => 0,
|
220
|
-
);
|
221
|
-
|
222
|
-
# We limit this to numeric types as the other types would generate
|
223
|
-
# very large databases
|
224
|
-
my %numeric_types_max = (
|
225
|
-
double => 'Inf',
|
226
|
-
float => 'Inf',
|
227
|
-
int32 => 0x7fffffff,
|
228
|
-
uint16 => 0xffff,
|
229
|
-
uint32 => string_to_uint128('0xffff_ffff'),
|
230
|
-
uint64 => string_to_uint128('0xffff_ffff_ffff_ffff'),
|
231
|
-
uint128 => MAX_UINT128,
|
232
|
-
);
|
233
|
-
|
234
|
-
sub write_decoder_test_db {
|
235
|
-
my $writer = _decoder_writer();
|
236
|
-
|
237
|
-
my @subnets
|
238
|
-
= map { Net::Works::Network->new_from_string( string => $_ ) }
|
239
|
-
qw(
|
240
|
-
::1.1.1.0/120
|
241
|
-
::2.2.0.0/112
|
242
|
-
::3.0.0.0/104
|
243
|
-
::4.5.6.7/128
|
244
|
-
abcd::/64
|
245
|
-
1000::1234:0000/112
|
246
|
-
);
|
247
|
-
|
248
|
-
for my $subnet (@subnets) {
|
249
|
-
$writer->insert_network(
|
250
|
-
$subnet,
|
251
|
-
\%all_types,
|
252
|
-
);
|
253
|
-
}
|
254
|
-
|
255
|
-
$writer->insert_network(
|
256
|
-
Net::Works::Network->new_from_string( string => '::0.0.0.0/128' ),
|
257
|
-
\%all_types_0,
|
258
|
-
);
|
259
|
-
|
260
|
-
$writer->insert_network(
|
261
|
-
Net::Works::Network->new_from_string(
|
262
|
-
string => '::255.255.255.255/128'
|
263
|
-
),
|
264
|
-
\%numeric_types_max,
|
265
|
-
);
|
266
|
-
|
267
|
-
open my $fh, '>', "$Dir/MaxMind-DB-test-decoder.mmdb";
|
268
|
-
$writer->write_tree($fh);
|
269
|
-
close $fh;
|
270
|
-
|
271
|
-
return;
|
272
|
-
}
|
273
|
-
|
274
|
-
sub write_pointer_decoder_test_db {
|
275
|
-
|
276
|
-
# We want to create a database where most values are pointers
|
277
|
-
no warnings 'redefine';
|
278
|
-
local *MaxMind::DB::Writer::Serializer::_should_cache_value
|
279
|
-
= sub { 1 };
|
280
|
-
my $writer = _decoder_writer();
|
281
|
-
|
282
|
-
# We add these slightly different records so that we end up with
|
283
|
-
# pointers for the individual values in the maps, not just pointers
|
284
|
-
# to the map
|
285
|
-
$writer->insert_network(
|
286
|
-
'1.0.0.0/32',
|
287
|
-
{
|
288
|
-
%all_types,
|
289
|
-
booleanX => 0,
|
290
|
-
arrayX => [ 1, 2, 3, 4, ],
|
291
|
-
mapXX => {
|
292
|
-
utf8_stringX => 'hello',
|
293
|
-
arrayX => [ 7, 8, 9, 10 ],
|
294
|
-
booleanX => 0,
|
295
|
-
},
|
296
|
-
},
|
297
|
-
);
|
298
|
-
|
299
|
-
$writer->insert_network(
|
300
|
-
'1.1.1.0/32',
|
301
|
-
{
|
302
|
-
%all_types,
|
303
|
-
|
304
|
-
# This has to be 0 rather than 1 as otherwise the buggy
|
305
|
-
# Perl writer will think it is the same as an uint32 value of
|
306
|
-
# 1 and make a pointer to a value of a different type.
|
307
|
-
boolean => 0,
|
308
|
-
},
|
309
|
-
);
|
310
|
-
|
311
|
-
open my $fh, '>', "$Dir/MaxMind-DB-test-pointer-decoder.mmdb";
|
312
|
-
$writer->write_tree($fh);
|
313
|
-
close $fh;
|
314
|
-
|
315
|
-
return;
|
316
|
-
}
|
317
|
-
|
318
|
-
sub _decoder_writer {
|
319
|
-
return MaxMind::DB::Writer::Tree->new(
|
320
|
-
ip_version => 6,
|
321
|
-
record_size => 24,
|
322
|
-
database_type => 'MaxMind DB Decoder Test',
|
323
|
-
languages => ['en'],
|
324
|
-
description => {
|
325
|
-
en =>
|
326
|
-
'MaxMind DB Decoder Test database - contains every MaxMind DB data type',
|
327
|
-
},
|
328
|
-
alias_ipv6_to_ipv4 => 1,
|
329
|
-
remove_reserved_networks => 0,
|
330
|
-
map_key_type_callback => sub {
|
331
|
-
my $key = $_[0];
|
332
|
-
$key =~ s/X*$//;
|
333
|
-
return $key eq 'array' ? [ 'array', 'uint32' ] : $key;
|
334
|
-
},
|
335
|
-
);
|
336
|
-
}
|
337
|
-
}
|
338
|
-
|
339
|
-
{
|
340
|
-
my %nested = (
|
341
|
-
map1 => {
|
342
|
-
map2 => {
|
343
|
-
array => [
|
344
|
-
{
|
345
|
-
map3 => { a => 1, b => 2, c => 3 },
|
346
|
-
},
|
347
|
-
],
|
348
|
-
},
|
349
|
-
},
|
350
|
-
);
|
351
|
-
|
352
|
-
sub write_deeply_nested_structures_db {
|
353
|
-
my $writer = MaxMind::DB::Writer::Tree->new(
|
354
|
-
ip_version => 6,
|
355
|
-
record_size => 24,
|
356
|
-
ip_version => 6,
|
357
|
-
database_type => 'MaxMind DB Nested Data Structures',
|
358
|
-
languages => ['en'],
|
359
|
-
description => {
|
360
|
-
en =>
|
361
|
-
'MaxMind DB Nested Data Structures Test database - contains deeply nested map/array structures',
|
362
|
-
},
|
363
|
-
alias_ipv6_to_ipv4 => 1,
|
364
|
-
map_key_type_callback => sub {
|
365
|
-
my $key = shift;
|
366
|
-
return
|
367
|
-
$key =~ /^map/ ? 'map'
|
368
|
-
: $key eq 'array' ? [ 'array', 'map' ]
|
369
|
-
: 'uint32';
|
370
|
-
}
|
371
|
-
);
|
372
|
-
|
373
|
-
my @subnets
|
374
|
-
= map { Net::Works::Network->new_from_string( string => $_ ) }
|
375
|
-
qw(
|
376
|
-
::1.1.1.0/120
|
377
|
-
::2.2.0.0/112
|
378
|
-
::3.0.0.0/104
|
379
|
-
::4.5.6.7/128
|
380
|
-
abcd::/64
|
381
|
-
1000::1234:0000/112
|
382
|
-
);
|
383
|
-
|
384
|
-
for my $subnet (@subnets) {
|
385
|
-
$writer->insert_network(
|
386
|
-
$subnet,
|
387
|
-
\%nested,
|
388
|
-
);
|
389
|
-
}
|
390
|
-
|
391
|
-
open my $fh, '>', "$Dir/MaxMind-DB-test-nested.mmdb";
|
392
|
-
$writer->write_tree($fh);
|
393
|
-
close $fh;
|
394
|
-
|
395
|
-
return;
|
396
|
-
}
|
397
|
-
}
|
398
|
-
|
399
|
-
sub write_geoip2_dbs {
|
400
|
-
_write_geoip2_db( @{$_}[ 0, 1 ], 'Test' )
|
401
|
-
for (
|
402
|
-
[ 'GeoIP2-Anonymous-IP', {} ],
|
403
|
-
['GeoIP2-City'],
|
404
|
-
['GeoIP2-Connection-Type'],
|
405
|
-
['GeoIP2-Country'],
|
406
|
-
['GeoIP2-DensityIncome'],
|
407
|
-
['GeoIP2-Domain'],
|
408
|
-
['GeoIP2-Enterprise'],
|
409
|
-
['GeoIP2-ISP'],
|
410
|
-
['GeoIP2-Precision-Enterprise'],
|
411
|
-
['GeoIP2-Static-IP-Score'],
|
412
|
-
['GeoIP2-User-Count'],
|
413
|
-
['GeoLite2-ASN'],
|
414
|
-
['GeoLite2-City'],
|
415
|
-
['GeoLite2-Country'],
|
416
|
-
);
|
417
|
-
}
|
418
|
-
|
419
|
-
sub write_broken_geoip2_city_db {
|
420
|
-
no warnings 'redefine';
|
421
|
-
|
422
|
-
# This is how we _used_ to encode doubles. Storing them this way with the
|
423
|
-
# current reader tools can lead to weird errors. This broken database is a
|
424
|
-
# good way to test the robustness of reader code in the face of broken
|
425
|
-
# databases.
|
426
|
-
local *MaxMind::DB::Writer::Serializer::_encode_double = sub {
|
427
|
-
my $self = shift;
|
428
|
-
my $value = shift;
|
429
|
-
|
430
|
-
$self->_simple_encode( double => $value );
|
431
|
-
};
|
432
|
-
|
433
|
-
_write_geoip2_db( 'GeoIP2-City', 0, 'Test Broken Double Format' );
|
434
|
-
}
|
435
|
-
|
436
|
-
sub write_invalid_node_count {
|
437
|
-
no warnings 'redefine';
|
438
|
-
local *MaxMind::DB::Writer::Tree::node_count = sub { 100000 };
|
439
|
-
|
440
|
-
_write_geoip2_db( 'GeoIP2-City', 0, 'Test Invalid Node Count' );
|
441
|
-
}
|
442
|
-
|
443
|
-
sub _universal_map_key_type_callback {
|
444
|
-
my $map = {
|
445
|
-
|
446
|
-
# languages
|
447
|
-
de => 'utf8_string',
|
448
|
-
en => 'utf8_string',
|
449
|
-
es => 'utf8_string',
|
450
|
-
fr => 'utf8_string',
|
451
|
-
ja => 'utf8_string',
|
452
|
-
'pt-BR' => 'utf8_string',
|
453
|
-
ru => 'utf8_string',
|
454
|
-
'zh-CN' => 'utf8_string',
|
455
|
-
|
456
|
-
# production
|
457
|
-
accuracy_radius => 'uint16',
|
458
|
-
autonomous_system_number => 'uint32',
|
459
|
-
autonomous_system_organization => 'utf8_string',
|
460
|
-
average_income => 'uint32',
|
461
|
-
city => 'map',
|
462
|
-
code => 'utf8_string',
|
463
|
-
confidence => 'uint16',
|
464
|
-
connection_type => 'utf8_string',
|
465
|
-
continent => 'map',
|
466
|
-
country => 'map',
|
467
|
-
domain => 'utf8_string',
|
468
|
-
geoname_id => 'uint32',
|
469
|
-
ipv4_24 => 'uint32',
|
470
|
-
ipv4_32 => 'uint32',
|
471
|
-
ipv6_32 => 'uint32',
|
472
|
-
ipv6_48 => 'uint32',
|
473
|
-
ipv6_64 => 'uint32',
|
474
|
-
is_anonymous => 'boolean',
|
475
|
-
is_anonymous_proxy => 'boolean',
|
476
|
-
is_anonymous_vpn => 'boolean',
|
477
|
-
is_hosting_provider => 'boolean',
|
478
|
-
is_in_european_union => 'boolean',
|
479
|
-
is_legitimate_proxy => 'boolean',
|
480
|
-
is_public_proxy => 'boolean',
|
481
|
-
is_residential_proxy => 'boolean',
|
482
|
-
is_satellite_provider => 'boolean',
|
483
|
-
is_tor_exit_node => 'boolean',
|
484
|
-
iso_code => 'utf8_string',
|
485
|
-
isp => 'utf8_string',
|
486
|
-
latitude => 'double',
|
487
|
-
location => 'map',
|
488
|
-
longitude => 'double',
|
489
|
-
metro_code => 'uint16',
|
490
|
-
mobile_country_code => 'utf8_string',
|
491
|
-
mobile_network_code => 'utf8_string',
|
492
|
-
names => 'map',
|
493
|
-
organization => 'utf8_string',
|
494
|
-
population_density => 'uint32',
|
495
|
-
postal => 'map',
|
496
|
-
registered_country => 'map',
|
497
|
-
represented_country => 'map',
|
498
|
-
score => 'double',
|
499
|
-
static_ip_score => 'double',
|
500
|
-
subdivisions => [ 'array', 'map' ],
|
501
|
-
time_zone => 'utf8_string',
|
502
|
-
traits => 'map',
|
503
|
-
traits => 'map',
|
504
|
-
type => 'utf8_string',
|
505
|
-
user_type => 'utf8_string',
|
506
|
-
|
507
|
-
# for testing only
|
508
|
-
foo => 'utf8_string',
|
509
|
-
bar => 'utf8_string',
|
510
|
-
buzz => 'utf8_string',
|
511
|
-
our_value => 'utf8_string',
|
512
|
-
};
|
513
|
-
|
514
|
-
my $callback = sub {
|
515
|
-
my $key = shift;
|
516
|
-
|
517
|
-
return $map->{$key} || die <<"ERROR";
|
518
|
-
Unknown tree key '$key'.
|
519
|
-
|
520
|
-
The universal_map_key_type_callback doesn't know what type to use for the passed
|
521
|
-
key. If you are adding a new key that will be used in a frozen tree / mmdb then
|
522
|
-
you should update the mapping in both our internal code and here.
|
523
|
-
ERROR
|
524
|
-
};
|
525
|
-
|
526
|
-
return $callback;
|
527
|
-
}
|
528
|
-
|
529
|
-
sub _write_geoip2_db {
|
530
|
-
my $type = shift;
|
531
|
-
my $populate_all_networks_with_data = shift;
|
532
|
-
my $description = shift;
|
533
|
-
|
534
|
-
my $writer = MaxMind::DB::Writer::Tree->new(
|
535
|
-
ip_version => 6,
|
536
|
-
record_size => 28,
|
537
|
-
ip_version => 6,
|
538
|
-
database_type => $type,
|
539
|
-
languages => [ 'en', $type eq 'GeoIP2-City' ? ('zh') : () ],
|
540
|
-
description => {
|
541
|
-
en => ( $type =~ s/-/ /gr )
|
542
|
-
. " $description Database (fake GeoIP2 data, for example purposes only)",
|
543
|
-
$type eq 'GeoIP2-City' ? ( zh => '小型数据库' ) : (),
|
544
|
-
},
|
545
|
-
alias_ipv6_to_ipv4 => 1,
|
546
|
-
map_key_type_callback => _universal_map_key_type_callback(),
|
547
|
-
);
|
548
|
-
|
549
|
-
_populate_all_networks( $writer, $populate_all_networks_with_data )
|
550
|
-
if $populate_all_networks_with_data;
|
551
|
-
|
552
|
-
my $value = shift;
|
553
|
-
my $nodes
|
554
|
-
= decode_json( read_binary("$Dir/../source-data/$type-Test.json") );
|
555
|
-
|
556
|
-
for my $node (@$nodes) {
|
557
|
-
for my $network ( keys %$node ) {
|
558
|
-
$writer->insert_network(
|
559
|
-
Net::Works::Network->new_from_string( string => $network ),
|
560
|
-
$node->{$network}
|
561
|
-
);
|
562
|
-
}
|
563
|
-
}
|
564
|
-
|
565
|
-
my $suffix = $description =~ s/ /-/gr;
|
566
|
-
open my $output_fh, '>', "$Dir/$type-$suffix.mmdb";
|
567
|
-
$writer->write_tree($output_fh);
|
568
|
-
close $output_fh;
|
569
|
-
|
570
|
-
return;
|
571
|
-
}
|
572
|
-
|
573
|
-
sub _populate_all_networks {
|
574
|
-
my $writer = shift;
|
575
|
-
my $data = shift;
|
576
|
-
|
577
|
-
my $max_uint128 = uint128(0) - 1;
|
578
|
-
my @networks = Net::Works::Network->range_as_subnets(
|
579
|
-
Net::Works::Address->new_from_integer(
|
580
|
-
integer => 0,
|
581
|
-
version => 6,
|
582
|
-
),
|
583
|
-
Net::Works::Address->new_from_integer(
|
584
|
-
integer => $max_uint128,
|
585
|
-
version => 6,
|
586
|
-
),
|
587
|
-
);
|
588
|
-
|
589
|
-
for my $network (@networks) {
|
590
|
-
$writer->insert_network( $network => $data );
|
591
|
-
}
|
592
|
-
}
|
593
|
-
|
594
|
-
sub write_no_ipv4_tree_db {
|
595
|
-
my $subnets = shift;
|
596
|
-
|
597
|
-
my $writer = MaxMind::DB::Writer::Tree->new(
|
598
|
-
ip_version => 6,
|
599
|
-
record_size => 24,
|
600
|
-
ip_version => 6,
|
601
|
-
database_type => 'MaxMind DB No IPv4 Search Tree',
|
602
|
-
languages => ['en'],
|
603
|
-
description => {
|
604
|
-
en => 'MaxMind DB No IPv4 Search Tree',
|
605
|
-
},
|
606
|
-
remove_reserved_networks => 0,
|
607
|
-
root_data_type => 'utf8_string',
|
608
|
-
map_key_type_callback => sub { {} },
|
609
|
-
);
|
610
|
-
|
611
|
-
my $subnet = Net::Works::Network->new_from_string( string => '::/64' );
|
612
|
-
$writer->insert_network( $subnet, $subnet->as_string() );
|
613
|
-
|
614
|
-
open my $output_fh, '>', "$Dir/MaxMind-DB-no-ipv4-search-tree.mmdb";
|
615
|
-
$writer->write_tree($output_fh);
|
616
|
-
close $output_fh;
|
617
|
-
|
618
|
-
return;
|
619
|
-
}
|
620
|
-
|
621
|
-
# The point of this database is to provide something where we can test looking
|
622
|
-
# up a single value. In other words, each IP address points to a non-compound
|
623
|
-
# value, a string rather than a map or array.
|
624
|
-
sub write_no_map_db {
|
625
|
-
my $subnets = shift;
|
626
|
-
|
627
|
-
my $writer = MaxMind::DB::Writer::Tree->new(
|
628
|
-
ip_version => 4,
|
629
|
-
record_size => 24,
|
630
|
-
database_type => 'MaxMind DB String Value Entries',
|
631
|
-
languages => ['en'],
|
632
|
-
description => {
|
633
|
-
en =>
|
634
|
-
'MaxMind DB String Value Entries (no maps or arrays as values)',
|
635
|
-
},
|
636
|
-
root_data_type => 'utf8_string',
|
637
|
-
map_key_type_callback => sub { {} },
|
638
|
-
);
|
639
|
-
|
640
|
-
for my $subnet ( @{$subnets} ) {
|
641
|
-
$writer->insert_network( $subnet, $subnet->as_string() );
|
642
|
-
}
|
643
|
-
|
644
|
-
open my $output_fh, '>', "$Dir/MaxMind-DB-string-value-entries.mmdb";
|
645
|
-
$writer->write_tree($output_fh);
|
646
|
-
close $output_fh;
|
647
|
-
|
648
|
-
return;
|
649
|
-
}
|
650
|
-
|
651
|
-
sub write_test_serialization_data {
|
652
|
-
my $serializer = MaxMind::DB::Writer::Serializer->new(
|
653
|
-
map_key_type_callback => sub { 'utf8_string' } );
|
654
|
-
|
655
|
-
$serializer->store_data( map => { long_key => 'long_value1' } );
|
656
|
-
$serializer->store_data( map => { long_key => 'long_value2' } );
|
657
|
-
$serializer->store_data( map => { long_key2 => 'long_value1' } );
|
658
|
-
$serializer->store_data( map => { long_key2 => 'long_value2' } );
|
659
|
-
$serializer->store_data( map => { long_key => 'long_value1' } );
|
660
|
-
$serializer->store_data( map => { long_key2 => 'long_value2' } );
|
661
|
-
|
662
|
-
open my $fh, '>', "$Dir/maps-with-pointers.raw";
|
663
|
-
print {$fh} ${ $serializer->buffer() }
|
664
|
-
or die "Cannot write to maps-with-pointers.raw: $!";
|
665
|
-
close $fh;
|
666
|
-
|
667
|
-
return;
|
668
|
-
}
|
669
|
-
|
670
|
-
sub write_db_with_metadata_pointers {
|
671
|
-
my $repeated_string = 'Lots of pointers in metadata';
|
672
|
-
my $writer = MaxMind::DB::Writer::Tree->new(
|
673
|
-
ip_version => 6,
|
674
|
-
record_size => 24,
|
675
|
-
map_key_type_callback => sub { 'utf8_string' },
|
676
|
-
database_type => $repeated_string,
|
677
|
-
languages => [ 'en', 'es', 'zh' ],
|
678
|
-
description => {
|
679
|
-
en => $repeated_string,
|
680
|
-
es => $repeated_string,
|
681
|
-
zh => $repeated_string,
|
682
|
-
},
|
683
|
-
|
684
|
-
);
|
685
|
-
|
686
|
-
_populate_all_networks( $writer, {} );
|
687
|
-
|
688
|
-
open my $fh, '>', "$Dir/MaxMind-DB-test-metadata-pointers.mmdb";
|
689
|
-
|
690
|
-
$writer->write_tree($fh);
|
691
|
-
|
692
|
-
close $fh;
|
693
|
-
}
|
694
|
-
|
695
|
-
main();
|