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