Initial Commit
This commit is contained in:
546
database/FileZillaFTP/source/iputils.cpp
Normal file
546
database/FileZillaFTP/source/iputils.cpp
Normal file
@@ -0,0 +1,546 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user