Open-Source-Software-Entwicklung und Downloads

Browse Subversion Repository

Contents of /trunk/TTProxy/ProxyWSockHook.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 16 - (show annotations) (download) (as text)
Thu Aug 3 13:33:30 2006 UTC (17 years, 10 months ago) by yutakakn
Original Path: TTProxy/trunk/ProxyWSockHook.h
File MIME type: text/x-chdr
File size: 62822 byte(s)
(none)

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(&section);
69 }
70 ~AsyncSelectInfoTable() {
71 ::DeleteCriticalSection(&section);
72 }
73 void put(SOCKET s, HWND window, UINT message, long event) {
74 ::EnterCriticalSection(&section);
75 if (message != 0 || event != 0) {
76 table.put(s, AsyncSelectInfo(window, message, event));
77 }else{
78 table.remove(s);
79 }
80 ::LeaveCriticalSection(&section);
81 }
82 void get(SOCKET s, HWND& window, UINT& message, long& event)const {
83 ::EnterCriticalSection(&section);
84 AsyncSelectInfo info = table.get(s);
85 ::LeaveCriticalSection(&section);
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(&section);
416 }
417 ~ConnectionInfoList() {
418 ::DeleteCriticalSection(&section);
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(&section);
437 ConnectionInfo* info = 0 <= index && index < countof(list) ? (ConnectionInfo*) list[index] : NULL;
438 ::LeaveCriticalSection(&section);
439 return info;
440 }
441 ConnectionInfo* find(const char* url) {
442 ::EnterCriticalSection(&section);
443 ConnectionInfo* info = table.get(url);
444 ::LeaveCriticalSection(&section);
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(&section);
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(&section);
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_

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26