golang实现远程控制主机

文章目录

  • ssh原理
  • 使用golang远程下发命令
  • 使用golang远程传输文件

ssh原理

说到ssh原理个人觉得解释最全的一张图是这张华为画的
在这里插入图片描述
Connection establishment
这一步就是建立tcp连接
version negotiation
这一步是ssh客户端(连接者)和被ssh服务端(连接者)进行协议的交换,比如ssh客户端支持那些加密协议,协商出最后使用的协议,还有就是协商ssh版本

Key Exchange
在说Key Exchange之前,我们要知道主机有2类的ssh-key分别是hostkey和user ssh key,每类key都分公钥和私钥,公钥可以加密,私钥可以解密

  • hostkey:

  • user ssh key:

首先hostkey,当ssh server安装的时候这个hostkey就会默认生成,在第一次连接对端的时候会显示的提醒我们叫我们确认时候继续连接如下

The authenticity of host '192.168.152.132 (192.168.152.132)' can't be established.
ECDSA key fingerprint is SHA256:MzAmI+qRcIEb0AS+6XMcAH5gtxnB779KpHRa1vOvAMs.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes	 

这是啥意思呢我们第一次连接ssh服务端,服务段会发送自己的hostkey的hash后的值给我们,我们如果选择yes,这段hash后的ssh服务端的hostkey被存入本地的.ssh/know_hosts中这是为了防止中间人攻击,有了这个hostkey之后,会使用diffie-hellman,这个算法用于为2端同时生成session key,因为diffie-hellman算法的特新session key必定相等,后续session建立后都会用这个session key进行加密传输

Key Authentication
随后是user ssh key,这个东西是用户用ssh-keygen生成的(也是ssh -i指定的identity_file]),当用户使用key认证而非密码认证的时候,这个就非常重要,ssh客户端将自己的public user ssh key发送给服务端(因为是session,用session可以进行加密),然后每当ssh客户端登录到服务端都会自己生成一个随机数用user 自己的userprivate key进行加密通过session传递给客户端,服务端再用接收客户端的公钥进行解密再发送回客户端,客户端进行check,是自己刚刚生成的key就发送验证成功的消息给服务端,最后验证通过,每当客户端向服务端进行数据传输都会使用之前的session key进行加密,服务段接收后用相同的session key进行解密

使用golang远程下发命令

