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