go语言实现ssh打隧道

如何打隧道

使用ssh打个隧道,是我一直想作的事情。出发点是:在公司内部常常有些机器访问不到,只能经过公司提供的开发机,可是开发机咱们能够在内网访问到,这个html

基础知识

SSH是一种网络协议,用于计算机之间的加密登陆,流程大体是:linux

  1. 远程主机收到用户的登陆请求,把本身的公钥发给用户。
  2. 用户使用这个公钥,将登陆密码加密后,发送回来。
  3. 远程主机用本身的私钥,解密登陆密码,若是密码正确,就赞成用户登陆。

上面这个过程当中很容易受到攻击的就是第一步,咱们怎么知道收到的公钥是真正的主机的,体如今实际登录中,就是会出现:git

 $ ssh user@host

  The authenticity of host 'host (12.18.429.21)' can't be established.   RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.   Are you sure you want to continue connecting (yes/no)? 复制代码

此处RSA key fingerprint就是对128公钥的MD5签名,当输入yes后,就会保存到$HOME/.ssh/known_hosts,说明是对公钥的承认。github

解决了信任问题后,下一个很差的是每次都须要输入密码,因而就有了公钥登录,就是用户将本身的公钥储存在远程主机上。登陆的时候,远程主机会向用户发送一段随机字符串,用户用本身的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,若是成功,就证实用户是可信的,直接容许登陆shell,再也不要求密码。golang

因此总结起来 ssh 认证的方式有两种:shell

  1. 用户名 + 证书
  2. 用户名 + 密码

下面咱们来看go中相应的操做方法bash

golang 实现 ssh client

go get -u golang.org/x/crypto/...
复制代码

先来讲2种认证方式,显示密码,经过ssh.Password来传入密码网络

sshConfig := &ssh.ClientConfig{
	User: "your_user_name",
	Auth: []ssh.AuthMethod{
		ssh.Password("your_password")
	},
}
复制代码

第二种是证书的方式,这又细分为两种,一种是咱们直接读取本身的私钥,另外一种是从ssh-agent读取,ssh-agent是用来帮助咱们管理私钥的程序,它的出现主要是为了解决当咱们访问不一样的主机使用不一样的私钥-公钥对,同时解决若是设置了私钥的密码,须要每次都手动设置的问题。 ps:ssh-agent的管理session

eval `ssh-agent` 启动agent代理
ssh-add /path/to/key/key_name 添加指定私钥
ssh-agent -k 关闭 agent
ssh-add -l 查看代理中私钥
ssh-add -L 查看代理中私钥对应的公钥
ssh-add -d /path/to/key/key_name 移除指定私钥
ssh-add -D 删除管理的全部私钥
复制代码

从文件读取ssh

func PublicKeyFile(file string) ssh.AuthMethod {
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		return nil
	}

	key, err := ssh.ParsePrivateKey(buffer)
	if err != nil {
		return nil
	}
	return ssh.PublicKeys(key)
}
复制代码

从 ssh-agent 读取

func SSHAgent() ssh.AuthMethod {
	if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
		return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
	}
	return nil
}
复制代码

client生成

当咱们有了认证方式后,下面就是生成ssh-client

sshClient, err := ssh.Dial("tcp", "host:port", sshConfig)
if err != nil {
	return nil, fmt.Errorf("Failed to dial: %s", err)
}
复制代码

创建链接后,咱们要建立一个命令执行的session,一个session就是一次命令执行,在开始执行命令以前,咱们还要创建一个伪终端,方便输入输出

modes := ssh.TerminalModes{
	ssh.ECHO:          0,     // disable echoing
	ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
	ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}

if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
	session.Close()
	return nil, fmt.Errorf("request for pseudo terminal failed: %s", err)
}
复制代码

再而后咱们就能够开始执行代码,完整代码见ssh_client

参考

how-to-create-an-ssh-tunnel-in-go

golang中ssh基础操做

基础知识

相关文章
相关标签/搜索