1 // Copyright (C) 2006-2010 David Sugar, Tycho Softworks
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 //
17 // As a special exception, you may use this file as part of a free software
18 // library without restriction. Specifically, if other files instantiate
19 // templates or use macros or inline functions from this file, or you compile
20 // this file and link it with other files to produce an executable, this
21 // file does not by itself cause the resulting executable to be covered by
22 // the GNU General Public License. This exception does not however
23 // invalidate any other reasons why the executable file might be covered by
24 // the GNU General Public License.
25 //
26 // This exception applies only to the code released under the name GNU
27 // Common C++. If you copy code from other releases into a copy of GNU
28 // Common C++, as the General Public License permits, the exception does
29 // not apply to the code that you add in this way. To avoid misleading
30 // anyone as to the status of such modified files, you must delete
31 // this exception notice from them.
32 //
33 // If you write modifications of your own for GNU Common C++, it is your choice
34 // whether to permit this exception to apply to your modifications.
35 // If you do not wish that, delete this exception notice.
36 //
37
38 #include <cc++/config.h>
39 #include <cc++/export.h>
40 #include <cc++/address.h>
41 #include "private.h"
42 #include <cstdlib>
43 #include <fcntl.h>
44 #include <cstdio>
45
46
47 #ifdef CCXX_NAMESPACES
48 namespace ost {
49 #endif
50
51 typedef unsigned char bit_t;
52
bitmask(bit_t * bits,bit_t * mask,unsigned len)53 static void bitmask(bit_t *bits, bit_t *mask, unsigned len)
54 {
55 while(len--)
56 *(bits++) &= *(mask++);
57 }
58
bitimask(bit_t * bits,bit_t * mask,unsigned len)59 static void bitimask(bit_t *bits, bit_t *mask, unsigned len)
60 {
61 while(len--)
62 *(bits++) |= ~(*(mask++));
63 }
64
bitset(bit_t * bits,unsigned blen)65 static void bitset(bit_t *bits, unsigned blen)
66 {
67 bit_t mask;
68
69 while(blen) {
70 mask = (bit_t)(1 << 7);
71 while(mask && blen) {
72 *bits |= mask;
73 mask >>= 1;
74 --blen;
75 }
76 ++bits;
77 }
78 }
79
bitcount(bit_t * bits,unsigned len)80 static unsigned bitcount(bit_t *bits, unsigned len)
81 {
82 unsigned count = 0;
83 bit_t mask, test;
84
85 while(len--) {
86 mask = (bit_t)(1<<7);
87 test = *bits++;
88 while(mask) {
89 if(!(mask & test))
90 return count;
91 ++count;
92 mask >>= 1;
93 }
94 }
95 return count;
96 }
97
IPV4Cidr()98 IPV4Cidr::IPV4Cidr()
99 {
100 memset(&network, 0, sizeof(network));
101 memset(&netmask, 0, sizeof(netmask));
102 }
103
IPV4Cidr(const char * cp)104 IPV4Cidr::IPV4Cidr(const char *cp)
105 {
106 set(cp);
107 }
108
IPV4Cidr(IPV4Cidr & cidr)109 IPV4Cidr::IPV4Cidr(IPV4Cidr &cidr)
110 {
111 memcpy(&network, &cidr.network, sizeof(network));
112 memcpy(&netmask, &cidr.netmask, sizeof(netmask));
113 }
114
isMember(const struct in_addr & addr) const115 bool IPV4Cidr::isMember(const struct in_addr &addr) const
116 {
117 struct in_addr host = addr;
118
119 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
120 if(!memcmp(&host, &network, sizeof(host)))
121 return true;
122
123 return false;
124 }
125
isMember(const struct sockaddr * saddr) const126 bool IPV4Cidr::isMember(const struct sockaddr *saddr) const
127 {
128 struct sockaddr_in *addr = (struct sockaddr_in *)saddr;
129 struct in_addr host;
130
131 if(saddr->sa_family != AF_INET)
132 return false;
133
134 memcpy(&host, &addr->sin_addr.s_addr, sizeof(host));
135 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
136 if(!memcmp(&host, &network, sizeof(host)))
137 return true;
138
139 return false;
140 }
141
getBroadcast(void) const142 struct in_addr IPV4Cidr::getBroadcast(void) const
143 {
144 struct in_addr bcast;
145 memcpy(&bcast, &network, sizeof(network));
146 bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast));
147 return bcast;
148 }
149
getMask(const char * cp) const150 unsigned IPV4Cidr::getMask(const char *cp) const
151 {
152 unsigned dcount = 0;
153 const char *gp = cp;
154 const char *mp = strchr(cp, '/');
155 unsigned char dots[4];
156 #ifdef WIN32
157 DWORD mask;
158 #else
159 uint32 mask;
160 #endif
161
162 if(mp) {
163 if(!strchr(++mp, '.'))
164 return atoi(mp);
165
166 mask = inet_addr(mp);
167 return bitcount((bit_t *)&mask, sizeof(mask));
168 }
169
170 memset(dots, 0, sizeof(dots));
171 dots[0] = atoi(cp);
172 while(*gp && dcount < 3) {
173 if(*(gp++) == '.')
174 dots[++dcount] = atoi(gp);
175 }
176
177 if(dots[3])
178 return 32;
179
180 if(dots[2])
181 return 24;
182
183 if(dots[1])
184 return 16;
185
186 return 8;
187 }
188
set(const char * cp)189 void IPV4Cidr::set(const char *cp)
190 {
191 char cbuf[INET_IPV4_ADDRESS_SIZE];
192 char *ep;
193 unsigned dots = 0;
194 #ifdef WIN32
195 DWORD addr;
196 #endif
197
198 memset(&netmask, 0, sizeof(netmask));
199 bitset((bit_t *)&netmask, getMask(cp));
200 setString(cbuf, sizeof(cbuf), cp);
201
202 ep = (char *)strchr(cp, '/');
203
204 if(ep)
205 *ep = 0;
206
207 cp = cbuf;
208 while(NULL != (cp = strchr(cp, '.'))) {
209 ++dots;
210 ++cp;
211 }
212
213 while(dots++ < 3)
214 addString(cbuf, sizeof(cbuf), ".0");
215
216 #ifdef WIN32
217 addr = inet_addr(cbuf);
218 memcpy(&network, &addr, sizeof(network));
219 #else
220 inet_aton(cbuf, &network);
221 #endif
222 bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network));
223 }
224
225
226
227
228 #ifdef CCXX_IPV6
229
IPV6Cidr()230 IPV6Cidr::IPV6Cidr()
231 {
232 memset(&network, 0, sizeof(network));
233 memset(&netmask, 0, sizeof(netmask));
234 }
235
IPV6Cidr(const char * cp)236 IPV6Cidr::IPV6Cidr(const char *cp)
237 {
238 set(cp);
239 }
240
IPV6Cidr(IPV6Cidr & cidr)241 IPV6Cidr::IPV6Cidr(IPV6Cidr &cidr)
242 {
243 memcpy(&network, &cidr.network, sizeof(network));
244 memcpy(&netmask, &cidr.netmask, sizeof(netmask));
245 }
246
isMember(const struct in6_addr & addr) const247 bool IPV6Cidr::isMember(const struct in6_addr &addr) const
248 {
249 struct in6_addr host = addr;
250
251 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
252 if(!memcmp(&host, &network, sizeof(host)))
253 return true;
254
255 return false;
256 }
257
isMember(const struct sockaddr * saddr) const258 bool IPV6Cidr::isMember(const struct sockaddr *saddr) const
259 {
260 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)saddr;
261 struct in6_addr host;
262
263 if(saddr->sa_family != AF_INET6)
264 return false;
265
266 memcpy(&host, &addr->sin6_addr, sizeof(host));
267 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
268 if(!memcmp(&host, &network, sizeof(host)))
269 return true;
270
271 return false;
272 }
273
getBroadcast(void) const274 struct in6_addr IPV6Cidr::getBroadcast(void) const
275 {
276 struct in6_addr bcast;
277 memcpy(&bcast, &network, sizeof(network));
278 bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast));
279 return bcast;
280 }
281
getMask(const char * cp) const282 unsigned IPV6Cidr::getMask(const char *cp) const
283 {
284 unsigned count = 0, rcount = 0;
285 const char *sp = strchr(cp, '/');
286 int flag = 0;
287
288 if(sp)
289 return atoi(++sp);
290
291 if(!strncmp(cp, "ff00:", 5))
292 return 8;
293
294 if(!strncmp(cp, "fe80:", 5))
295 return 10;
296
297 if(!strncmp(cp, "2002:", 5))
298 return 16;
299
300 sp = strrchr(cp, ':');
301 while(*(++sp) == '0')
302 ++sp;
303 if(*sp)
304 return 128;
305
306 while(*cp && count < 128) {
307 if(*(cp++) == ':') {
308 count+= 16;
309 while(*cp == '0')
310 ++cp;
311 if(*cp == ':') {
312 if(!flag)
313 rcount = count;
314 flag = 1;
315 }
316 else
317 flag = 0;
318 }
319 }
320 return rcount;
321 }
322
set(const char * cp)323 void IPV6Cidr::set(const char *cp)
324 {
325 char cbuf[INET_IPV6_ADDRESS_SIZE];
326 char *ep;
327
328 memset(&netmask, 0, sizeof(netmask));
329 bitset((bit_t *)&netmask, getMask(cp));
330 setString(cbuf, sizeof(cbuf), cp);
331 ep = (char *)strchr(cp, '/');
332 if(ep)
333 *ep = 0;
334
335 inet_pton(AF_INET6, cbuf, &network);
336 bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network));
337 }
338
339 #endif
340
341 #ifdef CCXX_NAMESPACES
342 }
343 #endif
344
345 /** EMACS **
346 * Local variables:
347 * mode: c++
348 * c-basic-offset: 4
349 * End:
350 */
351