Of course, the ideal solution would be to use IPv6 :-)
Given that's not ubiquituous, you still need some sort of gateway on
IPv4. What I do is to use an SOCKS5 server, configured to allow inbound
unauthenticated access (on IPv4) and make outbound to local network port
22 only (on IPv6).
Then on the ssh client side:
Host *.yourdomain.com
ProxyCommand sh -c 'nc %h %p || ncat --proxy-type socks5 --proxy
192.0.2.2:22080 %h %p'
Notes:
* 192.0.2.2 is the machine where the SOCKS5 server is running, listening
on port 22080
* The "nc %h %p ||" bit is so that it tries a direct connection first -
assuming you have an AAAA record in the DNS - and fallback to using
SOCKS only if that fails to connect. You can remove this if you *only*
support access via the SOCKS5 proxy.
The SOCKS5 server I'm using is danted, and I'll paste the sanitised
danted.conf below. It's back-to-front compared to normal deployments:
the "internal" interface is the outside public IP, and the "external"
interface is the one which originates connections to your local network.
I've found this works pretty well. The main downside is that you lose
visibility of the original source IPv4 address in your sshd logs. One
way I've thought of handling that is to have the SOCKS5 server bind to a
/96 block of IPv6 addresses, and embed the client's IPv4 address in the
low 32 bits - but that's more code hacking than I had time for.
I can think of variations on this theme. For example, you could choose
to require authentication on the SOCKS5 connection, and each user could
have different credentials that allow them access only to "their" target
server. But in my case, I trust sshd: I allow port 22 from the world
directly via IPv6 anyway, so I have no problem also allowing inbound
SOCKS5 proxying to port 22.
HTH,
Brian.
===== 8< =====
logoutput: stderr
# Accept connections from the outside interface. Use a non-default
# port to be slightly less susceptible to port scanning
internal.protocol: ipv4
internal: 192.0.2.2 port = 22080
# "Outgoing" connections use IPv6 only
external.protocol: ipv6
external: eth0
# methods for client-rules (on initial connection)
clientmethod: none
# methods for socks-rules (during negotiation)
socksmethod: username none
user.privileged: root
user.notprivileged: proxy
user.libwrap: proxy
# The rules prefixed with "client" are checked first and say who is allowed
# and who is not allowed to speak/connect to the server
#
# The "to:" in the "client" context gives the address the connection
# is accepted on, i.e the address the socksserver is listening on, or
# just "0.0.0.0/0" for any address the server is listening on.
client pass {
from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0
}
# you probably don't want people connecting to loopback addresses,
# who knows what could happen then.
socks block {
from: 0.0.0.0/0 to: 127.0.0.0/8
log: connect error
}
# unless you need it, you could block any bind requests.
socks block {
from: 0.0.0.0/0 to: 0.0.0.0/0
command: bind
log: connect error
}
# Allow inbound by hostname to home network SSH (unauthenticated)
socks pass {
from: 0.0.0.0/0 to: .yourdomain.com port=22
protocol: tcp udp
#socksmethod: username none
#user: proxy
}
# Allow inbound by IP to home network SSH (unauthenticated)
socks pass {
from: 0.0.0.0/0 to: 2001:db8::/64 port=22
protocol: tcp udp
#socksmethod: username none
#user: proxy
}
#socks pass {
# from: 0.0.0.0/0 to: 10.0.0.0/8 port=22
# protocol: tcp udp
# #socksmethod: username none
# #user: proxy
#}
# last line, block everyone else. This is the default but if you provide
# one yourself you can specify your own logging/actions
socks block {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: connect error
}
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev