subnets 1.0.0pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ have_header('ctype.h')
4
+ have_header('stdint.h')
5
+
6
+ create_makefile('subnets')
@@ -0,0 +1,402 @@
1
+ #include <ctype.h> /* isdigit, isxdigit */
2
+ #include <stdarg.h>
3
+ #include <stddef.h>
4
+ #include <stdint.h>
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+
9
+ #include <unistd.h>
10
+
11
+ #include "ipaddr.h"
12
+
13
+ ip4_t
14
+ mk_mask4(int prefixlen) {
15
+ if (prefixlen==0) return 0;
16
+
17
+ int shift = 32 - prefixlen;
18
+ return (~((ip4_t) 0) >> shift) << shift;
19
+ }
20
+
21
+ ip6_t
22
+ mk_mask6(int prefixlen) {
23
+ ip6_t mask;
24
+ uint16_t ones = ~((uint16_t) 0);
25
+
26
+ int pivot = prefixlen / 16;
27
+ int shift = 16 - (prefixlen % 16);
28
+
29
+ for (int i=0; i<pivot && i<8; i++) {
30
+ mask.x[i] = ones;
31
+ }
32
+ if (pivot<8) {
33
+ mask.x[pivot] = (ones >> shift) << shift;
34
+ }
35
+ for (int i = pivot+1; i<8; i++) {
36
+ mask.x[i] = 0;
37
+ }
38
+
39
+ return mask;
40
+ }
41
+
42
+ int
43
+ net4_include_p(net4_t net, ip4_t a) {
44
+ return ((net.address & net.mask) == (a & net.mask));
45
+ }
46
+
47
+ int
48
+ net6_include_p(net6_t net, ip6_t a) {
49
+ for (int i=0; i<8; i++) {
50
+ if ((net.address.x[i] & net.mask.x[i]) != (a.x[i] & net.mask.x[i])) return 0;
51
+ }
52
+ return !0;
53
+ }
54
+
55
+ int
56
+ net4_include_net4_p(net4_t net, net4_t other) {
57
+ return net.prefixlen <= other.prefixlen && net4_include_p(net, other.address);
58
+ }
59
+
60
+ int
61
+ net6_include_net6_p(net6_t net, net6_t other) {
62
+ return net.prefixlen <= other.prefixlen && net6_include_p(net, other.address);
63
+ }
64
+
65
+ net4_t
66
+ net4_network(net4_t net) {
67
+ net.address = net.address & net.mask;
68
+ return net;
69
+ }
70
+
71
+ int
72
+ ip4_snprint(ip4_t ip, char *str, size_t size) {
73
+ return snprintf(str, size, "%u.%u.%u.%u",
74
+ (ip >> 24) & 0xff,
75
+ (ip >> 16) & 0xff,
76
+ (ip >> 8) & 0xff,
77
+ (ip >> 0) & 0xff);
78
+ }
79
+
80
+ int
81
+ net4_snprint(net4_t net, char *str, size_t size) {
82
+ return snprintf(str, size, "%u.%u.%u.%u/%d",
83
+ (net.address >> 24) & 0xff,
84
+ (net.address >> 16) & 0xff,
85
+ (net.address >> 8) & 0xff,
86
+ (net.address >> 0) & 0xff,
87
+ net.prefixlen);
88
+ }
89
+
90
+ int
91
+ ip6_snprint(ip6_t ip, char *str, size_t size) {
92
+ /* find first longest string of zeroes */
93
+ int longzerostart = -1;
94
+ int longzeroend = -1;
95
+
96
+ int currzerostart = -1;
97
+ int currzeroend = -1;
98
+
99
+ for (int i = 0; i < 8; i++) {
100
+ if (0 == ip.x[i]) {
101
+ currzeroend = i+1;
102
+ if (currzerostart < 0) {
103
+ currzerostart = i;
104
+ }
105
+ if ((currzeroend - currzerostart) > (longzeroend - longzerostart)) {
106
+ longzerostart = currzerostart;
107
+ longzeroend = currzeroend;
108
+ }
109
+ } else {
110
+ if (currzerostart >= 0) {
111
+ currzerostart = -1;
112
+ }
113
+ }
114
+ }
115
+
116
+ if (longzeroend - longzerostart <= 1) {
117
+ return snprintf(str, size, "%x:%x:%x:%x:%x:%x:%x:%x",
118
+ ip.x[0],
119
+ ip.x[1],
120
+ ip.x[2],
121
+ ip.x[3],
122
+ ip.x[4],
123
+ ip.x[5],
124
+ ip.x[6],
125
+ ip.x[7]);
126
+ } else {
127
+ int total = 0;
128
+ int n;
129
+
130
+ /* print first before zeros */
131
+ for (int i = 0; i < 1 && i < longzerostart; i++) {
132
+ n = snprintf(str+total, size-total, "%x", ip.x[i]);
133
+ if (n < 0) { return n; }
134
+ total += n;
135
+ }
136
+
137
+ /* print rest before zeros with leading colon */
138
+ for (int i = 1; i < longzerostart; i++) {
139
+ n = snprintf(str+total, size-total, ":");
140
+ if (n < 0) { return n; }
141
+ total += n;
142
+ n = snprintf(str+total, size-total, "%x", ip.x[i]);
143
+ if (n < 0) { return n; }
144
+ total += n;
145
+ }
146
+
147
+ /* print double colon */
148
+ n = snprintf(str+total, size-total, "::");
149
+ if (n < 0) { return n; }
150
+ total += n;
151
+
152
+ /* print first after zeros */
153
+ for (int i = longzeroend; i < 8 && i < longzeroend+1; i++) {
154
+ n = snprintf(str+total, size-total, "%x", ip.x[i]);
155
+ if (n < 0) { return n; }
156
+ total += n;
157
+ }
158
+
159
+ /* print rest after zeros with leading colon */
160
+ for (int i = longzeroend + 1; i < 8; i++) {
161
+ n = snprintf(str+total, size-total, ":");
162
+ if (n < 0) { return n; }
163
+ total += n;
164
+
165
+ n = snprintf(str+total, size-total, "%x", ip.x[i]);
166
+ if (n < 0) { return n; }
167
+ total += n;
168
+ }
169
+
170
+ return total;
171
+ }
172
+ }
173
+
174
+ int
175
+ net6_snprint(net6_t net, char *str, size_t size) {
176
+ int n0, n1;
177
+ n0 = ip6_snprint(net.address, str, size);
178
+ if (n0 < 0) {
179
+ return n0;
180
+ }
181
+
182
+ n1 = snprintf(str+n0, size-n0, "/%d", net.prefixlen);
183
+ if (n1 < 0) {
184
+ return n1;
185
+ }
186
+
187
+ return n0 + n1;
188
+ }
189
+
190
+ int
191
+ hexvalue(unsigned int c) {
192
+ if (c-'0'<10) return c-'0';
193
+ if (c-'a'<6) return c-'a'+10;
194
+ if (c-'A'<6) return c-'A'+10;
195
+ return -1;
196
+ }
197
+
198
+ /*
199
+ * read_ip4 is adapted from musl-libc inet_pton
200
+ * https://git.musl-libc.org/cgit/musl/tree/src/network/inet_pton.c?id=fc13acc3dcb5b1f215c007f583a63551f6a71363
201
+ *
202
+ * Copyright © 2005-2014 Rich Felker, et al.
203
+ *
204
+ * Permission is hereby granted, free of charge, to any person
205
+ * obtaining a copy of this software and associated documentation
206
+ * files (the "Software"), to deal in the Software without
207
+ * restriction, including without limitation the rights to use, copy,
208
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
209
+ * of the Software, and to permit persons to whom the Software is
210
+ * furnished to do so, subject to the following conditions:
211
+ *
212
+ * The above copyright notice and this permission notice shall be
213
+ * included in all copies or substantial portions of the Software.
214
+ *
215
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
216
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
217
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
218
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
219
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
220
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
222
+ * DEALINGS IN THE SOFTWARE.
223
+ *
224
+ */
225
+ /**
226
+ * Read an Ip4 address from s.
227
+ *
228
+ * @return the number of characters consumed
229
+ */
230
+ size_t
231
+ read_ip4(const char *s, ip4_t *a) {
232
+ size_t pos = 0;
233
+
234
+ *a = 0;
235
+
236
+ for (int i = 0; i < 4; i++) {
237
+ int v, j;
238
+ for (v=j=0; j < 3 && isdigit(s[pos+j]); j++) {
239
+ v = 10*v + s[pos+j]-'0';
240
+ }
241
+ if (j==0 || (j>1 && s[pos]=='0') || v>255) return 0;
242
+ *a |= (v & 0xff) << (3-i)*8;
243
+ pos += j;
244
+ if (i == 3) return pos;
245
+ if (s[pos++] != '.') return 0;
246
+ }
247
+
248
+ return 0;
249
+ }
250
+
251
+ size_t
252
+ read_hextet(const char *s, uint16_t *v) {
253
+ int i;
254
+ for (i=0; i<4 && isxdigit(s[i]); i++) {
255
+ *v = 0x10*(*v) + hexvalue(s[i]);
256
+ }
257
+ if (i>1 && s[0]=='0') return 0;
258
+ return i;
259
+ }
260
+
261
+ size_t
262
+ read_ip6(const char *s, ip6_t *a) {
263
+ uint16_t hextets[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
264
+ size_t n;
265
+ int i = 0;
266
+ size_t pos = 0;
267
+ int brk = 8;
268
+
269
+ /*
270
+ * read optional leading hextet followed by zero or more
271
+ * colon-hextet pairs, zero or one lone colon (the second of a
272
+ * double-colon), zero or more colon-hextet pairs.
273
+ */
274
+
275
+ n = read_hextet(s+pos, &hextets[i]);
276
+ if (n) {
277
+ //printf("read hextet %d: %x\n", i, hextets[i]);
278
+ pos+=n;
279
+ i++;
280
+ }
281
+
282
+ for (; i < 8;) {
283
+ if (s[pos] != ':') break;
284
+ pos++;
285
+
286
+ if (brk==8 && s[pos] == ':') {
287
+ //printf("see break at pos=%d, brk=%d\n", pos, i);
288
+ pos++;
289
+ brk = i;
290
+ if (!isxdigit(s[pos])) break;
291
+ }
292
+ else if (i==0) { /* can't lead with single-colon */
293
+ return 0;
294
+ }
295
+
296
+ ip4_t ip4;
297
+ if ((i==6 || (brk<8 && i<4)) && (n = read_ip4(s+pos, &ip4))) {
298
+ pos += n;
299
+ hextets[i] = (ip4 >> 16) & 0xffff;
300
+ hextets[i+1] = (ip4 >> 0) & 0xffff;
301
+ i+=2;
302
+ break;
303
+ }
304
+
305
+ n = read_hextet(s+pos, &hextets[i]);
306
+ if (n) {
307
+ //printf("read hextet %d: %x\n", i, hextets[i]);
308
+ pos+=n;
309
+ i++;
310
+ }
311
+ else {
312
+ //printf("error 'cause read %c\n", s[pos]);
313
+ return 0;
314
+ }
315
+ }
316
+
317
+ if (brk==8 && i<8) return 0;
318
+ if (brk<8 && i==8) return 0;
319
+
320
+ for (int k = 0; k < 8; k++) {
321
+ //printf("brk=%d i=%d hextets[%d]=%x\n", brk, i, k, hextets[k]);
322
+ }
323
+
324
+ /* TODO move down hextets after the break */
325
+ //printf("before\n");
326
+ for (int j = 0; j < brk; j++) {
327
+ a->x[j] = hextets[j];
328
+ }
329
+ //printf("brk\n");
330
+ for (int j = 0; j < (8-i); j++) {
331
+ a->x[j+brk] = 0;
332
+ }
333
+ //printf("after\n");
334
+ for (int j = 0; j < (i-brk); j++) {
335
+ //printf(" (from hextets[%d])\n", j+brk);
336
+ a->x[j+(8-i)+brk] = hextets[j+brk];
337
+ }
338
+
339
+ return pos;
340
+ }
341
+
342
+ size_t
343
+ read_net4(const char *s, net4_t *net) {
344
+ int i, v=0;
345
+ size_t pos = read_ip4(s, &net->address);
346
+ if (!pos) return 0;
347
+
348
+ if (!(s[pos++] == '/')) return 0;
349
+ for (i = 0; i < 2 && isdigit(s[pos+i]); i++) {
350
+ v = v*10 + s[pos+i]-'0';
351
+ }
352
+ if (i==0 || (i>1 && s[pos]=='0') || v>32) return 0;
353
+ net->prefixlen = v;
354
+ net->mask = mk_mask4(net->prefixlen);
355
+ return pos+i;
356
+ }
357
+
358
+ size_t
359
+ read_ip4_strict(const char *s, ip4_t *ip) {
360
+ size_t n = read_ip4(s, ip);
361
+ if (!n || s[n] != 0) return 0;
362
+ return n;
363
+ }
364
+
365
+ size_t
366
+ read_net4_strict(const char *s, net4_t *net) {
367
+ size_t n = read_net4(s, net);
368
+ if (!n || s[n] != 0) return 0;
369
+ return n;
370
+ }
371
+
372
+ size_t
373
+ read_ip6_strict(const char *s, ip6_t *ip) {
374
+ size_t n = read_ip6(s, ip);
375
+ if (!n || s[n] != 0) return 0;
376
+ return n;
377
+ }
378
+
379
+ size_t
380
+ read_net6_strict(const char *s, net6_t *net) {
381
+ size_t n = read_net6(s, net);
382
+ if (!n || s[n] != 0) return 0;
383
+ return n;
384
+ }
385
+
386
+ size_t
387
+ read_net6(const char *s, net6_t *net) {
388
+ size_t pos;
389
+
390
+ pos = read_ip6(s, &net->address);
391
+ if (!pos) return 0;
392
+
393
+ int i, v = 0;
394
+ if (s[pos++] != '/') return 0;
395
+ for (i = 0; i < 3 && isdigit(s[pos+i]); i++) {
396
+ v = v*10 + s[pos+i]-'0';
397
+ }
398
+ if (i==0 || (i>1 && s[pos]=='0') || v>128) return 0;
399
+ net->prefixlen = v;
400
+ net->mask = mk_mask6(net->prefixlen);
401
+ return pos+i;
402
+ }
@@ -0,0 +1,105 @@
1
+ #ifndef __IPADDR_H__
2
+ #define __IPADDR_H__
3
+
4
+ #include <ctype.h> /* isdigit, isxdigit */
5
+ #include <stdarg.h>
6
+ #include <stddef.h>
7
+ #include <stdint.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ #include <unistd.h>
13
+
14
+ typedef uint32_t ip4_t;
15
+
16
+ typedef struct {
17
+ int prefixlen;
18
+ ip4_t address;
19
+ ip4_t mask;
20
+ } net4_t;
21
+
22
+ typedef struct {
23
+ uint16_t x[8];
24
+ } ip6_t;
25
+
26
+ typedef struct {
27
+ int prefixlen;
28
+ ip6_t address;
29
+ ip6_t mask;
30
+ } net6_t;
31
+
32
+ /**
33
+ * Make an IPv4 mask of the given prefixlen in the range [0,32].
34
+ */
35
+ ip4_t mk_mask4(int prefixlen);
36
+
37
+ /**
38
+ * Make an IPv6 mask of the given prefixlen in the range [0,128].
39
+ */
40
+ ip6_t mk_mask6(int prefixlen);
41
+
42
+ /**
43
+ * Test if this network includes the given ip.
44
+ */
45
+ int net4_include_p(net4_t, ip4_t);
46
+ int net6_include_p(net6_t, ip6_t);
47
+
48
+ /**
49
+ * Test if this network includes the given network, which must have a
50
+ * prefexlen greater than or equal to that of this network and a
51
+ * network address that is included within this network.
52
+ */
53
+ int net4_include_net4_p(net4_t, net4_t);
54
+ int net6_include_net6_p(net6_t, net6_t);
55
+
56
+ /**
57
+ * Zero-out the host portion of this network by applying the netmask,
58
+ * and return that network.
59
+ */
60
+ net4_t net4_network(net4_t);
61
+ net6_t net6_network(net6_t);
62
+
63
+ /**
64
+ * Write a string representation of this network to the given string,
65
+ * according to the rules of snprintf().
66
+ */
67
+ int net4_snprint(net4_t, char *, size_t);
68
+ int net6_snprint(net6_t, char *, size_t);
69
+
70
+ /**
71
+ * Write a string representation of this ip to the given string,
72
+ * according to the rules of snprintf().
73
+ */
74
+ int ip4_snprint(ip4_t, char *, size_t);
75
+ int ip6_snprint(ip6_t, char *, size_t);
76
+
77
+ /**
78
+ * Read an IP from the string, returning the number of bytes read, or
79
+ * zero on parse error.
80
+ */
81
+ size_t read_ip4(const char *, ip4_t *);
82
+ size_t read_ip6(const char *, ip6_t *);
83
+
84
+ /**
85
+ * Read a network from the string, returning the number of bytes read,
86
+ * or zero on parse error.
87
+ */
88
+ size_t read_net4(const char *, net4_t *);
89
+ size_t read_net6(const char *, net6_t *);
90
+
91
+ /**
92
+ * Like read_ip*, but it is an error if the IP is not followed by a
93
+ * null byte.
94
+ */
95
+ size_t read_ip4_strict(const char *, ip4_t *);
96
+ size_t read_ip6_strict(const char *, ip6_t *);
97
+
98
+ /**
99
+ * Like read_net*, but it is an error if the network is not followed
100
+ * by a null byte.
101
+ */
102
+ size_t read_net4_strict(const char *, net4_t *);
103
+ size_t read_net6_strict(const char *, net6_t *);
104
+
105
+ #endif /* __IPADDR_H__ */