source: filezilla/trunk/fuentes/src/putty/portfwd.c @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 3 years ago

Update new version: 3.15.02

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