Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/ttssh2/ttxssh/fwd-socks.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10495 - (show annotations) (download) (as text)
Sun Jan 15 15:06:39 2023 UTC (14 months, 3 weeks ago) by zmatsuo
File MIME type: text/x-csrc
File size: 15299 byte(s)
ttxsshのログをデバグ出力に出せるようにした

- 通常は従来どおりファイルに出力する
- ttxssh.c logputs() 内 outputdebugstring を true にすると OutputDebugString() が使用される
1 /*
2 * Copyright (C) 2017- TeraTerm Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "ttxssh.h"
30 #include "fwd.h"
31 #include "ttcommon.h"
32
33 // 4 + 1 + 255 + 2
34 #define SOCKS_REQUEST_MAXLEN 262
35
36 typedef enum {
37 SOCKS_STATE_INIT,
38 SOCKS_STATE_INITREPLY,
39 SOCKS_STATE_AUTHREPLY,
40 SOCKS_STATE_REQUESTSENT
41 } DynamicFwdState;
42
43 #define SOCKS4_COMMAND_CONNECT 0x01
44 #define SOCKS4_COMMAND_BIND 0x02
45
46 #define SOCKS4_RESULT_OK 0x5a
47 #define SOCKS4_RESULT_NG 0x5b
48 #define SOCKS4_RESULT_NOIDENTD 0x5c
49 #define SOCKS4_RESULT_IDENTDERR 0x5d
50
51 #define SOCKS5_COMMAND_CONNECT 0x01
52 #define SOCKS5_COMMAND_BIND 0x02
53 #define SOCKS5_COMMAND_UDP 0x03
54
55 #define SOCKS5_AUTH_NONE 0x00
56 #define SOCKS5_AUTH_GSSAPI 0x01
57 #define SOCKS5_AUTH_USERPASS 0x02
58 #define SOCKS5_AUTH_NOACCEPTABLE 0xff
59
60 #define SOCKS5_ADDRTYPE_IPV4 0x01
61 #define SOCKS5_ADDRTYPE_DOMAIN 0x03
62 #define SOCKS5_ADDRTYPE_IPV6 0x04
63
64 #define SOCKS5_OPEN_CONFIRM 128
65 #define SOCKS5_ERROR_COMMAND 129
66 #define SOCKS5_ERROR_ADDRTYPE 130
67
68 typedef struct {
69 PTInstVar pvar;
70
71 int channel_num;
72
73 char *peer_name;
74 int peer_port;
75
76 DynamicFwdState status;
77 unsigned int socks_ver;
78 unsigned char request_buf[SOCKS_REQUEST_MAXLEN];
79 unsigned int buflen;
80 } FWDDynamicFilterClosure;
81
82 void *SOCKS_init_filter(PTInstVar pvar, int channel_num, char *peer_name, int port)
83 {
84 FWDDynamicFilterClosure *closure = malloc(sizeof(FWDDynamicFilterClosure));
85
86 if (closure == NULL) {
87 logprintf(LOG_LEVEL_ERROR, "%s: Can't allocate memory for closure.", __FUNCTION__);
88 return NULL;
89 }
90
91 closure->pvar = pvar;
92 closure->channel_num = channel_num;
93 closure->peer_name = _strdup(peer_name);
94 closure->peer_port = port;
95
96 closure->status = SOCKS_STATE_INIT;
97 closure->socks_ver = 0;
98 closure->request_buf[0] = 0;
99 closure->buflen = 0;
100
101 return closure;
102 }
103
104 static void ClearRemoteConnectFlag(FWDDynamicFilterClosure *closure)
105 {
106 PTInstVar pvar = closure->pvar;
107 FWDChannel *c = pvar->fwd_state.channels + closure->channel_num;
108
109 c->status &= ~FWD_REMOTE_CONNECTED;
110 }
111
112 // �_�~�[���u���b�L���O���������p����
113 // �������������������������������������������A�u���b�L���O�������������������_���G���[������
114 static BOOL dummy_blocking_write(PTInstVar pvar, SOCKET s, const char *data, int length)
115 {
116 return FALSE;
117 }
118
119 static int send_socks_reply(FWDDynamicFilterClosure *closure, const char *data, int len)
120 {
121 PTInstVar pvar = closure->pvar;
122 FWDChannel *c = pvar->fwd_state.channels + closure->channel_num;
123
124 logprintf(LOG_LEVEL_VERBOSE, "%s: sending %d bytes.", __FUNCTION__, len);
125 //logprintf_hexdump(LOG_LEVEL_VERBOSE, data, len, "%s: sending %d bytes.", __FUNCTION__, len);
126
127 return UTIL_sock_buffered_write(pvar, &c->writebuf, dummy_blocking_write, c->local_socket, data, len);
128 }
129
130 static void send_socks4_reply(FWDDynamicFilterClosure *closure, int code)
131 {
132 unsigned char buff[] = {
133 0, // NUL
134 SOCKS4_RESULT_NG, // status
135 0, 0, // field 3
136 0, 0, 0, 0 // field 4
137 };
138
139 if (code == SOCKS4_RESULT_OK) {
140 buff[1] = SOCKS4_RESULT_OK;
141 }
142
143 send_socks_reply(closure, buff, sizeof(buff));
144 }
145
146 static void send_socks5_open_success(FWDDynamicFilterClosure *closure)
147 {
148 unsigned char buff[] = {
149 5, // version
150 0, // status -- success
151 0, // reserved
152 1, // addr-type (for dummy) -- IPv4
153 0, 0, 0, 0, // dummy address -- �T�[�o�� BIND Address �����m���������������� orz
154 0, 0 // dummy port number
155 };
156
157 send_socks_reply(closure, buff, sizeof(buff));
158 }
159
160 static void send_socks5_open_failure(FWDDynamicFilterClosure *closure, int reason)
161 {
162 unsigned char buff[] = {
163 5, // version
164 1, // status -- general failure
165 0, // reserved
166 1, // addr-type (for dummy) -- IPv4
167 0, 0, 0, 0, // dummy address -- �����o������������������ BIND Address ��������������
168 0, 0 // dummy port number
169 };
170
171 switch (reason) {
172 case 1: // SSH_OPEN_ADMINISTRATIVELY_PROHIBITED
173 buff[1] = 0x02; // connection not allowed
174 break;
175 case 2: // SSH_OPEN_CONNECT_FAILED
176 buff[1] = 0x04; // Host unreachable -- �����o���������R���F�X�����������A����������������
177 break;
178 case 3: // SSH_OPEN_UNKNOWN_CHANNEL_TYPE
179 buff[1] = 0x01; // general failure
180 break;
181 case 4: // SSH_OPEN_RESOURCE_SHORTAGE
182 buff[1] = 0x01; // general failure
183 break;
184 case SOCKS5_ERROR_COMMAND:
185 buff[1] = 0x07; // command not supported
186 break;
187 case SOCKS5_ERROR_ADDRTYPE:
188 buff[1] = 0x08; // address not supported
189 break;
190 }
191
192 send_socks_reply(closure, buff, sizeof(buff));
193 }
194
195 struct socks4_header {
196 unsigned char proto;
197 unsigned char command;
198 unsigned char port[2];
199 unsigned char addr[4];
200 };
201
202 static int parse_socks4_request(FWDDynamicFilterClosure *closure, unsigned char *buff, unsigned int bufflen)
203 {
204 struct socks4_header s4hdr;
205 unsigned char addrbuff[NI_MAXHOST];
206 unsigned char pname[NI_MAXSERV];
207 unsigned char *user, *addr;
208 int port;
209
210 if (bufflen < 8) {
211 return 0;
212 }
213
214 memcpy_s(&s4hdr, sizeof(s4hdr), buff, 8);
215
216 // CONNECT ��������
217 if (s4hdr.proto != 4 || s4hdr.command != SOCKS4_COMMAND_CONNECT) {
218 send_socks4_reply(closure, SOCKS4_RESULT_NG);
219 return -1;
220 }
221
222 // skip socks header
223 buff += 8;
224 bufflen -= 8;
225
226 user = buff;
227
228 while (bufflen > 0 && *buff != 0) {
229 bufflen--; buff++;
230 }
231
232 if (bufflen == 0) {
233 // NUL terminate ���������� -> ���N�G�X�g�������r��
234 return 0;
235 }
236
237 // skip NUL
238 buff++;
239 bufflen--;
240
241 port = s4hdr.port[0] * 256 + s4hdr.port[1];
242
243 if (s4hdr.addr[0] == 0 && s4hdr.addr[1] == 0 && s4hdr.addr[2] == 0 && s4hdr.addr[3] != 0) {
244 // SOCKS4a
245 addr = buff;
246 while (bufflen > 0 && *buff != 0) {
247 bufflen--; buff++;
248 }
249 if (bufflen == 0) {
250 // NUL terminate ���������� -> ���N�G�X�g�������r��
251 return 0;
252 }
253 }
254 else { // SOCKS4
255 struct sockaddr_in saddr4;
256
257 memset(&saddr4, 0, sizeof(saddr4));
258 saddr4.sin_family = AF_INET;
259 memcpy_s(&(saddr4.sin_addr), sizeof(saddr4.sin_addr), s4hdr.addr, 4);
260 getnameinfo((struct sockaddr *)&saddr4, sizeof(saddr4), addrbuff, sizeof(addrbuff),
261 pname, sizeof(pname), NI_NUMERICHOST | NI_NUMERICSERV);
262
263 addr = addrbuff;
264 }
265
266 // �T�[�o���v���������O���A�t���O���{��������������������
267 ClearRemoteConnectFlag(closure);
268
269 closure->socks_ver = 4;
270
271 SSH_open_channel(closure->pvar, closure->channel_num, addr, port, closure->peer_name, closure->peer_port);
272
273 closure->status = SOCKS_STATE_REQUESTSENT;
274 return 1;
275 }
276
277 static int parse_socks5_init_request(FWDDynamicFilterClosure *closure, unsigned char *buff, unsigned int bufflen)
278 {
279 unsigned int authmethod_count;
280 unsigned int i;
281 unsigned char reply_buff[2] = { 5, SOCKS5_AUTH_NOACCEPTABLE };
282 PTInstVar pvar = closure->pvar;
283 FWDChannel *channel = pvar->fwd_state.channels + closure->channel_num;
284
285 if (bufflen < 2) {
286 return 0;
287 }
288
289 if (buff[0] != 5) {
290 // protocol version missmatch
291 return -1;
292 }
293
294 authmethod_count = buff[1];
295
296 if (bufflen < authmethod_count + 2) {
297 return 0;
298 }
299
300 for (i=0; i<authmethod_count; i++) {
301 if (buff[i+2] == SOCKS5_AUTH_NONE) {
302 // ���������F�����������T�|�[�g
303 closure->socks_ver = 5;
304 reply_buff[1] = SOCKS5_AUTH_NONE;
305 send_socks_reply(closure, reply_buff, 2);
306
307 closure->status = SOCKS_STATE_AUTHREPLY;
308 closure->buflen = 0;
309 return 1;
310 }
311 }
312 send_socks_reply(closure, reply_buff, 2);
313 return -1;
314 }
315
316 struct socks5_header {
317 unsigned char proto;
318 unsigned char command;
319 unsigned char reserved;
320 unsigned char addr_type;
321 unsigned char addr_len;
322 };
323
324 static int parse_socks5_connect_request(FWDDynamicFilterClosure *closure, unsigned char *buff, unsigned int bufflen)
325 {
326 struct socks5_header s5hdr;
327 unsigned char addr[NI_MAXHOST];
328 unsigned char pname[NI_MAXSERV];
329 int port;
330 unsigned int reqlen, addrlen;
331
332 if (bufflen < 5) {
333 return 0;
334 }
335 memcpy_s(&s5hdr, sizeof(s5hdr), buff, 5);
336
337 switch (s5hdr.addr_type) {
338 case SOCKS5_ADDRTYPE_IPV4:
339 addrlen = 4;
340 break;
341 case SOCKS5_ADDRTYPE_DOMAIN:
342 addrlen = s5hdr.addr_len + 1;
343 break;
344 case SOCKS5_ADDRTYPE_IPV6:
345 addrlen = 16;
346 break;
347 default: // Invalid address type
348 send_socks5_open_failure(closure, SOCKS5_ERROR_ADDRTYPE);
349 return -1;
350 }
351
352 reqlen = 4 + addrlen + 2;
353
354 if (bufflen < reqlen) {
355 return 0;
356 }
357
358 if (s5hdr.proto != 5 || s5hdr.reserved != 0) {
359 return -1;
360 }
361
362 if (s5hdr.command != SOCKS5_COMMAND_CONNECT) {
363 // CONNECT ���O��������
364 send_socks5_open_failure(closure, SOCKS5_ERROR_COMMAND);
365 return -1;
366 }
367
368 switch (s5hdr.addr_type) {
369 case SOCKS5_ADDRTYPE_IPV4: {
370 struct sockaddr_in saddr4;
371
372 memset(&saddr4, 0, sizeof(saddr4));
373 saddr4.sin_family = AF_INET;
374 memcpy_s(&(saddr4.sin_addr), sizeof(saddr4.sin_addr), &buff[4], addrlen);
375 getnameinfo((struct sockaddr *)&saddr4, sizeof(saddr4), addr, sizeof(addr),
376 pname, sizeof(pname), NI_NUMERICHOST | NI_NUMERICSERV);
377 break;
378 }
379
380 case SOCKS5_ADDRTYPE_DOMAIN:
381 if (s5hdr.addr_len > sizeof(addr) - 1 ) {
382 return -1;
383 }
384 memcpy_s(addr, sizeof(addr), &buff[5], s5hdr.addr_len);
385 addr[s5hdr.addr_len] = 0;
386 break;
387
388 case SOCKS5_ADDRTYPE_IPV6: {
389 struct sockaddr_in6 saddr6;
390
391 memset(&saddr6, 0, sizeof(saddr6));
392 saddr6.sin6_family = AF_INET6;
393 memcpy_s(&(saddr6.sin6_addr), sizeof(saddr6.sin6_addr), &buff[4], addrlen);
394 getnameinfo((struct sockaddr *)&saddr6, sizeof(saddr6), addr, sizeof(addr),
395 pname, sizeof(pname), NI_NUMERICHOST | NI_NUMERICSERV);
396 break;
397 }
398 }
399
400 port = buff[4 + addrlen] * 256 + buff[4 + addrlen + 1];
401
402 // �T�[�o���v���������O���A�t���O���{��������������������
403 ClearRemoteConnectFlag(closure);
404
405 SSH_open_channel(closure->pvar, closure->channel_num, addr, port, closure->peer_name, closure->peer_port);
406 closure->status = SOCKS_STATE_REQUESTSENT;
407
408 return 1;
409 }
410
411 static FwdFilterResult parse_client_request(FWDDynamicFilterClosure *closure, int *len, unsigned char **buf)
412 {
413 unsigned char *request = closure->request_buf;
414 unsigned int reqlen, newlen;
415 int result = 0;
416
417 newlen = closure->buflen + *len;
418
419 if (newlen > SOCKS_REQUEST_MAXLEN || *len < 0) {
420 // ���N�G�X�g���������������������f����
421 logprintf(LOG_LEVEL_ERROR,
422 "%s: request too large: state=%d, buflen=%d, reqlen=%d",
423 __FUNCTION__, closure->status, closure->buflen, *len);
424 return FWD_FILTER_CLOSECHANNEL;
425 }
426
427 memcpy_s(closure->request_buf + closure->buflen,
428 sizeof(closure->request_buf) - closure->buflen,
429 *buf, *len);
430 closure->buflen = newlen;
431 request = closure->request_buf;
432 reqlen = closure->buflen;
433
434 // �e�X�g�������A�������f�[�^�������������������S������
435 **buf = 0; *len = 0;
436
437 switch (closure->status) {
438 case SOCKS_STATE_INIT:
439 if (request[0] == 4) {
440 result = parse_socks4_request(closure, request, reqlen);
441 }
442 else if (request[0] == 5) {
443 result = parse_socks5_init_request(closure, request, reqlen);
444 }
445 else {
446 // Invalid request
447 logprintf(LOG_LEVEL_ERROR, "%s: Invalid request. protocol-version=%d", __FUNCTION__, buf[0]);
448 result = -1;
449 }
450 break;
451 case SOCKS_STATE_AUTHREPLY:
452 if (request[0] == 5) {
453 result = parse_socks5_connect_request(closure, request, reqlen);
454 }
455 else {
456 // Invalid request
457 logprintf(LOG_LEVEL_ERROR, "%s: Invalid request. protocol-version=%d", __FUNCTION__, buf[0]);
458 result = -1;
459 }
460 break;
461 default:
462 // NOT REACHED
463 break;
464 }
465
466
467 if (result < 0) {
468 // �t���O���{��������(�����[�g������)������
469 // �����������������������A���������`���l������������������������������
470 ClearRemoteConnectFlag(closure);
471
472 return FWD_FILTER_CLOSECHANNEL;
473 }
474
475 return FWD_FILTER_RETAIN;
476 }
477
478 FwdFilterResult SOCKS_filter(void *void_closure, FwdFilterEvent event, int *len, unsigned char **buf)
479 {
480 FWDDynamicFilterClosure *closure = (FWDDynamicFilterClosure *)void_closure;
481
482 if (closure == NULL) {
483 logprintf(LOG_LEVEL_VERBOSE, "%s: closure does not available. event=%d", __FUNCTION__, event);
484 return FWD_FILTER_REMOVE;
485 }
486
487 switch (event) {
488 case FWD_FILTER_CLEANUP:
489 // FWD_FILTER_REMOVE ���������A���\�[�X�J�����������������x��������
490 logprintf(LOG_LEVEL_VERBOSE, "%s: closure cleanup. channel=%d", __FUNCTION__, closure->channel_num);
491 free(closure->peer_name);
492 free(closure);
493 return FWD_FILTER_REMOVE;
494
495 case FWD_FILTER_OPENCONFIRM:
496 // SSH_open_channel() ������
497 logprintf(LOG_LEVEL_VERBOSE, "%s: OpenConfirmation received", __FUNCTION__ );
498 if (closure->socks_ver == 4) {
499 send_socks4_reply(closure, SOCKS4_RESULT_OK);
500 }
501 else if (closure->socks_ver == 5) {
502 send_socks5_open_success(closure);
503 }
504 else {
505 logprintf(LOG_LEVEL_VERBOSE, "%s: protocol version missmatch. version=%d", __FUNCTION__, closure->socks_ver);
506 }
507 return FWD_FILTER_REMOVE;
508
509 case FWD_FILTER_OPENFAILURE:
510 // SSH_open_channel() �����s
511 logprintf(LOG_LEVEL_VERBOSE, "%s: Open Failure. reason=%d", __FUNCTION__, *len);
512 if (closure->socks_ver == 4) {
513 send_socks4_reply(closure, SOCKS4_RESULT_NG);
514 }
515 else if (closure->socks_ver == 5) {
516 send_socks5_open_failure(closure, *len);
517 }
518 else {
519 logprintf(LOG_LEVEL_VERBOSE, "%s: protocol version missmatch. version=%d", __FUNCTION__, closure->socks_ver);
520 }
521 return FWD_FILTER_CLOSECHANNEL;
522
523 case FWD_FILTER_FROM_SERVER:
524 // �����t�B���^���L�������_�����T�[�o�����`���l�����J��������������
525 // ������������������
526 logprintf(LOG_LEVEL_VERBOSE, "%s: data received from server. (bug?)", __FUNCTION__);
527 return FWD_FILTER_RETAIN;
528
529 case FWD_FILTER_FROM_CLIENT:
530 // �N���C�A���g�������v������������
531 logprintf(LOG_LEVEL_VERBOSE, "%s: data received from client. size=%d", __FUNCTION__, *len);
532 return parse_client_request(closure, len, buf);
533 }
534
535 // NOT REACHED
536 return FWD_FILTER_RETAIN;
537 }

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