sshportal/proxy.go

103 lines
2.2 KiB
Go
Raw Normal View History

2017-09-30 19:12:43 +08:00
package main
import (
"errors"
"fmt"
2017-09-30 19:12:43 +08:00
"io"
"log"
"github.com/gliderlabs/ssh"
gossh "golang.org/x/crypto/ssh"
)
2017-12-02 05:17:44 +08:00
func proxy(s ssh.Session, host *Host, hk gossh.HostKeyCallback) error {
2017-12-04 01:18:17 +08:00
config, err := host.clientConfig(s, hk)
2017-10-31 16:24:18 +08:00
if err != nil {
return err
}
rconn, err := gossh.Dial("tcp", host.Addr, config)
2017-09-30 19:12:43 +08:00
if err != nil {
return err
}
2017-12-04 01:18:17 +08:00
defer func() { _ = rconn.Close() }()
2017-09-30 19:12:43 +08:00
rch, rreqs, err := rconn.OpenChannel("session", []byte{})
if err != nil {
return err
}
2017-12-02 05:17:44 +08:00
log.Println("SSH Connection established")
2017-10-30 19:30:34 +08:00
return pipe(s.MaskedReqs(), rreqs, s, rch)
2017-09-30 19:12:43 +08:00
}
func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel) error {
defer func() {
2017-12-04 01:18:17 +08:00
_ = lch.Close()
_ = rch.Close()
2017-09-30 19:12:43 +08:00
}()
errch := make(chan error, 1)
go func() {
_, _ = io.Copy(lch, rch)
errch <- errors.New("lch closed the connection")
}()
go func() {
_, _ = io.Copy(rch, lch)
errch <- errors.New("rch closed the connection")
}()
for {
select {
case req := <-lreqs: // forward ssh requests from local to remote
if req == nil {
return nil
}
b, err := rch.SendRequest(req.Type, req.WantReply, req.Payload)
if err != nil {
return err
}
2017-12-04 01:18:17 +08:00
if err2 := req.Reply(b, nil); err2 != nil {
return err2
}
2017-09-30 19:12:43 +08:00
case req := <-rreqs: // forward ssh requests from remote to local
if req == nil {
return nil
}
b, err := lch.SendRequest(req.Type, req.WantReply, req.Payload)
if err != nil {
return err
}
2017-12-04 01:18:17 +08:00
if err2 := req.Reply(b, nil); err2 != nil {
return err2
}
2017-09-30 19:12:43 +08:00
case err := <-errch:
return err
}
}
}
2017-12-04 01:18:17 +08:00
func (host *Host) clientConfig(_ ssh.Session, hk gossh.HostKeyCallback) (*gossh.ClientConfig, error) {
config := gossh.ClientConfig{
User: host.User,
2017-12-02 05:17:44 +08:00
HostKeyCallback: hk,
Auth: []gossh.AuthMethod{},
}
2017-11-02 06:42:17 +08:00
if host.SSHKey != nil {
signer, err := gossh.ParsePrivateKey([]byte(host.SSHKey.PrivKey))
if err != nil {
return nil, err
}
config.Auth = append(config.Auth, gossh.PublicKeys(signer))
}
if host.Password != "" {
config.Auth = append(config.Auth, gossh.Password(host.Password))
}
if len(config.Auth) == 0 {
return nil, fmt.Errorf("no valid authentication method for host %q", host.Name)
}
return &config, nil
}