sshpoke/internal/server/driver/ssh/sshtun/sish_compat.go

77 lines
1.7 KiB
Go
Raw Normal View History

2023-11-18 21:23:29 +03:00
package sshtun
import (
"errors"
"net"
"reflect"
"sync"
"unsafe"
"golang.org/x/crypto/ssh"
)
type sishHostListener struct {
parent *ssh.Client
}
func newSishHostListener(parent *ssh.Client) *sishHostListener {
return &sishHostListener{parent: parent}
}
func (c *sishHostListener) ListenFakeRemoteHost(ep Endpoint) (net.Listener, error) {
c.doHandleForwardsOnce()
m := channelForwardMsg{
ep.Host,
uint32(ep.Port),
}
// send message
ok, resp, err := c.parent.SendRequest("tcpip-forward", true, ssh.Marshal(&m))
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("ssh: tcpip-forward request denied by peer")
}
laddr := &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: ep.Port,
}
if ep.Port == 0 {
var p struct {
Port uint32
}
if err := ssh.Unmarshal(resp, &p); err != nil {
return nil, err
}
laddr.Port = int(p.Port)
}
c.registerForward(laddr)
return nil, nil
}
func (c *sishHostListener) registerForward(addr *net.TCPAddr) {
cl := reflect.ValueOf(c.parent).Elem()
forwardsUn := cl.FieldByName("forwards")
forwards := reflect.NewAt(forwardsUn.Type(), unsafe.Pointer(forwardsUn.UnsafeAddr())).Elem()
forwardVal := forwards.MethodByName("add").Call([]reflect.Value{reflect.ValueOf(addr)})[0]
_ = forwardVal
}
func (c *sishHostListener) doHandleForwardsOnce() {
cl := reflect.ValueOf(c.parent)
clVal := cl.Elem()
onceField := clVal.FieldByName("handleForwardsOnce")
once := reflect.NewAt(onceField.Type(), unsafe.Pointer(onceField.UnsafeAddr())).Interface().(*sync.Once)
handleForwards := clVal.MethodByName("handleForwards")
once.Do(func() {
handleForwards.Call(nil)
})
}
type channelForwardMsg struct {
addr string
rport uint32
}