IPprefix 0.0.1

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.
Files changed (7) hide show
  1. data/Gemfile +1 -0
  2. data/IPprefix.gemspec +16 -0
  3. data/README +3 -0
  4. data/Rakefile +24 -0
  5. data/ext/IPprefix.c +559 -0
  6. data/ext/extconf.rb +5 -0
  7. metadata +75 -0
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ gemspec
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "IPprefix"
3
+ s.version = "0.0.1"
4
+ s.platform = Gem::Platform::RUBY
5
+ s.authors = ["Nathan Ward"]
6
+ s.email = ["nward@braintrust.co.nz"]
7
+ s.homepage = "http://github.com/nward/IPprefix"
8
+ s.summary = "Native, fast IP prefix handling code"
9
+ s.description = "Includes the IPprefix class, a fast class for handling IP prefixes."
10
+
11
+ s.required_rubygems_version = ">= 1.3.6"
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+
15
+ s.extensions = "ext/extconf.rb"
16
+ end
data/README ADDED
@@ -0,0 +1,3 @@
1
+ This gem is maintained by Nathan Ward <nward@braintrust.co.nz>.
2
+
3
+ The code was originally written by Nevil Brownlee <n.brownlee@auckland.ac.nz> of Auckland University, and was spun off from his ruby-libtrace project (http://www.cs.auckland.ac.nz/~nevil/ruby-libtrace/).
@@ -0,0 +1,24 @@
1
+ gemspec = eval(File.read(Dir["*.gemspec"].first))
2
+
3
+ desc "Validate the gemspec"
4
+ task :gemspec do
5
+ gemspec.validate
6
+ end
7
+
8
+ desc "Build gem locally"
9
+ task :build => :gemspec do
10
+ system "gem build #{gemspec.name}.gemspec"
11
+ FileUtils.mkdir_p "pkg"
12
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
13
+ end
14
+
15
+ desc "Install gem locally"
16
+ task :install => :build do
17
+ system "gem install pkg/#{gemspec.name}-#{gemspec.version}"
18
+ end
19
+
20
+ desc "Clean automatically generated files"
21
+ task :clean do
22
+ FileUtils.rm_rf "pkg"
23
+ end
24
+
@@ -0,0 +1,559 @@
1
+ /* 1531, Fri 29 Aug 08 (NZST)
2
+
3
+ IPprefix.c: IPprefix class, useful stuff for IP addresses and prefixes
4
+
5
+ Copyright (C) 2007-2009, Nevil Brownlee, U Auckland | CAIDA | WAND */
6
+
7
+ #include <stdint.h>
8
+ #include <arpa/inet.h>
9
+ #include <ctype.h>
10
+ #include "ruby.h"
11
+
12
+ #define IP4_ADDR_LEN 4
13
+ #define IP6_ADDR_LEN 16
14
+
15
+ #define IP4_LAST_BIT 31
16
+ #define IP6_LAST_BIT 127
17
+
18
+ static uint8_t b_mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
19
+ static uint8_t p_mask[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
20
+
21
+ VALUE ipPref; /* Global so we can use Check_Type( ,ipPref) */
22
+
23
+ /*
24
+ * Document-class: IPprefix
25
+ *
26
+ * IPprefix is a class encapsulating an IPv4 or IPv6 address with a prefix length.
27
+ */
28
+
29
+ /*
30
+ * Document-attr: addr
31
+ *
32
+ * Address as a 4 or 16 octet string
33
+ */
34
+
35
+ /*
36
+ * Document-attr: version
37
+ *
38
+ * IP version (4 or 6)
39
+ */
40
+
41
+ /*
42
+ * Document-attr: length
43
+ *
44
+ * Prefix length in bits
45
+ */
46
+
47
+ /*
48
+ * call-seq:
49
+ * initialize(version,addr) -> newPrefix
50
+ * initialize(version,addr,length) -> newPrefix
51
+ *
52
+ * Returns an IPprefix conatining an IP address, e.g. 192.168.0.3
53
+ * version = 4 for IPv4, 6 for IPv6
54
+ * addr = 4- or 16-byte string containing actual address
55
+ * length = Integer containing the prefix length (optional)
56
+ */
57
+ static VALUE pr_init(int argc, VALUE *argv, VALUE self) {
58
+ VALUE pa[3];
59
+ rb_scan_args(argc, argv, "12", &pa[0], &pa[1], &pa[2]);
60
+ if (argc < 1 || argc > 3) rb_raise(rb_eArgError,
61
+ "IPprefix.new called with < 1 or > 3 arguments!");
62
+
63
+ int version = NUM2INT(pa[0]);
64
+ if (version != 4 && version != 6) rb_raise(rb_eArgError,
65
+ "IPprefix.new: version must be 4 or 6!");
66
+ rb_iv_set(self, "@version", pa[0]);
67
+ int slen = version == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
68
+
69
+ if (argc == 1) { /* Create null prefix (root key for new ptrie) */
70
+ char null[IP6_ADDR_LEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
71
+ rb_iv_set(self, "@addr", rb_str_new(null, slen));
72
+ rb_iv_set(self, "@length", INT2FIX(0));
73
+ }
74
+ else {
75
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(pa[1]);
76
+ int alen = RSTRING_LEN(pa[1]);
77
+ if (version == 4 && alen > 4) rb_raise(rb_eArgError,
78
+ "IPprefix.new: string length >4 for an IPv4 address!");
79
+ else if (version == 6 && alen > 16) rb_raise(rb_eArgError,
80
+ "IPprefix.new: string length >a16for an IPv6 address!");
81
+ if (alen == slen) rb_iv_set(self, "@addr", pa[1]);
82
+ else {
83
+ char as[IP6_ADDR_LEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
84
+ memcpy(as, ap, alen);
85
+ rb_iv_set(self, "@addr", rb_str_new(as, slen));
86
+ }
87
+
88
+ if (argc == 3) rb_iv_set(self, "@length", pa[2]);
89
+ else rb_iv_set(self, "@length", Qnil);
90
+ }
91
+ return self;
92
+ }
93
+
94
+
95
+ /*
96
+ * Returns the IP version as a Fixnum.
97
+ */
98
+ static VALUE pr_version(VALUE self) {
99
+ return rb_iv_get(self, "@version");
100
+ }
101
+
102
+ /*
103
+ * Returns the address as a 4 or 16 byte string.
104
+ */
105
+ static VALUE pr_addr(VALUE self) {
106
+ return rb_iv_get(self, "@addr");
107
+ }
108
+
109
+ /*
110
+ * Returns the prefix length as a Fixnum, or nil if no length is set.
111
+ */
112
+ static VALUE pr_length(VALUE self) { /* ||k|| (may be nil) */
113
+ return rb_iv_get(self, "@length");
114
+ }
115
+
116
+ /*
117
+ * call-seq:
118
+ * length=(newLength) -> newLength
119
+ *
120
+ * Sets the prefix length.
121
+ */
122
+ static VALUE pr_set_length(VALUE self, VALUE length) {
123
+ int w = NUM2INT(length);
124
+ int ver = FIX2INT(rb_iv_get(self, "@version"));
125
+ if (w < 0) rb_raise(rb_eArgError,
126
+ "IPprefix.length= length must be >= 0!");
127
+ if (ver == 4 && w > IP4_ADDR_LEN*8) rb_raise(rb_eArgError,
128
+ "IPprefix.length= IPv4 length must be <= %d!", IP4_ADDR_LEN*8);
129
+ else if (ver == 6 && w > IP6_ADDR_LEN*8) rb_raise(rb_eArgError,
130
+ "IPprefix.length= IPv6 length must be <= %d!", IP6_ADDR_LEN*8);
131
+
132
+ rb_iv_set(self, "@length", length);
133
+ return length;
134
+ }
135
+
136
+ /*
137
+ * call-seq:
138
+ * ==(otherPrefix) -> (true,false)
139
+ *
140
+ * Tests to see if two IPprefix objects have the same version and addr. Does not test length.
141
+ */
142
+ static VALUE pr_addr_equal(VALUE self, VALUE sa) {
143
+ int vs = FIX2INT(rb_iv_get(self, "@version"));
144
+ if (vs != FIX2INT(rb_iv_get(sa, "@version"))) rb_raise(rb_eArgError,
145
+ "IPprefix.equal: Versions must be the same (4 or 6)");
146
+ int nb = vs == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
147
+ VALUE vsa = rb_iv_get(self, "@addr");
148
+ VALUE vaa = rb_iv_get(sa, "@addr");
149
+ uint8_t *sp = (uint8_t *)RSTRING_PTR(vsa);
150
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(vaa);
151
+ return memcmp(sp, ap, nb) == 0 ? Qtrue : Qfalse;
152
+ }
153
+
154
+ /*
155
+ * call-seq:
156
+ * <=>(otherPrefix) -> (-1,0,1)
157
+ *
158
+ * Compares self.addr otherprefix.addr and returns -1, 0 or 1. Useful for sorting prefixes.
159
+ */
160
+ static VALUE pr_addr_compare(VALUE self, VALUE sa) {
161
+ int vs = FIX2INT(rb_iv_get(self, "@version"));
162
+ if (vs != FIX2INT(rb_iv_get(sa, "@version"))) rb_raise(rb_eArgError,
163
+ "IPprefix.compare: Versions must be the same (4 or 6)");
164
+ int nb = vs == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
165
+ VALUE s_v = rb_iv_get(self, "@addr");
166
+ VALUE a_v = rb_iv_get(sa, "@addr");
167
+ uint8_t *sp = (uint8_t *)RSTRING_PTR(s_v);
168
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(a_v);
169
+ int r = memcmp(sp, ap, nb);
170
+ if (r != 0) return INT2FIX(r < 0 ? -1 : +1);
171
+ else return INT2FIX(0);
172
+ }
173
+
174
+ /*
175
+ * Returns length-1
176
+ */
177
+ static VALUE pr_width(VALUE self) { /* |k| = length-1 */
178
+ VALUE w = rb_iv_get(self, "@length");
179
+ if (w == Qnil) rb_raise(rb_eArgError,
180
+ "IPprefix.width: length nil, can't get width");
181
+ return INT2FIX(FIX2INT(w)-1);
182
+ }
183
+
184
+ /*
185
+ * call-seq:
186
+ * prefix?(otherPrefix) -> (true,false)
187
+ *
188
+ * Returns true if OtherIPprefix is a subnet of IPprefix, i.e. their first IPprefix.length bits are the same.
189
+ */
190
+ static VALUE pr_preceq(VALUE self, VALUE v_arg) { /* precedes or equals */
191
+ int vs = FIX2INT(rb_iv_get(self, "@version"));
192
+ if (vs != FIX2INT(rb_iv_get(v_arg, "@version"))) rb_raise(rb_eArgError,
193
+ "IPprefix.first_bit_different: Versions must be same version (4 or 6)");
194
+ int nb = vs == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
195
+ VALUE s_v = rb_iv_get(self, "@length");
196
+ VALUE a_v = rb_iv_get(v_arg, "@length");
197
+ if (s_v == Qnil || a_v == Qnil) rb_raise(rb_eArgError,
198
+ "IPprefix.first_bit_different: either or both lengthis nil");
199
+ int s_len = FIX2INT(s_v);
200
+ if (s_len > FIX2INT(a_v)) return Qfalse; /* Widths not <= */
201
+
202
+ uint8_t *sp = (uint8_t *)RSTRING_PTR(rb_iv_get(self, "@addr"));
203
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(rb_iv_get(v_arg, "@addr"));
204
+ int j, r;
205
+ uint8_t xor;
206
+ for (j = 0; j != nb; ++j)
207
+ if (ap[j] != sp[j]) break;
208
+ r = j*8;
209
+ if (r >= s_len) return Qtrue; /* They differ at or after min_len */
210
+ xor = ap[j] ^ sp[j];
211
+ while ((xor & 0x80) == 0) {
212
+ r += 1; xor <<= 1;
213
+ }
214
+ return r >= s_len ? Qtrue : Qfalse; /* first_bit_different > width */
215
+ }
216
+
217
+ /*
218
+ * call-seq:
219
+ * equals?(otherPrefix) -> (true,false)
220
+ *
221
+ * Returns true if self's addr, version, and length match otherPrefix.
222
+ */
223
+ static VALUE pr_equal(VALUE self, VALUE v_arg) {
224
+ int v = FIX2INT(rb_iv_get(self, "@version"));
225
+ if (v != FIX2INT(rb_iv_get(v_arg, "@version"))) rb_raise(rb_eArgError,
226
+ "IPprefix.equal: Versions must be same version (4 or 6)");
227
+ VALUE s_v = rb_iv_get(self, "@length");
228
+ VALUE a_v = rb_iv_get(v_arg, "@length");
229
+ if (s_v == Qnil || a_v == Qnil) rb_raise(rb_eArgError,
230
+ "IPprefix.equal: either or both length nil");
231
+ int s_len = FIX2INT(s_v);
232
+ if (s_len != FIX2INT(a_v)) return Qfalse;
233
+ int nb = v == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
234
+ uint8_t *sp = (uint8_t *)RSTRING_PTR(rb_iv_get(self, "@addr"));
235
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(rb_iv_get(v_arg, "@addr"));
236
+ int j;
237
+ for (j = 0; j != nb; ++j)
238
+ if (ap[j] != sp[j]) break;
239
+ if (j == nb) return Qtrue; /* All bits same */
240
+ return ((ap[j] ^ sp[j]) & p_mask[s_len%8]) == 0 ? Qtrue : Qfalse;
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * first_bit_different(otherPrefix) -> Integer
246
+ *
247
+ * Returns an Integer, the (0-origin) bit position where the two IPprefixes are different.
248
+ */
249
+ static VALUE pr_first_bit_differ(VALUE self, VALUE v_arg) {
250
+ int v = FIX2INT(rb_iv_get(self, "@version"));
251
+ if (v != FIX2INT(rb_iv_get(v_arg, "@version"))) rb_raise(rb_eArgError,
252
+ "IPprefix.first_bit_different: Versions must be same version (4 or 6)");
253
+ int nb = v == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
254
+ VALUE s_v = rb_iv_get(self, "@length");
255
+ VALUE a_v = rb_iv_get(v_arg, "@length");
256
+ if (s_v == Qnil || a_v == Qnil) rb_raise(rb_eArgError,
257
+ "IPprefix.first_bit_different: either or both length is nil");
258
+ int s_len = FIX2INT(s_v), a_len = FIX2INT(a_v);
259
+ uint8_t *sp = (uint8_t *)RSTRING_PTR(rb_iv_get(self, "@addr"));
260
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(rb_iv_get(v_arg, "@addr"));
261
+ int min_len = s_len < a_len ? s_len : a_len;
262
+ int j, r;
263
+ uint8_t xor;
264
+ for (j = 0; j != nb; ++j)
265
+ if (ap[j] != sp[j]) break;
266
+ if (j*8 >= min_len) /* They differ at or after min_len */
267
+ return INT2NUM(min_len);
268
+ xor = ap[j] ^ sp[j];
269
+ r = j*8;
270
+ while ((xor & 0x80) == 0) {
271
+ r += 1; xor <<= 1;
272
+ }
273
+ return INT2FIX(r >= min_len ? min_len : r);
274
+ }
275
+
276
+ /*
277
+ * call-seq:
278
+ * bit_set?(bit) -> (true,false)
279
+ *
280
+ * Returns true if a certain bit (specified as an Integer offset) is set.
281
+ */
282
+ static VALUE pr_bit_set(VALUE self, VALUE v_arg) {
283
+ VALUE v = FIX2INT(rb_iv_get(self, "@version"));
284
+ int last_bit = v == 4 ? IP4_LAST_BIT : IP6_LAST_BIT;
285
+ int n = NUM2INT(v_arg); /* 0-org */
286
+ if (n < 0) /* Special case: <root> node has bit_index -1 */
287
+ /* Always returns true, so <root> stays at top of the tree */
288
+ return Qtrue;
289
+ else if (n > last_bit) /* Past last byte of key (string), always false */
290
+ return Qfalse;
291
+ else {
292
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(rb_iv_get(self, "@addr"));
293
+ return(ap[n/8] & b_mask[n%8]) != 0 ? Qtrue : Qfalse;
294
+ }
295
+ }
296
+
297
+ /*
298
+ * Returns the complement of an IPprefix, i.e. one having the same length, but all bits the ones-complement of those in IPprefix.
299
+ */
300
+ static VALUE pr_complement(VALUE self) {
301
+ VALUE ver = rb_iv_get(self, "@version");
302
+ int nb = FIX2INT(ver) == 4 ? IP4_ADDR_LEN : IP6_ADDR_LEN;
303
+ uint8_t *sp = (uint8_t *)RSTRING_PTR(rb_iv_get(self, "@addr"));
304
+ VALUE len = rb_iv_get(self, "@length");
305
+ uint8_t a[IP6_ADDR_LEN]; int j;
306
+ for (j = 0; j != nb; ++j) a[j] = ~sp[j];
307
+ VALUE rk_argv[] = { ver, rb_str_new((char *)a, nb), len };
308
+ return rb_class_new_instance(3, rk_argv, ipPref);
309
+ }
310
+
311
+ static char *strmov(char *d, char *s) {
312
+ while (*s != '\0') *d++ = *s++;
313
+ return d;
314
+ }
315
+
316
+ static char v6a[60];
317
+ static char *v6addr_to_s(uint8_t *in6a)
318
+ { /* Returns pointer to next byte in v6a
319
+ Code from NeTraMet's nmc_pars.c */
320
+ char buf[10]; /* RFC 2373: IPv6 Address Architecture */
321
+ char *d = v6a;
322
+ char *a = (char *)in6a;
323
+ int j, k, st,len, stx,lenx;
324
+ uint32_t v, a2[8];
325
+
326
+ stx = st = len = lenx = 0;
327
+ for (k = j = 0; j != 16; j += 2) {
328
+ v = ntohs(*(uint16_t *)&a[j]);
329
+ a2[k++] = v; /* Build array of two-byte pairs */
330
+ if (v == 0) ++len;
331
+ else {
332
+ if (len > lenx) { /* Find longest run of zero pairs */
333
+ stx = st; lenx = len;
334
+ }
335
+ st = k; len = 0;
336
+ }
337
+ }
338
+
339
+ if (len > lenx) {
340
+ stx = st; lenx = len;
341
+ }
342
+ if (lenx != 0 && stx == 0) { /* Longest run at left */
343
+ d = strmov(d, ":"); j = lenx;
344
+ }
345
+ else {
346
+ sprintf(buf, "%x", a2[0]);
347
+ d = strmov(d,buf); j = 1;
348
+ }
349
+ for (; j < 8; ) {
350
+ if (lenx != 0 && j == stx) {
351
+ d = strmov(d,":"); j += lenx;
352
+ }
353
+ else {
354
+ sprintf(buf, ":%x", a2[j]);
355
+ d = strmov(d, buf); ++j;
356
+ }
357
+ }
358
+ if (j == stx+lenx) d = strmov(d, ":"); /* Longest run at right */
359
+ *d = '\0';
360
+ return d;
361
+ }
362
+
363
+ /*
364
+ * Returns a String with a human readable prefix and length in CIDR notation.
365
+ */
366
+ static VALUE pr_to_s(VALUE self) {
367
+ int ver = FIX2INT(rb_iv_get(self, "@version"));
368
+ VALUE addr = rb_iv_get(self, "@addr");
369
+ uint8_t *ap = (uint8_t *)RSTRING_PTR(addr);
370
+ VALUE length = rb_iv_get(self, "@length");
371
+ int w = length == Qnil ? -1 : FIX2INT(length);
372
+
373
+ if (ver == 4) {
374
+ if (w < 0) sprintf(v6a, "%u.%u.%u.%u",
375
+ ap[0],ap[1],ap[2],ap[3]);
376
+ else sprintf(v6a, "%u.%u.%u.%u/%u",
377
+ ap[0],ap[1],ap[2],ap[3], w);
378
+ }
379
+ else {
380
+ char *v6e = v6addr_to_s(ap);
381
+ if (w >= 0) sprintf(v6e, "/%u", w);
382
+ }
383
+ return rb_str_new2(v6a);
384
+ }
385
+
386
+ static uint16_t get_nbr(char **str, int *rem, int *base) {
387
+ char *s = *str;
388
+ int len = *rem, b = *base, j,k, c, n;
389
+
390
+ for (j = 0; j != len; ++j) {
391
+ c = s[j];
392
+ if (c == '.') {
393
+ if (!b) b = 10; break;
394
+ if (b == 16) rb_raise(rb_eArgError,
395
+ "IPprefix.from_s: can't have . in IPv6 address!");
396
+ }
397
+ if (c == ':') {
398
+ if (!b) b = 16; break;
399
+ if (b == 10) rb_raise(rb_eArgError,
400
+ "IPprefix.from_s: can't have : in IPv4 address!");
401
+ }
402
+ if (c == '/') break;
403
+ if (!isdigit(c) && isxdigit(c)) {
404
+ if (!b) { b = 16; }
405
+ }
406
+ if (b == 10 && !isdigit(c)) rb_raise(rb_eArgError,
407
+ "IPprefix.from_s: non-decimal digit in IPv4 address!");
408
+ else if (!isxdigit(c)) rb_raise(rb_eArgError,
409
+ "IPprefix.from_s: non-hex digit in IPv6 address!");
410
+ if (!isxdigit(c)) {
411
+ rb_raise(rb_eArgError,
412
+ "IPprefix.from_s: non-(hex) digit found!");
413
+ }
414
+ }
415
+
416
+ for (n = k = 0; k != j; ++k) {
417
+ c = s[k];
418
+ if (c >= '0' && c <= '9') n = n*b + (c-'0');
419
+ else if (c >= 'a' && c <= 'f') n = n*b + (10 + c-'a');
420
+ else n = n*b + (10 + c-'A');
421
+ }
422
+
423
+ *str = &s[j]; *rem = len-j; *base = b;
424
+ return n;
425
+ }
426
+
427
+ /*
428
+ * call-seq:
429
+ * from_s(string) -> IPprefix
430
+ *
431
+ * Parses str to find version and address, e.g.
432
+ * p = IPprefix::from_s('192.168.1.1')
433
+ * p = IPprefix.from_s('fe80::20d:60ff:fe38:18b/64')
434
+ */
435
+ static VALUE pr_from_s(VALUE self, VALUE v_str) {
436
+ VALUE pa[3] = { Qnil, Qnil, Qnil };
437
+ char *str = RSTRING_PTR(v_str), *sp;
438
+ int len = RSTRING_LEN(v_str);
439
+ int base, n, x, dcx, havedcx, y, argc;
440
+ char a[16], *a2p; uint16_t a2[8];
441
+
442
+ memset(a, 0, sizeof(a));
443
+ sp = str;
444
+ havedcx = dcx = 0;
445
+ if (sp[0] == ':') {
446
+ if (sp[1] == ':') {
447
+ base = 16; havedcx = 1; dcx = -1;
448
+ sp += 2; len -= 2;
449
+ }
450
+ else rb_raise(rb_eArgError,
451
+ "IPprefix.from_s: can't start an IPv6 address with : !");
452
+ }
453
+ else {
454
+ base = 0; havedcx = 0;
455
+ }
456
+
457
+ n = get_nbr(&sp, &len, &base);
458
+
459
+ if (base == 10) { /* IPv4 prefix */
460
+ for (x = 0; x != 4; ++x) {
461
+ if (n > 255) rb_raise(rb_eArgError,
462
+ "IPprefix.from_s: integer > 255 in IPv4 address!");
463
+ a[x] = n;
464
+ if (len == 0) break;
465
+ sp += 1; len -= 1;
466
+ n = get_nbr(&sp, &len, &base);
467
+ if (len == 0 || *sp == '/') {
468
+ a[x+1] = n; break;
469
+ }
470
+ }
471
+ pa[0] = INT2FIX(4);
472
+ pa[1] = rb_str_new(a, 4);
473
+ if (len == 0) argc = 2;
474
+ else if (*sp == '/') {
475
+ argc = 3;
476
+ sp += 1; len -= 1;
477
+ n = get_nbr(&sp, &len, &base);
478
+ if (n > 32) rb_raise(rb_eArgError,
479
+ "IPprefix.from_s: IPv4 prefix length > 32!");
480
+ pa[2] = INT2FIX(n);
481
+ }
482
+ else rb_raise(rb_eArgError,
483
+ "IPprefix.from_s: more than 4 integers in IPv4 address!");
484
+ }
485
+ else if (base == 16) { /* IPv6 prefix */
486
+ memset(a2, 0, sizeof(a2));
487
+ for (x = 0; x != 8; ++x) {
488
+ if (n > 0xFFFF) rb_raise(rb_eArgError,
489
+ "IPprefix.from_s: integer > 0xFFFF in IPv6 address!");
490
+ a2[x] = ntohs((uint16_t)n); /* Nathan, 13 Aug 09 */
491
+ if (len == 0 || *sp == '/') {
492
+ /* x += 1; a2[x] = ntohs((uint16_t)n); Nathan, 13 Aug 09 */
493
+ break;
494
+ }
495
+ sp += 1; len -= 1; /* Skip the delimiter */
496
+ n = get_nbr(&sp, &len, &base);
497
+ if (sp[1] == ':') {
498
+ if (havedcx) rb_raise(rb_eArgError,
499
+ "IPprefix.from_s: can only have one :: in an IPv6 address!");
500
+ dcx = x+1; havedcx = 1;
501
+ sp += 1; len -= 1;
502
+ }
503
+ }
504
+ a2p = (char *)a2;
505
+ if (!havedcx) memcpy(a, a2p, 16);
506
+ else {
507
+ if (dcx >= 0) memcpy(a, a2p, (dcx+1)*2);
508
+ y = (x-dcx)*2;
509
+ memcpy(a + (16-y), a2p + (dcx+1)*2, y);
510
+ }
511
+ pa[0] = INT2FIX(6);
512
+ pa[1] = rb_str_new(a, 16);
513
+ if (len == 0) argc = 2;
514
+ else if (*sp == '/') {
515
+ argc = 3;
516
+ sp += 1; len -= 1; base = 10;
517
+ n = get_nbr(&sp, &len, &base);
518
+ if (n > 128) rb_raise(rb_eArgError,
519
+ "IPprefix.from_s: IPv6 prefix length > 128!");
520
+ pa[2] = INT2FIX(n);
521
+ }
522
+ else rb_raise(rb_eArgError,
523
+ "IPprefix.from_s: more than 8 hex numbers in IPv6 address!");
524
+ }
525
+ else rb_raise(rb_eArgError,
526
+ "IPprefix.from_s: can't tell whether address is IPv4 or IPv6!");
527
+
528
+ VALUE vp = rb_class_new_instance(argc, pa, ipPref);
529
+ return vp;
530
+ }
531
+
532
+ void Init_IPprefix() {
533
+ ipPref = rb_define_class("IPprefix", rb_cObject);
534
+ /* from_s is a class function */
535
+ rb_define_module_function(ipPref, "from_s", pr_from_s, 1);
536
+
537
+ rb_define_method(ipPref, "initialize", pr_init, -1);
538
+ rb_define_method(ipPref, "version", pr_version, 0);
539
+ rb_define_method(ipPref, "addr", pr_addr, 0);
540
+ rb_define_method(ipPref, "length", pr_length, 0); /* ||k|| */
541
+ rb_define_method(ipPref, "length=", pr_set_length, 1);
542
+ rb_define_method(ipPref, "==", pr_addr_equal, 1); /* Only compare addrs */
543
+ rb_define_method(ipPref, "<=>", pr_addr_compare, 1);
544
+ rb_define_method(ipPref, "to_s", pr_to_s, 0);
545
+
546
+ /* Following methods check that length is non-nil (for IP prefix testing) */
547
+ rb_define_method(ipPref, "width", pr_width, 0); /* |k| = length-1 */
548
+ rb_define_method(ipPref, "prefix?", pr_preceq, 1);
549
+ rb_define_method(ipPref, "equal", pr_equal, 1);
550
+ rb_define_method(ipPref, "bit_set?", pr_bit_set, 1);
551
+ rb_define_method(ipPref, "first_bit_different", pr_first_bit_differ, 1);
552
+ rb_define_method(ipPref, "complement", pr_complement, 0);
553
+
554
+ /* Define the attributes */
555
+ rb_define_attr(ipPref, "addr", 1,0);
556
+ rb_define_attr(ipPref, "version", 1,0);
557
+ rb_define_attr(ipPref, "length", 1,1);
558
+
559
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+
5
+ create_makefile("IPprefix")
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: IPprefix
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Nathan Ward
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-12 00:00:00 +13:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Includes the IPprefix class, a fast class for handling IP prefixes.
23
+ email:
24
+ - nward@braintrust.co.nz
25
+ executables: []
26
+
27
+ extensions:
28
+ - ext/extconf.rb
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - Gemfile
33
+ - IPprefix.gemspec
34
+ - README
35
+ - Rakefile
36
+ - ext/IPprefix.c
37
+ - ext/extconf.rb
38
+ has_rdoc: true
39
+ homepage: http://github.com/nward/IPprefix
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ hash: 3
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 23
62
+ segments:
63
+ - 1
64
+ - 3
65
+ - 6
66
+ version: 1.3.6
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.7
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Native, fast IP prefix handling code
74
+ test_files: []
75
+