Server : Apache/2.4.43 (Win64) OpenSSL/1.1.1g PHP/7.4.6 System : Windows NT USER-PC 6.1 build 7601 (Windows 7 Professional Edition Service Pack 1) AMD64 User : User ( 0) PHP Version : 7.4.6 Disable Function : NONE Directory : C:/xampp/FileZillaFTP/source/ |
// 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; }