47df570d18
These updates make it easier to implement and pass custom Session and Context implementations No compatibilty breaking, all tests pass
59 lines
1.2 KiB
Go
59 lines
1.2 KiB
Go
package ssh
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
|
|
gossh "golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
// direct-tcpip data struct as specified in RFC4254, Section 7.2
|
|
type forwardData struct {
|
|
DestinationHost string
|
|
DestinationPort uint32
|
|
|
|
OriginatorHost string
|
|
OriginatorPort uint32
|
|
}
|
|
|
|
func directTcpipHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) {
|
|
d := forwardData{}
|
|
if err := gossh.Unmarshal(newChan.ExtraData(), &d); err != nil {
|
|
newChan.Reject(gossh.ConnectionFailed, "error parsing forward data: "+err.Error())
|
|
return
|
|
}
|
|
|
|
if srv.LocalPortForwardingCallback == nil || !srv.LocalPortForwardingCallback(ctx, d.DestinationHost, d.DestinationPort) {
|
|
newChan.Reject(gossh.Prohibited, "port forwarding is disabled")
|
|
return
|
|
}
|
|
|
|
dest := fmt.Sprintf("%s:%d", d.DestinationHost, d.DestinationPort)
|
|
|
|
var dialer net.Dialer
|
|
dconn, err := dialer.DialContext(ctx, "tcp", dest)
|
|
if err != nil {
|
|
newChan.Reject(gossh.ConnectionFailed, err.Error())
|
|
return
|
|
}
|
|
|
|
ch, reqs, err := newChan.Accept()
|
|
if err != nil {
|
|
dconn.Close()
|
|
return
|
|
}
|
|
go gossh.DiscardRequests(reqs)
|
|
|
|
go func() {
|
|
defer ch.Close()
|
|
defer dconn.Close()
|
|
io.Copy(ch, dconn)
|
|
}()
|
|
go func() {
|
|
defer ch.Close()
|
|
defer dconn.Close()
|
|
io.Copy(dconn, ch)
|
|
}()
|
|
}
|