зеркало из https://github.com/github/putty.git
Move port-forwarding setup out of ssh.c.
The tree234 storing currently active port forwardings - both local and remote - now lives in portfwd.c, as does the complicated function that updates it based on a Conf listing the new set of desired forwardings. Local port forwardings are passed to ssh.c via the same route as before - once the listening port receives a connection and portfwd.c knows where it should be directed to (in particular, after the SOCKS exchange, if any), it calls ssh_send_port_open. Remote forwardings are now initiated by calling ssh_rportfwd_alloc, which adds an entry to the rportfwds tree (which _is_ still in ssh.c, and still confusingly sorted by a different criterion depending on SSH protocol version) and sends out the appropriate protocol request. ssh_rportfwd_remove cancels one again, sending a protocol request too. Those functions look enough like ssh_{alloc,remove}_sharing_rportfwd that I've merged those into the new pair as well - now allocating an rportfwd allows you to specify either a destination host/port or a sharing context, and returns a handy pointer you can use to cancel the forwarding later.
This commit is contained in:
Родитель
aa08e6ca91
Коммит
895b09a4c6
3
defs.h
3
defs.h
|
@ -60,6 +60,9 @@ typedef struct ssh_sharing_state ssh_sharing_state;
|
||||||
typedef struct ssh_sharing_connstate ssh_sharing_connstate;
|
typedef struct ssh_sharing_connstate ssh_sharing_connstate;
|
||||||
typedef struct share_channel share_channel;
|
typedef struct share_channel share_channel;
|
||||||
|
|
||||||
|
typedef struct PortFwdManager PortFwdManager;
|
||||||
|
typedef struct PortFwdRecord PortFwdRecord;
|
||||||
|
|
||||||
typedef struct dlgparam dlgparam;
|
typedef struct dlgparam dlgparam;
|
||||||
|
|
||||||
typedef struct settings_w settings_w;
|
typedef struct settings_w settings_w;
|
||||||
|
|
11
misc.c
11
misc.c
|
@ -1181,6 +1181,17 @@ int smemeq(const void *av, const void *bv, size_t len)
|
||||||
return (0x100 - val) >> 8;
|
return (0x100 - val) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nullstrcmp(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
if (a == NULL && b == NULL)
|
||||||
|
return 0;
|
||||||
|
if (a == NULL)
|
||||||
|
return -1;
|
||||||
|
if (b == NULL)
|
||||||
|
return +1;
|
||||||
|
return strcmp(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
ptrlen make_ptrlen(const void *ptr, size_t len)
|
ptrlen make_ptrlen(const void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
ptrlen pl;
|
ptrlen pl;
|
||||||
|
|
6
misc.h
6
misc.h
|
@ -87,6 +87,12 @@ int validate_manual_hostkey(char *key);
|
||||||
|
|
||||||
struct tm ltime(void);
|
struct tm ltime(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special form of strcmp which can cope with NULL inputs. NULL is
|
||||||
|
* defined to sort before even the empty string.
|
||||||
|
*/
|
||||||
|
int nullstrcmp(const char *a, const char *b);
|
||||||
|
|
||||||
ptrlen make_ptrlen(const void *ptr, size_t len);
|
ptrlen make_ptrlen(const void *ptr, size_t len);
|
||||||
int ptrlen_eq_string(ptrlen pl, const char *str);
|
int ptrlen_eq_string(ptrlen pl, const char *str);
|
||||||
char *mkstr(ptrlen pl);
|
char *mkstr(ptrlen pl);
|
||||||
|
|
503
portfwd.c
503
portfwd.c
|
@ -10,6 +10,18 @@
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "sshchan.h"
|
#include "sshchan.h"
|
||||||
|
|
||||||
|
static void logeventf(Frontend *frontend, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
buf = dupvprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
logevent(frontend, buf);
|
||||||
|
sfree(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumeration of values that live in the 'socks_state' field of
|
* Enumeration of values that live in the 'socks_state' field of
|
||||||
* struct PortForwarding.
|
* struct PortForwarding.
|
||||||
|
@ -139,6 +151,8 @@ static void pfd_closing(Plug plug, const char *error_msg, int error_code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pfl_terminate(struct PortListener *pl);
|
||||||
|
|
||||||
static void pfl_closing(Plug plug, const char *error_msg, int error_code,
|
static void pfl_closing(Plug plug, const char *error_msg, int error_code,
|
||||||
int calling_back)
|
int calling_back)
|
||||||
{
|
{
|
||||||
|
@ -447,61 +461,6 @@ static const struct ChannelVtable PortForwarding_channelvt = {
|
||||||
chan_no_eager_close,
|
chan_no_eager_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when receiving a PORT OPEN from the server to make a
|
|
||||||
* connection to a destination host.
|
|
||||||
*
|
|
||||||
* On success, returns NULL and fills in *pf_ret. On error, returns a
|
|
||||||
* dynamically allocated error message string.
|
|
||||||
*/
|
|
||||||
char *pfd_connect(Channel **chan_ret, char *hostname,int port,
|
|
||||||
SshChannel *c, Conf *conf, int addressfamily)
|
|
||||||
{
|
|
||||||
SockAddr addr;
|
|
||||||
const char *err;
|
|
||||||
char *dummy_realhost = NULL;
|
|
||||||
struct PortForwarding *pf;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to find host.
|
|
||||||
*/
|
|
||||||
addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily,
|
|
||||||
NULL, NULL);
|
|
||||||
if ((err = sk_addr_error(addr)) != NULL) {
|
|
||||||
char *err_ret = dupstr(err);
|
|
||||||
sk_addr_free(addr);
|
|
||||||
sfree(dummy_realhost);
|
|
||||||
return err_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open socket.
|
|
||||||
*/
|
|
||||||
pf = new_portfwd_state();
|
|
||||||
*chan_ret = &pf->chan;
|
|
||||||
pf->plugvt = &PortForwarding_plugvt;
|
|
||||||
pf->chan.initial_fixed_window_size = 0;
|
|
||||||
pf->chan.vt = &PortForwarding_channelvt;
|
|
||||||
pf->input_wanted = TRUE;
|
|
||||||
pf->ready = 1;
|
|
||||||
pf->c = c;
|
|
||||||
pf->ssh = NULL; /* we shouldn't need this */
|
|
||||||
pf->socks_state = SOCKS_NONE;
|
|
||||||
|
|
||||||
pf->s = new_connection(addr, dummy_realhost, port,
|
|
||||||
0, 1, 0, 0, &pf->plugvt, conf);
|
|
||||||
sfree(dummy_realhost);
|
|
||||||
if ((err = sk_socket_error(pf->s)) != NULL) {
|
|
||||||
char *err_ret = dupstr(err);
|
|
||||||
sk_close(pf->s);
|
|
||||||
free_portfwd_state(pf);
|
|
||||||
*chan_ret = NULL;
|
|
||||||
return err_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
called when someone connects to the local port
|
called when someone connects to the local port
|
||||||
*/
|
*/
|
||||||
|
@ -560,10 +519,12 @@ static const Plug_vtable PortListener_plugvt = {
|
||||||
/*
|
/*
|
||||||
* Add a new port-forwarding listener from srcaddr:port -> desthost:destport.
|
* Add a new port-forwarding listener from srcaddr:port -> desthost:destport.
|
||||||
*
|
*
|
||||||
|
* desthost == NULL indicates dynamic SOCKS port forwarding.
|
||||||
|
*
|
||||||
* On success, returns NULL and fills in *pl_ret. On error, returns a
|
* On success, returns NULL and fills in *pl_ret. On error, returns a
|
||||||
* dynamically allocated error message string.
|
* dynamically allocated error message string.
|
||||||
*/
|
*/
|
||||||
char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
static char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
||||||
int port, Ssh ssh, Conf *conf,
|
int port, Ssh ssh, Conf *conf,
|
||||||
struct PortListener **pl_ret, int address_family)
|
struct PortListener **pl_ret, int address_family)
|
||||||
{
|
{
|
||||||
|
@ -614,7 +575,7 @@ static void pfd_close(struct PortForwarding *pf)
|
||||||
/*
|
/*
|
||||||
* Terminate a listener.
|
* Terminate a listener.
|
||||||
*/
|
*/
|
||||||
void pfl_terminate(struct PortListener *pl)
|
static void pfl_terminate(struct PortListener *pl)
|
||||||
{
|
{
|
||||||
if (!pl)
|
if (!pl)
|
||||||
return;
|
return;
|
||||||
|
@ -676,9 +637,431 @@ static void pfd_open_failure(Channel *chan, const char *errtext)
|
||||||
assert(chan->vt == &PortForwarding_channelvt);
|
assert(chan->vt == &PortForwarding_channelvt);
|
||||||
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
|
||||||
|
|
||||||
char *msg = dupprintf(
|
logeventf(ssh_get_frontend(pf->ssh),
|
||||||
"Forwarded connection refused by server%s%s",
|
"Forwarded connection refused by server%s%s",
|
||||||
errtext ? ": " : "", errtext ? errtext : "");
|
errtext ? ": " : "", errtext ? errtext : "");
|
||||||
logevent(ssh_get_frontend(pf->ssh), msg);
|
}
|
||||||
sfree(msg);
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
* Code to manage the complete set of currently active port
|
||||||
|
* forwardings, and update it from Conf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct PortFwdRecord {
|
||||||
|
enum { DESTROY, KEEP, CREATE } status;
|
||||||
|
int type;
|
||||||
|
unsigned sport, dport;
|
||||||
|
char *saddr, *daddr;
|
||||||
|
char *sserv, *dserv;
|
||||||
|
struct ssh_rportfwd *remote;
|
||||||
|
int addressfamily;
|
||||||
|
struct PortListener *local;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pfr_cmp(void *av, void *bv)
|
||||||
|
{
|
||||||
|
PortFwdRecord *a = (PortFwdRecord *) av;
|
||||||
|
PortFwdRecord *b = (PortFwdRecord *) bv;
|
||||||
|
int i;
|
||||||
|
if (a->type > b->type)
|
||||||
|
return +1;
|
||||||
|
if (a->type < b->type)
|
||||||
|
return -1;
|
||||||
|
if (a->addressfamily > b->addressfamily)
|
||||||
|
return +1;
|
||||||
|
if (a->addressfamily < b->addressfamily)
|
||||||
|
return -1;
|
||||||
|
if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)
|
||||||
|
return i < 0 ? -1 : +1;
|
||||||
|
if (a->sport > b->sport)
|
||||||
|
return +1;
|
||||||
|
if (a->sport < b->sport)
|
||||||
|
return -1;
|
||||||
|
if (a->type != 'D') {
|
||||||
|
if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)
|
||||||
|
return i < 0 ? -1 : +1;
|
||||||
|
if (a->dport > b->dport)
|
||||||
|
return +1;
|
||||||
|
if (a->dport < b->dport)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pfr_free(PortFwdRecord *pfr)
|
||||||
|
{
|
||||||
|
/* Dispose of any listening socket. */
|
||||||
|
if (pfr->local)
|
||||||
|
pfl_terminate(pfr->local);
|
||||||
|
|
||||||
|
sfree(pfr->saddr);
|
||||||
|
sfree(pfr->daddr);
|
||||||
|
sfree(pfr->sserv);
|
||||||
|
sfree(pfr->dserv);
|
||||||
|
sfree(pfr);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PortFwdManager {
|
||||||
|
Ssh ssh;
|
||||||
|
Frontend *frontend;
|
||||||
|
Conf *conf;
|
||||||
|
tree234 *forwardings;
|
||||||
|
};
|
||||||
|
|
||||||
|
PortFwdManager *portfwdmgr_new(Ssh ssh)
|
||||||
|
{
|
||||||
|
PortFwdManager *mgr = snew(PortFwdManager);
|
||||||
|
|
||||||
|
mgr->ssh = ssh;
|
||||||
|
mgr->frontend = ssh_get_frontend(ssh);
|
||||||
|
mgr->conf = NULL;
|
||||||
|
mgr->forwardings = newtree234(pfr_cmp);
|
||||||
|
|
||||||
|
return mgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr)
|
||||||
|
{
|
||||||
|
PortFwdRecord *realpfr = del234(mgr->forwardings, pfr);
|
||||||
|
if (realpfr == pfr)
|
||||||
|
pfr_free(pfr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void portfwdmgr_close_all(PortFwdManager *mgr)
|
||||||
|
{
|
||||||
|
PortFwdRecord *pfr;
|
||||||
|
|
||||||
|
while ((pfr = delpos234(mgr->forwardings, 0)) != NULL)
|
||||||
|
pfr_free(pfr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void portfwdmgr_free(PortFwdManager *mgr)
|
||||||
|
{
|
||||||
|
portfwdmgr_close_all(mgr);
|
||||||
|
freetree234(mgr->forwardings);
|
||||||
|
if (mgr->conf)
|
||||||
|
conf_free(mgr->conf);
|
||||||
|
sfree(mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
|
||||||
|
{
|
||||||
|
PortFwdRecord *pfr;
|
||||||
|
int i;
|
||||||
|
char *key, *val;
|
||||||
|
|
||||||
|
if (mgr->conf)
|
||||||
|
conf_free(mgr->conf);
|
||||||
|
mgr->conf = conf_copy(conf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go through the existing port forwardings and tag them
|
||||||
|
* with status==DESTROY. Any that we want to keep will be
|
||||||
|
* re-enabled (status==KEEP) as we go through the
|
||||||
|
* configuration and find out which bits are the same as
|
||||||
|
* they were before.
|
||||||
|
*/
|
||||||
|
for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++)
|
||||||
|
pfr->status = DESTROY;
|
||||||
|
|
||||||
|
for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
|
||||||
|
val != NULL;
|
||||||
|
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
|
||||||
|
char *kp, *kp2, *vp, *vp2;
|
||||||
|
char address_family, type;
|
||||||
|
int sport, dport, sserv, dserv;
|
||||||
|
char *sports, *dports, *saddr, *host;
|
||||||
|
|
||||||
|
kp = key;
|
||||||
|
|
||||||
|
address_family = 'A';
|
||||||
|
type = 'L';
|
||||||
|
if (*kp == 'A' || *kp == '4' || *kp == '6')
|
||||||
|
address_family = *kp++;
|
||||||
|
if (*kp == 'L' || *kp == 'R')
|
||||||
|
type = *kp++;
|
||||||
|
|
||||||
|
if ((kp2 = host_strchr(kp, ':')) != NULL) {
|
||||||
|
/*
|
||||||
|
* There's a colon in the middle of the source port
|
||||||
|
* string, which means that the part before it is
|
||||||
|
* actually a source address.
|
||||||
|
*/
|
||||||
|
char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp);
|
||||||
|
saddr = host_strduptrim(saddr_tmp);
|
||||||
|
sfree(saddr_tmp);
|
||||||
|
sports = kp2+1;
|
||||||
|
} else {
|
||||||
|
saddr = NULL;
|
||||||
|
sports = kp;
|
||||||
|
}
|
||||||
|
sport = atoi(sports);
|
||||||
|
sserv = 0;
|
||||||
|
if (sport == 0) {
|
||||||
|
sserv = 1;
|
||||||
|
sport = net_service_lookup(sports);
|
||||||
|
if (!sport) {
|
||||||
|
logeventf(mgr->frontend, "Service lookup failed for source"
|
||||||
|
" port \"%s\"", sports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == 'L' && !strcmp(val, "D")) {
|
||||||
|
/* dynamic forwarding */
|
||||||
|
host = NULL;
|
||||||
|
dports = NULL;
|
||||||
|
dport = -1;
|
||||||
|
dserv = 0;
|
||||||
|
type = 'D';
|
||||||
|
} else {
|
||||||
|
/* ordinary forwarding */
|
||||||
|
vp = val;
|
||||||
|
vp2 = vp + host_strcspn(vp, ":");
|
||||||
|
host = dupprintf("%.*s", (int)(vp2 - vp), vp);
|
||||||
|
if (*vp2)
|
||||||
|
vp2++;
|
||||||
|
dports = vp2;
|
||||||
|
dport = atoi(dports);
|
||||||
|
dserv = 0;
|
||||||
|
if (dport == 0) {
|
||||||
|
dserv = 1;
|
||||||
|
dport = net_service_lookup(dports);
|
||||||
|
if (!dport) {
|
||||||
|
logeventf(mgr->frontend,
|
||||||
|
"Service lookup failed for destination"
|
||||||
|
" port \"%s\"", dports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sport && dport) {
|
||||||
|
/* Set up a description of the source port. */
|
||||||
|
pfr = snew(PortFwdRecord);
|
||||||
|
pfr->type = type;
|
||||||
|
pfr->saddr = saddr;
|
||||||
|
pfr->sserv = sserv ? dupstr(sports) : NULL;
|
||||||
|
pfr->sport = sport;
|
||||||
|
pfr->daddr = host;
|
||||||
|
pfr->dserv = dserv ? dupstr(dports) : NULL;
|
||||||
|
pfr->dport = dport;
|
||||||
|
pfr->local = NULL;
|
||||||
|
pfr->remote = NULL;
|
||||||
|
pfr->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :
|
||||||
|
address_family == '6' ? ADDRTYPE_IPV6 :
|
||||||
|
ADDRTYPE_UNSPEC);
|
||||||
|
|
||||||
|
PortFwdRecord *existing = add234(mgr->forwardings, pfr);
|
||||||
|
if (existing != pfr) {
|
||||||
|
if (existing->status == DESTROY) {
|
||||||
|
/*
|
||||||
|
* We already have a port forwarding up and running
|
||||||
|
* with precisely these parameters. Hence, no need
|
||||||
|
* to do anything; simply re-tag the existing one
|
||||||
|
* as KEEP.
|
||||||
|
*/
|
||||||
|
existing->status = KEEP;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Anything else indicates that there was a duplicate
|
||||||
|
* in our input, which we'll silently ignore.
|
||||||
|
*/
|
||||||
|
pfr_free(pfr);
|
||||||
|
} else {
|
||||||
|
pfr->status = CREATE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sfree(saddr);
|
||||||
|
sfree(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now go through and destroy any port forwardings which were
|
||||||
|
* not re-enabled.
|
||||||
|
*/
|
||||||
|
for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) {
|
||||||
|
if (pfr->status == DESTROY) {
|
||||||
|
char *message;
|
||||||
|
|
||||||
|
message = dupprintf("%s port forwarding from %s%s%d",
|
||||||
|
pfr->type == 'L' ? "local" :
|
||||||
|
pfr->type == 'R' ? "remote" : "dynamic",
|
||||||
|
pfr->saddr ? pfr->saddr : "",
|
||||||
|
pfr->saddr ? ":" : "",
|
||||||
|
pfr->sport);
|
||||||
|
|
||||||
|
if (pfr->type != 'D') {
|
||||||
|
char *msg2 = dupprintf("%s to %s:%d", message,
|
||||||
|
pfr->daddr, pfr->dport);
|
||||||
|
sfree(message);
|
||||||
|
message = msg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
logeventf(mgr->frontend, "Cancelling %s", message);
|
||||||
|
sfree(message);
|
||||||
|
|
||||||
|
/* pfr->remote or pfr->local may be NULL if setting up a
|
||||||
|
* forwarding failed. */
|
||||||
|
if (pfr->remote) {
|
||||||
|
/*
|
||||||
|
* Cancel the port forwarding at the server
|
||||||
|
* end.
|
||||||
|
*
|
||||||
|
* Actually closing the listening port on the server
|
||||||
|
* side may fail - because in SSH-1 there's no message
|
||||||
|
* in the protocol to request it!
|
||||||
|
*
|
||||||
|
* Instead, we simply remove the record of the
|
||||||
|
* forwarding from our local end, so that any
|
||||||
|
* connections the server tries to make on it are
|
||||||
|
* rejected.
|
||||||
|
*/
|
||||||
|
ssh_rportfwd_remove(mgr->ssh, pfr->remote);
|
||||||
|
} else if (pfr->local) {
|
||||||
|
pfl_terminate(pfr->local);
|
||||||
|
}
|
||||||
|
|
||||||
|
delpos234(mgr->forwardings, i);
|
||||||
|
pfr_free(pfr);
|
||||||
|
i--; /* so we don't skip one in the list */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And finally, set up any new port forwardings (status==CREATE).
|
||||||
|
*/
|
||||||
|
for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) {
|
||||||
|
if (pfr->status == CREATE) {
|
||||||
|
char *sportdesc, *dportdesc;
|
||||||
|
sportdesc = dupprintf("%s%s%s%s%d%s",
|
||||||
|
pfr->saddr ? pfr->saddr : "",
|
||||||
|
pfr->saddr ? ":" : "",
|
||||||
|
pfr->sserv ? pfr->sserv : "",
|
||||||
|
pfr->sserv ? "(" : "",
|
||||||
|
pfr->sport,
|
||||||
|
pfr->sserv ? ")" : "");
|
||||||
|
if (pfr->type == 'D') {
|
||||||
|
dportdesc = NULL;
|
||||||
|
} else {
|
||||||
|
dportdesc = dupprintf("%s:%s%s%d%s",
|
||||||
|
pfr->daddr,
|
||||||
|
pfr->dserv ? pfr->dserv : "",
|
||||||
|
pfr->dserv ? "(" : "",
|
||||||
|
pfr->dport,
|
||||||
|
pfr->dserv ? ")" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfr->type == 'L') {
|
||||||
|
char *err = pfl_listen(pfr->daddr, pfr->dport,
|
||||||
|
pfr->saddr, pfr->sport,
|
||||||
|
mgr->ssh, conf, &pfr->local,
|
||||||
|
pfr->addressfamily);
|
||||||
|
|
||||||
|
logeventf(mgr->frontend,
|
||||||
|
"Local %sport %s forwarding to %s%s%s",
|
||||||
|
pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
|
||||||
|
pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
|
||||||
|
sportdesc, dportdesc,
|
||||||
|
err ? " failed: " : "", err ? err : "");
|
||||||
|
if (err)
|
||||||
|
sfree(err);
|
||||||
|
} else if (pfr->type == 'D') {
|
||||||
|
char *err = pfl_listen(NULL, -1, pfr->saddr, pfr->sport,
|
||||||
|
mgr->ssh, conf, &pfr->local,
|
||||||
|
pfr->addressfamily);
|
||||||
|
|
||||||
|
logeventf(mgr->frontend,
|
||||||
|
"Local %sport %s SOCKS dynamic forwarding%s%s",
|
||||||
|
pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
|
||||||
|
pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
|
||||||
|
sportdesc,
|
||||||
|
err ? " failed: " : "", err ? err : "");
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
sfree(err);
|
||||||
|
} else {
|
||||||
|
const char *shost;
|
||||||
|
|
||||||
|
if (pfr->saddr) {
|
||||||
|
shost = pfr->saddr;
|
||||||
|
} else if (conf_get_int(conf, CONF_rport_acceptall)) {
|
||||||
|
shost = "";
|
||||||
|
} else {
|
||||||
|
shost = "localhost";
|
||||||
|
}
|
||||||
|
|
||||||
|
pfr->remote = ssh_rportfwd_alloc(
|
||||||
|
mgr->ssh, shost, pfr->sport, pfr->daddr, pfr->dport,
|
||||||
|
pfr->addressfamily, sportdesc, pfr, NULL);
|
||||||
|
|
||||||
|
if (!pfr->remote) {
|
||||||
|
logeventf(mgr->frontend,
|
||||||
|
"Duplicate remote port forwarding to %s:%d",
|
||||||
|
pfr->daddr, pfr->dport);
|
||||||
|
pfr_free(pfr);
|
||||||
|
} else {
|
||||||
|
logeventf(mgr->frontend, "Requesting remote port %s"
|
||||||
|
" forward to %s", sportdesc, dportdesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfree(sportdesc);
|
||||||
|
sfree(dportdesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when receiving a PORT OPEN from the server to make a
|
||||||
|
* connection to a destination host.
|
||||||
|
*
|
||||||
|
* On success, returns NULL and fills in *pf_ret. On error, returns a
|
||||||
|
* dynamically allocated error message string.
|
||||||
|
*/
|
||||||
|
char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
|
||||||
|
char *hostname, int port, SshChannel *c,
|
||||||
|
int addressfamily)
|
||||||
|
{
|
||||||
|
SockAddr addr;
|
||||||
|
const char *err;
|
||||||
|
char *dummy_realhost = NULL;
|
||||||
|
struct PortForwarding *pf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to find host.
|
||||||
|
*/
|
||||||
|
addr = name_lookup(hostname, port, &dummy_realhost, mgr->conf,
|
||||||
|
addressfamily, NULL, NULL);
|
||||||
|
if ((err = sk_addr_error(addr)) != NULL) {
|
||||||
|
char *err_ret = dupstr(err);
|
||||||
|
sk_addr_free(addr);
|
||||||
|
sfree(dummy_realhost);
|
||||||
|
return err_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open socket.
|
||||||
|
*/
|
||||||
|
pf = new_portfwd_state();
|
||||||
|
*chan_ret = &pf->chan;
|
||||||
|
pf->plugvt = &PortForwarding_plugvt;
|
||||||
|
pf->chan.initial_fixed_window_size = 0;
|
||||||
|
pf->chan.vt = &PortForwarding_channelvt;
|
||||||
|
pf->input_wanted = TRUE;
|
||||||
|
pf->ready = 1;
|
||||||
|
pf->c = c;
|
||||||
|
pf->ssh = mgr->ssh;
|
||||||
|
pf->socks_state = SOCKS_NONE;
|
||||||
|
|
||||||
|
pf->s = new_connection(addr, dummy_realhost, port,
|
||||||
|
0, 1, 0, 0, &pf->plugvt, mgr->conf);
|
||||||
|
sfree(dummy_realhost);
|
||||||
|
if ((err = sk_socket_error(pf->s)) != NULL) {
|
||||||
|
char *err_ret = dupstr(err);
|
||||||
|
sk_close(pf->s);
|
||||||
|
free_portfwd_state(pf);
|
||||||
|
*chan_ret = NULL;
|
||||||
|
return err_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
552
ssh.c
552
ssh.c
|
@ -527,42 +527,22 @@ struct ssh_portfwd; /* forward declaration */
|
||||||
struct ssh_rportfwd {
|
struct ssh_rportfwd {
|
||||||
unsigned sport, dport;
|
unsigned sport, dport;
|
||||||
char *shost, *dhost;
|
char *shost, *dhost;
|
||||||
char *sportdesc;
|
int addressfamily;
|
||||||
|
char *log_description; /* name of remote listening port, for logging */
|
||||||
ssh_sharing_connstate *share_ctx;
|
ssh_sharing_connstate *share_ctx;
|
||||||
struct ssh_portfwd *pfrec;
|
PortFwdRecord *pfr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_rportfwd(struct ssh_rportfwd *pf)
|
static void free_rportfwd(struct ssh_rportfwd *pf)
|
||||||
{
|
{
|
||||||
if (pf) {
|
if (pf) {
|
||||||
sfree(pf->sportdesc);
|
sfree(pf->log_description);
|
||||||
sfree(pf->shost);
|
sfree(pf->shost);
|
||||||
sfree(pf->dhost);
|
sfree(pf->dhost);
|
||||||
sfree(pf);
|
sfree(pf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Separately to the rportfwd tree (which is for looking up port
|
|
||||||
* open requests from the server), a tree of _these_ structures is
|
|
||||||
* used to keep track of all the currently open port forwardings,
|
|
||||||
* so that we can reconfigure in mid-session if the user requests
|
|
||||||
* it.
|
|
||||||
*/
|
|
||||||
struct ssh_portfwd {
|
|
||||||
enum { DESTROY, KEEP, CREATE } status;
|
|
||||||
int type;
|
|
||||||
unsigned sport, dport;
|
|
||||||
char *saddr, *daddr;
|
|
||||||
char *sserv, *dserv;
|
|
||||||
struct ssh_rportfwd *remote;
|
|
||||||
int addressfamily;
|
|
||||||
struct PortListener *local;
|
|
||||||
};
|
|
||||||
#define free_portfwd(pf) ( \
|
|
||||||
((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \
|
|
||||||
sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )
|
|
||||||
|
|
||||||
static void ssh1_protocol_setup(Ssh ssh);
|
static void ssh1_protocol_setup(Ssh ssh);
|
||||||
static void ssh2_protocol_setup(Ssh ssh);
|
static void ssh2_protocol_setup(Ssh ssh);
|
||||||
static void ssh2_bare_connection_protocol_setup(Ssh ssh);
|
static void ssh2_bare_connection_protocol_setup(Ssh ssh);
|
||||||
|
@ -746,7 +726,8 @@ struct ssh_tag {
|
||||||
int clean_exit;
|
int clean_exit;
|
||||||
int disconnect_message_seen;
|
int disconnect_message_seen;
|
||||||
|
|
||||||
tree234 *rportfwds, *portfwds;
|
tree234 *rportfwds;
|
||||||
|
PortFwdManager *portfwdmgr;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SSH_STATE_PREPACKET,
|
SSH_STATE_PREPACKET,
|
||||||
|
@ -1063,51 +1044,6 @@ static int ssh_rportcmp_ssh2(void *av, void *bv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Special form of strcmp which can cope with NULL inputs. NULL is
|
|
||||||
* defined to sort before even the empty string.
|
|
||||||
*/
|
|
||||||
static int nullstrcmp(const char *a, const char *b)
|
|
||||||
{
|
|
||||||
if (a == NULL && b == NULL)
|
|
||||||
return 0;
|
|
||||||
if (a == NULL)
|
|
||||||
return -1;
|
|
||||||
if (b == NULL)
|
|
||||||
return +1;
|
|
||||||
return strcmp(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ssh_portcmp(void *av, void *bv)
|
|
||||||
{
|
|
||||||
struct ssh_portfwd *a = (struct ssh_portfwd *) av;
|
|
||||||
struct ssh_portfwd *b = (struct ssh_portfwd *) bv;
|
|
||||||
int i;
|
|
||||||
if (a->type > b->type)
|
|
||||||
return +1;
|
|
||||||
if (a->type < b->type)
|
|
||||||
return -1;
|
|
||||||
if (a->addressfamily > b->addressfamily)
|
|
||||||
return +1;
|
|
||||||
if (a->addressfamily < b->addressfamily)
|
|
||||||
return -1;
|
|
||||||
if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)
|
|
||||||
return i < 0 ? -1 : +1;
|
|
||||||
if (a->sport > b->sport)
|
|
||||||
return +1;
|
|
||||||
if (a->sport < b->sport)
|
|
||||||
return -1;
|
|
||||||
if (a->type != 'D') {
|
|
||||||
if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)
|
|
||||||
return i < 0 ? -1 : +1;
|
|
||||||
if (a->dport > b->dport)
|
|
||||||
return +1;
|
|
||||||
if (a->dport < b->dport)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int alloc_channel_id(Ssh ssh)
|
static int alloc_channel_id(Ssh ssh)
|
||||||
{
|
{
|
||||||
const unsigned CHANNEL_NUMBER_OFFSET = 256;
|
const unsigned CHANNEL_NUMBER_OFFSET = 256;
|
||||||
|
@ -2230,18 +2166,7 @@ static int ssh_do_close(Ssh ssh, int notify_exit)
|
||||||
* Go through port-forwardings, and close any associated
|
* Go through port-forwardings, and close any associated
|
||||||
* listening sockets.
|
* listening sockets.
|
||||||
*/
|
*/
|
||||||
if (ssh->portfwds) {
|
portfwdmgr_close_all(ssh->portfwdmgr);
|
||||||
struct ssh_portfwd *pf;
|
|
||||||
while (NULL != (pf = index234(ssh->portfwds, 0))) {
|
|
||||||
/* Dispose of any listening socket. */
|
|
||||||
if (pf->local)
|
|
||||||
pfl_terminate(pf->local);
|
|
||||||
del234(ssh->portfwds, pf); /* moving next one to index 0 */
|
|
||||||
free_portfwd(pf);
|
|
||||||
}
|
|
||||||
freetree234(ssh->portfwds);
|
|
||||||
ssh->portfwds = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Also stop attempting to connection-share.
|
* Also stop attempting to connection-share.
|
||||||
|
@ -3816,58 +3741,110 @@ static void ssh_queue_handler(Ssh ssh, int msg1, int msg2,
|
||||||
|
|
||||||
static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx)
|
static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx)
|
||||||
{
|
{
|
||||||
struct ssh_rportfwd *rpf, *pf = (struct ssh_rportfwd *)ctx;
|
struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx;
|
||||||
|
|
||||||
if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS :
|
if (pktin->type == (ssh->version == 1 ? SSH1_SMSG_SUCCESS :
|
||||||
SSH2_MSG_REQUEST_SUCCESS)) {
|
SSH2_MSG_REQUEST_SUCCESS)) {
|
||||||
logeventf(ssh, "Remote port forwarding from %s enabled",
|
logeventf(ssh, "Remote port forwarding from %s enabled",
|
||||||
pf->sportdesc);
|
rpf->log_description);
|
||||||
} else {
|
} else {
|
||||||
logeventf(ssh, "Remote port forwarding from %s refused",
|
logeventf(ssh, "Remote port forwarding from %s refused",
|
||||||
pf->sportdesc);
|
rpf->log_description);
|
||||||
|
|
||||||
rpf = del234(ssh->rportfwds, pf);
|
struct ssh_rportfwd *realpf = del234(ssh->rportfwds, rpf);
|
||||||
assert(rpf == pf);
|
assert(realpf == rpf);
|
||||||
pf->pfrec->remote = NULL;
|
portfwdmgr_close(ssh->portfwdmgr, rpf->pfr);
|
||||||
free_rportfwd(pf);
|
free_rportfwd(rpf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
|
struct ssh_rportfwd *ssh_rportfwd_alloc(
|
||||||
|
Ssh ssh, const char *shost, int sport, const char *dhost, int dport,
|
||||||
|
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
||||||
ssh_sharing_connstate *share_ctx)
|
ssh_sharing_connstate *share_ctx)
|
||||||
{
|
{
|
||||||
struct ssh_rportfwd *pf = snew(struct ssh_rportfwd);
|
/*
|
||||||
pf->dhost = NULL;
|
* Ensure the remote port forwardings tree exists.
|
||||||
pf->dport = 0;
|
*/
|
||||||
pf->share_ctx = share_ctx;
|
|
||||||
pf->shost = dupstr(shost);
|
|
||||||
pf->sport = sport;
|
|
||||||
pf->sportdesc = NULL;
|
|
||||||
if (!ssh->rportfwds) {
|
if (!ssh->rportfwds) {
|
||||||
assert(ssh->version == 2);
|
if (ssh->version == 1)
|
||||||
|
ssh->rportfwds = newtree234(ssh_rportcmp_ssh1);
|
||||||
|
else
|
||||||
ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);
|
ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);
|
||||||
}
|
}
|
||||||
if (add234(ssh->rportfwds, pf) != pf) {
|
|
||||||
sfree(pf->shost);
|
struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd);
|
||||||
sfree(pf);
|
|
||||||
return FALSE;
|
rpf->shost = dupstr(shost);
|
||||||
|
rpf->sport = sport;
|
||||||
|
rpf->dhost = dupstr(dhost);
|
||||||
|
rpf->dport = dport;
|
||||||
|
rpf->addressfamily = addressfamily;
|
||||||
|
rpf->log_description = dupstr(log_description);
|
||||||
|
rpf->pfr = pfr;
|
||||||
|
rpf->share_ctx = share_ctx;
|
||||||
|
|
||||||
|
if (add234(ssh->rportfwds, rpf) != rpf) {
|
||||||
|
free_rportfwd(rpf);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
return TRUE;
|
|
||||||
|
if (!rpf->share_ctx) {
|
||||||
|
PktOut *pktout;
|
||||||
|
|
||||||
|
if (ssh->version == 1) {
|
||||||
|
pktout = ssh_bpp_new_pktout(
|
||||||
|
ssh->bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
|
||||||
|
put_uint32(pktout, rpf->sport);
|
||||||
|
put_stringz(pktout, rpf->dhost);
|
||||||
|
put_uint32(pktout, rpf->dport);
|
||||||
|
ssh_pkt_write(ssh, pktout);
|
||||||
|
ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS,
|
||||||
|
SSH1_SMSG_FAILURE,
|
||||||
|
ssh_rportfwd_succfail, rpf);
|
||||||
|
} else {
|
||||||
|
pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_GLOBAL_REQUEST);
|
||||||
|
put_stringz(pktout, "tcpip-forward");
|
||||||
|
put_bool(pktout, 1); /* want reply */
|
||||||
|
put_stringz(pktout, rpf->shost);
|
||||||
|
put_uint32(pktout, rpf->sport);
|
||||||
|
ssh2_pkt_send(ssh, pktout);
|
||||||
|
|
||||||
|
ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,
|
||||||
|
SSH2_MSG_REQUEST_FAILURE,
|
||||||
|
ssh_rportfwd_succfail, rpf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
|
void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf)
|
||||||
ssh_sharing_connstate *share_ctx)
|
|
||||||
{
|
{
|
||||||
struct ssh_rportfwd pf, *realpf;
|
if (ssh->version == 1) {
|
||||||
|
/*
|
||||||
|
* We cannot cancel listening ports on the server side in
|
||||||
|
* SSH-1! There's no message to support it.
|
||||||
|
*/
|
||||||
|
} else if (rpf->share_ctx) {
|
||||||
|
/*
|
||||||
|
* We don't manufacture a cancel-tcpip-forward message for
|
||||||
|
* remote port forwardings being removed on behalf of a
|
||||||
|
* downstream; we just pass through the one the downstream
|
||||||
|
* sent to us.
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
PktOut *pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_GLOBAL_REQUEST);
|
||||||
|
put_stringz(pktout, "cancel-tcpip-forward");
|
||||||
|
put_bool(pktout, 0); /* _don't_ want reply */
|
||||||
|
put_stringz(pktout, rpf->shost);
|
||||||
|
put_uint32(pktout, rpf->sport);
|
||||||
|
ssh2_pkt_send(ssh, pktout);
|
||||||
|
}
|
||||||
|
|
||||||
assert(ssh->rportfwds);
|
struct ssh_rportfwd *realpf = del234(ssh->rportfwds, rpf);
|
||||||
pf.shost = dupstr(shost);
|
assert(realpf == rpf);
|
||||||
pf.sport = sport;
|
free_rportfwd(rpf);
|
||||||
realpf = del234(ssh->rportfwds, &pf);
|
|
||||||
assert(realpf);
|
|
||||||
assert(realpf->share_ctx == share_ctx);
|
|
||||||
sfree(realpf->shost);
|
|
||||||
sfree(realpf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin,
|
static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin,
|
||||||
|
@ -3885,334 +3862,6 @@ void ssh_sharing_queue_global_request(Ssh ssh,
|
||||||
ssh_sharing_global_request_response, share_ctx);
|
ssh_sharing_global_request_response, share_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssh_setup_portfwd(Ssh ssh, Conf *conf)
|
|
||||||
{
|
|
||||||
struct ssh_portfwd *epf;
|
|
||||||
int i;
|
|
||||||
char *key, *val;
|
|
||||||
|
|
||||||
if (!ssh->portfwds) {
|
|
||||||
ssh->portfwds = newtree234(ssh_portcmp);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Go through the existing port forwardings and tag them
|
|
||||||
* with status==DESTROY. Any that we want to keep will be
|
|
||||||
* re-enabled (status==KEEP) as we go through the
|
|
||||||
* configuration and find out which bits are the same as
|
|
||||||
* they were before.
|
|
||||||
*/
|
|
||||||
struct ssh_portfwd *epf;
|
|
||||||
int i;
|
|
||||||
for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)
|
|
||||||
epf->status = DESTROY;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
|
|
||||||
val != NULL;
|
|
||||||
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
|
|
||||||
char *kp, *kp2, *vp, *vp2;
|
|
||||||
char address_family, type;
|
|
||||||
int sport,dport,sserv,dserv;
|
|
||||||
char *sports, *dports, *saddr, *host;
|
|
||||||
|
|
||||||
kp = key;
|
|
||||||
|
|
||||||
address_family = 'A';
|
|
||||||
type = 'L';
|
|
||||||
if (*kp == 'A' || *kp == '4' || *kp == '6')
|
|
||||||
address_family = *kp++;
|
|
||||||
if (*kp == 'L' || *kp == 'R')
|
|
||||||
type = *kp++;
|
|
||||||
|
|
||||||
if ((kp2 = host_strchr(kp, ':')) != NULL) {
|
|
||||||
/*
|
|
||||||
* There's a colon in the middle of the source port
|
|
||||||
* string, which means that the part before it is
|
|
||||||
* actually a source address.
|
|
||||||
*/
|
|
||||||
char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp);
|
|
||||||
saddr = host_strduptrim(saddr_tmp);
|
|
||||||
sfree(saddr_tmp);
|
|
||||||
sports = kp2+1;
|
|
||||||
} else {
|
|
||||||
saddr = NULL;
|
|
||||||
sports = kp;
|
|
||||||
}
|
|
||||||
sport = atoi(sports);
|
|
||||||
sserv = 0;
|
|
||||||
if (sport == 0) {
|
|
||||||
sserv = 1;
|
|
||||||
sport = net_service_lookup(sports);
|
|
||||||
if (!sport) {
|
|
||||||
logeventf(ssh, "Service lookup failed for source"
|
|
||||||
" port \"%s\"", sports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == 'L' && !strcmp(val, "D")) {
|
|
||||||
/* dynamic forwarding */
|
|
||||||
host = NULL;
|
|
||||||
dports = NULL;
|
|
||||||
dport = -1;
|
|
||||||
dserv = 0;
|
|
||||||
type = 'D';
|
|
||||||
} else {
|
|
||||||
/* ordinary forwarding */
|
|
||||||
vp = val;
|
|
||||||
vp2 = vp + host_strcspn(vp, ":");
|
|
||||||
host = dupprintf("%.*s", (int)(vp2 - vp), vp);
|
|
||||||
if (*vp2)
|
|
||||||
vp2++;
|
|
||||||
dports = vp2;
|
|
||||||
dport = atoi(dports);
|
|
||||||
dserv = 0;
|
|
||||||
if (dport == 0) {
|
|
||||||
dserv = 1;
|
|
||||||
dport = net_service_lookup(dports);
|
|
||||||
if (!dport) {
|
|
||||||
logeventf(ssh, "Service lookup failed for destination"
|
|
||||||
" port \"%s\"", dports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sport && dport) {
|
|
||||||
/* Set up a description of the source port. */
|
|
||||||
struct ssh_portfwd *pfrec, *epfrec;
|
|
||||||
|
|
||||||
pfrec = snew(struct ssh_portfwd);
|
|
||||||
pfrec->type = type;
|
|
||||||
pfrec->saddr = saddr;
|
|
||||||
pfrec->sserv = sserv ? dupstr(sports) : NULL;
|
|
||||||
pfrec->sport = sport;
|
|
||||||
pfrec->daddr = host;
|
|
||||||
pfrec->dserv = dserv ? dupstr(dports) : NULL;
|
|
||||||
pfrec->dport = dport;
|
|
||||||
pfrec->local = NULL;
|
|
||||||
pfrec->remote = NULL;
|
|
||||||
pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :
|
|
||||||
address_family == '6' ? ADDRTYPE_IPV6 :
|
|
||||||
ADDRTYPE_UNSPEC);
|
|
||||||
|
|
||||||
epfrec = add234(ssh->portfwds, pfrec);
|
|
||||||
if (epfrec != pfrec) {
|
|
||||||
if (epfrec->status == DESTROY) {
|
|
||||||
/*
|
|
||||||
* We already have a port forwarding up and running
|
|
||||||
* with precisely these parameters. Hence, no need
|
|
||||||
* to do anything; simply re-tag the existing one
|
|
||||||
* as KEEP.
|
|
||||||
*/
|
|
||||||
epfrec->status = KEEP;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Anything else indicates that there was a duplicate
|
|
||||||
* in our input, which we'll silently ignore.
|
|
||||||
*/
|
|
||||||
free_portfwd(pfrec);
|
|
||||||
} else {
|
|
||||||
pfrec->status = CREATE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sfree(saddr);
|
|
||||||
sfree(host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now go through and destroy any port forwardings which were
|
|
||||||
* not re-enabled.
|
|
||||||
*/
|
|
||||||
for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)
|
|
||||||
if (epf->status == DESTROY) {
|
|
||||||
char *message;
|
|
||||||
|
|
||||||
message = dupprintf("%s port forwarding from %s%s%d",
|
|
||||||
epf->type == 'L' ? "local" :
|
|
||||||
epf->type == 'R' ? "remote" : "dynamic",
|
|
||||||
epf->saddr ? epf->saddr : "",
|
|
||||||
epf->saddr ? ":" : "",
|
|
||||||
epf->sport);
|
|
||||||
|
|
||||||
if (epf->type != 'D') {
|
|
||||||
char *msg2 = dupprintf("%s to %s:%d", message,
|
|
||||||
epf->daddr, epf->dport);
|
|
||||||
sfree(message);
|
|
||||||
message = msg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
logeventf(ssh, "Cancelling %s", message);
|
|
||||||
sfree(message);
|
|
||||||
|
|
||||||
/* epf->remote or epf->local may be NULL if setting up a
|
|
||||||
* forwarding failed. */
|
|
||||||
if (epf->remote) {
|
|
||||||
struct ssh_rportfwd *rpf = epf->remote;
|
|
||||||
PktOut *pktout;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cancel the port forwarding at the server
|
|
||||||
* end.
|
|
||||||
*/
|
|
||||||
if (ssh->version == 1) {
|
|
||||||
/*
|
|
||||||
* We cannot cancel listening ports on the
|
|
||||||
* server side in SSH-1! There's no message
|
|
||||||
* to support it. Instead, we simply remove
|
|
||||||
* the rportfwd record from the local end
|
|
||||||
* so that any connections the server tries
|
|
||||||
* to make on it are rejected.
|
|
||||||
*/
|
|
||||||
} else {
|
|
||||||
pktout = ssh_bpp_new_pktout(
|
|
||||||
ssh->bpp, SSH2_MSG_GLOBAL_REQUEST);
|
|
||||||
put_stringz(pktout, "cancel-tcpip-forward");
|
|
||||||
put_bool(pktout, 0);/* _don't_ want reply */
|
|
||||||
if (epf->saddr) {
|
|
||||||
put_stringz(pktout, epf->saddr);
|
|
||||||
} else if (conf_get_int(conf, CONF_rport_acceptall)) {
|
|
||||||
/* XXX: rport_acceptall may not represent
|
|
||||||
* what was used to open the original connection,
|
|
||||||
* since it's reconfigurable. */
|
|
||||||
put_stringz(pktout, "");
|
|
||||||
} else {
|
|
||||||
put_stringz(pktout, "localhost");
|
|
||||||
}
|
|
||||||
put_uint32(pktout, epf->sport);
|
|
||||||
ssh2_pkt_send(ssh, pktout);
|
|
||||||
}
|
|
||||||
|
|
||||||
del234(ssh->rportfwds, rpf);
|
|
||||||
free_rportfwd(rpf);
|
|
||||||
} else if (epf->local) {
|
|
||||||
pfl_terminate(epf->local);
|
|
||||||
}
|
|
||||||
|
|
||||||
delpos234(ssh->portfwds, i);
|
|
||||||
free_portfwd(epf);
|
|
||||||
i--; /* so we don't skip one in the list */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* And finally, set up any new port forwardings (status==CREATE).
|
|
||||||
*/
|
|
||||||
for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)
|
|
||||||
if (epf->status == CREATE) {
|
|
||||||
char *sportdesc, *dportdesc;
|
|
||||||
sportdesc = dupprintf("%s%s%s%s%d%s",
|
|
||||||
epf->saddr ? epf->saddr : "",
|
|
||||||
epf->saddr ? ":" : "",
|
|
||||||
epf->sserv ? epf->sserv : "",
|
|
||||||
epf->sserv ? "(" : "",
|
|
||||||
epf->sport,
|
|
||||||
epf->sserv ? ")" : "");
|
|
||||||
if (epf->type == 'D') {
|
|
||||||
dportdesc = NULL;
|
|
||||||
} else {
|
|
||||||
dportdesc = dupprintf("%s:%s%s%d%s",
|
|
||||||
epf->daddr,
|
|
||||||
epf->dserv ? epf->dserv : "",
|
|
||||||
epf->dserv ? "(" : "",
|
|
||||||
epf->dport,
|
|
||||||
epf->dserv ? ")" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (epf->type == 'L') {
|
|
||||||
char *err = pfl_listen(epf->daddr, epf->dport,
|
|
||||||
epf->saddr, epf->sport,
|
|
||||||
ssh, conf, &epf->local,
|
|
||||||
epf->addressfamily);
|
|
||||||
|
|
||||||
logeventf(ssh, "Local %sport %s forwarding to %s%s%s",
|
|
||||||
epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
|
|
||||||
epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
|
|
||||||
sportdesc, dportdesc,
|
|
||||||
err ? " failed: " : "", err ? err : "");
|
|
||||||
if (err)
|
|
||||||
sfree(err);
|
|
||||||
} else if (epf->type == 'D') {
|
|
||||||
char *err = pfl_listen(NULL, -1, epf->saddr, epf->sport,
|
|
||||||
ssh, conf, &epf->local,
|
|
||||||
epf->addressfamily);
|
|
||||||
|
|
||||||
logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s",
|
|
||||||
epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
|
|
||||||
epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
|
|
||||||
sportdesc,
|
|
||||||
err ? " failed: " : "", err ? err : "");
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
sfree(err);
|
|
||||||
} else {
|
|
||||||
struct ssh_rportfwd *pf;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure the remote port forwardings tree exists.
|
|
||||||
*/
|
|
||||||
if (!ssh->rportfwds) {
|
|
||||||
if (ssh->version == 1)
|
|
||||||
ssh->rportfwds = newtree234(ssh_rportcmp_ssh1);
|
|
||||||
else
|
|
||||||
ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pf = snew(struct ssh_rportfwd);
|
|
||||||
pf->share_ctx = NULL;
|
|
||||||
pf->dhost = dupstr(epf->daddr);
|
|
||||||
pf->dport = epf->dport;
|
|
||||||
if (epf->saddr) {
|
|
||||||
pf->shost = dupstr(epf->saddr);
|
|
||||||
} else if (conf_get_int(conf, CONF_rport_acceptall)) {
|
|
||||||
pf->shost = dupstr("");
|
|
||||||
} else {
|
|
||||||
pf->shost = dupstr("localhost");
|
|
||||||
}
|
|
||||||
pf->sport = epf->sport;
|
|
||||||
if (add234(ssh->rportfwds, pf) != pf) {
|
|
||||||
logeventf(ssh, "Duplicate remote port forwarding to %s:%d",
|
|
||||||
epf->daddr, epf->dport);
|
|
||||||
sfree(pf);
|
|
||||||
} else {
|
|
||||||
PktOut *pktout;
|
|
||||||
|
|
||||||
logeventf(ssh, "Requesting remote port %s"
|
|
||||||
" forward to %s", sportdesc, dportdesc);
|
|
||||||
|
|
||||||
pf->sportdesc = sportdesc;
|
|
||||||
sportdesc = NULL;
|
|
||||||
epf->remote = pf;
|
|
||||||
pf->pfrec = epf;
|
|
||||||
|
|
||||||
if (ssh->version == 1) {
|
|
||||||
pktout = ssh_bpp_new_pktout(
|
|
||||||
ssh->bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
|
|
||||||
put_uint32(pktout, epf->sport);
|
|
||||||
put_stringz(pktout, epf->daddr);
|
|
||||||
put_uint32(pktout, epf->dport);
|
|
||||||
ssh_pkt_write(ssh, pktout);
|
|
||||||
ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS,
|
|
||||||
SSH1_SMSG_FAILURE,
|
|
||||||
ssh_rportfwd_succfail, pf);
|
|
||||||
} else {
|
|
||||||
pktout = ssh_bpp_new_pktout(
|
|
||||||
ssh->bpp, SSH2_MSG_GLOBAL_REQUEST);
|
|
||||||
put_stringz(pktout, "tcpip-forward");
|
|
||||||
put_bool(pktout, 1);/* want reply */
|
|
||||||
put_stringz(pktout, pf->shost);
|
|
||||||
put_uint32(pktout, pf->sport);
|
|
||||||
ssh2_pkt_send(ssh, pktout);
|
|
||||||
|
|
||||||
ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,
|
|
||||||
SSH2_MSG_REQUEST_FAILURE,
|
|
||||||
ssh_rportfwd_succfail, pf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sfree(sportdesc);
|
|
||||||
sfree(dportdesc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ssh1_smsg_stdout_stderr_data(Ssh ssh, PktIn *pktin)
|
static void ssh1_smsg_stdout_stderr_data(Ssh ssh, PktIn *pktin)
|
||||||
{
|
{
|
||||||
ptrlen string;
|
ptrlen string;
|
||||||
|
@ -4321,8 +3970,8 @@ static void ssh1_msg_port_open(Ssh ssh, PktIn *pktin)
|
||||||
|
|
||||||
logeventf(ssh, "Received remote port open request for %s:%d",
|
logeventf(ssh, "Received remote port open request for %s:%d",
|
||||||
pf.dhost, port);
|
pf.dhost, port);
|
||||||
err = pfd_connect(&c->chan, pf.dhost, port,
|
err = portfwdmgr_connect(ssh->portfwdmgr, &c->chan, pf.dhost, port,
|
||||||
&c->sc, ssh->conf, pfp->pfrec->addressfamily);
|
&c->sc, pfp->addressfamily);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
logeventf(ssh, "Port open failed: %s", err);
|
logeventf(ssh, "Port open failed: %s", err);
|
||||||
sfree(err);
|
sfree(err);
|
||||||
|
@ -4562,7 +4211,7 @@ static void do_ssh1_connection(void *vctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_setup_portfwd(ssh, ssh->conf);
|
portfwdmgr_config(ssh->portfwdmgr, ssh->conf);
|
||||||
ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open;
|
ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open;
|
||||||
|
|
||||||
if (!conf_get_int(ssh->conf, CONF_nopty)) {
|
if (!conf_get_int(ssh->conf, CONF_nopty)) {
|
||||||
|
@ -7858,8 +7507,9 @@ static void ssh2_msg_channel_open(Ssh ssh, PktIn *pktin)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pfd_connect(&c->chan, realpf->dhost, realpf->dport,
|
err = portfwdmgr_connect(
|
||||||
&c->sc, ssh->conf, realpf->pfrec->addressfamily);
|
ssh->portfwdmgr, &c->chan, realpf->dhost, realpf->dport,
|
||||||
|
&c->sc, realpf->addressfamily);
|
||||||
logeventf(ssh, "Attempting to forward remote port to "
|
logeventf(ssh, "Attempting to forward remote port to "
|
||||||
"%s:%d", realpf->dhost, realpf->dport);
|
"%s:%d", realpf->dhost, realpf->dport);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
|
@ -9925,7 +9575,7 @@ static void do_ssh2_connection(void *vctx)
|
||||||
/*
|
/*
|
||||||
* Enable port forwardings.
|
* Enable port forwardings.
|
||||||
*/
|
*/
|
||||||
ssh_setup_portfwd(ssh, ssh->conf);
|
portfwdmgr_config(ssh->portfwdmgr, ssh->conf);
|
||||||
|
|
||||||
if (ssh->mainchan && !ssh->ncmode) {
|
if (ssh->mainchan && !ssh->ncmode) {
|
||||||
/*
|
/*
|
||||||
|
@ -10703,7 +10353,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle,
|
||||||
|
|
||||||
ssh->channels = NULL;
|
ssh->channels = NULL;
|
||||||
ssh->rportfwds = NULL;
|
ssh->rportfwds = NULL;
|
||||||
ssh->portfwds = NULL;
|
ssh->portfwdmgr = portfwdmgr_new(ssh);
|
||||||
|
|
||||||
ssh->send_ok = 0;
|
ssh->send_ok = 0;
|
||||||
ssh->editing = 0;
|
ssh->editing = 0;
|
||||||
|
@ -10798,6 +10448,7 @@ static void ssh_free(Backend *be)
|
||||||
freetree234(ssh->rportfwds);
|
freetree234(ssh->rportfwds);
|
||||||
ssh->rportfwds = NULL;
|
ssh->rportfwds = NULL;
|
||||||
}
|
}
|
||||||
|
portfwdmgr_free(ssh->portfwdmgr);
|
||||||
if (ssh->x11disp)
|
if (ssh->x11disp)
|
||||||
x11_free_display(ssh->x11disp);
|
x11_free_display(ssh->x11disp);
|
||||||
while ((auth = delpos234(ssh->x11authtree, 0)) != NULL)
|
while ((auth = delpos234(ssh->x11authtree, 0)) != NULL)
|
||||||
|
@ -10864,8 +10515,7 @@ static void ssh_reconfig(Backend *be, Conf *conf)
|
||||||
int i, rekey_time;
|
int i, rekey_time;
|
||||||
|
|
||||||
pinger_reconfig(ssh->pinger, ssh->conf, conf);
|
pinger_reconfig(ssh->pinger, ssh->conf, conf);
|
||||||
if (ssh->portfwds)
|
portfwdmgr_config(ssh->portfwdmgr, conf);
|
||||||
ssh_setup_portfwd(ssh, conf);
|
|
||||||
|
|
||||||
rekey_time = conf_get_int(conf, CONF_ssh_rekey_time);
|
rekey_time = conf_get_int(conf, CONF_ssh_rekey_time);
|
||||||
if (ssh2_timer_update(ssh, rekey_mins(rekey_time, 60)))
|
if (ssh2_timer_update(ssh, rekey_mins(rekey_time, 60)))
|
||||||
|
|
33
ssh.h
33
ssh.h
|
@ -149,10 +149,6 @@ void ssh_connshare_log(Ssh ssh, int event, const char *logtext,
|
||||||
const char *ds_err, const char *us_err);
|
const char *ds_err, const char *us_err);
|
||||||
unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate);
|
unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate);
|
||||||
void ssh_delete_sharing_channel(Ssh ssh, unsigned localid);
|
void ssh_delete_sharing_channel(Ssh ssh, unsigned localid);
|
||||||
int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
|
|
||||||
ssh_sharing_connstate *connstate);
|
|
||||||
void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
|
|
||||||
ssh_sharing_connstate *connstate);
|
|
||||||
void ssh_sharing_queue_global_request(
|
void ssh_sharing_queue_global_request(
|
||||||
Ssh ssh, ssh_sharing_connstate *connstate);
|
Ssh ssh, ssh_sharing_connstate *connstate);
|
||||||
struct X11FakeAuth *ssh_sharing_add_x11_display(
|
struct X11FakeAuth *ssh_sharing_add_x11_display(
|
||||||
|
@ -175,6 +171,23 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
|
||||||
int protomajor, int protominor,
|
int protomajor, int protominor,
|
||||||
const void *initial_data, int initial_len);
|
const void *initial_data, int initial_len);
|
||||||
|
|
||||||
|
struct ssh_rportfwd;
|
||||||
|
struct ssh_rportfwd *ssh_rportfwd_alloc(
|
||||||
|
Ssh ssh, const char *shost, int sport, const char *dhost, int dport,
|
||||||
|
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
||||||
|
ssh_sharing_connstate *share_ctx);
|
||||||
|
void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf);
|
||||||
|
|
||||||
|
/* Exports from portfwd.c */
|
||||||
|
PortFwdManager *portfwdmgr_new(Ssh ssh);
|
||||||
|
void portfwdmgr_free(PortFwdManager *mgr);
|
||||||
|
void portfwdmgr_config(PortFwdManager *mgr, Conf *conf);
|
||||||
|
void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr);
|
||||||
|
void portfwdmgr_close_all(PortFwdManager *mgr);
|
||||||
|
char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
|
||||||
|
char *hostname, int port, SshChannel *c,
|
||||||
|
int addressfamily);
|
||||||
|
|
||||||
Frontend *ssh_get_frontend(Ssh ssh);
|
Frontend *ssh_get_frontend(Ssh ssh);
|
||||||
|
|
||||||
#define SSH_CIPHER_IDEA 1
|
#define SSH_CIPHER_IDEA 1
|
||||||
|
@ -718,22 +731,10 @@ void random_add_heavynoise(void *noise, int length);
|
||||||
|
|
||||||
void logevent(Frontend *, const char *);
|
void logevent(Frontend *, const char *);
|
||||||
|
|
||||||
struct PortForwarding;
|
|
||||||
|
|
||||||
/* Allocate and register a new channel for port forwarding */
|
/* Allocate and register a new channel for port forwarding */
|
||||||
SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port,
|
SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port,
|
||||||
const char *org, Channel *chan);
|
const char *org, Channel *chan);
|
||||||
|
|
||||||
/* Exports from portfwd.c */
|
|
||||||
extern char *pfd_connect(Channel **chan_ret, char *hostname, int port,
|
|
||||||
SshChannel *c, Conf *conf, int addressfamily);
|
|
||||||
struct PortListener;
|
|
||||||
/* desthost == NULL indicates dynamic (SOCKS) port forwarding */
|
|
||||||
extern char *pfl_listen(char *desthost, int destport, char *srcaddr,
|
|
||||||
int port, Ssh ssh, Conf *conf,
|
|
||||||
struct PortListener **pl, int address_family);
|
|
||||||
extern void pfl_terminate(struct PortListener *);
|
|
||||||
|
|
||||||
/* Exports from x11fwd.c */
|
/* Exports from x11fwd.c */
|
||||||
enum {
|
enum {
|
||||||
X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256
|
X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256
|
||||||
|
|
16
sshshare.c
16
sshshare.c
|
@ -242,6 +242,7 @@ struct share_forwarding {
|
||||||
char *host;
|
char *host;
|
||||||
int port;
|
int port;
|
||||||
int active; /* has the server sent REQUEST_SUCCESS? */
|
int active; /* has the server sent REQUEST_SUCCESS? */
|
||||||
|
struct ssh_rportfwd *rpf;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct share_xchannel_message {
|
struct share_xchannel_message {
|
||||||
|
@ -856,8 +857,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
|
||||||
"cleanup after downstream went away");
|
"cleanup after downstream went away");
|
||||||
strbuf_free(packet);
|
strbuf_free(packet);
|
||||||
|
|
||||||
ssh_remove_sharing_rportfwd(cs->parent->ssh,
|
ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf);
|
||||||
fwd->host, fwd->port, cs);
|
|
||||||
share_remove_forwarding(cs, fwd);
|
share_remove_forwarding(cs, fwd);
|
||||||
i--; /* don't accidentally skip one as a result */
|
i--; /* don't accidentally skip one as a result */
|
||||||
}
|
}
|
||||||
|
@ -1306,7 +1306,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
|
||||||
if (ptrlen_eq_string(request_name, "tcpip-forward")) {
|
if (ptrlen_eq_string(request_name, "tcpip-forward")) {
|
||||||
ptrlen hostpl;
|
ptrlen hostpl;
|
||||||
char *host;
|
char *host;
|
||||||
int port, ret;
|
int port;
|
||||||
|
struct ssh_rportfwd *rpf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick the packet apart to find the want_reply field and
|
* Pick the packet apart to find the want_reply field and
|
||||||
|
@ -1328,8 +1329,9 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
|
||||||
* ourselves to manufacture a failure packet and send it
|
* ourselves to manufacture a failure packet and send it
|
||||||
* back to downstream.
|
* back to downstream.
|
||||||
*/
|
*/
|
||||||
ret = ssh_alloc_sharing_rportfwd(cs->parent->ssh, host, port, cs);
|
rpf = ssh_rportfwd_alloc(
|
||||||
if (!ret) {
|
cs->parent->ssh, host, port, NULL, 0, 0, NULL, NULL, cs);
|
||||||
|
if (!rpf) {
|
||||||
if (orig_wantreply) {
|
if (orig_wantreply) {
|
||||||
send_packet_to_downstream(cs, SSH2_MSG_REQUEST_FAILURE,
|
send_packet_to_downstream(cs, SSH2_MSG_REQUEST_FAILURE,
|
||||||
"", 0, NULL);
|
"", 0, NULL);
|
||||||
|
@ -1359,6 +1361,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
|
||||||
globreq->fwd = fwd;
|
globreq->fwd = fwd;
|
||||||
globreq->want_reply = orig_wantreply;
|
globreq->want_reply = orig_wantreply;
|
||||||
globreq->type = GLOBREQ_TCPIP_FORWARD;
|
globreq->type = GLOBREQ_TCPIP_FORWARD;
|
||||||
|
|
||||||
|
fwd->rpf = rpf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,7 +1399,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
|
||||||
* Tell ssh.c to stop sending us channel-opens for
|
* Tell ssh.c to stop sending us channel-opens for
|
||||||
* this forwarding.
|
* this forwarding.
|
||||||
*/
|
*/
|
||||||
ssh_remove_sharing_rportfwd(cs->parent->ssh, host, port, cs);
|
ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pass the cancel request on to the SSH server, but
|
* Pass the cancel request on to the SSH server, but
|
||||||
|
|
Загрузка…
Ссылка в новой задаче