Discussion:
StreamLocal forwarding
(too old to reply)
Rogan Dawes
2016-05-03 11:48:28 UTC
Permalink
Hi folks,

Can nobody help me to figure out why this is not working? I'd like to think
that I have given it a good attempt at figuring it out for myself, but
everything I see says my configuration *should* be working.

Many thanks!

Rogan
Hi folks,
(3rd time I am sending this message, none of the other appear to have
made it through!)
Using "OpenSSH_6.9p1 Ubuntu-2ubuntu0.1, OpenSSL 1.0.2d 9 Jul 2015" on
the server, "OpenSSH_7.2p2, OpenSSL 1.0.2g 1 Mar 2016" on the client.
I am trying to use sshtunnel with StreamLocal forwarding to enable me
to connect back to the client's ssh port, without having to arbitrate
ports between clients.
The idea is to configure the server to allow StreamLocalForwarding via
a unique Unix socket on the host, that relays back to the client.
i.e. on the client (named gateway for this example, but will be unique
/usr/bin/ssh -o CheckHostIP=yes -o LogLevel=INFO -o
ServerAliveCountMax=3 -o ServerAliveInterval=5 -o
StrictHostKeyChecking=yes -o TCPKeepAlive=yes -o
StreamLocalBindUnlink=yes -o ExitOnForwardFailure=yes -o BatchMode=yes
Match User sshvpn
ChrootDirectory /var/sshvpn/
AllowTCPForwarding no
AllowStreamLocalForwarding yes
StreamLocalBindUnlink yes
So, it works fine the first time, when the socket does not exist. Once
the connection terminates, and the client attempts to log in again, it
debug1: user sshvpn matched 'User sshvpn' at line 89
debug3: match found
debug3: reprocess config:90 setting ChrootDirectory /var/sshvpn/
debug3: reprocess config:91 setting AllowTCPForwarding no
debug3: reprocess config:92 setting AllowStreamLocalForwarding yes
debug3: reprocess config:93 setting StreamLocalBindUnlink yes
[...snip...]
debug1: server_input_global_request: rtype
debug1: server_input_global_request: streamlocal-forward listen path
/sshvpn/gateway
debug3: channel_setup_fwd_listener_streamlocal: type 19 path
/sshvpn/gateway
bind: Address already in use
unix_listener: cannot bind to path: /sshvpn/gateway
I am aware of the StreamLocalBindUnlink option, and you can see that
it is set on both the client and the server, but it doesn't seem to be
effective.
24079 write(2, "debug3: channel_setup_fwd_listen"..., 78) = 78
24079 umask(0177) = 02
24079 socket(1, 1, 0) = 8
24079 bind(8, 0x7ffc4f8915c0, 110, -1) = -1
24079 __errno_location() = 0x7f03f55a5710
24079 strerror(98) = "Address
already in use"
From this, it appears that there is no attempt to unlink the socket if
it already exists, as would be expected from this code
(
https://github.com/openssh/openssh-portable/blob/7de4b03a6e4071d454b72927ffaf52949fa34545/misc.c#L1083
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
saved_errno = errno;
error("socket: %.100s", strerror(errno));
errno = saved_errno;
return -1;
}
if (unlink_first == 1) {
if (unlink(path) != 0 && errno != ENOENT)
error("unlink(%s): %.100s", path, strerror(errno));
}
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
saved_errno = errno;
error("bind: %.100s", strerror(errno));
close(sock);
error("%s: cannot bind to path: %s", __func__, path);
errno = saved_errno;
return -1;
}
What am I missing?
Rogan
Damien Miller
2016-05-03 12:21:25 UTC
Permalink
Hi,

The code definitely attempts to unlink any old listener
beforehand (see misc.c:unix_listener()) so I don't understand why
that isn't being called. You might try simulating your configuration
using sshd's -T and -C to make sure the flag is correctly being set.

Could chroot be interfering? Some platforms implement additional
restrictions on devices and sockets inside chroot.

