Introduce .gitattributes file for patches of libgit2
[TortoiseGit.git] / src / TortoisePlink / PORTFWD.C
blob5f5f2379ab1e221ed93665e9614ee94a8d4ccba0
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 PortForwarding {\r
19     const struct plug_function_table *fn;\r
20     /* the above variable absolutely *must* be the first in this structure */\r
21     struct ssh_channel *c;        /* channel structure held 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 the nonzero values are also a state machine\r
31      * tracking where the SOCKS exchange has got to.\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 struct PortListener {\r
56     const struct plug_function_table *fn;\r
57     /* the above variable absolutely *must* be the first in this structure */\r
58     void *backhandle;                  /* instance of SSH backend itself */\r
59     Socket s;\r
60     /*\r
61      * `dynamic' is set to 0 for an ordinary forwarded port, and\r
62      * nonzero for SOCKS-style dynamic port forwarding.\r
63      */\r
64     int dynamic;\r
65     /*\r
66      * `hostname' and `port' are the real hostname and port, for\r
67      * ordinary forwardings.\r
68      */\r
69     char *hostname;\r
70     int port;\r
71 };\r
73 static struct PortForwarding *new_portfwd_state(void)\r
74 {\r
75     struct PortForwarding *pf = snew(struct PortForwarding);\r
76     pf->hostname = NULL;\r
77     pf->socksbuf = NULL;\r
78     pf->sockslen = pf->sockssize = 0;\r
79     pf->buffer = NULL;\r
80     return pf;\r
81 }\r
83 static void free_portfwd_state(struct PortForwarding *pf)\r
84 {\r
85     if (!pf)\r
86         return;\r
87     sfree(pf->hostname);\r
88     sfree(pf->socksbuf);\r
89     sfree(pf->buffer);\r
90     sfree(pf);\r
91 }\r
93 static struct PortListener *new_portlistener_state(void)\r
94 {\r
95     struct PortListener *pl = snew(struct PortListener);\r
96     pl->hostname = NULL;\r
97     return pl;\r
98 }\r
100 static void free_portlistener_state(struct PortListener *pl)\r
102     if (!pl)\r
103         return;\r
104     sfree(pl->hostname);\r
105     sfree(pl);\r
108 static void pfd_log(Plug plug, int type, SockAddr addr, int port,\r
109                     const char *error_msg, int error_code)\r
111     /* we have to dump these since we have no interface to logging.c */\r
114 static void pfl_log(Plug plug, int type, SockAddr addr, int port,\r
115                     const char *error_msg, int error_code)\r
117     /* we have to dump these since we have no interface to logging.c */\r
120 static int pfd_closing(Plug plug, const char *error_msg, int error_code,\r
121                        int calling_back)\r
123     struct PortForwarding *pf = (struct PortForwarding *) plug;\r
125     if (error_msg) {\r
126         /*\r
127          * Socket error. Slam the connection instantly shut.\r
128          */\r
129         if (pf->c) {\r
130             sshfwd_unclean_close(pf->c, error_msg);\r
131         } else {\r
132             /*\r
133              * We might not have an SSH channel, if a socket error\r
134              * occurred during SOCKS negotiation. If not, we must\r
135              * clean ourself up without sshfwd_unclean_close's call\r
136              * back to pfd_close.\r
137              */\r
138             pfd_close(pf);\r
139         }\r
140     } else {\r
141         /*\r
142          * Ordinary EOF received on socket. Send an EOF on the SSH\r
143          * channel.\r
144          */\r
145         if (pf->c)\r
146             sshfwd_write_eof(pf->c);\r
147     }\r
149     return 1;\r
152 static int pfl_closing(Plug plug, const char *error_msg, int error_code,\r
153                        int calling_back)\r
155     struct PortListener *pl = (struct PortListener *) plug;\r
156     pfl_terminate(pl);\r
157     return 1;\r
160 static int pfd_receive(Plug plug, int urgent, char *data, int len)\r
162     struct PortForwarding *pf = (struct PortForwarding *) plug;\r
163     if (pf->dynamic) {\r
164         while (len--) {\r
165             if (pf->sockslen >= pf->sockssize) {\r
166                 pf->sockssize = pf->sockslen * 5 / 4 + 256;\r
167                 pf->socksbuf = sresize(pf->socksbuf, pf->sockssize, char);\r
168             }\r
169             pf->socksbuf[pf->sockslen++] = *data++;\r
171             /*\r
172              * Now check what's in the buffer to see if it's a\r
173              * valid and complete message in the SOCKS exchange.\r
174              */\r
175             if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 4) &&\r
176                 pf->socksbuf[0] == 4) {\r
177                 /*\r
178                  * SOCKS 4.\r
179                  */\r
180                 if (pf->dynamic == 1)\r
181                     pf->dynamic = 0x4000;\r
182                 if (pf->sockslen < 2)\r
183                     continue;        /* don't have command code yet */\r
184                 if (pf->socksbuf[1] != 1) {\r
185                     /* Not CONNECT. */\r
186                     /* Send back a SOCKS 4 error before closing. */\r
187                     char data[8];\r
188                     memset(data, 0, sizeof(data));\r
189                     data[1] = 91;      /* generic `request rejected' */\r
190                     sk_write(pf->s, data, 8);\r
191                     pfd_close(pf);\r
192                     return 1;\r
193                 }\r
194                 if (pf->sockslen <= 8)\r
195                     continue;      /* haven't started user/hostname */\r
196                 if (pf->socksbuf[pf->sockslen-1] != 0)\r
197                     continue;          /* haven't _finished_ user/hostname */\r
198                 /*\r
199                  * Now we have a full SOCKS 4 request. Check it to\r
200                  * see if it's a SOCKS 4A request.\r
201                  */\r
202                 if (pf->socksbuf[4] == 0 && pf->socksbuf[5] == 0 &&\r
203                     pf->socksbuf[6] == 0 && pf->socksbuf[7] != 0) {\r
204                     /*\r
205                      * It's SOCKS 4A. So if we haven't yet\r
206                      * collected the host name, we should continue\r
207                      * waiting for data in order to do so; if we\r
208                      * have, we can go ahead.\r
209                      */\r
210                     int len;\r
211                     if (pf->dynamic == 0x4000) {\r
212                         pf->dynamic = 0x4001;\r
213                         pf->sockslen = 8; /* reset buffer to overwrite name */\r
214                         continue;\r
215                     }\r
216                     pf->socksbuf[0] = 0;   /* reply version code */\r
217                     pf->socksbuf[1] = 90;   /* request granted */\r
218                     sk_write(pf->s, pf->socksbuf, 8);\r
219                     len = pf->sockslen - 8;\r
220                     pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2);\r
221                     pf->hostname = snewn(len+1, char);\r
222                     pf->hostname[len] = '\0';\r
223                     memcpy(pf->hostname, pf->socksbuf + 8, len);\r
224                     goto connect;\r
225                 } else {\r
226                     /*\r
227                      * It's SOCKS 4, which means we should format\r
228                      * the IP address into the hostname string and\r
229                      * then just go.\r
230                      */\r
231                     pf->socksbuf[0] = 0;   /* reply version code */\r
232                     pf->socksbuf[1] = 90;   /* request granted */\r
233                     sk_write(pf->s, pf->socksbuf, 8);\r
234                     pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2);\r
235                     pf->hostname = dupprintf("%d.%d.%d.%d",\r
236                                              (unsigned char)pf->socksbuf[4],\r
237                                              (unsigned char)pf->socksbuf[5],\r
238                                              (unsigned char)pf->socksbuf[6],\r
239                                              (unsigned char)pf->socksbuf[7]);\r
240                     goto connect;\r
241                 }\r
242             }\r
244             if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 5) &&\r
245                 pf->socksbuf[0] == 5) {\r
246                 /*\r
247                  * SOCKS 5.\r
248                  */\r
249                 if (pf->dynamic == 1)\r
250                     pf->dynamic = 0x5000;\r
252                 if (pf->dynamic == 0x5000) {\r
253                     int i, method;\r
254                     char data[2];\r
255                     /*\r
256                      * We're receiving a set of method identifiers.\r
257                      */\r
258                     if (pf->sockslen < 2)\r
259                         continue;      /* no method count yet */\r
260                     if (pf->sockslen < 2 + (unsigned char)pf->socksbuf[1])\r
261                         continue;      /* no methods yet */\r
262                     method = 0xFF;     /* invalid */\r
263                     for (i = 0; i < (unsigned char)pf->socksbuf[1]; i++)\r
264                         if (pf->socksbuf[2+i] == 0) {\r
265                             method = 0;/* no auth */\r
266                             break;\r
267                         }\r
268                     data[0] = 5;\r
269                     data[1] = method;\r
270                     sk_write(pf->s, data, 2);\r
271                     pf->dynamic = 0x5001;\r
272                     pf->sockslen = 0;      /* re-empty the buffer */\r
273                     continue;\r
274                 }\r
276                 if (pf->dynamic == 0x5001) {\r
277                     /*\r
278                      * We're receiving a SOCKS request.\r
279                      */\r
280                     unsigned char reply[10]; /* SOCKS5 atyp=1 reply */\r
281                     int atype, alen = 0;\r
283                     /*\r
284                      * Pre-fill reply packet.\r
285                      * In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0\r
286                      * (atyp=1) in the reply; if we succeed, we don't know\r
287                      * the right answers, and if we fail, they should be\r
288                      * ignored.\r
289                      */\r
290                     memset(reply, 0, lenof(reply));\r
291                     reply[0] = 5; /* VER */\r
292                     reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */\r
294                     if (pf->sockslen < 6) continue;\r
295                     atype = (unsigned char)pf->socksbuf[3];\r
296                     if (atype == 1)    /* IPv4 address */\r
297                         alen = 4;\r
298                     if (atype == 4)    /* IPv6 address */\r
299                         alen = 16;\r
300                     if (atype == 3)    /* domain name has leading length */\r
301                         alen = 1 + (unsigned char)pf->socksbuf[4];\r
302                     if (pf->sockslen < 6 + alen) continue;\r
303                     if (pf->socksbuf[1] != 1 || pf->socksbuf[2] != 0) {\r
304                         /* Not CONNECT or reserved field nonzero - error */\r
305                         reply[1] = 1;   /* generic failure */\r
306                         sk_write(pf->s, (char *) reply, lenof(reply));\r
307                         pfd_close(pf);\r
308                         return 1;\r
309                     }\r
310                     /*\r
311                      * Now we have a viable connect request. Switch\r
312                      * on atype.\r
313                      */\r
314                     pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+4+alen);\r
315                     if (atype == 1) {\r
316                         /* REP=0 (success) already */\r
317                         sk_write(pf->s, (char *) reply, lenof(reply));\r
318                         pf->hostname = dupprintf("%d.%d.%d.%d",\r
319                                                  (unsigned char)pf->socksbuf[4],\r
320                                                  (unsigned char)pf->socksbuf[5],\r
321                                                  (unsigned char)pf->socksbuf[6],\r
322                                                  (unsigned char)pf->socksbuf[7]);\r
323                         goto connect;\r
324                     } else if (atype == 3) {\r
325                         /* REP=0 (success) already */\r
326                         sk_write(pf->s, (char *) reply, lenof(reply));\r
327                         pf->hostname = snewn(alen, char);\r
328                         pf->hostname[alen-1] = '\0';\r
329                         memcpy(pf->hostname, pf->socksbuf + 5, alen-1);\r
330                         goto connect;\r
331                     } else {\r
332                         /*\r
333                          * Unknown address type. (FIXME: support IPv6!)\r
334                          */\r
335                         reply[1] = 8;   /* atype not supported */\r
336                         sk_write(pf->s, (char *) reply, lenof(reply));\r
337                         pfd_close(pf);\r
338                         return 1;\r
339                     }\r
340                 }\r
341             }\r
343             /*\r
344              * If we get here without either having done `continue'\r
345              * or `goto connect', it must be because there is no\r
346              * sensible interpretation of what's in our buffer. So\r
347              * close the connection rudely.\r
348              */\r
349             pfd_close(pf);\r
350             return 1;\r
351         }\r
352         return 1;\r
354         /*\r
355          * We come here when we're ready to make an actual\r
356          * connection.\r
357          */\r
358         connect:\r
359         sfree(pf->socksbuf);\r
360         pf->socksbuf = NULL;\r
362         /*\r
363          * Freeze the socket until the SSH server confirms the\r
364          * connection.\r
365          */\r
366         sk_set_frozen(pf->s, 1);\r
368         pf->c = new_sock_channel(pf->backhandle, pf);\r
369         if (pf->c == NULL) {\r
370             pfd_close(pf);\r
371             return 1;\r
372         } else {\r
373             /* asks to forward to the specified host/port for this */\r
374             ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding");\r
375         }\r
376         pf->dynamic = 0;\r
378         /*\r
379          * If there's any data remaining in our current buffer,\r
380          * save it to be sent on pfd_confirm().\r
381          */\r
382         if (len > 0) {\r
383             pf->buffer = snewn(len, char);\r
384             memcpy(pf->buffer, data, len);\r
385             pf->buflen = len;\r
386         }\r
387     }\r
388     if (pf->ready) {\r
389         if (sshfwd_write(pf->c, data, len) > 0) {\r
390             pf->throttled = 1;\r
391             sk_set_frozen(pf->s, 1);\r
392         }\r
393     }\r
394     return 1;\r
397 static void pfd_sent(Plug plug, int bufsize)\r
399     struct PortForwarding *pf = (struct PortForwarding *) plug;\r
401     if (pf->c)\r
402         sshfwd_unthrottle(pf->c, bufsize);\r
405 /*\r
406  * Called when receiving a PORT OPEN from the server to make a\r
407  * connection to a destination host.\r
408  *\r
409  * On success, returns NULL and fills in *pf_ret. On error, returns a\r
410  * dynamically allocated error message string.\r
411  */\r
412 char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,\r
413                   void *c, Conf *conf, int addressfamily)\r
415     static const struct plug_function_table fn_table = {\r
416         pfd_log,\r
417         pfd_closing,\r
418         pfd_receive,\r
419         pfd_sent,\r
420         NULL\r
421     };\r
423     SockAddr addr;\r
424     const char *err;\r
425     char *dummy_realhost;\r
426     struct PortForwarding *pf;\r
428     /*\r
429      * Try to find host.\r
430      */\r
431     addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily);\r
432     if ((err = sk_addr_error(addr)) != NULL) {\r
433         char *err_ret = dupstr(err);\r
434         sk_addr_free(addr);\r
435         sfree(dummy_realhost);\r
436         return err_ret;\r
437     }\r
439     /*\r
440      * Open socket.\r
441      */\r
442     pf = *pf_ret = new_portfwd_state();\r
443     pf->fn = &fn_table;\r
444     pf->throttled = pf->throttle_override = 0;\r
445     pf->ready = 1;\r
446     pf->c = c;\r
447     pf->backhandle = NULL;             /* we shouldn't need this */\r
448     pf->dynamic = 0;\r
450     pf->s = new_connection(addr, dummy_realhost, port,\r
451                            0, 1, 0, 0, (Plug) pf, conf);\r
452     sfree(dummy_realhost);\r
453     if ((err = sk_socket_error(pf->s)) != NULL) {\r
454         char *err_ret = dupstr(err);\r
455         sk_close(pf->s);\r
456         free_portfwd_state(pf);\r
457         *pf_ret = NULL;\r
458         return err_ret;\r
459     }\r
461     return NULL;\r
464 /*\r
465  called when someone connects to the local port\r
466  */\r
468 static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)\r
470     static const struct plug_function_table fn_table = {\r
471         pfd_log,\r
472         pfd_closing,\r
473         pfd_receive,\r
474         pfd_sent,\r
475         NULL\r
476     };\r
477     struct PortForwarding *pf;\r
478     struct PortListener *pl;\r
479     Socket s;\r
480     const char *err;\r
482     pl = (struct PortListener *)p;\r
483     pf = new_portfwd_state();\r
484     pf->fn = &fn_table;\r
486     pf->c = NULL;\r
487     pf->backhandle = pl->backhandle;\r
489     pf->s = s = constructor(ctx, (Plug) pf);\r
490     if ((err = sk_socket_error(s)) != NULL) {\r
491         free_portfwd_state(pf);\r
492         return err != NULL;\r
493     }\r
495     pf->throttled = pf->throttle_override = 0;\r
496     pf->ready = 0;\r
498     if (pl->dynamic) {\r
499         pf->dynamic = 1;\r
500         pf->port = 0;                  /* "hostname" buffer is so far empty */\r
501         sk_set_frozen(s, 0);           /* we want to receive SOCKS _now_! */\r
502     } else {\r
503         pf->dynamic = 0;\r
504         pf->hostname = dupstr(pl->hostname);\r
505         pf->port = pl->port;    \r
506         pf->c = new_sock_channel(pl->backhandle, pf);\r
508         if (pf->c == NULL) {\r
509             free_portfwd_state(pf);\r
510             return 1;\r
511         } else {\r
512             /* asks to forward to the specified host/port for this */\r
513             ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding");\r
514         }\r
515     }\r
517     return 0;\r
521 /*\r
522  * Add a new port-forwarding listener from srcaddr:port -> desthost:destport.\r
523  *\r
524  * On success, returns NULL and fills in *pl_ret. On error, returns a\r
525  * dynamically allocated error message string.\r
526  */\r
527 char *pfl_listen(char *desthost, int destport, char *srcaddr,\r
528                  int port, void *backhandle, Conf *conf,\r
529                  struct PortListener **pl_ret, int address_family)\r
531     static const struct plug_function_table fn_table = {\r
532         pfl_log,\r
533         pfl_closing,\r
534         NULL,                          /* recv */\r
535         NULL,                          /* send */\r
536         pfl_accepting\r
537     };\r
539     const char *err;\r
540     struct PortListener *pl;\r
542     /*\r
543      * Open socket.\r
544      */\r
545     pl = *pl_ret = new_portlistener_state();\r
546     pl->fn = &fn_table;\r
547     if (desthost) {\r
548         pl->hostname = dupstr(desthost);\r
549         pl->port = destport;\r
550         pl->dynamic = 0;\r
551     } else\r
552         pl->dynamic = 1;\r
553     pl->backhandle = backhandle;\r
555     pl->s = new_listener(srcaddr, port, (Plug) pl,\r
556                          !conf_get_int(conf, CONF_lport_acceptall),\r
557                          conf, address_family);\r
558     if ((err = sk_socket_error(pl->s)) != NULL) {\r
559         char *err_ret = dupstr(err);\r
560         sk_close(pl->s);\r
561         free_portlistener_state(pl);\r
562         *pl_ret = NULL;\r
563         return err_ret;\r
564     }\r
566     return NULL;\r
569 void pfd_close(struct PortForwarding *pf)\r
571     if (!pf)\r
572         return;\r
574     sk_close(pf->s);\r
575     free_portfwd_state(pf);\r
578 /*\r
579  * Terminate a listener.\r
580  */\r
581 void pfl_terminate(struct PortListener *pl)\r
583     if (!pl)\r
584         return;\r
586     sk_close(pl->s);\r
587     free_portlistener_state(pl);\r
590 void pfd_unthrottle(struct PortForwarding *pf)\r
592     if (!pf)\r
593         return;\r
595     pf->throttled = 0;\r
596     sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);\r
599 void pfd_override_throttle(struct PortForwarding *pf, int enable)\r
601     if (!pf)\r
602         return;\r
604     pf->throttle_override = enable;\r
605     sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);\r
608 /*\r
609  * Called to send data down the raw connection.\r
610  */\r
611 int pfd_send(struct PortForwarding *pf, char *data, int len)\r
613     if (pf == NULL)\r
614         return 0;\r
615     return sk_write(pf->s, data, len);\r
618 void pfd_send_eof(struct PortForwarding *pf)\r
620     sk_write_eof(pf->s);\r
623 void pfd_confirm(struct PortForwarding *pf)\r
625     if (pf == NULL)\r
626         return;\r
628     pf->ready = 1;\r
629     sk_set_frozen(pf->s, 0);\r
630     sk_write(pf->s, NULL, 0);\r
631     if (pf->buffer) {\r
632         sshfwd_write(pf->c, pf->buffer, pf->buflen);\r
633         sfree(pf->buffer);\r
634         pf->buffer = NULL;\r
635     }\r