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

Contents of /trunk/Src/wptSOCKS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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


1 /* 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 #include "wptGPG.h"
28 #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