1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * @f inet
11 * @a Fabian Groffen
12 * @v 1.0
13 * @* The inet module
14 * The inet module contains a collection of functions that operate on IPv4
15 * addresses. The most relevant functions are the `containment' functions
16 * that deal with subnet masks. The functionality of this module is
17 * greatly inspired by the PostgreSQL inet atom.
18 *
19 */
20#include "monetdb_config.h"
21#include "gdk.h"
22#include "mal.h"
23#include "mal_exception.h"
24
25/*
26 * @* Implementation Code
27 * The first 4 bytes of the used lng are in use by the four quads of the
28 * IPv4 address, stored in network order. In the four bytes left,
29 * additional information is stored.
30 * Currently the fifth byte holds the number of bits from the IPv4 address
31 * that should match (ie. /8, /16, /24, /32) also known as subnet mask.
32 * The last byte holds whether inet atom represents the value nil or not.
33 * The value nil is represented as (per byte) 0000 0001.
34 *
35 */
36typedef struct _inet {
37 /* use a union to force alignment compatible with lng */
38 union {
39 struct {
40 unsigned char _q1;
41 unsigned char _q2;
42 unsigned char _q3;
43 unsigned char _q4;
44 unsigned char _mask;
45 unsigned char _filler1;
46 unsigned char _filler2;
47 unsigned char _isnil;
48 } s;
49 lng alignment;
50 } u;
51} inet;
52#define q1 u.s._q1
53#define q2 u.s._q2
54#define q3 u.s._q3
55#define q4 u.s._q4
56#define mask u.s._mask
57#define filler1 u.s._filler1
58#define filler2 u.s._filler2
59#define isnil u.s._isnil
60
61#ifdef WORDS_BIGENDIAN
62/* HACK ALERT: once upon a time, lng_nil was used as inet_nil, but on
63 * big endian hardware, the byte that is not zero is on the other end;
64 * luckily, a mask of 0 is pretty useless, so we regard 128.0.0.0/0
65 * also as nil */
66#define is_inet_nil(i) ((((i)->q1 == 0 && (i)->isnil != 0) || ((i)->q1 == 128 && (i)->isnil == 0 && (i)->filler1 == 0 && (i)->filler2 == 0)) && (i)->q2 == 0 && (i)->q3 == 0 && (i)->q4 == 0 && (i)->mask == 0)
67#else
68#define is_inet_nil(i) ((i)->q1 == 0 && (i)->q2 == 0 && (i)->q3 == 0 && (i)->q4 == 0 && (i)->mask == 0 && (i)->isnil != 0)
69#endif
70#define in_setnil(i) (i)->q1 = (i)->q2 = (i)->q3 = (i)->q4 = (i)->mask = (i)->filler1 = (i)->filler2 = 0; (i)->isnil = 1
71
72mal_export ssize_t INETfromString(const char *src, size_t *len, inet **retval, bool external);
73mal_export ssize_t INETtoString(str *retval, size_t *len, const inet *handle, bool external);
74mal_export int INETcompare(const inet *l, const inet *r);
75mal_export str INETnew(inet *retval, str *in);
76mal_export str INET_isnil(bit *retval, const inet *val);
77mal_export str INET_comp_EQ(bit *retval, const inet *val1, const inet *val2);
78mal_export str INET_comp_NEQ(bit *retval, const inet *val1, const inet *val2);
79mal_export str INET_comp_LT(bit *retval, const inet *val1, const inet *val2);
80mal_export str INET_comp_GT(bit *retval, const inet *val1, const inet *val2);
81mal_export str INET_comp_LE(bit *retval, const inet *val1, const inet *val2);
82mal_export str INET_comp_GE(bit *retval, const inet *val1, const inet *val2);
83mal_export str INET_comp_CW(bit *retval, const inet *val1, const inet *val2);
84mal_export str INET_comp_CWE(bit *retval, const inet *val1, const inet *val2);
85mal_export str INET_comp_CS(bit *retval, const inet *val1, const inet *val2);
86mal_export str INET_comp_CSE(bit *retval, const inet *val1, const inet *val2);
87mal_export str INETbroadcast(inet *retval, const inet *val);
88mal_export str INEThost(str *retval, const inet *val);
89mal_export str INETmasklen(int *retval, const inet *val);
90mal_export str INETsetmasklen(inet *retval, const inet *val, const int *msk);
91mal_export str INETnetmask(inet *retval, const inet *val);
92mal_export str INEThostmask(inet *retval, const inet *val);
93mal_export str INETnetwork(inet *retval, const inet *val);
94mal_export str INETtext(str *retval, const inet *val);
95mal_export str INETabbrev(str *retval, const inet *val);
96mal_export str INET_inet(inet *d, const inet *s);
97mal_export str INET_fromstr(inet *ret, str *s);
98mal_export const inet *INETnull(void);
99
100static inet inet_nil = {{{0,0,0,0,0,0,0,1}}};
101
102/**
103 * Creates a new inet from the given string.
104 * Warning: GDK function, does NOT pass a string by reference, and wants
105 * a pointer to a pointer for the retval!
106 * Returns the number of chars read
107 */
108ssize_t
109INETfromString(const char *src, size_t *len, inet **retval, bool external)
110{
111 int i, last, type;
112 long parse; /* type long returned by strtol() */
113 char *endptr;
114 char sep = '.';
115
116 last = 0;
117 type = 0;
118
119 if (*len < sizeof(inet) || *retval == NULL) {
120 GDKfree(*retval);
121 *retval = GDKzalloc(sizeof(inet));
122 if( *retval == NULL){
123 *len = 0;
124 return -1;
125 }
126 *len = sizeof(inet);
127 } else {
128 **retval = (inet) {.q1 = 0,};
129 }
130
131 /* handle the nil string */
132 if (external && strcmp(src, "nil") == 0) {
133 in_setnil(*retval);
134 return 3;
135 }
136 if (GDK_STRNIL(src)) {
137 in_setnil(*retval);
138 return 1;
139 }
140
141 /* use the DIY technique to guarantee maximum cross-platform
142 * portability */
143 for (i = 0; src[i] != '\0'; i++) {
144 if (src[i] == '.' || src[i] == '/') {
145 sep = src[i];
146 parse = strtol(src + last, &endptr, 10);
147 if (*endptr != sep || last >= i) {
148 GDKerror("Error while parsing, unexpected string '%s'", endptr);
149 goto error;
150 }
151 if (parse > 255 || parse < 0) {
152 GDKerror("Illegal quad value: %ld", parse);
153 goto error;
154 }
155 switch (type) {
156 case 0:
157 (*retval)->q1 = (unsigned char) parse;
158 break;
159 case 1:
160 (*retval)->q2 = (unsigned char) parse;
161 break;
162 case 2:
163 (*retval)->q3 = (unsigned char) parse;
164 break;
165 case 3:
166 (*retval)->q4 = (unsigned char) parse;
167 break;
168 }
169
170 last = i + 1;
171 type++;
172
173 if (sep == '/') {
174 /* zero out (default) unused bytes */
175 switch (type) {
176 case 1:
177 (*retval)->q2 = (unsigned char) 0;
178 /* fall through */
179 case 2:
180 (*retval)->q3 = (unsigned char) 0;
181 /* fall through */
182 case 3:
183 (*retval)->q4 = (unsigned char) 0;
184 break;
185 }
186 /* force evaluation of the mask below when we break
187 * out of this loop */
188 type = 4;
189 break;
190 }
191 }
192 }
193 /* parse the last quad
194 * the contract is that the caller makes sure the string is
195 * null-terminated here */
196 parse = strtol(src + last, &endptr, 10);
197 if (*endptr != '\0' || (sep != '/' && last >= i)) {
198 GDKerror("Error while parsing, unexpected string '%s'", endptr);
199 goto error;
200 }
201 if (type == 3) {
202 if (parse > 255 || parse < 0) {
203 GDKerror("Illegal quad value: %ld", parse);
204 goto error;
205 }
206 (*retval)->q4 = (unsigned char) parse;
207 /* default to an exact match (all bits) */
208 (*retval)->mask = (unsigned char) 32;
209 } else if (type == 4) {
210 if (parse < 0 || parse > 32) {
211 GDKerror("Illegal mask value: %ld", parse);
212 goto error;
213 }
214 (*retval)->mask = (unsigned char) parse;
215 } else {
216 GDKerror("Error while parsing, unexpected string '%s'", endptr);
217 goto error;
218 }
219
220 return (ssize_t) (endptr - src);
221
222 error:
223 in_setnil(*retval);
224 return -1;
225}
226/**
227 * Returns the string representation of the given inet value.
228 * Warning: GDK function
229 * Returns the length of the string
230 */
231ssize_t
232INETtoString(str *retval, size_t *len, const inet *handle, bool external)
233{
234 const inet *value = (const inet *)handle;
235
236 if (*len < 20 || *retval == NULL) {
237 GDKfree(*retval);
238 *retval = GDKmalloc(sizeof(char) * (*len = 20));
239 if( *retval == NULL)
240 return -1;
241 }
242 if (is_inet_nil(value)) {
243 if (external)
244 return snprintf(*retval, *len, "nil");
245 strcpy(*retval, str_nil);
246 return 1;
247 } else if (value->mask == 32) {
248 return snprintf(*retval, *len, "%d.%d.%d.%d",
249 value->q1, value->q2, value->q3, value->q4);
250 } else {
251 return snprintf(*retval, *len, "%d.%d.%d.%d/%d",
252 value->q1, value->q2, value->q3, value->q4,
253 value->mask);
254 }
255}
256/**
257 * Returns a inet, parsed from a string. The fromStr function is used
258 * to parse the string.
259 */
260str
261INETnew(inet *retval, str *in)
262{
263 ssize_t pos;
264 size_t len = sizeof(inet);
265
266 pos = INETfromString(*in, &len, &retval, false);
267 if (pos < 0)
268 throw(PARSE, "inet.new", GDK_EXCEPTION);
269
270 return (MAL_SUCCEED);
271}
272
273int
274INETcompare(const inet *l, const inet *r)
275{
276 bit res = 0;
277 if (is_inet_nil(l))
278 return is_inet_nil(r) ? 0 : -1;
279 if (is_inet_nil(r))
280 return 1;
281 INET_comp_EQ(&res, l, r);
282 if (res)
283 return 0;
284 INET_comp_LT(&res, l, r);
285 if (res)
286 return -1;
287 return 1;
288}
289
290/* === Operators === */
291/**
292 * Returns whether val represents a nil inet value
293 */
294str
295INET_isnil(bit *retval, const inet *val)
296{
297 *retval = is_inet_nil(val);
298
299 return (MAL_SUCCEED);
300}
301/**
302 * Returns whether val1 and val2 are equal.
303 */
304str
305INET_comp_EQ(bit *retval, const inet *val1, const inet *val2)
306{
307 if (is_inet_nil(val1) || is_inet_nil(val2)) {
308 *retval = bit_nil;
309 } else if (val1->q1 == val2->q1 && val1->q2 == val2->q2 &&
310 val1->q3 == val2->q3 && val1->q4 == val2->q4 &&
311 val1->mask == val2->mask) {
312 *retval = 1;
313 } else {
314 *retval = 0;
315 }
316
317 return (MAL_SUCCEED);
318}
319/**
320 * Returns whether val1 and val2 are not equal.
321 */
322str
323INET_comp_NEQ(bit *retval, const inet *val1, const inet *val2)
324{
325 if (is_inet_nil(val1) || is_inet_nil(val2)) {
326 *retval = bit_nil;
327 } else if (val1->q1 == val2->q1 && val1->q2 == val2->q2 &&
328 val1->q3 == val2->q3 && val1->q4 == val2->q4 &&
329 val1->mask == val2->mask) {
330 *retval = 0;
331 } else {
332 *retval = 1;
333 }
334
335 return (MAL_SUCCEED);
336}
337/**
338 * Returns whether val1 is smaller than val2.
339 */
340str
341INET_comp_LT(bit *retval, const inet *val1, const inet *val2)
342{
343 if (is_inet_nil(val1) || is_inet_nil(val2)) {
344 *retval = bit_nil;
345 } else if (val1->q1 < val2->q1) {
346 *retval = 1;
347 } else if (val1->q1 > val2->q1) {
348 *retval = 0;
349 } else if (val1->q2 < val2->q2) {
350 *retval = 1;
351 } else if (val1->q2 > val2->q2) {
352 *retval = 0;
353 } else if (val1->q3 < val2->q3) {
354 *retval = 1;
355 } else if (val1->q3 > val2->q3) {
356 *retval = 0;
357 } else if (val1->q4 < val2->q4) {
358 *retval = 1;
359 } else if (val1->q4 > val2->q4) {
360 *retval = 0;
361 } else if (val1->mask < val2->mask) {
362 *retval = 1;
363 } else {
364 *retval = 0;
365 }
366
367 return (MAL_SUCCEED);
368}
369/**
370 * Returns whether val1 is greater than val2.
371 */
372str
373INET_comp_GT(bit *retval, const inet *val1, const inet *val2)
374{
375 return (INET_comp_LT(retval, val2, val1));
376}
377/**
378 * Returns whether val1 is smaller than or equal to val2.
379 */
380str
381INET_comp_LE(bit *retval, const inet *val1, const inet *val2)
382{
383 bit ret;
384
385 INET_comp_LT(&ret, val1, val2);
386 if (ret == 0)
387 INET_comp_EQ(&ret, val1, val2);
388
389 *retval = ret;
390 return (MAL_SUCCEED);
391}
392/**
393 * Returns whether val1 is smaller than or equal to val2.
394 */
395str
396INET_comp_GE(bit *retval, const inet *val1, const inet *val2)
397{
398 bit ret;
399
400 /* warning: we use LT here with swapped arguments to avoid one
401 * method invocation, since inet_comp_GT does the same */
402 INET_comp_LT(&ret, val2, val1);
403 if (ret == 0)
404 INET_comp_EQ(&ret, val1, val2);
405
406 *retval = ret;
407 return (MAL_SUCCEED);
408}
409/**
410 * Returns whether val1 is contained within val2
411 */
412str
413INET_comp_CW(bit *retval, const inet *val1, const inet *val2)
414{
415 if (is_inet_nil(val1) || is_inet_nil(val2)) {
416 *retval = bit_nil;
417 } else if (val1->mask <= val2->mask) {
418 /* if the mask is bigger (less specific) or equal it can never
419 * be contained within */
420 *retval = 0;
421 } else {
422 unsigned int msk;
423 unsigned char m[4];
424
425 if (val2->mask > 0)
426 msk = ~0U << (32 - val2->mask);
427 else
428 msk = 0;
429
430 m[0] = (msk >> 24) & 0xFF;
431 m[1] = (msk >> 16) & 0xFF;
432 m[2] = (msk >> 8) & 0xFF;
433 m[3] = msk & 0xFF;
434
435 /* all operations here are done byte based, to avoid byte sex
436 * problems */
437
438 /* if you want to see some bytes, remove this comment
439 fprintf(stderr, "%x %x %x %x => %x %x %x %x %x %x %x %x\n",
440 m[0], m[1], m[2], m[3], val1->q1, val1->q2,
441 val1->q3, val1->q4, val2->q1, val2->q2, val2->q3,
442 val2->q4);
443 */
444
445 if ((val1->q1 & m[0]) == (val2->q1 & m[0]) &&
446 (val1->q2 & m[1]) == (val2->q2 & m[1]) &&
447 (val1->q3 & m[2]) == (val2->q3 & m[2]) &&
448 (val1->q4 & m[3]) == (val2->q4 & m[3])) {
449 *retval = 1;
450 } else {
451 *retval = 0;
452 }
453
454 /* example: (hex notation)
455 * inet1: 10.0.0.0/24
456 * IP1: 10 00 00 00
457 * mask1: ff ff ff 00
458 * &1: 10 00 00 00
459 * inet2: 10.0.0.254
460 * IP2: 10 00 00 ef
461 * mask1: ff ff ff 00
462 * &2: 10 00 00 00
463 * &1 and &2 are equal, so inet2 is within inet1
464 */
465 }
466 return (MAL_SUCCEED);
467}
468/**
469 * Returns whether val1 is contained within or equal to val2
470 */
471str
472INET_comp_CWE(bit *retval, const inet *val1, const inet *val2)
473{
474 bit ret;
475
476 /* use existing code, not fully optimal, but cheap enough */
477 INET_comp_CW(&ret, val1, val2);
478 if (!ret)
479 INET_comp_EQ(&ret, val1, val2);
480
481 *retval = ret;
482 return (MAL_SUCCEED);
483}
484/**
485 * Returns whether val1 is contains val2
486 */
487str
488INET_comp_CS(bit *retval, const inet *val1, const inet *val2)
489{
490 /* swap the input arguments and call the contained within function */
491 return (INET_comp_CW(retval, val2, val1));
492}
493/**
494 * Returns whether val1 contains or is equal to val2
495 */
496str
497INET_comp_CSE(bit *retval, const inet *val1, const inet *val2)
498{
499 /* swap the input arguments and call the contained within function */
500 return (INET_comp_CWE(retval, val2, val1));
501}
502
503
504/* === Functions === */
505/**
506 * Returns the broadcast address for the network the inet represents.
507 * If the subnet mask is 32, the given input inet is returned.
508 */
509str
510INETbroadcast(inet *retval, const inet *val)
511{
512 *retval = *val;
513 if (!is_inet_nil(val) && val->mask != 32) {
514 unsigned int msk;
515 unsigned char m[4];
516
517 if (val->mask > 0)
518 msk = ~0U << (32 - val->mask);
519 else
520 msk = 0;
521
522 msk = ~msk; /* invert the mask */
523 m[0] = (msk >> 24) & 0xFF;
524 m[1] = (msk >> 16) & 0xFF;
525 m[2] = (msk >> 8) & 0xFF;
526 m[3] = msk & 0xFF;
527
528 /* if you want to see some bytes, remove this comment
529 fprintf(stderr, "%x %x %x %x => %x %x %x %x\n",
530 m[0], m[1], m[2], m[3], val->q1, val->q2,
531 val->q3, val->q4);
532 */
533
534 /* apply the inverted mask, so we get the broadcast */
535 retval->q1 |= m[0];
536 retval->q2 |= m[1];
537 retval->q3 |= m[2];
538 retval->q4 |= m[3];
539
540 /* example: (hex notation)
541 * inet: 10.0.0.1/24
542 * IP: 10 00 00 01
543 * mask: 00 00 00 ff
544 * &: 10 00 00 ff
545 * results in 10.0.0.255
546 */
547 }
548 return (MAL_SUCCEED);
549}
550/**
551 * Extract only the IP address as text. Unlike the toString function,
552 * this function never returns the netmask length.
553 */
554str
555INEThost(str *retval, const inet *val)
556{
557 str ip;
558
559 if (is_inet_nil(val)) {
560 *retval = GDKstrdup(str_nil);
561 if( *retval == NULL)
562 throw(MAL,"INEThost", SQLSTATE(HY001) MAL_MALLOC_FAIL);
563 } else {
564 ip = GDKmalloc(sizeof(char) * 16);
565 if( ip == NULL)
566 throw(MAL,"INEThost", SQLSTATE(HY001) MAL_MALLOC_FAIL);
567 sprintf(ip, "%d.%d.%d.%d", val->q1, val->q2, val->q3, val->q4);
568 *retval = ip;
569 }
570 return (MAL_SUCCEED);
571}
572/**
573 * Extract netmask length.
574 */
575str
576INETmasklen(int *retval, const inet *val)
577{
578 if (is_inet_nil(val)) {
579 *retval = int_nil;
580 } else {
581 *retval = val->mask;
582 }
583 return (MAL_SUCCEED);
584}
585/**
586 * Set netmask length for inet value.
587 */
588str
589INETsetmasklen(inet *retval, const inet *val, const int *msk)
590{
591 if (*msk < 0 || *msk > 32)
592 throw(ILLARG, "inet.setmask", "Illegal netmask length value: %d", *msk);
593
594 *retval = *val;
595 if (!is_inet_nil(val))
596 retval->mask = *msk;
597
598 return (MAL_SUCCEED);
599}
600/**
601 * Construct netmask for network.
602 */
603str
604INETnetmask(inet *retval, const inet *val)
605{
606 *retval = *val;
607 if (!is_inet_nil(val)) {
608 unsigned int msk;
609 unsigned char m[4];
610
611 if (val->mask > 0)
612 msk = ~0U << (32 - val->mask);
613 else
614 msk = 0;
615
616 m[0] = (msk >> 24) & 0xFF;
617 m[1] = (msk >> 16) & 0xFF;
618 m[2] = (msk >> 8) & 0xFF;
619 m[3] = msk & 0xFF;
620
621 retval->q1 = m[0];
622 retval->q2 = m[1];
623 retval->q3 = m[2];
624 retval->q4 = m[3];
625 retval->mask = 32;
626
627 /* example: (hex notation)
628 * inet: 10.0.0.1/24
629 * mask: ff ff ff 00
630 * results in 255.255.255.0
631 */
632 }
633 return (MAL_SUCCEED);
634}
635/**
636 * Construct host mask for network.
637 */
638str
639INEThostmask(inet *retval, const inet *val)
640{
641 INETnetmask(retval, val);
642 /* invert the netmask to obtain the host mask */
643 if (!is_inet_nil(retval)) {
644 retval->q1 = ~retval->q1;
645 retval->q2 = ~retval->q2;
646 retval->q3 = ~retval->q3;
647 retval->q4 = ~retval->q4;
648 }
649
650 /* example: (hex notation)
651 * netmask: 255.255.255.0
652 * IP: ff ff ff 00
653 * ~: 00 00 00 ff
654 * results in 0.0.0.255
655 */
656
657 return (MAL_SUCCEED);
658}
659/**
660 * Extract network part of address, returns the same inet if the netmask
661 * is equal to 32. This function basically zeros out values that are
662 * not covered by the netmask.
663 */
664str
665INETnetwork(inet *retval, const inet *val)
666{
667 *retval = *val;
668 if (!is_inet_nil(val)) {
669 unsigned int msk;
670 unsigned char m[4];
671
672 if (val->mask > 0)
673 msk = ~0U << (32 - val->mask);
674 else
675 msk = 0;
676
677 m[0] = (msk >> 24) & 0xFF;
678 m[1] = (msk >> 16) & 0xFF;
679 m[2] = (msk >> 8) & 0xFF;
680 m[3] = msk & 0xFF;
681
682 retval->q1 &= m[0];
683 retval->q2 &= m[1];
684 retval->q3 &= m[2];
685 retval->q4 &= m[3];
686
687 /* example: (hex notation)
688 * inet: 10.0.0.1/24
689 * IP: 10 00 00 01
690 * mask: ff ff ff 00
691 * &: 10 00 00 00
692 * results in 10.0.0.0/24
693 */
694 }
695 return (MAL_SUCCEED);
696}
697/**
698 * Extract IP address and netmask length as text. Unlike the toStr
699 * function, this function always prints the netmask length.
700 */
701str
702INETtext(str *retval, const inet *val)
703{
704 str ip;
705
706 if (is_inet_nil(val)) {
707 *retval = GDKstrdup(str_nil);
708 if( *retval == NULL)
709 throw(MAL,"INETtext", SQLSTATE(HY001) MAL_MALLOC_FAIL);
710 } else {
711 ip = GDKmalloc(sizeof(char) * 20);
712 if( ip == NULL)
713 throw(MAL,"INETtext", SQLSTATE(HY001) MAL_MALLOC_FAIL);
714
715 snprintf(ip, sizeof(char) * 20, "%d.%d.%d.%d/%d",
716 val->q1, val->q2, val->q3, val->q4, val->mask);
717 *retval = ip;
718 }
719 return (MAL_SUCCEED);
720}
721/**
722 * Abbreviated display format as text. The abbreviation is only made if
723 * the value has no bits set to right of mask. Otherwise the return of
724 * this function is equal to the function text.
725 */
726str
727INETabbrev(str *retval, const inet *val)
728{
729 str ip;
730
731 if (is_inet_nil(val)) {
732 *retval = GDKstrdup(str_nil);
733 if (*retval == NULL)
734 throw(MAL, "inet.abbrev", SQLSTATE(HY001) MAL_MALLOC_FAIL);
735 } else {
736 unsigned int msk;
737 unsigned char m[4];
738
739 if (val->mask > 0)
740 msk = ~0U << (32 - val->mask);
741 else
742 msk = 0;
743 msk = ~msk; /* invert the mask */
744
745 m[0] = (msk >> 24) & 0xFF;
746 m[1] = (msk >> 16) & 0xFF;
747 m[2] = (msk >> 8) & 0xFF;
748 m[3] = msk & 0xFF;
749
750 if ((val->q1 & m[0]) != 0 ||
751 (val->q2 & m[1]) != 0 ||
752 (val->q3 & m[2]) != 0 ||
753 (val->q4 & m[3]) != 0) {
754 msk = 32;
755 } else {
756 msk = val->mask;
757 }
758
759 /* example: (hex notation)
760 * inet: 10.1.0.0/16
761 * IP: 10 01 00 00
762 * mask: 00 00 ff ff
763 * &: 00 00 00 00
764 * all zero, thus no bits on the right side of the mask
765 */
766
767 ip = GDKmalloc(sizeof(char) * 20);
768 if (ip == NULL)
769 throw(MAL, "inet.abbrev", SQLSTATE(HY001) MAL_MALLOC_FAIL);
770
771 if (msk > 24) {
772 snprintf(ip, sizeof(char) * 20, "%d.%d.%d.%d/%d",
773 val->q1, val->q2, val->q3, val->q4, val->mask);
774 } else if (msk > 16) {
775 snprintf(ip, sizeof(char) * 20, "%d.%d.%d/%d",
776 val->q1, val->q2, val->q3, val->mask);
777 } else if (msk > 8) {
778 snprintf(ip, sizeof(char) * 20, "%d.%d/%d",
779 val->q1, val->q2, val->mask);
780 } else if (msk > 0) {
781 snprintf(ip, sizeof(char) * 20, "%d/%d", val->q1, val->mask);
782 } else {
783 snprintf(ip, sizeof(char) * 20, "/0");
784 }
785
786 *retval = ip;
787 }
788 return (MAL_SUCCEED);
789}
790str
791INET_inet(inet *d, const inet *s)
792{
793 *d = *s;
794 return MAL_SUCCEED;
795}
796str
797INET_fromstr(inet *ret, str *s)
798{
799 size_t len = sizeof(inet);
800 if (INETfromString(*s, &len, &ret, false) < 0)
801 throw(MAL, "inet.inet", GDK_EXCEPTION);
802 return MAL_SUCCEED;
803}
804
805const inet *
806INETnull(void)
807{
808 return &inet_nil;
809}
810