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