OSDN Git Service

Enable Clean Up and Show log at GitStatusListCtrl
[tortoisegit/TortoiseGitJp.git] / src / TortoisePlink / PORTFWD.C
1 /*\r
2  * SSH port forwarding.\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 \r
8 #include "putty.h"\r
9 #include "ssh.h"\r
10 \r
11 #ifndef FALSE\r
12 #define FALSE 0\r
13 #endif\r
14 #ifndef TRUE\r
15 #define TRUE 1\r
16 #endif\r
17 \r
18 struct PFwdPrivate {\r
19     const struct plug_function_table *fn;\r
20     /* the above variable absolutely *must* be the first in this structure */\r
21     void *c;                           /* (channel) data used by ssh.c */\r
22     void *backhandle;                  /* instance of SSH backend itself */\r
23     /* Note that backhandle need not be filled in if c is non-NULL */\r
24     Socket s;\r
25     int throttled, throttle_override;\r
26     int ready;\r
27     /*\r
28      * `dynamic' does double duty. It's set to 0 for an ordinary\r
29      * forwarded port, and nonzero for SOCKS-style dynamic port\r
30      * forwarding; but it also represents the state of the SOCKS\r
31      * exchange.\r
32      */\r
33     int dynamic;\r
34     /*\r
35      * `hostname' and `port' are the real hostname and port, once\r
36      * we know what we're connecting to; they're unused for this\r
37      * purpose while conducting a local SOCKS exchange, which means\r
38      * we can also use them as a buffer and pointer for reading\r
39      * data from the SOCKS client.\r
40      */\r
41     char hostname[256+8];\r
42     int port;\r
43     /*\r
44      * When doing dynamic port forwarding, we can receive\r
45      * connection data before we are actually able to send it; so\r
46      * we may have to temporarily hold some in a dynamically\r
47      * allocated buffer here.\r
48      */\r
49     void *buffer;\r
50     int buflen;\r
51 };\r
52 \r
53 static void pfd_log(Plug plug, int type, SockAddr addr, int port,\r
54                     const char *error_msg, int error_code)\r
55 {\r
56     /* we have to dump these since we have no interface to logging.c */\r
57 }\r
58 \r
59 static int pfd_closing(Plug plug, const char *error_msg, int error_code,\r
60                        int calling_back)\r
61 {\r
62     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;\r
63 \r
64     /*\r
65      * We have no way to communicate down the forwarded connection,\r
66      * so if an error occurred on the socket, we just ignore it\r
67      * and treat it like a proper close.\r
68      */\r
69     if (pr->c)\r
70         sshfwd_close(pr->c);\r
71     pfd_close(pr->s);\r
72     return 1;\r
73 }\r
74 \r
75 static int pfd_receive(Plug plug, int urgent, char *data, int len)\r
76 {\r
77     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;\r
78     if (pr->dynamic) {\r
79         while (len--) {\r
80             /*\r
81              * Throughout SOCKS negotiation, "hostname" is re-used as a\r
82              * random protocol buffer with "port" storing the length.\r
83              */ \r
84             if (pr->port >= lenof(pr->hostname)) {\r
85                 /* Request too long. */\r
86                 if ((pr->dynamic >> 12) == 4) {\r
87                     /* Send back a SOCKS 4 error before closing. */\r
88                     char data[8];\r
89                     memset(data, 0, sizeof(data));\r
90                     data[1] = 91;      /* generic `request rejected' */\r
91                     sk_write(pr->s, data, 8);\r
92                 }\r
93                 pfd_close(pr->s);\r
94                 return 1;\r
95             }\r
96             pr->hostname[pr->port++] = *data++;\r
97 \r
98             /*\r
99              * Now check what's in the buffer to see if it's a\r
100              * valid and complete message in the SOCKS exchange.\r
101              */\r
102             if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) &&\r
103                 pr->hostname[0] == 4) {\r
104                 /*\r
105                  * SOCKS 4.\r
106                  */\r
107                 if (pr->dynamic == 1)\r
108                     pr->dynamic = 0x4000;\r
109                 if (pr->port < 2) continue;/* don't have command code yet */\r
110                 if (pr->hostname[1] != 1) {\r
111                     /* Not CONNECT. */\r
112                     /* Send back a SOCKS 4 error before closing. */\r
113                     char data[8];\r
114                     memset(data, 0, sizeof(data));\r
115                     data[1] = 91;      /* generic `request rejected' */\r
116                     sk_write(pr->s, data, 8);\r
117                     pfd_close(pr->s);\r
118                     return 1;\r
119                 }\r
120                 if (pr->port <= 8) continue; /* haven't started user/hostname */\r
121                 if (pr->hostname[pr->port-1] != 0)\r
122                     continue;          /* haven't _finished_ user/hostname */\r
123                 /*\r
124                  * Now we have a full SOCKS 4 request. Check it to\r
125                  * see if it's a SOCKS 4A request.\r
126                  */\r
127                 if (pr->hostname[4] == 0 && pr->hostname[5] == 0 &&\r
128                     pr->hostname[6] == 0 && pr->hostname[7] != 0) {\r
129                     /*\r
130                      * It's SOCKS 4A. So if we haven't yet\r
131                      * collected the host name, we should continue\r
132                      * waiting for data in order to do so; if we\r
133                      * have, we can go ahead.\r
134                      */\r
135                     int len;\r
136                     if (pr->dynamic == 0x4000) {\r
137                         pr->dynamic = 0x4001;\r
138                         pr->port = 8;      /* reset buffer to overwrite name */\r
139                         continue;\r
140                     }\r
141                     pr->hostname[0] = 0;   /* reply version code */\r
142                     pr->hostname[1] = 90;   /* request granted */\r
143                     sk_write(pr->s, pr->hostname, 8);\r
144                     len= pr->port - 8;\r
145                     pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);\r
146                     memmove(pr->hostname, pr->hostname + 8, len);\r
147                     goto connect;\r
148                 } else {\r
149                     /*\r
150                      * It's SOCKS 4, which means we should format\r
151                      * the IP address into the hostname string and\r
152                      * then just go.\r
153                      */\r
154                     pr->hostname[0] = 0;   /* reply version code */\r
155                     pr->hostname[1] = 90;   /* request granted */\r
156                     sk_write(pr->s, pr->hostname, 8);\r
157                     pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);\r
158                     sprintf(pr->hostname, "%d.%d.%d.%d",\r
159                             (unsigned char)pr->hostname[4],\r
160                             (unsigned char)pr->hostname[5],\r
161                             (unsigned char)pr->hostname[6],\r
162                             (unsigned char)pr->hostname[7]);\r
163                     goto connect;\r
164                 }\r
165             }\r
166 \r
167             if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) &&\r
168                 pr->hostname[0] == 5) {\r
169                 /*\r
170                  * SOCKS 5.\r
171                  */\r
172                 if (pr->dynamic == 1)\r
173                     pr->dynamic = 0x5000;\r
174 \r
175                 if (pr->dynamic == 0x5000) {\r
176                     int i, method;\r
177                     char data[2];\r
178                     /*\r
179                      * We're receiving a set of method identifiers.\r
180                      */\r
181                     if (pr->port < 2) continue;/* no method count yet */\r
182                     if (pr->port < 2 + (unsigned char)pr->hostname[1])\r
183                         continue;      /* no methods yet */\r
184                     method = 0xFF;     /* invalid */\r
185                     for (i = 0; i < (unsigned char)pr->hostname[1]; i++)\r
186                         if (pr->hostname[2+i] == 0) {\r
187                             method = 0;/* no auth */\r
188                             break;\r
189                         }\r
190                     data[0] = 5;\r
191                     data[1] = method;\r
192                     sk_write(pr->s, data, 2);\r
193                     pr->dynamic = 0x5001;\r
194                     pr->port = 0;      /* re-empty the buffer */\r
195                     continue;\r
196                 }\r
197 \r
198                 if (pr->dynamic == 0x5001) {\r
199                     /*\r
200                      * We're receiving a SOCKS request.\r
201                      */\r
202                     unsigned char reply[10]; /* SOCKS5 atyp=1 reply */\r
203                     int atype, alen = 0;\r
204 \r
205                     /*\r
206                      * Pre-fill reply packet.\r
207                      * In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0\r
208                      * (atyp=1) in the reply; if we succeed, we don't know\r
209                      * the right answers, and if we fail, they should be\r
210                      * ignored.\r
211                      */\r
212                     memset(reply, 0, lenof(reply));\r
213                     reply[0] = 5; /* VER */\r
214                     reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */\r
215 \r
216                     if (pr->port < 6) continue;\r
217                     atype = (unsigned char)pr->hostname[3];\r
218                     if (atype == 1)    /* IPv4 address */\r
219                         alen = 4;\r
220                     if (atype == 4)    /* IPv6 address */\r
221                         alen = 16;\r
222                     if (atype == 3)    /* domain name has leading length */\r
223                         alen = 1 + (unsigned char)pr->hostname[4];\r
224                     if (pr->port < 6 + alen) continue;\r
225                     if (pr->hostname[1] != 1 || pr->hostname[2] != 0) {\r
226                         /* Not CONNECT or reserved field nonzero - error */\r
227                         reply[1] = 1;   /* generic failure */\r
228                         sk_write(pr->s, (char *) reply, lenof(reply));\r
229                         pfd_close(pr->s);\r
230                         return 1;\r
231                     }\r
232                     /*\r
233                      * Now we have a viable connect request. Switch\r
234                      * on atype.\r
235                      */\r
236                     pr->port = GET_16BIT_MSB_FIRST(pr->hostname+4+alen);\r
237                     if (atype == 1) {\r
238                         /* REP=0 (success) already */\r
239                         sk_write(pr->s, (char *) reply, lenof(reply));\r
240                         sprintf(pr->hostname, "%d.%d.%d.%d",\r
241                                 (unsigned char)pr->hostname[4],\r
242                                 (unsigned char)pr->hostname[5],\r
243                                 (unsigned char)pr->hostname[6],\r
244                                 (unsigned char)pr->hostname[7]);\r
245                         goto connect;\r
246                     } else if (atype == 3) {\r
247                         /* REP=0 (success) already */\r
248                         sk_write(pr->s, (char *) reply, lenof(reply));\r
249                         memmove(pr->hostname, pr->hostname + 5, alen-1);\r
250                         pr->hostname[alen-1] = '\0';\r
251                         goto connect;\r
252                     } else {\r
253                         /*\r
254                          * Unknown address type. (FIXME: support IPv6!)\r
255                          */\r
256                         reply[1] = 8;   /* atype not supported */\r
257                         sk_write(pr->s, (char *) reply, lenof(reply));\r
258                         pfd_close(pr->s);\r
259                         return 1;\r
260                     }\r
261                 }\r
262             }\r
263 \r
264             /*\r
265              * If we get here without either having done `continue'\r
266              * or `goto connect', it must be because there is no\r
267              * sensible interpretation of what's in our buffer. So\r
268              * close the connection rudely.\r
269              */\r
270             pfd_close(pr->s);\r
271             return 1;\r
272         }\r
273         return 1;\r
274 \r
275         /*\r
276          * We come here when we're ready to make an actual\r
277          * connection.\r
278          */\r
279         connect:\r
280 \r
281         pr->c = new_sock_channel(pr->backhandle, pr->s);\r
282         if (pr->c == NULL) {\r
283             pfd_close(pr->s);\r
284             return 1;\r
285         } else {\r
286             /* asks to forward to the specified host/port for this */\r
287             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");\r
288         }\r
289         pr->dynamic = 0;\r
290 \r
291         /*\r
292          * Now freeze the socket until the SSH server confirms the\r
293          * connection.\r
294          */\r
295         sk_set_frozen(pr->s, 1);\r
296         /*\r
297          * If there's any data remaining in our current buffer,\r
298          * save it to be sent on pfd_confirm().\r
299          */\r
300         if (len > 0) {\r
301             pr->buffer = snewn(len, char);\r
302             memcpy(pr->buffer, data, len);\r
303             pr->buflen = len;\r
304         }\r
305     }\r
306     if (pr->ready) {\r
307         if (sshfwd_write(pr->c, data, len) > 0) {\r
308             pr->throttled = 1;\r
309             sk_set_frozen(pr->s, 1);\r
310         }\r
311     }\r
312     return 1;\r
313 }\r
314 \r
315 static void pfd_sent(Plug plug, int bufsize)\r
316 {\r
317     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;\r
318 \r
319     if (pr->c)\r
320         sshfwd_unthrottle(pr->c, bufsize);\r
321 }\r
322 \r
323 /*\r
324  * Called when receiving a PORT OPEN from the server\r
325  */\r
326 const char *pfd_newconnect(Socket *s, char *hostname, int port,\r
327                            void *c, const Config *cfg, int addressfamily)\r
328 {\r
329     static const struct plug_function_table fn_table = {\r
330         pfd_log,\r
331         pfd_closing,\r
332         pfd_receive,\r
333         pfd_sent,\r
334         NULL\r
335     };\r
336 \r
337     SockAddr addr;\r
338     const char *err;\r
339     char *dummy_realhost;\r
340     struct PFwdPrivate *pr;\r
341 \r
342     /*\r
343      * Try to find host.\r
344      */\r
345     addr = name_lookup(hostname, port, &dummy_realhost, cfg, addressfamily);\r
346     if ((err = sk_addr_error(addr)) != NULL) {\r
347         sk_addr_free(addr);\r
348         return err;\r
349     }\r
350 \r
351     /*\r
352      * Open socket.\r
353      */\r
354     pr = snew(struct PFwdPrivate);\r
355     pr->buffer = NULL;\r
356     pr->fn = &fn_table;\r
357     pr->throttled = pr->throttle_override = 0;\r
358     pr->ready = 1;\r
359     pr->c = c;\r
360     pr->backhandle = NULL;             /* we shouldn't need this */\r
361     pr->dynamic = 0;\r
362 \r
363     pr->s = *s = new_connection(addr, dummy_realhost, port,\r
364                                 0, 1, 0, 0, (Plug) pr, cfg);\r
365     if ((err = sk_socket_error(*s)) != NULL) {\r
366         sfree(pr);\r
367         return err;\r
368     }\r
369 \r
370     sk_set_private_ptr(*s, pr);\r
371     return NULL;\r
372 }\r
373 \r
374 /*\r
375  called when someone connects to the local port\r
376  */\r
377 \r
378 static int pfd_accepting(Plug p, OSSocket sock)\r
379 {\r
380     static const struct plug_function_table fn_table = {\r
381         pfd_log,\r
382         pfd_closing,\r
383         pfd_receive,\r
384         pfd_sent,\r
385         NULL\r
386     };\r
387     struct PFwdPrivate *pr, *org;\r
388     Socket s;\r
389     const char *err;\r
390 \r
391     org = (struct PFwdPrivate *)p;\r
392     pr = snew(struct PFwdPrivate);\r
393     pr->buffer = NULL;\r
394     pr->fn = &fn_table;\r
395 \r
396     pr->c = NULL;\r
397     pr->backhandle = org->backhandle;\r
398 \r
399     pr->s = s = sk_register(sock, (Plug) pr);\r
400     if ((err = sk_socket_error(s)) != NULL) {\r
401         sfree(pr);\r
402         return err != NULL;\r
403     }\r
404 \r
405     sk_set_private_ptr(s, pr);\r
406 \r
407     pr->throttled = pr->throttle_override = 0;\r
408     pr->ready = 0;\r
409 \r
410     if (org->dynamic) {\r
411         pr->dynamic = 1;\r
412         pr->port = 0;                  /* "hostname" buffer is so far empty */\r
413         sk_set_frozen(s, 0);           /* we want to receive SOCKS _now_! */\r
414     } else {\r
415         pr->dynamic = 0;\r
416         strcpy(pr->hostname, org->hostname);\r
417         pr->port = org->port;   \r
418         pr->c = new_sock_channel(org->backhandle, s);\r
419 \r
420         if (pr->c == NULL) {\r
421             sfree(pr);\r
422             return 1;\r
423         } else {\r
424             /* asks to forward to the specified host/port for this */\r
425             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");\r
426         }\r
427     }\r
428 \r
429     return 0;\r
430 }\r
431 \r
432 \r
433 /* Add a new forwarding from port -> desthost:destport\r
434  sets up a listener on the local machine on (srcaddr:)port\r
435  */\r
436 const char *pfd_addforward(char *desthost, int destport, char *srcaddr,\r
437                            int port, void *backhandle, const Config *cfg,\r
438                            void **sockdata, int address_family)\r
439 {\r
440     static const struct plug_function_table fn_table = {\r
441         pfd_log,\r
442         pfd_closing,\r
443         pfd_receive,                   /* should not happen... */\r
444         pfd_sent,                      /* also should not happen */\r
445         pfd_accepting\r
446     };\r
447 \r
448     const char *err;\r
449     struct PFwdPrivate *pr;\r
450     Socket s;\r
451 \r
452     /*\r
453      * Open socket.\r
454      */\r
455     pr = snew(struct PFwdPrivate);\r
456     pr->buffer = NULL;\r
457     pr->fn = &fn_table;\r
458     pr->c = NULL;\r
459     if (desthost) {\r
460         strcpy(pr->hostname, desthost);\r
461         pr->port = destport;\r
462         pr->dynamic = 0;\r
463     } else\r
464         pr->dynamic = 1;\r
465     pr->throttled = pr->throttle_override = 0;\r
466     pr->ready = 0;\r
467     pr->backhandle = backhandle;\r
468 \r
469     pr->s = s = new_listener(srcaddr, port, (Plug) pr,\r
470                              !cfg->lport_acceptall, cfg, address_family);\r
471     if ((err = sk_socket_error(s)) != NULL) {\r
472         sfree(pr);\r
473         return err;\r
474     }\r
475 \r
476     sk_set_private_ptr(s, pr);\r
477 \r
478     *sockdata = (void *)s;\r
479 \r
480     return NULL;\r
481 }\r
482 \r
483 void pfd_close(Socket s)\r
484 {\r
485     struct PFwdPrivate *pr;\r
486 \r
487     if (!s)\r
488         return;\r
489 \r
490     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
491 \r
492     sfree(pr->buffer);\r
493     sfree(pr);\r
494 \r
495     sk_close(s);\r
496 }\r
497 \r
498 /*\r
499  * Terminate a listener.\r
500  */\r
501 void pfd_terminate(void *sv)\r
502 {\r
503     pfd_close((Socket)sv);\r
504 }\r
505 \r
506 void pfd_unthrottle(Socket s)\r
507 {\r
508     struct PFwdPrivate *pr;\r
509     if (!s)\r
510         return;\r
511     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
512 \r
513     pr->throttled = 0;\r
514     sk_set_frozen(s, pr->throttled || pr->throttle_override);\r
515 }\r
516 \r
517 void pfd_override_throttle(Socket s, int enable)\r
518 {\r
519     struct PFwdPrivate *pr;\r
520     if (!s)\r
521         return;\r
522     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
523 \r
524     pr->throttle_override = enable;\r
525     sk_set_frozen(s, pr->throttled || pr->throttle_override);\r
526 }\r
527 \r
528 /*\r
529  * Called to send data down the raw connection.\r
530  */\r
531 int pfd_send(Socket s, char *data, int len)\r
532 {\r
533     if (s == NULL)\r
534         return 0;\r
535     return sk_write(s, data, len);\r
536 }\r
537 \r
538 \r
539 void pfd_confirm(Socket s)\r
540 {\r
541     struct PFwdPrivate *pr;\r
542 \r
543     if (s == NULL)\r
544         return;\r
545 \r
546     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
547     pr->ready = 1;\r
548     sk_set_frozen(s, 0);\r
549     sk_write(s, NULL, 0);\r
550     if (pr->buffer) {\r
551         sshfwd_write(pr->c, pr->buffer, pr->buflen);\r
552         sfree(pr->buffer);\r
553         pr->buffer = NULL;\r
554     }\r
555 }\r