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.mzph.cn/news/84735.shtml

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

相关文章

Jetpack Compose 的简单 MVI 框架

Jetpack Compose 的简单 MVI 框架 在 Jetpack Compose 应用程序中管理状态的一种简单方法 选择正确的架构是至关重要的&#xff0c;因为架构变更后期代价高昂。MVP已被MVVM和MVI取代&#xff0c;而MVI更受欢迎。MVI通过强制实施结构化的状态管理方法&#xff0c;只在reducer中…

std::thread简单使用

std::thread 是 C 标准库中用于多线程编程的类。它允许你创建和管理线程&#xff0c;使程序能够并发执行不同的任务。以下是关于 std::thread 的详细介绍以及几个示例说明&#xff1a; 创建线程 你可以使用 std::thread 构造函数创建新的线程&#xff0c;并将要执行的函数传递…

预防API漏洞简述

随着对网络应用程序和数字平台的日益依赖&#xff0c;应用程序编程接口&#xff08;API&#xff09;的使用变得越来越流行。如果你不熟悉这个术语&#xff0c;API允许应用程序相互通信&#xff0c;它们在现代软件开发中发挥着至关重要的作用。 然而&#xff0c;API使用量的增加…

控制台日志打印console的封装,加入美化、行显示与打印开关,支持node.js环境

控制台日志打印console的封装&#xff0c;加入美化、行显示与打印开关&#xff0c;支持node.js环境 为什么要写这个&#xff1f; 封装这个控制台日志打印工具&#xff0c;主要是在项目中自己做的SDK需要提供给其他开发人员使用&#xff0c;加入了日志美化和打印打开&#xff…

【数据结构】顺序表与ArrayList

作者主页&#xff1a;paper jie 的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVA数据结构》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精…

【云计算】虚拟私有云 VPC

虚拟私有云 VPC 1.前言1.1 基本介绍1.2 VPC 的作用1.3 VPC 的适用人群 2.VPC 基本概念2.1 VPC 相关基本概念2.2 其他相关基本概念 3.VPC 通信场景3.1 VPC 内部互通3.2 VPC 间互通3.2.1 对等连接3.2.2 Transit Gateway 或者云联网 3.3 访问 Internet3.3.1 Internet 网关3.3.2 NA…

多进程操作数据库异常问题

问题场景&#xff1a; 消息中心批量删除历史数据&#xff0c;偶现删不掉的情况。 消息中心的数据存储在数据库中&#xff0c;在删除数据时&#xff0c;由于是批量操作&#xff0c;可能这时候有新消息过来&#xff0c;就会插入新数据&#xff0c;这样就出现多线程操作数据库的情…

【HCIE】04.网络安全技术

端口隔离 在同一VLAN中可以隔离二层与三层通信&#xff0c;让同VLAN内的设备可以通信或者不可以通信。 定义一个端口隔离组&#xff0c;在一个组内无法互访&#xff0c;不在一个组里面可以进行互访 port-isolate enable group1 //使能端口隔离功能 port-isolate mdoe all //全…

B : DS顺序表--连续操作

Description 建立顺序表的类&#xff0c;属性包括&#xff1a;数组、实际长度、最大长度&#xff08;设定为1000&#xff09; 该类具有以下成员函数&#xff1a; 构造函数&#xff1a;实现顺序表的初始化。 插入多个数据的multiinsert(int i, int n, int item[])函数&#…

Unity 开发人员转CGE(castle Game engine)城堡游戏引擎指导手册

Unity 开发人员的城堡游戏引擎概述 一、简介2. Unity相当于什么GameObject&#xff1f;3. 如何设计一个由多种资产、生物等组成的关卡&#xff1f;4. 在哪里放置特定角色的代码&#xff08;例如生物、物品&#xff09;&#xff1f;Unity 中“向 GameObject 添加 MonoBehaviour”…

qml ProgressBar用法介绍

ProgressBar 是 QML 中的一个组件,用于显示一个任务的完成进度。它是 Qt Quick Controls 2 模块中的一个组件,使用时需要包含import QtQuick.Controls. ProgressBar常用于显示文件上传、下载、计算或其他长时间任务的进度。 下面是 ProgressBar 的一些基本用法: 1. 基本使…

GAN初识

1. 生成对抗网络GAN简介 1.1 生成器 G(Z)接受随机噪声Z作为输入生成仿品&#xff0c;并训练自己去欺骗判别器D&#xff0c;让D以为G(Z)产生的任何数据都是真实的。 1.2 判别器 D(Y)可以基于真品和仿品来判断仿造品的仿真程度&#xff0c;通常值越靠近0表示越真实(靠近1表示仿造…

Vue3大屏项目实现数字跳动的效果

一、vue-count-to组件&#xff1a; 1、安装&#xff1a; npm install vue3-count-to --save 2、使用&#xff1a; <template><BaseCountTo:startVal"startVal":endVal"endVal":duration"duration":decimals"decimals":pr…

基于复旦微的FMQL45T900全国产化ARM核心模块(100%国产化)

TES745D是一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板。该核心板将复旦微的FMQL45T900&#xff08;与XILINX的XC7Z045-2FFG900I兼容&#xff09;的最小系统集成在了一个87*117mm的核心板上&#xff0c;可以作为一个核心模块&#xff0c;进行功能性扩展&#xff0c;能…

Redis 五大类型源码及底层实现

面试题&#xff1a; 谈谈Redis数据类型的底层数据结构&#xff1a; SDS动态字符串双向链表玉缩列表ziplist哈希表hashtable跳表kiplist整数集合intset快速列表quicklist紧凑列表listpack Redis源代码的核心部分 官网&#xff1a;GitHub - redis/redis: Redis is an in-memory…

在已知的二维坐标里找到最接近的点

一、业务场景 最近在研发的项目&#xff0c;在做可视化层&#xff0c;在全球地图上&#xff0c;对我们的国家的陆地地图经纬度按照步长为1的间隔做了二维处理。在得到一组整数的点位信息后&#xff0c;需要将我们已有的数据库数据(业务项目)按照地址的经纬度&#xff0c;映射到…

大数据Flink(八十三):SQL语法的DML:With、SELECT WHERE、SELECT DISTINCT 子句

文章目录 SQL语法的DML:With、SELECT & WHERE、SELECT DISTINCT 子句 一、DML:With 子句

本地Docker Registry远程连接,为你带来高效便捷的镜像管理体验!

Linux 本地 Docker Registry本地镜像仓库远程连接 文章目录 Linux 本地 Docker Registry本地镜像仓库远程连接1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址…

jmeterbeanshell调用jsonpath获取对应值

1.jmeter 新建线程组、Java Request、BeanShell Assertion、View Results Tree 2、在BeanShell Assertion中贴入代码&#xff1a; import org.apache.jmeter.extractor.json.jsonpath.JSONManager; import java.util.List; JSONManager js new JSONManager(); String jsonStr…

电商项目高级篇-01 elasticsearch

电商项目高级篇-01 elasticsearch 1、linux下安装elasticsearch和可视化工具2、docker设置虚拟机开机启动和容器开机启动3、elasticsearch的curd3.1、新增、更新3.2、查询 1、linux下安装elasticsearch和可视化工具 将安装好jdk1.8和tomcat的centos7下安装elasticsearch dock…