Add more options to version.txt
[TortoiseGit.git] / src / TortoisePlink / PORTFWD.C
blobbb9abe6ac06aabee45fc3c4d6f872fd9e059bd82
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
11 #ifndef FALSE\r
12 #define FALSE 0\r
13 #endif\r
14 #ifndef TRUE\r
15 #define TRUE 1\r
16 #endif\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.\r
37      */\r
38     char *hostname;\r
39     int port;\r
40     /*\r
41      * `socksbuf' is the buffer we use to accumulate a SOCKS request.\r
42      */\r
43     char *socksbuf;\r
44     int sockslen, sockssize;\r
45     /*\r
46      * When doing dynamic port forwarding, we can receive\r
47      * connection data before we are actually able to send it; so\r
48      * we may have to temporarily hold some in a dynamically\r
49      * allocated buffer here.\r
50      */\r
51     void *buffer;\r
52     int buflen;\r
53 };\r
55 static struct PFwdPrivate *new_portfwd_private(void)\r
56 {\r
57     struct PFwdPrivate *pr = snew(struct PFwdPrivate);\r
58     pr->hostname = NULL;\r
59     pr->socksbuf = NULL;\r
60     pr->sockslen = pr->sockssize = 0;\r
61     pr->buffer = NULL;\r
62     return pr;\r
63 }\r
65 static void free_portfwd_private(struct PFwdPrivate *pr)\r
66 {\r
67     if (!pr)\r
68         return;\r
69     sfree(pr->hostname);\r
70     sfree(pr->socksbuf);\r
71     sfree(pr->buffer);\r
72     sfree(pr);\r
73 }\r
75 static void pfd_log(Plug plug, int type, SockAddr addr, int port,\r
76                     const char *error_msg, int error_code)\r
77 {\r
78     /* we have to dump these since we have no interface to logging.c */\r
79 }\r
81 static int pfd_closing(Plug plug, const char *error_msg, int error_code,\r
82                        int calling_back)\r
83 {\r
84     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;\r
86     if (error_msg) {\r
87         /*\r
88          * Socket error. Slam the connection instantly shut.\r
89          */\r
90         sshfwd_unclean_close(pr->c);\r
91     } else {\r
92         /*\r
93          * Ordinary EOF received on socket. Send an EOF on the SSH\r
94          * channel.\r
95          */\r
96         if (pr->c)\r
97             sshfwd_write_eof(pr->c);\r
98     }\r
100     return 1;\r
103 static int pfd_receive(Plug plug, int urgent, char *data, int len)\r
105     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;\r
106     if (pr->dynamic) {\r
107         while (len--) {\r
108             if (pr->sockslen >= pr->sockssize) {\r
109                 pr->sockssize = pr->sockslen * 5 / 4 + 256;\r
110                 pr->socksbuf = sresize(pr->socksbuf, pr->sockssize, char);\r
111             }\r
112             pr->socksbuf[pr->sockslen++] = *data++;\r
114             /*\r
115              * Now check what's in the buffer to see if it's a\r
116              * valid and complete message in the SOCKS exchange.\r
117              */\r
118             if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) &&\r
119                 pr->socksbuf[0] == 4) {\r
120                 /*\r
121                  * SOCKS 4.\r
122                  */\r
123                 if (pr->dynamic == 1)\r
124                     pr->dynamic = 0x4000;\r
125                 if (pr->sockslen < 2)\r
126                     continue;        /* don't have command code yet */\r
127                 if (pr->socksbuf[1] != 1) {\r
128                     /* Not CONNECT. */\r
129                     /* Send back a SOCKS 4 error before closing. */\r
130                     char data[8];\r
131                     memset(data, 0, sizeof(data));\r
132                     data[1] = 91;      /* generic `request rejected' */\r
133                     sk_write(pr->s, data, 8);\r
134                     pfd_close(pr->s);\r
135                     return 1;\r
136                 }\r
137                 if (pr->sockslen <= 8)\r
138                     continue;      /* haven't started user/hostname */\r
139                 if (pr->socksbuf[pr->sockslen-1] != 0)\r
140                     continue;          /* haven't _finished_ user/hostname */\r
141                 /*\r
142                  * Now we have a full SOCKS 4 request. Check it to\r
143                  * see if it's a SOCKS 4A request.\r
144                  */\r
145                 if (pr->socksbuf[4] == 0 && pr->socksbuf[5] == 0 &&\r
146                     pr->socksbuf[6] == 0 && pr->socksbuf[7] != 0) {\r
147                     /*\r
148                      * It's SOCKS 4A. So if we haven't yet\r
149                      * collected the host name, we should continue\r
150                      * waiting for data in order to do so; if we\r
151                      * have, we can go ahead.\r
152                      */\r
153                     int len;\r
154                     if (pr->dynamic == 0x4000) {\r
155                         pr->dynamic = 0x4001;\r
156                         pr->sockslen = 8; /* reset buffer to overwrite name */\r
157                         continue;\r
158                     }\r
159                     pr->socksbuf[0] = 0;   /* reply version code */\r
160                     pr->socksbuf[1] = 90;   /* request granted */\r
161                     sk_write(pr->s, pr->socksbuf, 8);\r
162                     len = pr->sockslen - 8;\r
163                     pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+2);\r
164                     pr->hostname = snewn(len+1, char);\r
165                     pr->hostname[len] = '\0';\r
166                     memcpy(pr->hostname, pr->socksbuf + 8, len);\r
167                     goto connect;\r
168                 } else {\r
169                     /*\r
170                      * It's SOCKS 4, which means we should format\r
171                      * the IP address into the hostname string and\r
172                      * then just go.\r
173                      */\r
174                     pr->socksbuf[0] = 0;   /* reply version code */\r
175                     pr->socksbuf[1] = 90;   /* request granted */\r
176                     sk_write(pr->s, pr->socksbuf, 8);\r
177                     pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+2);\r
178                     pr->hostname = dupprintf("%d.%d.%d.%d",\r
179                                              (unsigned char)pr->socksbuf[4],\r
180                                              (unsigned char)pr->socksbuf[5],\r
181                                              (unsigned char)pr->socksbuf[6],\r
182                                              (unsigned char)pr->socksbuf[7]);\r
183                     goto connect;\r
184                 }\r
185             }\r
187             if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) &&\r
188                 pr->socksbuf[0] == 5) {\r
189                 /*\r
190                  * SOCKS 5.\r
191                  */\r
192                 if (pr->dynamic == 1)\r
193                     pr->dynamic = 0x5000;\r
195                 if (pr->dynamic == 0x5000) {\r
196                     int i, method;\r
197                     char data[2];\r
198                     /*\r
199                      * We're receiving a set of method identifiers.\r
200                      */\r
201                     if (pr->sockslen < 2)\r
202                         continue;      /* no method count yet */\r
203                     if (pr->sockslen < 2 + (unsigned char)pr->socksbuf[1])\r
204                         continue;      /* no methods yet */\r
205                     method = 0xFF;     /* invalid */\r
206                     for (i = 0; i < (unsigned char)pr->socksbuf[1]; i++)\r
207                         if (pr->socksbuf[2+i] == 0) {\r
208                             method = 0;/* no auth */\r
209                             break;\r
210                         }\r
211                     data[0] = 5;\r
212                     data[1] = method;\r
213                     sk_write(pr->s, data, 2);\r
214                     pr->dynamic = 0x5001;\r
215                     pr->sockslen = 0;      /* re-empty the buffer */\r
216                     continue;\r
217                 }\r
219                 if (pr->dynamic == 0x5001) {\r
220                     /*\r
221                      * We're receiving a SOCKS request.\r
222                      */\r
223                     unsigned char reply[10]; /* SOCKS5 atyp=1 reply */\r
224                     int atype, alen = 0;\r
226                     /*\r
227                      * Pre-fill reply packet.\r
228                      * In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0\r
229                      * (atyp=1) in the reply; if we succeed, we don't know\r
230                      * the right answers, and if we fail, they should be\r
231                      * ignored.\r
232                      */\r
233                     memset(reply, 0, lenof(reply));\r
234                     reply[0] = 5; /* VER */\r
235                     reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */\r
237                     if (pr->sockslen < 6) continue;\r
238                     atype = (unsigned char)pr->socksbuf[3];\r
239                     if (atype == 1)    /* IPv4 address */\r
240                         alen = 4;\r
241                     if (atype == 4)    /* IPv6 address */\r
242                         alen = 16;\r
243                     if (atype == 3)    /* domain name has leading length */\r
244                         alen = 1 + (unsigned char)pr->socksbuf[4];\r
245                     if (pr->sockslen < 6 + alen) continue;\r
246                     if (pr->socksbuf[1] != 1 || pr->socksbuf[2] != 0) {\r
247                         /* Not CONNECT or reserved field nonzero - error */\r
248                         reply[1] = 1;   /* generic failure */\r
249                         sk_write(pr->s, (char *) reply, lenof(reply));\r
250                         pfd_close(pr->s);\r
251                         return 1;\r
252                     }\r
253                     /*\r
254                      * Now we have a viable connect request. Switch\r
255                      * on atype.\r
256                      */\r
257                     pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+4+alen);\r
258                     if (atype == 1) {\r
259                         /* REP=0 (success) already */\r
260                         sk_write(pr->s, (char *) reply, lenof(reply));\r
261                         pr->hostname = dupprintf("%d.%d.%d.%d",\r
262                                                  (unsigned char)pr->socksbuf[4],\r
263                                                  (unsigned char)pr->socksbuf[5],\r
264                                                  (unsigned char)pr->socksbuf[6],\r
265                                                  (unsigned char)pr->socksbuf[7]);\r
266                         goto connect;\r
267                     } else if (atype == 3) {\r
268                         /* REP=0 (success) already */\r
269                         sk_write(pr->s, (char *) reply, lenof(reply));\r
270                         pr->hostname = snewn(alen, char);\r
271                         pr->hostname[alen-1] = '\0';\r
272                         memcpy(pr->hostname, pr->socksbuf + 5, alen-1);\r
273                         goto connect;\r
274                     } else {\r
275                         /*\r
276                          * Unknown address type. (FIXME: support IPv6!)\r
277                          */\r
278                         reply[1] = 8;   /* atype not supported */\r
279                         sk_write(pr->s, (char *) reply, lenof(reply));\r
280                         pfd_close(pr->s);\r
281                         return 1;\r
282                     }\r
283                 }\r
284             }\r
286             /*\r
287              * If we get here without either having done `continue'\r
288              * or `goto connect', it must be because there is no\r
289              * sensible interpretation of what's in our buffer. So\r
290              * close the connection rudely.\r
291              */\r
292             pfd_close(pr->s);\r
293             return 1;\r
294         }\r
295         return 1;\r
297         /*\r
298          * We come here when we're ready to make an actual\r
299          * connection.\r
300          */\r
301         connect:\r
302         sfree(pr->socksbuf);\r
303         pr->socksbuf = NULL;\r
305         /*\r
306          * Freeze the socket until the SSH server confirms the\r
307          * connection.\r
308          */\r
309         sk_set_frozen(pr->s, 1);\r
311         pr->c = new_sock_channel(pr->backhandle, pr->s);\r
312         if (pr->c == NULL) {\r
313             pfd_close(pr->s);\r
314             return 1;\r
315         } else {\r
316             /* asks to forward to the specified host/port for this */\r
317             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");\r
318         }\r
319         pr->dynamic = 0;\r
321         /*\r
322          * If there's any data remaining in our current buffer,\r
323          * save it to be sent on pfd_confirm().\r
324          */\r
325         if (len > 0) {\r
326             pr->buffer = snewn(len, char);\r
327             memcpy(pr->buffer, data, len);\r
328             pr->buflen = len;\r
329         }\r
330     }\r
331     if (pr->ready) {\r
332         if (sshfwd_write(pr->c, data, len) > 0) {\r
333             pr->throttled = 1;\r
334             sk_set_frozen(pr->s, 1);\r
335         }\r
336     }\r
337     return 1;\r
340 static void pfd_sent(Plug plug, int bufsize)\r
342     struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;\r
344     if (pr->c)\r
345         sshfwd_unthrottle(pr->c, bufsize);\r
348 /*\r
349  * Called when receiving a PORT OPEN from the server\r
350  */\r
351 const char *pfd_newconnect(Socket *s, char *hostname, int port,\r
352                            void *c, Conf *conf, int addressfamily)\r
354     static const struct plug_function_table fn_table = {\r
355         pfd_log,\r
356         pfd_closing,\r
357         pfd_receive,\r
358         pfd_sent,\r
359         NULL\r
360     };\r
362     SockAddr addr;\r
363     const char *err;\r
364     char *dummy_realhost;\r
365     struct PFwdPrivate *pr;\r
367     /*\r
368      * Try to find host.\r
369      */\r
370     addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily);\r
371     if ((err = sk_addr_error(addr)) != NULL) {\r
372         sk_addr_free(addr);\r
373         sfree(dummy_realhost);\r
374         return err;\r
375     }\r
377     /*\r
378      * Open socket.\r
379      */\r
380     pr = new_portfwd_private();\r
381     pr->fn = &fn_table;\r
382     pr->throttled = pr->throttle_override = 0;\r
383     pr->ready = 1;\r
384     pr->c = c;\r
385     pr->backhandle = NULL;             /* we shouldn't need this */\r
386     pr->dynamic = 0;\r
388     pr->s = *s = new_connection(addr, dummy_realhost, port,\r
389                                 0, 1, 0, 0, (Plug) pr, conf);\r
390     sfree(dummy_realhost);\r
391     if ((err = sk_socket_error(*s)) != NULL) {\r
392         free_portfwd_private(pr);\r
393         return err;\r
394     }\r
396     sk_set_private_ptr(*s, pr);\r
397     return NULL;\r
400 /*\r
401  called when someone connects to the local port\r
402  */\r
404 static int pfd_accepting(Plug p, OSSocket sock)\r
406     static const struct plug_function_table fn_table = {\r
407         pfd_log,\r
408         pfd_closing,\r
409         pfd_receive,\r
410         pfd_sent,\r
411         NULL\r
412     };\r
413     struct PFwdPrivate *pr, *org;\r
414     Socket s;\r
415     const char *err;\r
417     org = (struct PFwdPrivate *)p;\r
418     pr = new_portfwd_private();\r
419     pr->fn = &fn_table;\r
421     pr->c = NULL;\r
422     pr->backhandle = org->backhandle;\r
424     pr->s = s = sk_register(sock, (Plug) pr);\r
425     if ((err = sk_socket_error(s)) != NULL) {\r
426         free_portfwd_private(pr);\r
427         return err != NULL;\r
428     }\r
430     sk_set_private_ptr(s, pr);\r
432     pr->throttled = pr->throttle_override = 0;\r
433     pr->ready = 0;\r
435     if (org->dynamic) {\r
436         pr->dynamic = 1;\r
437         pr->port = 0;                  /* "hostname" buffer is so far empty */\r
438         sk_set_frozen(s, 0);           /* we want to receive SOCKS _now_! */\r
439     } else {\r
440         pr->dynamic = 0;\r
441         pr->hostname = dupstr(org->hostname);\r
442         pr->port = org->port;   \r
443         pr->c = new_sock_channel(org->backhandle, s);\r
445         if (pr->c == NULL) {\r
446             free_portfwd_private(pr);\r
447             return 1;\r
448         } else {\r
449             /* asks to forward to the specified host/port for this */\r
450             ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");\r
451         }\r
452     }\r
454     return 0;\r
458 /* Add a new forwarding from port -> desthost:destport\r
459  sets up a listener on the local machine on (srcaddr:)port\r
460  */\r
461 const char *pfd_addforward(char *desthost, int destport, char *srcaddr,\r
462                            int port, void *backhandle, Conf *conf,\r
463                            void **sockdata, int address_family)\r
465     static const struct plug_function_table fn_table = {\r
466         pfd_log,\r
467         pfd_closing,\r
468         pfd_receive,                   /* should not happen... */\r
469         pfd_sent,                      /* also should not happen */\r
470         pfd_accepting\r
471     };\r
473     const char *err;\r
474     struct PFwdPrivate *pr;\r
475     Socket s;\r
477     /*\r
478      * Open socket.\r
479      */\r
480     pr = new_portfwd_private();\r
481     pr->fn = &fn_table;\r
482     pr->c = NULL;\r
483     if (desthost) {\r
484         pr->hostname = dupstr(desthost);\r
485         pr->port = destport;\r
486         pr->dynamic = 0;\r
487     } else\r
488         pr->dynamic = 1;\r
489     pr->throttled = pr->throttle_override = 0;\r
490     pr->ready = 0;\r
491     pr->backhandle = backhandle;\r
493     pr->s = s = new_listener(srcaddr, port, (Plug) pr,\r
494                              !conf_get_int(conf, CONF_lport_acceptall),\r
495                              conf, address_family);\r
496     if ((err = sk_socket_error(s)) != NULL) {\r
497         free_portfwd_private(pr);\r
498         return err;\r
499     }\r
501     sk_set_private_ptr(s, pr);\r
503     *sockdata = (void *)s;\r
505     return NULL;\r
508 void pfd_close(Socket s)\r
510     struct PFwdPrivate *pr;\r
512     if (!s)\r
513         return;\r
515     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
517     free_portfwd_private(pr);\r
519     sk_close(s);\r
522 /*\r
523  * Terminate a listener.\r
524  */\r
525 void pfd_terminate(void *sv)\r
527     pfd_close((Socket)sv);\r
530 void pfd_unthrottle(Socket s)\r
532     struct PFwdPrivate *pr;\r
533     if (!s)\r
534         return;\r
535     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
537     pr->throttled = 0;\r
538     sk_set_frozen(s, pr->throttled || pr->throttle_override);\r
541 void pfd_override_throttle(Socket s, int enable)\r
543     struct PFwdPrivate *pr;\r
544     if (!s)\r
545         return;\r
546     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
548     pr->throttle_override = enable;\r
549     sk_set_frozen(s, pr->throttled || pr->throttle_override);\r
552 /*\r
553  * Called to send data down the raw connection.\r
554  */\r
555 int pfd_send(Socket s, char *data, int len)\r
557     if (s == NULL)\r
558         return 0;\r
559     return sk_write(s, data, len);\r
562 void pfd_send_eof(Socket s)\r
564     sk_write_eof(s);\r
567 void pfd_confirm(Socket s)\r
569     struct PFwdPrivate *pr;\r
571     if (s == NULL)\r
572         return;\r
574     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);\r
575     pr->ready = 1;\r
576     sk_set_frozen(s, 0);\r
577     sk_write(s, NULL, 0);\r
578     if (pr->buffer) {\r
579         sshfwd_write(pr->c, pr->buffer, pr->buflen);\r
580         sfree(pr->buffer);\r
581         pr->buffer = NULL;\r
582     }\r