blob: 2420e6738ea37df9dc7a8d6a10cffc7895a8da81 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// 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
48namespace ost {
49#endif
50
51typedef unsigned char bit_t;
52
53static void bitmask(bit_t *bits, bit_t *mask, unsigned len)
54{
55 while(len--)
56 *(bits++) &= *(mask++);
57}
58
59static void bitimask(bit_t *bits, bit_t *mask, unsigned len)
60{
61 while(len--)
62 *(bits++) |= ~(*(mask++));
63}
64
65static 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
80static 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
98IPV4Cidr::IPV4Cidr()
99{
100 memset(&network, 0, sizeof(network));
101 memset(&netmask, 0, sizeof(netmask));
102}
103
104IPV4Cidr::IPV4Cidr(const char *cp)
105{
106 set(cp);
107}
108
109IPV4Cidr::IPV4Cidr(IPV4Cidr &cidr)
110{
111 memcpy(&network, &cidr.network, sizeof(network));
112 memcpy(&netmask, &cidr.netmask, sizeof(netmask));
113}
114
115bool 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
126bool 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
142struct 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
150unsigned 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
189void 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
230IPV6Cidr::IPV6Cidr()
231{
232 memset(&network, 0, sizeof(network));
233 memset(&netmask, 0, sizeof(netmask));
234}
235
236IPV6Cidr::IPV6Cidr(const char *cp)
237{
238 set(cp);
239}
240
241IPV6Cidr::IPV6Cidr(IPV6Cidr &cidr)
242{
243 memcpy(&network, &cidr.network, sizeof(network));
244 memcpy(&netmask, &cidr.netmask, sizeof(netmask));
245}
246
247bool 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
258bool 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
274struct 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
282unsigned 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
323void 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 */