/[winpt]/trunk/Src/wptSOCKS.cpp
ViewVC logotype

Annotation of /trunk/Src/wptSOCKS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 271 - (hide annotations)
Sun Nov 5 08:57:45 2006 UTC (18 years, 3 months ago) by twoaday
File size: 7869 byte(s)


1 twoaday 180 /* wptSOCKS.cpp - SOCKS proxy support
2     * Copyright (C) 2006 Timo Schulz
3     *
4     * This file is part of WinPT.
5     *
6     * WinPT is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU General Public License
8     * as published by the Free Software Foundation; either version 2
9     * of the License, or (at your option) any later version.
10     *
11     * WinPT is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with WinPT; if not, write to the Free Software Foundation,
18     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #ifdef HAVE_CONFIG_H
22     #include <config.h>
23     #endif
24     #include <windows.h>
25    
26     #include "wptTypes.h"
27 twoaday 271 #include "wptGPG.h"
28 twoaday 180 #include "wptKeyserver.h"
29     #include "wptErrors.h"
30     #include "wptNLS.h"
31    
32     /* Known socks errors. */
33     enum socks5_error_t {
34     ERR_SUCCESS = 0x00,
35     ERR_GENERAL = 0x01,
36     ERR_NOTALLOWED = 0x02,
37     ERR_NETUNREACH = 0x03,
38     ERR_HOSTUNREACH = 0x04,
39     ERR_CONNREFUSED = 0x05,
40     ERR_INVADDR = 0x08
41     };
42    
43     /* Known socks address types. */
44     enum socks5_addr_t {
45     ADDR_IPV4 = 0x01,
46     ADDR_DOMAIN = 0x03,
47     ADDR_IPV6 = 0x04
48     };
49    
50     /* Known socks authentication methods. */
51     enum socks5_method_t {
52     METH_NOAUTH = 0x00,
53     METH_GSSAPI = 0x01,
54     METH_USERPASS = 0x02,
55     METH_ERR = 0xFF
56     };
57    
58    
59     /* Return human readable SOCKS error. */
60     static const char*
61     socks_strerror (int err)
62     {
63     switch (err) {
64     case ERR_SUCCESS: _("No error"); break;
65     case ERR_GENERAL: _("General SOCKS error"); break;
66     case ERR_NOTALLOWED: _("Connection not allowed by ruleset"); break;
67     case ERR_NETUNREACH: _("Network is unreachable"); break;
68     case ERR_HOSTUNREACH: _("Host could not be resolved"); break;
69     case ERR_CONNREFUSED: _("Connection refused"); break;
70     case ERR_INVADDR: _("Address type is not supported"); break;
71     }
72     return _("Unknown SOCKS error");
73     }
74    
75    
76     /* Send initial method packet. */
77     static int
78     send_methods (int conn_fd)
79     {
80     BYTE pkt[4];
81    
82     pkt[0] = 0x05;
83     pkt[1] = 0x02;
84     pkt[2] = METH_NOAUTH;
85     pkt[3] = METH_USERPASS;
86     if (send (conn_fd, (const char*)pkt, 4, 0) == SOCKET_ERROR) {
87     log_debug ("send_methods failed ec=%d\n", (int)WSAGetLastError ());
88     return -1;
89     }
90     return 0;
91     }
92    
93    
94     /* Parse the chosen server method. */
95     static int
96     recv_method (int conn_fd)
97     {
98     BYTE pkt[2];
99    
100     if (recv (conn_fd, (char*)pkt, 2, 0) == SOCKET_ERROR) {
101     log_debug ("recv_method failed ec=%d\n", (int)WSAGetLastError ());
102     return -1;
103     }
104     if (pkt[0] != 0x05) {
105     log_debug ("recv_method: protocol violation\n");
106     return -1;
107     }
108     return pkt[1];
109     }
110    
111    
112     /*
113     +----+------+----------+------+----------+
114     |VER | ULEN | UNAME | PLEN | PASSWD |
115     +----+------+----------+------+----------+
116     | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
117     +----+------+----------+------+----------+
118     Do user/password authentication.
119     */
120     static int
121     do_userpass_auth (int conn_fd, keyserver_proxy_t ctx, int *err)
122     {
123     BYTE *pkt;
124     DWORD pktlen;
125    
126     *err = 0;
127     pktlen = 1+1+strlen (ctx->user)+1+strlen (ctx->pass);
128     pkt = (BYTE*)malloc (pktlen);
129     pkt[0] = 0x05;
130     pkt[1] = strlen (ctx->user);
131     memcpy (pkt+2, ctx->user, strlen (ctx->user));
132     pkt[2+strlen (ctx->user)] = strlen (ctx->pass);
133     memcpy (pkt+2+strlen (ctx->user)+1, ctx->pass, strlen (ctx->pass));
134     if (send (conn_fd, (const char*)pkt, pktlen, 0) == SOCKET_ERROR) {
135     log_debug ("do_userpass_auth failed ec=%d\n", (int)WSAGetLastError ());
136     free (pkt);
137     return -1;
138     }
139     /* Parse reply [VER 1|STATUS 1] */
140     if (recv (conn_fd, (char*)pkt, 2, 0) == SOCKET_ERROR) {
141     log_debug ("do_userpass_auth failed ec=%d\n", (int)WSAGetLastError ());
142     free (pkt);
143     return -1;
144     }
145     *err = pkt[1];
146     free (pkt);
147     if (*err != ERR_SUCCESS)
148     return -1;
149     return 0;
150     }
151    
152    
153     /* Do the actual authentication. */
154     static int
155     do_auth (int conn_fd, int auth_method, keyserver_proxy_t ctx, int *err)
156     {
157     switch (auth_method) {
158     case PROXY_AUTH_NONE:
159     *err = 0;
160     return 0;
161    
162     case PROXY_AUTH_PLAIN:
163     return do_userpass_auth (conn_fd, ctx, err);
164    
165     default:
166     return -1;
167     }
168     return 0;
169     }
170    
171    
172     /*
173     +----+-----+-------+------+----------+----------+
174     |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
175     +----+-----+-------+------+----------+----------+
176     | 1 | 1 | X'00' | 1 | Variable | 2 |
177     +----+-----+-------+------+----------+----------+
178     Send a connection reqeust for host @host and port @port.
179     */
180     static int
181     send_connect_request (int conn_fd, const char *host, WORD port)
182     {
183     struct hostent *hp;
184     DWORD addr;
185     BYTE pkt[10];
186    
187     addr = inet_addr (host);
188     if (addr == INADDR_NONE) {
189     hp = gethostbyname (host);
190     if (hp != NULL)
191     memcpy ((char*)&addr, hp->h_addr_list, hp->h_length);
192     else {
193     log_debug ("gethostbyname() failed ec=%d\n", (int)WSAGetLastError ());
194     return -1;
195     }
196     }
197    
198     pkt[0] = 0x05;
199     pkt[1] = 0x01; /*CONNECT*/
200     pkt[2] = 0x00;
201     pkt[3] = ADDR_IPV4;
202     pkt[4] = (BYTE)addr >> 24;
203     pkt[5] = (BYTE)addr >> 16;
204     pkt[6] = (BYTE)addr >> 8;
205     pkt[7] = (BYTE)addr >> 0;
206     pkt[8] = (BYTE)port >> 8;
207     pkt[9] = (BYTE)port >> 0;
208     if (send (conn_fd, (const char*)pkt, 9, 0) == SOCKET_ERROR) {
209     log_debug ("send_connect_request failed ec=%d\n", (int)WSAGetLastError ());
210     return -1;
211     }
212    
213     return 0;
214     }
215    
216    
217     /*
218     +----+-----+-------+------+----------+----------+
219     |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
220     +----+-----+-------+------+----------+----------+
221     | 1 | 1 | X'00' | 1 | Variable | 2 |
222     +----+-----+-------+------+----------+----------+
223     Parse the connect reply.
224     Set @err with the specific error value.
225     */
226     static int
227     recv_connect_reply (int conn_fd, int *err)
228     {
229     BYTE pkt[4], addr[16], port[2];
230     int ndomain;
231    
232     *err = 0;
233     if (recv (conn_fd, (char*)pkt, 4, 0) == SOCKET_ERROR)
234     return -1;
235     if (pkt[0] != 0x05 || pkt[2] != 0x00) {
236     log_debug ("recv_connect_reply: protocol violation.\n");
237     return -1;
238     }
239     *err = pkt[1];
240     if (pkt[1] != ERR_SUCCESS)
241     return -1;
242     switch (pkt[3]) {
243     case ADDR_IPV4:
244     if (recv (conn_fd, (char*)addr, 4, 0) == SOCKET_ERROR)
245     return -1;
246     break;
247    
248     case ADDR_DOMAIN:
249     recv (conn_fd, (char*)addr, 1, 0);
250     ndomain = addr[0];
251     while (ndomain-- > 0)
252     recv (conn_fd, (char*)addr, 1, 0);
253     break;
254    
255     case ADDR_IPV6:
256     if ( recv (conn_fd, (char*)addr, 16, 0) == SOCKET_ERROR)
257     return -1;
258     break;
259     }
260     if (recv (conn_fd, (char*)port, 2, 0) == SOCKET_ERROR)
261     return -1;
262     return 0;
263     }
264    
265    
266     /* Perform all needed steps to initiate a SOCKSv5 proxy connection .*/
267     int
268     socks_handshake (keyserver_proxy_t ctx, int conn_fd,
269     const char *hostname, WORD port)
270     {
271     int method, err;
272    
273     if (send_methods (conn_fd))
274     return -1;
275     method = recv_method (conn_fd);
276     if (method == METH_ERR) {
277     msg_box (NULL, _("No acceptable methods"), _("SOCKS Proxy"), MB_ERR);
278     return -1;
279     }
280     if (do_auth (conn_fd, method, ctx, &err)) {
281     if (!err)
282     msg_box (NULL, _("Authentication failed or unspported"), _("SOCKS Proxy"), MB_ERR);
283     else
284     msg_box (NULL, socks_strerror (err), _("SOCKS Proxy"), MB_ERR);
285     return -1;
286     }
287     if (send_connect_request (conn_fd, hostname, port)) {
288     msg_box (NULL, _("Could not send SOCKS request"), _("SOCKS Proxy"), MB_ERR);
289     return -1;
290     }
291     if (recv_connect_reply (conn_fd, &err)) {
292     if (!err)
293     msg_box (NULL, _("Error while parsing SOCKS reply"), _("SOCKS Proxy"), MB_ERR);
294     else
295     msg_box (NULL, socks_strerror (err), _("SOCKS Proxy"), MB_ERR);
296     return -1;
297     }
298     return 0;
299     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26