source: filezilla/trunk/fuentes/src/engine/misc.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

File size: 8.7 KB
Line 
1#include <filezilla.h>
2#include <gnutls/gnutls.h>
3#include <sqlite3.h>
4#include <random>
5#include <cstdint>
6
7#include "timeex.h"
8#include "tlssocket.h"
9
10wxString GetIPV6LongForm(wxString short_address)
11{
12        if (!short_address.empty() && short_address[0] == '[') {
13                if (short_address.Last() != ']')
14                        return wxString();
15                short_address.RemoveLast();
16                short_address = short_address.Mid(1);
17        }
18        short_address.MakeLower();
19
20        wxChar buffer[40] = { '0', '0', '0', '0', ':',
21                                                  '0', '0', '0', '0', ':',
22                                                  '0', '0', '0', '0', ':',
23                                                  '0', '0', '0', '0', ':',
24                                                  '0', '0', '0', '0', ':',
25                                                  '0', '0', '0', '0', ':',
26                                                  '0', '0', '0', '0', ':',
27                                                  '0', '0', '0', '0', 0
28                                                };
29        wxChar* out = buffer;
30
31        const unsigned int len = short_address.Len();
32        if (len > 39)
33                return wxString();
34
35        // First part, before possible ::
36        unsigned int i = 0;
37        unsigned int grouplength = 0;
38
39        wxChar const* s = short_address.c_str(); // Get it zero-terminated.
40        for (i = 0; i < len + 1; ++i) {
41                const wxChar& c = s[i];
42                if (c == ':' || !c) {
43                        if (!grouplength) {
44                                // Empty group length, not valid
45                                if (!c || s[i + 1] != ':')
46                                        return wxString();
47                                ++i;
48                                break;
49                        }
50
51                        out += 4 - grouplength;
52                        for (unsigned int j = grouplength; j > 0; j--)
53                                *out++ = s[i - j];
54                        // End of string...
55                        if (!c) {
56                                if (!*out)
57                                        // ...on time
58                                        return buffer;
59                                else
60                                        // ...premature
61                                        return wxString();
62                        }
63                        else if (!*out) {
64                                // Too long
65                                return wxString();
66                        }
67
68                        ++out;
69
70                        grouplength = 0;
71                        if (s[i + 1] == ':') {
72                                ++i;
73                                break;
74                        }
75                        continue;
76                }
77                else if ((c < '0' || c > '9') &&
78                                 (c < 'a' || c > 'f'))
79                {
80                        // Invalid character
81                        return wxString();
82                }
83                // Too long group
84                if (++grouplength > 4)
85                        return wxString();
86        }
87
88        // Second half after ::
89
90        wxChar* end_first = out;
91        out = &buffer[38];
92        unsigned int stop = i;
93        for (i = len - 1; i > stop; i--)
94        {
95                if (out < end_first)
96                {
97                        // Too long
98                        return wxString();
99                }
100
101                const wxChar& c = s[i];
102                if (c == ':')
103                {
104                        if (!grouplength)
105                        {
106                                // Empty group length, not valid
107                                return wxString();
108                        }
109
110                        out -= 5 - grouplength;
111
112                        grouplength = 0;
113                        continue;
114                }
115                else if ((c < '0' || c > '9') &&
116                                 (c < 'a' || c > 'f'))
117                {
118                        // Invalid character
119                        return wxString();
120                }
121                // Too long group
122                if (++grouplength > 4)
123                        return wxString();
124                *out-- = c;
125        }
126        if (!grouplength)
127        {
128                // Empty group length, not valid
129                return wxString();
130        }
131        out -= 5 - grouplength;
132        out += 2;
133
134        int diff = out - end_first;
135        if (diff < 0 || diff % 5)
136                return wxString();
137
138        return buffer;
139}
140
141int DigitHexToDecNum(wxChar c)
142{
143        if (c >= 'a')
144                return c - 'a' + 10;
145        if (c >= 'A')
146                return c - 'A' + 10;
147        else
148                return c - '0';
149}
150
151bool IsRoutableAddress(const wxString& address, CSocket::address_family family)
152{
153        if (family == CSocket::ipv6)
154        {
155                wxString long_address = GetIPV6LongForm(address);
156                if (long_address.size() != 39)
157                        return false;
158                if (long_address[0] == '0')
159                {
160                        // ::/128
161                        if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0000"))
162                                return false;
163                        // ::1/128
164                        if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0001"))
165                                return false;
166
167                        if (long_address.Left(30) == _T("0000:0000:0000:0000:0000:ffff:"))
168                        {
169                                // IPv4 mapped
170                                wxString ipv4 = wxString::Format(_T("%d.%d.%d.%d"),
171                                                DigitHexToDecNum(long_address[30]) * 16 + DigitHexToDecNum(long_address[31]),
172                                                DigitHexToDecNum(long_address[32]) * 16 + DigitHexToDecNum(long_address[33]),
173                                                DigitHexToDecNum(long_address[35]) * 16 + DigitHexToDecNum(long_address[36]),
174                                                DigitHexToDecNum(long_address[37]) * 16 + DigitHexToDecNum(long_address[38]));
175                                return IsRoutableAddress(ipv4, CSocket::ipv4);
176                        }
177
178                        return true;
179                }
180                if (long_address[0] == 'f')
181                {
182                        if (long_address[1] == 'e')
183                        {
184                                // fe80::/10 (link local)
185                                const wxChar& c = long_address[2];
186                                int v;
187                                if (c >= 'a')
188                                        v = c - 'a' + 10;
189                                else
190                                        v = c - '0';
191                                if ((v & 0xc) == 0x8)
192                                        return false;
193
194                                return true;
195                        }
196                        else if (long_address[1] == 'c' || long_address[1] == 'd')
197                        {
198                                // fc00::/7 (site local)
199                                return false;
200                        }
201                }
202
203                return true;
204        }
205        else
206        {
207                // Assumes address is already a valid IP address
208                if (address.Left(3) == _T("127") ||
209                        address.Left(3) == _T("10.") ||
210                        address.Left(7) == _T("192.168") ||
211                        address.Left(7) == _T("169.254"))
212                        return false;
213
214                if (address.Left(3) == _T("172"))
215                {
216                        wxString middle = address.Mid(4);
217                        int pos = address.Find(_T("."));
218                        wxASSERT(pos != -1);
219                        long part;
220                        middle.Left(pos).ToLong(&part);
221
222                        if (part >= 16 && part <= 31)
223                                return false;
224                }
225
226                return true;
227        }
228}
229
230bool IsIpAddress(const wxString& address)
231{
232        if (!GetIPV6LongForm(address).empty())
233                return true;
234
235        int segment = 0;
236        int dotcount = 0;
237        for (size_t i = 0; i < address.Len(); ++i) {
238                wxChar const c = address[i];
239                if (c == '.') {
240                        if (i + 1 < address.Len() && address[i + 1] == '.') {
241                                // Disallow multiple dots in a row
242                                return false;
243                        }
244
245                        if (segment > 255)
246                                return false;
247                        if (!dotcount && !segment)
248                                return false;
249                        dotcount++;
250                        segment = 0;
251                }
252                else if (c < '0' || c > '9') {
253                        return false;
254                }
255                else {
256                        segment = segment * 10 + c - '0';
257                }
258        }
259        if (dotcount != 3)
260                return false;
261
262        if (segment > 255)
263                return false;
264
265        return true;
266}
267
268namespace {
269#if defined(__WXMSW__) && !defined(_MSC_VER)
270// Unfortunately MiNGW does not have a working random_device
271// Implement our own in terms of CryptGenRandom.
272// Fall back to time-seeded mersenne twister on error
273struct provider
274{
275        provider()
276        {
277                if (!CryptAcquireContextW(&h_, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
278                        h_ = 0;
279                }
280                mt_.seed(CDateTime::Now().GetTimeT());
281        }
282        ~provider()
283        {
284                if (h_) {
285                        CryptReleaseContext(h_, 0);
286                }
287        }
288
289        HCRYPTPROV h_{};
290        std::mt19937_64 mt_;
291};
292
293struct working_random_device
294{
295        typedef uint64_t result_type;
296
297        constexpr static result_type min() { return std::numeric_limits<result_type>::min(); }
298        constexpr static result_type max() { return std::numeric_limits<result_type>::max(); }
299
300        result_type operator()()
301        {
302                thread_local provider prov;
303
304                result_type ret{};
305                if (!prov.h_ || !CryptGenRandom(prov.h_, sizeof(ret), reinterpret_cast<BYTE*>(&ret))) {
306                        ret = prov.mt_();
307                }
308
309                return ret;
310        }
311};
312
313static_assert(working_random_device::max() == std::mt19937_64::max(), "Unsupported std::mt19937_64::max()");
314static_assert(working_random_device::min() == std::mt19937_64::min(), "Unsupported std::mt19937_64::min()");
315#else
316typedef std::random_device working_random_device;
317#endif
318}
319
320int GetRandomNumber(int min, int max)
321{
322        wxASSERT(min <= max);
323        if (min >= max)
324                return min;
325
326        std::uniform_int_distribution<int> dist(min, max);
327        working_random_device rd;
328        return dist(rd);
329}
330
331void MakeLowerAscii(wxString& str)
332{
333        for (size_t i = 0; i < str.size(); i++) {
334                wxChar c = str.GetChar(i);
335                if (c >= 'A' && c <= 'Z') {
336                        c += 32;
337                        str.SetChar(i, wxUniChar(c));
338                }
339                else if (c == 0x130 || c == 0x131) {
340                        c = 'i';
341                        str.SetChar(i, wxUniChar(c));
342                }
343        }
344}
345
346void MakeLowerAscii(fzstring& str)
347{
348        for (size_t i = 0; i < str.size(); i++) {
349                auto & c = str[i];
350                if (c >= 'A' && c <= 'Z') {
351                        c += 32;
352                }
353                else if (c == 0x130 || c == 0x131) {
354                        c = 'i';
355                }
356        }
357}
358
359wxString GetDependencyVersion(dependency::type d)
360{
361        switch (d) {
362        case dependency::wxwidgets:
363                return wxVERSION_NUM_DOT_STRING_T;
364        case dependency::gnutls:
365                {
366                        const char* v = gnutls_check_version(0);
367                        if (!v || !*v)
368                                return _T("unknown");
369
370                        return wxString(v, wxConvLibc);
371                }
372        case dependency::sqlite:
373                return wxString::FromUTF8(sqlite3_libversion());
374        default:
375                return wxString();
376        }
377}
378
379wxString GetDependencyName(dependency::type d)
380{
381        switch (d) {
382        case dependency::wxwidgets:
383                return _T("wxWidgets");
384        case dependency::gnutls:
385                return _T("GnuTLS");
386        case dependency::sqlite:
387                return _T("SQLite");
388        default:
389                return wxString();
390        }
391}
392
393wxString ListTlsCiphers(const wxString& priority)
394{
395        return CTlsSocket::ListTlsCiphers(priority);
396}
397
398#ifdef __WXMSW__
399bool IsAtLeast(int major, int minor = 0)
400{
401        OSVERSIONINFOEX vi = { 0 };
402        vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
403        vi.dwMajorVersion = major;
404        vi.dwMinorVersion = minor;
405        vi.dwPlatformId = VER_PLATFORM_WIN32_NT;
406
407        DWORDLONG mask = 0;
408        VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
409        VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL);
410        VER_SET_CONDITION(mask, VER_PLATFORMID, VER_EQUAL);
411        return VerifyVersionInfo(&vi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, mask) != 0;
412}
413#endif
414
415bool GetRealOsVersion(int& major, int& minor)
416{
417#ifndef __WXMSW__
418        return wxGetOsVersion(&major, &minor) != wxOS_UNKNOWN;
419#else
420        major = 4;
421        minor = 0;
422        while (IsAtLeast(++major, minor))
423        {
424        }
425        --major;
426        while (IsAtLeast(major, ++minor))
427        {
428        }
429        --minor;
430
431        return true;
432#endif
433}
Note: See TracBrowser for help on using the repository browser.