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