subnets 1.0.0pre1 → 1.0.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/README.md +3 -3
- data/ext/subnets/ext.c +112 -59
- data/ext/subnets/ipaddr.c +5 -3
- data/test/eql_and_hash.rb +9 -1
- data/test/subnets/ip4_test.rb +19 -0
- data/test/subnets/ip6_test.rb +24 -0
- data/test/subnets/net4_test.rb +5 -1
- data/test/subnets/net6_test.rb +6 -2
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17cca826fc5397edbbf19b80546c22487603991ce8138b71905cccebb2ddb9dd
|
4
|
+
data.tar.gz: c13ca13ebc0cf9821555974921c6d9e8ac80e779a087d9a43703b4c74f9dde37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4403041659c6f4420a47f042f97e349df8493885bbb7a2b640ddb87889bb3ebec8fb910a4c02d23bbaecf03abefc97339bb220eeb6d693a9826330ccdb51b570
|
7
|
+
data.tar.gz: daa48990aab7c42e05b41428dbaf2dbbdc94831ca60634ec2b42cd36772ea67b4c15a4fdab3f92f0a1d2b558e985c144eddf026057469aec37b15a13350b239a
|
data/README.md
CHANGED
@@ -72,9 +72,9 @@ This has not been used in production.
|
|
72
72
|
## Safe?
|
73
73
|
|
74
74
|
The IPv4 and IPv6 parsers are written in C. In addition to the unit
|
75
|
-
test suite, the parsers have had minimal (
|
76
|
-
[American fuzzy lop](http://lcamtuf.coredump.cx/afl/). There is
|
77
|
-
confidence
|
75
|
+
test suite, the parsers have had minimal (16+ hours) of fuzzing with
|
76
|
+
[American fuzzy lop](http://lcamtuf.coredump.cx/afl/). There is medium
|
77
|
+
confidence that the parsers will not read out-of-bounds.
|
78
78
|
|
79
79
|
## Correct?
|
80
80
|
|
data/ext/subnets/ext.c
CHANGED
@@ -24,22 +24,23 @@ VALUE rb_intern_xor = Qnil;
|
|
24
24
|
} \
|
25
25
|
} while (0)
|
26
26
|
|
27
|
+
#define MIN(a,b) ((a) > (b) ? (b) : (a))
|
28
|
+
|
27
29
|
/**
|
28
30
|
* ParseError indicates the input string could not be parsed as the
|
29
31
|
* requested type.
|
30
32
|
*/
|
31
33
|
VALUE ParseError = Qnil;
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
}
|
42
|
-
}
|
35
|
+
/* 49 is longest possible ip6 cidr */
|
36
|
+
/* ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128 */
|
37
|
+
#define raise_parse_error(type, data) do { \
|
38
|
+
if (strlen(data) > 49) { \
|
39
|
+
rb_raise(ParseError, "failed to parse as %s: '%.45s...'", (type), (data)); \
|
40
|
+
} else { \
|
41
|
+
rb_raise(ParseError, "failed to parse as %s: '%s'", (type), (data)); \
|
42
|
+
} \
|
43
|
+
} while (0)
|
43
44
|
|
44
45
|
VALUE
|
45
46
|
ip4_new(VALUE class, ip4_t src) {
|
@@ -82,6 +83,21 @@ method_ip4_new(VALUE class, VALUE address) {
|
|
82
83
|
return ip4_new(class, RB_NUM2UINT(address));
|
83
84
|
}
|
84
85
|
|
86
|
+
VALUE
|
87
|
+
method_ip6_new(VALUE class, VALUE hextets) {
|
88
|
+
ip6_t ip;
|
89
|
+
|
90
|
+
if (RARRAY_LEN(hextets) != 8) {
|
91
|
+
rb_raise(rb_eArgError, "hextets must be size=8, was %ld", RARRAY_LEN(hextets));
|
92
|
+
}
|
93
|
+
|
94
|
+
for (ssize_t i = 0; i < RARRAY_LEN(hextets); i++) {
|
95
|
+
ip.x[i] = NUM2INT(RARRAY_AREF(hextets, i)) & 0xffff;
|
96
|
+
}
|
97
|
+
|
98
|
+
return ip6_new(class, ip);
|
99
|
+
}
|
100
|
+
|
85
101
|
VALUE
|
86
102
|
method_net4_new(VALUE class, VALUE address, VALUE prefixlen) {
|
87
103
|
net4_t net;
|
@@ -171,14 +187,14 @@ method_net6_parse(VALUE class, VALUE s) {
|
|
171
187
|
VALUE
|
172
188
|
method_ip4_random(int argc, VALUE *argv, VALUE class) {
|
173
189
|
ip4_t ip;
|
174
|
-
VALUE rng;
|
190
|
+
VALUE rng, rand;
|
175
191
|
|
176
192
|
rb_scan_args(argc, argv, "01", &rng);
|
177
193
|
if (Qnil == rng) {
|
178
194
|
rng = rb_funcall(rb_cRandom, rb_intern("new"), 0);
|
179
195
|
}
|
180
196
|
|
181
|
-
|
197
|
+
rand = rb_intern("rand");
|
182
198
|
ip = FIX2INT(rb_funcall(rng, rand, 1, INT2FIX(0xffff+1)));
|
183
199
|
ip |= FIX2INT(rb_funcall(rng, rand, 1, INT2FIX(0xffff+1))) << 16;
|
184
200
|
|
@@ -193,14 +209,14 @@ method_ip4_random(int argc, VALUE *argv, VALUE class) {
|
|
193
209
|
VALUE
|
194
210
|
method_net4_random(int argc, VALUE *argv, VALUE class) {
|
195
211
|
net4_t net;
|
196
|
-
VALUE rng;
|
212
|
+
VALUE rng, rand;
|
197
213
|
|
198
214
|
rb_scan_args(argc, argv, "01", &rng);
|
199
215
|
if (Qnil == rng) {
|
200
216
|
rng = rb_funcall(rb_cRandom, rb_intern("new"), 0);
|
201
217
|
}
|
202
218
|
|
203
|
-
|
219
|
+
rand = rb_intern("rand");
|
204
220
|
net.address = FIX2INT(rb_funcall(rng, rand, 1, INT2FIX(0xffff+1)));
|
205
221
|
net.address |= FIX2INT(rb_funcall(rng, rand, 1, INT2FIX(0xffff+1))) << 16;
|
206
222
|
net.prefixlen = FIX2INT(rb_funcall(rng, rb_intern("rand"), 1, INT2FIX(32+1)));
|
@@ -211,13 +227,15 @@ method_net4_random(int argc, VALUE *argv, VALUE class) {
|
|
211
227
|
|
212
228
|
void
|
213
229
|
ip6_fill_random(ip6_t *ip, VALUE rng, VALUE opts) {
|
230
|
+
VALUE rand;
|
231
|
+
int pre, zeros;
|
232
|
+
|
214
233
|
if (Qnil == rng) {
|
215
234
|
rng = rb_funcall(rb_cRandom, rb_intern("new"), 0);
|
216
235
|
}
|
217
236
|
|
218
|
-
|
219
|
-
|
220
|
-
|
237
|
+
rand = rb_intern("rand");
|
238
|
+
|
221
239
|
if (Qnil != opts && RTEST(rb_hash_aref(opts, ID2SYM(rb_intern("zeros"))))) {
|
222
240
|
pre = FIX2INT(rb_funcall(rng, rand, 1, INT2FIX(8+1)));
|
223
241
|
zeros = FIX2INT(rb_funcall(rng, rand, 1, INT2FIX(8+1 - pre)));
|
@@ -276,6 +294,9 @@ method_net6_random(int argc, VALUE *argv, VALUE class) {
|
|
276
294
|
return net6_new(class, net);
|
277
295
|
}
|
278
296
|
|
297
|
+
/**
|
298
|
+
* @return [IP4] bitwise NOT of +self+
|
299
|
+
*/
|
279
300
|
VALUE
|
280
301
|
method_ip4_not(VALUE self) {
|
281
302
|
ip4_t *ip;
|
@@ -283,6 +304,10 @@ method_ip4_not(VALUE self) {
|
|
283
304
|
return ip4_new(IP4, ~ *ip);
|
284
305
|
}
|
285
306
|
|
307
|
+
/**
|
308
|
+
* @param other [Subnets::IP4]
|
309
|
+
* @return [Subnets::IP4] bitwise OR of +self+ and +other+
|
310
|
+
*/
|
286
311
|
VALUE
|
287
312
|
method_ip4_bor(VALUE self, VALUE other) {
|
288
313
|
ip4_t *a, *b;
|
@@ -294,6 +319,10 @@ method_ip4_bor(VALUE self, VALUE other) {
|
|
294
319
|
return ip4_new(IP4, *a | *b);
|
295
320
|
}
|
296
321
|
|
322
|
+
/**
|
323
|
+
* @param other [Subnets::IP4]
|
324
|
+
* @return [Subnets::IP4] bitwise exclusive XOR of +self+ and +other+
|
325
|
+
*/
|
297
326
|
VALUE
|
298
327
|
method_ip4_xor(VALUE self, VALUE other) {
|
299
328
|
ip4_t *a, *b;
|
@@ -305,6 +334,10 @@ method_ip4_xor(VALUE self, VALUE other) {
|
|
305
334
|
return ip4_new(IP4, *a ^ *b);
|
306
335
|
}
|
307
336
|
|
337
|
+
/**
|
338
|
+
* @param other [Subnets::IP4]
|
339
|
+
* @return [Subnets::IP4] bitwise AND of +self+ and +other+
|
340
|
+
*/
|
308
341
|
VALUE
|
309
342
|
method_ip4_band(VALUE self, VALUE other) {
|
310
343
|
ip4_t *a, *b;
|
@@ -316,6 +349,9 @@ method_ip4_band(VALUE self, VALUE other) {
|
|
316
349
|
return ip4_new(IP4, *a & *b);
|
317
350
|
}
|
318
351
|
|
352
|
+
/**
|
353
|
+
* @return [Subnets::IP6] bitwise NOT of +self+
|
354
|
+
*/
|
319
355
|
VALUE
|
320
356
|
method_ip6_not(VALUE self) {
|
321
357
|
ip6_t *ip;
|
@@ -323,6 +359,10 @@ method_ip6_not(VALUE self) {
|
|
323
359
|
return ip6_new(IP6, ip6_not(*ip));
|
324
360
|
}
|
325
361
|
|
362
|
+
/**
|
363
|
+
* @param other [Subnets::IP6]
|
364
|
+
* @return [Subnets::IP4] bitwise OR of +self+ and +other+
|
365
|
+
*/
|
326
366
|
VALUE
|
327
367
|
method_ip6_bor(VALUE self, VALUE other) {
|
328
368
|
ip6_t *a, *b;
|
@@ -335,6 +375,10 @@ method_ip6_bor(VALUE self, VALUE other) {
|
|
335
375
|
return ip6_new(IP6, ip6_bor(*a, *b));
|
336
376
|
}
|
337
377
|
|
378
|
+
/**
|
379
|
+
* @param other [Subnets::IP6]
|
380
|
+
* @return [Subnets::IP4] bitwise XOR of +self+ and +other+
|
381
|
+
*/
|
338
382
|
VALUE
|
339
383
|
method_ip6_xor(VALUE self, VALUE other) {
|
340
384
|
ip6_t *a, *b;
|
@@ -347,6 +391,10 @@ method_ip6_xor(VALUE self, VALUE other) {
|
|
347
391
|
return ip6_new(IP6, ip6_xor(*a, *b));
|
348
392
|
}
|
349
393
|
|
394
|
+
/**
|
395
|
+
* @param other [Subnets::IP6]
|
396
|
+
* @return [Subnets::IP4] bitwise AND of +self+ and +other+
|
397
|
+
*/
|
350
398
|
VALUE
|
351
399
|
method_ip6_band(VALUE self, VALUE other) {
|
352
400
|
ip6_t *a, *b;
|
@@ -480,10 +528,9 @@ method_net6_include_p(VALUE self, VALUE v) {
|
|
480
528
|
VALUE
|
481
529
|
method_ip4_to_s(VALUE self) {
|
482
530
|
ip4_t *ip;
|
483
|
-
Data_Get_Struct(self, ip4_t, ip);
|
484
|
-
|
485
531
|
char buf[16];
|
486
532
|
|
533
|
+
Data_Get_Struct(self, ip4_t, ip);
|
487
534
|
ip4_snprint(*ip, buf, 16);
|
488
535
|
return rb_str_new2(buf);
|
489
536
|
}
|
@@ -497,10 +544,9 @@ method_ip4_to_s(VALUE self) {
|
|
497
544
|
VALUE
|
498
545
|
method_ip6_to_s(VALUE self) {
|
499
546
|
ip6_t *ip;
|
500
|
-
Data_Get_Struct(self, ip6_t, ip);
|
501
|
-
|
502
547
|
char buf[64];
|
503
548
|
|
549
|
+
Data_Get_Struct(self, ip6_t, ip);
|
504
550
|
ip6_snprint(*ip, buf, 64);
|
505
551
|
return rb_str_new2(buf);
|
506
552
|
}
|
@@ -513,10 +559,9 @@ method_ip6_to_s(VALUE self) {
|
|
513
559
|
VALUE
|
514
560
|
method_net4_to_s(VALUE self) {
|
515
561
|
net4_t *net;
|
516
|
-
Data_Get_Struct(self, net4_t, net);
|
517
|
-
|
518
562
|
char buf[32];
|
519
563
|
|
564
|
+
Data_Get_Struct(self, net4_t, net);
|
520
565
|
net4_snprint(*net, buf, 32);
|
521
566
|
return rb_str_new2(buf);
|
522
567
|
}
|
@@ -529,14 +574,16 @@ method_net4_to_s(VALUE self) {
|
|
529
574
|
VALUE
|
530
575
|
method_net6_to_s(VALUE self) {
|
531
576
|
net6_t *net;
|
532
|
-
Data_Get_Struct(self, net6_t, net);
|
533
|
-
|
534
577
|
char buf[64];
|
535
578
|
|
579
|
+
Data_Get_Struct(self, net6_t, net);
|
536
580
|
net6_snprint(*net, buf, 64);
|
537
581
|
return rb_str_new2(buf);
|
538
582
|
}
|
539
583
|
|
584
|
+
/**
|
585
|
+
* @return [Numeric] the 32 bit integer representing this address
|
586
|
+
*/
|
540
587
|
VALUE
|
541
588
|
method_ip4_to_i(VALUE self) {
|
542
589
|
ip4_t *ip;
|
@@ -544,14 +591,19 @@ method_ip4_to_i(VALUE self) {
|
|
544
591
|
return RB_UINT2NUM(*ip);
|
545
592
|
}
|
546
593
|
|
594
|
+
/**
|
595
|
+
* @return [Numeric] the 128 bit integer representing this address
|
596
|
+
*/
|
547
597
|
VALUE
|
548
598
|
method_ip6_to_i(VALUE self) {
|
549
599
|
VALUE ret;
|
550
600
|
ip6_t *ip;
|
601
|
+
ID lshift, plus;
|
602
|
+
|
551
603
|
Data_Get_Struct(self, ip6_t, ip);
|
552
604
|
|
553
|
-
|
554
|
-
|
605
|
+
lshift = rb_intern("<<");
|
606
|
+
plus = rb_intern("+");
|
555
607
|
|
556
608
|
ret = RB_INT2NUM(0);
|
557
609
|
|
@@ -569,18 +621,16 @@ method_ip6_to_i(VALUE self) {
|
|
569
621
|
*/
|
570
622
|
VALUE
|
571
623
|
method_ip4_eql_p(VALUE self, VALUE other) {
|
624
|
+
ip4_t *a, *b;
|
625
|
+
|
572
626
|
if (CLASS_OF(other) != CLASS_OF(self)) {
|
573
627
|
return Qfalse;
|
574
628
|
}
|
575
629
|
|
576
|
-
ip4_t *a, *b;
|
577
630
|
Data_Get_Struct(self, ip4_t, a);
|
578
631
|
Data_Get_Struct(other, ip4_t, b);
|
579
632
|
|
580
|
-
|
581
|
-
return Qfalse;
|
582
|
-
}
|
583
|
-
return Qtrue;
|
633
|
+
return (*a == *b) ? Qtrue : Qfalse;
|
584
634
|
}
|
585
635
|
|
586
636
|
/**
|
@@ -588,11 +638,12 @@ method_ip4_eql_p(VALUE self, VALUE other) {
|
|
588
638
|
*/
|
589
639
|
VALUE
|
590
640
|
method_net4_eql_p(VALUE self, VALUE other) {
|
641
|
+
net4_t *a, *b;
|
642
|
+
|
591
643
|
if (CLASS_OF(other) != CLASS_OF(self)) {
|
592
644
|
return Qfalse;
|
593
645
|
}
|
594
646
|
|
595
|
-
net4_t *a, *b;
|
596
647
|
Data_Get_Struct(self, net4_t, a);
|
597
648
|
Data_Get_Struct(other, net4_t, b);
|
598
649
|
|
@@ -610,11 +661,12 @@ method_net4_eql_p(VALUE self, VALUE other) {
|
|
610
661
|
*/
|
611
662
|
VALUE
|
612
663
|
method_ip6_eql_p(VALUE self, VALUE other) {
|
664
|
+
ip6_t *a, *b;
|
665
|
+
|
613
666
|
if (CLASS_OF(other) != CLASS_OF(self)) {
|
614
667
|
return Qfalse;
|
615
668
|
}
|
616
669
|
|
617
|
-
ip6_t *a, *b;
|
618
670
|
Data_Get_Struct(self, ip6_t, a);
|
619
671
|
Data_Get_Struct(other, ip6_t, b);
|
620
672
|
|
@@ -626,11 +678,12 @@ method_ip6_eql_p(VALUE self, VALUE other) {
|
|
626
678
|
*/
|
627
679
|
VALUE
|
628
680
|
method_net6_eql_p(VALUE self, VALUE other) {
|
681
|
+
net6_t *a, *b;
|
682
|
+
|
629
683
|
if (CLASS_OF(other) != CLASS_OF(self)) {
|
630
684
|
return Qfalse;
|
631
685
|
}
|
632
686
|
|
633
|
-
net6_t *a, *b;
|
634
687
|
Data_Get_Struct(self, net6_t, a);
|
635
688
|
Data_Get_Struct(other, net6_t, b);
|
636
689
|
|
@@ -651,7 +704,7 @@ VALUE
|
|
651
704
|
method_ip4_hash(VALUE self) {
|
652
705
|
ip4_t *ip;
|
653
706
|
Data_Get_Struct(self, ip4_t, ip);
|
654
|
-
return hash(UINT2NUM(ip));
|
707
|
+
return hash(UINT2NUM(*ip));
|
655
708
|
}
|
656
709
|
|
657
710
|
/**
|
@@ -670,9 +723,11 @@ method_net4_hash(VALUE self) {
|
|
670
723
|
VALUE
|
671
724
|
method_ip6_hash(VALUE self) {
|
672
725
|
ip6_t *ip;
|
726
|
+
VALUE ret;
|
727
|
+
|
673
728
|
Data_Get_Struct(self, ip6_t, ip);
|
674
729
|
|
675
|
-
|
730
|
+
ret = hash(INT2FIX(ip->x[0]));
|
676
731
|
for (int i=1; i<8; i++) {
|
677
732
|
ret = xor(ret, hash(INT2FIX(ip->x[i])));
|
678
733
|
}
|
@@ -685,9 +740,11 @@ method_ip6_hash(VALUE self) {
|
|
685
740
|
VALUE
|
686
741
|
method_net6_hash(VALUE self) {
|
687
742
|
net6_t *net;
|
743
|
+
VALUE ret;
|
744
|
+
|
688
745
|
Data_Get_Struct(self, net6_t, net);
|
689
746
|
|
690
|
-
|
747
|
+
ret = hash(INT2FIX(net->prefixlen));
|
691
748
|
for (int i=0; i<8; i++) {
|
692
749
|
ret = xor(ret, hash(INT2FIX(net->address.x[i])));
|
693
750
|
}
|
@@ -736,9 +793,11 @@ method_net6_mask(VALUE self) {
|
|
736
793
|
VALUE
|
737
794
|
method_ip6_hextets(VALUE self) {
|
738
795
|
ip6_t *ip;
|
796
|
+
VALUE hextets;
|
797
|
+
|
739
798
|
Data_Get_Struct(self, ip6_t, ip);
|
740
799
|
|
741
|
-
|
800
|
+
hextets = rb_ary_new();
|
742
801
|
for (int i=0; i<8; i++) {
|
743
802
|
rb_ary_push(hextets, INT2FIX(ip->x[i]));
|
744
803
|
}
|
@@ -751,9 +810,11 @@ method_ip6_hextets(VALUE self) {
|
|
751
810
|
VALUE
|
752
811
|
method_net6_hextets(VALUE self) {
|
753
812
|
net6_t *net;
|
813
|
+
VALUE hextets;
|
814
|
+
|
754
815
|
Data_Get_Struct(self, net6_t, net);
|
755
816
|
|
756
|
-
|
817
|
+
hextets = rb_ary_new();
|
757
818
|
for (int i=0; i<8; i++) {
|
758
819
|
rb_ary_push(hextets, INT2FIX(net->address.x[i]));
|
759
820
|
}
|
@@ -771,11 +832,11 @@ method_net4_summarize(VALUE class, VALUE nets) {
|
|
771
832
|
net4_t result;
|
772
833
|
|
773
834
|
for (ssize_t i = 0; i < RARRAY_LEN(nets); i++) {
|
835
|
+
const net4_t *net;
|
774
836
|
VALUE rbnet = RARRAY_AREF(nets, i);
|
775
837
|
|
776
838
|
assert_kind_of(rbnet, Net4);
|
777
839
|
|
778
|
-
const net4_t *net;
|
779
840
|
Data_Get_Struct(rbnet, net4_t, net);
|
780
841
|
|
781
842
|
if (i == 0) {
|
@@ -783,14 +844,9 @@ method_net4_summarize(VALUE class, VALUE nets) {
|
|
783
844
|
result.prefixlen = net->prefixlen;
|
784
845
|
result.mask = net->mask;
|
785
846
|
} else {
|
786
|
-
|
787
|
-
|
788
|
-
result.
|
789
|
-
result.address &= result.mask;
|
790
|
-
}
|
791
|
-
|
792
|
-
while (result.address != (net->address & result.mask)) {
|
793
|
-
result.prefixlen -= 1;
|
847
|
+
while (result.prefixlen > net->prefixlen ||
|
848
|
+
result.address != (net->address & result.mask)) {
|
849
|
+
result.prefixlen = MIN(result.prefixlen-1, net->prefixlen);
|
794
850
|
result.mask = mk_mask4(result.prefixlen);
|
795
851
|
result.address &= result.mask;
|
796
852
|
}
|
@@ -811,11 +867,11 @@ method_net6_summarize(VALUE class, VALUE nets) {
|
|
811
867
|
net6_t result;
|
812
868
|
|
813
869
|
for (ssize_t i = 0; i < RARRAY_LEN(nets); i++) {
|
870
|
+
net6_t *net;
|
814
871
|
VALUE rbnet = RARRAY_AREF(nets, i);
|
815
872
|
|
816
873
|
assert_kind_of(rbnet, Net6);
|
817
874
|
|
818
|
-
net6_t *net;
|
819
875
|
Data_Get_Struct(rbnet, net6_t, net);
|
820
876
|
|
821
877
|
if (i == 0) {
|
@@ -823,14 +879,9 @@ method_net6_summarize(VALUE class, VALUE nets) {
|
|
823
879
|
result.prefixlen = net->prefixlen;
|
824
880
|
result.mask = net->mask;
|
825
881
|
} else {
|
826
|
-
|
827
|
-
|
828
|
-
result.
|
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;
|
882
|
+
while(result.prefixlen > net->prefixlen ||
|
883
|
+
!ip6_eql_p(result.address, ip6_band(net->address, result.mask))) {
|
884
|
+
result.prefixlen = MIN(result.prefixlen-1, net->prefixlen);
|
834
885
|
result.mask = mk_mask6(result.prefixlen);
|
835
886
|
result.address = ip6_band(result.address, result.mask);
|
836
887
|
}
|
@@ -848,8 +899,9 @@ method_net6_summarize(VALUE class, VALUE nets) {
|
|
848
899
|
*/
|
849
900
|
VALUE
|
850
901
|
method_subnets_parse(VALUE mod, VALUE str) {
|
902
|
+
const char *s;
|
851
903
|
str = StringValue(str);
|
852
|
-
|
904
|
+
s = StringValueCStr(str);
|
853
905
|
{
|
854
906
|
net4_t net;
|
855
907
|
if (read_net4_strict(s, &net)) return net4_new(Net4, net);
|
@@ -1019,6 +1071,7 @@ void Init_Subnets() {
|
|
1019
1071
|
// Subnets::IP6
|
1020
1072
|
IP6 = rb_define_class_under(Subnets, "IP6", IP);
|
1021
1073
|
rb_define_singleton_method(IP6, "random", method_ip6_random, -1);
|
1074
|
+
rb_define_singleton_method(IP6, "new", method_ip6_new, 1);
|
1022
1075
|
rb_define_method(IP6, "==", method_ip6_eql_p, 1);
|
1023
1076
|
rb_define_alias(IP6, "eql?", "==");
|
1024
1077
|
rb_define_method(IP6, "hash", method_ip6_hash, 0);
|
data/ext/subnets/ipaddr.c
CHANGED
@@ -12,9 +12,11 @@
|
|
12
12
|
|
13
13
|
ip4_t
|
14
14
|
mk_mask4(int prefixlen) {
|
15
|
+
int shift;
|
16
|
+
|
15
17
|
if (prefixlen==0) return 0;
|
16
18
|
|
17
|
-
|
19
|
+
shift = 32 - prefixlen;
|
18
20
|
return (~((ip4_t) 0) >> shift) << shift;
|
19
21
|
}
|
20
22
|
|
@@ -309,6 +311,7 @@ read_ip6(const char *s, ip6_t *a) {
|
|
309
311
|
int i = 0;
|
310
312
|
size_t pos = 0;
|
311
313
|
int brk = 8;
|
314
|
+
ip4_t ip4;
|
312
315
|
|
313
316
|
/*
|
314
317
|
* read optional leading hextet followed by zero or more
|
@@ -337,7 +340,6 @@ read_ip6(const char *s, ip6_t *a) {
|
|
337
340
|
return 0;
|
338
341
|
}
|
339
342
|
|
340
|
-
ip4_t ip4;
|
341
343
|
if ((i==6 || (brk<8 && i<4)) && (n = read_ip4(s+pos, &ip4))) {
|
342
344
|
pos += n;
|
343
345
|
hextets[i] = (ip4 >> 16) & 0xffff;
|
@@ -430,11 +432,11 @@ read_net6_strict(const char *s, net6_t *net) {
|
|
430
432
|
size_t
|
431
433
|
read_net6(const char *s, net6_t *net) {
|
432
434
|
size_t pos;
|
435
|
+
int i, v = 0;
|
433
436
|
|
434
437
|
pos = read_ip6(s, &net->address);
|
435
438
|
if (!pos) return 0;
|
436
439
|
|
437
|
-
int i, v = 0;
|
438
440
|
if (s[pos++] != '/') return 0;
|
439
441
|
for (i = 0; i < 3 && isdigit(s[pos+i]); i++) {
|
440
442
|
v = v*10 + s[pos+i]-'0';
|
data/test/eql_and_hash.rb
CHANGED
@@ -3,6 +3,10 @@ module EqlAndHash
|
|
3
3
|
c.new(*constructor_args)
|
4
4
|
end
|
5
5
|
|
6
|
+
def other_obj(c=klass)
|
7
|
+
c.new(*other_constructor_args)
|
8
|
+
end
|
9
|
+
|
6
10
|
def new_obj_subclass
|
7
11
|
new_obj(Class.new(klass))
|
8
12
|
end
|
@@ -18,14 +22,18 @@ module EqlAndHash
|
|
18
22
|
end
|
19
23
|
|
20
24
|
def test_eq_string
|
25
|
+
refute_equal new_obj, other_obj
|
21
26
|
refute_equal new_obj, 'str'
|
22
27
|
end
|
23
28
|
|
24
29
|
def test_hash
|
25
|
-
a, b = [new_obj, new_obj]
|
30
|
+
a, b, = [new_obj, new_obj]
|
26
31
|
refute_equal a.object_id, b.object_id
|
27
32
|
assert_equal a.hash, b.hash
|
28
33
|
|
34
|
+
other = other_obj
|
35
|
+
refute_equal a.hash, other.hash
|
36
|
+
|
29
37
|
h = {}
|
30
38
|
h[a] = 'found'
|
31
39
|
assert_equal 'found', h[a]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Subnets
|
4
|
+
class TestIP6 < Minitest::Test
|
5
|
+
include EqlAndHash
|
6
|
+
|
7
|
+
# for EqlAndHash
|
8
|
+
def klass
|
9
|
+
IP6
|
10
|
+
end
|
11
|
+
|
12
|
+
# for EqlAndHash
|
13
|
+
def constructor_args
|
14
|
+
[[1,2,3,4,5,6,7,8]]
|
15
|
+
end
|
16
|
+
|
17
|
+
# for EqlAndHash
|
18
|
+
def other_constructor_args
|
19
|
+
[[5,5,5,5,5,5,5,5]]
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
data/test/subnets/net4_test.rb
CHANGED
data/test/subnets/net6_test.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'test_helper'
|
2
|
-
require 'ipaddr'
|
3
2
|
|
4
3
|
module Subnets
|
5
4
|
class TestNet6 < Minitest::Test
|
@@ -15,7 +14,12 @@ module Subnets
|
|
15
14
|
def constructor_args
|
16
15
|
[[1,2,3,4,5,6,7,8], 96]
|
17
16
|
end
|
18
|
-
|
17
|
+
|
18
|
+
# for EqlAndHash
|
19
|
+
def other_constructor_args
|
20
|
+
[[5,5,5,5,5,5,5,5], 122]
|
21
|
+
end
|
22
|
+
|
19
23
|
class New < Minitest::Test
|
20
24
|
def test_rejects_invalid_prefixlen
|
21
25
|
assert_raises(ArgumentError) { Net6.new([0,0,0,0,0,0,0,0], 129) }
|
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.0
|
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-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -172,6 +172,8 @@ files:
|
|
172
172
|
- test/private_networks_benchmark.rb
|
173
173
|
- test/rack_ip_benchmark.rb
|
174
174
|
- test/rails_remote_ip_benchmark.rb
|
175
|
+
- test/subnets/ip4_test.rb
|
176
|
+
- test/subnets/ip6_test.rb
|
175
177
|
- test/subnets/net4_test.rb
|
176
178
|
- test/subnets/net6_test.rb
|
177
179
|
- test/subnets_test.rb
|
@@ -193,9 +195,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
193
195
|
version: '0'
|
194
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
197
|
requirements:
|
196
|
-
- - "
|
198
|
+
- - ">="
|
197
199
|
- !ruby/object:Gem::Version
|
198
|
-
version:
|
200
|
+
version: '0'
|
199
201
|
requirements: []
|
200
202
|
rubyforge_project:
|
201
203
|
rubygems_version: 2.7.6
|