]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/inet.c
- Silence benign static analysis warnings.
[thirdparty/dhcp.git] / common / inet.c
1 /* inet.c
2
3 Subroutines to manipulate internet addresses and ports in a safely portable
4 way... */
5
6 /*
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
11 *
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.
15 *
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.
23 *
24 * Internet Systems Consortium, Inc.
25 * 950 Charter Street
26 * Redwood City, CA 94063
27 * <info@isc.org>
28 * https://www.isc.org/
29 *
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''.
36 */
37
38 #include "dhcpd.h"
39
40 /* Return just the network number of an internet address... */
41
42 struct iaddr subnet_number (addr, mask)
43 struct iaddr addr;
44 struct iaddr mask;
45 {
46 int i;
47 struct iaddr rv;
48
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.",
53 MDL);
54
55 rv.len = 0;
56
57 /* Both addresses must have the same length... */
58 if (addr.len != mask.len)
59 return rv;
60
61 rv.len = addr.len;
62 for (i = 0; i < rv.len; i++)
63 rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i];
64 return rv;
65 }
66
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. */
70
71 struct iaddr ip_addr (subnet, mask, host_address)
72 struct iaddr subnet;
73 struct iaddr mask;
74 u_int32_t host_address;
75 {
76 int i, j, k;
77 u_int32_t swaddr;
78 struct iaddr rv;
79 unsigned char habuf [sizeof swaddr];
80
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.",
85 MDL);
86
87 swaddr = htonl (host_address);
88 memcpy (habuf, &swaddr, sizeof swaddr);
89
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. */
93 rv = subnet;
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)) {
98 rv.len = 0;
99 return rv;
100 }
101 for (k = i - 1; k >= 0; k--) {
102 if (habuf [k]) {
103 rv.len = 0;
104 return rv;
105 }
106 }
107 rv.iabuf [i + j] |= habuf [i];
108 break;
109 } else
110 rv.iabuf [i + j] = habuf [i];
111 }
112
113 return rv;
114 }
115
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). */
119
120 struct iaddr broadcast_addr (subnet, mask)
121 struct iaddr subnet;
122 struct iaddr mask;
123 {
124 int i;
125 struct iaddr rv;
126
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.",
131 MDL);
132
133 if (subnet.len != mask.len) {
134 rv.len = 0;
135 return rv;
136 }
137
138 for (i = 0; i < subnet.len; i++) {
139 rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255);
140 }
141 rv.len = subnet.len;
142
143 return rv;
144 }
145
146 u_int32_t host_addr (addr, mask)
147 struct iaddr addr;
148 struct iaddr mask;
149 {
150 int i;
151 u_int32_t swaddr;
152 struct iaddr rv;
153
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.",
158 MDL);
159
160 rv.len = 0;
161
162 /* Mask out the network bits... */
163 rv.len = addr.len;
164 for (i = 0; i < rv.len; i++)
165 rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i];
166
167 /* Copy out up to 32 bits... */
168 memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr);
169
170 /* Swap it and return it. */
171 return ntohl (swaddr);
172 }
173
174 int addr_eq (addr1, addr2)
175 struct iaddr addr1, addr2;
176 {
177 if (addr1.len > sizeof(addr1.iabuf))
178 log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL);
179
180 if (addr1.len != addr2.len)
181 return 0;
182 return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
183 }
184
185 /* addr_match
186 *
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.
190 */
191 int
192 addr_match(addr, match)
193 struct iaddr *addr;
194 struct iaddrmatch *match;
195 {
196 int i;
197
198 if (addr->len != match->addr.len)
199 return 0;
200
201 for (i = 0 ; i < addr->len ; i++) {
202 if ((addr->iabuf[i] & match->mask.iabuf[i]) !=
203 match->addr.iabuf[i])
204 return 0;
205 }
206 return 1;
207 }
208
209 /*
210 * Compares the addresses a1 and a2.
211 *
212 * If a1 < a2, returns -1.
213 * If a1 == a2, returns 0.
214 * If a1 > a2, returns 1.
215 *
216 * WARNING: if a1 and a2 differ in length, returns 0.
217 */
218 int
219 addr_cmp(const struct iaddr *a1, const struct iaddr *a2) {
220 int i;
221
222 if (a1->len != a2->len) {
223 return 0;
224 }
225
226 for (i=0; i<a1->len; i++) {
227 if (a1->iabuf[i] < a2->iabuf[i]) {
228 return -1;
229 }
230 if (a1->iabuf[i] > a2->iabuf[i]) {
231 return 1;
232 }
233 }
234
235 return 0;
236 }
237
238 /*
239 * Performs a bitwise-OR of two addresses.
240 *
241 * Returns 1 if the result is non-zero, or 0 otherwise.
242 *
243 * WARNING: if a1 and a2 differ in length, returns 0.
244 */
245 int
246 addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
247 int i;
248 int all_zero;
249
250 if (a1->len != a2->len) {
251 return 0;
252 }
253
254 all_zero = 1;
255
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) {
260 all_zero = 0;
261 }
262 }
263
264 return !all_zero;
265 }
266
267 /*
268 * Performs a bitwise-AND of two addresses.
269 *
270 * Returns 1 if the result is non-zero, or 0 otherwise.
271 *
272 * WARNING: if a1 and a2 differ in length, returns 0.
273 */
274 int
275 addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
276 int i;
277 int all_zero;
278
279 if (a1->len != a2->len) {
280 return 0;
281 }
282
283 all_zero = 1;
284
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) {
289 all_zero = 0;
290 }
291 }
292
293 return !all_zero;
294 }
295
296 /*
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.
299 *
300 * So, this is valid:
301 *
302 * 127.0.0.0/8
303 *
304 * But this is not:
305 *
306 * 127.0.0.1/8
307 *
308 * Because the final ".1" would get masked out by the /8.
309 */
310 isc_boolean_t
311 is_cidr_mask_valid(const struct iaddr *addr, int bits) {
312 int zero_bits;
313 int zero_bytes;
314 int i;
315 char byte;
316 int shift_bits;
317
318 /*
319 * Check our bit boundaries.
320 */
321 if (bits < 0) {
322 return ISC_FALSE;
323 }
324 if (bits > (addr->len * 8)) {
325 return ISC_FALSE;
326 }
327
328 /*
329 * Figure out how many low-order bits need to be zero.
330 */
331 zero_bits = (addr->len * 8) - bits;
332 zero_bytes = zero_bits / 8;
333
334 /*
335 * Check to make sure the low-order bytes are zero.
336 */
337 for (i=1; i<=zero_bytes; i++) {
338 if (addr->iabuf[addr->len-i] != 0) {
339 return ISC_FALSE;
340 }
341 }
342
343 /*
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
348 * happy.
349 */
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);
354 }
355
356 /*
357 * range2cidr
358 *
359 * Converts a range of IP addresses to a set of CIDR networks.
360 *
361 * Examples:
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,
365 * 255.255.255.128/25
366 */
367 isc_result_t
368 range2cidr(struct iaddrcidrnetlist **result,
369 const struct iaddr *lo, const struct iaddr *hi) {
370 struct iaddr addr;
371 struct iaddr mask;
372 int bit;
373 struct iaddr end_addr;
374 struct iaddr dummy;
375 int ofs, val;
376 struct iaddrcidrnetlist *net;
377 int tmp;
378
379 if (result == NULL) {
380 return DHCP_R_INVALIDARG;
381 }
382 if (*result != NULL) {
383 return DHCP_R_INVALIDARG;
384 }
385 if ((lo == NULL) || (hi == NULL) || (lo->len != hi->len)) {
386 return DHCP_R_INVALIDARG;
387 }
388
389 /*
390 * Put our start and end in the right order, if reversed.
391 */
392 if (addr_cmp(lo, hi) > 0) {
393 const struct iaddr *tmp;
394 tmp = lo;
395 lo = hi;
396 hi = tmp;
397 }
398
399 /*
400 * Theory of operation:
401 *
402 * -------------------
403 * Start at the low end, and keep trying larger networks
404 * until we get one that is too big (explained below).
405 *
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.
409 *
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
412 * result, like this:
413 *
414 * addr: 192.168.1.0, mask: 0.0.1.255
415 * bitwise-AND: 0.0.1.0
416 *
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,
419 * like this:
420 *
421 * start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255
422 * bitwise-OR: 192.168.1.255
423 *
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.
427 *
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.
431 */
432 addr = *lo;
433 bit = 0;
434 memset(&mask, 0, sizeof(mask));
435 mask.len = addr.len;
436 while (addr_cmp(&addr, hi) <= 0) {
437 /*
438 * Bitwise-OR mask with (1 << bit)
439 */
440 ofs = addr.len - (bit / 8) - 1;
441 val = 1 << (bit % 8);
442 if (ofs >= 0) {
443 mask.iabuf[ofs] |= val;
444 }
445
446 /*
447 * See if we're too big, and save this network if so.
448 */
449 addr_or(&end_addr, &addr, &mask);
450 if ((ofs < 0) ||
451 (addr_cmp(&end_addr, hi) > 0) ||
452 addr_and(&dummy, &addr, &mask)) {
453 /*
454 * Add a new prefix to our list.
455 */
456 net = dmalloc(sizeof(*net), MDL);
457 if (net == NULL) {
458 while (*result != NULL) {
459 net = (*result)->next;
460 dfree(*result, MDL);
461 *result = net;
462 }
463 return ISC_R_NOMEMORY;
464 }
465 net->cidrnet.lo_addr = addr;
466 net->cidrnet.bits = (addr.len * 8) - bit;
467 net->next = *result;
468 *result = net;
469
470 /*
471 * Figure out our new starting address,
472 * by adding (1 << bit) to our previous
473 * starting address.
474 */
475 tmp = addr.iabuf[ofs] + val;
476 while ((ofs >= 0) && (tmp > 255)) {
477 addr.iabuf[ofs] = tmp - 256;
478 ofs--;
479 tmp = addr.iabuf[ofs] + 1;
480 }
481 if (ofs < 0) {
482 /* Gone past last address, we're done. */
483 break;
484 }
485 addr.iabuf[ofs] = tmp;
486
487 /*
488 * Reset our bit and mask.
489 */
490 bit = 0;
491 memset(mask.iabuf, 0, sizeof(mask.iabuf));
492 memset(end_addr.iabuf, 0, sizeof(end_addr.iabuf));
493 } else {
494 /*
495 * If we're not too big, increase our network size.
496 */
497 bit++;
498 }
499 }
500
501 /*
502 * We're done.
503 */
504 return ISC_R_SUCCESS;
505 }
506
507 /*
508 * Free a list of CIDR networks, such as returned from range2cidr().
509 */
510 isc_result_t
511 free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) {
512 struct iaddrcidrnetlist *p;
513
514 if (result == NULL) {
515 return DHCP_R_INVALIDARG;
516 }
517 if (*result == NULL) {
518 return DHCP_R_INVALIDARG;
519 }
520
521 while (*result != NULL) {
522 p = *result;
523 *result = p->next;
524 dfree(p, MDL);
525 }
526
527 return ISC_R_SUCCESS;
528 }
529
530 /* piaddr() turns an iaddr structure into a printable address. */
531 /* XXX: should use a const pointer rather than passing the structure */
532 const char *
533 piaddr(const struct iaddr addr) {
534 static char
535 pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
536 /* "255.255.255.255" */
537
538 /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */
539
540 if (addr.len == 0) {
541 return "<null address>";
542 }
543 if (addr.len == 4) {
544 return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf));
545 }
546 if (addr.len == 16) {
547 return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf));
548 }
549
550 log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL,
551 addr.len);
552 /* quell compiler warnings */
553 return NULL;
554 }
555
556 /* piaddrmask takes an iaddr structure mask, determines the bitlength of
557 * the mask, and then returns the printable CIDR notation of the two.
558 */
559 char *
560 piaddrmask(struct iaddr *addr, struct iaddr *mask) {
561 int mw;
562 unsigned int oct, bit;
563
564 if ((addr->len != 4) && (addr->len != 16))
565 log_fatal("piaddrmask():%s:%d: Address length %d invalid",
566 MDL, addr->len);
567 if (addr->len != mask->len)
568 log_fatal("piaddrmask():%s:%d: Address and mask size mismatch",
569 MDL);
570
571 /* Determine netmask width in bits. */
572 for (mw = (mask->len * 8) ; mw > 0 ; ) {
573 oct = (mw - 1) / 8;
574 bit = 0x80 >> ((mw - 1) % 8);
575 if (!mask->iabuf[oct])
576 mw -= 8;
577 else if (mask->iabuf[oct] & bit)
578 break;
579 else
580 mw--;
581 }
582
583 if (mw < 0)
584 log_fatal("Impossible condition at %s:%d.", MDL);
585
586 return piaddrcidr(addr, mw);
587 }
588
589 /* Format an address and mask-length into printable CIDR notation. */
590 char *
591 piaddrcidr(const struct iaddr *addr, unsigned int bits) {
592 static char
593 ret[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")];
594 /* "255.255.255.255/32" */
595
596 /* INSIST(addr != NULL); */
597 /* INSIST((addr->len == 4) || (addr->len == 16)); */
598 /* INSIST(bits <= (addr->len * 8)); */
599
600 if (bits > (addr->len * 8))
601 return NULL;
602
603 sprintf(ret, "%s/%d", piaddr(*addr), bits);
604
605 return ret;
606 }
607
608 /* Validate that the string represents a valid port number and
609 * return it in network byte order
610 */
611
612 u_int16_t
613 validate_port(char *port) {
614 long local_port = 0;
615 long lower = 1;
616 long upper = 65535;
617 char *endptr;
618
619 errno = 0;
620 local_port = strtol(port, &endptr, 10);
621
622 if ((*endptr != '\0') || (errno == ERANGE) || (errno == EINVAL))
623 log_fatal ("Invalid port number specification: %s", port);
624
625 if (local_port < lower || local_port > upper)
626 log_fatal("Port number specified is out of range (%ld-%ld).",
627 lower, upper);
628
629 return htons((u_int16_t)local_port);
630 }