//============================================================================= // // File : kvi_netutlis.cpp // Creation date : Sun Jun 18 2000 18:37:27 by Szymon Stefanek // // This file is part of the KVirc irc client distribution // Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) // // 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 opinion) 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. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARGH! // This effect is caused by the combination of broken CVS installation and // the ugly windows "text mode" files #define __KVILIB__ #define _KVI_NETUTILS_CPP_ #include "kvi_netutils.h" #include "kvi_memmove.h" #include #ifndef COMPILE_ON_WINDOWS #include // struct timeval #endif #include #include "kvi_qstring.h" #ifndef COMPILE_ON_WINDOWS #include #include #endif #ifdef COMPILE_GET_INTERFACE_ADDRESS #include #include #endif //COMPILE_GET_INTERFACE_ADDRESS #ifndef HAVE_INET_ATON // FIXME: #warning "Your system lacks the inet_aton function," // FIXME: #warning "you're trying to compile this file without" // FIXME: #warning "the config.h created by the configure script," // FIXME: #warning "Using own internal implementation of inet_aton." #include // Need own inet_aton implementation // // Check whether "cp" is a valid ascii representation // of an Internet address and convert to a binary address. // Returns 1 if the address is valid, 0 if not. // This replaces inet_addr, the return value from which // cannot distinguish between failure and a local broadcast address. // // Original code comes from the ircd source. // bool kvi_stringIpToBinaryIp(const char *szIp,struct in_addr *address) { register unsigned long val; register int base, n; register char c; unsigned int parts[4]; register unsigned int *pp = parts; if(!szIp)return false; c = *szIp; for(;;){ // Collect number up to ``.''. // Values are specified as for C: // 0x=hex, 0=octal, isdigit=decimal. if(!isdigit(c))return false; val = 0; base = 10; if(c == '0'){ c = *++szIp; if((c == 'x')||(c == 'X'))base = 16, c = *++szIp; else base = 8; } for (;;) { if(isascii(c) && isdigit(c)) { val = (val * base) + (c - '0'); c = *++szIp; } else if (base == 16 && isascii(c) && isxdigit(c)) { val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A')); c = *++szIp; } else break; } if(c == '.'){ // Internet format: // a.b.c.d // a.b.c (with c treated as 16 bits) // a.b (with b treated as 24 bits) if(pp >= (parts + 3)) return false; *pp++ = val; c = *++szIp; } else break; } // Check for trailing characters. if ((c != '\0') && (!isascii(c) || !isspace(c)))return false; // Concact the address according to // the number of parts specified. n = pp - parts + 1; switch (n) { case 0: return false; // initial nondigit case 1: break; // a -- 32 bits case 2: // a.b -- 8.24 bits if(val > 0xffffff) return false; val |= parts[0] << 24; break; case 3: // a.b.c -- 8.8.16 bits if(val > 0xffff)return false; val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: // a.b.c.d -- 8.8.8.8 bits if(val > 0xff)return false; val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if(address)address->s_addr = htonl(val); return true; } #else //!HAVE_INET_ATON bool kvi_stringIpToBinaryIp(const char *szIp,struct in_addr *address) { if(!szIp)return false; return (inet_aton(szIp,address) != 0); } #endif //!HAVE_INET_ATON #ifndef HAVE_INET_NTOA // FIXME: #warning "Your system lacks the inet_ntoa function," // FIXME: #warning "you're trying to compile this file without" // FIXME: #warning "the config.h created by the configure script," // FIXME: #warning "Using own internal implementation of inet_ntoa." // // Original code comes from the ircd source. // bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer) { unsigned char *s = (unsigned char *)∈ int a,b,c,d; a = (int)*s++; b = (int)*s++; c = (int)*s++; d = (int)*s; szBuffer.sprintf("%d.%d.%d.%d", a,b,c,d ); return true; } #else //HAVE_INET_NTOA bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer) { // FIXME: #warning "This is NOT thread safe!" char * ptr = inet_ntoa(in); if(!ptr)return false; szBuffer = ptr; return true; } #endif //HAVE_INET_NTOA bool kvi_isValidStringIp(const char *szIp) { struct in_addr address; if(!szIp)return false; if(!isdigit(*szIp))return false; return kvi_stringIpToBinaryIp(szIp,&address); } #ifdef COMPILE_IPV6_SUPPORT #ifdef COMPILE_ON_WINDOWS //#include //#include //#include / //#include //#include "dietfeatures.h" static unsigned int scan_ip6(const char *s,char ip[16]) { unsigned int i; unsigned int len=0; unsigned long u; char suffix[16]; unsigned int prefixlen=0; unsigned int suffixlen=0; for (i=0; i<16; i++) ip[i]=0; for (;;) { if (*s == ':') { len++; if (s[1] == ':') { /* Found "::", skip to part 2 */ s+=2; len++; break; } s++; } { char *tmp; u=strtoul(s,&tmp,16); i=tmp-s; } if (!i) return 0; if (prefixlen==12 && s[i]=='.') { /* the last 4 bytes may be written as IPv4 address */ if (kvi_stringIpToBinaryIp(s,(struct in_addr*)(ip+12))) return i+len; else return 0; } ip[prefixlen++] = (u >> 8); ip[prefixlen++] = (u & 255); s += i; len += i; if (prefixlen==16) return len; } /* part 2, after "::" */ for (;;) { if (*s == ':') { if (suffixlen==0) break; s++; len++; } else if (suffixlen!=0) break; { char *tmp; u=strtol(s,&tmp,16); i=tmp-s; } if (!i) { if (*s) len--; break; } if (suffixlen+prefixlen<=12 && s[i]=='.') { if (kvi_stringIpToBinaryIp(s,(struct in_addr*)(suffix+suffixlen))) { suffixlen+=4; len+=(unsigned int)strlen(s); break; } else prefixlen=12-suffixlen; /* make end-of-loop test true */ } suffix[suffixlen++] = (u >> 8); suffix[suffixlen++] = (u & 255); s += i; len += i; if (prefixlen+suffixlen==16) break; } for (i=0; i //#include //extern char *inet_ntoa_r(struct in_addr in,char* buf); static const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; static char tohex(char hexdigit) { return hexdigit>9?hexdigit+'a'-10:hexdigit+'0'; } static int fmt_xlong(char* s,unsigned int i) { char* bak=s; *s=tohex((i>>12)&0xf); if (s!=bak || *s!='0') ++s; *s=tohex((i>>8)&0xf); if (s!=bak || *s!='0') ++s; *s=tohex((i>>4)&0xf); if (s!=bak || *s!='0') ++s; *s=tohex(i&0xf); return s-bak+1; } static unsigned int i2a(char* dest,unsigned int x) { register unsigned int tmp=x; register unsigned int len=0; if (x>=100) { *dest++=tmp/100+'0'; tmp=tmp%100; ++len; } if (x>=10) { *dest++=tmp/10+'0'; tmp=tmp%10; ++len; } *dest++=tmp+'0'; return len+1; } char *inet_ntoa_r(struct in_addr in,char* buf) { unsigned int len; unsigned char *ip=(unsigned char*)∈ len=i2a(buf,ip[0]); buf[len]='.'; ++len; len+=i2a(buf+ len,ip[1]); buf[len]='.'; ++len; len+=i2a(buf+ len,ip[2]); buf[len]='.'; ++len; len+=i2a(buf+ len,ip[3]); buf[len]=0; return buf; } unsigned int fmt_ip6(char *s,const char ip[16]) { unsigned int len; unsigned int i; unsigned int temp; unsigned int compressing; // 0 not compressing , 1 compressing now , 2 already compressed once len = 0; compressing = 0; for(int j=0;j<16;j+=2) { if (j==12 && !memcmp(ip,V4mappedprefix,12)) { inet_ntoa_r(*(struct in_addr*)(ip+12),s); temp=(unsigned int)strlen(s); return len+temp; } temp = ((unsigned long) (unsigned char) ip[j] << 8) + (unsigned long) (unsigned char) ip[j+1]; if(temp == 0) { if(compressing == 0) { compressing=1; if (j==0) { *s++=':'; ++len; } } } else { if(compressing == 1) { compressing=2; // don't do it again *s++=':'; ++len; } i = fmt_xlong(s,temp); len += i; s += i; if (j<14) { *s++ = ':'; ++len; } } } if(compressing == 1) { *s++=':'; ++len; } *s=0; return len; } const char* inet_ntop(int AF, const void *CP, char *BUF, size_t LEN) { char buf[100]; size_t len; if (AF==AF_INET) { inet_ntoa_r(*(struct in_addr*)CP,buf); len=strlen(buf); } else if (AF==AF_INET6) { len=fmt_ip6(buf,(char *)CP); } else return 0; if (len bool kvi_select(int fd,bool * bCanRead,bool * bCanWrite,int iUSecs) { // FIXME: This stuff should DIE! fd_set rs; fd_set ws; FD_ZERO(&rs); FD_ZERO(&ws); FD_SET(fd,&rs); FD_SET(fd,&ws); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = iUSecs; int ret = select(fd + 1,&rs,&ws,0,&tv); if(ret < 1)return false; // EINTR or ENOSTUFFATALL *bCanRead = FD_ISSET(fd,&rs); *bCanWrite = FD_ISSET(fd,&ws); return true; } namespace KviNetUtils { bool stringIpToBinaryIp(const QString &szStringIp,struct in_addr * address) { #ifndef HAVE_INET_ATON QString szAddr = szStringIp.simplifyWhiteSpace(); Q_UINT32 iAddr=0; QStringList ipv4 = QStringList::split(".", szAddr, FALSE); if (ipv4.count() == 4) { int i = 0; bool ok = TRUE; while(ok && i < 4) { uint byteValue = ipv4[i].toUInt(&ok); if ( (byteValue > 255) && ok ) ok = FALSE; if (ok) iAddr = (iAddr << 8) + byteValue; ++i; } if (ok) { if(address)address->s_addr = htonl(iAddr); return true; } } return FALSE; #else //HAVE_INET_ATON if(szStringIp.isEmpty())return false; return (inet_aton(KviQString::toUtf8(szStringIp).data(),address) != 0); #endif //HAVE_INET_ATON } bool isValidStringIp(const QString &szIp) { struct in_addr address; if(szIp.isEmpty())return false; if(!szIp[0].isNumber())return false; return stringIpToBinaryIp(szIp,&address); } #ifdef COMPILE_IPV6_SUPPORT bool stringIpToBinaryIp_V6(const QString &szStringIp,struct in6_addr * address) { return (inet_pton(AF_INET6,KviQString::toUtf8(szStringIp).data(),(void *)address) == 1); } bool isValidStringIp_V6(const QString &szIp) { struct in6_addr address; if(szIp.isEmpty())return false; return stringIpToBinaryIp_V6(szIp,&address); } bool binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer) { char buf[46]; bool bRet = inet_ntop(AF_INET6,(void *)&in,buf,46); szBuffer= buf; return bRet; } #endif //COMPILE_IPV6_SUPPORT bool binaryIpToStringIp(struct in_addr in,QString &szBuffer) { char * ptr = inet_ntoa(in); if(!ptr)return false; szBuffer = ptr; return true; } bool isRoutableIpString(const QString &szIpString) { struct in_addr a; if(szIpString.isEmpty())return false; stringIpToBinaryIp(szIpString,&a); return isRoutableIp((const char *)&a); } bool isRoutableIp(const char * ipaddr) { if(!ipaddr)return false; const unsigned char * ip = (const unsigned char *)ipaddr; if(ip[0] == 0)return false; // old-style broadcast if(ip[0] == 10)return false; // Class A VPN if(ip[0] == 127)return false; // loopback if((ip[0] == 172) && (ip[1] >= 16) && (ip[1] <= 31))return false; // Class B VPN if((ip[0] == 192) && (ip[1] == 168))return false; // Class C VPN if((ip[0] == 169) && (ip[1] == 254))return false; // APIPA if((ip[0] == 192) && (ip[1] == 0) && (ip[2] == 2))return false; // Class B VPN if(ip[0] >= 224)return false; // class D multicast and class E reserved return true; } bool getInterfaceAddress(const QString &szInterfaceName,QString &szBuffer) { #ifdef COMPILE_GET_INTERFACE_ADDRESS struct sockaddr *sa; struct sockaddr_in *sin; struct ifreq ifr; int len = szInterfaceName.length(); if(len > (IFNAMSIZ - 1))return false; // invalid interface anyway kvi_memmove(ifr.ifr_name,KviQString::toUtf8(szInterfaceName).data(),len + 1); int fd = socket(AF_INET,SOCK_STREAM,0); if(fd < 0)return false; if(ioctl(fd,SIOCGIFADDR,&ifr) == -1)return false; // supports only IPV4 ? close(fd); sa = (struct sockaddr *)&(ifr.ifr_addr); if (sa->sa_family != AF_INET) return false; sin = (struct sockaddr_in*) sa; return binaryIpToStringIp(sin->sin_addr,szBuffer); // (this seems to work for AF_INET only anyway) #else //!COMPILE_GET_INTERFACE_ADDRESS return false; #endif //!COMPILE_GET_INTERFACE_ADDRESS } void formatNetworkBandwidthString(QString &szBuffer,unsigned int uBytesPerSec) { if(uBytesPerSec > (1024 * 1024)) { unsigned int uMB = uBytesPerSec / (1024 * 1024); unsigned int uRem = ((uBytesPerSec % (1024 * 1024)) * 100) / (1024 * 1024); KviQString::sprintf(szBuffer,"%u.%u%u MB/s",uMB,uRem / 10,uRem % 10); return; } if(uBytesPerSec >= 1024) { unsigned int uKB = uBytesPerSec / 1024; unsigned int uRem = ((uBytesPerSec % 1024) * 100) / 1024; KviQString::sprintf(szBuffer,"%u.%u%u KB/s",uKB,uRem / 10,uRem % 10); return; } KviQString::sprintf(szBuffer,"%u B/s",uBytesPerSec); } }; bool kvi_getInterfaceAddress(const char * ifname,QString &buffer) { debug("kvi_getInterfaceAddress is deprecated: use KviNetUtils::getInterfaceAddress"); QString szRet; bool bRes = KviNetUtils::getInterfaceAddress(QString(ifname),szRet); buffer = szRet; return bRes; } bool kvi_isRoutableIpString(const char * ipstring) { struct in_addr a; if(!ipstring)return false; kvi_stringIpToBinaryIp(ipstring,&a); return kvi_isRoutableIp((const char *)&a); } bool kvi_isRoutableIp(const char * ipaddr) { if(!ipaddr)return false; const unsigned char * ip = (const unsigned char *)ipaddr; if(ip[0] == 0)return false; // old-style broadcast if(ip[0] == 10)return false; // Class A VPN if(ip[0] == 127)return false; // loopback if((ip[0] == 172) && (ip[1] >= 16) && (ip[1] <= 31))return false; // Class B VPN if((ip[0] == 192) && (ip[1] == 168))return false; // Class C VPN if((ip[0] == 169) && (ip[1] == 254))return false; // APIPA if((ip[0] == 192) && (ip[1] == 0) && (ip[2] == 2))return false; // Class B VPN if(ip[0] >= 224)return false; // class D multicast and class E reserved return true; } bool kvi_getLocalHostAddress(QString &buffer) { // This will work only on windoze... char buf[1024]; if(gethostname(buf,1024) != 0)return false; struct hostent * h = gethostbyname(buf); if(!h)return false; QString tmp; int i=0; while(h->h_addr_list[i]) { if(kvi_binaryIpToStringIp(*((struct in_addr *)(h->h_addr_list[i])),tmp)) { if(kvi_isRoutableIp(h->h_addr_list[i])) { buffer = tmp; return true; } } i++; } buffer = tmp; return true; } KviSockaddr::KviSockaddr(const char * szIpAddress,kvi_u32_t uPort,bool bIpV6,bool bUdp) { struct addrinfo hints; kvi_memset((void *)&hints,0,sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; #ifdef COMPILE_IPV6_SUPPORT hints.ai_family = bIpV6 ? PF_INET6 : PF_INET; #else hints.ai_family = PF_INET; #endif hints.ai_socktype = bUdp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = 0; m_pData = 0; KviStr szPort(KviStr::Format,"%u",uPort); getaddrinfo(szIpAddress,szPort.ptr(),&hints,(struct addrinfo **)&m_pData); } KviSockaddr::KviSockaddr(kvi_u32_t uPort,bool bIpV6,bool bUdp) // passive sockaddr { struct addrinfo hints; kvi_memset((void *)&hints,0,sizeof(hints)); hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; #ifdef COMPILE_IPV6_SUPPORT hints.ai_family = bIpV6 ? PF_INET6 : PF_INET; #else hints.ai_family = PF_INET; #endif hints.ai_socktype = bUdp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = 0; m_pData = 0; KviStr szPort(KviStr::Format,"%u",uPort); getaddrinfo(0,szPort.ptr(),&hints,(struct addrinfo **)&m_pData); } KviSockaddr::~KviSockaddr() { if(m_pData) { freeaddrinfo((struct addrinfo *)m_pData); m_pData = 0; } } struct sockaddr * KviSockaddr::socketAddress() { if(!m_pData)return 0; return ((struct addrinfo *)m_pData)->ai_addr; } size_t KviSockaddr::addressLength() { if(!m_pData)return 0; return ((struct addrinfo *)m_pData)->ai_addrlen; } int KviSockaddr::addressFamily() { if(!m_pData)return 0; return ((struct addrinfo *)m_pData)->ai_family; } bool KviSockaddr::isIpV6() { if(!m_pData)return false; #ifdef COMPILE_IPV6_SUPPORT return false; #else return (addressFamily() == AF_INET6); #endif } kvi_u32_t KviSockaddr::port() { if(!m_pData)return 0; #ifdef COMPILE_IPV6_SUPPORT switch(((struct addrinfo *)m_pData)->ai_family) { case AF_INET: return ntohs(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_port); break; case AF_INET6: return ntohs(((struct sockaddr_in6 *)(((struct addrinfo *)m_pData)->ai_addr))->sin6_port); break; } return 0; #else return ntohs(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_port); #endif } bool KviSockaddr::getStringAddress(QString &szBuffer) { if(!m_pData)return 0; #ifdef COMPILE_IPV6_SUPPORT switch(((struct addrinfo *)m_pData)->ai_family) { case AF_INET: return kvi_binaryIpToStringIp(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_addr,szBuffer); break; case AF_INET6: return kvi_binaryIpToStringIp_V6(((struct sockaddr_in6 *)(((struct addrinfo *)m_pData)->ai_addr))->sin6_addr,szBuffer); break; } return false; #else return kvi_binaryIpToStringIp(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_addr,szBuffer); #endif }