ssh: fake remote host support
This commit is contained in:
parent
99b5b8c775
commit
273482e3fa
@ -45,7 +45,7 @@ func New(ctx context.Context, name string, params config.DriverParams) (base.Dri
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *SSH) forward(val sshtun.Forward) conn {
|
func (d *SSH) forward(val sshtun.Forward) conn {
|
||||||
tun := sshtun.New(d.params.Address, d.params.Auth.User, d.params.DisableRemoteHostResolve, val, d.auth, d.Log())
|
tun := sshtun.New(d.params.Address, d.params.Auth.User, d.params.FakeRemoteHost, val, d.auth, d.Log())
|
||||||
ctx, cancel := context.WithCancel(d.Context())
|
ctx, cancel := context.WithCancel(d.Context())
|
||||||
go tun.Connect(ctx, sshtun.StdoutPrinterSessionCallback(d.Log().With("ssh-output", val.Remote.String())))
|
go tun.Connect(ctx, sshtun.StdoutPrinterSessionCallback(d.Log().With("ssh-output", val.Remote.String())))
|
||||||
return conn{ctx: ctx, cancel: cancel, tun: tun}
|
return conn{ctx: ctx, cancel: cancel, tun: tun}
|
||||||
|
@ -6,16 +6,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Address string `mapstructure:"address" validate:"required"`
|
Address string `mapstructure:"address" validate:"required"`
|
||||||
DefaultHost *string `mapstructure:"default_host,omitempty"`
|
DefaultHost *string `mapstructure:"default_host,omitempty"`
|
||||||
ForwardPort uint16 `mapstructure:"forward_port"`
|
ForwardPort uint16 `mapstructure:"forward_port"`
|
||||||
Auth types.Auth `mapstructure:"auth"`
|
Auth types.Auth `mapstructure:"auth"`
|
||||||
KeepAlive types.KeepAlive `mapstructure:"keepalive"`
|
KeepAlive types.KeepAlive `mapstructure:"keepalive"`
|
||||||
Domain string `mapstructure:"domain"`
|
Domain string `mapstructure:"domain"`
|
||||||
DomainProto string `mapstructure:"domain_proto"`
|
DomainProto string `mapstructure:"domain_proto"`
|
||||||
DomainExtractRegex string `mapstructure:"domain_extract_regex" validate:"validregexp"`
|
DomainExtractRegex string `mapstructure:"domain_extract_regex" validate:"validregexp"`
|
||||||
Mode types.DomainMode `mapstructure:"mode" validate:"required,oneof=single multi"`
|
Mode types.DomainMode `mapstructure:"mode" validate:"required,oneof=single multi"`
|
||||||
DisableRemoteHostResolve bool `mapstructure:"disable_remote_host_resolve"`
|
FakeRemoteHost bool `mapstructure:"fake_remote_host"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Params) Validate() error {
|
func (p *Params) Validate() error {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -173,15 +174,14 @@ func (c *Tunnel) ipFromAddr(addr net.Addr) net.IP {
|
|||||||
func handleReverseForwardConn(client net.Conn, forward Forward, log *zap.SugaredLogger) {
|
func handleReverseForwardConn(client net.Conn, forward Forward, log *zap.SugaredLogger) {
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
log.Debugf("%s connected", client.RemoteAddr())
|
|
||||||
defer log.Debug("closed")
|
|
||||||
|
|
||||||
remote, err := net.Dial("tcp", forward.Local.String())
|
remote, err := net.Dial("tcp", forward.Local.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("dial INTO local service error: %s", err.Error())
|
log.Errorf("cannot dial local service: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("proxying %s <-> %s", forward.Local.String(), client.RemoteAddr())
|
||||||
|
|
||||||
// pipe data in both directions:
|
// pipe data in both directions:
|
||||||
// - client => remote
|
// - client => remote
|
||||||
// - remote => client
|
// - remote => client
|
||||||
@ -194,6 +194,10 @@ func handleReverseForwardConn(client net.Conn, forward Forward, log *zap.Sugared
|
|||||||
bidipipe.WithName("client", client),
|
bidipipe.WithName("client", client),
|
||||||
bidipipe.WithName("remote", remote),
|
bidipipe.WithName("remote", remote),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
// we can safely ignore those errors.
|
||||||
|
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||||
|
return
|
||||||
|
}
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--- pkg/proto/ssh/tcpip.go 2023-11-18 21:39:15.394837005 +0300
|
--- cryptolib/ssh/tcpip.go 2023-11-18 22:20:50.609146922 +0300
|
||||||
+++ pkg/proto/ssh/tcpip.go 2023-11-18 21:38:25.706173351 +0300
|
+++ pkg/proto/ssh/tcpip.go 2023-11-18 22:19:08.891684669 +0300
|
||||||
@@ -101,14 +101,18 @@
|
@@ -101,14 +101,18 @@
|
||||||
// ListenTCP requests the remote peer open a listening socket
|
// ListenTCP requests the remote peer open a listening socket
|
||||||
// on laddr. Incoming connections will be available by calling
|
// on laddr. Incoming connections will be available by calling
|
||||||
@ -10,7 +10,7 @@
|
|||||||
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
|
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
|
||||||
return c.autoPortListenWorkaround(laddr)
|
return c.autoPortListenWorkaround(laddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
+ host := laddr.IP.String()
|
+ host := laddr.IP.String()
|
||||||
+ if len(fakeHost) > 0 {
|
+ if len(fakeHost) > 0 {
|
||||||
+ host = fakeHost[0]
|
+ host = fakeHost[0]
|
||||||
@ -21,3 +21,76 @@
|
|||||||
uint32(laddr.Port),
|
uint32(laddr.Port),
|
||||||
}
|
}
|
||||||
// send message
|
// send message
|
||||||
|
@@ -133,7 +137,12 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this forward, using the port number we obtained.
|
||||||
|
- ch := c.forwards.add(laddr)
|
||||||
|
+ var ch chan forward
|
||||||
|
+ if len(fakeHost) > 0 {
|
||||||
|
+ ch = c.forwards.add(laddr, fakeHost[0])
|
||||||
|
+ } else {
|
||||||
|
+ ch = c.forwards.add(laddr)
|
||||||
|
+ }
|
||||||
|
|
||||||
|
return &tcpListener{laddr, c, ch}, nil
|
||||||
|
}
|
||||||
|
@@ -142,7 +151,9 @@
|
||||||
|
// forward requests and the tcpListeners.
|
||||||
|
type forwardList struct {
|
||||||
|
sync.Mutex
|
||||||
|
- entries []forwardEntry
|
||||||
|
+ fdm sync.RWMutex
|
||||||
|
+ fakeDomainsMap map[string]string
|
||||||
|
+ entries []forwardEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwardEntry represents an established mapping of a laddr on a
|
||||||
|
@@ -160,17 +171,30 @@
|
||||||
|
raddr net.Addr // the raddr of the incoming connection
|
||||||
|
}
|
||||||
|
|
||||||
|
-func (l *forwardList) add(addr net.Addr) chan forward {
|
||||||
|
+func (l *forwardList) add(addr net.Addr, fakeHost ...string) chan forward {
|
||||||
|
l.Lock()
|
||||||
|
defer l.Unlock()
|
||||||
|
f := forwardEntry{
|
||||||
|
laddr: addr,
|
||||||
|
c: make(chan forward, 1),
|
||||||
|
}
|
||||||
|
+ if len(fakeHost) > 0 {
|
||||||
|
+ if l.fakeDomainsMap == nil {
|
||||||
|
+ l.fakeDomainsMap = make(map[string]string)
|
||||||
|
+ }
|
||||||
|
+ defer l.fdm.Unlock()
|
||||||
|
+ l.fdm.Lock()
|
||||||
|
+ l.fakeDomainsMap[fakeHost[0]] = l.ipFromAddr(addr)
|
||||||
|
+ }
|
||||||
|
l.entries = append(l.entries, f)
|
||||||
|
return f.c
|
||||||
|
}
|
||||||
|
|
||||||
|
+func (l *forwardList) ipFromAddr(addr net.Addr) string {
|
||||||
|
+ host, _, _ := net.SplitHostPort(addr.String())
|
||||||
|
+ return host
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// See RFC 4254, section 7.2
|
||||||
|
type forwardedTCPPayload struct {
|
||||||
|
Addr string
|
||||||
|
@@ -206,6 +230,15 @@
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
+ l.fdm.RLock()
|
||||||
|
+ if addr, ok := l.fakeDomainsMap[payload.Addr]; ok {
|
||||||
|
+ payload.Addr = addr
|
||||||
|
+ }
|
||||||
|
+ if addr, ok := l.fakeDomainsMap[payload.OriginAddr]; ok {
|
||||||
|
+ payload.OriginAddr = addr
|
||||||
|
+ }
|
||||||
|
+ l.fdm.RUnlock()
|
||||||
|
+
|
||||||
|
// RFC 4254 section 7.2 specifies that incoming
|
||||||
|
// addresses should list the address, in string
|
||||||
|
// format. It is implied that this should be an IP
|
||||||
|
@ -137,7 +137,12 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr, fakeHost ...string) (net.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register this forward, using the port number we obtained.
|
// Register this forward, using the port number we obtained.
|
||||||
ch := c.forwards.add(laddr)
|
var ch chan forward
|
||||||
|
if len(fakeHost) > 0 {
|
||||||
|
ch = c.forwards.add(laddr, fakeHost[0])
|
||||||
|
} else {
|
||||||
|
ch = c.forwards.add(laddr)
|
||||||
|
}
|
||||||
|
|
||||||
return &tcpListener{laddr, c, ch}, nil
|
return &tcpListener{laddr, c, ch}, nil
|
||||||
}
|
}
|
||||||
@ -146,7 +151,9 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr, fakeHost ...string) (net.Listener
|
|||||||
// forward requests and the tcpListeners.
|
// forward requests and the tcpListeners.
|
||||||
type forwardList struct {
|
type forwardList struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
entries []forwardEntry
|
fdm sync.RWMutex
|
||||||
|
fakeDomainsMap map[string]string
|
||||||
|
entries []forwardEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
// forwardEntry represents an established mapping of a laddr on a
|
// forwardEntry represents an established mapping of a laddr on a
|
||||||
@ -164,17 +171,30 @@ type forward struct {
|
|||||||
raddr net.Addr // the raddr of the incoming connection
|
raddr net.Addr // the raddr of the incoming connection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *forwardList) add(addr net.Addr) chan forward {
|
func (l *forwardList) add(addr net.Addr, fakeHost ...string) chan forward {
|
||||||
l.Lock()
|
l.Lock()
|
||||||
defer l.Unlock()
|
defer l.Unlock()
|
||||||
f := forwardEntry{
|
f := forwardEntry{
|
||||||
laddr: addr,
|
laddr: addr,
|
||||||
c: make(chan forward, 1),
|
c: make(chan forward, 1),
|
||||||
}
|
}
|
||||||
|
if len(fakeHost) > 0 {
|
||||||
|
if l.fakeDomainsMap == nil {
|
||||||
|
l.fakeDomainsMap = make(map[string]string)
|
||||||
|
}
|
||||||
|
defer l.fdm.Unlock()
|
||||||
|
l.fdm.Lock()
|
||||||
|
l.fakeDomainsMap[fakeHost[0]] = l.ipFromAddr(addr)
|
||||||
|
}
|
||||||
l.entries = append(l.entries, f)
|
l.entries = append(l.entries, f)
|
||||||
return f.c
|
return f.c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *forwardList) ipFromAddr(addr net.Addr) string {
|
||||||
|
host, _, _ := net.SplitHostPort(addr.String())
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
// See RFC 4254, section 7.2
|
// See RFC 4254, section 7.2
|
||||||
type forwardedTCPPayload struct {
|
type forwardedTCPPayload struct {
|
||||||
Addr string
|
Addr string
|
||||||
@ -210,6 +230,15 @@ func (l *forwardList) handleChannels(in <-chan NewChannel) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l.fdm.RLock()
|
||||||
|
if addr, ok := l.fakeDomainsMap[payload.Addr]; ok {
|
||||||
|
payload.Addr = addr
|
||||||
|
}
|
||||||
|
if addr, ok := l.fakeDomainsMap[payload.OriginAddr]; ok {
|
||||||
|
payload.OriginAddr = addr
|
||||||
|
}
|
||||||
|
l.fdm.RUnlock()
|
||||||
|
|
||||||
// RFC 4254 section 7.2 specifies that incoming
|
// RFC 4254 section 7.2 specifies that incoming
|
||||||
// addresses should list the address, in string
|
// addresses should list the address, in string
|
||||||
// format. It is implied that this should be an IP
|
// format. It is implied that this should be an IP
|
||||||
|
Loading…
Reference in New Issue
Block a user