Open-Source-Software-Entwicklung und Downloads

Browse Subversion Repository

Annotation of /trunk/TTProxy/ProxyWSockHook.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (hide annotations) (download) (as text)
Tue Mar 27 23:47:41 2007 UTC (17 years, 2 months ago) by maya
Original Path: TTProxy/trunk/ProxyWSockHook.h
File MIME type: text/x-chdr
File size: 65710 byte(s)
バージョン情報の表示フォーマットを変更した。

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

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