1 |
#ifndef _YEBISOCKS_PROXYWSOCKHOOK_H_ |
2 |
#define _YEBISOCKS_PROXYWSOCKHOOK_H_ |
3 |
|
4 |
#include <YCL/StringBuffer.h> |
5 |
#include <YCL/Dialog.h> |
6 |
#include <YCL/ComboBoxCtrl.h> |
7 |
#include <YCL/EditBoxCtrl.h> |
8 |
#include <YCL/IniFile.h> |
9 |
#include <YCL/Resource.h> |
10 |
#include <YCL/FileVersion.h> |
11 |
using namespace yebisuya; |
12 |
|
13 |
#include "resource.h" |
14 |
#include "Hooker.h" |
15 |
#include "Logger.h" |
16 |
#include "SSLSocket.h" |
17 |
|
18 |
class ProxyWSockHook { |
19 |
public: |
20 |
class MessageShower { |
21 |
public: |
22 |
virtual void showMessage(const char* message)const = NULL; |
23 |
}; |
24 |
private: |
25 |
struct DUMMYHOSTENT { |
26 |
struct hostent entry; |
27 |
in_addr addr; |
28 |
char* addrlist[2]; |
29 |
char* alias; |
30 |
char hostname[1]; |
31 |
}; |
32 |
|
33 |
class AsyncSelectInfoTable { |
34 |
private: |
35 |
struct AsyncSelectInfo { |
36 |
HWND window; |
37 |
UINT message; |
38 |
long event; |
39 |
AsyncSelectInfo():window(NULL), message(0), event(0) { |
40 |
} |
41 |
AsyncSelectInfo(const AsyncSelectInfo& src):window(src.window), message(src.message), event(src.event) { |
42 |
} |
43 |
AsyncSelectInfo(HWND window, UINT message, long event):window(window), message(message), event(event) { |
44 |
} |
45 |
bool operator==(const AsyncSelectInfo& src) { |
46 |
return window == src.window && message == src.message && event == src.event; |
47 |
} |
48 |
void operator=(const AsyncSelectInfo& src) { |
49 |
window = src.window; |
50 |
message = src.message; |
51 |
event = src.event; |
52 |
} |
53 |
void operator=(int v) { |
54 |
if (v == 0) { |
55 |
window = NULL; |
56 |
message = 0; |
57 |
event = 0; |
58 |
} |
59 |
} |
60 |
operator int()const { |
61 |
return window == NULL && message == 0 && event == 0 ? 0 : (int) window; |
62 |
} |
63 |
}; |
64 |
Hashtable<SOCKET, AsyncSelectInfo> table; |
65 |
mutable CRITICAL_SECTION section; |
66 |
public: |
67 |
AsyncSelectInfoTable() { |
68 |
::InitializeCriticalSection(§ion); |
69 |
} |
70 |
~AsyncSelectInfoTable() { |
71 |
::DeleteCriticalSection(§ion); |
72 |
} |
73 |
void put(SOCKET s, HWND window, UINT message, long event) { |
74 |
::EnterCriticalSection(§ion); |
75 |
if (message != 0 || event != 0) { |
76 |
table.put(s, AsyncSelectInfo(window, message, event)); |
77 |
}else{ |
78 |
table.remove(s); |
79 |
} |
80 |
::LeaveCriticalSection(§ion); |
81 |
} |
82 |
void get(SOCKET s, HWND& window, UINT& message, long& event)const { |
83 |
::EnterCriticalSection(§ion); |
84 |
AsyncSelectInfo info = table.get(s); |
85 |
::LeaveCriticalSection(§ion); |
86 |
window = info.window; |
87 |
message = info.message; |
88 |
event = info.event; |
89 |
} |
90 |
}; |
91 |
class ProxyInfo { |
92 |
public: |
93 |
enum Type { |
94 |
TYPE_NONE, |
95 |
TYPE_HTTP, |
96 |
TYPE_TELNET, |
97 |
TYPE_SOCKS4, |
98 |
TYPE_SOCKS5, |
99 |
TYPE_SSL, |
100 |
TYPE_HTTP_SSL, |
101 |
TYPE_TELNET_SSL, |
102 |
TYPE_SOCKS4_SSL, |
103 |
TYPE_SOCKS5_SSL, |
104 |
TYPE_NONE_FORCE, |
105 |
}; |
106 |
private: |
107 |
struct PROXY_TYPE_TABLE { |
108 |
Type type; |
109 |
const char* name; |
110 |
}; |
111 |
static const PROXY_TYPE_TABLE* proxy_type_table() { |
112 |
static PROXY_TYPE_TABLE table[] = { |
113 |
{TYPE_HTTP, "http"}, |
114 |
{TYPE_SOCKS5, "socks"}, |
115 |
{TYPE_SOCKS4, "socks4"}, |
116 |
{TYPE_TELNET, "telnet"}, |
117 |
{TYPE_SOCKS5, "socks5"}, |
118 |
{TYPE_NONE_FORCE, "none"}, |
119 |
{TYPE_HTTP_SSL, "http+ssl"}, |
120 |
{TYPE_SOCKS5_SSL, "socks+ssl"}, |
121 |
{TYPE_SOCKS4_SSL, "socks4+ssl"}, |
122 |
{TYPE_TELNET_SSL, "telnet+ssl"}, |
123 |
{TYPE_SOCKS5_SSL, "socks5+ssl"}, |
124 |
{TYPE_SSL, "ssl"}, |
125 |
{TYPE_SSL, "none+ssl"}, |
126 |
{TYPE_NONE, NULL}, |
127 |
}; |
128 |
return table; |
129 |
} |
130 |
public: |
131 |
static Type parseType(const char* string) { |
132 |
return parseType(string, string + strlen(string)); |
133 |
} |
134 |
static Type parseType(const char* string, const char* end) { |
135 |
int length = end - string; |
136 |
char* buffer = (char*) alloca(length + 1); |
137 |
char* dst = buffer; |
138 |
while (length-- > 0 && *string != '\0') { |
139 |
int ch = *string++; |
140 |
if ('A' <= ch && ch <= 'Z') { |
141 |
ch += 'a' - 'A'; |
142 |
} |
143 |
*dst++ = ch; |
144 |
} |
145 |
*dst = '\0'; |
146 |
const PROXY_TYPE_TABLE* table = proxy_type_table(); |
147 |
while (table->name != NULL) { |
148 |
if (strcmp(buffer, table->name) == 0) |
149 |
return table->type; |
150 |
table++; |
151 |
} |
152 |
return TYPE_NONE; |
153 |
} |
154 |
static const char* getTypeName(Type type) { |
155 |
if (type != TYPE_NONE && type != TYPE_NONE_FORCE) { |
156 |
const PROXY_TYPE_TABLE* table = proxy_type_table(); |
157 |
while (table->name != NULL) { |
158 |
if (type == table->type) |
159 |
return table->name; |
160 |
table++; |
161 |
} |
162 |
} |
163 |
return NULL; |
164 |
} |
165 |
|
166 |
static int parsePort(const char* string) { |
167 |
return parsePort(string, string + strlen(string)); |
168 |
} |
169 |
static int parsePort(const char* string, const char* end) { |
170 |
if (string > end || *string < '1' || '9' < *string) |
171 |
return -1; |
172 |
int digit = 0; |
173 |
while (string < end) { |
174 |
if (*string < '0' || '9' < *string) |
175 |
return -1; |
176 |
digit = digit * 10 + (*string - '0'); |
177 |
if (digit > 65535) |
178 |
return -1; |
179 |
string++; |
180 |
} |
181 |
if (digit == 0) |
182 |
return -1; |
183 |
return digit; |
184 |
} |
185 |
|
186 |
static String parse(const char* url, ProxyInfo& proxy) { |
187 |
char* p = strstr((char*) url, "://"); |
188 |
if (p == NULL) { |
189 |
proxy.type = TYPE_NONE; |
190 |
return NULL; |
191 |
} |
192 |
proxy.type = parseType(url, p); |
193 |
if (proxy.type == TYPE_NONE) |
194 |
return NULL; |
195 |
p += 3; |
196 |
const char* start = p; |
197 |
while (*p != '\0' && *p != '/') { |
198 |
if (*p == ':') { |
199 |
if (proxy.host != NULL || start >= p) { |
200 |
proxy.type = TYPE_NONE; |
201 |
return NULL; |
202 |
} |
203 |
proxy.host = urldecode(start, p); |
204 |
start = p + 1; |
205 |
}else if (*p == '@') { |
206 |
if (proxy.user != NULL) { |
207 |
proxy.type = TYPE_NONE; |
208 |
return NULL; |
209 |
} |
210 |
if (proxy.host == NULL) { |
211 |
proxy.user = urldecode(start, p); |
212 |
}else{ |
213 |
proxy.user = proxy.host; |
214 |
proxy.pass = urldecode(start, p); |
215 |
proxy.host = NULL; |
216 |
} |
217 |
start = p + 1; |
218 |
} |
219 |
p++; |
220 |
} |
221 |
if (proxy.type != TYPE_NONE_FORCE && proxy.type != TYPE_SSL) { |
222 |
if (proxy.host == NULL) { |
223 |
if (start >= p) { |
224 |
proxy.type = TYPE_NONE; |
225 |
return NULL; |
226 |
} |
227 |
proxy.host = urldecode(start, p); |
228 |
}else{ |
229 |
proxy.port = parsePort(start, p); |
230 |
if (proxy.port < 0) { |
231 |
proxy.type = TYPE_NONE; |
232 |
return NULL; |
233 |
} |
234 |
} |
235 |
} |
236 |
if (*p == '/') |
237 |
p++; |
238 |
return p; |
239 |
} |
240 |
String generateURL()const { |
241 |
if (type == TYPE_NONE || host == NULL) |
242 |
return NULL; |
243 |
StringBuffer buffer; |
244 |
buffer.append(getTypeName(type)); |
245 |
buffer.append("://"); |
246 |
if (type != TYPE_SSL) { |
247 |
if (user != NULL) { |
248 |
urlencode(user, buffer); |
249 |
if (pass != NULL) { |
250 |
buffer.append(':'); |
251 |
urlencode(pass, buffer); |
252 |
} |
253 |
buffer.append('@'); |
254 |
} |
255 |
urlencode(host, buffer); |
256 |
if (port != 0) { |
257 |
buffer.append(':'); |
258 |
int digit = 10000; |
259 |
while (digit > 0 && (unsigned) port < (unsigned) digit) { |
260 |
digit /= 10; |
261 |
} |
262 |
while (digit > 0) { |
263 |
int d = (unsigned) port / digit % 10; |
264 |
digit /= 10; |
265 |
buffer.append('0' + d); |
266 |
} |
267 |
} |
268 |
} |
269 |
return buffer.toString(); |
270 |
} |
271 |
private: |
272 |
static int hexdigit(int ch) { |
273 |
if ('0' <= ch && ch <= '9') { |
274 |
return ch - '0'; |
275 |
}else if ('A' <= ch && ch <= 'F') { |
276 |
return ch - 'A' + 10; |
277 |
}else if ('a' <= ch && ch <= 'f') { |
278 |
return ch - 'a' + 10; |
279 |
}else{ |
280 |
return -1; |
281 |
} |
282 |
} |
283 |
|
284 |
static String urldecode(const char* start, const char* end) { |
285 |
char* buffer = (char*) alloca((end - start) * 3 + 1); |
286 |
char* dst = buffer; |
287 |
int c1, c2; |
288 |
while (start < end) { |
289 |
if (*start == '%' && start + 2 < end && (c1 = hexdigit(start[1])) != -1 && (c2 = hexdigit(start[2])) != -1) { |
290 |
*buffer++ = (char) (c1 << 4 | c2); |
291 |
start += 3; |
292 |
}else{ |
293 |
if (IsDBCSLeadByte(*start)) { |
294 |
*dst++ = *start++; |
295 |
} |
296 |
*dst++ = *start++; |
297 |
} |
298 |
} |
299 |
*dst = '\0'; |
300 |
return buffer; |
301 |
} |
302 |
static String urlencode(const char* string, StringBuffer& buffer) { |
303 |
static const char table[] = "0123456789ABCDEF"; |
304 |
const char* start = string; |
305 |
while (*string != '\0') { |
306 |
if ('0' <= *string && *string <= '0' |
307 |
|| 'A' <= *string && *string <= 'Z' |
308 |
|| 'a' <= *string && *string <= 'z' |
309 |
|| *string == '-' || *string == '.' || *string == '_') { |
310 |
}else if (::IsDBCSLeadByte(*string)) { |
311 |
string++; |
312 |
}else{ |
313 |
if (start < string) { |
314 |
buffer.append(start, string - start); |
315 |
} |
316 |
buffer.append('%'); |
317 |
buffer.append(table[(unsigned) *string >> 4]); |
318 |
buffer.append(table[(unsigned) *string & 0x0f]); |
319 |
start = string + 1; |
320 |
} |
321 |
string++; |
322 |
} |
323 |
if (start < string) { |
324 |
buffer.append(start); |
325 |
} |
326 |
return buffer; |
327 |
} |
328 |
public: |
329 |
ProxyInfo():type(TYPE_NONE), port(0) { |
330 |
} |
331 |
~ProxyInfo() { |
332 |
} |
333 |
short getPort() { |
334 |
if (port == 0) { |
335 |
switch (type) { |
336 |
case TYPE_SOCKS4: |
337 |
case TYPE_SOCKS5: |
338 |
case TYPE_SOCKS4_SSL: |
339 |
case TYPE_SOCKS5_SSL: |
340 |
return 1080; |
341 |
case TYPE_TELNET: |
342 |
case TYPE_TELNET_SSL: |
343 |
return 23; |
344 |
case TYPE_HTTP: |
345 |
case TYPE_HTTP_SSL: |
346 |
return 80; |
347 |
} |
348 |
} |
349 |
return port; |
350 |
} |
351 |
Type type; |
352 |
String host; |
353 |
short port; |
354 |
String user; |
355 |
String pass; |
356 |
}; |
357 |
|
358 |
struct ConnectionInfo { |
359 |
ProxyInfo proxy; |
360 |
String realhost; |
361 |
short realport; |
362 |
in_addr addr; |
363 |
char* buffer; |
364 |
DWORD time; |
365 |
ConnectionInfo(ProxyInfo& proxy, String realhost):proxy(proxy), realhost(realhost), buffer(NULL) { |
366 |
} |
367 |
~ConnectionInfo() { |
368 |
delete[] buffer; |
369 |
} |
370 |
void fillBuffer(char* buffer, int bufferLength) { |
371 |
DUMMYHOSTENT* dst = (DUMMYHOSTENT*) buffer; |
372 |
dst->addr = addr; |
373 |
dst->addrlist[0] = (char*) &dst->addr; |
374 |
dst->addrlist[1] = NULL; |
375 |
dst->entry.h_addr_list = dst->addrlist; |
376 |
dst->alias = NULL; |
377 |
dst->entry.h_aliases = &dst->alias; |
378 |
dst->entry.h_addrtype = AF_INET; |
379 |
dst->entry.h_length = sizeof (in_addr); |
380 |
dst->entry.h_name = dst->hostname; |
381 |
strcpy_s(dst->hostname, bufferLength - sizeof (DUMMYHOSTENT), realhost); |
382 |
} |
383 |
}; |
384 |
class ConnectionInfoHolder { |
385 |
private: |
386 |
ConnectionInfo* info; |
387 |
public: |
388 |
ConnectionInfoHolder():info(NULL) { |
389 |
} |
390 |
~ConnectionInfoHolder() { |
391 |
delete info; |
392 |
} |
393 |
operator ConnectionInfo*()const { |
394 |
return info; |
395 |
} |
396 |
void operator=(ConnectionInfo* newInfo) { |
397 |
if (info != newInfo) { |
398 |
delete info; |
399 |
info = newInfo; |
400 |
} |
401 |
} |
402 |
// �����o�I�����Z�q |
403 |
ConnectionInfo* operator->()const { |
404 |
return info; |
405 |
} |
406 |
}; |
407 |
|
408 |
class ConnectionInfoList { |
409 |
private: |
410 |
CRITICAL_SECTION section; |
411 |
ConnectionInfoHolder list[254]; |
412 |
Hashtable<String,ConnectionInfo*> table; |
413 |
public: |
414 |
ConnectionInfoList() { |
415 |
::InitializeCriticalSection(§ion); |
416 |
} |
417 |
~ConnectionInfoList() { |
418 |
::DeleteCriticalSection(§ion); |
419 |
} |
420 |
HANDLE getTask(ConnectionInfo* info) { |
421 |
if (info == NULL) |
422 |
return NULL; |
423 |
return (HANDLE) -info->addr.S_un.S_un_b.s_b4; |
424 |
} |
425 |
ConnectionInfo* get(HANDLE task) { |
426 |
if ((DWORD) task >= 0) |
427 |
return NULL; |
428 |
return get((int) -((long) task) - 1); |
429 |
} |
430 |
ConnectionInfo* get(in_addr addr) { |
431 |
if (addr.S_un.S_un_b.s_b1 != 0 || addr.S_un.S_un_b.s_b2 != 0 || addr.S_un.S_un_b.s_b3 != 0) |
432 |
return NULL; |
433 |
return get(addr.S_un.S_un_b.s_b4 - 1); |
434 |
} |
435 |
ConnectionInfo* get(int index) { |
436 |
::EnterCriticalSection(§ion); |
437 |
ConnectionInfo* info = 0 <= index && index < countof(list) ? (ConnectionInfo*) list[index] : NULL; |
438 |
::LeaveCriticalSection(§ion); |
439 |
return info; |
440 |
} |
441 |
ConnectionInfo* find(const char* url) { |
442 |
::EnterCriticalSection(§ion); |
443 |
ConnectionInfo* info = table.get(url); |
444 |
::LeaveCriticalSection(§ion); |
445 |
if (info != NULL) { |
446 |
info->time = ::GetTickCount(); |
447 |
return info; |
448 |
} |
449 |
ProxyInfo proxy; |
450 |
String realhost = ProxyInfo::parse(url, proxy); |
451 |
if (realhost == NULL || realhost.length() == 0) { |
452 |
proxy = instance().defaultProxy; |
453 |
if (proxy.type != ProxyInfo::TYPE_NONE) { |
454 |
realhost = url; |
455 |
} |
456 |
} |
457 |
if (proxy.type == ProxyInfo::TYPE_NONE) |
458 |
return NULL; |
459 |
info = new ConnectionInfo(proxy, realhost); |
460 |
|
461 |
int i; |
462 |
::EnterCriticalSection(§ion); |
463 |
for (i = 0; i < countof(list); i++) { |
464 |
if (list[i] == NULL) { |
465 |
list[i] = info; |
466 |
break; |
467 |
} |
468 |
} |
469 |
if (i >= countof(list)) { |
470 |
DWORD now = ::GetTickCount(); |
471 |
DWORD max = 0; |
472 |
int index = -1; |
473 |
for (i = 0; i < countof(list); i++) { |
474 |
if (list[i] != NULL) { |
475 |
if (now - list[i]->time > max) { |
476 |
max = now - list[i]->time; |
477 |
index = i; |
478 |
} |
479 |
} |
480 |
} |
481 |
list[index] = info; |
482 |
} |
483 |
table.put(url, info); |
484 |
::LeaveCriticalSection(§ion); |
485 |
info->addr.s_addr = htonl(i + 1); |
486 |
|
487 |
info->time = ::GetTickCount(); |
488 |
return info; |
489 |
} |
490 |
}; |
491 |
friend class ConnectionInfoList; |
492 |
|
493 |
class OptionsSettingDialog : public Dialog { |
494 |
private: |
495 |
ComboBoxCtrl resolveCombo; |
496 |
Window host; |
497 |
Window user; |
498 |
Window pass; |
499 |
Window conn; |
500 |
Window erro; |
501 |
Window log; |
502 |
protected: |
503 |
virtual bool dispatch(int message, int wParam, long lParam) { |
504 |
if (message == WM_COMMAND && wParam == MAKEWPARAM(IDC_REFER, BN_CLICKED)) { |
505 |
char buffer[1024]; |
506 |
OPENFILENAME ofn = { |
507 |
sizeof ofn, |
508 |
*this, |
509 |
}; |
510 |
ofn.lpstrFile = buffer; |
511 |
ofn.nMaxFile = countof(buffer); |
512 |
ofn.Flags = OFN_LONGNAMES | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_NOREADONLYRETURN | OFN_HIDEREADONLY; |
513 |
static String title = Resource::loadString(IDS_LOGFILE_SELECT); |
514 |
ofn.lpstrTitle = title; |
515 |
if (logfile != NULL) { |
516 |
strcpy_s(buffer, sizeof buffer, logfile); |
517 |
}else{ |
518 |
buffer[0] = '\0'; |
519 |
} |
520 |
if (::GetSaveFileName(&ofn)) { |
521 |
if (buffer[0] != '\0') { |
522 |
logfile = buffer; |
523 |
}else{ |
524 |
logfile = NULL; |
525 |
} |
526 |
log.SetWindowText(buffer); |
527 |
} |
528 |
return true; |
529 |
} |
530 |
return Dialog::dispatch(message, wParam, lParam); |
531 |
} |
532 |
virtual bool onInitDialog() { |
533 |
Dialog::onInitDialog(); |
534 |
|
535 |
host = GetDlgItem(IDC_HOSTNAME); |
536 |
user = GetDlgItem(IDC_USERNAME); |
537 |
pass = GetDlgItem(IDC_PASSWORD); |
538 |
conn = GetDlgItem(IDC_CONNECTED); |
539 |
erro = GetDlgItem(IDC_ERROR); |
540 |
log = GetDlgItem(IDC_LOGFILE); |
541 |
|
542 |
SetDlgItemInt(IDC_TIMEOUT, timeout, false); |
543 |
|
544 |
resolveCombo <<= GetDlgItem(IDC_RESOLVE); |
545 |
resolveCombo.addString(instance().loadString(IDS_RESOLVE_AUTO)); |
546 |
resolveCombo.addString(instance().loadString(IDS_RESOLVE_REMOTE)); |
547 |
resolveCombo.addString(instance().loadString(IDS_RESOLVE_LOCAL)); |
548 |
resolveCombo.setCurSel(resolve); |
549 |
|
550 |
host.SetWindowText(HostnamePrompt); |
551 |
user.SetWindowText(UsernamePrompt); |
552 |
pass.SetWindowText(PasswordPrompt); |
553 |
conn.SetWindowText(ConnectedMessage); |
554 |
erro.SetWindowText(ErrorMessage); |
555 |
|
556 |
if (logfile != NULL) |
557 |
log.SetWindowText(logfile); |
558 |
|
559 |
return true; |
560 |
} |
561 |
virtual void onOK() { |
562 |
if (host.GetWindowTextLength() == 0 |
563 |
|| user.GetWindowTextLength() == 0 |
564 |
|| pass.GetWindowTextLength() == 0 |
565 |
|| conn.GetWindowTextLength() == 0 |
566 |
|| erro.GetWindowTextLength() == 0) { |
567 |
MessageBox(instance().loadString(IDS_EMPTY_PARAMETER), FileVersion::getOwnVersion().getProductName(), MB_OK | MB_ICONERROR); |
568 |
return; |
569 |
} |
570 |
|
571 |
timeout = GetDlgItemInt(IDC_TIMEOUT, 0, false); |
572 |
|
573 |
resolve = resolveCombo.getCurSel(); |
574 |
|
575 |
HostnamePrompt = host.GetWindowText(); |
576 |
UsernamePrompt = user.GetWindowText(); |
577 |
PasswordPrompt = pass.GetWindowText(); |
578 |
ConnectedMessage = conn.GetWindowText(); |
579 |
ErrorMessage = erro.GetWindowText(); |
580 |
|
581 |
logfile = log.GetWindowTextLength() > 0 ? log.GetWindowText() : NULL; |
582 |
|
583 |
Dialog::onOK(); |
584 |
} |
585 |
public: |
586 |
String logfile; |
587 |
int timeout; |
588 |
int resolve; |
589 |
|
590 |
String HostnamePrompt; |
591 |
String UsernamePrompt; |
592 |
String PasswordPrompt; |
593 |
String ConnectedMessage; |
594 |
String ErrorMessage; |
595 |
|
596 |
int open(HWND owner) { |
597 |
return Dialog::open(instance().resource_module, IDD_OPTION_SETTING, owner); |
598 |
} |
599 |
}; |
600 |
friend class OptionsSettingDialog; |
601 |
|
602 |
class SettingDialog : public Dialog { |
603 |
private: |
604 |
EditBoxCtrl url; |
605 |
ComboBoxCtrl type; |
606 |
EditBoxCtrl host; |
607 |
EditBoxCtrl port; |
608 |
EditBoxCtrl user; |
609 |
EditBoxCtrl pass; |
610 |
bool lock; |
611 |
protected: |
612 |
virtual bool dispatch(int message, int wParam, long lParam) { |
613 |
if (message == WM_COMMAND) { |
614 |
switch (wParam) { |
615 |
case MAKEWPARAM(IDC_OPTIONS, BN_CLICKED): |
616 |
onOptions(); |
617 |
return true; |
618 |
case MAKEWPARAM(IDC_TYPE, CBN_SELCHANGE): |
619 |
case MAKEWPARAM(IDC_HOSTNAME, EN_CHANGE): |
620 |
case MAKEWPARAM(IDC_PORT, EN_CHANGE): |
621 |
case MAKEWPARAM(IDC_USERNAME, EN_CHANGE): |
622 |
case MAKEWPARAM(IDC_PASSWORD, EN_CHANGE): |
623 |
if (!lock) |
624 |
onChanged(LOWORD(wParam)); |
625 |
return true; |
626 |
} |
627 |
} |
628 |
return Dialog::dispatch(message, wParam, lParam); |
629 |
} |
630 |
virtual bool onInitDialog() { |
631 |
Dialog::onInitDialog(); |
632 |
|
633 |
url <<= GetDlgItem(IDC_URL); |
634 |
type <<= GetDlgItem(IDC_TYPE); |
635 |
host <<= GetDlgItem(IDC_HOSTNAME); |
636 |
port <<= GetDlgItem(IDC_PORT); |
637 |
user <<= GetDlgItem(IDC_USERNAME); |
638 |
pass <<= GetDlgItem(IDC_PASSWORD); |
639 |
|
640 |
lock = true; |
641 |
type.addString(instance().loadString(IDS_TYPE_NONE)); |
642 |
type.addString("HTTP"); |
643 |
type.addString("TELNET"); |
644 |
type.addString("SOCKS4"); |
645 |
type.addString("SOCKS5"); |
646 |
type.addString("SSL"); |
647 |
type.addString("HTTP+SSL"); |
648 |
type.addString("TELNET+SSL"); |
649 |
type.addString("SOCKS4+SSL"); |
650 |
type.addString("SOCKS5+SSL"); |
651 |
type.setCurSel(proxy.type); |
652 |
|
653 |
if (proxy.type != ProxyInfo::TYPE_NONE || proxy.type != ProxyInfo::TYPE_SSL) { |
654 |
if (proxy.host != NULL) { |
655 |
host.SetWindowText(proxy.host); |
656 |
if (proxy.port != 0) { |
657 |
char buffer[16]; |
658 |
_itoa_s(proxy.port, buffer, sizeof buffer, 10); |
659 |
port.SetWindowText(buffer); |
660 |
} |
661 |
if (proxy.user != NULL) { |
662 |
user.SetWindowText(proxy.user); |
663 |
if (proxy.pass != NULL) { |
664 |
pass.SetWindowText(proxy.pass); |
665 |
} |
666 |
} |
667 |
} |
668 |
} |
669 |
lock = false; |
670 |
onChanged(0); |
671 |
return true; |
672 |
} |
673 |
virtual void onOK() { |
674 |
if (proxy.type != ProxyInfo::TYPE_NONE || proxy.type != ProxyInfo::TYPE_SSL) { |
675 |
if (proxy.host == NULL) { |
676 |
MessageBox(instance().loadString(IDS_EMPTY_HOSTNAME), FileVersion::getOwnVersion().getProductName(), MB_OK | MB_ICONERROR); |
677 |
return; |
678 |
} |
679 |
if (port.GetWindowTextLength() != 0 && proxy.port <= 0) { |
680 |
MessageBox(instance().loadString(IDS_ILLEGAL_PORT), FileVersion::getOwnVersion().getProductName(), MB_OK | MB_ICONERROR); |
681 |
return; |
682 |
} |
683 |
} |
684 |
Dialog::onOK(); |
685 |
} |
686 |
void onOptions() { |
687 |
OptionsSettingDialog dlg; |
688 |
dlg.timeout = instance().timeout; |
689 |
switch (instance().resolve) { |
690 |
case RESOLVE_REMOTE: |
691 |
dlg.resolve = 1; |
692 |
break; |
693 |
case RESOLVE_LOCAL: |
694 |
dlg.resolve = 2; |
695 |
break; |
696 |
default: |
697 |
dlg.resolve = 0; |
698 |
break; |
699 |
} |
700 |
dlg.HostnamePrompt = instance().prompt_table[0]; |
701 |
dlg.UsernamePrompt = instance().prompt_table[1]; |
702 |
dlg.PasswordPrompt = instance().prompt_table[2]; |
703 |
dlg.ConnectedMessage = instance().prompt_table[3]; |
704 |
dlg.ErrorMessage = instance().prompt_table[4]; |
705 |
dlg.logfile = instance().logfile; |
706 |
if (dlg.open(*this) == IDOK) { |
707 |
instance().timeout = dlg.timeout; |
708 |
switch (dlg.resolve) { |
709 |
case 1: |
710 |
instance().resolve = RESOLVE_REMOTE; |
711 |
break; |
712 |
case 2: |
713 |
instance().resolve = RESOLVE_LOCAL; |
714 |
break; |
715 |
default: |
716 |
instance().resolve = RESOLVE_AUTO; |
717 |
break; |
718 |
} |
719 |
instance().prompt_table[0] = dlg.HostnamePrompt; |
720 |
instance().prompt_table[1] = dlg.UsernamePrompt; |
721 |
instance().prompt_table[2] = dlg.PasswordPrompt; |
722 |
instance().prompt_table[3] = dlg.ConnectedMessage; |
723 |
instance().prompt_table[4] = dlg.ErrorMessage; |
724 |
|
725 |
if (instance().logfile != dlg.logfile) { |
726 |
instance().logfile = dlg.logfile; |
727 |
Logger::open(dlg.logfile); |
728 |
} |
729 |
} |
730 |
} |
731 |
void onChanged(int id) { |
732 |
if (id == 0 || id == IDC_TYPE || id == IDC_HOSTNAME || id == IDC_USERNAME) { |
733 |
int enabled = 0; |
734 |
int typeN = type.getCurSel(); |
735 |
if (typeN != ProxyInfo::TYPE_NONE || typeN != ProxyInfo::TYPE_SSL) { |
736 |
enabled |= 1; |
737 |
if (::GetWindowTextLength(GetDlgItem(IDC_HOSTNAME)) > 0) { |
738 |
enabled |= 2; |
739 |
if (::GetWindowTextLength(GetDlgItem(IDC_USERNAME)) > 0) { |
740 |
enabled |= 4; |
741 |
} |
742 |
} |
743 |
} |
744 |
::EnableWindow(GetDlgItem(IDC_HOSTNAME), (enabled & 1) != 0); |
745 |
::EnableWindow(GetDlgItem(IDC_PORT), (enabled & 2) != 0); |
746 |
::EnableWindow(GetDlgItem(IDC_USERNAME), (enabled & 2) != 0); |
747 |
::EnableWindow(GetDlgItem(IDC_PASSWORD), (enabled & 4) != 0); |
748 |
} |
749 |
|
750 |
if (id != 0) { |
751 |
proxy.type = (ProxyInfo::Type) type.getCurSel(); |
752 |
if (proxy.type != ProxyInfo::TYPE_NONE || proxy.type != ProxyInfo::TYPE_SSL) { |
753 |
proxy.host = host.GetWindowText(); |
754 |
if (host.GetWindowTextLength() == 0) { |
755 |
proxy.host = NULL; |
756 |
}else{ |
757 |
proxy.host = host.GetWindowText(); |
758 |
} |
759 |
proxy.port = GetDlgItemInt(IDC_PORT, NULL, FALSE); |
760 |
proxy.user = user.GetWindowTextLength() > 0 ? user.GetWindowText() : NULL; |
761 |
proxy.pass = pass.GetWindowTextLength() > 0 ? pass.GetWindowText() : NULL; |
762 |
}else{ |
763 |
proxy.host = NULL; |
764 |
proxy.port = 0; |
765 |
proxy.user = NULL; |
766 |
proxy.pass = NULL; |
767 |
} |
768 |
} |
769 |
String urlS = proxy.generateURL(); |
770 |
if (urlS == NULL) { |
771 |
urlS = "none:///"; |
772 |
} |
773 |
url.SetWindowText(urlS); |
774 |
} |
775 |
public: |
776 |
ProxyInfo proxy; |
777 |
SettingDialog():lock(false) { |
778 |
} |
779 |
|
780 |
int open(HWND owner) { |
781 |
return Dialog::open(instance().resource_module, IDD_SETTING, owner); |
782 |
} |
783 |
}; |
784 |
friend class SettingDialog; |
785 |
|
786 |
int _sendToSocket(SOCKET s, const unsigned char* buffer, int size) { |
787 |
int count = 0; |
788 |
while (count < size) { |
789 |
struct timeval tv = {timeout, 0}; |
790 |
fd_set fd; |
791 |
FD_ZERO(&fd); |
792 |
FD_SET(s, &fd); |
793 |
if (select((int) (s + 1), NULL, &fd, NULL, timeout > 0 ? &tv : NULL) == SOCKET_ERROR) |
794 |
return SOCKET_ERROR; |
795 |
if (!FD_ISSET(s, &fd)) { |
796 |
return SOCKET_ERROR; |
797 |
} |
798 |
int written = ORIG_send(s, (const char*) buffer + count, size - count, 0); |
799 |
if (written == SOCKET_ERROR) |
800 |
return SOCKET_ERROR; |
801 |
count += written; |
802 |
} |
803 |
return count; |
804 |
} |
805 |
|
806 |
int sendToSocket(SOCKET s, const unsigned char* buffer, int size) { |
807 |
int i = 0; |
808 |
Logger::log("send", buffer, size); |
809 |
return _sendToSocket(s, buffer, size); |
810 |
} |
811 |
|
812 |
int sendToSocketFormat(SOCKET s, const char* format, ...) { |
813 |
char buf[1024]; |
814 |
int len; |
815 |
va_list arglist; |
816 |
va_start(arglist, format); |
817 |
len = wvsprintf(buf, format, arglist); |
818 |
va_end(arglist); |
819 |
Logger::log("send", buf); |
820 |
return _sendToSocket(s, (const unsigned char*) buf, len); |
821 |
} |
822 |
|
823 |
int recieveFromSocketTimeout(SOCKET s, unsigned char* buffer, int size, int timeout) { |
824 |
int ready = 0; |
825 |
while (!ready) { |
826 |
struct timeval tv = {timeout, 0}; |
827 |
fd_set fd; |
828 |
FD_ZERO(&fd); |
829 |
FD_SET(s, &fd); |
830 |
switch (select((int) (s + 1), &fd, NULL, NULL, timeout > 0 ? &tv : NULL)) { |
831 |
case SOCKET_ERROR: |
832 |
return SOCKET_ERROR; |
833 |
case 0: |
834 |
return 0; |
835 |
default: |
836 |
ready = FD_ISSET(s, &fd); |
837 |
break; |
838 |
} |
839 |
} |
840 |
return ORIG_recv(s, (char*) buffer, size, 0); |
841 |
} |
842 |
|
843 |
int recieveFromSocket(SOCKET s, unsigned char* buffer, int size) { |
844 |
int result = recieveFromSocketTimeout(s, buffer, size, timeout); |
845 |
if (result != SOCKET_ERROR) { |
846 |
Logger::log("recv", buffer, result); |
847 |
} |
848 |
return result; |
849 |
} |
850 |
|
851 |
int line_input(SOCKET s, char *buf, int size) { |
852 |
char* dst = buf; |
853 |
if (size == 0) |
854 |
return 0; /* no error */ |
855 |
size--; |
856 |
while (size > 0) { |
857 |
switch (recieveFromSocketTimeout(s, (unsigned char*) dst, 1, timeout)) { |
858 |
case SOCKET_ERROR: |
859 |
return SOCKET_ERROR; |
860 |
case 0: |
861 |
size = 0; |
862 |
break; |
863 |
default: |
864 |
if (*dst == '\n') { |
865 |
size = 0; |
866 |
} else { |
867 |
size--; |
868 |
} |
869 |
dst++; |
870 |
break; |
871 |
} |
872 |
} |
873 |
*dst = '\0'; |
874 |
Logger::log("recv", buf); |
875 |
return 0; |
876 |
} |
877 |
|
878 |
int wait_for_prompt(SOCKET s, String prompts[], int count, int timeout /* sec */) { |
879 |
char buf[1024]; |
880 |
while (1) { |
881 |
char *dst = buf; |
882 |
char *end = buf + sizeof buf - 1; |
883 |
while (dst < end) { |
884 |
switch (recieveFromSocketTimeout(s, (unsigned char*) dst, 1, timeout)) { /* recv one-by-one */ |
885 |
case SOCKET_ERROR: |
886 |
if (WSAGetLastError() != WSAEWOULDBLOCK) { |
887 |
return SOCKET_ERROR; |
888 |
} |
889 |
// no break |
890 |
case 0: |
891 |
end = dst; /* end of stream */ |
892 |
break; |
893 |
default: |
894 |
/* continue reading until last 1 char is EOL? */ |
895 |
if (*dst++ == '\n') { |
896 |
/* finished */ |
897 |
end = dst; |
898 |
} |
899 |
} |
900 |
} |
901 |
if (dst > buf) { |
902 |
int i; |
903 |
*dst = '\0'; |
904 |
Logger::log("recv", buf); |
905 |
for (i = 0; i < count; i++) { |
906 |
char* found = strstr(buf, prompts[i]); |
907 |
if (found != NULL) { |
908 |
return i; |
909 |
} |
910 |
} |
911 |
} |
912 |
} |
913 |
} |
914 |
|
915 |
int begin_relay_http(ProxyInfo& proxy, String realhost, short realport, SOCKET s) { |
916 |
static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
917 |
char buf[1024]; |
918 |
int status_code; |
919 |
if (sendToSocketFormat(s, "CONNECT %s:%d HTTP/1.0\r\n", realhost, realport) == SOCKET_ERROR) |
920 |
return SOCKET_ERROR; |
921 |
if (proxy.user != NULL) { |
922 |
int userlen = strlen(proxy.user); |
923 |
int passlen = strlen(proxy.pass); |
924 |
int authlen = userlen + 1 + passlen; |
925 |
int encodedlen = (authlen + 2) / 3 * 4; |
926 |
char* auth = (char*) alloca(authlen + 1); |
927 |
char* encoded = (char*) alloca(encodedlen + 1); |
928 |
unsigned char *src = (unsigned char *) auth; |
929 |
char *dst = encoded; |
930 |
int bits = 0; |
931 |
int data = 0; |
932 |
strcpy_s(auth, userlen + 1, proxy.user); |
933 |
auth[userlen] = ':'; |
934 |
strcpy_s(auth + userlen + 1, passlen, proxy.pass); |
935 |
|
936 |
/* make base64 string */ |
937 |
while (*src != '\0') { |
938 |
data = (data << 8) | *src++; |
939 |
bits += 8; |
940 |
while (bits >= 6){ |
941 |
bits -= 6; |
942 |
*dst++ = base64_table[0x3F & (data >> bits)]; |
943 |
encodedlen--; |
944 |
} |
945 |
} |
946 |
while (encodedlen-- > 0) { |
947 |
*dst++ = '='; |
948 |
} |
949 |
*dst = '\0'; |
950 |
|
951 |
if (sendToSocketFormat(s, "Proxy-Authorization: Basic %s\r\n", encoded) == SOCKET_ERROR) |
952 |
return SOCKET_ERROR; |
953 |
} |
954 |
if (sendToSocketFormat(s, "\r\n") == SOCKET_ERROR) |
955 |
return SOCKET_ERROR; |
956 |
if (line_input(s, buf, sizeof buf) == SOCKET_ERROR) |
957 |
return SOCKET_ERROR; |
958 |
status_code = atoi(strchr(buf, ' ')); |
959 |
do { |
960 |
if (line_input(s, buf, sizeof buf) == SOCKET_ERROR) { |
961 |
return SOCKET_ERROR; |
962 |
} |
963 |
} while (strcmp(buf,"\r\n") != 0); |
964 |
if (status_code != 200) { |
965 |
int msgid; |
966 |
switch (status_code) { |
967 |
case 401: |
968 |
case 407: |
969 |
msgid = IDS_PROXY_UNAUTHORIZED; |
970 |
break; |
971 |
case 400: |
972 |
case 405: |
973 |
case 406: |
974 |
case 403: |
975 |
msgid = IDS_PROXY_BAD_REQUEST; |
976 |
break; |
977 |
} |
978 |
return setError(s, msgid); |
979 |
} |
980 |
return 0; |
981 |
} |
982 |
|
983 |
enum { |
984 |
SOCKS5_VERSION = 5, |
985 |
SOCKS5_REJECT = 0xFF, /* No acceptable */ |
986 |
SOCKS5_CMD_CONNECT = 1, |
987 |
SOCKS5_ATYP_IPv4 = 1, |
988 |
SOCKS5_ATYP_DOMAINNAME = 3, |
989 |
SOCKS5_ATYP_IPv6 = 4, |
990 |
SOCKS5_AUTH_SUBNEGOVER = 1, |
991 |
|
992 |
/* informations for SOCKS */ |
993 |
SOCKS5_REP_SUCCEEDED = 0x00, /* succeeded */ |
994 |
SOCKS5_REP_FAIL = 0x01, /* general SOCKS serer failure */ |
995 |
SOCKS5_REP_NALLOWED = 0x02, /* connection not allowed by ruleset */ |
996 |
SOCKS5_REP_NUNREACH = 0x03, /* Network unreachable */ |
997 |
SOCKS5_REP_HUNREACH = 0x04, /* Host unreachable */ |
998 |
SOCKS5_REP_REFUSED = 0x05, /* connection refused */ |
999 |
SOCKS5_REP_EXPIRED = 0x06, /* TTL expired */ |
1000 |
SOCKS5_REP_CNOTSUP = 0x07, /* Command not supported */ |
1001 |
SOCKS5_REP_ANOTSUP = 0x08, /* Address not supported */ |
1002 |
SOCKS5_REP_INVADDR = 0x09, /* Inalid address */ |
1003 |
|
1004 |
/* SOCKS5 authentication methods */ |
1005 |
SOCKS5_AUTH_NOAUTH = 0x00, /* without authentication */ |
1006 |
SOCKS5_AUTH_GSSAPI = 0x01, /* GSSAPI */ |
1007 |
SOCKS5_AUTH_USERPASS = 0x02, /* User/Password */ |
1008 |
SOCKS5_AUTH_CHAP = 0x03, /* Challenge-Handshake Auth Proto. */ |
1009 |
SOCKS5_AUTH_EAP = 0x05, /* Extensible Authentication Proto. */ |
1010 |
SOCKS5_AUTH_MAF = 0x08, /* Multi-Authentication Framework */ |
1011 |
}; |
1012 |
int begin_relay_socks5(ProxyInfo& proxy, String realhost, short realport, SOCKET s) { |
1013 |
int len; |
1014 |
unsigned char auth_method; |
1015 |
int auth_result; |
1016 |
unsigned char buf[256]; |
1017 |
unsigned char* ptr = buf; |
1018 |
*ptr++ = SOCKS5_VERSION; |
1019 |
if (proxy.user != NULL && proxy.pass != NULL) { |
1020 |
*ptr++ = 2; // support 2 auth methods : SOCKS5_AUTH_NOAUTH, SOCKS5_AUTH_USERPASS |
1021 |
*ptr++ = SOCKS5_AUTH_NOAUTH; |
1022 |
*ptr++ = SOCKS5_AUTH_USERPASS; |
1023 |
}else{ |
1024 |
*ptr++ = 1; // support only 1 auth method : SOCKS5_AUTH_NOAUTH |
1025 |
*ptr++ = SOCKS5_AUTH_NOAUTH; |
1026 |
} |
1027 |
if (sendToSocket(s, buf, ptr - buf) == SOCKET_ERROR) |
1028 |
return SOCKET_ERROR; |
1029 |
if (recieveFromSocket(s, buf, 2) == SOCKET_ERROR) |
1030 |
return SOCKET_ERROR; |
1031 |
|
1032 |
if (buf[0] != SOCKS5_VERSION || buf[1] == SOCKS5_REJECT) { |
1033 |
return setError(s, IDS_PROXY_BAD_REQUEST); |
1034 |
} |
1035 |
auth_method = buf[1]; |
1036 |
|
1037 |
auth_result = -1; |
1038 |
switch (auth_method) { |
1039 |
case SOCKS5_AUTH_NOAUTH: |
1040 |
/* nothing to do */ |
1041 |
auth_result = 0; |
1042 |
break; |
1043 |
case SOCKS5_AUTH_USERPASS: |
1044 |
/* make authentication packet */ |
1045 |
ptr = buf; |
1046 |
*ptr++ = SOCKS5_AUTH_SUBNEGOVER; |
1047 |
len = proxy.user.length(); |
1048 |
*ptr++ = len; |
1049 |
strcpy_s((char*) ptr, sizeof buf - (ptr - buf), proxy.user); |
1050 |
ptr += len; |
1051 |
len = proxy.pass.length(); |
1052 |
*ptr++ = len; |
1053 |
strcpy_s((char*) ptr, sizeof buf - (ptr - buf), proxy.pass); |
1054 |
ptr += len; |
1055 |
|
1056 |
/* send it and get answer */ |
1057 |
if (sendToSocket(s, buf, ptr - buf) == SOCKET_ERROR) |
1058 |
return SOCKET_ERROR; |
1059 |
if (recieveFromSocket(s, buf, 2) == SOCKET_ERROR) |
1060 |
return SOCKET_ERROR; |
1061 |
|
1062 |
/* check status */ |
1063 |
auth_result = buf[1] != 0; |
1064 |
break; |
1065 |
default: |
1066 |
return setError(s, IDS_PROXY_BAD_REQUEST); |
1067 |
} |
1068 |
if (auth_result == SOCKET_ERROR) { |
1069 |
return SOCKET_ERROR; |
1070 |
}else if (auth_result != 0) { |
1071 |
return setError(s, IDS_PROXY_UNAUTHORIZED); |
1072 |
} |
1073 |
/* request to connect */ |
1074 |
ptr = buf; |
1075 |
*ptr++ = SOCKS5_VERSION; |
1076 |
*ptr++ = SOCKS5_CMD_CONNECT; |
1077 |
*ptr++ = 0; /* reserved */ |
1078 |
in_addr addr; |
1079 |
addr.s_addr = INADDR_NONE; |
1080 |
char ch = realhost.charAt(0); |
1081 |
if ('0' <= ch && ch <= '9') { |
1082 |
addr.s_addr = inet_addr(realhost); |
1083 |
} |
1084 |
if (addr.s_addr != INADDR_NONE) { |
1085 |
*ptr++ = SOCKS5_ATYP_IPv4; |
1086 |
memcpy(ptr, &addr, sizeof addr); |
1087 |
ptr += sizeof addr; |
1088 |
}else{ |
1089 |
struct hostent* entry = resolve != RESOLVE_REMOTE ? gethostbyname(realhost) : NULL; |
1090 |
if (entry != NULL) { |
1091 |
#ifndef AF_INET6 |
1092 |
#define AF_INET6 23 |
1093 |
#endif |
1094 |
if ((entry->h_addrtype == AF_INET || entry->h_addrtype == AF_INET6) |
1095 |
&& entry->h_length == (entry->h_addrtype == AF_INET ? 4 : 16)) { |
1096 |
*ptr++ = entry->h_addrtype == AF_INET ? SOCKS5_ATYP_IPv4 : SOCKS5_ATYP_IPv6; |
1097 |
memcpy(ptr, entry->h_addr_list[0], entry->h_length); |
1098 |
ptr += entry->h_length; |
1099 |
}else{ |
1100 |
WSASetLastError(WSAECONNREFUSED); |
1101 |
return SOCKET_ERROR; |
1102 |
} |
1103 |
}else if (resolve == RESOLVE_LOCAL) { |
1104 |
WSASetLastError(WSAECONNREFUSED); |
1105 |
return SOCKET_ERROR; |
1106 |
}else{ |
1107 |
*ptr++ = SOCKS5_ATYP_DOMAINNAME; |
1108 |
len = strlen(realhost); |
1109 |
*ptr++ = len; |
1110 |
memcpy(ptr, realhost, len); |
1111 |
ptr += len; |
1112 |
} |
1113 |
} |
1114 |
*ptr++ = realport >> 8; /* DST.PORT */ |
1115 |
*ptr++ = realport & 0xFF; |
1116 |
if (sendToSocket(s, buf, ptr - buf) == SOCKET_ERROR) |
1117 |
return SOCKET_ERROR; |
1118 |
if (recieveFromSocket(s, buf, 4) == SOCKET_ERROR) |
1119 |
return SOCKET_ERROR; |
1120 |
if (buf[0] != SOCKS5_VERSION || buf[1] != SOCKS5_REP_SUCCEEDED) { /* check reply code */ |
1121 |
return setError(s, IDS_PROXY_BAD_REQUEST); |
1122 |
} |
1123 |
// buf[2] is reserved |
1124 |
switch (buf[3]) { /* case by ATYP */ |
1125 |
case SOCKS5_ATYP_IPv4: |
1126 |
/* recv IPv4 addr and port */ |
1127 |
if (recieveFromSocket(s, buf, 4 + 2) == SOCKET_ERROR) |
1128 |
return SOCKET_ERROR; |
1129 |
break; |
1130 |
case SOCKS5_ATYP_DOMAINNAME: |
1131 |
/* recv name and port */ |
1132 |
if (recieveFromSocket(s, buf, 1) == SOCKET_ERROR) |
1133 |
return SOCKET_ERROR; |
1134 |
if (recieveFromSocket(s, buf, buf[0] + 2) == SOCKET_ERROR) |
1135 |
return SOCKET_ERROR; |
1136 |
break; |
1137 |
case SOCKS5_ATYP_IPv6: |
1138 |
/* recv IPv6 addr and port */ |
1139 |
if (recieveFromSocket(s, buf, 16 + 2) == SOCKET_ERROR) |
1140 |
return SOCKET_ERROR; |
1141 |
break; |
1142 |
} |
1143 |
/* Conguraturation, connected via SOCKS5 server! */ |
1144 |
return 0; |
1145 |
} |
1146 |
|
1147 |
enum { |
1148 |
SOCKS4_VERSION = 4, |
1149 |
SOCKS4_CMD_CONNECT = 1, |
1150 |
|
1151 |
SOCKS4_REP_SUCCEEDED = 90, /* rquest granted (succeeded) */ |
1152 |
SOCKS4_REP_REJECTED = 91, /* request rejected or failed */ |
1153 |
SOCKS4_REP_IDENT_FAIL = 92, /* cannot connect identd */ |
1154 |
SOCKS4_REP_USERID = 93, /* user id not matched */ |
1155 |
}; |
1156 |
|
1157 |
int begin_relay_socks4(ProxyInfo& proxy, String realhost, short realport, SOCKET s) { |
1158 |
unsigned char buf[256], *ptr; |
1159 |
|
1160 |
/* make connect request packet |
1161 |
protocol v4: |
1162 |
VN:1, CD:1, PORT:2, ADDR:4, USER:n, NULL:1 |
1163 |
protocol v4a: |
1164 |
VN:1, CD:1, PORT:2, DUMMY:4, USER:n, NULL:1, HOSTNAME:n, NULL:1 |
1165 |
*/ |
1166 |
ptr = buf; |
1167 |
*ptr++ = SOCKS4_VERSION; |
1168 |
*ptr++ = SOCKS4_CMD_CONNECT; |
1169 |
*ptr++ = realport >> 8; |
1170 |
*ptr++ = realport & 0xFF; |
1171 |
in_addr addr; |
1172 |
addr.s_addr = INADDR_NONE; |
1173 |
char ch = realhost.charAt(0); |
1174 |
if ('0' <= ch && ch <= '9') { |
1175 |
addr.s_addr = inet_addr(realhost); |
1176 |
} |
1177 |
if (addr.s_addr != INADDR_NONE) { |
1178 |
memcpy(ptr, &addr, sizeof addr); |
1179 |
ptr += sizeof addr; |
1180 |
}else{ |
1181 |
struct hostent* entry = resolve != RESOLVE_REMOTE ? gethostbyname(realhost) : NULL; |
1182 |
if (entry != NULL && entry->h_addrtype == AF_INET && entry->h_length == sizeof (in_addr)) { |
1183 |
addr.s_addr = INADDR_LOOPBACK; |
1184 |
memcpy(ptr, entry->h_addr_list[0], entry->h_length); |
1185 |
ptr += entry->h_length; |
1186 |
}else if (resolve == RESOLVE_LOCAL) { |
1187 |
WSASetLastError(WSAECONNREFUSED); |
1188 |
return SOCKET_ERROR; |
1189 |
}else{ |
1190 |
/* destination IP fake, protocol 4a */ |
1191 |
*ptr++ = 0; |
1192 |
*ptr++ = 0; |
1193 |
*ptr++ = 0; |
1194 |
*ptr++ = 1; |
1195 |
} |
1196 |
} |
1197 |
/* username */ |
1198 |
if (proxy.user != NULL) { |
1199 |
strcpy_s((char*) ptr, sizeof buf - (ptr - buf), proxy.user); |
1200 |
ptr += proxy.user.length() + 1; |
1201 |
}else{ |
1202 |
*ptr++ = '\0'; |
1203 |
} |
1204 |
if (addr.s_addr == INADDR_NONE) { |
1205 |
/* destination host name (for protocol 4a) */ |
1206 |
strcpy_s((char*) ptr, sizeof buf - (ptr - buf), realhost); |
1207 |
ptr += strlen(realhost) + 1; |
1208 |
} |
1209 |
/* send command and get response |
1210 |
response is: VN:1, CD:1, PORT:2, ADDR:4 */ |
1211 |
if (sendToSocket(s, buf, ptr - buf) == SOCKET_ERROR) { |
1212 |
return SOCKET_ERROR; |
1213 |
} |
1214 |
if (recieveFromSocket(s, buf, 8) == SOCKET_ERROR) { |
1215 |
return SOCKET_ERROR; |
1216 |
} |
1217 |
int messageid = 0; |
1218 |
if (buf[0] != 0) { |
1219 |
messageid = IDS_PROXY_BAD_REQUEST; |
1220 |
}else if (buf[1] == SOCKS4_REP_IDENT_FAIL || buf[1] == SOCKS4_REP_USERID) { |
1221 |
messageid = IDS_PROXY_UNAUTHORIZED; |
1222 |
}else if (buf[1] != SOCKS4_REP_SUCCEEDED) { |
1223 |
messageid = IDS_PROXY_BAD_REQUEST; |
1224 |
} |
1225 |
if (messageid != 0) { |
1226 |
return setError(s, messageid); |
1227 |
} |
1228 |
|
1229 |
/* Conguraturation, connected via SOCKS4 server! */ |
1230 |
return 0; |
1231 |
} |
1232 |
|
1233 |
int begin_relay_telnet(ProxyInfo& proxy, String realhost, short realport, SOCKET s) { |
1234 |
int err = 0; |
1235 |
|
1236 |
while (!err) { |
1237 |
switch (wait_for_prompt(s, prompt_table, countof(prompt_table), 10)) { |
1238 |
case 0: /* Hostname prompt */ |
1239 |
if (sendToSocketFormat(s, "%s:%d\n", realhost, realport) == SOCKET_ERROR) |
1240 |
return SOCKET_ERROR; |
1241 |
break; |
1242 |
case 1: /* Username prompt */ |
1243 |
if (sendToSocketFormat(s, "%s\n", proxy.user) == SOCKET_ERROR) |
1244 |
return SOCKET_ERROR; |
1245 |
break; |
1246 |
case 2: /* Password prompt */ |
1247 |
if (sendToSocketFormat(s, "%s\n", proxy.pass) == SOCKET_ERROR) |
1248 |
return SOCKET_ERROR; |
1249 |
break; |
1250 |
case 3: /* Established message */ |
1251 |
return 0; |
1252 |
case 4: /* Refused message */ |
1253 |
default: /* Connection error, etc. */ |
1254 |
err = 1; |
1255 |
break; |
1256 |
} |
1257 |
} |
1258 |
return setError(s, IDS_PROXY_BAD_REQUEST); |
1259 |
} |
1260 |
|
1261 |
String loadString(int id) { |
1262 |
return Resource::loadString(resource_module, id); |
1263 |
} |
1264 |
int setError(SOCKET s, int id) { |
1265 |
if (id != 0) |
1266 |
showMessage(id); |
1267 |
HWND window; |
1268 |
UINT message; |
1269 |
long event; |
1270 |
asyncselectinfo.get(s, window, message, event); |
1271 |
if ((event & FD_CONNECT) != 0) { |
1272 |
MSG msg; |
1273 |
while (::PeekMessage(&msg, window, message, message, PM_REMOVE)) |
1274 |
; |
1275 |
} |
1276 |
WSASetLastError(WSAECONNREFUSED); |
1277 |
return SOCKET_ERROR; |
1278 |
} |
1279 |
void showMessage(int id) { |
1280 |
if (shower != NULL) { |
1281 |
shower->showMessage(loadString(id)); |
1282 |
} |
1283 |
} |
1284 |
|
1285 |
#define DECLARE_HOOKAPI(RETTYPE, APINAME, ARGLIST, ARGS) \ |
1286 |
public: \ |
1287 |
static FARPROC hook_##APINAME(FARPROC original) { \ |
1288 |
(FARPROC&) instance().ORIG_##APINAME = original; \ |
1289 |
return (FARPROC) HOOKEDAPI_##APINAME; \ |
1290 |
} \ |
1291 |
static FARPROC unhook_##APINAME(FARPROC hookedProc) { \ |
1292 |
return hookedProc == (FARPROC) HOOKEDAPI_##APINAME \ |
1293 |
? (FARPROC) instance().ORIG_##APINAME \ |
1294 |
: hookedProc; \ |
1295 |
} \ |
1296 |
private: \ |
1297 |
static RETTYPE PASCAL HOOKEDAPI_##APINAME ARGLIST { \ |
1298 |
return instance().hooked_##APINAME ARGS; \ |
1299 |
} \ |
1300 |
RETTYPE (PASCAL* ORIG_##APINAME) ARGLIST; \ |
1301 |
RETTYPE hooked_##APINAME ARGLIST |
1302 |
|
1303 |
#define INSTALL_HOOKAPI(APINAME) \ |
1304 |
Hooker::hook(module, (FARPROC) instance().ORIG_##APINAME, (FARPROC) HOOKEDAPI_##APINAME); |
1305 |
|
1306 |
#define UNINSTALL_HOOKAPI(APINAME) \ |
1307 |
Hooker::hook(module, (FARPROC) HOOKEDAPI_##APINAME, (FARPROC) instance().ORIG_##APINAME); |
1308 |
|
1309 |
#define LOADAPI(APINAME) \ |
1310 |
(FARPROC&) ORIG_##APINAME = ::GetProcAddress(wsock32, #APINAME); |
1311 |
|
1312 |
#define SETUP_HOOKAPI(APINAME) \ |
1313 |
Hooker::setup((FARPROC) instance().ORIG_##APINAME, (FARPROC) HOOKEDAPI_##APINAME); |
1314 |
|
1315 |
DECLARE_HOOKAPI(int, connect, (SOCKET s, const struct sockaddr* name, int namelen), (s, name, namelen)) { |
1316 |
ConnectionInfo* info = NULL; |
1317 |
ConnectionInfoHolder holder; |
1318 |
if (name->sa_family == AF_INET) { |
1319 |
struct sockaddr_in* in = (struct sockaddr_in*) name; |
1320 |
info = connectioninfolist.get(in->sin_addr); |
1321 |
if (info == NULL && defaultProxy.type != ProxyInfo::TYPE_NONE) { |
1322 |
info = new ConnectionInfo(defaultProxy, inet_ntoa(in->sin_addr)); |
1323 |
holder = info; |
1324 |
} |
1325 |
} |
1326 |
if (info != NULL) { |
1327 |
if (info->proxy.type == ProxyInfo::TYPE_NONE_FORCE) { |
1328 |
info = NULL; |
1329 |
}else{ |
1330 |
const char* hostname; |
1331 |
if (info->proxy.type == ProxyInfo::TYPE_SSL) { |
1332 |
hostname = info->realhost; |
1333 |
}else{ |
1334 |
info->realport = ntohs(((struct sockaddr_in*) name)->sin_port); |
1335 |
((struct sockaddr_in*) name)->sin_port = htons(info->proxy.getPort()); |
1336 |
hostname = info->proxy.host; |
1337 |
} |
1338 |
struct hostent* entry = ORIG_gethostbyname(hostname); |
1339 |
if (entry == NULL) { |
1340 |
WSASetLastError(WSAECONNREFUSED); |
1341 |
return SOCKET_ERROR; |
1342 |
} |
1343 |
memcpy(&((struct sockaddr_in*) name)->sin_addr, entry->h_addr_list[0], entry->h_length); |
1344 |
} |
1345 |
} |
1346 |
int result = ORIG_connect(s, name, namelen); |
1347 |
if (info == NULL) { |
1348 |
return result; |
1349 |
} |
1350 |
if (result == 0) { |
1351 |
// do nothing |
1352 |
}else if (WSAGetLastError() == WSAEWOULDBLOCK) { |
1353 |
struct timeval tv = {timeout, 0}; |
1354 |
fd_set ifd; |
1355 |
fd_set ofd; |
1356 |
fd_set efd; |
1357 |
FD_ZERO(&ifd); |
1358 |
FD_ZERO(&ofd); |
1359 |
FD_ZERO(&efd); |
1360 |
FD_SET(s, &ifd); |
1361 |
FD_SET(s, &ofd); |
1362 |
FD_SET(s, &efd); |
1363 |
if (select((int) (s + 1), &ifd, &ofd, &efd, timeout > 0 ? &tv : NULL) == SOCKET_ERROR) |
1364 |
return SOCKET_ERROR; |
1365 |
if (FD_ISSET(s, &efd)) { |
1366 |
WSASetLastError(WSAECONNREFUSED); |
1367 |
return SOCKET_ERROR; |
1368 |
} |
1369 |
}else{ |
1370 |
return SOCKET_ERROR; |
1371 |
} |
1372 |
switch (info->proxy.type) { |
1373 |
default: |
1374 |
result = 0; |
1375 |
break; |
1376 |
case ProxyInfo::TYPE_HTTP: |
1377 |
case ProxyInfo::TYPE_HTTP_SSL: |
1378 |
result = begin_relay_http(info->proxy, info->realhost, info->realport, s); |
1379 |
break; |
1380 |
case ProxyInfo::TYPE_TELNET: |
1381 |
case ProxyInfo::TYPE_TELNET_SSL: |
1382 |
result = begin_relay_telnet(info->proxy, info->realhost, info->realport, s); |
1383 |
break; |
1384 |
case ProxyInfo::TYPE_SOCKS4: |
1385 |
case ProxyInfo::TYPE_SOCKS4_SSL: |
1386 |
result = begin_relay_socks4(info->proxy, info->realhost, info->realport, s); |
1387 |
break; |
1388 |
case ProxyInfo::TYPE_SOCKS5: |
1389 |
case ProxyInfo::TYPE_SOCKS5_SSL: |
1390 |
result = begin_relay_socks5(info->proxy, info->realhost, info->realport, s); |
1391 |
break; |
1392 |
} |
1393 |
if (result == 0) { |
1394 |
if (info->proxy.type == ProxyInfo::TYPE_SSL |
1395 |
|| info->proxy.type == ProxyInfo::TYPE_HTTP_SSL |
1396 |
|| info->proxy.type == ProxyInfo::TYPE_TELNET_SSL |
1397 |
|| info->proxy.type == ProxyInfo::TYPE_SOCKS4_SSL |
1398 |
|| info->proxy.type == ProxyInfo::TYPE_SOCKS5_SSL) { |
1399 |
if (!SSLSocket::isEnabled()) { |
1400 |
WSASetLastError(WSAECONNREFUSED); |
1401 |
return SOCKET_ERROR; |
1402 |
} |
1403 |
SSLSocket* ssl = new SSLSocket(); |
1404 |
if (!ssl->connect(s, info->realhost)) { |
1405 |
shutdown(s, SD_BOTH); |
1406 |
int error_code = ssl->get_verify_result(); |
1407 |
delete ssl; |
1408 |
return setError(s, error_code); |
1409 |
} |
1410 |
sslmap.put(s,ssl); |
1411 |
} |
1412 |
} |
1413 |
return result; |
1414 |
} |
1415 |
|
1416 |
DECLARE_HOOKAPI(struct hostent*, gethostbyname, (const char* hostname), (hostname)) { |
1417 |
ConnectionInfo* info = connectioninfolist.find(hostname); |
1418 |
if (info != NULL) { |
1419 |
if (info->proxy.type == ProxyInfo::TYPE_NONE_FORCE) { |
1420 |
hostname = info->realhost; |
1421 |
}else{ |
1422 |
if (info->proxy.type == ProxyInfo::TYPE_SSL |
1423 |
|| info->proxy.type == ProxyInfo::TYPE_HTTP_SSL |
1424 |
|| info->proxy.type == ProxyInfo::TYPE_TELNET_SSL |
1425 |
|| info->proxy.type == ProxyInfo::TYPE_SOCKS4_SSL |
1426 |
|| info->proxy.type == ProxyInfo::TYPE_SOCKS5_SSL) { |
1427 |
if (!SSLSocket::isEnabled()) { |
1428 |
::WSASetLastError(WSAHOST_NOT_FOUND); |
1429 |
return NULL; |
1430 |
} |
1431 |
} |
1432 |
if (info->buffer == NULL) { |
1433 |
int bufferLength = sizeof (DUMMYHOSTENT) + strlen(info->realhost); |
1434 |
info->buffer = new char[bufferLength]; |
1435 |
info->fillBuffer(info->buffer, bufferLength); |
1436 |
} |
1437 |
return (struct hostent*) info->buffer; |
1438 |
} |
1439 |
} |
1440 |
return ORIG_gethostbyname(hostname); |
1441 |
} |
1442 |
|
1443 |
DECLARE_HOOKAPI(HANDLE, WSAAsyncGetHostByName, (HWND window, UINT message, const char* hostname, char* buffer, int bufferLength), (window, message, hostname, buffer, bufferLength)) { |
1444 |
ConnectionInfo* info = connectioninfolist.find(hostname); |
1445 |
if (info == NULL || info->proxy.type == ProxyInfo::TYPE_NONE_FORCE) { |
1446 |
return ORIG_WSAAsyncGetHostByName(window, message, hostname, buffer, bufferLength); |
1447 |
} |
1448 |
if (info->proxy.type == ProxyInfo::TYPE_SSL |
1449 |
|| info->proxy.type == ProxyInfo::TYPE_HTTP_SSL |
1450 |
|| info->proxy.type == ProxyInfo::TYPE_TELNET_SSL |
1451 |
|| info->proxy.type == ProxyInfo::TYPE_SOCKS4_SSL |
1452 |
|| info->proxy.type == ProxyInfo::TYPE_SOCKS5_SSL) { |
1453 |
if (!SSLSocket::isEnabled()) { |
1454 |
::WSASetLastError(WSAHOST_NOT_FOUND); |
1455 |
return NULL; |
1456 |
} |
1457 |
} |
1458 |
HANDLE handle = connectioninfolist.getTask(info); |
1459 |
int len = sizeof (DUMMYHOSTENT) + strlen(hostname); |
1460 |
if (bufferLength < len) { |
1461 |
::PostMessage(window, message, (WPARAM) handle, MAKELPARAM(len, WSAENOBUFS)); |
1462 |
::WSASetLastError(WSAENOBUFS); |
1463 |
return handle; |
1464 |
} |
1465 |
info->fillBuffer(buffer, bufferLength); |
1466 |
::PostMessage(window, message, (WPARAM) handle, MAKELPARAM(len, 0)); |
1467 |
return handle; |
1468 |
} |
1469 |
|
1470 |
DECLARE_HOOKAPI(int, WSAAsyncSelect, (SOCKET s, HWND window, UINT message, long event), (s, window, message, event)) { |
1471 |
asyncselectinfo.put(s, window, message, event); |
1472 |
return ORIG_WSAAsyncSelect(s, window, message, event); |
1473 |
} |
1474 |
|
1475 |
DECLARE_HOOKAPI(int, WSACancelAsyncRequest, (HANDLE task), (task)) { |
1476 |
ConnectionInfo* info = connectioninfolist.get(task); |
1477 |
if (info != NULL) { |
1478 |
return 0; |
1479 |
} |
1480 |
return ORIG_WSACancelAsyncRequest(task); |
1481 |
} |
1482 |
|
1483 |
DECLARE_HOOKAPI(int, send, (SOCKET s, const char* buf, int len, int flags), (s, buf, len, flags)) { |
1484 |
SSLSocket* ssl = sslmap.get(s); |
1485 |
if (ssl != NULL) |
1486 |
return ssl->write(buf, len); |
1487 |
return ORIG_send(s, buf, len, flags); |
1488 |
} |
1489 |
DECLARE_HOOKAPI(int, sendto, (SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen), (s, buf, len, flags, to, tolen)) { |
1490 |
return ORIG_sendto(s, buf, len, flags, to, tolen); |
1491 |
} |
1492 |
DECLARE_HOOKAPI(int, recv, (SOCKET s, char* buf, int len, int flags), (s, buf, len, flags)) { |
1493 |
SSLSocket* ssl = sslmap.get(s); |
1494 |
if (ssl != NULL) |
1495 |
return ssl->read(buf, len); |
1496 |
return ORIG_recv(s, buf, len, flags); |
1497 |
} |
1498 |
DECLARE_HOOKAPI(int, recvfrom, (SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen), (s, buf, len, flags, from, fromlen)) { |
1499 |
return ORIG_recvfrom(s, buf, len, flags, from, fromlen); |
1500 |
} |
1501 |
DECLARE_HOOKAPI(int, closesocket, (SOCKET s), (s)) { |
1502 |
SSLSocket* ssl = sslmap.get(s); |
1503 |
if (ssl != NULL) { |
1504 |
ssl->close(); |
1505 |
sslmap.remove(s); |
1506 |
delete ssl; |
1507 |
} |
1508 |
return ORIG_closesocket(s); |
1509 |
} |
1510 |
|
1511 |
String logfile; |
1512 |
int timeout; |
1513 |
enum SocksResolve { |
1514 |
RESOLVE_AUTO, |
1515 |
RESOLVE_REMOTE, |
1516 |
RESOLVE_LOCAL, |
1517 |
} resolve; |
1518 |
String prompt_table[5]; |
1519 |
ProxyInfo defaultProxy; |
1520 |
ConnectionInfoList connectioninfolist; |
1521 |
Hashtable<SOCKET, SSLSocket*> sslmap; |
1522 |
MessageShower* shower; |
1523 |
HWND owner; |
1524 |
HMODULE resource_module; |
1525 |
AsyncSelectInfoTable asyncselectinfo; |
1526 |
|
1527 |
ProxyWSockHook():shower(NULL), owner(NULL), resource_module(GetInstanceHandle()), timeout(0) { |
1528 |
HMODULE wsock32 = ::GetModuleHandle("wsock32.dll"); |
1529 |
LOADAPI(connect) |
1530 |
LOADAPI(gethostbyname) |
1531 |
LOADAPI(WSAAsyncGetHostByName) |
1532 |
LOADAPI(WSAAsyncSelect) |
1533 |
LOADAPI(WSACancelAsyncRequest) |
1534 |
LOADAPI(send) |
1535 |
LOADAPI(sendto) |
1536 |
LOADAPI(recv) |
1537 |
LOADAPI(recvfrom) |
1538 |
LOADAPI(closesocket) |
1539 |
} |
1540 |
static ProxyWSockHook& instance() { |
1541 |
static ProxyWSockHook instance; |
1542 |
return instance; |
1543 |
} |
1544 |
void _load(IniFile& ini) { |
1545 |
String temp; |
1546 |
temp = ini.getString("ProxyType"); |
1547 |
if (temp != NULL) { |
1548 |
defaultProxy.type = ProxyInfo::parseType(temp); |
1549 |
if (defaultProxy.type != ProxyInfo::TYPE_NONE) { |
1550 |
defaultProxy.host = ini.getString("ProxyHost"); |
1551 |
if (defaultProxy.host == NULL || defaultProxy.type == ProxyInfo::TYPE_NONE_FORCE) { |
1552 |
defaultProxy.type = ProxyInfo::TYPE_NONE; |
1553 |
}else{ |
1554 |
defaultProxy.port = (short) ini.getInteger("ProxyPort"); |
1555 |
defaultProxy.user = ini.getString("ProxyUser"); |
1556 |
if (defaultProxy.user != NULL) |
1557 |
defaultProxy.pass = ini.getString("ProxyPass"); |
1558 |
} |
1559 |
} |
1560 |
} |
1561 |
|
1562 |
timeout = ini.getInteger("ConnectionTimeout", 10); |
1563 |
|
1564 |
temp = ini.getString("SocksResolve"); |
1565 |
if (temp.equalsIgnoreCase("remote")) { |
1566 |
resolve = RESOLVE_REMOTE; |
1567 |
}else if (temp.equalsIgnoreCase("local")) { |
1568 |
resolve = RESOLVE_LOCAL; |
1569 |
}else{ |
1570 |
resolve = RESOLVE_AUTO; |
1571 |
} |
1572 |
|
1573 |
prompt_table[0] = ini.getString("TelnetHostnamePrompt", ">> Host name: "); |
1574 |
prompt_table[1] = ini.getString("TelnetUsernamePrompt", "Username:"); |
1575 |
prompt_table[2] = ini.getString("TelnetPasswordPrompt", "Password:"); |
1576 |
prompt_table[3] = ini.getString("TelnetConnectedMessage", "-- Connected to "); |
1577 |
prompt_table[4] = ini.getString("TelnetErrorMessage", "!!!!!!!!"); |
1578 |
|
1579 |
logfile = ini.getString("DebugLog"); |
1580 |
Logger::open(logfile); |
1581 |
} |
1582 |
void _save(IniFile& ini) { |
1583 |
const char* type = NULL; |
1584 |
const char* host = NULL; |
1585 |
const char* port = NULL; |
1586 |
const char* user = NULL; |
1587 |
const char* pass = NULL; |
1588 |
if (defaultProxy.type != ProxyInfo::TYPE_NONE && defaultProxy.type != ProxyInfo::TYPE_NONE_FORCE && defaultProxy.host != NULL) { |
1589 |
type = ProxyInfo::getTypeName(defaultProxy.type); |
1590 |
host = defaultProxy.host; |
1591 |
if (defaultProxy.port != 0) { |
1592 |
char* buffer = (char*) alloca(5); |
1593 |
_itoa_s(defaultProxy.port, buffer, 5, 10); |
1594 |
port = buffer; |
1595 |
} |
1596 |
if (defaultProxy.user != NULL) { |
1597 |
user = defaultProxy.user; |
1598 |
if (defaultProxy.pass != NULL) { |
1599 |
pass = defaultProxy.pass; |
1600 |
} |
1601 |
} |
1602 |
} |
1603 |
ini.setString("ProxyType", type); |
1604 |
ini.setString("ProxyHost", host); |
1605 |
ini.setString("ProxyPort", port); |
1606 |
ini.setString("ProxyUser", user); |
1607 |
ini.setString("ProxyPass", pass); |
1608 |
|
1609 |
ini.setInteger("ConnectionTimeout", timeout); |
1610 |
|
1611 |
switch (resolve) { |
1612 |
case RESOLVE_REMOTE: |
1613 |
type = "remote"; |
1614 |
break; |
1615 |
case RESOLVE_LOCAL: |
1616 |
type = "local"; |
1617 |
break; |
1618 |
default: |
1619 |
type = "auto"; |
1620 |
break; |
1621 |
} |
1622 |
ini.setString("SocksResolve", type); |
1623 |
|
1624 |
ini.setString("TelnetHostnamePrompt", prompt_table[0]); |
1625 |
ini.setString("TelnetUsernamePrompt", prompt_table[1]); |
1626 |
ini.setString("TelnetPasswordPrompt", prompt_table[2]); |
1627 |
ini.setString("TelnetConnectedMessage", prompt_table[3]); |
1628 |
ini.setString("TelnetErrorMessage", prompt_table[4]); |
1629 |
|
1630 |
ini.setString("DebugLog", logfile); |
1631 |
} |
1632 |
public: |
1633 |
static void setOwner(HWND owner) { |
1634 |
instance().owner = owner; |
1635 |
} |
1636 |
static void setMessageShower(MessageShower* shower) { |
1637 |
instance().shower = shower; |
1638 |
} |
1639 |
static void load(IniFile& ini) { |
1640 |
instance()._load(ini); |
1641 |
} |
1642 |
static void save(IniFile& ini) { |
1643 |
instance()._save(ini); |
1644 |
} |
1645 |
static bool setupDialog(HWND owner) { |
1646 |
SettingDialog dlg; |
1647 |
dlg.proxy = instance().defaultProxy; |
1648 |
if (dlg.open(owner) == IDOK) { |
1649 |
instance().defaultProxy = dlg.proxy; |
1650 |
return true; |
1651 |
} |
1652 |
return false; |
1653 |
} |
1654 |
|
1655 |
|
1656 |
static void setupHooks() { |
1657 |
SETUP_HOOKAPI(connect) |
1658 |
SETUP_HOOKAPI(gethostbyname) |
1659 |
SETUP_HOOKAPI(WSAAsyncGetHostByName) |
1660 |
SETUP_HOOKAPI(WSAAsyncSelect) |
1661 |
SETUP_HOOKAPI(WSACancelAsyncRequest) |
1662 |
SETUP_HOOKAPI(send) |
1663 |
SETUP_HOOKAPI(sendto) |
1664 |
SETUP_HOOKAPI(recv) |
1665 |
SETUP_HOOKAPI(recvfrom) |
1666 |
SETUP_HOOKAPI(closesocket) |
1667 |
} |
1668 |
static void installHook(HMODULE module) { |
1669 |
INSTALL_HOOKAPI(connect) |
1670 |
INSTALL_HOOKAPI(gethostbyname) |
1671 |
INSTALL_HOOKAPI(WSAAsyncGetHostByName) |
1672 |
INSTALL_HOOKAPI(WSAAsyncSelect) |
1673 |
INSTALL_HOOKAPI(WSACancelAsyncRequest) |
1674 |
INSTALL_HOOKAPI(send) |
1675 |
INSTALL_HOOKAPI(sendto) |
1676 |
INSTALL_HOOKAPI(recv) |
1677 |
INSTALL_HOOKAPI(recvfrom) |
1678 |
INSTALL_HOOKAPI(closesocket) |
1679 |
} |
1680 |
|
1681 |
static void uninstallHook(HMODULE module) { |
1682 |
UNINSTALL_HOOKAPI(connect) |
1683 |
UNINSTALL_HOOKAPI(gethostbyname) |
1684 |
UNINSTALL_HOOKAPI(WSAAsyncGetHostByName) |
1685 |
UNINSTALL_HOOKAPI(WSAAsyncSelect) |
1686 |
UNINSTALL_HOOKAPI(WSACancelAsyncRequest) |
1687 |
UNINSTALL_HOOKAPI(send) |
1688 |
UNINSTALL_HOOKAPI(sendto) |
1689 |
UNINSTALL_HOOKAPI(recv) |
1690 |
UNINSTALL_HOOKAPI(recvfrom) |
1691 |
UNINSTALL_HOOKAPI(closesocket) |
1692 |
} |
1693 |
static String generateURL() { |
1694 |
return instance().defaultProxy.generateURL(); |
1695 |
} |
1696 |
static String parseURL(const char* url) { |
1697 |
ProxyInfo proxy; |
1698 |
String realhost = ProxyInfo::parse(url, proxy); |
1699 |
if (realhost != NULL) { |
1700 |
instance().defaultProxy = proxy; |
1701 |
if (realhost.length() == 0) |
1702 |
realhost = NULL; |
1703 |
} |
1704 |
return realhost; |
1705 |
} |
1706 |
static void setResourceModule(HMODULE module) { |
1707 |
instance().resource_module = module; |
1708 |
} |
1709 |
}; |
1710 |
|
1711 |
#endif//_YEBISOCKS_PROXYWSOCKHOOK_H_ |