++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