-d
Post by Rogan Dawes
Hi folks,
Can nobody help me to figure out why this is not working? I'd like to think
that I have given it a good attempt at figuring it out for myself, but
everything I see says my configuration *should* be working.
Many thanks!
Rogan
Post by Rogan Dawes
Hi folks,
(3rd time I am sending this message, none of the other appear to have
made it through!)
Using "OpenSSH_6.9p1 Ubuntu-2ubuntu0.1, OpenSSL 1.0.2d 9 Jul 2015" on
the server, "OpenSSH_7.2p2, OpenSSL 1.0.2g 1 Mar 2016" on the client.
I am trying to use sshtunnel with StreamLocal forwarding to enable me
to connect back to the client's ssh port, without having to arbitrate
ports between clients.
The idea is to configure the server to allow StreamLocalForwarding via
a unique Unix socket on the host, that relays back to the client.
i.e. on the client (named gateway for this example, but will be unique
/usr/bin/ssh -o CheckHostIP=yes -o LogLevel=INFO -o
ServerAliveCountMax=3 -o ServerAliveInterval=5 -o
StrictHostKeyChecking=yes -o TCPKeepAlive=yes -o
StreamLocalBindUnlink=yes -o ExitOnForwardFailure=yes -o BatchMode=yes
Match User sshvpn
ChrootDirectory /var/sshvpn/
AllowTCPForwarding no
AllowStreamLocalForwarding yes
StreamLocalBindUnlink yes
So, it works fine the first time, when the socket does not exist. Once
the connection terminates, and the client attempts to log in again, it
debug1: user sshvpn matched 'User sshvpn' at line 89
debug3: match found
debug3: reprocess config:90 setting ChrootDirectory /var/sshvpn/
debug3: reprocess config:91 setting AllowTCPForwarding no
debug3: reprocess config:92 setting AllowStreamLocalForwarding yes
debug3: reprocess config:93 setting StreamLocalBindUnlink yes
[...snip...]
debug1: server_input_global_request: rtype
debug1: server_input_global_request: streamlocal-forward listen path
/sshvpn/gateway
debug3: channel_setup_fwd_listener_streamlocal: type 19 path
/sshvpn/gateway
bind: Address already in use
unix_listener: cannot bind to path: /sshvpn/gateway
I am aware of the StreamLocalBindUnlink option, and you can see that
it is set on both the client and the server, but it doesn't seem to be
effective.
24079 write(2, "debug3: channel_setup_fwd_listen"..., 78) = 78
24079 umask(0177) = 02
24079 socket(1, 1, 0) = 8
24079 bind(8, 0x7ffc4f8915c0, 110, -1) = -1
24079 __errno_location() = 0x7f03f55a5710
24079 strerror(98) = "Address
already in use"
From this, it appears that there is no attempt to unlink the socket if
it already exists, as would be expected from this code
(
https://github.com/openssh/openssh-portable/blob/7de4b03a6e4071d454b72927ffaf52949fa34545/misc.c#L1083
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
saved_errno = errno;
error("socket: %.100s", strerror(errno));
errno = saved_errno;
return -1;
}
if (unlink_first == 1) {
if (unlink(path) != 0 && errno != ENOENT)
error("unlink(%s): %.100s", path, strerror(errno));
}
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
saved_errno = errno;
error("bind: %.100s", strerror(errno));
close(sock);
error("%s: cannot bind to path: %s", __func__, path);
errno = saved_errno;
return -1;
}
What am I missing?
Rogan
_______________________________________________
openssh-unix-dev mailing list
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Rogan Dawes
2016-05-03 15:14:44 UTC
Permalink
Hi Damien,

Thanks for the response!

I tried moving the StreamLocalBindUnlink directive outside of the Match
rule, and it worked. But that doesn't explain why the Match was not
correctly setting the directive:

This is running on an alternate port with -ddd:

debug3: checking match for 'User sshvpn' user sshvpn host 196.209.244.243
addr 196.209.244.243 laddr 176.9.9.247 lport 52221
debug1: user sshvpn matched 'User sshvpn' at line 91
debug3: match found
debug3: reprocess config:92 setting ChrootDirectory /var/sshvpn/
debug3: reprocess config:93 setting AllowTCPForwarding no
debug3: reprocess config:94 setting AllowStreamLocalForwarding yes
debug3: reprocess config:95 setting StreamLocalBindUnlink yes

And, surprisingly, even having set the directive outside the Match block,
the following command still doesn't show streamlocalbindunlink set:

sshd -T -C "user=sshvpn,host=196.209.244.243,addr=196.209.244.243" | grep
-i stream
streamlocalbindmask 0177
allowstreamlocalforwarding yes

That just looks like default settings.

Confusing! Anyway, thank you for the help, I now have it working, although
I wonder about the other Matched directives. At least I know that the
chroot is working!

