ISC DHCP 4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
 
Loading...
Searching...
No Matches
inet.c
Go to the documentation of this file.
1/* inet.c
2
3 Subroutines to manipulate internet addresses and ports in a safely portable
4 way... */
5
6/*
7 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1995-2003 by Internet Software Consortium
9 *
10 * This Source Code Form is subject to the terms of the Mozilla Public
11 * License, v. 2.0. If a copy of the MPL was not distributed with this
12 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Internet Systems Consortium, Inc.
23 * PO Box 360
24 * Newmarket, NH 03857 USA
25 * <info@isc.org>
26 * https://www.isc.org/
27 *
28 */
29
30#include "dhcpd.h"
31
32/* Return just the network number of an internet address... */
33
34struct iaddr subnet_number (addr, mask)
35 struct iaddr addr;
36 struct iaddr mask;
37{
38 int i;
39 struct iaddr rv;
40
41 if (addr.len > sizeof(addr.iabuf))
42 log_fatal("subnet_number():%s:%d: Invalid addr length.", MDL);
43 if (addr.len != mask.len)
44 log_fatal("subnet_number():%s:%d: Addr/mask length mismatch.",
45 MDL);
46
47 rv.len = 0;
48
49 /* Both addresses must have the same length... */
50 if (addr.len != mask.len)
51 return rv;
52
53 rv.len = addr.len;
54 for (i = 0; i < rv.len; i++)
55 rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i];
56 return rv;
57}
58
59/* Combine a network number and a integer to produce an internet address.
60 This won't work for subnets with more than 32 bits of host address, but
61 maybe this isn't a problem. */
62
63struct iaddr ip_addr (subnet, mask, host_address)
64 struct iaddr subnet;
65 struct iaddr mask;
66 u_int32_t host_address;
67{
68 int i, j, k;
69 u_int32_t swaddr;
70 struct iaddr rv;
71 unsigned char habuf [sizeof swaddr];
72
73 if (subnet.len > sizeof(subnet.iabuf))
74 log_fatal("ip_addr():%s:%d: Invalid addr length.", MDL);
75 if (subnet.len != mask.len)
76 log_fatal("ip_addr():%s:%d: Addr/mask length mismatch.",
77 MDL);
78
79 swaddr = htonl (host_address);
80 memcpy (habuf, &swaddr, sizeof swaddr);
81
82 /* Combine the subnet address and the host address. If
83 the host address is bigger than can fit in the subnet,
84 return a zero-length iaddr structure. */
85 rv = subnet;
86 j = rv.len - sizeof habuf;
87 for (i = sizeof habuf - 1; i >= 0; i--) {
88 if (mask.iabuf [i + j]) {
89 if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
90 rv.len = 0;
91 return rv;
92 }
93 for (k = i - 1; k >= 0; k--) {
94 if (habuf [k]) {
95 rv.len = 0;
96 return rv;
97 }
98 }
99 rv.iabuf [i + j] |= habuf [i];
100 break;
101 } else
102 rv.iabuf [i + j] = habuf [i];
103 }
104
105 return rv;
106}
107
108/* Given a subnet number and netmask, return the address on that subnet
109 for which the host portion of the address is all ones (the standard
110 broadcast address). */
111
113 struct iaddr subnet;
114 struct iaddr mask;
115{
116 int i;
117 struct iaddr rv;
118
119 if (subnet.len > sizeof(subnet.iabuf))
120 log_fatal("broadcast_addr():%s:%d: Invalid addr length.", MDL);
121 if (subnet.len != mask.len)
122 log_fatal("broadcast_addr():%s:%d: Addr/mask length mismatch.",
123 MDL);
124
125 if (subnet.len != mask.len) {
126 rv.len = 0;
127 return rv;
128 }
129
130 for (i = 0; i < subnet.len; i++) {
131 rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255);
132 }
133 rv.len = subnet.len;
134
135 return rv;
136}
137
138u_int32_t host_addr (addr, mask)
139 struct iaddr addr;
140 struct iaddr mask;
141{
142 int i;
143 u_int32_t swaddr;
144 struct iaddr rv;
145
146 if (addr.len > sizeof(addr.iabuf))
147 log_fatal("host_addr():%s:%d: Invalid addr length.", MDL);
148 if (addr.len != mask.len)
149 log_fatal("host_addr():%s:%d: Addr/mask length mismatch.",
150 MDL);
151
152 rv.len = 0;
153
154 /* Mask out the network bits... */
155 rv.len = addr.len;
156 for (i = 0; i < rv.len; i++)
157 rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i];
158
159 /* Copy out up to 32 bits... */
160 memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr);
161
162 /* Swap it and return it. */
163 return ntohl (swaddr);
164}
165
166int addr_eq (addr1, addr2)
167 struct iaddr addr1, addr2;
168{
169 if (addr1.len > sizeof(addr1.iabuf))
170 log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL);
171
172 if (addr1.len != addr2.len)
173 return 0;
174 return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
175}
176
177/* addr_match
178 *
179 * compares an IP address against a network/mask combination
180 * by ANDing the IP with the mask and seeing whether the result
181 * matches the masked network value.
182 */
183int
184addr_match(addr, match)
185 struct iaddr *addr;
186 struct iaddrmatch *match;
187{
188 int i;
189
190 if (addr->len != match->addr.len)
191 return 0;
192
193 for (i = 0 ; i < addr->len ; i++) {
194 if ((addr->iabuf[i] & match->mask.iabuf[i]) !=
195 match->addr.iabuf[i])
196 return 0;
197 }
198 return 1;
199}
200
201/*
202 * Compares the addresses a1 and a2.
203 *
204 * If a1 < a2, returns -1.
205 * If a1 == a2, returns 0.
206 * If a1 > a2, returns 1.
207 *
208 * WARNING: if a1 and a2 differ in length, returns 0.
209 */
210int
211addr_cmp(const struct iaddr *a1, const struct iaddr *a2) {
212 int i;
213
214 if (a1->len != a2->len) {
215 return 0;
216 }
217
218 for (i=0; i<a1->len; i++) {
219 if (a1->iabuf[i] < a2->iabuf[i]) {
220 return -1;
221 }
222 if (a1->iabuf[i] > a2->iabuf[i]) {
223 return 1;
224 }
225 }
226
227 return 0;
228}
229
230/*
231 * Performs a bitwise-OR of two addresses.
232 *
233 * Returns 1 if the result is non-zero, or 0 otherwise.
234 *
235 * WARNING: if a1 and a2 differ in length, returns 0.
236 */
237int
238addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
239 int i;
240 int all_zero;
241
242 if (a1->len != a2->len) {
243 return 0;
244 }
245
246 all_zero = 1;
247
248 result->len = a1->len;
249 for (i=0; i<a1->len; i++) {
250 result->iabuf[i] = a1->iabuf[i] | a2->iabuf[i];
251 if (result->iabuf[i] != 0) {
252 all_zero = 0;
253 }
254 }
255
256 return !all_zero;
257}
258
259/*
260 * Performs a bitwise-AND of two addresses.
261 *
262 * Returns 1 if the result is non-zero, or 0 otherwise.
263 *
264 * WARNING: if a1 and a2 differ in length, returns 0.
265 */
266int
267addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
268 int i;
269 int all_zero;
270
271 if (a1->len != a2->len) {
272 return 0;
273 }
274
275 all_zero = 1;
276
277 result->len = a1->len;
278 for (i=0; i<a1->len; i++) {
279 result->iabuf[i] = a1->iabuf[i] & a2->iabuf[i];
280 if (result->iabuf[i] != 0) {
281 all_zero = 0;
282 }
283 }
284
285 return !all_zero;
286}
287
288/*
289 * Check if a bitmask of the given length is valid for the address.
290 * This is not the case if any bits longer than the bitmask are 1.
291 *
292 * So, this is valid:
293 *
294 * 127.0.0.0/8
295 *
296 * But this is not:
297 *
298 * 127.0.0.1/8
299 *
300 * Because the final ".1" would get masked out by the /8.
301 */
303is_cidr_mask_valid(const struct iaddr *addr, int bits) {
304 int zero_bits;
305 int zero_bytes;
306 int i;
307 char byte;
308 int shift_bits;
309
310 /*
311 * Check our bit boundaries.
312 */
313 if (bits < 0) {
314 return ISC_FALSE;
315 }
316 if (bits > (addr->len * 8)) {
317 return ISC_FALSE;
318 }
319
320 /*
321 * Figure out how many low-order bits need to be zero.
322 */
323 zero_bits = (addr->len * 8) - bits;
324 zero_bytes = zero_bits / 8;
325
326 /*
327 * Check to make sure the low-order bytes are zero.
328 */
329 for (i=1; i<=zero_bytes; i++) {
330 if (addr->iabuf[addr->len-i] != 0) {
331 return ISC_FALSE;
332 }
333 }
334
335 /*
336 * Look to see if any bits not in right-hand bytes are
337 * non-zero, by making a byte that has these bits set to zero
338 * comparing to the original byte. If these two values are
339 * equal, then the right-hand bits are zero, and we are
340 * happy.
341 */
342 shift_bits = zero_bits % 8;
343 if (shift_bits == 0) return ISC_TRUE;
344 byte = addr->iabuf[addr->len-zero_bytes-1];
345 return (((byte >> shift_bits) << shift_bits) == byte);
346}
347
348/*
349 * range2cidr
350 *
351 * Converts a range of IP addresses to a set of CIDR networks.
352 *
353 * Examples:
354 * 192.168.0.0 - 192.168.0.255 = 192.168.0.0/24
355 * 10.0.0.0 - 10.0.1.127 = 10.0.0.0/24, 10.0.1.0/25
356 * 255.255.255.32 - 255.255.255.255 = 255.255.255.32/27, 255.255.255.64/26,
357 * 255.255.255.128/25
358 */
359isc_result_t
361 const struct iaddr *lo, const struct iaddr *hi) {
362 struct iaddr addr;
363 struct iaddr mask;
364 int bit;
365 struct iaddr end_addr;
366 struct iaddr dummy;
367 int ofs, val;
368 struct iaddrcidrnetlist *net;
369 int tmp;
370
371 if (result == NULL) {
372 return DHCP_R_INVALIDARG;
373 }
374 if (*result != NULL) {
375 return DHCP_R_INVALIDARG;
376 }
377 if ((lo == NULL) || (hi == NULL) || (lo->len != hi->len)) {
378 return DHCP_R_INVALIDARG;
379 }
380
381 /*
382 * Put our start and end in the right order, if reversed.
383 */
384 if (addr_cmp(lo, hi) > 0) {
385 const struct iaddr *tmp;
386 tmp = lo;
387 lo = hi;
388 hi = tmp;
389 }
390
391 /*
392 * Theory of operation:
393 *
394 * -------------------
395 * Start at the low end, and keep trying larger networks
396 * until we get one that is too big (explained below).
397 *
398 * We keep a "mask", which is the ones-complement of a
399 * normal netmask. So, a /23 has a netmask of 255.255.254.0,
400 * and a mask of 0.0.1.255.
401 *
402 * We know when a network is too big when we bitwise-AND the
403 * mask with the starting address and we get a non-zero
404 * result, like this:
405 *
406 * addr: 192.168.1.0, mask: 0.0.1.255
407 * bitwise-AND: 0.0.1.0
408 *
409 * A network is also too big if the bitwise-OR of the mask
410 * with the starting address is larger than the end address,
411 * like this:
412 *
413 * start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255
414 * bitwise-OR: 192.168.1.255
415 *
416 * -------------------
417 * Once we have found a network that is too big, we add the
418 * appropriate CIDR network to our list of found networks.
419 *
420 * We then use the next IP address as our low address, and
421 * begin the process of searching for a network that is
422 * too big again, starting with an empty mask.
423 */
424 addr = *lo;
425 bit = 0;
426 memset(&mask, 0, sizeof(mask));
427 mask.len = addr.len;
428 while (addr_cmp(&addr, hi) <= 0) {
429 /*
430 * Bitwise-OR mask with (1 << bit)
431 */
432 ofs = addr.len - (bit / 8) - 1;
433 val = 1 << (bit % 8);
434 if (ofs >= 0) {
435 mask.iabuf[ofs] |= val;
436 }
437
438 /*
439 * See if we're too big, and save this network if so.
440 */
441 addr_or(&end_addr, &addr, &mask);
442 if ((ofs < 0) ||
443 (addr_cmp(&end_addr, hi) > 0) ||
444 addr_and(&dummy, &addr, &mask)) {
445 /*
446 * Add a new prefix to our list.
447 */
448 net = dmalloc(sizeof(*net), MDL);
449 if (net == NULL) {
450 while (*result != NULL) {
451 net = (*result)->next;
452 dfree(*result, MDL);
453 *result = net;
454 }
455 return ISC_R_NOMEMORY;
456 }
457 net->cidrnet.lo_addr = addr;
458 net->cidrnet.bits = (addr.len * 8) - bit;
459 net->next = *result;
460 *result = net;
461
462 /*
463 * Figure out our new starting address,
464 * by adding (1 << bit) to our previous
465 * starting address.
466 */
467 tmp = addr.iabuf[ofs] + val;
468 while ((ofs >= 0) && (tmp > 255)) {
469 addr.iabuf[ofs] = tmp - 256;
470 ofs--;
471 tmp = addr.iabuf[ofs] + 1;
472 }
473 if (ofs < 0) {
474 /* Gone past last address, we're done. */
475 break;
476 }
477 addr.iabuf[ofs] = tmp;
478
479 /*
480 * Reset our bit and mask.
481 */
482 bit = 0;
483 memset(mask.iabuf, 0, sizeof(mask.iabuf));
484 memset(end_addr.iabuf, 0, sizeof(end_addr.iabuf));
485 } else {
486 /*
487 * If we're not too big, increase our network size.
488 */
489 bit++;
490 }
491 }
492
493 /*
494 * We're done.
495 */
496 return ISC_R_SUCCESS;
497}
498
499/*
500 * Free a list of CIDR networks, such as returned from range2cidr().
501 */
502isc_result_t
504 struct iaddrcidrnetlist *p;
505
506 if (result == NULL) {
507 return DHCP_R_INVALIDARG;
508 }
509 if (*result == NULL) {
510 return DHCP_R_INVALIDARG;
511 }
512
513 while (*result != NULL) {
514 p = *result;
515 *result = p->next;
516 dfree(p, MDL);
517 }
518
519 return ISC_R_SUCCESS;
520}
521
522static const char *
523inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size)
524{
525 char tmp[sizeof("32.255.255.255.255")];
526 int len;
527
528 switch (srclen) {
529 case 2:
530 len = sprintf (tmp, "%u.%u", src[0], src[1]);
531 break;
532 case 3:
533 len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]);
534 break;
535 case 4:
536 len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
537 break;
538 case 5:
539 len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]);
540 break;
541 default:
542 return NULL;
543 }
544 if (len < 0)
545 return NULL;
546
547 if (len > size) {
548 errno = ENOSPC;
549 return NULL;
550 }
551
552 return strcpy (dst, tmp);
553}
554
555/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */
556const char *
557pdestdesc(const struct iaddr addr) {
558 static char pbuf[sizeof("255.255.255.255.255")];
559
560 if (addr.len == 0) {
561 return "<null destination descriptor>";
562 }
563 if (addr.len == 1) {
564 return "0";
565 }
566 if ((addr.len >= 2) && (addr.len <= 5)) {
567 return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf));
568 }
569
570 log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.",
571 MDL, addr.len);
572 /* quell compiler warnings */
573 return NULL;
574}
575
576/* piaddr() turns an iaddr structure into a printable address. */
577/* XXX: should use a const pointer rather than passing the structure */
578const char *
579piaddr(const struct iaddr addr) {
580 static char
581 pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
582 /* "255.255.255.255" */
583
584 /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */
585
586 if (addr.len == 0) {
587 return "<null address>";
588 }
589 if (addr.len == 4) {
590 return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf));
591 }
592 if (addr.len == 16) {
593 return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf));
594 }
595
596 log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL,
597 addr.len);
598 /* quell compiler warnings */
599 return NULL;
600}
601
602/* piaddrmask takes an iaddr structure mask, determines the bitlength of
603 * the mask, and then returns the printable CIDR notation of the two.
604 */
605char *
606piaddrmask(struct iaddr *addr, struct iaddr *mask) {
607 int mw;
608 unsigned int oct, bit;
609
610 if ((addr->len != 4) && (addr->len != 16))
611 log_fatal("piaddrmask():%s:%d: Address length %d invalid",
612 MDL, addr->len);
613 if (addr->len != mask->len)
614 log_fatal("piaddrmask():%s:%d: Address and mask size mismatch",
615 MDL);
616
617 /* Determine netmask width in bits. */
618 for (mw = (mask->len * 8) ; mw > 0 ; ) {
619 oct = (mw - 1) / 8;
620 bit = 0x80 >> ((mw - 1) % 8);
621 if (!mask->iabuf[oct])
622 mw -= 8;
623 else if (mask->iabuf[oct] & bit)
624 break;
625 else
626 mw--;
627 }
628
629 if (mw < 0)
630 log_fatal("Impossible condition at %s:%d.", MDL);
631
632 return piaddrcidr(addr, mw);
633}
634
635/* Format an address and mask-length into printable CIDR notation. */
636char *
637piaddrcidr(const struct iaddr *addr, unsigned int bits) {
638 static char
639 ret[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")];
640 /* "255.255.255.255/32" */
641
642 /* INSIST(addr != NULL); */
643 /* INSIST((addr->len == 4) || (addr->len == 16)); */
644 /* INSIST(bits <= (addr->len * 8)); */
645
646 if (bits > (addr->len * 8))
647 return NULL;
648
649 sprintf(ret, "%s/%d", piaddr(*addr), bits);
650
651 return ret;
652}
653
654/* Validate that the string represents a valid port number and
655 * return it in network byte order
656 */
657
658u_int16_t
659validate_port(char *port) {
660 long local_port = 0;
661 long lower = 1;
662 long upper = 65535;
663 char *endptr;
664
665 errno = 0;
666 local_port = strtol(port, &endptr, 10);
667
668 if ((*endptr != '\0') || (errno == ERANGE) || (errno == EINVAL))
669 log_fatal ("Invalid port number specification: %s", port);
670
672 log_fatal("Port number specified is out of range (%ld-%ld).",
673 lower, upper);
674
675 return htons((u_int16_t)local_port);
676}
677
678/* \brief Validate that the string represents a valid port pair (i.e. n,n+1)
679 *
680 * \param the string to validate
681 * \return the first port number in network byte order
682 */
683
684u_int16_t
686 long local_port = 0;
687 long lower = 1;
688 long upper = 65534;
689 char *endptr;
690
691 errno = 0;
692 local_port = strtol(port, &endptr, 10);
693
694 if ((*endptr != '\0') || (errno == ERANGE) || (errno == EINVAL))
695 log_fatal ("Invalid port pair specification: %s", port);
696
698 log_fatal("Port pair specified is out of range (%ld-%ld).",
699 lower, upper);
700
701 return htons((u_int16_t)local_port);
702}
703
704#ifdef DHCPv6
705/* Print a v6 address from an in6_addr struct */
706const char *
707pin6_addr(const struct in6_addr *src){
708
709 if (!src) {
710 return ("<null>");
711 }
712
713 struct iaddr addr;
714 addr.len = 16;
715 memcpy(addr.iabuf, src->s6_addr, 16);
716 return (piaddr(addr));
717}
718#endif
isc_boolean_t
Definition data.h:150
#define ISC_TRUE
Definition data.h:153
#define ISC_FALSE
Definition data.h:152
u_int16_t local_port
Definition discover.c:48
const char * pin6_addr(const struct in6_addr *)
isc_result_t range2cidr(struct iaddrcidrnetlist **result, const struct iaddr *lo, const struct iaddr *hi)
Definition inet.c:360
isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result)
Definition inet.c:503
u_int32_t host_addr(struct iaddr addr, struct iaddr mask)
Definition inet.c:138
isc_boolean_t is_cidr_mask_valid(const struct iaddr *addr, int bits)
Definition inet.c:303
u_int16_t validate_port(char *port)
Definition inet.c:659
struct iaddr ip_addr(struct iaddr subnet, struct iaddr mask, u_int32_t host_address)
Definition inet.c:63
char * piaddrcidr(const struct iaddr *addr, unsigned int bits)
Definition inet.c:637
const char * piaddr(const struct iaddr addr)
Definition inet.c:579
const char * pdestdesc(const struct iaddr addr)
Definition inet.c:557
int addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2)
Definition inet.c:238
int addr_eq(struct iaddr addr1, struct iaddr addr2)
Definition inet.c:166
struct iaddr broadcast_addr(struct iaddr subnet, struct iaddr mask)
Definition inet.c:112
int addr_cmp(const struct iaddr *a1, const struct iaddr *a2)
Definition inet.c:211
u_int16_t validate_port_pair(char *port)
Definition inet.c:685
int addr_match(struct iaddr *addr, struct iaddrmatch *match)
Definition inet.c:184
struct iaddr subnet_number(struct iaddr addr, struct iaddr mask)
Definition inet.c:34
char * piaddrmask(struct iaddr *addr, struct iaddr *mask)
Definition inet.c:606
int addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2)
Definition inet.c:267
#define ISC_R_SUCCESS
#define MDL
Definition omapip.h:567
void * dmalloc(size_t, const char *, int)
Definition alloc.c:57
void dfree(void *, const char *, int)
Definition alloc.c:145
void log_fatal(const char *,...) __attribute__((__format__(__printf__
#define DHCP_R_INVALIDARG
Definition result.h:49
Definition inet.h:31
unsigned char iabuf[16]
Definition inet.h:33
unsigned len
Definition inet.h:32
struct iaddr lo_addr
Definition inet.h:71
int bits
Definition inet.h:72
struct iaddrcidrnet cidrnet
Definition inet.h:77
struct iaddrcidrnetlist * next
Definition inet.h:76
struct iaddr addr
Definition inet.h:54
struct iaddr mask
Definition inet.h:55