++dynamic port forwarding patch + blog entry
Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>
This commit is contained in:
parent
a4b8201801
commit
0264bb72fb
2 changed files with 180 additions and 0 deletions
|
@ -0,0 +1,98 @@
|
||||||
|
[[!meta title="OpenSSH 6.2: Add callback functionality (using dynamic remote port forwarding)"]]
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This article describes a patch to OpenSSH 6.2 that I wrote to enable
|
||||||
|
**ssh callback** using dynamic ports. This is rather useful to have
|
||||||
|
for various types of software, including [[cdist|software/cdist]]
|
||||||
|
and [[ccollect|software/ccollect]].
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
Assume you have two hosts:
|
||||||
|
|
||||||
|
* A **target host**
|
||||||
|
* A **control host**
|
||||||
|
(backup server in case of [[ccollect|software/ccollect]],
|
||||||
|
configuration server in case of [[cdist|software/cdist]])
|
||||||
|
|
||||||
|
Assume further that the target host can directly reach the control
|
||||||
|
host, but the control host cannot connect to the target host directly.
|
||||||
|
|
||||||
|
This is for instance the case,
|
||||||
|
when the target host is hidden by NAT
|
||||||
|
or protected by a firewall.
|
||||||
|
|
||||||
|
## Approaches
|
||||||
|
|
||||||
|
### Create a tunnel from the target host to the control host
|
||||||
|
|
||||||
|
A very simple solution is to create a static tunnel
|
||||||
|
from the target host to the control host, which allows
|
||||||
|
the control host to connect back:
|
||||||
|
|
||||||
|
targethost% ssh -R 42523:localhost:22 controlhost
|
||||||
|
controlhost% ssh -p 42523 localhost
|
||||||
|
|
||||||
|
The drawback is that the remote port needs to be defined
|
||||||
|
beforehand and both sides needs to know about it.
|
||||||
|
|
||||||
|
This is especially nasty, if you have a lot of
|
||||||
|
target hosts that need to be backed up / configured.
|
||||||
|
|
||||||
|
### Use dynamic port allocation
|
||||||
|
|
||||||
|
The [OpenSSH](http://openssh.org/) developers seem to have
|
||||||
|
spotted this problem and include an option to use a random
|
||||||
|
free port: If port 0 is chosen as the remote
|
||||||
|
forwarding port, the port is dynamically chosen by the
|
||||||
|
ssh server, which in our case runs on the controlhost.
|
||||||
|
|
||||||
|
Even better, the port information is also displayed on stdout:
|
||||||
|
|
||||||
|
targethost% ssh -R 0:localhost:22 controlhost
|
||||||
|
Allocated port 59818 for remote forward to localhost:22
|
||||||
|
|
||||||
|
The problem here is: The shell on the remote side does not
|
||||||
|
know which port was chosen, as it is only printed on stdout
|
||||||
|
by the **ssh client**.
|
||||||
|
|
||||||
|
|
||||||
|
### Expose remote forwarding ports
|
||||||
|
|
||||||
|
[[This patch|openssh-6.2p1-expose-remote-port-forwarding.diff]]
|
||||||
|
against OpenSSH 6.2p1 creates a new environment variable
|
||||||
|
***SSH_REMOTE_FORWARDING_PORTS***, which contains all ports
|
||||||
|
that are used for remote forwarding:
|
||||||
|
|
||||||
|
targethost % ssh -R 1234:localhost:22 controlhost
|
||||||
|
controlhost % echo $SSH_REMOTE_FORWARDING_PORTS
|
||||||
|
1234
|
||||||
|
|
||||||
|
As this works for all remotely forwarded ports, this can
|
||||||
|
also be used for dynamic port assignments:
|
||||||
|
|
||||||
|
targethost % ssh -R 0:localhost:22 controlhost
|
||||||
|
controlhost % echo $SSH_REMOTE_FORWARDING_PORTS
|
||||||
|
54294
|
||||||
|
|
||||||
|
If more than one port forwarding definition is given, they are listed
|
||||||
|
space separated:
|
||||||
|
|
||||||
|
targethost % ssh -R 0:localhost:22 -R 1234:localhost:22 controlhost
|
||||||
|
controlhost % echo $SSH_REMOTE_FORWARDING_PORTS
|
||||||
|
59056 1234
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
The given patch has some known limitations:
|
||||||
|
|
||||||
|
* The destination is not shown, as it is not known for ssh2 connections
|
||||||
|
* The number of listed ports is limited by the buffer size of 256 characters
|
||||||
|
|
||||||
|
## Future
|
||||||
|
|
||||||
|
The patch will be submitted to the
|
||||||
|
[openssh-unix-dev mailinglist](https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev) for discussion.
|
||||||
|
|
||||||
|
[[!tag net unix]]
|
|
@ -0,0 +1,82 @@
|
||||||
|
diff -ru openssh-6.2p1/channels.c openssh-6.2p1.patched/channels.c
|
||||||
|
--- openssh-6.2p1/channels.c 2012-12-02 23:50:55.000000000 +0100
|
||||||
|
+++ openssh-6.2p1.patched/channels.c 2013-05-15 23:26:17.119989982 +0200
|
||||||
|
@@ -2865,6 +2865,52 @@
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Write list of remote forwarding ports into an existing buffer
|
||||||
|
+ */
|
||||||
|
+void
|
||||||
|
+channel_list_rport_listener(char *buf, size_t size)
|
||||||
|
+{
|
||||||
|
+ u_int i, j, num_ports = 0;
|
||||||
|
+ int offset = 0;
|
||||||
|
+ int *ports;
|
||||||
|
+ int skip;
|
||||||
|
+
|
||||||
|
+ ports = xcalloc(channels_alloc, sizeof(int));
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < channels_alloc; i++) {
|
||||||
|
+ skip = 0;
|
||||||
|
+ Channel *c = channels[i];
|
||||||
|
+ if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ /* Skip already added ports - IPv4 + IPv6 == same port twice */
|
||||||
|
+ for(j = 0; j < num_ports; j++) {
|
||||||
|
+ if (ports[j] == c->listening_port) {
|
||||||
|
+ skip = 1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if(skip) continue;
|
||||||
|
+
|
||||||
|
+ ports[num_ports] = c->listening_port;
|
||||||
|
+ num_ports++;
|
||||||
|
+
|
||||||
|
+ if(!offset) {
|
||||||
|
+ offset += snprintf(&buf[offset], size - offset, "%d", c->listening_port);
|
||||||
|
+ } else
|
||||||
|
+ offset += snprintf(&buf[offset], size - offset, " %d", c->listening_port);
|
||||||
|
+
|
||||||
|
+ if(offset >= size) {
|
||||||
|
+ error("Exceeded buffer space for remote forwarding ports listing");
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ xfree(ports);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int
|
||||||
|
channel_cancel_rport_listener(const char *host, u_short port)
|
||||||
|
{
|
||||||
|
Only in openssh-6.2p1.patched/: .channels.c.swp
|
||||||
|
diff -ru openssh-6.2p1/channels.h openssh-6.2p1.patched/channels.h
|
||||||
|
--- openssh-6.2p1/channels.h 2012-04-22 03:21:10.000000000 +0200
|
||||||
|
+++ openssh-6.2p1.patched/channels.h 2013-05-09 23:21:37.385423623 +0200
|
||||||
|
@@ -222,6 +222,7 @@
|
||||||
|
void channel_cancel_cleanup(int);
|
||||||
|
int channel_close_fd(int *);
|
||||||
|
void channel_send_window_changes(void);
|
||||||
|
+void channel_list_rport_listener(char *buf, size_t size);
|
||||||
|
|
||||||
|
/* protocol handler */
|
||||||
|
|
||||||
|
diff -ru openssh-6.2p1/session.c openssh-6.2p1.patched/session.c
|
||||||
|
--- openssh-6.2p1/session.c 2013-03-15 01:22:37.000000000 +0100
|
||||||
|
+++ openssh-6.2p1.patched/session.c 2013-05-15 23:27:12.459989713 +0200
|
||||||
|
@@ -1235,6 +1235,9 @@
|
||||||
|
xfree(laddr);
|
||||||
|
child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
|
||||||
|
|
||||||
|
+ channel_list_rport_listener(buf, sizeof buf);
|
||||||
|
+ child_set_env(&env, &envsize, "SSH_REMOTE_FORWARDING_PORTS", buf);
|
||||||
|
+
|
||||||
|
if (s->ttyfd != -1)
|
||||||
|
child_set_env(&env, &envsize, "SSH_TTY", s->tty);
|
||||||
|
if (s->term)
|
||||||
|
Only in openssh-6.2p1.patched/: .session.c.swp
|
Loading…
Reference in a new issue