Rogan
Post by Damien Miller
Hi,
The code definitely attempts to unlink any old listener
beforehand (see misc.c:unix_listener()) so I don't understand why
that isn't being called. You might try simulating your configuration
using sshd's -T and -C to make sure the flag is correctly being set.
Could chroot be interfering? Some platforms implement additional
restrictions on devices and sockets inside chroot.
-d
Post by Rogan Dawes
Hi folks,
Can nobody help me to figure out why this is not working? I'd like to
think
Post by Rogan Dawes
that I have given it a good attempt at figuring it out for myself, but
everything I see says my configuration *should* be working.
Many thanks!
Rogan
Post by Rogan Dawes
Hi folks,
(3rd time I am sending this message, none of the other appear to have
made it through!)
Using "OpenSSH_6.9p1 Ubuntu-2ubuntu0.1, OpenSSL 1.0.2d 9 Jul 2015" on
the server, "OpenSSH_7.2p2, OpenSSL 1.0.2g 1 Mar 2016" on the client.
I am trying to use sshtunnel with StreamLocal forwarding to enable me
to connect back to the client's ssh port, without having to arbitrate
ports between clients.
The idea is to configure the server to allow StreamLocalForwarding via
a unique Unix socket on the host, that relays back to the client.
i.e. on the client (named gateway for this example, but will be unique
/usr/bin/ssh -o CheckHostIP=yes -o LogLevel=INFO -o
ServerAliveCountMax=3 -o ServerAliveInterval=5 -o
StrictHostKeyChecking=yes -o TCPKeepAlive=yes -o
StreamLocalBindUnlink=yes -o ExitOnForwardFailure=yes -o BatchMode=yes
Match User sshvpn
ChrootDirectory /var/sshvpn/
AllowTCPForwarding no
AllowStreamLocalForwarding yes
StreamLocalBindUnlink yes
So, it works fine the first time, when the socket does not exist. Once
the connection terminates, and the client attempts to log in again, it
debug1: user sshvpn matched 'User sshvpn' at line 89
debug3: match found
debug3: reprocess config:90 setting ChrootDirectory /var/sshvpn/
debug3: reprocess config:91 setting AllowTCPForwarding no
debug3: reprocess config:92 setting AllowStreamLocalForwarding yes
debug3: reprocess config:93 setting StreamLocalBindUnlink yes
[...snip...]
debug1: server_input_global_request: rtype
debug1: server_input_global_request: streamlocal-forward listen path
/sshvpn/gateway
debug3: channel_setup_fwd_listener_streamlocal: type 19 path
/sshvpn/gateway
bind: Address already in use
unix_listener: cannot bind to path: /sshvpn/gateway
I am aware of the StreamLocalBindUnlink option, and you can see that
it is set on both the client and the server, but it doesn't seem to be
effective.
24079 write(2, "debug3: channel_setup_fwd_listen"..., 78) = 78
24079 umask(0177) = 02
24079 socket(1, 1, 0) = 8
24079 bind(8, 0x7ffc4f8915c0, 110, -1) = -1
24079 __errno_location() =
0x7f03f55a5710
Post by Rogan Dawes
Post by Rogan Dawes
24079 strerror(98) = "Address
already in use"
From this, it appears that there is no attempt to unlink the socket if
it already exists, as would be expected from this code
(
https://github.com/openssh/openssh-portable/blob/7de4b03a6e4071d454b72927ffaf52949fa34545/misc.c#L1083
Post by Rogan Dawes
Post by Rogan Dawes
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
saved_errno = errno;
error("socket: %.100s", strerror(errno));
errno = saved_errno;
return -1;
}
if (unlink_first == 1) {
if (unlink(path) != 0 && errno != ENOENT)
error("unlink(%s): %.100s", path, strerror(errno));
}
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
saved_errno = errno;
error("bind: %.100s", strerror(errno));
close(sock);
error("%s: cannot bind to path: %s", __func__, path);
errno = saved_errno;
return -1;
}
What am I missing?
Rogan
_______________________________________________
openssh-unix-dev mailing list
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Damien Miller
2016-05-03 15:23:40 UTC
Permalink
Post by Rogan Dawes
Hi Damien,
Thanks for the response!
I tried moving the StreamLocalBindUnlink directive outside of the Match
rule, and it worked. But that doesn't explain why the Match was not
debug3: checking match for 'User sshvpn' user sshvpn host 196.209.244.243
addr 196.209.244.243 laddr 176.9.9.247 lport 52221
debug1: user sshvpn matched 'User sshvpn' at line 91
debug3: match found
debug3: reprocess config:92 setting ChrootDirectory /var/sshvpn/
debug3: reprocess config:93 setting AllowTCPForwarding no
debug3: reprocess config:94 setting AllowStreamLocalForwarding yes
debug3: reprocess config:95 setting StreamLocalBindUnlink yes
And, surprisingly, even having set the directive outside the Match block,
sshd -T -C "user=sshvpn,host=196.209.244.243,addr=196.209.244.243" | grep -i
stream
streamlocalbindmask 0177
allowstreamlocalforwarding yes
oh, that's a bug in the config dump support.

