subnets 1.0.0pre → 1.0.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|