Пример #1
0
func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.Client, error) {
	sshd, err := exec.LookPath("sshd")
	if err != nil {
		s.t.Skipf("skipping test: %v", err)
	}

	c1, c2, err := unixConnection()
	if err != nil {
		s.t.Fatalf("unixConnection: %v", err)
	}

	s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e")
	f, err := c2.File()
	if err != nil {
		s.t.Fatalf("UnixConn.File: %v", err)
	}
	defer f.Close()
	s.cmd.Stdin = f
	s.cmd.Stdout = f
	s.cmd.Stderr = &s.output
	if err := s.cmd.Start(); err != nil {
		s.t.Fail()
		s.Shutdown()
		s.t.Fatalf("s.cmd.Start: %v", err)
	}
	s.clientConn = c1
	conn, chans, reqs, err := ssh.NewClientConn(c1, "", config)
	if err != nil {
		return nil, err
	}
	return ssh.NewClient(conn, chans, reqs), nil
}
Пример #2
0
func (config BeaconConfig) Dial() (*ssh.Client, error) {
	workerPrivateKeyBytes, err := ioutil.ReadFile(string(config.WorkerPrivateKey))
	if err != nil {
		return nil, fmt.Errorf("failed to read worker private key: %s", err)
	}

	workerPrivateKey, err := ssh.ParsePrivateKey(workerPrivateKeyBytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse worker private key: %s", err)
	}

	tsaAddr := fmt.Sprintf("%s:%d", config.Host, config.Port)

	conn, err := net.DialTimeout("tcp", tsaAddr, 10*time.Second)
	if err != nil {
		return nil, fmt.Errorf("failed to connect to TSA:", err)
	}

	clientConfig := &ssh.ClientConfig{
		User: "******", // doesn't matter

		HostKeyCallback: config.checkHostKey,

		Auth: []ssh.AuthMethod{ssh.PublicKeys(workerPrivateKey)},
	}

	clientConn, chans, reqs, err := ssh.NewClientConn(conn, tsaAddr, clientConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to construct client connection:", err)
	}

	return ssh.NewClient(clientConn, chans, reqs), nil
}
Пример #3
0
func executeCmd(cmd, hostname string, config *ssh.ClientConfig, timeout time.Duration) (string, error) {
	// Dial up TCP connection to remote machine.
	conn, err := net.Dial("tcp", hostname+":22")
	if err != nil {
		return "", fmt.Errorf("Failed to ssh connect to %s. Make sure \"PubkeyAuthentication yes\" is in your sshd_config: %s", hostname, err)
	}
	defer util.Close(conn)
	util.LogErr(conn.SetDeadline(time.Now().Add(timeout)))

	// Create new SSH client connection.
	sshConn, sshChan, req, err := ssh.NewClientConn(conn, hostname+":22", config)
	if err != nil {
		return "", fmt.Errorf("Failed to ssh connect to %s: %s", hostname, err)
	}
	// Use client connection to create new client.
	client := ssh.NewClient(sshConn, sshChan, req)

	// Client connections can support multiple interactive sessions.
	session, err := client.NewSession()
	if err != nil {
		return "", fmt.Errorf("Failed to ssh connect to %s: %s", hostname, err)
	}

	var stdoutBuf bytes.Buffer
	session.Stdout = &stdoutBuf
	if err := session.Run(cmd); err != nil {
		return "", fmt.Errorf("Errored or Timeout out while running \"%s\" on %s: %s", cmd, hostname, err)
	}
	return stdoutBuf.String(), nil
}
Пример #4
0
func DialSSHTimeout(network, addr string, config *ssh.ClientConfig, timeout time.Duration) (*ssh.Client, error) {
	conn, err := net.DialTimeout(network, addr, timeout)
	if err != nil {
		return nil, err
	}
	timeoutConn := &SSHConn{conn, timeout, timeout}
	c, chans, reqs, err := ssh.NewClientConn(timeoutConn, addr, config)
	if err != nil {
		return nil, err
	}
	client := ssh.NewClient(c, chans, reqs)

	// this sends keepalive packets every 3 seconds
	// there's no useful response from these, so we can just abort if there's an error
	go func() {
		t := time.NewTicker(KEEPALIVE_INTERVAL)
		defer t.Stop()
		for {
			<-t.C
			_, _, err := client.Conn.SendRequest("*****@*****.**", true, nil)
			if err != nil {
				log.Fatalf("Remote server did not respond to keepalive.")
				return
			}
		}
	}()
	return client, nil
}
Пример #5
0
func (c *comm) reconnect() error {
	// Close previous connection.
	if c.conn != nil {
		c.Close()
	}

	var err error
	c.conn, err = c.config.Connection()
	if err != nil {
		// Explicitly set this to the REAL nil. Connection() can return
		// a nil implementation of net.Conn which will make the
		// "if c.conn == nil" check fail above. Read here for more information
		// on this psychotic language feature:
		//
		// http://golang.org/doc/faq#nil_error
		c.conn = nil
		c.config.Logger.Error("reconnection error", "error", err)
		return err
	}

	sshConn, sshChan, req, err := ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
	if err != nil {
		c.config.Logger.Error("handshake error", "error", err)
		c.Close()
		return err
	}
	if sshConn != nil {
		c.client = ssh.NewClient(sshConn, sshChan, req)
	}
	c.connectToAgent()

	return nil
}
Пример #6
0
//DialClient returns two channels where one returns a ssh.Client and the other and error
func DialClient(dial, expire time.Duration, ip string, conf *ssh.ClientConfig, retry <-chan struct{}) (*ssh.Client, error) {

	flux.Report(nil, fmt.Sprintf("MakeDial for %s for dailing at %+s and expiring in %+s", conf.User, dial, expire))

	cons := make(chan *ssh.Client)
	errs := make(chan error)

	var con net.Conn
	var sc ssh.Conn
	var chans <-chan ssh.NewChannel
	var req <-chan *ssh.Request
	var err error

	flux.GoDefer("MakeDial", func() {
		con, err = net.DialTimeout("tcp", ip, dial)

		if err != nil {
			flux.Report(err, fmt.Sprintf("MakeDial:Before for %s net.DailTimeout", ip))
			errs <- err
			return
		}

		sc, chans, req, err = ssh.NewClientConn(con, ip, conf)

		if err != nil {
			flux.Report(err, fmt.Sprintf("MakeDial:After for %s ssh.NewClientConn", ip))
			errs <- err
			return
		}

		flux.Report(nil, fmt.Sprintf("MakeDial initiating NewClient for %s", ip))
		cons <- ssh.NewClient(sc, chans, req)
		return
	})

	expiration := threshold(expire)

	go func() {
		for _ = range retry {
			expiration = threshold(expire)
		}
	}()

	select {
	case err := <-errs:
		flux.Report(err, fmt.Sprintf("NewClient Ending!"))
		return nil, err
	case som := <-cons:
		flux.Report(nil, fmt.Sprintf("NewClient Created!"))
		expiration = nil
		return som, nil
	case <-expiration:
		flux.Report(nil, fmt.Sprintf("MakeDial Expired for %s!", ip))
		defer con.Close()
		if sc != nil {
			sc.Close()
		}
		return nil, ErrTimeout
	}
}
Пример #7
0
func connect(username, host string, authMethod ssh.AuthMethod, timeout time.Duration) (*Client, error) {
	if username == "" {
		user, err := user.Current()
		if err != nil {
			return nil, fmt.Errorf("Username wasn't specified and couldn't get current user: %v", err)
		}

		username = user.Username
	}

	config := &ssh.ClientConfig{
		User: username,
		Auth: []ssh.AuthMethod{authMethod},
	}

	host = addPortToHost(host)

	conn, err := net.DialTimeout("tcp", host, timeout)
	if err != nil {
		return nil, err
	}
	sshConn, chans, reqs, err := ssh.NewClientConn(conn, host, config)
	if err != nil {
		return nil, err
	}
	client := ssh.NewClient(sshConn, chans, reqs)

	c := &Client{SSHClient: client}
	return c, nil
}
Пример #8
0
func (c *comm) reconnect() (err error) {
	if c.conn != nil {
		c.conn.Close()
	}

	// Set the conn and client to nil since we'll recreate it
	c.conn = nil
	c.client = nil

	c.conn, err = c.config.Connection()
	if err != nil {
		// Explicitly set this to the REAL nil. Connection() can return
		// a nil implementation of net.Conn which will make the
		// "if c.conn == nil" check fail above. Read here for more information
		// on this psychotic language feature:
		//
		// http://golang.org/doc/faq#nil_error
		c.conn = nil
		log.Printf("reconnection error: %s", err)
		return
	}

	sshConn, sshChan, req, err := ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
	if err != nil {
		log.Printf("handshake error: %s", err)
	}
	if sshConn != nil {
		c.client = ssh.NewClient(sshConn, sshChan, req)
	}
	c.connectToAgent()

	return
}
Пример #9
0
func SSHDialTimeout(network, addr string, config *ssh.ClientConfig, timeout time.Duration) (*ssh.Client, error) {
	conn, err := net.DialTimeout(network, addr, timeout)
	if err != nil {
		return nil, err
	}

	timeoutConn := &Conn{conn, timeout, timeout}
	c, chans, reqs, err := ssh.NewClientConn(timeoutConn, addr, config)
	if err != nil {
		return nil, err
	}
	client := ssh.NewClient(c, chans, reqs)

	// this sends keepalive packets every 2 seconds
	// there's no useful response from these, so we can just abort if there's an error
	go func() {
		t := time.NewTicker(2 * time.Second)
		defer t.Stop()
		for {
			<-t.C
			if _, _, err := client.Conn.SendRequest("*****@*****.**", true, nil); err != nil {
				return
			}
		}
	}()
	return client, nil
}
Пример #10
0
// NewRemotePassAuthRunnerWithTimeouts is one of functions for creating remote
// runner. Use this one instead of NewRemotePassAuthRunner if you need to setup
// nondefault timeouts for ssh connection
func NewRemotePassAuthRunnerWithTimeouts(
	user, host, password string, timeouts Timeouts,
) (*Remote, error) {
	config := &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{ssh.Password(password)},
	}

	dialer := net.Dialer{
		Timeout:   timeouts.ConnectionTimeout,
		Deadline:  time.Now().Add(timeouts.ConnectionTimeout),
		KeepAlive: timeouts.KeepAlive,
	}

	conn, err := dialer.Dial("tcp", host)
	if err != nil {
		return nil, err
	}

	connection := &timeBoundedConnection{
		Conn:         conn,
		readTimeout:  timeouts.SendTimeout,
		writeTimeout: timeouts.ReceiveTimeout,
	}

	sshConnection, channels, requests, err := ssh.NewClientConn(
		connection, host, config,
	)
	if err != nil {
		return nil, err
	}

	return &Remote{ssh.NewClient(sshConnection, channels, requests)}, nil
}
Пример #11
0
Файл: ssh.go Проект: calmh/mole
func sshOnConn(conn net.Conn, h conf.Host) (*ssh.Client, error) {
	var auths []ssh.AuthMethod

	if h.Pass != "" {
		auths = append(auths, ssh.Password(h.Pass))
		auths = append(auths, ssh.KeyboardInteractive(kbdInteractive(h.Pass)))
	}

	if h.Key != "" {
		k := &keyring{}
		err := k.loadPEM([]byte(h.Key))
		if err != nil {
			return nil, err
		}
		for _, k := range k.keys {
			s, _ := ssh.NewSignerFromKey(k)
			auths = append(auths, ssh.PublicKeys(s))
		}
	}

	config := &ssh.ClientConfig{
		User: h.User,
		Auth: auths,
	}

	debugln("handshake & authenticate")
	cc, nc, reqs, err := ssh.NewClientConn(conn, conn.RemoteAddr().String(), config)
	if err != nil {
		return nil, err
	}
	client := ssh.NewClient(cc, nc, reqs)
	return client, nil
}
Пример #12
0
func (ctx *ExecContext) reconnect() (err error) {
	if ctx.hostname != "" {
		ctx.isReconnecting = true
		username := ctx.username
		addr := fmt.Sprintf("%s:%d", ctx.hostname, ctx.port)
		ctx.unlock()
		agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
		if err != nil {
			ctx.lock()
			ctx.isReconnecting = false
			return err
		}
		defer agentConn.Close()
		ag := agent.NewClient(agentConn)
		auths := []ssh.AuthMethod{ssh.PublicKeysCallback(ag.Signers)}
		config := &ssh.ClientConfig{
			User: username,
			Auth: auths,
		}
		conn, err := net.DialTimeout("tcp", addr, networkTimeout)
		if err != nil {
			ctx.lock()
			ctx.isReconnecting = false
			return err
		}

		timeoutConn := &Conn{conn, networkTimeout, networkTimeout}
		c, chans, reqs, err := ssh.NewClientConn(timeoutConn, addr, config)
		if err != nil {
			ctx.lock()
			ctx.isReconnecting = false
			return err
		}
		client := ssh.NewClient(c, chans, reqs)

		// Send periodic keepalive messages
		go func() {
			t := time.NewTicker(networkTimeout / 2)
			defer t.Stop()
			for {
				<-t.C
				_, _, err := client.Conn.SendRequest("*****@*****.**", true, nil)
				if err != nil {
					ctx.lock()
					if ctx.sshClient == client {
						ctx.isConnected = false
					}
					ctx.unlock()
					return
				}
			}
		}()
		ctx.lock()
		ctx.isReconnecting = false
		ctx.sshClient = client
	}
	ctx.isConnected = true
	return nil
}
Пример #13
0
// The function ssh.Dial doesn't have timeout mechanism for dial so this function is used
func dialWithTimeout(network, addr string, config *ssh.ClientConfig, timeout time.Duration) (*ssh.Client, error) {
	conn, err := net.DialTimeout(network, addr, timeout)
	if err != nil {
		return nil, err
	}
	c, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
	if err != nil {
		return nil, err
	}
	return ssh.NewClient(c, chans, reqs), nil
}
Пример #14
0
// DialThrough will create a new connection from the ssh server sc is connected to. DialThrough is an SSHDialer.
func (sc *SSHClient) DialThrough(net, addr string, config *ssh.ClientConfig) (*ssh.Client, error) {
	conn, err := sc.conn.Dial(net, addr)
	if err != nil {
		return nil, err
	}
	c, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
	if err != nil {
		return nil, err
	}
	return ssh.NewClient(c, chans, reqs), nil

}
Пример #15
0
func Hop(through *ssh.Client, toaddr string, c *ssh.ClientConfig) (*ssh.Client, error) {
	hopconn, err := through.Dial("tcp", toaddr)
	if err != nil {
		return nil, err
	}

	conn, chans, reqs, err := ssh.NewClientConn(hopconn, toaddr, c)
	if err != nil {
		return nil, err
	}

	return ssh.NewClient(conn, chans, reqs), nil
}
Пример #16
0
func (opts *sshOpts) dial(config *ssh.ClientConfig) (*ssh.Client, error) {
	addr := opts.Hostname + ":" + strconv.Itoa(opts.Port)
	timeout := opts.Timeout * float64(time.Second)
	conn, err := net.DialTimeout("tcp", addr, time.Duration(timeout))
	if err != nil {
		return nil, err
	}
	c, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
	if err != nil {
		return nil, err
	}
	return ssh.NewClient(c, chans, reqs), nil
}
Пример #17
0
func (d *realSSHDialer) Dial(network, addr string, config *ssh.ClientConfig) (*ssh.Client, error) {
	conn, err := net.DialTimeout(network, addr, config.Timeout)
	if err != nil {
		return nil, err
	}
	conn.SetReadDeadline(time.Now().Add(30 * time.Second))
	c, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
	if err != nil {
		return nil, err
	}
	conn.SetReadDeadline(time.Time{})
	return ssh.NewClient(c, chans, reqs), nil
}
Пример #18
0
func NewClient(clientNetConn net.Conn, clientConfig *ssh.ClientConfig) *ssh.Client {
	if clientConfig == nil {
		clientConfig = &ssh.ClientConfig{
			User: "******",
			Auth: []ssh.AuthMethod{
				ssh.Password("secret"),
			},
		}
	}

	clientConn, clientChannels, clientRequests, clientConnErr := ssh.NewClientConn(clientNetConn, "0.0.0.0", clientConfig)
	Expect(clientConnErr).NotTo(HaveOccurred())

	return ssh.NewClient(clientConn, clientChannels, clientRequests)
}
Пример #19
0
// NewRemoteKeyAuthRunnerWithTimeouts is one of functions for creating remote
// runner. Use this one instead of NewRemoteKeyAuthRunner if you need to setup
// nondefault timeouts for ssh connection
func NewRemoteKeyAuthRunnerWithTimeouts(
	user, host, key string, timeouts Timeouts,
) (*Remote, error) {
	if _, err := os.Stat(key); os.IsNotExist(err) {
		return nil, err
	}

	pemBytes, err := ioutil.ReadFile(key)
	if err != nil {
		return nil, err
	}

	signer, err := ssh.ParsePrivateKey(pemBytes)
	if err != nil {
		return nil, errors.New("can't parse pem data: " + err.Error())
	}

	config := &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
	}

	dialer := net.Dialer{
		Timeout:   timeouts.ConnectionTimeout,
		Deadline:  time.Now().Add(timeouts.ConnectionTimeout),
		KeepAlive: timeouts.KeepAlive,
	}

	conn, err := dialer.Dial("tcp", host)
	if err != nil {
		return nil, err
	}

	connection := &timeBoundedConnection{
		Conn:         conn,
		readTimeout:  timeouts.SendTimeout,
		writeTimeout: timeouts.ReceiveTimeout,
	}

	sshConnection, channels, requests, err := ssh.NewClientConn(
		connection, host, config,
	)
	if err != nil {
		return nil, err
	}

	return &Remote{ssh.NewClient(sshConnection, channels, requests)}, nil
}
Пример #20
0
func (c *Communicator) Client() (*ssh.Client, error) {
	if c.client != nil {
		return c.client, nil
	}

	// create ssh client.
	client, err := ssh.Dial("tcp", c.Config.HostOrDefault()+":"+c.Config.PortOrDefault(), c.ClientConfig)
	if err != nil {
		return nil, err
	}
	c.clientConns = append(c.clientConns, client)

	// If it has a upstream server?
	for c.UpstreamConfig != nil {
		// It is next server config to connect.
		var config *Config = nil

		// Does the upstream server need proxy to connet?
		proxy := c.UpstreamConfig.PopProxyConfig()
		if proxy != nil {
			config = proxy
		} else {
			config = c.UpstreamConfig
			c.UpstreamConfig = nil
		}

		// dial to ssh proxy
		connection, err := client.Dial("tcp", config.HostOrDefault()+":"+config.PortOrDefault())
		if err != nil {
			return nil, err
		}
		c.clientConns = append(c.clientConns, connection)

		conn, chans, reqs, err := ssh.NewClientConn(connection, config.HostOrDefault()+":"+config.PortOrDefault(), c.ClientConfig)
		if err != nil {
			return nil, err
		}
		client = ssh.NewClient(conn, chans, reqs)
		c.clientConns = append(c.clientConns, client)

		if err != nil {
			return nil, err
		}
	}

	c.client = client
	return c.client, nil
}
Пример #21
0
func connToTransport(conn net.Conn, config *ssh.ClientConfig) (*TransportSSH, error) {
	c, chans, reqs, err := ssh.NewClientConn(conn, conn.RemoteAddr().String(), config)
	if err != nil {
		return nil, err
	}

	t := &TransportSSH{}
	t.sshClient = ssh.NewClient(c, chans, reqs)

	err = t.setupSession()
	if err != nil {
		return nil, err
	}

	return t, nil
}
Пример #22
0
func TestSetupForwardAgent(t *testing.T) {
	a, b, err := netPipe()
	if err != nil {
		t.Fatalf("netPipe: %v", err)
	}

	defer a.Close()
	defer b.Close()

	_, socket, cleanup := startAgent(t)
	defer cleanup()

	serverConf := ssh.ServerConfig{
		NoClientAuth: true,
	}
	serverConf.AddHostKey(testSigners["rsa"])
	incoming := make(chan *ssh.ServerConn, 1)
	go func() {
		conn, _, _, err := ssh.NewServerConn(a, &serverConf)
		if err != nil {
			t.Fatalf("Server: %v", err)
		}
		incoming <- conn
	}()

	conf := ssh.ClientConfig{}
	conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf)
	if err != nil {
		t.Fatalf("NewClientConn: %v", err)
	}
	client := ssh.NewClient(conn, chans, reqs)

	if err := ForwardToRemote(client, socket); err != nil {
		t.Fatalf("SetupForwardAgent: %v", err)
	}

	server := <-incoming
	ch, reqs, err := server.OpenChannel(channelType, nil)
	if err != nil {
		t.Fatalf("OpenChannel(%q): %v", channelType, err)
	}
	go ssh.DiscardRequests(reqs)

	agentClient := NewClient(ch)
	testAgentInterface(t, agentClient, testPrivateKeys["rsa"], nil, 0)
	conn.Close()
}
Пример #23
0
func getSSHClient(
	sshSigner ssh.Signer,
	user string,
	host string,
	port string,
	dialTimeout time.Duration,
) (*ssh.Client, error) {

	clientConfig := ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{ssh.PublicKeys(sshSigner)},
		// ssh.Password("password"),
	}
	addr := host + ":" + port

	// if we need to set up dial timeout.
	//
	c, err := net.DialTimeout("tcp", addr, dialTimeout)
	if err != nil {
		return nil, err
	}
	if tc, ok := c.(*net.TCPConn); ok {
		// if c is tcp connection, set these:
		tc.SetKeepAlive(true)
		tc.SetKeepAlivePeriod(5 * time.Second)
	}
	// func NewClientConn(c net.Conn, addr string, config *ClientConfig)
	// (Conn, <-chan NewChannel, <-chan *Request, error)
	conn, newChan, reqChan, err := ssh.NewClientConn(
		c,
		addr,
		&clientConfig,
	)
	if err != nil {
		return nil, err
	}
	if conn == nil {
		return nil, errors.New("Can't establish SSH")
	}
	// func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client
	return ssh.NewClient(conn, newChan, reqChan), nil

	// or
	//
	// return ssh.Dial("tcp", addr, &clientConfig)
}
Пример #24
0
func dialSSH(info *SSHTunnel, config *ssh.ClientConfig, proxyCommand string) (*ssh.Client, error) {
	var conn net.Conn
	var err error

	if proxyCommand == "" {
		conn, err = directConnect(`tcp`, info.Address, 5*time.Second)
	} else {
		conn, err = connectProxy(proxyCommand, info.Address)
	}
	if err != nil {
		return nil, err
	}
	c, chans, reqs, err := ssh.NewClientConn(conn, info.Address, config)
	if err != nil {
		return nil, err
	}
	return ssh.NewClient(c, chans, reqs), nil
}
Пример #25
0
//DialSSH will open an ssh session using the specified authentication
func DialSSH(server, username string, timeout int, auth ...ssh.AuthMethod) (*Session, error) {
	config := &ssh.ClientConfig{
		User: username,
		Auth: auth,
	}
	if strings.Index(server, ":") < 0 {
		server += ":22"
	}
	conn, err := net.DialTimeout("tcp", server, time.Duration(timeout)*time.Second)
	if err != nil {
		return nil, err
	}

	c, chans, reqs, err := ssh.NewClientConn(conn, server, config)
	if err != nil {
		return nil, err
	}
	return NewSession(ssh.NewClient(c, chans, reqs))
}
Пример #26
0
// Create a new NETCONF session using an existing net.Conn.
func NewSSHSession(conn net.Conn, config *ssh.ClientConfig) (*Session, error) {
	var (
		t   TransportSSH
		err error
	)

	c, chans, reqs, err := ssh.NewClientConn(conn, conn.RemoteAddr().String(), config)
	if err != nil {
		return nil, err
	}

	t.sshClient = ssh.NewClient(c, chans, reqs)

	err = t.setupSession()
	if err != nil {
		return nil, err
	}

	return NewSession(&t), nil
}
Пример #27
0
func (s *sshServer) run(c *gc.C) {
	netconn, err := s.listener.Accept()
	c.Assert(err, jc.ErrorIsNil)
	defer func() {
		err := netconn.Close()
		c.Assert(err, jc.ErrorIsNil)
	}()
	conn, chans, reqs, err := cryptossh.NewServerConn(netconn, s.cfg)
	c.Assert(err, jc.ErrorIsNil)
	s.client = cryptossh.NewClient(conn, chans, reqs)
	var wg sync.WaitGroup
	defer wg.Wait()
	sessionChannels := s.client.HandleChannelOpen("session")
	c.Assert(sessionChannels, gc.NotNil)
	for newChannel := range sessionChannels {
		c.Assert(newChannel.ChannelType(), gc.Equals, "session")
		channel, reqs, err := newChannel.Accept()
		c.Assert(err, jc.ErrorIsNil)
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer channel.Close()
			for req := range reqs {
				switch req.Type {
				case "exec":
					c.Assert(req.WantReply, jc.IsTrue)
					n := binary.BigEndian.Uint32(req.Payload[:4])
					command := string(req.Payload[4 : n+4])
					c.Assert(command, gc.Equals, testCommandFlat)
					req.Reply(true, nil)
					channel.Write([]byte("abc value\n"))
					_, err := channel.SendRequest("exit-status", false, cryptossh.Marshal(&struct{ n uint32 }{0}))
					c.Assert(err, jc.ErrorIsNil)
					return
				default:
					c.Fatalf("Unexpected request type: %v", req.Type)
				}
			}
		}()
	}
}
Пример #28
0
func NewTunnelledSSHClient(user, tunaddr, tgtaddr string, checker *HostKeyChecker, agentForwarding bool, timeout time.Duration) (*SSHForwardingClient, error) {
	clientConfig, err := sshClientConfig(user, checker)
	if err != nil {
		return nil, err
	}

	tunaddr = maybeAddDefaultPort(tunaddr)
	tgtaddr = maybeAddDefaultPort(tgtaddr)

	var tunnelClient *gossh.Client
	dialFunc := func(echan chan error) {
		var err error
		tunnelClient, err = gossh.Dial("tcp", tunaddr, clientConfig)
		echan <- err
	}
	err = timeoutSSHDial(dialFunc, timeout)
	if err != nil {
		return nil, err
	}

	var targetConn net.Conn
	dialFunc = func(echan chan error) {
		tgtTCPAddr, err := net.ResolveTCPAddr("tcp", tgtaddr)
		if err != nil {
			echan <- err
			return
		}
		targetConn, err = tunnelClient.DialTCP("tcp", nil, tgtTCPAddr)
		echan <- err
	}
	err = timeoutSSHDial(dialFunc, timeout)
	if err != nil {
		return nil, err
	}

	c, chans, reqs, err := gossh.NewClientConn(targetConn, tgtaddr, clientConfig)
	if err != nil {
		return nil, err
	}
	return newSSHForwardingClient(gossh.NewClient(c, chans, reqs), agentForwarding)
}
Пример #29
0
func (sconn *SshConn) SshConnect(sc *SshContext, addr string, log *Log) error {
	conn, err := net.DialTimeout("tcp", addr, sc.timeout)
	if err != nil {
		log.Error("Create ssh connection to %s failed", addr)
		return err
	}

	err = conn.SetDeadline(time.Now().Add(sc.timeout))
	if err != nil {
		log.Error("Set deadline failed")
		return err
	}

	sshConn, chans, reqs, err := ssh.NewClientConn(conn, addr, sc.config)
	if err != nil {
		return err
	}
	client := ssh.NewClient(sshConn, chans, reqs)

	sconn.client = client
	sconn.conn = &conn

	return nil
}
Пример #30
0
// dialSsh is a helper that builds the transport layers and establishes the SSH connection.
// When a meek protocols is selected, additional MeekStats are recorded and returned.
func dialSsh(
	config *Config,
	pendingConns *Conns,
	serverEntry *ServerEntry,
	selectedProtocol,
	sessionId string) (
	conn net.Conn, sshClient *ssh.Client, meekStats *MeekStats, err error) {

	// The meek protocols tunnel obfuscated SSH. Obfuscated SSH is layered on top of SSH.
	// So depending on which protocol is used, multiple layers are initialized.

	useObfuscatedSsh := false
	var directTCPDialAddress string
	var meekConfig *MeekConfig

	switch selectedProtocol {
	case TUNNEL_PROTOCOL_OBFUSCATED_SSH:
		useObfuscatedSsh = true
		directTCPDialAddress = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.SshObfuscatedPort)

	case TUNNEL_PROTOCOL_SSH:
		directTCPDialAddress = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.SshPort)

	default:
		useObfuscatedSsh = true
		meekConfig, err = initMeekConfig(config, serverEntry, selectedProtocol, sessionId)
		if err != nil {
			return nil, nil, nil, ContextError(err)
		}
	}

	NoticeConnectingServer(
		serverEntry.IpAddress,
		serverEntry.Region,
		selectedProtocol,
		directTCPDialAddress,
		meekConfig)

	// Use an asynchronous callback to record the resolved IP address when
	// dialing a domain name. Note that DialMeek doesn't immediately
	// establish any HTTPS connections, so the resolved IP address won't be
	// reported until during/after ssh session establishment (the ssh traffic
	// is meek payload). So don't Load() the IP address value until after that
	// has completed to ensure a result.
	var resolvedIPAddress atomic.Value
	resolvedIPAddress.Store("")
	setResolvedIPAddress := func(IPAddress string) {
		resolvedIPAddress.Store(IPAddress)
	}

	// Create the base transport: meek or direct connection
	dialConfig := &DialConfig{
		UpstreamProxyUrl:              config.UpstreamProxyUrl,
		ConnectTimeout:                time.Duration(*config.TunnelConnectTimeoutSeconds) * time.Second,
		PendingConns:                  pendingConns,
		DeviceBinder:                  config.DeviceBinder,
		DnsServerGetter:               config.DnsServerGetter,
		UseIndistinguishableTLS:       config.UseIndistinguishableTLS,
		TrustedCACertificatesFilename: config.TrustedCACertificatesFilename,
		DeviceRegion:                  config.DeviceRegion,
		ResolvedIPCallback:            setResolvedIPAddress,
	}
	if meekConfig != nil {
		conn, err = DialMeek(meekConfig, dialConfig)
		if err != nil {
			return nil, nil, nil, ContextError(err)
		}
	} else {
		conn, err = DialTCP(directTCPDialAddress, dialConfig)
		if err != nil {
			return nil, nil, nil, ContextError(err)
		}
	}

	cleanupConn := conn
	defer func() {
		// Cleanup on error
		if err != nil {
			cleanupConn.Close()
		}
	}()

	// Add obfuscated SSH layer
	var sshConn net.Conn
	sshConn = conn
	if useObfuscatedSsh {
		sshConn, err = NewObfuscatedSshConn(
			OBFUSCATION_CONN_MODE_CLIENT, conn, serverEntry.SshObfuscatedKey)
		if err != nil {
			return nil, nil, nil, ContextError(err)
		}
	}

	// Now establish the SSH session over the sshConn transport
	expectedPublicKey, err := base64.StdEncoding.DecodeString(serverEntry.SshHostKey)
	if err != nil {
		return nil, nil, nil, ContextError(err)
	}
	sshCertChecker := &ssh.CertChecker{
		HostKeyFallback: func(addr string, remote net.Addr, publicKey ssh.PublicKey) error {
			if !bytes.Equal(expectedPublicKey, publicKey.Marshal()) {
				return ContextError(errors.New("unexpected host public key"))
			}
			return nil
		},
	}
	sshPasswordPayload, err := json.Marshal(
		struct {
			SessionId   string `json:"SessionId"`
			SshPassword string `json:"SshPassword"`
		}{sessionId, serverEntry.SshPassword})
	if err != nil {
		return nil, nil, nil, ContextError(err)
	}
	sshClientConfig := &ssh.ClientConfig{
		User: serverEntry.SshUsername,
		Auth: []ssh.AuthMethod{
			ssh.Password(string(sshPasswordPayload)),
		},
		HostKeyCallback: sshCertChecker.CheckHostKey,
	}

	// The ssh session establishment (via ssh.NewClientConn) is wrapped
	// in a timeout to ensure it won't hang. We've encountered firewalls
	// that allow the TCP handshake to complete but then send a RST to the
	// server-side and nothing to the client-side, and if that happens
	// while ssh.NewClientConn is reading, it may wait forever. The timeout
	// closes the conn, which interrupts it.
	// Note: TCP handshake timeouts are provided by TCPConn, and session
	// timeouts *after* ssh establishment are provided by the ssh keep alive
	// in operate tunnel.
	// TODO: adjust the timeout to account for time-elapsed-from-start

	type sshNewClientResult struct {
		sshClient *ssh.Client
		err       error
	}
	resultChannel := make(chan *sshNewClientResult, 2)
	if *config.TunnelConnectTimeoutSeconds > 0 {
		time.AfterFunc(time.Duration(*config.TunnelConnectTimeoutSeconds)*time.Second, func() {
			resultChannel <- &sshNewClientResult{nil, errors.New("ssh dial timeout")}
		})
	}

	go func() {
		// The following is adapted from ssh.Dial(), here using a custom conn
		// The sshAddress is passed through to host key verification callbacks; we don't use it.
		sshAddress := ""
		sshClientConn, sshChans, sshReqs, err := ssh.NewClientConn(sshConn, sshAddress, sshClientConfig)
		var sshClient *ssh.Client
		if err == nil {
			sshClient = ssh.NewClient(sshClientConn, sshChans, sshReqs)
		}
		resultChannel <- &sshNewClientResult{sshClient, err}
	}()

	result := <-resultChannel
	if result.err != nil {
		return nil, nil, nil, ContextError(result.err)
	}

	if meekConfig != nil {
		meekStats = &MeekStats{
			DialAddress:         meekConfig.DialAddress,
			ResolvedIPAddress:   resolvedIPAddress.Load().(string),
			SNIServerName:       meekConfig.SNIServerName,
			HostHeader:          meekConfig.HostHeader,
			TransformedHostName: meekConfig.TransformedHostName,
		}

		NoticeConnectedMeekStats(serverEntry.IpAddress, meekStats)
	}

	return conn, result.sshClient, meekStats, nil
}