From 83439617051112744e4b5797927d7b5ce786f899 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Oct 2018 22:47:49 +0100 Subject: [PATCH] Server prep: factor out portfwd_raw_new(). This new function contains the core setup for a PortForwarding structure, and should be reusable for any kind of forwarding that will simply be passing data between a local socket and an SSH channel without any tricky modifications. On the server side, X11 and agent forwarding both work exactly like this, so they will find this refactored function useful during setup. The contents of the function was originally part of pfl_accepting, which now does all that by calling the new function. pfl_accepting is not _quite_ doing a simple unmodified forwarding, because it might have to prefix it with a SOCKS exchange; in that situation it rewrites a few fields of the PortForwarding to some less generic values once portfwd_raw_new() has returned. --- portfwd.c | 73 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/portfwd.c b/portfwd.c index 99076b99..87c6dae3 100644 --- a/portfwd.c +++ b/portfwd.c @@ -467,18 +467,10 @@ static const struct ChannelVtable PortForwarding_channelvt = { chan_no_request_response, }; -/* - called when someone connects to the local port - */ - -static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) +Channel *portfwd_raw_new(ConnectionLayer *cl, Plug **plug) { struct PortForwarding *pf; - struct PortListener *pl; - Socket *s; - const char *err; - pl = container_of(p, struct PortListener, plug); pf = new_portfwd_state(); pf->plug.vt = &PortForwarding_plugvt; pf->chan.initial_fixed_window_size = 0; @@ -486,29 +478,72 @@ static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) pf->input_wanted = TRUE; pf->c = NULL; - pf->cl = pl->cl; - - pf->s = s = constructor(ctx, &pf->plug); - if ((err = sk_socket_error(s)) != NULL) { - free_portfwd_state(pf); - return err != NULL; - } + pf->cl = cl; pf->input_wanted = TRUE; pf->ready = 0; + pf->socks_state = SOCKS_NONE; + pf->hostname = NULL; + pf->port = 0; + + *plug = &pf->plug; + return &pf->chan; +} + +void portfwd_raw_free(Channel *pfchan) +{ + struct PortForwarding *pf; + assert(pfchan->vt == &PortForwarding_channelvt); + pf = container_of(pfchan, struct PortForwarding, chan); + free_portfwd_state(pf); +} + +void portfwd_raw_setup(Channel *pfchan, Socket *s, SshChannel *sc) +{ + struct PortForwarding *pf; + assert(pfchan->vt == &PortForwarding_channelvt); + pf = container_of(pfchan, struct PortForwarding, chan); + + pf->s = s; + pf->c = sc; +} + +/* + called when someone connects to the local port + */ + +static int pfl_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) +{ + struct PortListener *pl = container_of(p, struct PortListener, plug); + struct PortForwarding *pf; + Channel *chan; + Plug *plug; + Socket *s; + const char *err; + + chan = portfwd_raw_new(pl->cl, &plug); + s = constructor(ctx, plug); + if ((err = sk_socket_error(s)) != NULL) { + portfwd_raw_free(chan); + return TRUE; + } + + pf = container_of(chan, struct PortForwarding, chan); + if (pl->is_dynamic) { + pf->s = s; pf->socks_state = SOCKS_INITIAL; pf->socksbuf = strbuf_new(); pf->socksbuf_consumed = 0; pf->port = 0; /* "hostname" buffer is so far empty */ sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */ } else { - pf->socks_state = SOCKS_NONE; pf->hostname = dupstr(pl->hostname); pf->port = pl->port; - pf->c = wrap_lportfwd_open(pl->cl, pf->hostname, pf->port, - s, &pf->chan); + portfwd_raw_setup( + chan, s, + wrap_lportfwd_open(pl->cl, pf->hostname, pf->port, s, &pf->chan)); } return 0;