1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2008 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.org
8 
9   $Id$
10 
11 
12   This program is free software which we release under the GNU General Public
13   License. You may redistribute and/or modify this program under the terms
14   of that license as published by the Free Software Foundation; either
15   version 2 of the License, or (at your option) any later version.
16 
17   This program is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   GNU General Public License for more details.
21 
22   To get a copy of the GNU General Public License, write to the Free Software
23   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 
25 */
26 
27 #include "config.h"
28 #include "fwbuilder/libfwbuilder-config.h"
29 
30 
31 #include "fwbuilder/InetAddr.h"
32 #include "fwbuilder/Interface.h"
33 
34 extern "C" {
35 #  include "fwbuilder/inet_net.h"
36 }
37 
38 #ifndef _WIN32
39 
40 #  include <sys/types.h>
41 #  include <netinet/in.h>
42 #  include <arpa/inet.h>
43 #  include <sys/types.h>
44 #  include <sys/socket.h>
45 
46 #endif
47 
48 #include <errno.h>
49 #include <stdio.h>
50 #include <iostream>
51 #include <sstream>
52 #include <cstring>
53 #include <cstdlib>
54 #include <assert.h>
55 
56 #ifndef _WIN32
57 #  include <sys/types.h>
58 #  include <netinet/in.h>
59 #else
60 #  include <winsock2.h>
61 #endif
62 
63 #ifdef __linux__
64 # ifndef _GNU_SOURCE
65 #  define _GNU_SOURCE
66 # endif
67 # define A6PREF __in6_u
68 #else
69 # define A6PREF __u6_addr
70 #endif
71 
72 
73 using namespace std;
74 using namespace libfwbuilder;
75 
76 /*
77  * if data is a string that represents integer number without '.' or ':'
78  * in it, call init_from_int
79  */
init_from_string(const char * data)80 void InetAddr::init_from_string(const char* data)
81 {
82     if(!data) throw FWException("NULL IP address data..");
83     if (strchr(data, '.')==NULL && strchr(data, ':')==NULL)
84     {
85         char *invalid_chars;
86         long r = strtol(data, &invalid_chars, 10);
87         if (invalid_chars && *invalid_chars == '\0')
88             init_from_int(r);
89         else
90             throw FWException(string("Invalid IP address: '") + string(data) + "'");
91 
92     } else
93     {
94         if (address_family == AF_INET)
95         {
96             if (inet_net_pton(AF_INET, data, &ipv4, sizeof(ipv4)) < 0)
97                 throw FWException(string("Invalid IP address: '") +
98                                   string(data)+"'");
99         } else
100         {
101             if (inet_net_pton(AF_INET6, data, &ipv6, sizeof(ipv6)) < 0)
102                 throw FWException(string("Invalid IPv6 address: '") +
103                                   string(data)+"'");
104         }
105     }
106 }
107 
init_from_int(unsigned int len)108 void InetAddr::init_from_int(unsigned int len)
109 {
110    if (address_family == AF_INET)
111    {
112        if (len > addressLengthBits())
113        {
114            throw FWException(string("Invalid netmask length"));
115        }
116 
117        unsigned long nm_bits = 0;
118        int i = len;
119        while (i>0)
120        {
121            nm_bits >>= 1;
122            nm_bits |= 0x80000000;
123            i--;
124        }
125        ipv4.s_addr = htonl(nm_bits);
126    } else
127    {
128        if (len > addressLengthBits())
129        {
130            throw FWException(string("Invalid netmask length"));
131        }
132 
133        ((uint32_t *) (&ipv6))[0] = 0xffffffff;
134        ((uint32_t *) (&ipv6))[1] = 0xffffffff;
135        ((uint32_t *) (&ipv6))[2] = 0xffffffff;
136        ((uint32_t *) (&ipv6))[3] = 0xffffffff;
137 
138        // bits is number of zeros counting from the right end
139        unsigned int nbits = addressLengthBits() - len;
140        for (int i=3; i>=0; --i)
141        {
142            if (nbits >= 32)
143            {
144                ((uint32_t*)(&ipv6))[i] = 0;
145                nbits -= 32;
146                continue;
147            }
148            uint32_t t = 0xffffffff;
149            for (int k = nbits % 32; k; --k)
150            {
151                t <<= 1;
152                t &= 0xfffffffe;
153            }
154            ((uint32_t*)(&ipv6))[i] = htonl(t);
155            break;
156        }
157    }
158 }
159 
160 /*
161  * Netmask with "holes" is accepted by InetAddr, but we do not support
162  * it at this time. This function returns true if InetAddr object
163  * corresponds to an integer with a string of consequitive "1" bits
164  * and then string of consequtive "0" bits. The function only works
165  * for ipv4 addresses.
166  */
isValidV4Netmask()167 bool InetAddr::isValidV4Netmask()
168 {
169     assert(isV4());
170 
171     unsigned int n = ntohl(ipv4.s_addr);
172 
173     while (n & 0x80000000)
174     {
175         n = n<<1;
176     }
177 
178     return (n == 0);
179 }
180 
181 // uint128 is always in the host order
init_from_uint128(uint128 la)182 void InetAddr::init_from_uint128(uint128 la)
183 {
184     ((uint32_t *) (&ipv6))[0] = htonl((la >> 96).to_integer() & 0xffffffff);
185     ((uint32_t *) (&ipv6))[1] = htonl((la >> 64).to_integer() & 0xffffffff);
186     ((uint32_t *) (&ipv6))[2] = htonl((la >> 32).to_integer() & 0xffffffff);
187     ((uint32_t *) (&ipv6))[3] = htonl( la.to_integer() & 0xffffffff);
188 }
189 
to_uint128() const190 uint128 InetAddr::to_uint128() const
191 {
192     assert(isV6());
193     uint128 res;
194     uint128 x = uint64_t(ntohl(((uint32_t *) (&ipv6))[0]));
195     x <<= 96;
196     res |= x;
197     x = uint64_t(ntohl(((uint32_t *) (&ipv6))[1]));
198     x <<= 64;
199     res |= x;
200     x = uint64_t(ntohl(((uint32_t *) (&ipv6))[2]));
201     x <<= 32;
202     res |= x;
203     x = uint64_t(ntohl(((uint32_t *) (&ipv6))[3]));
204     res |= x;
205     return res;
206 }
207 
InetAddr(const InetAddr & o)208 InetAddr::InetAddr(const InetAddr &o)
209 {
210     *this = o;
211 }
212 
InetAddr(const string & s)213 InetAddr::InetAddr(const string &s)
214     throw(FWException, FWNotSupportedException)
215 {
216     address_family = AF_INET;
217     init_from_string(s.c_str());
218 }
219 
InetAddr(int af,const string & s)220 InetAddr::InetAddr(int af, const string &s)
221     throw(FWException, FWNotSupportedException)
222 {
223     address_family = af;
224     init_from_string(s.c_str());
225 }
226 
InetAddr(const char * data)227 InetAddr::InetAddr(const char *data) throw(FWException)
228 {
229     address_family = AF_INET;
230     init_from_string(data);
231 }
232 
InetAddr(int af,const char * data)233 InetAddr::InetAddr(int af, const char *data) throw(FWException)
234 {
235     address_family = af;
236     init_from_string(data);
237 }
238 
InetAddr(const struct in_addr * na)239 InetAddr::InetAddr(const struct in_addr *na) throw(FWException)
240 {
241     address_family = AF_INET;
242     ipv4.s_addr = na->s_addr;
243 }
244 
InetAddr(const struct in6_addr * na)245 InetAddr::InetAddr(const struct in6_addr *na) throw(FWException)
246 {
247     address_family = AF_INET6;
248     _copy_in6_addr(&ipv6, na);
249 }
250 
251 // Set netmask to 'n' bits
InetAddr(int n)252 InetAddr::InetAddr(int n)  throw(FWException)
253 {
254     address_family = AF_INET;
255     init_from_int(n);
256 }
257 
InetAddr(int af,int n)258 InetAddr::InetAddr(int af, int n)  throw(FWException)
259 {
260     address_family = af;
261     init_from_int(n);
262 }
263 
operator =(const InetAddr & addr)264 InetAddr& InetAddr::operator=(const InetAddr &addr)
265 {
266     if ((address_family = addr.address_family)==AF_INET)
267     {
268         ipv4.s_addr = addr.ipv4.s_addr;
269     } else
270     {
271         InetAddr::_copy_in6_addr(&ipv6, &(addr.ipv6) );
272     }
273     return *this;
274 }
275 
getLength() const276 int InetAddr::getLength() const
277 {
278     if (address_family==AF_INET)
279     {
280         if (ipv4.s_addr == INADDR_BROADCAST) return addressLengthBits();
281         if (ipv4.s_addr == 0) return 0;
282 
283         unsigned int n = ntohl(ipv4.s_addr);
284 
285         int   i=0;
286         while (n)
287         {
288             n=n<<1;
289             i++;
290         }
291 
292         return i;
293     } else
294     {
295         int bits = 0;
296         for (int i=3; i>=0; --i)
297         {
298             uint32_t n = ntohl(((uint32_t*)(&ipv6))[i]);
299             if (n==0)
300             {
301                 bits += 32;
302                 continue;
303             }
304             while ((n & 1) == 0)
305             {
306                 bits++;
307                 n = n >> 1;
308             }
309             bits = 128 - bits;
310             break;
311         }
312         return bits;
313     }
314 }
315 
toString() const316 string InetAddr::toString() const
317 {
318     if (address_family==AF_INET)
319     {
320         return std::string(inet_ntoa(ipv4));
321     } else
322     {
323         char ntop_buf[sizeof
324                       "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
325         /*
326          * Our included copy of inet_net_ntop does not add /netmask if
327          * bits==-1 (argument #3). However, the same function included
328          * in libc on FreeBSD returns EINVAL for bits=-1. Here is a
329          * hack: use bits=128 and then strip /128 that inet_net_ntop
330          * adds to the generated string. Both our included
331          * inet_net_ntop and the one shipped with FreeBSD add "/128"
332          * consistently, so this works on all platforms.
333          */
334         char *cp;
335         cp = inet_net_ntop(AF_INET6, (const void*)(&ipv6),
336                            128, ntop_buf, sizeof(ntop_buf));
337         if (cp==NULL)
338         {
339             ostringstream err;
340             switch (errno)
341             {
342             case EINVAL:
343                 err << "InetAddr::toString() Invalid bit length 0";
344                 throw FWException(err.str());
345                 ;;
346             case EMSGSIZE:
347                 err << "InetAddr::toString() EMSGSIZE error";
348                 throw FWException(err.str());
349                 ;;
350             case EAFNOSUPPORT:
351                 err << "InetAddr::toString() EAFNOSUPPORT error";
352                 throw FWException(err.str());
353                 ;;
354             default:
355                 err << "InetAddr::toString() other error: " << errno;
356                 throw FWException(err.str());
357                 ;;
358             }
359         }
360         char *slash_p = strchr(ntop_buf, '/');
361         if (slash_p!=NULL) *slash_p = '\0';
362         return std::string(ntop_buf);
363     }
364 }
365 
366 // note that address family of the result is dictated by the address family of
367 // "this". Address family of mask must be the same.
opAnd(const InetAddr & mask) const368 InetAddr InetAddr::opAnd(const InetAddr &mask) const
369 {
370     assert(address_family==mask.address_family);
371     if (address_family==AF_INET)
372     {
373         struct in_addr res;
374         res.s_addr = htonl(ntohl(ipv4.s_addr) & ntohl(mask.ipv4.s_addr));
375         return InetAddr(&res);
376     } else {
377         struct in6_addr res;
378         for (int i=0; i<4; ++i)
379             ((uint32_t*)(&res))[i] =
380                 htonl(ntohl(((uint32_t*)(&(ipv6)))[i]) &
381                       ntohl(((uint32_t*)(&(mask.ipv6)))[i]));
382         return InetAddr(&res);
383     }
384 }
385 
opOr(const InetAddr & mask) const386 InetAddr InetAddr::opOr(const InetAddr &mask) const
387 {
388     assert(address_family==mask.address_family);
389     if (address_family==AF_INET)
390     {
391         struct in_addr res;
392         res.s_addr = htonl(ntohl(ipv4.s_addr) | ntohl(mask.ipv4.s_addr));
393         return InetAddr(&res);
394     } else
395     {
396         struct in6_addr res;
397         for (int i=0; i<4; ++i)
398             ((uint32_t*)(&res))[i] =
399                 htonl(ntohl(((uint32_t*)(&(ipv6)))[i]) |
400                       ntohl(((uint32_t*)(&(mask.ipv6)))[i]));
401         return InetAddr(&res);
402     }
403 }
404 
opPlus(int increment) const405 InetAddr InetAddr::opPlus(int increment) const
406 {
407     if (address_family==AF_INET)
408     {
409         struct in_addr res;
410         res.s_addr = htonl(ntohl(ipv4.s_addr) + increment);
411         return InetAddr(&res);
412     } else
413     {
414         uint128 x = to_uint128();
415         x += increment;
416         InetAddr res(AF_INET6, 0);
417         res.init_from_uint128(x);
418         return res;
419 
420 //         struct in6_addr res;
421 //         InetAddr::_copy_in6_addr(&res, &(ipv6) );
422 //         ((uint32_t*)(&res))[3] =
423 //             htonl(ntohl( ((uint32_t*)(&(ipv6)))[3]) + increment);
424 //         return InetAddr(&res);
425     }
426 }
427 
opMinus(int decrement) const428 InetAddr InetAddr::opMinus(int decrement) const
429 {
430     if (address_family==AF_INET)
431     {
432         struct in_addr res;
433         res.s_addr = htonl(ntohl(ipv4.s_addr) - decrement);
434         return InetAddr(&res);
435     } else
436     {
437         uint128 x = to_uint128();
438         x -= decrement;
439         InetAddr res(AF_INET6, 0);
440         res.init_from_uint128(x);
441         return res;
442 
443 //         struct in6_addr res;
444 //         InetAddr::_copy_in6_addr(&res, &(ipv6) );
445 //         ((uint32_t*)(&res))[3] =
446 //             htonl(ntohl( ((uint32_t*)(&(ipv6)))[3]) - decrement);
447 //         return InetAddr(&res);
448     }
449 }
450 
opLT(const InetAddr & other) const451 bool InetAddr::opLT(const InetAddr &other) const
452 {
453     if (address_family!=other.address_family) return false;
454     if (address_family==AF_INET)
455     {
456         return (ntohl( ipv4.s_addr ) < ntohl( other.ipv4.s_addr ));
457     } else
458     {
459         uint128 a = to_uint128();
460         uint128 b = other.to_uint128();
461         return a < b;
462 
463 //         return (ntohl(((uint32_t*)(&(ipv6)))[3]) <
464 //                 ntohl(((uint32_t*)(&(other.ipv6)))[3]));
465     }
466 }
467 
opGT(const InetAddr & other) const468 bool InetAddr::opGT(const InetAddr &other) const
469 {
470     if (address_family!=other.address_family) return false;
471     if (address_family==AF_INET)
472     {
473         return (ntohl( ipv4.s_addr ) > ntohl( other.ipv4.s_addr ));
474     } else
475     {
476         uint128 a = to_uint128();
477         uint128 b = other.to_uint128();
478         return a > b;
479 
480 //         return (ntohl(((uint32_t*)(&(ipv6)))[3]) >
481 //                 ntohl(((uint32_t*)(&(other.ipv6)))[3]));
482     }
483 }
484 
opEQ(const InetAddr & other) const485 bool InetAddr::opEQ(const InetAddr &other) const
486 {
487     if (address_family!=other.address_family) return false;
488     if (address_family==AF_INET)
489     {
490         return ipv4.s_addr == other.ipv4.s_addr;
491     } else
492     {
493         return (IN6_ARE_ADDR_EQUAL(&(ipv6), &(other.ipv6)));
494     }
495 }
496 
opNEQ(const InetAddr & other) const497 bool InetAddr::opNEQ(const InetAddr &other) const
498 {
499     if (address_family!=other.address_family) return false;
500     if (address_family==AF_INET)
501     {
502         return ipv4.s_addr != other.ipv4.s_addr;
503     } else
504     {
505         return (!(IN6_ARE_ADDR_EQUAL(&(ipv6), &(other.ipv6))));
506     }
507 }
508 
opCompl() const509 InetAddr InetAddr::opCompl() const
510 {
511     if (address_family==AF_INET)
512     {
513         struct in_addr res;
514         res.s_addr = htonl(~(ntohl(ipv4.s_addr)));
515         return InetAddr(&res);
516     } else
517     {
518         struct in6_addr res;
519         ((uint32_t *) (&res))[0] = htonl(~(ntohl(((uint32_t *) (&ipv6))[0])));
520         ((uint32_t *) (&res))[1] = htonl(~(ntohl(((uint32_t *) (&ipv6))[1])));
521         ((uint32_t *) (&res))[2] = htonl(~(ntohl(((uint32_t *) (&ipv6))[2])));
522         ((uint32_t *) (&res))[3] = htonl(~(ntohl(((uint32_t *) (&ipv6))[3])));
523         return InetAddr(&res);
524     }
525 }
526 
527