зеркало из https://github.com/github/putty.git
Dynamic port forwarding by means of a local SOCKS server. Fully
supports SOCKS 4, SOCKS 4A and SOCKS 5 (well, actually IPv6 in SOCKS 5 isn't supported, but it'll be no difficulty once I actually get round to it). Thanks to Chas Honton for his `stone soup' patch: I didn't end up actually using any of his code, but it galvanised me into doing it properly myself :-) [originally from svn r3055]
This commit is contained in:
Родитель
3bd0415579
Коммит
8a3ff2bf3e
21
cmdline.c
21
cmdline.c
|
@ -166,35 +166,37 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg)
|
|||
strncpy(cfg->username, value, sizeof(cfg->username));
|
||||
cfg->username[sizeof(cfg->username) - 1] = '\0';
|
||||
}
|
||||
if ((!strcmp(p, "-L") || !strcmp(p, "-R"))) {
|
||||
if ((!strcmp(p, "-L") || !strcmp(p, "-R") || !strcmp(p, "-D"))) {
|
||||
char *fwd, *ptr, *q, *qq;
|
||||
int i=0;
|
||||
int dynamic, i=0;
|
||||
RETURN(2);
|
||||
UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK);
|
||||
SAVEABLE(0);
|
||||
dynamic = !strcmp(p, "-D");
|
||||
fwd = value;
|
||||
ptr = cfg->portfwd;
|
||||
/* if multiple forwards, find end of list */
|
||||
if (ptr[0]=='R' || ptr[0]=='L') {
|
||||
if (ptr[0]=='R' || ptr[0]=='L' || ptr[0] == 'D') {
|
||||
for (i = 0; i < sizeof(cfg->portfwd) - 2; i++)
|
||||
if (ptr[i]=='\000' && ptr[i+1]=='\000')
|
||||
break;
|
||||
ptr = ptr + i + 1; /* point to next forward slot */
|
||||
}
|
||||
ptr[0] = p[1]; /* insert a 'L' or 'R' at the start */
|
||||
ptr[0] = p[1]; /* insert a 'L', 'R' or 'D' at the start */
|
||||
if (strlen(fwd) > sizeof(cfg->portfwd) - i - 2) {
|
||||
cmdline_error("out of space for port forwardings");
|
||||
return ret;
|
||||
}
|
||||
strncpy(ptr+1, fwd, sizeof(cfg->portfwd) - i);
|
||||
if (!dynamic) {
|
||||
/*
|
||||
* We expect _at least_ two colons in this string. The
|
||||
* possible formats are `sourceport:desthost:destport', or
|
||||
* `sourceip:sourceport:desthost:destport' if you're
|
||||
* possible formats are `sourceport:desthost:destport',
|
||||
* or `sourceip:sourceport:desthost:destport' if you're
|
||||
* specifying a particular loopback address. We need to
|
||||
* replace the one between source and dest with a \t; this
|
||||
* means we must find the second-to-last colon in the
|
||||
* string.
|
||||
* replace the one between source and dest with a \t;
|
||||
* this means we must find the second-to-last colon in
|
||||
* the string.
|
||||
*/
|
||||
q = qq = strchr(ptr, ':');
|
||||
while (qq) {
|
||||
|
@ -204,6 +206,7 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg)
|
|||
qq = qqq;
|
||||
}
|
||||
if (q) *q = '\t'; /* replace second-last colon with \t */
|
||||
}
|
||||
cfg->portfwd[sizeof(cfg->portfwd) - 1] = '\0';
|
||||
cfg->portfwd[sizeof(cfg->portfwd) - 2] = '\0';
|
||||
ptr[strlen(ptr)+1] = '\000'; /* append two '\000' */
|
||||
|
|
19
config.c
19
config.c
|
@ -634,24 +634,31 @@ static void portfwd_handler(union control *ctrl, void *dlg,
|
|||
if (ctrl == pfd->addbutton) {
|
||||
char str[sizeof(cfg->portfwd)];
|
||||
char *p;
|
||||
if (dlg_radiobutton_get(pfd->direction, dlg) == 0)
|
||||
int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
|
||||
if (whichbutton == 0)
|
||||
str[0] = 'L';
|
||||
else
|
||||
else if (whichbutton == 1)
|
||||
str[0] = 'R';
|
||||
else
|
||||
str[0] = 'D';
|
||||
dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
|
||||
if (!str[1]) {
|
||||
dlg_error_msg(dlg, "You need to specify a source port number");
|
||||
return;
|
||||
}
|
||||
p = str + strlen(str);
|
||||
if (str[0] != 'D') {
|
||||
*p++ = '\t';
|
||||
dlg_editbox_get(pfd->destbox, dlg, p, sizeof(str)-1 - (p - str));
|
||||
dlg_editbox_get(pfd->destbox, dlg, p,
|
||||
sizeof(str)-1 - (p - str));
|
||||
if (!*p || !strchr(p, ':')) {
|
||||
dlg_error_msg(dlg,
|
||||
"You need to specify a destination address\n"
|
||||
"in the form \"host.name:port\"");
|
||||
return;
|
||||
}
|
||||
} else
|
||||
*p = '\0';
|
||||
p = cfg->portfwd;
|
||||
while (*p) {
|
||||
while (*p)
|
||||
|
@ -1550,11 +1557,13 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
|
|||
pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
|
||||
HELPCTX(ssh_tunnels_portfwd),
|
||||
portfwd_handler, P(pfd), P(NULL));
|
||||
pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
|
||||
pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
|
||||
HELPCTX(ssh_tunnels_portfwd),
|
||||
portfwd_handler, P(pfd),
|
||||
"Local", 'l', P(NULL),
|
||||
"Remote", 'm', P(NULL), NULL);
|
||||
"Remote", 'm', P(NULL),
|
||||
"Dynamic", 'y', P(NULL),
|
||||
NULL);
|
||||
ctrl_tabdelay(s, pfd->addbutton);
|
||||
ctrl_columns(s, 1, 100);
|
||||
|
||||
|
|
1
plink.c
1
plink.c
|
@ -207,6 +207,7 @@ static void usage(void)
|
|||
printf(" -batch disable all interactive prompts\n");
|
||||
printf("The following options only apply to SSH connections:\n");
|
||||
printf(" -pw passw login with specified password\n");
|
||||
printf(" -D listen-port Dynamic SOCKS-based port forwarding\n");
|
||||
printf(" -L listen-port:host:port Forward local port to "
|
||||
"remote address\n");
|
||||
printf(" -R listen-port:host:port Forward remote port to"
|
||||
|
|
270
portfwd.c
270
portfwd.c
|
@ -51,11 +51,6 @@
|
|||
(cp)[0] = (value) >> 8, \
|
||||
(cp)[1] = (value) )
|
||||
|
||||
struct pfwd_queue {
|
||||
struct pfwd_queue *next;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
struct PFwdPrivate {
|
||||
const struct plug_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
|
@ -63,14 +58,34 @@ struct PFwdPrivate {
|
|||
void *backhandle; /* instance of SSH backend itself */
|
||||
/* Note that backhandle need not be filled in if c is non-NULL */
|
||||
Socket s;
|
||||
char hostname[128];
|
||||
int throttled, throttle_override;
|
||||
int port;
|
||||
int ready;
|
||||
struct pfwd_queue *waiting;
|
||||
/*
|
||||
* `dynamic' does double duty. It's set to 0 for an ordinary
|
||||
* forwarded port, and nonzero for SOCKS-style dynamic port
|
||||
* forwarding; but it also represents the state of the SOCKS
|
||||
* exchange.
|
||||
*/
|
||||
int dynamic;
|
||||
/*
|
||||
* `hostname' and `port' are the real hostname and port, once
|
||||
* we know what we're connecting to; they're unused for this
|
||||
* purpose while conducting a local SOCKS exchange, which means
|
||||
* we can also use them as a buffer and pointer for reading
|
||||
* data from the SOCKS client.
|
||||
*/
|
||||
char hostname[256];
|
||||
int port;
|
||||
/*
|
||||
* When doing dynamic port forwarding, we can receive
|
||||
* connection data before we are actually able to send it; so
|
||||
* we may have to temporarily hold some in a dynamically
|
||||
* allocated buffer here.
|
||||
*/
|
||||
void *buffer;
|
||||
int buflen;
|
||||
};
|
||||
|
||||
|
||||
static int pfd_closing(Plug plug, char *error_msg, int error_code,
|
||||
int calling_back)
|
||||
{
|
||||
|
@ -81,6 +96,7 @@ static int pfd_closing(Plug plug, char *error_msg, int error_code,
|
|||
* so if an error occurred on the socket, we just ignore it
|
||||
* and treat it like a proper close.
|
||||
*/
|
||||
if (pr->c)
|
||||
sshfwd_close(pr->c);
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
|
@ -89,6 +105,212 @@ static int pfd_closing(Plug plug, char *error_msg, int error_code,
|
|||
static int pfd_receive(Plug plug, int urgent, char *data, int len)
|
||||
{
|
||||
struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
|
||||
if (pr->dynamic) {
|
||||
while (len--) {
|
||||
if (pr->port >= lenof(pr->hostname)) {
|
||||
if ((pr->dynamic >> 12) == 4) {
|
||||
/* Send back a SOCKS 4 error before closing. */
|
||||
char data[8];
|
||||
memset(data, 0, sizeof(data));
|
||||
data[1] = 91; /* generic `request rejected' */
|
||||
sk_write(pr->s, data, 8);
|
||||
}
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
}
|
||||
pr->hostname[pr->port++] = *data++;
|
||||
|
||||
/*
|
||||
* Now check what's in the buffer to see if it's a
|
||||
* valid and complete message in the SOCKS exchange.
|
||||
*/
|
||||
if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) &&
|
||||
pr->hostname[0] == 4) {
|
||||
/*
|
||||
* SOCKS 4.
|
||||
*/
|
||||
if (pr->dynamic == 1)
|
||||
pr->dynamic = 0x4000;
|
||||
if (pr->port < 2) continue;/* don't have command code yet */
|
||||
if (pr->hostname[1] != 1) {
|
||||
/* Send back a SOCKS 4 error before closing. */
|
||||
char data[8];
|
||||
memset(data, 0, sizeof(data));
|
||||
data[1] = 91; /* generic `request rejected' */
|
||||
sk_write(pr->s, data, 8);
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
}
|
||||
if (pr->port < 8) continue; /* haven't started username */
|
||||
if (pr->hostname[pr->port-1] != 0)
|
||||
continue; /* haven't _finished_ username */
|
||||
/*
|
||||
* Now we have a full SOCKS 4 request. Check it to
|
||||
* see if it's a SOCKS 4A request.
|
||||
*/
|
||||
if (pr->hostname[4] == 0 && pr->hostname[5] == 0 &&
|
||||
pr->hostname[6] == 0 && pr->hostname[7] != 0) {
|
||||
/*
|
||||
* It's SOCKS 4A. So if we haven't yet
|
||||
* collected the host name, we should continue
|
||||
* waiting for data in order to do so; if we
|
||||
* have, we can go ahead.
|
||||
*/
|
||||
int len;
|
||||
if (pr->dynamic == 0x4000) {
|
||||
pr->dynamic = 0x4001;
|
||||
continue;
|
||||
}
|
||||
pr->hostname[0] = 0; /* reply version code */
|
||||
pr->hostname[1] = 90; /* request granted */
|
||||
sk_write(pr->s, pr->hostname, 8);
|
||||
pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);
|
||||
len = strlen(pr->hostname+8);
|
||||
memmove(pr->hostname, pr->hostname + 8 + len + 1,
|
||||
lenof(pr->hostname) - (8 + len + 1));
|
||||
goto connect;
|
||||
} else {
|
||||
/*
|
||||
* It's SOCKS 4, which means we should format
|
||||
* the IP address into the hostname string and
|
||||
* then just go.
|
||||
*/
|
||||
pr->hostname[0] = 0; /* reply version code */
|
||||
pr->hostname[1] = 90; /* request granted */
|
||||
sk_write(pr->s, pr->hostname, 8);
|
||||
pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);
|
||||
sprintf(pr->hostname, "%d.%d.%d.%d",
|
||||
(unsigned char)pr->hostname[4],
|
||||
(unsigned char)pr->hostname[5],
|
||||
(unsigned char)pr->hostname[6],
|
||||
(unsigned char)pr->hostname[7]);
|
||||
goto connect;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) &&
|
||||
pr->hostname[0] == 5) {
|
||||
/*
|
||||
* SOCKS 5.
|
||||
*/
|
||||
if (pr->dynamic == 1)
|
||||
pr->dynamic = 0x5000;
|
||||
|
||||
if (pr->dynamic == 0x5000) {
|
||||
int i, method;
|
||||
char data[2];
|
||||
/*
|
||||
* We're receiving a set of method identifiers.
|
||||
*/
|
||||
if (pr->port < 2) continue;/* no method count yet */
|
||||
if (pr->port < 2 + (unsigned char)pr->hostname[1])
|
||||
continue; /* no methods yet */
|
||||
method = 0xFF; /* invalid */
|
||||
for (i = 0; i < (unsigned char)pr->hostname[1]; i++)
|
||||
if (pr->hostname[2+i] == 0) {
|
||||
method = 0;/* no auth */
|
||||
break;
|
||||
}
|
||||
data[0] = 5;
|
||||
data[1] = method;
|
||||
sk_write(pr->s, data, 2);
|
||||
pr->dynamic = 0x5001;
|
||||
pr->port = 0; /* re-empty the buffer */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pr->dynamic == 0x5001) {
|
||||
int atype, alen;
|
||||
if (pr->port < 6) continue;
|
||||
atype = (unsigned char)pr->hostname[3];
|
||||
if (atype == 1) /* IPv4 address */
|
||||
alen = 4;
|
||||
if (atype == 4) /* IPv6 address */
|
||||
alen = 16;
|
||||
if (atype == 3) /* domain name has leading length */
|
||||
alen = 1 + (unsigned char)pr->hostname[4];
|
||||
if (pr->port < 6 + alen) continue;
|
||||
if (pr->hostname[1] != 1 || pr->hostname[2] != 0) {
|
||||
pr->hostname[1] = 1; /* generic failure */
|
||||
pr->hostname[2] = 0; /* reserved */
|
||||
sk_write(pr->s, pr->hostname, pr->port);
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Now we have a viable connect request. Switch
|
||||
* on atype.
|
||||
*/
|
||||
pr->port = GET_16BIT_MSB_FIRST(pr->hostname+4+alen);
|
||||
if (atype == 1) {
|
||||
pr->hostname[1] = 0; /* succeeded */
|
||||
sk_write(pr->s, pr->hostname, alen + 6);
|
||||
sprintf(pr->hostname, "%d.%d.%d.%d",
|
||||
(unsigned char)pr->hostname[4],
|
||||
(unsigned char)pr->hostname[5],
|
||||
(unsigned char)pr->hostname[6],
|
||||
(unsigned char)pr->hostname[7]);
|
||||
goto connect;
|
||||
} else if (atype == 3) {
|
||||
pr->hostname[1] = 0; /* succeeded */
|
||||
sk_write(pr->s, pr->hostname, alen + 6);
|
||||
memmove(pr->hostname, pr->hostname + 5, alen-1);
|
||||
pr->hostname[alen-1] = '\0';
|
||||
goto connect;
|
||||
} else {
|
||||
/*
|
||||
* Unknown address type. (FIXME: support IPv6!)
|
||||
*/
|
||||
pr->hostname[1] = 8; /* atype not supported */
|
||||
sk_write(pr->s, pr->hostname, pr->port);
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here without either having done `continue'
|
||||
* or `goto connect', it must be because there is no
|
||||
* sensible interpretation of what's in our buffer. So
|
||||
* close the connection rudely.
|
||||
*/
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* We come here when we're ready to make an actual
|
||||
* connection.
|
||||
*/
|
||||
connect:
|
||||
|
||||
pr->c = new_sock_channel(pr->backhandle, pr->s);
|
||||
if (pr->c == NULL) {
|
||||
pfd_close(pr->s);
|
||||
return 1;
|
||||
} else {
|
||||
/* asks to forward to the specified host/port for this */
|
||||
ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
|
||||
}
|
||||
pr->dynamic = 0;
|
||||
|
||||
/*
|
||||
* Now freeze the socket until the SSH server confirms the
|
||||
* connection.
|
||||
*/
|
||||
sk_set_frozen(pr->s, 1);
|
||||
/*
|
||||
* If there's any data remaining in our current buffer,
|
||||
* save it to be sent on pfd_confirm().
|
||||
*/
|
||||
if (len > 0) {
|
||||
pr->buffer = snewn(len, char);
|
||||
memcpy(pr->buffer, data, len);
|
||||
pr->buflen = len;
|
||||
}
|
||||
}
|
||||
if (pr->ready) {
|
||||
if (sshfwd_write(pr->c, data, len) > 0) {
|
||||
pr->throttled = 1;
|
||||
|
@ -102,6 +324,7 @@ static void pfd_sent(Plug plug, int bufsize)
|
|||
{
|
||||
struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
|
||||
|
||||
if (pr->c)
|
||||
sshfwd_unthrottle(pr->c, bufsize);
|
||||
}
|
||||
|
||||
|
@ -133,6 +356,7 @@ char *pfd_newconnect(Socket *s, char *hostname, int port, void *c,
|
|||
* Open socket.
|
||||
*/
|
||||
pr = snew(struct PFwdPrivate);
|
||||
pr->buffer = NULL;
|
||||
pr->fn = &fn_table;
|
||||
pr->throttled = pr->throttle_override = 0;
|
||||
pr->ready = 1;
|
||||
|
@ -169,6 +393,7 @@ static int pfd_accepting(Plug p, void *sock)
|
|||
|
||||
org = (struct PFwdPrivate *)p;
|
||||
pr = snew(struct PFwdPrivate);
|
||||
pr->buffer = NULL;
|
||||
pr->fn = &fn_table;
|
||||
|
||||
pr->c = NULL;
|
||||
|
@ -180,15 +405,19 @@ static int pfd_accepting(Plug p, void *sock)
|
|||
return err != NULL;
|
||||
}
|
||||
|
||||
pr->c = new_sock_channel(org->backhandle, s);
|
||||
sk_set_private_ptr(s, pr);
|
||||
|
||||
strcpy(pr->hostname, org->hostname);
|
||||
pr->port = org->port;
|
||||
pr->throttled = pr->throttle_override = 0;
|
||||
pr->ready = 0;
|
||||
pr->waiting = NULL;
|
||||
|
||||
sk_set_private_ptr(s, pr);
|
||||
if (org->dynamic) {
|
||||
pr->dynamic = 1;
|
||||
pr->port = 0; /* hostname buffer is so far empty */
|
||||
sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */
|
||||
} else {
|
||||
strcpy(pr->hostname, org->hostname);
|
||||
pr->port = org->port;
|
||||
pr->c = new_sock_channel(org->backhandle, s);
|
||||
|
||||
if (pr->c == NULL) {
|
||||
sfree(pr);
|
||||
|
@ -197,6 +426,7 @@ static int pfd_accepting(Plug p, void *sock)
|
|||
/* asks to forward to the specified host/port for this */
|
||||
ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -223,13 +453,17 @@ char *pfd_addforward(char *desthost, int destport, char *srcaddr, int port,
|
|||
* Open socket.
|
||||
*/
|
||||
pr = snew(struct PFwdPrivate);
|
||||
pr->buffer = NULL;
|
||||
pr->fn = &fn_table;
|
||||
pr->c = NULL;
|
||||
if (desthost) {
|
||||
strcpy(pr->hostname, desthost);
|
||||
pr->port = destport;
|
||||
pr->dynamic = 0;
|
||||
} else
|
||||
pr->dynamic = 1;
|
||||
pr->throttled = pr->throttle_override = 0;
|
||||
pr->ready = 0;
|
||||
pr->waiting = NULL;
|
||||
pr->backhandle = backhandle;
|
||||
|
||||
pr->s = s = new_listener(srcaddr, port, (Plug) pr,
|
||||
|
@ -253,6 +487,7 @@ void pfd_close(Socket s)
|
|||
|
||||
pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
|
||||
|
||||
sfree(pr->buffer);
|
||||
sfree(pr);
|
||||
|
||||
sk_close(s);
|
||||
|
@ -302,4 +537,9 @@ void pfd_confirm(Socket s)
|
|||
pr->ready = 1;
|
||||
sk_set_frozen(s, 0);
|
||||
sk_write(s, NULL, 0);
|
||||
if (pr->buffer) {
|
||||
sshfwd_write(pr->c, pr->buffer, pr->buflen);
|
||||
sfree(pr->buffer);
|
||||
pr->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
|
13
putty.h
13
putty.h
|
@ -442,7 +442,18 @@ struct config_tag {
|
|||
/* port forwarding */
|
||||
int lport_acceptall; /* accept conns from hosts other than localhost */
|
||||
int rport_acceptall; /* same for remote forwarded ports (SSH2 only) */
|
||||
char portfwd[1024]; /* [LR]localport\thost:port\000[LR]localport\thost:port\000\000 */
|
||||
/*
|
||||
* The port forwarding string contains a number of
|
||||
* NUL-terminated substrings, terminated in turn by an empty
|
||||
* string (i.e. a second NUL immediately after the previous
|
||||
* one). Each string can be of one of the following forms:
|
||||
*
|
||||
* [LR]localport\thost:port
|
||||
* [LR]localaddr:localport\thost:port
|
||||
* Dlocalport
|
||||
* Dlocaladdr:localport
|
||||
*/
|
||||
char portfwd[1024];
|
||||
/* SSH bug compatibility modes */
|
||||
int sshbug_ignore1, sshbug_plainpw1, sshbug_rsa1,
|
||||
sshbug_hmac2, sshbug_derivekey2, sshbug_rsapad2,
|
||||
|
|
26
ssh.c
26
ssh.c
|
@ -3149,6 +3149,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||
if (n < 255) sports[n++] = *ssh->portfwd_strptr++;
|
||||
}
|
||||
sports[n] = 0;
|
||||
if (type != 'D') {
|
||||
if (*ssh->portfwd_strptr == '\t')
|
||||
ssh->portfwd_strptr++;
|
||||
n = 0;
|
||||
|
@ -3174,6 +3175,9 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||
" destination port \"%s\"", dports);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (*ssh->portfwd_strptr) ssh->portfwd_strptr++;
|
||||
}
|
||||
sport = atoi(sports);
|
||||
sserv = 0;
|
||||
if (sport == 0) {
|
||||
|
@ -3197,6 +3201,15 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||
host,
|
||||
(int)(dserv ? strlen(dports) : 0), dports,
|
||||
dserv, "(", dport, dserv, ")");
|
||||
} else if (type == 'D') {
|
||||
pfd_addforward(NULL, -1, *saddr ? saddr : NULL,
|
||||
sport, ssh, &ssh->cfg);
|
||||
logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
|
||||
" doing SOCKS dynamic forwarding",
|
||||
(int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
|
||||
(int)(*saddr?1:0), ":",
|
||||
(int)(sserv ? strlen(sports) : 0), sports,
|
||||
sserv, "(", sport, sserv, ")");
|
||||
} else {
|
||||
struct ssh_rportfwd *pf;
|
||||
pf = snew(struct ssh_rportfwd);
|
||||
|
@ -5230,6 +5243,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||
if (n < 255) sports[n++] = *ssh->portfwd_strptr++;
|
||||
}
|
||||
sports[n] = 0;
|
||||
if (type != 'D') {
|
||||
if (*ssh->portfwd_strptr == '\t')
|
||||
ssh->portfwd_strptr++;
|
||||
n = 0;
|
||||
|
@ -5255,6 +5269,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||
" port \"%s\"", dports);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (*ssh->portfwd_strptr) ssh->portfwd_strptr++;
|
||||
}
|
||||
sport = atoi(sports);
|
||||
sserv = 0;
|
||||
if (sport == 0) {
|
||||
|
@ -5278,6 +5295,15 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
|
|||
host,
|
||||
(int)(dserv ? strlen(dports) : 0), dports,
|
||||
dserv, "(", dport, dserv, ")");
|
||||
} else if (type == 'D') {
|
||||
pfd_addforward(NULL, -1, *saddr ? saddr : NULL,
|
||||
sport, ssh, &ssh->cfg);
|
||||
logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
|
||||
" doing SOCKS dynamic forwarding",
|
||||
(int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
|
||||
(int)(*saddr?1:0), ":",
|
||||
(int)(sserv ? strlen(sports) : 0), sports,
|
||||
sserv, "(", sport, sserv, ")");
|
||||
} else {
|
||||
struct ssh_rportfwd *pf;
|
||||
pf = snew(struct ssh_rportfwd);
|
||||
|
|
1
ssh.h
1
ssh.h
|
@ -259,6 +259,7 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org);
|
|||
/* Exports from portfwd.c */
|
||||
extern char *pfd_newconnect(Socket * s, char *hostname, int port, void *c,
|
||||
const Config *cfg);
|
||||
/* desthost == NULL indicates dynamic (SOCKS) port forwarding */
|
||||
extern char *pfd_addforward(char *desthost, int destport, char *srcaddr,
|
||||
int port, void *backhandle, const Config *cfg);
|
||||
extern void pfd_close(Socket s);
|
||||
|
|
|
@ -263,6 +263,7 @@ static void usage(void)
|
|||
printf(" -batch disable all interactive prompts\n");
|
||||
printf("The following options only apply to SSH connections:\n");
|
||||
printf(" -pw passw login with specified password\n");
|
||||
printf(" -D listen-port Dynamic SOCKS-based port forwarding\n");
|
||||
printf(" -L listen-port:host:port Forward local port to "
|
||||
"remote address\n");
|
||||
printf(" -R listen-port:host:port Forward remote port to"
|
||||
|
|
Загрузка…
Ссылка в новой задаче