Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / isc-dhcp / common / inet.c
1 /* inet.c
2
3    Subroutines to manipulate internet addresses in a safely portable
4    way... */
5
6 /*
7  * Copyright (c) 1995-2002 Internet Software Consortium.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of The Internet Software Consortium nor the names
20  *    of its contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * This software has been written for the Internet Software Consortium
38  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
39  * To learn more about the Internet Software Consortium, see
40  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
41  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
42  * ``http://www.nominum.com''.
43  */
44
45 #ifndef lint
46 static char copyright[] =
47 "$Id: inet.c,v 1.8.2.4 2002/11/17 02:26:58 dhankins Exp $ Copyright (c) 1995-2002 The Internet Software Consortium.  All rights reserved.\n";
48 #endif /* not lint */
49
50 #include "dhcpd.h"
51
52 /* Return just the network number of an internet address... */
53
54 struct iaddr subnet_number (addr, mask)
55         struct iaddr addr;
56         struct iaddr mask;
57 {
58         int i;
59         struct iaddr rv;
60
61         rv.len = 0;
62
63         /* Both addresses must have the same length... */
64         if (addr.len != mask.len)
65                 return rv;
66
67         rv.len = addr.len;
68         for (i = 0; i < rv.len; i++)
69                 rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i];
70         return rv;
71 }
72
73 /* Combine a network number and a integer to produce an internet address.
74    This won't work for subnets with more than 32 bits of host address, but
75    maybe this isn't a problem. */
76
77 struct iaddr ip_addr (subnet, mask, host_address)
78         struct iaddr subnet;
79         struct iaddr mask;
80         u_int32_t host_address;
81 {
82         int i, j, k;
83         u_int32_t swaddr;
84         struct iaddr rv;
85         unsigned char habuf [sizeof swaddr];
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, j, k;
125         struct iaddr rv;
126
127         if (subnet.len != mask.len) {
128                 rv.len = 0;
129                 return rv;
130         }
131
132         for (i = 0; i < subnet.len; i++) {
133                 rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255);
134         }
135         rv.len = subnet.len;
136
137         return rv;
138 }
139
140 u_int32_t host_addr (addr, mask)
141         struct iaddr addr;
142         struct iaddr mask;
143 {
144         int i;
145         u_int32_t swaddr;
146         struct iaddr rv;
147
148         rv.len = 0;
149
150         /* Mask out the network bits... */
151         rv.len = addr.len;
152         for (i = 0; i < rv.len; i++)
153                 rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i];
154
155         /* Copy out up to 32 bits... */
156         memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr);
157
158         /* Swap it and return it. */
159         return ntohl (swaddr);
160 }
161
162 int addr_eq (addr1, addr2)
163         struct iaddr addr1, addr2;
164 {
165         if (addr1.len != addr2.len)
166                 return 0;
167         return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
168 }
169
170 char *piaddr (addr)
171         struct iaddr addr;
172 {
173         static char pbuf [4 * 16];
174         char *s = pbuf;
175         int i;
176
177         if (addr.len == 0) {
178                 strcpy (s, "<null address>");
179         }
180         for (i = 0; i < addr.len; i++) {
181                 sprintf (s, "%s%d", i ? "." : "", addr.iabuf [i]);
182                 s += strlen (s);
183         }
184         return pbuf;
185 }
186
187 char *piaddr1 (addr)
188         struct iaddr addr;
189 {
190         static char pbuf [4 * 16];
191         char *s = pbuf;
192         int i;
193
194         if (addr.len == 0) {
195                 strcpy (s, "<null address>");
196         }
197         for (i = 0; i < addr.len; i++) {
198                 sprintf (s, "%s%d", i ? "." : "", addr.iabuf [i]);
199                 s += strlen (s);
200         }
201         return pbuf;
202 }
203
204 char *piaddrmask (struct iaddr addr, struct iaddr mask,
205                   const char *file, int line)
206 {
207         char *s, *t;
208         int i, mw;
209         unsigned len;
210
211         for (i = 0; i < 32; i++) {
212                 if (!mask.iabuf [3 - i / 8])
213                         i += 7;
214                 else if (mask.iabuf [3 - i / 8] & (1 << (i % 8)))
215                         break;
216         }
217         mw = 32 - i;
218         len = mw > 9 ? 2 : 1;
219         len += 4;       /* three dots and a slash. */
220         for (i = 0; i < (mw / 8) + 1; i++) {
221                 if (addr.iabuf [i] > 99)
222                         len += 3;
223                 else if (addr.iabuf [i] > 9)
224                         len += 2;
225                 else
226                         len++;
227         }
228         s = dmalloc (len + 1, file, line);
229         if (!s)
230                 return s;
231         t = s;
232         sprintf (t, "%d", addr.iabuf [0]);
233         t += strlen (t);
234         for (i = 1; i < (mw / 8) + 1; i++) {
235                 sprintf (t, ".%d", addr.iabuf [i]);
236                 t += strlen (t);
237         }
238         *t++ = '/';
239         sprintf (t, "%d", mw);
240         return s;
241 }
242