IPprefix 0.0.1

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