From 0264bb72fb28fb15b13afa1b88818945ec5194b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 May 2013 23:29:34 +0200 Subject: [PATCH] ++dynamic port forwarding patch + blog entry Signed-off-by: Nico Schottelius --- ...-using-dynamic-remote-port-forwarding.mdwn | 98 +++++++++++++++++++ ...h-6.2p1-expose-remote-port-forwarding.diff | 82 ++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding.mdwn create mode 100644 blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding/openssh-6.2p1-expose-remote-port-forwarding.diff diff --git a/blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding.mdwn b/blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding.mdwn new file mode 100644 index 00000000..4aabaeb5 --- /dev/null +++ b/blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding.mdwn @@ -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]] diff --git a/blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding/openssh-6.2p1-expose-remote-port-forwarding.diff b/blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding/openssh-6.2p1-expose-remote-port-forwarding.diff new file mode 100644 index 00000000..14381990 --- /dev/null +++ b/blog/openssh-6.2-add-callback-functionality-using-dynamic-remote-port-forwarding/openssh-6.2p1-expose-remote-port-forwarding.diff @@ -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