| // Copyright (C) 2006-2010 David Sugar, Tycho Softworks |
| // |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 2 of the License, or |
| // (at your option) any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| // |
| // As a special exception, you may use this file as part of a free software |
| // library without restriction. Specifically, if other files instantiate |
| // templates or use macros or inline functions from this file, or you compile |
| // this file and link it with other files to produce an executable, this |
| // file does not by itself cause the resulting executable to be covered by |
| // the GNU General Public License. This exception does not however |
| // invalidate any other reasons why the executable file might be covered by |
| // the GNU General Public License. |
| // |
| // This exception applies only to the code released under the name GNU |
| // Common C++. If you copy code from other releases into a copy of GNU |
| // Common C++, as the General Public License permits, the exception does |
| // not apply to the code that you add in this way. To avoid misleading |
| // anyone as to the status of such modified files, you must delete |
| // this exception notice from them. |
| // |
| // If you write modifications of your own for GNU Common C++, it is your choice |
| // whether to permit this exception to apply to your modifications. |
| // If you do not wish that, delete this exception notice. |
| // |
| |
| #include <cc++/config.h> |
| #include <cc++/export.h> |
| #include <cc++/address.h> |
| #include "private.h" |
| #include <cstdlib> |
| #include <fcntl.h> |
| #include <cstdio> |
| |
| |
| #ifdef CCXX_NAMESPACES |
| namespace ost { |
| #endif |
| |
| typedef unsigned char bit_t; |
| |
| static void bitmask(bit_t *bits, bit_t *mask, unsigned len) |
| { |
| while(len--) |
| *(bits++) &= *(mask++); |
| } |
| |
| static void bitimask(bit_t *bits, bit_t *mask, unsigned len) |
| { |
| while(len--) |
| *(bits++) |= ~(*(mask++)); |
| } |
| |
| static void bitset(bit_t *bits, unsigned blen) |
| { |
| bit_t mask; |
| |
| while(blen) { |
| mask = (bit_t)(1 << 7); |
| while(mask && blen) { |
| *bits |= mask; |
| mask >>= 1; |
| --blen; |
| } |
| ++bits; |
| } |
| } |
| |
| static unsigned bitcount(bit_t *bits, unsigned len) |
| { |
| unsigned count = 0; |
| bit_t mask, test; |
| |
| while(len--) { |
| mask = (bit_t)(1<<7); |
| test = *bits++; |
| while(mask) { |
| if(!(mask & test)) |
| return count; |
| ++count; |
| mask >>= 1; |
| } |
| } |
| return count; |
| } |
| |
| IPV4Cidr::IPV4Cidr() |
| { |
| memset(&network, 0, sizeof(network)); |
| memset(&netmask, 0, sizeof(netmask)); |
| } |
| |
| IPV4Cidr::IPV4Cidr(const char *cp) |
| { |
| set(cp); |
| } |
| |
| IPV4Cidr::IPV4Cidr(IPV4Cidr &cidr) |
| { |
| memcpy(&network, &cidr.network, sizeof(network)); |
| memcpy(&netmask, &cidr.netmask, sizeof(netmask)); |
| } |
| |
| bool IPV4Cidr::isMember(const struct in_addr &addr) const |
| { |
| struct in_addr host = addr; |
| |
| bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); |
| if(!memcmp(&host, &network, sizeof(host))) |
| return true; |
| |
| return false; |
| } |
| |
| bool IPV4Cidr::isMember(const struct sockaddr *saddr) const |
| { |
| struct sockaddr_in *addr = (struct sockaddr_in *)saddr; |
| struct in_addr host; |
| |
| if(saddr->sa_family != AF_INET) |
| return false; |
| |
| memcpy(&host, &addr->sin_addr.s_addr, sizeof(host)); |
| bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); |
| if(!memcmp(&host, &network, sizeof(host))) |
| return true; |
| |
| return false; |
| } |
| |
| struct in_addr IPV4Cidr::getBroadcast(void) const |
| { |
| struct in_addr bcast; |
| memcpy(&bcast, &network, sizeof(network)); |
| bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast)); |
| return bcast; |
| } |
| |
| unsigned IPV4Cidr::getMask(const char *cp) const |
| { |
| unsigned dcount = 0; |
| const char *gp = cp; |
| const char *mp = strchr(cp, '/'); |
| unsigned char dots[4]; |
| #ifdef WIN32 |
| DWORD mask; |
| #else |
| uint32 mask; |
| #endif |
| |
| if(mp) { |
| if(!strchr(++mp, '.')) |
| return atoi(mp); |
| |
| mask = inet_addr(mp); |
| return bitcount((bit_t *)&mask, sizeof(mask)); |
| } |
| |
| memset(dots, 0, sizeof(dots)); |
| dots[0] = atoi(cp); |
| while(*gp && dcount < 3) { |
| if(*(gp++) == '.') |
| dots[++dcount] = atoi(gp); |
| } |
| |
| if(dots[3]) |
| return 32; |
| |
| if(dots[2]) |
| return 24; |
| |
| if(dots[1]) |
| return 16; |
| |
| return 8; |
| } |
| |
| void IPV4Cidr::set(const char *cp) |
| { |
| char cbuf[INET_IPV4_ADDRESS_SIZE]; |
| char *ep; |
| unsigned dots = 0; |
| #ifdef WIN32 |
| DWORD addr; |
| #endif |
| |
| memset(&netmask, 0, sizeof(netmask)); |
| bitset((bit_t *)&netmask, getMask(cp)); |
| setString(cbuf, sizeof(cbuf), cp); |
| |
| ep = (char *)strchr(cp, '/'); |
| |
| if(ep) |
| *ep = 0; |
| |
| cp = cbuf; |
| while(NULL != (cp = strchr(cp, '.'))) { |
| ++dots; |
| ++cp; |
| } |
| |
| while(dots++ < 3) |
| addString(cbuf, sizeof(cbuf), ".0"); |
| |
| #ifdef WIN32 |
| addr = inet_addr(cbuf); |
| memcpy(&network, &addr, sizeof(network)); |
| #else |
| inet_aton(cbuf, &network); |
| #endif |
| bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network)); |
| } |
| |
| |
| |
| |
| #ifdef CCXX_IPV6 |
| |
| IPV6Cidr::IPV6Cidr() |
| { |
| memset(&network, 0, sizeof(network)); |
| memset(&netmask, 0, sizeof(netmask)); |
| } |
| |
| IPV6Cidr::IPV6Cidr(const char *cp) |
| { |
| set(cp); |
| } |
| |
| IPV6Cidr::IPV6Cidr(IPV6Cidr &cidr) |
| { |
| memcpy(&network, &cidr.network, sizeof(network)); |
| memcpy(&netmask, &cidr.netmask, sizeof(netmask)); |
| } |
| |
| bool IPV6Cidr::isMember(const struct in6_addr &addr) const |
| { |
| struct in6_addr host = addr; |
| |
| bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); |
| if(!memcmp(&host, &network, sizeof(host))) |
| return true; |
| |
| return false; |
| } |
| |
| bool IPV6Cidr::isMember(const struct sockaddr *saddr) const |
| { |
| struct sockaddr_in6 *addr = (struct sockaddr_in6 *)saddr; |
| struct in6_addr host; |
| |
| if(saddr->sa_family != AF_INET6) |
| return false; |
| |
| memcpy(&host, &addr->sin6_addr, sizeof(host)); |
| bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host)); |
| if(!memcmp(&host, &network, sizeof(host))) |
| return true; |
| |
| return false; |
| } |
| |
| struct in6_addr IPV6Cidr::getBroadcast(void) const |
| { |
| struct in6_addr bcast; |
| memcpy(&bcast, &network, sizeof(network)); |
| bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast)); |
| return bcast; |
| } |
| |
| unsigned IPV6Cidr::getMask(const char *cp) const |
| { |
| unsigned count = 0, rcount = 0; |
| const char *sp = strchr(cp, '/'); |
| int flag = 0; |
| |
| if(sp) |
| return atoi(++sp); |
| |
| if(!strncmp(cp, "ff00:", 5)) |
| return 8; |
| |
| if(!strncmp(cp, "fe80:", 5)) |
| return 10; |
| |
| if(!strncmp(cp, "2002:", 5)) |
| return 16; |
| |
| sp = strrchr(cp, ':'); |
| while(*(++sp) == '0') |
| ++sp; |
| if(*sp) |
| return 128; |
| |
| while(*cp && count < 128) { |
| if(*(cp++) == ':') { |
| count+= 16; |
| while(*cp == '0') |
| ++cp; |
| if(*cp == ':') { |
| if(!flag) |
| rcount = count; |
| flag = 1; |
| } |
| else |
| flag = 0; |
| } |
| } |
| return rcount; |
| } |
| |
| void IPV6Cidr::set(const char *cp) |
| { |
| char cbuf[INET_IPV6_ADDRESS_SIZE]; |
| char *ep; |
| |
| memset(&netmask, 0, sizeof(netmask)); |
| bitset((bit_t *)&netmask, getMask(cp)); |
| setString(cbuf, sizeof(cbuf), cp); |
| ep = (char *)strchr(cp, '/'); |
| if(ep) |
| *ep = 0; |
| |
| inet_pton(AF_INET6, cbuf, &network); |
| bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network)); |
| } |
| |
| #endif |
| |
| #ifdef CCXX_NAMESPACES |
| } |
| #endif |
| |
| /** EMACS ** |
| * Local variables: |
| * mode: c++ |
| * c-basic-offset: 4 |
| * End: |
| */ |