subnets 1.0.0pre

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.
@@ -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__ */