]>
git.ipfire.org Git - thirdparty/dhcp.git/blob - common/inet.c
3 Subroutines to manipulate internet addresses and ports in a safely portable
7 * Copyright (c) 2011,2013 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2007-2009 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 2004,2005 by Internet Systems Consortium, Inc. ("ISC")
10 * Copyright (c) 1995-2003 by Internet Software Consortium
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
16 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Internet Systems Consortium, Inc.
26 * Redwood City, CA 94063
28 * https://www.isc.org/
30 * This software has been written for Internet Systems Consortium
31 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
32 * To learn more about Internet Systems Consortium, see
33 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
34 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
35 * ``http://www.nominum.com''.
40 /* Return just the network number of an internet address... */
42 struct iaddr
subnet_number (addr
, mask
)
49 if (addr
.len
> sizeof(addr
.iabuf
))
50 log_fatal("subnet_number():%s:%d: Invalid addr length.", MDL
);
51 if (addr
.len
!= mask
.len
)
52 log_fatal("subnet_number():%s:%d: Addr/mask length mismatch.",
57 /* Both addresses must have the same length... */
58 if (addr
.len
!= mask
.len
)
62 for (i
= 0; i
< rv
.len
; i
++)
63 rv
.iabuf
[i
] = addr
.iabuf
[i
] & mask
.iabuf
[i
];
67 /* Combine a network number and a integer to produce an internet address.
68 This won't work for subnets with more than 32 bits of host address, but
69 maybe this isn't a problem. */
71 struct iaddr
ip_addr (subnet
, mask
, host_address
)
74 u_int32_t host_address
;
79 unsigned char habuf
[sizeof swaddr
];
81 if (subnet
.len
> sizeof(subnet
.iabuf
))
82 log_fatal("ip_addr():%s:%d: Invalid addr length.", MDL
);
83 if (subnet
.len
!= mask
.len
)
84 log_fatal("ip_addr():%s:%d: Addr/mask length mismatch.",
87 swaddr
= htonl (host_address
);
88 memcpy (habuf
, &swaddr
, sizeof swaddr
);
90 /* Combine the subnet address and the host address. If
91 the host address is bigger than can fit in the subnet,
92 return a zero-length iaddr structure. */
94 j
= rv
.len
- sizeof habuf
;
95 for (i
= sizeof habuf
- 1; i
>= 0; i
--) {
96 if (mask
.iabuf
[i
+ j
]) {
97 if (habuf
[i
] > (mask
.iabuf
[i
+ j
] ^ 0xFF)) {
101 for (k
= i
- 1; k
>= 0; k
--) {
107 rv
.iabuf
[i
+ j
] |= habuf
[i
];
110 rv
.iabuf
[i
+ j
] = habuf
[i
];
116 /* Given a subnet number and netmask, return the address on that subnet
117 for which the host portion of the address is all ones (the standard
118 broadcast address). */
120 struct iaddr
broadcast_addr (subnet
, mask
)
127 if (subnet
.len
> sizeof(subnet
.iabuf
))
128 log_fatal("broadcast_addr():%s:%d: Invalid addr length.", MDL
);
129 if (subnet
.len
!= mask
.len
)
130 log_fatal("broadcast_addr():%s:%d: Addr/mask length mismatch.",
133 if (subnet
.len
!= mask
.len
) {
138 for (i
= 0; i
< subnet
.len
; i
++) {
139 rv
.iabuf
[i
] = subnet
.iabuf
[i
] | (~mask
.iabuf
[i
] & 255);
146 u_int32_t
host_addr (addr
, mask
)
154 if (addr
.len
> sizeof(addr
.iabuf
))
155 log_fatal("host_addr():%s:%d: Invalid addr length.", MDL
);
156 if (addr
.len
!= mask
.len
)
157 log_fatal("host_addr():%s:%d: Addr/mask length mismatch.",
162 /* Mask out the network bits... */
164 for (i
= 0; i
< rv
.len
; i
++)
165 rv
.iabuf
[i
] = addr
.iabuf
[i
] & ~mask
.iabuf
[i
];
167 /* Copy out up to 32 bits... */
168 memcpy (&swaddr
, &rv
.iabuf
[rv
.len
- sizeof swaddr
], sizeof swaddr
);
170 /* Swap it and return it. */
171 return ntohl (swaddr
);
174 int addr_eq (addr1
, addr2
)
175 struct iaddr addr1
, addr2
;
177 if (addr1
.len
> sizeof(addr1
.iabuf
))
178 log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL
);
180 if (addr1
.len
!= addr2
.len
)
182 return memcmp (addr1
.iabuf
, addr2
.iabuf
, addr1
.len
) == 0;
187 * compares an IP address against a network/mask combination
188 * by ANDing the IP with the mask and seeing whether the result
189 * matches the masked network value.
192 addr_match(addr
, match
)
194 struct iaddrmatch
*match
;
198 if (addr
->len
!= match
->addr
.len
)
201 for (i
= 0 ; i
< addr
->len
; i
++) {
202 if ((addr
->iabuf
[i
] & match
->mask
.iabuf
[i
]) !=
203 match
->addr
.iabuf
[i
])
210 * Compares the addresses a1 and a2.
212 * If a1 < a2, returns -1.
213 * If a1 == a2, returns 0.
214 * If a1 > a2, returns 1.
216 * WARNING: if a1 and a2 differ in length, returns 0.
219 addr_cmp(const struct iaddr
*a1
, const struct iaddr
*a2
) {
222 if (a1
->len
!= a2
->len
) {
226 for (i
=0; i
<a1
->len
; i
++) {
227 if (a1
->iabuf
[i
] < a2
->iabuf
[i
]) {
230 if (a1
->iabuf
[i
] > a2
->iabuf
[i
]) {
239 * Performs a bitwise-OR of two addresses.
241 * Returns 1 if the result is non-zero, or 0 otherwise.
243 * WARNING: if a1 and a2 differ in length, returns 0.
246 addr_or(struct iaddr
*result
, const struct iaddr
*a1
, const struct iaddr
*a2
) {
250 if (a1
->len
!= a2
->len
) {
256 result
->len
= a1
->len
;
257 for (i
=0; i
<a1
->len
; i
++) {
258 result
->iabuf
[i
] = a1
->iabuf
[i
] | a2
->iabuf
[i
];
259 if (result
->iabuf
[i
] != 0) {
268 * Performs a bitwise-AND of two addresses.
270 * Returns 1 if the result is non-zero, or 0 otherwise.
272 * WARNING: if a1 and a2 differ in length, returns 0.
275 addr_and(struct iaddr
*result
, const struct iaddr
*a1
, const struct iaddr
*a2
) {
279 if (a1
->len
!= a2
->len
) {
285 result
->len
= a1
->len
;
286 for (i
=0; i
<a1
->len
; i
++) {
287 result
->iabuf
[i
] = a1
->iabuf
[i
] & a2
->iabuf
[i
];
288 if (result
->iabuf
[i
] != 0) {
297 * Check if a bitmask of the given length is valid for the address.
298 * This is not the case if any bits longer than the bitmask are 1.
308 * Because the final ".1" would get masked out by the /8.
311 is_cidr_mask_valid(const struct iaddr
*addr
, int bits
) {
319 * Check our bit boundaries.
324 if (bits
> (addr
->len
* 8)) {
329 * Figure out how many low-order bits need to be zero.
331 zero_bits
= (addr
->len
* 8) - bits
;
332 zero_bytes
= zero_bits
/ 8;
335 * Check to make sure the low-order bytes are zero.
337 for (i
=1; i
<=zero_bytes
; i
++) {
338 if (addr
->iabuf
[addr
->len
-i
] != 0) {
344 * Look to see if any bits not in right-hand bytes are
345 * non-zero, by making a byte that has these bits set to zero
346 * comparing to the original byte. If these two values are
347 * equal, then the right-hand bits are zero, and we are
350 shift_bits
= zero_bits
% 8;
351 if (shift_bits
== 0) return ISC_TRUE
;
352 byte
= addr
->iabuf
[addr
->len
-zero_bytes
-1];
353 return (((byte
>> shift_bits
) << shift_bits
) == byte
);
359 * Converts a range of IP addresses to a set of CIDR networks.
362 * 192.168.0.0 - 192.168.0.255 = 192.168.0.0/24
363 * 10.0.0.0 - 10.0.1.127 = 10.0.0.0/24, 10.0.1.0/25
364 * 255.255.255.32 - 255.255.255.255 = 255.255.255.32/27, 255.255.255.64/26,
368 range2cidr(struct iaddrcidrnetlist
**result
,
369 const struct iaddr
*lo
, const struct iaddr
*hi
) {
373 struct iaddr end_addr
;
376 struct iaddrcidrnetlist
*net
;
379 if (result
== NULL
) {
380 return DHCP_R_INVALIDARG
;
382 if (*result
!= NULL
) {
383 return DHCP_R_INVALIDARG
;
385 if ((lo
== NULL
) || (hi
== NULL
) || (lo
->len
!= hi
->len
)) {
386 return DHCP_R_INVALIDARG
;
390 * Put our start and end in the right order, if reversed.
392 if (addr_cmp(lo
, hi
) > 0) {
393 const struct iaddr
*tmp
;
400 * Theory of operation:
402 * -------------------
403 * Start at the low end, and keep trying larger networks
404 * until we get one that is too big (explained below).
406 * We keep a "mask", which is the ones-complement of a
407 * normal netmask. So, a /23 has a netmask of 255.255.254.0,
408 * and a mask of 0.0.1.255.
410 * We know when a network is too big when we bitwise-AND the
411 * mask with the starting address and we get a non-zero
414 * addr: 192.168.1.0, mask: 0.0.1.255
415 * bitwise-AND: 0.0.1.0
417 * A network is also too big if the bitwise-OR of the mask
418 * with the starting address is larger than the end address,
421 * start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255
422 * bitwise-OR: 192.168.1.255
424 * -------------------
425 * Once we have found a network that is too big, we add the
426 * appropriate CIDR network to our list of found networks.
428 * We then use the next IP address as our low address, and
429 * begin the process of searching for a network that is
430 * too big again, starting with an empty mask.
434 memset(&mask
, 0, sizeof(mask
));
436 while (addr_cmp(&addr
, hi
) <= 0) {
438 * Bitwise-OR mask with (1 << bit)
440 ofs
= addr
.len
- (bit
/ 8) - 1;
441 val
= 1 << (bit
% 8);
443 mask
.iabuf
[ofs
] |= val
;
447 * See if we're too big, and save this network if so.
449 addr_or(&end_addr
, &addr
, &mask
);
451 (addr_cmp(&end_addr
, hi
) > 0) ||
452 addr_and(&dummy
, &addr
, &mask
)) {
454 * Add a new prefix to our list.
456 net
= dmalloc(sizeof(*net
), MDL
);
458 while (*result
!= NULL
) {
459 net
= (*result
)->next
;
463 return ISC_R_NOMEMORY
;
465 net
->cidrnet
.lo_addr
= addr
;
466 net
->cidrnet
.bits
= (addr
.len
* 8) - bit
;
471 * Figure out our new starting address,
472 * by adding (1 << bit) to our previous
475 tmp
= addr
.iabuf
[ofs
] + val
;
476 while ((ofs
>= 0) && (tmp
> 255)) {
477 addr
.iabuf
[ofs
] = tmp
- 256;
479 tmp
= addr
.iabuf
[ofs
] + 1;
482 /* Gone past last address, we're done. */
485 addr
.iabuf
[ofs
] = tmp
;
488 * Reset our bit and mask.
491 memset(mask
.iabuf
, 0, sizeof(mask
.iabuf
));
492 memset(end_addr
.iabuf
, 0, sizeof(end_addr
.iabuf
));
495 * If we're not too big, increase our network size.
504 return ISC_R_SUCCESS
;
508 * Free a list of CIDR networks, such as returned from range2cidr().
511 free_iaddrcidrnetlist(struct iaddrcidrnetlist
**result
) {
512 struct iaddrcidrnetlist
*p
;
514 if (result
== NULL
) {
515 return DHCP_R_INVALIDARG
;
517 if (*result
== NULL
) {
518 return DHCP_R_INVALIDARG
;
521 while (*result
!= NULL
) {
527 return ISC_R_SUCCESS
;
530 /* piaddr() turns an iaddr structure into a printable address. */
531 /* XXX: should use a const pointer rather than passing the structure */
533 piaddr(const struct iaddr addr
) {
535 pbuf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
536 /* "255.255.255.255" */
538 /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */
541 return "<null address>";
544 return inet_ntop(AF_INET
, addr
.iabuf
, pbuf
, sizeof(pbuf
));
546 if (addr
.len
== 16) {
547 return inet_ntop(AF_INET6
, addr
.iabuf
, pbuf
, sizeof(pbuf
));
550 log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL
,
552 /* quell compiler warnings */
556 /* piaddrmask takes an iaddr structure mask, determines the bitlength of
557 * the mask, and then returns the printable CIDR notation of the two.
560 piaddrmask(struct iaddr
*addr
, struct iaddr
*mask
) {
562 unsigned int oct
, bit
;
564 if ((addr
->len
!= 4) && (addr
->len
!= 16))
565 log_fatal("piaddrmask():%s:%d: Address length %d invalid",
567 if (addr
->len
!= mask
->len
)
568 log_fatal("piaddrmask():%s:%d: Address and mask size mismatch",
571 /* Determine netmask width in bits. */
572 for (mw
= (mask
->len
* 8) ; mw
> 0 ; ) {
574 bit
= 0x80 >> ((mw
- 1) % 8);
575 if (!mask
->iabuf
[oct
])
577 else if (mask
->iabuf
[oct
] & bit
)
584 log_fatal("Impossible condition at %s:%d.", MDL
);
586 return piaddrcidr(addr
, mw
);
589 /* Format an address and mask-length into printable CIDR notation. */
591 piaddrcidr(const struct iaddr
*addr
, unsigned int bits
) {
593 ret
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")];
594 /* "255.255.255.255/32" */
596 /* INSIST(addr != NULL); */
597 /* INSIST((addr->len == 4) || (addr->len == 16)); */
598 /* INSIST(bits <= (addr->len * 8)); */
600 if (bits
> (addr
->len
* 8))
603 sprintf(ret
, "%s/%d", piaddr(*addr
), bits
);
608 /* Validate that the string represents a valid port number and
609 * return it in network byte order
613 validate_port(char *port
) {
620 local_port
= strtol(port
, &endptr
, 10);
622 if ((*endptr
!= '\0') || (errno
== ERANGE
) || (errno
== EINVAL
))
623 log_fatal ("Invalid port number specification: %s", port
);
625 if (local_port
< lower
|| local_port
> upper
)
626 log_fatal("Port number specified is out of range (%ld-%ld).",
629 return htons((u_int16_t
)local_port
);