package mainimport ("fmt""log""os""golang.org/x/crypto/ssh""golang.org/x/crypto/ssh/knownhosts"//"golang.org/x/cryto/ssh"
)func main() {//用于对方返回的keyhostkey, err := knownhosts.New("/root/.ssh/known_hosts")if err != nil {log.Fatal("get knowhosts file error: %s", err.Error())}identify_file := "/root/.ssh/ansible"addr := "192.168.152.132:22"key, err := os.ReadFile(identify_file)if err != nil {log.Fatal("error,Can not Read file " + identify_file + " : " + err.Error())}//将私钥用PEM方式加密返回成签名signer, err := ssh.ParsePrivateKey(key)if err != nil {log.Fatal("unbale to parseprivatekey: ", err)}//设置连接peer时候的configconfig := &ssh.ClientConfig{User: "root",Auth: []ssh.AuthMethod{ssh.PublicKeys(signer),},HostKeyCallback: hostkey,}//连接(key exchange,这里exhcange的是host key,用于认证session,而user key也就是自己手动生成的key用于验证用户)client, err := ssh.Dial("tcp", addr, config)if err != nil {log.Fatal("unable to connect: " + err.Error())}defer client.Close()session, err := client.NewSession()if err != nil {log.Fatal("new session error: %s", err.Error())}result, _ := session.Output("ip a")if err != nil {fmt.Fprintf(os.Stderr, "faile to run command, err:%s", err.Error())}fmt.Println(string(result))}

代码非常简单,注意我们如果是第一次连接那么上述代码会执行失败,因为第一次连接,ssh server要返回自己的hostkey给客户端(我们执行代码的机器),客户端要在自己的know_host里面check,但是第一次连接know_host没有数据就会失败,所以可以将代码改成不安全的模式,也就是不check know_host,方法也很简单,就是将连接时候的config的HostKeyCallback对应的值改为ssh.InsecureIgnoreHostKey()如下

package mainimport ("fmt""log""os""golang.org/x/crypto/ssh"//"golang.org/x/crypto/ssh/knownhosts"//"golang.org/x/cryto/ssh"
)func main() {//用于对方返回的key//hostkey, err := knownhosts.New("/root/.ssh/known_hosts")//if err != nil {//      log.Fatal("get knowhosts file error: %s", err.Error())//}identify_file := "/root/.ssh/ansible"addr := "192.168.152.132:22"key, err := os.ReadFile(identify_file)if err != nil {log.Fatal("error,Can not Read file " + identify_file + " : " + err.Error())}//将私钥用PEM方式加密返回成签名signer, err := ssh.ParsePrivateKey(key)if err != nil {log.Fatal("unbale to parseprivatekey: ", err)}//设置连接peer时候的configconfig := &ssh.ClientConfig{User: "root",Auth: []ssh.AuthMethod{ssh.PublicKeys(signer),},HostKeyCallback: ssh.InsecureIgnoreHostKey(),}//连接(key exchange,这里exhcange的是host key,用于认证session,而user key也就是自己手动生成的key用于验证用户)client, err := ssh.Dial("tcp", addr, config)if err != nil {log.Fatal("unable to connect: " + err.Error())}defer client.Close()session, err := client.NewSession()if err != nil {log.Fatal("new session error: %s", err.Error())}result, _ := session.Output("ip a")if err != nil {fmt.Fprintf(os.Stderr, "faile to run command, err:%s", err.Error())}fmt.Println(string(result))}

最后打印出结果

root@master:~/demo/ssh# ./ssh
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000link/ether 00:0c:29:7e:76:1b brd ff:ff:ff:ff:ff:ffaltname enp2s0inet 192.168.152.132/24 brd 192.168.152.255 scope global noprefixroute ens32valid_lft forever preferred_lft foreverinet6 fe80::20c:29ff:fe7e:761b/64 scope linkvalid_lft forever preferred_lft forever

使用golang远程传输文件

在代码之前,我们要了解2个小的知识点

  • scp -t的用途
  • 文件形式

首先scp -t这个选项不管是man还是其他的公开官方资料中都很难找到其身影,我们先运行看是在干嘛

root@slaver1:/test# scp -t .

输入后就卡着不动,因为这个时候scp的程序在等待远端的scp程序通过tcp的22号端口向他发送文件…
所以scp -t是通过端口接收文件用的

在说一个文件的格式,一个文件开头第一行标记了文件的信息,比如权限,比如大小,比如文件名,后面的才是内容,最后以\x000结尾,所以我们传递的时候最好使用管道,先传递文件原信息,再传递文件的内容,最后传递\x000表示结尾,直接看代码

package main
import ("bytes""fmt""io""log""os""sync""golang.org/x/crypto/ssh"
)func main(){identify_file := "/root/.ssh/ansible"addr := "192.168.152.132:22"key, _ := os.ReadFile(identify_file)signer, _ := ssh.ParsePrivateKey(key) //用协商出来的动态session key进行加密config := &ssh.ClientConfig{User: "root",Auth: []ssh.AuthMethod{ssh.PublicKeys(signer),},HostKeyCallback: ssh.InsecureIgnoreHostKey(),}client, _ := ssh.Dial("tcp", addr, config)defer client.Close()session, _ := client.NewSession()defer session.Close()file, _ := os.Open("apply.sh")defer file.Close()stat, _ := file.Stat()wg := sync.WaitGroup{}wg.Add(1)go func() {hostIn, _ := session.StdinPipe()defer hostIn.Close()fmt.Fprintf(hostIn, "C0655 %d %s\n", stat.Size(), "apply.sh")//第一行输入文件元数据io.Copy(hostIn, file)	//copy 文件内容fmt.Fprint(hostIn, "\x000") //表示结束wg.Done()}()session.Run("/usr/bin/scp -t /test")wg.Wait()}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/140731.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字符函数和字符串函数(1)

前言 C语言中对字符和字符串的处理很是频繁&#xff0c;但是C语言本身是没有字符串类型的&#xff0c;字符串通常放在 常量字符串 中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数. 1.求字符串长度 strlen 1.1 strlen size_t strlen ( const char * s…

Windows安装cuda和cudnn教程最新版(2023年9月)

文章目录 cudacudnn cuda 查看电脑的cuda最高驱动版本&#xff08;适用于N卡电脑-Nvidia&#xff09; winR打开命令行&#xff0c;输入nvidia-smi 右上角cuda -version就是目前支持的最高cuda版本&#xff0c;目前是12.2 nvidia官网下载cuda 下载地址&#xff1a;https://d…

华为NFC设置教程(门禁卡/公交卡/校园卡等)

今天把华为NFC设置教程分享给大家 出门带门禁卡、校园卡、银行卡、身份证……东西又多&#xff0c;携带又麻烦&#xff0c;还容易搞丢&#xff0c;有没有一种方法可以把它们都装下&#xff1f;有&#xff01;只要一部手机&#xff0c;出门不带卡包&#xff0c;各种证件&#x…

010_第一代软件开发(二)

第一代软件开发(二) 文章目录 第一代软件开发(二)项目介绍界面布局功能完善快照功能获取可用串口播放按键提示音 关键字&#xff1a; Qt、 Qml、 QSerialPort、 QPixmap、 QSoundEffect 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff…

主打低功耗物联网国产替代,纵行科技ZT1826芯片以速率和灵敏度出圈

在低功耗物联网领域&#xff0c;国产替代的趋势越演越烈。 9月20日&#xff0c;纵行科技在“IOTE 2023深圳物联网通信技术与应用高峰论坛”发表了“自主原创Advanced M-FSK调制技术助力国产替代和泛在物联”的演讲&#xff0c;并推出了ZT1826芯片&#xff0c;以“更低功耗、更…

NetSuite BOM成本查询

这是个23.2的新功能&#xff0c;如题所示是对BOM成本的一个查询工具&#xff0c;是对之前版本那个无用的“Costed Bill of Materials Inquiry”的一次救赎。 其重要的功能是&#xff1a; •基于BOM所使用的版本、工艺路线和成本模板&#xff0c;通过Break Down的方式计算一个装…

超好用的接口自动化框架,lemon-easytest内测版发布,赶紧用起来~

easytest easytest 是一个接口自动化框架。 功能特点&#xff1a; 支持 http 接口测试 支持 json&#xff0c;html,xml 格式的响应断言 支持数据库断言 支持用例标记筛选 支持用例失败重运行 支持多线程 安装 pip install lemon_easytest 快速使用 不需要写任何代码…

整合minio时出现的错误

Action:Correct the classpath of your application so that it contains compatible versions of the classes io.minio.S3Base and okhttp3.RequestBody 这个错误是我在整合minio时报的错&#xff0c;说实话遇到这个错误我还是很头大的&#xff0c;因为之前在springboot项目…

​2:DDD概念大白话

产品代码都给你看了&#xff0c;可别再说不会DDD&#xff08;二&#xff09;&#xff1a;DDD概念大白话 # 这是一个讲解DDD落地的文章系列&#xff0c;作者是《实现领域驱动设计》的译者滕云。本文章系列以一个真实的并已成功上线的软件项目——码如云&#xff08;https://www…

【吴恩达老师《机器学习》】课后习题5之【偏差与方差】

在本练习中&#xff0c;您将实现正则化线性回归&#xff0c;并使用它来研究具有不同偏差-方差特性的模型。 在练习的前半部分&#xff0c;您将实现正则化线性回归&#xff0c;利用水库水位的变化来预测从大坝流出的水量。在后半部分中&#xff0c;您将对调试学习算法进行一些诊…

【C# Programming】值类型、良构类型

值类型 1、值类型 值类型的变量直接包含值。换言之&#xff0c; 变量引用的位置就是值内存中实际存储的位置。 2、引用类型 引用类型的变量存储的是对一个对象实例的引用&#xff08;通常为内存地址)。 复制引用类型的值时&#xff0c;复制的只是引用。这个引用非常小&#xf…

yum和vim工具的使用

目录 yum工具的使用 yum下载原理 软件的查找&下载&删除操作 查找lrzsz软件&#xff08;文件上传或者下载软件&#xff09; 下载lrzsz软件 删除lrzsz软件 vim工具的使用 vim命令模式 命令模式与光标相关的快捷键&#xff1a; 插入模式 底行模式 在本次的博客当中我们主要…

云服务部署:AWS、Azure和GCP比较

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

游戏扫码登录+多功能工具箱 微信小程序源码

一个集合了多种实用功能的微信小程序&#xff0c;这个微信小程序源码不仅具备美观的界面设计&#xff0c;还拥有许多实用的功能&#xff0c;而且最重要的是&#xff0c;它无需服务器和域名&#xff0c;所有功能都无需API接口&#xff0c;因此不用担心功能失效的问题。这意味着&…

利用PPT导出一张高清图的方法,office与WPS只需要使用一个即可,我使用的是office。

利用PPT导出一张高清图的方法&#xff0c;office与WPS只需要使用一个即可&#xff0c;我使用的是office。 1&#xff0c;PPT的功能拓展来解决导出高清图片方法1.1&#xff0c;PPT功能拓展—>安装插件&#xff1a; 2&#xff0c;各种方法导出图片效果显示&#xff1a;2.1&…

Linux下git安装及使用

Linux下Git使用 1. git的安装 sudo apt install git安装完&#xff0c;使用git --version查看git版本 2. 配置git git config --global user.name "Your Name“ ##配置用户 git config --global user.email emailexample.com ##配置邮箱git config --global --list …

NLP BigModel

NLP 基础 建议看 [CS224N 2023]打基础 【NLP入门】1. n元语法模型 / 循环神经网络 【NLP入门】3. Word2Vec / GloVe Language Model&#xff1a;语言模型的马尔可夫假设&#xff08;每个词出现的概率仅依赖前面出现的词&#xff09;&#xff0c;是一个自回归模型&#xff08;…

docker部署nginx下日志自动切割方法

前言&#xff1a;nginx采用docker部署&#xff0c;简单方便&#xff0c;但出现一个问题&#xff0c;就是日志没有自动切割&#xff0c;导致access.log 无限增大。如果非docker安装&#xff0c;则nginx的日志默认有切割的&#xff0c;那docker为何没有呢&#xff0c;最后发现&am…

git | 合并merge、衍合rebase与同步更新cherry-pick

git | 合并merge、衍合rebase与同步更新cherry-pick 文章目录 git | 合并merge、衍合rebase与同步更新cherry-pickgit meregegit rebasegit rebase和git merge的区别总结 cherry-pick 把别的分支的改动内容同步更新到自己的分支Example: Reference 欢迎关注公众号“三戒纪元” …

第 4 章 串(文本行编辑实现)

1. 背景说明 该文本编辑器利用串的堆实现&#xff0c;其中对串的原始存储方式基本不作修改&#xff08;有部分修改之处&#xff09;&#xff0c;优化之处在于在串的末尾加上了一个空字符&#xff0c;目的是区分字符串结尾&#xff0c;便于将串保存在文件中&#xff0c;且该优化…