示例#1
0
文件: ssh.go 项目: reth-/mole
func sshOnConn(conn net.Conn, h conf.Host) (*ssh.ClientConn, error) {
	var auths []ssh.ClientAuth

	if h.Pass != "" {
		auths = append(auths, ssh.ClientAuthPassword(password(h.Pass)))
		auths = append(auths, ssh.ClientAuthKeyboardInteractive(challenge(h.Pass)))
	}

	if h.Key != "" {
		k := &keyring{}
		err := k.loadPEM([]byte(h.Key))
		if err != nil {
			return nil, err
		}
		auths = append(auths, ssh.ClientAuthKeyring(k))
	}

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

	debugln("handshake & authenticate")
	client, err := ssh.Client(conn, config)
	if err != nil {
		return nil, err
	}
	return client, nil
}
示例#2
0
文件: ssh_test.go 项目: kr/runx
func TestSSHD(t *testing.T) {
	block, _ := pem.Decode([]byte(testClientPrivateKey))
	rsakey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	pub, _ := ssh.NewPublicKey(&rsakey.PublicKey)
	cmd, c, err := startSSHD(ssh.MarshalAuthorizedKey(pub))
	if err != nil {
		t.Fatal(err)
	}
	defer cmd.Wait()
	defer cmd.Process.Kill()
	u, err := user.Current()
	if err != nil {
		t.Fatal(err)
	}
	_ = u
	config := &ssh.ClientConfig{
		User: u.Username,
		Auth: []ssh.ClientAuth{ssh.ClientAuthKeyring(&keyring{rsakey})},
	}
	client, err := ssh.Client(c, config)
	if err != nil {
		t.Fatal(err)
	}
	sess, err := client.NewSession()
	if err != nil {
		t.Fatal(err)
	}
	out, err := sess.Output("echo hello")
	if err != nil {
		t.Fatal(err)
	}
	if string(out) != "hello\n" {
		t.Fatalf("out = %q want %q", string(out), "hello\n")
	}
}
示例#3
0
func remoteCmdOutput(username, hostname, privateKey, cmd string) []byte {
	block, _ := pem.Decode([]byte(privateKey))
	rsakey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	clientKey := &keychain{rsakey}
	clientConfig := &ssh.ClientConfig{
		User: username,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(clientKey),
		},
	}
	client, err := ssh.Dial("tcp", hostname, clientConfig)
	if err != nil {
		log.Println("ERROR: Failed to dial: " + err.Error())
		return []byte{}
	}
	session, err := client.NewSession()
	if err != nil {
		log.Println("ERROR: Failed to create session: " + err.Error())
		return []byte{}
	}
	defer session.Close()
	output, err := session.Output(cmd)
	if err != nil {
		log.Printf("ERROR: Failed to run cmd on host %s: %s", hostname, err.Error())
		return []byte{}
	}
	return output
}
示例#4
0
文件: connpool.go 项目: afajl/ctrl
func getConn(host *host.Host) (*ssh.ClientConn, error) {
	hostkey := host.Id
	if con, ok := conns[hostkey]; ok {
		return con, nil
	}
	if host.User == "" {
		return nil, fmt.Errorf("user not set")
	}
	for _, keyfile := range host.Keyfiles {
		// TODO add key to global keyring, ok?
		if err := keys.loadPEM(keyfile); err != nil {
			return nil, fmt.Errorf("unable to load %s: %v", keyfile, err)
		}
	}
	config := &ssh.ClientConfig{
		User: host.User,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(keys),
		},
	}
	conn, err := ssh.Dial("tcp", host.ConnStr(), config)
	if err != nil {
		return nil, fmt.Errorf("unable to connect to %s: %v", host, err)
	}
	conns[hostkey] = conn
	return conn, nil
}
示例#5
0
文件: connection.go 项目: tobert/gdsh
func (conn *Conn) Connect() error {
	var auth []ssh.ClientAuth

	// only load a private key if requested ~/.ssh/id_rsa is _not_ loaded automatically
	// ssh-agent should be the usual path
	if conn.Key != "" {
		kr := new(keyring)
		if err := kr.loadPEM(conn.Key); err != nil {
			log.Fatal("Couldn't load specified private key '", conn.Key, "': ", err)
		}
		auth = append(auth, ssh.ClientAuthKeyring(kr))
	}

	agentSock := os.Getenv("SSH_AUTH_SOCK")

	// ssh-agent support, might need to reuse this in the future?
	// how bad are 100's or 1000's of connections to the agent?
	if agentSock != "" {
		sock, err := net.Dial("unix", agentSock)
		if err != nil {
			log.Fatal("Could not connect to SSH_AUTH_SOCK. Is ssh-agent running?")
		}

		agent := ssh.NewAgentClient(sock)
		auth = append(auth, ssh.ClientAuthAgent(agent))
	}

	conn.config = &ssh.ClientConfig{
		User: conn.User,
		Auth: auth,
	}

	return conn.connect()
}
示例#6
0
func TestSshCmd(t *testing.T) {
	kc := new(keychain)
	kc.load()
	config := &ssh.ClientConfig{
		User: os.Getenv("USER"),
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(kc),
		},
	}
	client, err := ssh.Dial("tcp", "localhost:22", config)
	if err != nil {
		panic("Failed to dial: " + err.Error())
	}

	// Each ClientConn can support multiple interactive sessions,
	// represented by a Session.
	session, err := client.NewSession()
	if err != nil {
		panic("Failed to create session: " + err.Error())
	}
	defer session.Close()

	// Once a Session is created, you can execute a single command on
	// the remote side using the Run method.
	var b bytes.Buffer
	session.Stdout = &b
	if err := session.Run("/usr/bin/whoami"); err != nil {
		panic("Failed to run: " + err.Error())
	}
	log.Printf("Result of running whoami via ssh: %s\n", b)
	//fmt.Println(b.String())
}
示例#7
0
func ConnectAndForward(addresses Addresses) {
	// Load id_rsa file
	keychain := new(keyChain)
	err := keychain.loadPEM(addresses.PrivateKeyPathString)
	if err != nil {
		log.Fatalf("Cannot load key: %v", err)
	}

	// Setup SSH config (type *ssh.ClientConfig)
	config := &ssh.ClientConfig{
		User: addresses.SSHUserString,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(keychain),
		},
	}

	// Setup localListener (type net.Listener)
	localListener, err := net.Listen("tcp", addresses.LocalAddrString)
	if err != nil {
		log.Fatalf("net.Listen failed: %v", err)
	}
	defer localListener.Close()

	for {
		// Setup localConn (type net.Conn)
		localConn, err := localListener.Accept()
		if err != nil {
			log.Fatalf("listen.Accept failed: %v", err)
		}
		defer localConn.Close()
		go forward(localConn, config, addresses.ServerAddrString, addresses.RemoteAddrString)
	}
}
示例#8
0
文件: sandhog.go 项目: hut8/sandhog
func main() {
	logger = log.New(os.Stdout, "wam: ", log.LstdFlags|log.Lshortfile)
	logger.Println("sandhog")

	configData, err := loadConfig()
	if err != nil {
		printUsage()
		logger.Fatalln(err)
	}

	keyring, err := LoadKeyring(configData.keyPath)
	if err != nil {
		logger.Fatalln(err)
	}
	logger.Printf("loaded keyring: %s", keyring)

	sshConfig := &ssh.ClientConfig{
		User: "******",
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(keyring),
		},
	}
	logger.Printf("created SSH client config: %s", sshConfig)

	// Dial your ssh server.
	logger.Println("connecting")
	conn, err := ssh.Dial("tcp", "localhost:22", sshConfig)
	if err != nil {
		logger.Fatalf("unable to connect: %s\n", err)
	}
	defer conn.Close()
	logger.Println("connected!")

	// Request the remote side to open port 8080 on all interfaces.
	// When they
	remoteListenEndpoint := fmt.Sprintf("127.0.0.1:%d", configData.remotePort)
	logger.Printf("requesting remote host listen on: %s\n", remoteListenEndpoint)
	listener, err := conn.Listen("tcp", remoteListenEndpoint)
	if err != nil {
		log.Fatalf("unable to register tcp forward: %s", err)
	}
	defer listener.Close()

	logger.Printf("remote host listening on %s\n", remoteListenEndpoint)

	for {
		conn, err := listener.Accept()
		if err != nil {
			logger.Println(err)
			break
		}
		go handleConn(conn, *configData)
	}
	// Serve HTTP with your SSH server acting as a reverse proxy.
	http.Serve(listener, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(resp, "Hello world!\n")
	}))
}
示例#9
0
func (this *Handel) check() (err error) {
	if this.auth == nil {
		keys := new(keychain)
		if err = keys.LoadPEM(this.PrivateKey); err != nil {
			return
		}
		this.auth = &ssh.ClientConfig{
			User: this.User,
			Auth: []ssh.ClientAuth{
				ssh.ClientAuthKeyring(keys),
			},
		}
	}
	if this.Port == "" {
		this.Port = SSH_PORT
	}
	if this.client == nil {
		this.client, err = ssh.Dial("tcp", this.Host+":"+this.Port, this.auth)
		if err != nil {
			return
		}
	}
	if this.session == nil {
		this.session, err = this.client.NewSession()
		if err != nil {
			return
		}
	}

	//stdin
	if this.FileIn == "" {
		this.session.Stdin = os.Stdin
	} else if fd, err := os.Open(this.FileIn); err == nil {
		this.session.Stdin = fd
	} else {
		return errors.New("process config error : bad input file : " + err.Error())
	}
	//stdout
	if this.FileOut == "" {
		this.session.Stdout = os.Stdout
	} else if fd, err := os.OpenFile(this.FileOut, os.O_WRONLY|os.O_CREATE, 0666); err == nil {
		this.session.Stdout = fd
	} else {
		return errors.New("process config error : bad output file : " + err.Error())
	}
	//stderr
	if this.FileErr == "" {
		this.session.Stderr = os.Stderr
	} else if fd, err := os.OpenFile(this.FileErr, os.O_WRONLY|os.O_CREATE, 0666); err == nil {
		this.session.Stderr = fd
	} else {
		return errors.New("process config error : bad error file : " + err.Error())
	}

	return
}
示例#10
0
func clientConfig() *ssh.ClientConfig {
	kc := new(keychain)
	kc.keys = append(kc.keys, rsakey)
	config := &ssh.ClientConfig{
		User: username(),
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(kc),
		},
	}
	return config
}
示例#11
0
文件: client.go 项目: rubiojr/victor
func NewClient(user string, addr string, keys *Keychain) *Client {
	return &Client{
		Addr: addr,
		Config: &ssh.ClientConfig{
			User: user,
			Auth: []ssh.ClientAuth{
				ssh.ClientAuthKeyring(keys),
			},
		},
	}
}
示例#12
0
func clientConfig() *ssh.ClientConfig {
	keyChecker := storedHostKey{}
	keyChecker.Add("ssh-rsa", serializedHostKey)

	kc := new(keychain)
	kc.keys = append(kc.keys, rsakey)
	config := &ssh.ClientConfig{
		User: username(),
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(kc),
		},
		HostKeyChecker: &keyChecker,
	}
	return config
}
示例#13
0
func clientConfig() *ssh.ClientConfig {
	keyChecker := storedHostKey{}
	keyChecker.Add(hostKey.PublicKey())

	kc := new(keychain)
	kc.keys = append(kc.keys, privateKey)
	config := &ssh.ClientConfig{
		User: username(),
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(kc),
		},
		HostKeyChecker: &keyChecker,
	}
	return config
}
示例#14
0
文件: ssh.go 项目: EdevMosaic/packer
// sshConfig returns the ssh configuration.
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
	config := state.Get("config").(*Config)
	privateKey := state.Get("ssh_private_key").(string)

	keyring := new(ssh.SimpleKeychain)
	if err := keyring.AddPEMKey(privateKey); err != nil {
		return nil, fmt.Errorf("Error setting up SSH config: %s", err)
	}

	sshConfig := &gossh.ClientConfig{
		User: config.SSHUsername,
		Auth: []gossh.ClientAuth{gossh.ClientAuthKeyring(keyring)},
	}

	return sshConfig, nil
}
示例#15
0
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) {
	config := state["config"].(config)
	privateKey := state["privateKey"].(string)

	keyring := new(ssh.SimpleKeychain)
	if err := keyring.AddPEMKey(privateKey); err != nil {
		return nil, fmt.Errorf("Error setting up SSH config: %s", err)
	}

	return &gossh.ClientConfig{
		User: config.SSHUsername,
		Auth: []gossh.ClientAuth{
			gossh.ClientAuthKeyring(keyring),
		},
	}, nil
}
示例#16
0
func (ss *ScpStorage) Connect() error {
	var err error

	clientConfig := &ssh.ClientConfig{
		User: ss.User,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(ss.Keychain),
		},
	}

	ss.connexion, err = ssh.Dial("tcp", ss.Endpoint, clientConfig)
	if err != nil {
		return fmt.Errorf("Failed to dial: %s", err.Error())
	}

	return nil
}
示例#17
0
文件: ssh.go 项目: EdevMosaic/packer
// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(multistep.StateBag) (*gossh.ClientConfig, error) {
	return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
		privateKey := state.Get("privateKey").(string)

		keyring := new(ssh.SimpleKeychain)
		if err := keyring.AddPEMKey(privateKey); err != nil {
			return nil, fmt.Errorf("Error setting up SSH config: %s", err)
		}

		return &gossh.ClientConfig{
			User: username,
			Auth: []gossh.ClientAuth{
				gossh.ClientAuthKeyring(keyring),
			},
		}, nil
	}
}
示例#18
0
文件: config.go 项目: postfix/sshutil
// Dial a hostname, intelligently using your local ssh settings to do so
func Dial(hostname string) (*ssh.ClientConn, error) {
	options := []configFileOption{}

	f, err := os.Open(filepath.Join(homeDir(), ".ssh", "config"))
	if err == nil {
		defer f.Close()
		cfg, err := parseConfigFile(f)
		if err == nil {
			options = cfg.getOptions(hostname)
		} else {
			log.Println("[ssh]", "[error]", err)
		}
	} else {
		log.Println("[ssh]", "[error]", err)
	}

	port := 22
	username := getUserName(options)
	for _, kv := range options {
		switch strings.ToLower(kv.key) {
		case "hostname":
			hostname = kv.value
		case "port":
			port, _ = strconv.Atoi(kv.value)
		}
	}

	auths := []ssh.ClientAuth{}
	for _, kv := range options {
		switch strings.ToLower(kv.key) {
		case "identityfile":
			keychain, err := GetKeyChain(toAbsolute(hostname, username, kv.value))
			if err == nil {
				auths = append(auths, ssh.ClientAuthKeyring(keychain))
			}
		}
	}

	log.Println("[ssh]", "dialing", fmt.Sprint(username+"@"+hostname, port))

	return ssh.Dial("tcp", fmt.Sprint(hostname, ":", port), &ssh.ClientConfig{
		User: username,
		Auth: auths,
	})
}
示例#19
0
func makeKeyring() {
	signers := []ssh.Signer{}
	keys := []string{os.Getenv("HOME") + "/.ssh/id_rsa", os.Getenv("HOME") + "/.ssh/id_dsa"}

	for _, keyname := range keys {
		signer, err := makeSigner(keyname)
		if err == nil {
			signers = append(signers, signer)
		}
	}

	if len(signers) == 0 {
		haveKeyring = false
	} else {
		haveKeyring = true
		keyring = ssh.ClientAuthKeyring(&SignerContainer{signers})
	}
}
示例#20
0
文件: sshutil.go 项目: krzsas/dcs
// Reads an OpenSSH key and provides it as a ssh.ClientAuth.
func OpenSshClientAuth(path string) (ssh.ClientAuth, error) {
	privateKey, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(privateKey)
	if block == nil {
		return nil, fmt.Errorf(`No key data found in PEM file "%s"`, path)
	}

	rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	clientKey := &keychain{rsakey}
	return ssh.ClientAuthKeyring(clientKey), nil
}
示例#21
0
func (c *SSHClient) connect() error {
	if !c.Connected {
		config := &ssh.ClientConfig{
			User: c.User,
			Auth: []ssh.ClientAuth{
				ssh.ClientAuthKeyring(c.ClientKeychain),
			},
		}
		conn, err := ssh.Dial("tcp", c.Host, config)
		// defer conn.Close()
		if err != nil {
			return err
		}
		log.Println("[Info] connected to " + c.Host)

		c.Connection = conn
		c.Connected = true
	}
	return nil
}
示例#22
0
文件: ssh.go 项目: rvowles/gowest
func ConnectToSsh(username string, keyfile string, server string) (*ssh.Session, error) {
	k := new(keychain)
	k.loadPEM(keyfile)

	config := &ssh.ClientConfig{
		User: username,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(k),
		},
	}
	client, err := ssh.Dial("tcp", server, config)
	if err != nil {
		panic("Failed to dial: " + err.Error())
	}

	session, err := client.NewSession()
	if err != nil {
		return nil, err
	}

	return session, nil
}
示例#23
0
文件: sshutil.go 项目: spicavigo/gomr
func GetSSHConn(server string, username string, pemFile string) *ssh.ClientConn {

	clientKeychain := new(keychain)
	err := clientKeychain.loadPEM(pemFile)

	if err != nil {
		panic("Cannot load PEM File: " + err.Error())
	}

	config := &ssh.ClientConfig{
		User: username,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(clientKeychain),
		},
	}
	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", server), config)
	if err != nil {
		panic(err)
	}
	return client

}
示例#24
0
func main() {
	// Decode and parse our key
	block, _ := pem.Decode([]byte(clientPrivateKey))
	privateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)

	// Add it to the keychain
	clientKeychain := new(keychain)
	clientKeychain.keys = append(clientKeychain.keys, privateKey)

	// Create our client config with key-based auth
	config := &ssh.ClientConfig{
		User: "******",
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(clientKeychain),
		},
	}

	// Connect
	client, err := ssh.Dial("tcp", "127.0.0.1:22", config)
	if err != nil {
		panic("Failed to dial: " + err.Error())
	}

	// Create a new session
	session, err := client.NewSession()
	if err != nil {
		panic("Failed to create session: " + err.Error())
	}
	defer session.Close()

	// Execute command
	var b bytes.Buffer
	session.Stdout = &b
	if err := session.Run("/bin/whoami"); err != nil {
		panic("Failed to run: " + err.Error())
	}
	fmt.Print(b.String())
}
示例#25
0
文件: gssh.go 项目: erikwb/gssh
/* real */
func main() {
	k := new(keychain)
	err := k.loadPEM(*sshkey)
	if err != nil {
		fmt.Println(err)
	}

	config := &ssh.ClientConfig{
		User: *sshuser,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(k),
		},
	}

	go run_cmd(*sshhost+":22", "/usr/bin/w", config)
	go run_cmd(*sshhost+":22", "/usr/bin/whoami", config)

	output := <-outputs
	fmt.Println(output)
	output = <-outputs
	fmt.Println(output)

}
示例#26
0
文件: ssh.go 项目: B-Rich/packer
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
	config := state.Get("config").(*config)

	auth := []gossh.ClientAuth{
		gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
		gossh.ClientAuthKeyboardInteractive(
			ssh.PasswordKeyboardInteractive(config.SSHPassword)),
	}

	if config.SSHKeyPath != "" {
		keyring, err := sshKeyToKeyring(config.SSHKeyPath)
		if err != nil {
			return nil, err
		}

		auth = append(auth, gossh.ClientAuthKeyring(keyring))
	}

	return &gossh.ClientConfig{
		User: config.SSHUser,
		Auth: auth,
	}, nil
}
示例#27
0
func (s *server) Dial() *ssh.ClientConn {
	s.cmd = exec.Command("sshd", "-f", s.configfile, "-i")
	stdin, err := s.cmd.StdinPipe()
	if err != nil {
		s.t.Fatal(err)
	}
	stdout, err := s.cmd.StdoutPipe()
	if err != nil {
		s.t.Fatal(err)
	}
	s.cmd.Stderr = os.Stderr
	err = s.cmd.Start()
	if err != nil {
		s.Shutdown()
		s.t.Fatal(err)
	}

	user, err := user.Current()
	if err != nil {
		s.Shutdown()
		s.t.Fatal(err)
	}
	kc := new(keychain)
	kc.keys = append(kc.keys, rsakey)
	config := &ssh.ClientConfig{
		User: user.Username,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(kc),
		},
	}
	conn, err := ssh.Client(&client{stdin, stdout}, config)
	if err != nil {
		s.Shutdown()
		s.t.Fatal(err)
	}
	return conn
}
示例#28
0
func (c *goCryptoCommand) ensureSession() (*ssh.Session, error) {
	if c.sess != nil {
		return c.sess, nil
	}
	if len(c.signers) == 0 {
		return nil, fmt.Errorf("no private keys available")
	}
	if c.user == "" {
		currentUser, err := user.Current()
		if err != nil {
			return nil, fmt.Errorf("getting current user: %v", err)
		}
		c.user = currentUser.Username
	}
	config := &ssh.ClientConfig{
		User: c.user,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthKeyring(keyring{c.signers}),
		},
	}
	conn, err := sshDialWithProxy(c.addr, c.proxyCommand, config)
	if err != nil {
		return nil, err
	}
	sess, err := conn.NewSession()
	if err != nil {
		conn.Close()
		return nil, err
	}
	c.conn = conn
	c.sess = sess
	c.sess.Stdin = c.stdin
	c.sess.Stdout = c.stdout
	c.sess.Stderr = c.stderr
	return sess, nil
}
func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
	config := state["config"].(config)
	privateKey := state["privateKey"].(string)
	ui := state["ui"].(packer.Ui)
	ipAddress := state["droplet_ip"]

	// Build the keyring for authentication. This stores the private key
	// we'll use to authenticate.
	keyring := &ssh.SimpleKeychain{}
	err := keyring.AddPEMKey(privateKey)
	if err != nil {
		err := fmt.Errorf("Error setting up SSH config: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	connFunc := ssh.ConnectFunc(
		"tcp",
		fmt.Sprintf("%s:%d", ipAddress, config.SSHPort),
		5*time.Minute)

	// Build the actual SSH client configuration
	sshConfig := &ssh.Config{
		Connection: connFunc,
		SSHConfig: &gossh.ClientConfig{
			User: config.SSHUsername,
			Auth: []gossh.ClientAuth{
				gossh.ClientAuthKeyring(keyring),
			},
		},
	}

	// Start trying to connect to SSH
	connected := make(chan error, 1)
	connectQuit := make(chan bool, 1)
	defer func() {
		connectQuit <- true
	}()

	var comm packer.Communicator
	go func() {
		ui.Say("Connecting to the droplet via SSH...")
		attempts := 0
		handshakeAttempts := 0
		for {
			select {
			case <-connectQuit:
				return
			default:
			}

			// A brief sleep so we're not being overly zealous attempting
			// to connect to the instance.
			time.Sleep(500 * time.Millisecond)

			attempts += 1
			nc, err := connFunc()
			if err != nil {
				continue
			}
			nc.Close()

			log.Println("TCP connection made. Attempting SSH handshake.")
			comm, err = ssh.New(sshConfig)
			if err == nil {
				log.Println("Connected to SSH!")
				break
			}

			handshakeAttempts += 1
			log.Printf("SSH handshake error: %s", err)

			if handshakeAttempts > 5 {
				connected <- err
				return
			}
		}

		connected <- nil
	}()

	log.Printf("Waiting up to %s for SSH connection", config.sshTimeout)
	timeout := time.After(config.sshTimeout)

ConnectWaitLoop:
	for {
		select {
		case err := <-connected:
			if err != nil {
				err := fmt.Errorf("Error connecting to SSH: %s", err)
				state["error"] = err
				ui.Error(err.Error())
				return multistep.ActionHalt
			}

			// We connected. Just break the loop.
			break ConnectWaitLoop
		case <-timeout:
			err := errors.New("Timeout waiting for SSH to become available.")
			state["error"] = err
			ui.Error(err.Error())
			return multistep.ActionHalt
		case <-time.After(1 * time.Second):
			if _, ok := state[multistep.StateCancelled]; ok {
				log.Println("Interrupt detected, quitting waiting for SSH.")
				return multistep.ActionHalt
			}
		}
	}

	// Set the communicator on the state bag so it can be used later
	s.comm = comm
	state["communicator"] = comm

	return multistep.ActionContinue
}
// This blocks until SSH becomes available, and sends the communicator
// on the given channel.
func (s *stepConnectSSH) waitForSSH(state map[string]interface{}) (packer.Communicator, error) {
	config := state["config"].(config)
	instance := state["instance"].(*ec2.Instance)
	privateKey := state["privateKey"].(string)
	ui := state["ui"].(packer.Ui)

	// Build the keyring for authentication. This stores the private key
	// we'll use to authenticate.
	keyring := &ssh.SimpleKeychain{}
	err := keyring.AddPEMKey(privateKey)
	if err != nil {
		return nil, fmt.Errorf("Error setting up SSH config: %s", err)
	}

	// Create the function that will be used to create the connection
	connFunc := ssh.ConnectFunc(
		"tcp", fmt.Sprintf("%s:%d", instance.DNSName, config.SSHPort), 5*time.Minute)

	ui.Say("Waiting for SSH to become available...")
	var comm packer.Communicator
	for {
		time.Sleep(5 * time.Second)

		if s.cancel {
			log.Println("SSH wait cancelled. Exiting loop.")
			return nil, errors.New("SSH wait cancelled")
		}

		// First just attempt a normal TCP connection that we close right
		// away. We just test this in order to wait for the TCP port to be ready.
		nc, err := connFunc()
		if err != nil {
			log.Printf("TCP connection to SSH ip/port failed: %s", err)
			continue
		}
		nc.Close()

		// Build the configuration to connect to SSH
		config := &ssh.Config{
			Connection: connFunc,
			SSHConfig: &gossh.ClientConfig{
				User: config.SSHUsername,
				Auth: []gossh.ClientAuth{
					gossh.ClientAuthKeyring(keyring),
				},
			},
		}

		sshConnectSuccess := make(chan bool, 1)
		go func() {
			comm, err = ssh.New(config)
			if err != nil {
				log.Printf("SSH connection fail: %s", err)
				sshConnectSuccess <- false
				return
			}

			sshConnectSuccess <- true
		}()

		select {
		case success := <-sshConnectSuccess:
			if !success {
				continue
			}
		case <-time.After(5 * time.Second):
			log.Printf("SSH handshake timeout. Trying again.")
			continue
		}

		ui.Say("Connected via SSH!")
		break
	}

	return comm, nil
}