Viewing file: iputils.cpp (10.87 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
// FileZilla Server - a Windows ftp server
// Copyright (C) 2004 - Tim Kosse <tim.kosse@gmx.de>
// 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.
#include "stdafx.h"
#include "iputils.h"
bool IsLocalhost(const CStdString& ip)
{
if (ip.Left(4) == _T("127."))
return true;
if (GetIPV6ShortForm(ip) == _T("::1"))
return true;
return false;
}
bool IsValidAddressFilter(CStdString& filter)
{
CStdString left;
int pos = filter.Find(_T("/"));
int prefixLength = 0;
if (!pos)
return false;
else if (pos != -1)
{
left = filter.Left(pos);
prefixLength = _ttoi(filter.Mid(pos + 1));
if (prefixLength <= 0 || prefixLength > 128)
return false;
}
else
left = filter;
if (!IsIpAddress(left))
return false;
if (left.Find(':') != -1)
left = GetIPV6ShortForm(left);
if (prefixLength)
filter.Format(_T("%s/%d"), (LPCTSTR)left, prefixLength);
else
filter = left;
return true;
}
int DigitHexToDecNum(TCHAR c)
{
if (c >= 'a')
return c - 'a' + 10;
if (c >= 'A')
return c - 'A' + 10;
else
return c - '0';
}
static unsigned long const prefixMasksV4[] = {
0x00000000u,
0x80000000u,
0xc0000000u,
0xe0000000u,
0xf0000000u,
0xf8000000u,
0xfc000000u,
0xfe000000u,
0xff000000u,
0xff800000u,
0xffc00000u,
0xffe00000u,
0xfff00000u,
0xfff80000u,
0xfffc0000u,
0xfffe0000u,
0xffff0000u,
0xffff8000u,
0xffffc000u,
0xffffe000u,
0xfffff000u,
0xfffff800u,
0xfffffc00u,
0xfffffe00u,
0xffffff00u,
0xffffff80u,
0xffffffc0u,
0xffffffe0u,
0xfffffff0u,
0xfffffff8u,
0xfffffffcu,
0xfffffffeu,
0xffffffffu
};
bool MatchesFilter(CStdString filter, CStdString ip)
{
// A single asterix matches all IPs.
if (filter == _T("*"))
return true;
// Check for IP range syntax.
int pos = filter.Find('/');
if (pos != -1)
{
// CIDR filter
int prefixLength = _ttoi(filter.Mid(pos+1));
if (ip.Find(':') != -1)
{
// IPv6 address
CStdString left = GetIPV6LongForm(filter.Left(pos));
if (left.Find(':') == -1)
return false;
ip = GetIPV6LongForm(ip);
LPCTSTR i = ip;
LPCTSTR f = left;
while (prefixLength >= 4)
{
if (*i != *f)
return false;
if (!*i)
return true;
if (*i == ':')
{
++i;
++f;
}
++i;
++f;
prefixLength -= 4;
}
if (!prefixLength)
return true;
int mask;
if (prefixLength == 1)
mask = 0x8;
else if (prefixLength == 2)
mask = 0xc;
else
mask = 0xe;
return (DigitHexToDecNum(*i) & mask) == (DigitHexToDecNum(*f) & mask);
}
else
{
if (prefixLength < 0)
prefixLength = 0;
else if (prefixLength > 32)
prefixLength = 32;
// IPv4 address
CStdString left = filter.Left(pos);
if (left.Find(':') != -1)
return false;
unsigned long i = ntohl(inet_addr(ConvToLocal(ip)));
unsigned long f = ntohl(inet_addr(ConvToLocal(left)));
i &= prefixMasksV4[prefixLength];
f &= prefixMasksV4[prefixLength];
return i == f;
}
}
else
{
// Literal filter
if (filter.Find(':') != -1)
return filter == GetIPV6ShortForm(ip);
else
return filter == ip;
}
}
bool ParseIPFilter(CStdString in, std::list<CStdString>* output /*=0*/)
{
bool valid = true;
in.Replace(_T("\n"), _T(" "));
in.Replace(_T("\r"), _T(" "));
in.Replace(_T("\t"), _T(" "));
while (in.Replace(_T(" "), _T(" ")));
in.TrimLeft(_T(" "));
in.TrimRight(_T(" "));
in += _T(" ");
int pos;
while ((pos = in.Find(_T(" "))) != -1)
{
CStdString ip = in.Left(pos);
if (ip == _T(""))
break;
in = in.Mid(pos + 1);
if (ip == _T("*") || IsValidAddressFilter(ip))
{
if (output)
output->push_back(ip);
}
else
valid = false;
}
return valid;
}
CStdString GetIPV6LongForm(CStdString short_address)
{
if (short_address[0] == '[')
{
if (short_address[short_address.GetLength() - 1] != ']')
return _T("");
short_address = short_address.Mid(1, short_address.GetLength() - 2);
}
short_address.MakeLower();
TCHAR buffer[40] = { '0', '0', '0', '0', ':',
'0', '0', '0', '0', ':',
'0', '0', '0', '0', ':',
'0', '0', '0', '0', ':',
'0', '0', '0', '0', ':',
'0', '0', '0', '0', ':',
'0', '0', '0', '0', ':',
'0', '0', '0', '0', 0
};
TCHAR* out = buffer;
const unsigned int len = short_address.GetLength();
if (len > 39)
return _T("");
// First part, before possible ::
unsigned int i = 0;
unsigned int grouplength = 0;
for (i = 0; i < len + 1; i++)
{
const TCHAR& c = short_address[i];
if (c == ':' || !c)
{
if (!grouplength)
{
// Empty group length, not valid
if (!c || short_address[i + 1] != ':')
return _T("");
i++;
break;
}
out += 4 - grouplength;
for (unsigned int j = grouplength; j > 0; j--)
*out++ = short_address[i - j];
// End of string...
if (!c)
{
if (!*out)
// ...on time
return buffer;
else
// ...premature
return _T("");
}
else if (!*out)
{
// Too long
return _T("");
}
out++;
grouplength = 0;
if (short_address[i + 1] == ':')
{
i++;
break;
}
continue;
}
else if ((c < '0' || c > '9') &&
(c < 'a' || c > 'f'))
{
// Invalid character
return _T("");
}
// Too long group
if (++grouplength > 4)
return _T("");
}
// Second half after ::
TCHAR* end_first = out;
out = &buffer[38];
unsigned int stop = i;
for (i = len - 1; i > stop; i--)
{
if (out < end_first)
{
// Too long
return _T("");
}
const TCHAR& c = short_address[i];
if (c == ':')
{
if (!grouplength)
{
// Empty group length, not valid
return _T("");
}
out -= 5 - grouplength;
grouplength = 0;
continue;
}
else if ((c < '0' || c > '9') &&
(c < 'a' || c > 'f'))
{
// Invalid character
return _T("");
}
// Too long group
if (++grouplength > 4)
return _T("");
*out-- = c;
}
if (!grouplength)
{
// Empty group length, not valid
return _T("");
}
out -= 5 - grouplength;
out += 2;
int diff = out - end_first;
if (diff < 0 || diff % 5)
return _T("");
return buffer;
}
bool IsRoutableAddress(const CStdString& address)
{
if (address.Find(_T(":")) != -1)
{
CStdString long_address = GetIPV6LongForm(address);
if (long_address.IsEmpty())
return false;
if (long_address[0] == '0')
{
// ::/128
if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0000"))
return false;
// ::1/128
if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0001"))
return false;
if (long_address.Left(30) == _T("0000:0000:0000:0000:0000:ffff:"))
{
// IPv4 mapped
CStdString ipv4;
ipv4.Format(_T("%d.%d.%d.%d"),
DigitHexToDecNum(long_address[30]) * 16 + DigitHexToDecNum(long_address[31]),
DigitHexToDecNum(long_address[32]) * 16 + DigitHexToDecNum(long_address[33]),
DigitHexToDecNum(long_address[35]) * 16 + DigitHexToDecNum(long_address[36]),
DigitHexToDecNum(long_address[37]) * 16 + DigitHexToDecNum(long_address[38]));
return IsRoutableAddress(ipv4);
}
return true;
}
if (long_address[0] == 'f')
{
if (long_address[1] == 'e')
{
// fe80::/10 (link local)
const TCHAR& c = long_address[2];
int v;
if (c >= 'a')
v = c - 'a' + 10;
else
v = c - '0';
if ((v & 0xc) == 0x8)
return false;
return true;
}
else if (long_address[1] == 'c' || long_address[1] == 'd')
{
// fc00::/7 (site local)
return false;
}
}
return true;
}
else
{
// Assumes address is already a valid IP address
if (address.Left(3) == _T("127") ||
address.Left(3) == _T("10.") ||
address.Left(7) == _T("192.168") ||
address.Left(7) == _T("169.254"))
return false;
if (address.Left(3) == _T("172"))
{
CStdString middle = address.Mid(4);
int pos = address.Find(_T("."));
if (pos == -1)
return false;
int part = _ttoi(middle.Left(pos));
if (part >= 16 && part <= 31)
return false;
}
return true;
}
}
bool IsIpAddress(const CStdString& address)
{
if (GetIPV6LongForm(address) != _T(""))
return true;
int segment = 0;
int dotcount = 0;
for (int i = 0; i < address.GetLength(); ++i)
{
const TCHAR& c = address[i];
if (c == '.')
{
if (address[i + 1] == '.')
// Disallow multiple dots in a row
return false;
if (segment > 255)
return false;
if (!dotcount && !segment)
return false;
dotcount++;
segment = 0;
}
else if (c < '0' || c > '9')
return false;
segment = segment * 10 + c - '0';
}
if (dotcount != 3)
return false;
if (segment > 255)
return false;
return true;
}
CStdString GetIPV6ShortForm(const CStdString& ip)
{
// This could be optimized a lot.
// First get the long form in a well-known format
CStdString l = GetIPV6LongForm(ip);
if (l.IsEmpty())
return CStdString();
LPCTSTR p = l;
TCHAR outbuf[42];
*outbuf = ':';
TCHAR* out = outbuf + 1;
bool segmentStart = true;
bool readLeadingZero = false;
while (*p)
{
switch (*p)
{
case ':':
if (readLeadingZero)
*(out++) = '0';
*out++ = ':';
readLeadingZero = false;
segmentStart = true;
break;
case '0':
if (segmentStart)
readLeadingZero = true;
else
{
*out++ = '0';
readLeadingZero = false;
}
break;
default:
readLeadingZero = false;
segmentStart = false;
*out++ = *p;
break;
}
++p;
}
*(out++) = ':';
*out = 0;
// Replace longest run of concesutive zeroes
CStdString shortIp(outbuf);
CStdString s = _T(":0:0:0:0:0:0:0:0:");
while (s.GetLength() > 2)
{
int pos = shortIp.Find(s);
if (pos != -1)
{
shortIp = shortIp.Left( pos + 1 ) + shortIp.Mid(pos + s.GetLength() -1);
break;
}
s = s.Mid(2);
}
if (shortIp[0] == ':' && shortIp[1] != ':')
shortIp = shortIp.Mid(1);
if (shortIp[shortIp.GetLength()-1] == ':' && shortIp[shortIp.GetLength()-2] != ':')
shortIp = shortIp.Left(shortIp.GetLength()-1);
return shortIp;
}
|