subnets 1.0.0pre → 1.0.0pre1
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/README.md +5 -5
- data/ext/subnets/ext.c +104 -34
- data/ext/subnets/ipaddr.c +44 -0
- data/ext/subnets/ipaddr.h +6 -0
- data/test/private_networks_benchmark.rb +2 -2
- data/test/subnets/net4_test.rb +16 -0
- data/test/subnets/net6_test.rb +1 -0
- data/test/summarize.rb +12 -0
- data/test/test_helper.rb +12 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54f0c79b3c0859e0d9cd2758276652d48fd0ceeece739695691b76c5cb8d01a7
|
4
|
+
data.tar.gz: 69b64044d769ede44735081a0411b088cf3016bf6a4a732238c5996c105e5e19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ceebcd95e1fb22ee86acf2c4eb606c3deda2a97c04a7f57d0e97f5493974441855f3e7a04e2525e6b4ff1a88f6508df29b548bebcfca36dceb0ee4384ab76f82
|
7
|
+
data.tar.gz: ac0e808b3e42227f53881eed50a807e136a0b2602f0402bda120a42f9cc78d16ce64029cd2d5aa2e6fd9456dfb797411fe5496c6fda5321528e4cd39a828e591
|
data/README.md
CHANGED
@@ -27,11 +27,11 @@ better. Plotted on logscale. (Ruby 2.5.0p0, 2.5 GHz Intel Core i7).
|
|
27
27
|
```
|
28
28
|
$ bundle exec rake benchmark TEST=test/private_networks_benchmark
|
29
29
|
|
30
|
-
ipaddr : 46.
|
31
|
-
ipaddress : 63.
|
32
|
-
netaddr : 31.
|
33
|
-
*subnets : 4.
|
34
|
-
rack (regexp) : 5.
|
30
|
+
ipaddr : 46.25μs/ip ██████████████████████████████████▋
|
31
|
+
ipaddress : 63.88μs/ip ██████████████████████████████████████▏
|
32
|
+
netaddr : 31.03μs/ip ██████████████████████████████▎
|
33
|
+
*subnets : 4.19μs/ip ████████▏
|
34
|
+
rack (regexp) : 5.25μs/ip ██████████▋
|
35
35
|
' ' ' ' '
|
36
36
|
2 5 10 20 50
|
37
37
|
```
|
data/ext/subnets/ext.c
CHANGED
@@ -318,54 +318,45 @@ method_ip4_band(VALUE self, VALUE other) {
|
|
318
318
|
|
319
319
|
VALUE
|
320
320
|
method_ip6_not(VALUE self) {
|
321
|
-
ip6_t *ip
|
321
|
+
ip6_t *ip;
|
322
322
|
Data_Get_Struct(self, ip6_t, ip);
|
323
|
-
|
324
|
-
not.x[i] = ~(ip->x[i]);
|
325
|
-
}
|
326
|
-
return ip6_new(IP6, not);
|
323
|
+
return ip6_new(IP6, ip6_not(*ip));
|
327
324
|
}
|
328
325
|
|
329
326
|
VALUE
|
330
327
|
method_ip6_bor(VALUE self, VALUE other) {
|
331
|
-
ip6_t *a, *b
|
328
|
+
ip6_t *a, *b;
|
332
329
|
|
333
330
|
assert_kind_of(other, IP6);
|
334
331
|
|
335
332
|
Data_Get_Struct(self, ip6_t, a);
|
336
333
|
Data_Get_Struct(other, ip6_t, b);
|
337
|
-
|
338
|
-
|
339
|
-
}
|
340
|
-
return ip6_new(IP6, bor);
|
334
|
+
|
335
|
+
return ip6_new(IP6, ip6_bor(*a, *b));
|
341
336
|
}
|
342
337
|
|
343
338
|
VALUE
|
344
339
|
method_ip6_xor(VALUE self, VALUE other) {
|
345
|
-
ip6_t *a, *b
|
340
|
+
ip6_t *a, *b;
|
346
341
|
|
347
342
|
assert_kind_of(other, IP6);
|
348
343
|
|
349
344
|
Data_Get_Struct(self, ip6_t, a);
|
350
345
|
Data_Get_Struct(other, ip6_t, b);
|
351
|
-
|
352
|
-
|
353
|
-
}
|
354
|
-
return ip6_new(IP6, xor);
|
346
|
+
|
347
|
+
return ip6_new(IP6, ip6_xor(*a, *b));
|
355
348
|
}
|
356
349
|
|
357
350
|
VALUE
|
358
351
|
method_ip6_band(VALUE self, VALUE other) {
|
359
|
-
ip6_t *a, *b
|
352
|
+
ip6_t *a, *b;
|
360
353
|
|
361
354
|
assert_kind_of(other, IP6);
|
362
355
|
|
363
356
|
Data_Get_Struct(self, ip6_t, a);
|
364
357
|
Data_Get_Struct(other, ip6_t, b);
|
365
|
-
|
366
|
-
|
367
|
-
}
|
368
|
-
return ip6_new(IP6, band);
|
358
|
+
|
359
|
+
return ip6_new(IP6, ip6_band(*a, *b));
|
369
360
|
}
|
370
361
|
|
371
362
|
/**
|
@@ -546,6 +537,33 @@ method_net6_to_s(VALUE self) {
|
|
546
537
|
return rb_str_new2(buf);
|
547
538
|
}
|
548
539
|
|
540
|
+
VALUE
|
541
|
+
method_ip4_to_i(VALUE self) {
|
542
|
+
ip4_t *ip;
|
543
|
+
Data_Get_Struct(self, ip4_t, ip);
|
544
|
+
return RB_UINT2NUM(*ip);
|
545
|
+
}
|
546
|
+
|
547
|
+
VALUE
|
548
|
+
method_ip6_to_i(VALUE self) {
|
549
|
+
VALUE ret;
|
550
|
+
ip6_t *ip;
|
551
|
+
Data_Get_Struct(self, ip6_t, ip);
|
552
|
+
|
553
|
+
ID lshift = rb_intern("<<");
|
554
|
+
ID plus = rb_intern("+");
|
555
|
+
|
556
|
+
ret = RB_INT2NUM(0);
|
557
|
+
|
558
|
+
for (int i=0; i<8; i++) {
|
559
|
+
VALUE hextet = RB_UINT2NUM(ip->x[i]);
|
560
|
+
VALUE inc = rb_funcall(hextet, lshift, 1, RB_INT2NUM(16*(7-i)));
|
561
|
+
ret = rb_funcall(ret, plus, 1, inc);
|
562
|
+
}
|
563
|
+
|
564
|
+
return ret;
|
565
|
+
}
|
566
|
+
|
549
567
|
/**
|
550
568
|
* @return [Boolean]
|
551
569
|
*/
|
@@ -600,10 +618,7 @@ method_ip6_eql_p(VALUE self, VALUE other) {
|
|
600
618
|
Data_Get_Struct(self, ip6_t, a);
|
601
619
|
Data_Get_Struct(other, ip6_t, b);
|
602
620
|
|
603
|
-
|
604
|
-
if (a->x[i] != b->x[i]) return Qfalse;
|
605
|
-
}
|
606
|
-
return Qtrue;
|
621
|
+
return ip6_eql_p(*a, *b) ? Qtrue : Qfalse;
|
607
622
|
}
|
608
623
|
|
609
624
|
/**
|
@@ -745,34 +760,86 @@ method_net6_hextets(VALUE self) {
|
|
745
760
|
return hextets;
|
746
761
|
}
|
747
762
|
|
763
|
+
/**
|
764
|
+
* @return [Subnets::Net4] the smallest subnet that includes all of
|
765
|
+
* the subnets in +nets+
|
766
|
+
*
|
767
|
+
* @param nets [Array<Subnets::Net4>]
|
768
|
+
*/
|
748
769
|
VALUE
|
749
770
|
method_net4_summarize(VALUE class, VALUE nets) {
|
750
771
|
net4_t result;
|
751
772
|
|
752
|
-
result.address = mk_mask4(32);
|
753
|
-
result.prefixlen = 32;
|
754
|
-
result.mask = mk_mask4(32);
|
755
|
-
|
756
773
|
for (ssize_t i = 0; i < RARRAY_LEN(nets); i++) {
|
757
774
|
VALUE rbnet = RARRAY_AREF(nets, i);
|
758
775
|
|
759
776
|
assert_kind_of(rbnet, Net4);
|
760
777
|
|
761
|
-
net4_t *net;
|
778
|
+
const net4_t *net;
|
762
779
|
Data_Get_Struct(rbnet, net4_t, net);
|
763
780
|
|
764
|
-
|
781
|
+
if (i == 0) {
|
782
|
+
result.address = (net->address & net->mask);
|
783
|
+
result.prefixlen = net->prefixlen;
|
784
|
+
result.mask = net->mask;
|
785
|
+
} else {
|
786
|
+
if (result.prefixlen > net->prefixlen) {
|
787
|
+
result.prefixlen = net->prefixlen;
|
788
|
+
result.mask = net->mask;
|
789
|
+
result.address &= result.mask;
|
790
|
+
}
|
765
791
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
792
|
+
while (result.address != (net->address & result.mask)) {
|
793
|
+
result.prefixlen -= 1;
|
794
|
+
result.mask = mk_mask4(result.prefixlen);
|
795
|
+
result.address &= result.mask;
|
796
|
+
}
|
770
797
|
}
|
771
798
|
}
|
772
799
|
|
773
800
|
return net4_new(class, result);
|
774
801
|
}
|
775
802
|
|
803
|
+
/**
|
804
|
+
* @return [Subnets::Net6] the smallest subnet that includes all of
|
805
|
+
* the subnets in +nets+
|
806
|
+
*
|
807
|
+
* @param nets [Array<Subnets::Net6>]
|
808
|
+
*/
|
809
|
+
VALUE
|
810
|
+
method_net6_summarize(VALUE class, VALUE nets) {
|
811
|
+
net6_t result;
|
812
|
+
|
813
|
+
for (ssize_t i = 0; i < RARRAY_LEN(nets); i++) {
|
814
|
+
VALUE rbnet = RARRAY_AREF(nets, i);
|
815
|
+
|
816
|
+
assert_kind_of(rbnet, Net6);
|
817
|
+
|
818
|
+
net6_t *net;
|
819
|
+
Data_Get_Struct(rbnet, net6_t, net);
|
820
|
+
|
821
|
+
if (i == 0) {
|
822
|
+
result.address = ip6_band(net->address, net->mask);
|
823
|
+
result.prefixlen = net->prefixlen;
|
824
|
+
result.mask = net->mask;
|
825
|
+
} else {
|
826
|
+
if (result.prefixlen > net->prefixlen) {
|
827
|
+
result.prefixlen = net->prefixlen;
|
828
|
+
result.mask = net->mask;
|
829
|
+
result.address = ip6_band(result.address, result.mask);
|
830
|
+
}
|
831
|
+
|
832
|
+
while(!ip6_eql_p(result.address, ip6_band(net->address, result.mask))) {
|
833
|
+
result.prefixlen -= 1;
|
834
|
+
result.mask = mk_mask6(result.prefixlen);
|
835
|
+
result.address = ip6_band(result.address, result.mask);
|
836
|
+
}
|
837
|
+
}
|
838
|
+
}
|
839
|
+
|
840
|
+
return net6_new(class, result);
|
841
|
+
}
|
842
|
+
|
776
843
|
/**
|
777
844
|
* Try parsing +str+ as Net4, Net6, IP4, IP6.
|
778
845
|
*
|
@@ -942,6 +1009,7 @@ void Init_Subnets() {
|
|
942
1009
|
rb_define_alias(IP4, "eql?", "==");
|
943
1010
|
rb_define_method(IP4, "hash", method_ip4_hash, 0);
|
944
1011
|
rb_define_method(IP4, "to_s", method_ip4_to_s, 0);
|
1012
|
+
rb_define_method(IP4, "to_i", method_ip4_to_i, 0);
|
945
1013
|
|
946
1014
|
rb_define_method(IP4, "~", method_ip4_not, 0);
|
947
1015
|
rb_define_method(IP4, "|", method_ip4_bor, 1);
|
@@ -955,6 +1023,7 @@ void Init_Subnets() {
|
|
955
1023
|
rb_define_alias(IP6, "eql?", "==");
|
956
1024
|
rb_define_method(IP6, "hash", method_ip6_hash, 0);
|
957
1025
|
rb_define_method(IP6, "to_s", method_ip6_to_s, 0);
|
1026
|
+
rb_define_method(IP6, "to_i", method_ip6_to_i, 0);
|
958
1027
|
rb_define_method(IP6, "hextets", method_ip6_hextets, 0);
|
959
1028
|
|
960
1029
|
rb_define_method(IP6, "~", method_ip6_not, 0);
|
@@ -988,6 +1057,7 @@ void Init_Subnets() {
|
|
988
1057
|
rb_define_singleton_method(Net6, "parse", method_net6_parse, 1);
|
989
1058
|
rb_define_singleton_method(Net6, "random", method_net6_random, -1);
|
990
1059
|
rb_define_singleton_method(Net6, "new", method_net6_new, 2);
|
1060
|
+
rb_define_singleton_method(Net6, "summarize", method_net6_summarize, 1);
|
991
1061
|
rb_define_method(Net6, "==", method_net6_eql_p, 1);
|
992
1062
|
rb_define_alias(Net6, "eql?", "==");
|
993
1063
|
rb_define_method(Net6, "hash", method_net6_hash, 0);
|
data/ext/subnets/ipaddr.c
CHANGED
@@ -187,6 +187,50 @@ net6_snprint(net6_t net, char *str, size_t size) {
|
|
187
187
|
return n0 + n1;
|
188
188
|
}
|
189
189
|
|
190
|
+
int
|
191
|
+
ip6_eql_p(ip6_t a, ip6_t b) {
|
192
|
+
for (int i=0; i<8; i++) {
|
193
|
+
if (a.x[i] != b.x[i]) return 0;
|
194
|
+
}
|
195
|
+
return !0;
|
196
|
+
}
|
197
|
+
|
198
|
+
ip6_t
|
199
|
+
ip6_not(ip6_t ip) {
|
200
|
+
ip6_t not;
|
201
|
+
for (int i=0; i<8; i++) {
|
202
|
+
not.x[i] = ~(ip.x[i]);
|
203
|
+
}
|
204
|
+
return not;
|
205
|
+
}
|
206
|
+
|
207
|
+
ip6_t
|
208
|
+
ip6_band(ip6_t a, ip6_t b) {
|
209
|
+
ip6_t band;
|
210
|
+
for (int i=0; i<8; i++) {
|
211
|
+
band.x[i] = a.x[i] & b.x[i];
|
212
|
+
}
|
213
|
+
return band;
|
214
|
+
}
|
215
|
+
|
216
|
+
ip6_t
|
217
|
+
ip6_bor(ip6_t a, ip6_t b) {
|
218
|
+
ip6_t bor;
|
219
|
+
for (int i=0; i<8; i++) {
|
220
|
+
bor.x[i] = a.x[i] | b.x[i];
|
221
|
+
}
|
222
|
+
return bor;
|
223
|
+
}
|
224
|
+
|
225
|
+
ip6_t
|
226
|
+
ip6_xor(ip6_t a, ip6_t b) {
|
227
|
+
ip6_t xor;
|
228
|
+
for (int i=0; i<8; i++) {
|
229
|
+
xor.x[i] = a.x[i] ^ b.x[i];
|
230
|
+
}
|
231
|
+
return xor;
|
232
|
+
}
|
233
|
+
|
190
234
|
int
|
191
235
|
hexvalue(unsigned int c) {
|
192
236
|
if (c-'0'<10) return c-'0';
|
data/ext/subnets/ipaddr.h
CHANGED
@@ -102,4 +102,10 @@ size_t read_ip6_strict(const char *, ip6_t *);
|
|
102
102
|
size_t read_net4_strict(const char *, net4_t *);
|
103
103
|
size_t read_net6_strict(const char *, net6_t *);
|
104
104
|
|
105
|
+
int ip6_eql_p(ip6_t, ip6_t);
|
106
|
+
ip6_t ip6_not(ip6_t);
|
107
|
+
ip6_t ip6_band(ip6_t, ip6_t);
|
108
|
+
ip6_t ip6_bor(ip6_t, ip6_t);
|
109
|
+
ip6_t ip6_xor(ip6_t, ip6_t);
|
110
|
+
|
105
111
|
#endif /* __IPADDR_H__ */
|
@@ -43,11 +43,11 @@ puts "# check if single IP is in the private IPv4 subnets"
|
|
43
43
|
}.total
|
44
44
|
count += 100
|
45
45
|
end
|
46
|
-
puts "%10.10s: checked %8d (%6d hits, %2d%%) in %2.2f for %7.
|
46
|
+
puts "%10.10s: checked %8d (%6d hits, %2d%%) in %2.2f for %7.2fμs/ip" %
|
47
47
|
[check.name, count, hits, 100.0*hits/count, total, total/count*1e6]
|
48
48
|
|
49
49
|
results[check.name] = total/count*1e6
|
50
50
|
end
|
51
51
|
|
52
52
|
puts
|
53
|
-
plotbarslogscale(prefix: '%-15.15s: %5.
|
53
|
+
plotbarslogscale(prefix: '%-15.15s: %5.2fμs/ip ', width: 46, min: 2, max: 65, tics: [2,5,10,20,50], data: results)
|
data/test/subnets/net4_test.rb
CHANGED
@@ -3,6 +3,7 @@ require 'test_helper'
|
|
3
3
|
module Subnets
|
4
4
|
class TestNet4 < Minitest::Test
|
5
5
|
include EqlAndHash
|
6
|
+
include Summarize
|
6
7
|
|
7
8
|
def klass
|
8
9
|
Net4
|
@@ -70,5 +71,20 @@ module Subnets
|
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|
74
|
+
|
75
|
+
def test_summarize
|
76
|
+
data = {
|
77
|
+
'192.168.0.0/24' => ['192.168.0.0/25', '192.168.0.128/25'],
|
78
|
+
'10.0.0.0/8' => ['10.0.0.0/24', '10.250.2.3/19'],
|
79
|
+
}
|
80
|
+
|
81
|
+
data.each do |summ, nets|
|
82
|
+
summ = Subnets.parse(summ)
|
83
|
+
nets = nets.map(&Subnets.method(:parse))
|
84
|
+
|
85
|
+
assert_equal summ, Net4.summarize(nets)
|
86
|
+
assert_summarizes summ, nets
|
87
|
+
end
|
88
|
+
end
|
73
89
|
end
|
74
90
|
end
|
data/test/subnets/net6_test.rb
CHANGED
data/test/summarize.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Summarize
|
2
|
+
def test_summarizing_net_includes_subnets
|
3
|
+
random = Random.new
|
4
|
+
start = Time.now
|
5
|
+
until Time.now - start > TIMED_TEST_DURATION
|
6
|
+
nets = (1..3).map{klass.random(random)}
|
7
|
+
summ = klass.summarize(nets)
|
8
|
+
assert_operator summ.prefixlen, :>=, 0, "summarized #{nets} to invalid #{summ}"
|
9
|
+
assert_summarizes klass.summarize(nets), nets
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -18,6 +18,7 @@ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new,
|
|
18
18
|
require 'subnets'
|
19
19
|
require 'well_known_subnets'
|
20
20
|
require 'eql_and_hash'
|
21
|
+
require 'summarize'
|
21
22
|
|
22
23
|
TIMED_TEST_DURATION = (ENV['TIMED_TEST_DURATION'] || 1).to_i
|
23
24
|
|
@@ -28,3 +29,14 @@ end
|
|
28
29
|
def refute_include(obj, val)
|
29
30
|
refute obj.include?(val), "#{obj} should not include #{val}"
|
30
31
|
end
|
32
|
+
|
33
|
+
def assert_summarizes(summ, nets)
|
34
|
+
bad = nil
|
35
|
+
nets.each do |net|
|
36
|
+
unless summ.include?(net)
|
37
|
+
bad = net
|
38
|
+
break
|
39
|
+
end
|
40
|
+
end
|
41
|
+
refute bad, "#{nets} not summarized by #{summ}: #{summ}.include?(#{bad}) was false"
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subnets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.0pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Mahoney
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -175,6 +175,7 @@ files:
|
|
175
175
|
- test/subnets/net4_test.rb
|
176
176
|
- test/subnets/net6_test.rb
|
177
177
|
- test/subnets_test.rb
|
178
|
+
- test/summarize.rb
|
178
179
|
- test/test_helper.rb
|
179
180
|
- test/well_known_subnets.rb
|
180
181
|
homepage: https://github.com/raisemarketplace/subnets
|