diff --git a/servconf.c b/servconf.c
index 6111c5a..2094c48 100644
--- a/servconf.c
+++ b/servconf.c
@@ -2293,6 +2293,7 @@ dump_config(ServerOptions *o)
dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
+ dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
Damien Miller
2016-05-03 15:49:08 UTC
Permalink
Post by Damien Miller
Post by Rogan Dawes
And, surprisingly, even having set the directive outside the Match block,
sshd -T -C "user=sshvpn,host=196.209.244.243,addr=196.209.244.243" | grep -i
stream
streamlocalbindmask 0177
allowstreamlocalforwarding yes
oh, that's a bug in the config dump support.
... and with that fixed the real bug reveals itself:

diff --git a/servconf.c b/servconf.c
index 6111c5a..5e8b7ca 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1994,6 +1994,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
M_CP_INTOPT(allow_agent_forwarding);
M_CP_INTOPT(permit_tun);
M_CP_INTOPT(fwd_opts.gateway_ports);
+ M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
M_CP_INTOPT(x11_display_offset);
M_CP_INTOPT(x11_forwarding);
M_CP_INTOPT(x11_use_localhost);
@@ -2006,6 +2007,12 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);

+ /* This is a mode_t, so can't use M_CP_INTOPT */
+ if (src->fwd_opts.streamlocal_bind_mask == (mode_t)-1) {
+ dst->fwd_opts.streamlocal_bind_mask =
+ src->fwd_opts.streamlocal_bind_mask;
+ }
+
/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
#define M_CP_STROPT(n) do {\
if (src->n != NULL && dst->n != src->n) { \
Rogan Dawes
2016-05-03 16:05:56 UTC
Permalink
Haha!

Glad to know i wasn't just doing something stupid!

Thanks for your help!

Rogan
Post by Rogan Dawes
Post by Damien Miller
Post by Rogan Dawes
And, surprisingly, even having set the directive outside the Match
block,
Post by Damien Miller
Post by Rogan Dawes
sshd -T -C "user=sshvpn,host=196.209.244.243,addr=196.209.244.243" |
grep -i
Post by Damien Miller
Post by Rogan Dawes
stream
streamlocalbindmask 0177
allowstreamlocalforwarding yes
oh, that's a bug in the config dump support.
diff --git a/servconf.c b/servconf.c
index 6111c5a..5e8b7ca 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1994,6 +1994,7 @@ copy_set_server_options(ServerOptions *dst,
ServerOptions *src, int preauth)
M_CP_INTOPT(allow_agent_forwarding);
M_CP_INTOPT(permit_tun);
M_CP_INTOPT(fwd_opts.gateway_ports);
+ M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
M_CP_INTOPT(x11_display_offset);
M_CP_INTOPT(x11_forwarding);
M_CP_INTOPT(x11_use_localhost);
@@ -2006,6 +2007,12 @@ copy_set_server_options(ServerOptions *dst,
ServerOptions *src, int preauth)
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);
+ /* This is a mode_t, so can't use M_CP_INTOPT */
+ if (src->fwd_opts.streamlocal_bind_mask == (mode_t)-1) {
+ dst->fwd_opts.streamlocal_bind_mask =
+ src->fwd_opts.streamlocal_bind_mask;
+ }
+
/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here
*/
#define M_CP_STROPT(n) do {\
if (src->n != NULL && dst->n != src->n) { \
Damien Miller
2016-05-03 15:59:57 UTC
Permalink
Post by Damien Miller
Post by Rogan Dawes
And, surprisingly, even having set the directive outside the Match block,
sshd -T -C "user=sshvpn,host=196.209.244.243,addr=196.209.244.243" | grep -i
stream
streamlocalbindmask 0177
allowstreamlocalforwarding yes
oh, that's a bug in the config dump support.
both fixes committed and in HEAD:

commit cfefbcea1057c2623e76c579174a4107a0b6e6cd
Author: ***@openbsd.org <***@openbsd.org>
Date: Tue May 3 15:57:39 2016 +0000

upstream commit

fix overriding of StreamLocalBindMask and
StreamLocalBindUnlink in Match blocks; found the hard way by Rogan Dawes

Upstream-ID: 940bc69ec0249ab428d24ccd0722ce35cb932ee2

commit 771c2f51ffc0c9a2877b7892fada0c77bd1f6549
Author: ***@openbsd.org <***@openbsd.org>
Date: Tue May 3 15:25:06 2016 +0000

upstream commit

don't forget to include StreamLocalBindUnlink in the
config dump output

Upstream-ID: 14a6d970b3b45c8e94272e3c661e9a0b2a0ee7cb

Loading...