闲着没事搞了小程序,在Window上面往linux机器上群发命令,
写的不好欢迎大家指正,还有就是用此工具发送恶意命令的人请离开,
编译了一份64_Window和linux的程序,供大家参考使用,Rm_tmp_cmd.exe 在win下面提供使用!
我的目录结构:
flagparse
--------flag.go
Getconf
--------getconfig.go
Maste
--------scp.go
--------ssh_client.go
Zip_File
--------zip.go
maste.go
ssh.conf
命令文件:ssh.conf 第一行是需要群发的命令,用英文','隔开 然后下面是主机IP:PORT user password command ---->这个command的是只发给这个主机的命令,不会发到其他的主机上,可以理解为私有的命令 0`ls -a,df -h 1`127.0.0.1:5000`root`123456`ls -l,free -m 2`127.0.0.1:5000`root`123456`df -h,pwd 3`127.0.0.1:5506`root`123456`cd /mnt/ && python ping.py > 2015.txt &
flag.go 命令行解析参数文件: package flagparse import ( "flag" ) func Flag() (*string, *bool, *string, *bool) { var ( sendfile = flag.String("F", "", "此参数表示向所有标签主机发送文件,参数代表文件路径,例如:-F=/mnt/2015.go") Global_command = flag.Bool("G", false, "此参数代表是否执行全局命令,默认是不启用,如果启用使用:-G=true或-G") SendAll = flag.String("S", "", "此参数代表向这些标签的主机发送命令:-S=1,2执行1,2标签的命令") PrintLog = flag.Bool("P", false, "此参数默认表示是否印输出执行结果,如果打印日志使用:-P=true或-P") ) flag.Parse() return sendfile, Global_command, SendAll, PrintLog }
getconfig.go 解析配置文件(ssh.conf) package Getconf import ( "bufio" "fmt" "io" "os" "path/filepath" "strings" ) //获取ssh.conf的配置文件,以map的形式把每行的数据返回 func GetConfig() map[string][]string { ProPath := os.Args[0] os.Chdir(filepath.Dir(ProPath)) Config := make(map[string][]string) File, err := os.Open("ssh.conf") if err != nil { fmt.Println("From GetConfig :", err) } defer File.Close() Buf := bufio.NewReader(File) for { line, _, err := Buf.ReadLine() if err != nil { if err == io.EOF { break } fmt.Println("From GetConfig :", err) break } x := strings.Split(string(line), "`") Config[x[0]] = x[1:] } return Config }
scp.go 用来发送文件: package Maste import ( "Zip_File" "fmt" "go-ssh/ssh" "io" "os" "path/filepath" "strings" ) func Use_Scp_Send(SendAll, Path *string, config map[string][]string, Ok, Err, Sta chan string) { FlagList := strings.Split(*SendAll, ",") Name := filepath.Base(*Path) SendFilePath := *Path OldPath, _ := os.Getwd() if File, e := os.Stat(SendFilePath); e == nil { if File.IsDir() { Zip_File.AddFilesToZip(SendFilePath, Name) SendFilePath = fmt.Sprintf("%s\\%s.zip", OldPath, Name) Name = fmt.Sprintf("%s.zip", Name) } } else { fmt.Println(SendFilePath, " :不存在!") os.Exit(2) } fmt.Println("发送的文件名:", Name) if *SendAll == "" { for i, _ := range config { if i != "0" { go connect(config[i][0], config[i][1], config[i][2], SendFilePath, Name, Ok, Err, Sta) } } } else { for _, i := range FlagList { go connect(config[i][0], config[i][1], config[i][2], SendFilePath, Name, Ok, Err, Sta) } } } func connect(ip, user, password, FilePath, Name string, Ok, Err, Sta chan string) { Auth := []ssh.AuthMethod{ssh.Password(password)} conf := ssh.ClientConfig{Auth: Auth, User: user} Client, err0 := ssh.Dial("tcp", ip, &conf) if err0 == nil { Ok <- fmt.Sprint(ip, " 连接状态:Ok") } else { Err <- fmt.Sprint(ip, " 连接错误:", err0) } defer Client.Close() conn, err1 := Client.NewSession() if err1 == nil { Ok <- fmt.Sprint(ip, " 会话状态:Ok") } else { Err <- fmt.Sprint(ip, " 会话错误:", err1) } defer conn.Close() go func() { Buf := make([]byte, 1024) w, _ := conn.StdinPipe() defer w.Close() File, _ := os.Open(FilePath) defer File.Close() info, _ := File.Stat() fmt.Fprintln(w, "C0644", info.Size(), Name) for { n, err := File.Read(Buf) fmt.Fprint(w, string(Buf[:n])) if err != nil { if err == io.EOF { return } else { panic(err) } } } }() err3 := conn.Run("scp -qrt /mnt/") //会保存在mnt下面 if err3.Error() == "Process exited with: 1. Reason was: ()" { Ok <- fmt.Sprint(ip, " 执行状态:Ok") Sta <- "Ok" } else { Err <- fmt.Sprint(ip, " 执行错误:", err3) } }
ssh_client.go 连接主机主程序 package Maste import ( "bytes" "fmt" "go-ssh/ssh" ) func SSH_Client(ip_port, user, password string, command []string, P bool, Ok, Err, Res chan string) { PassWd := []ssh.AuthMethod{ssh.Password(password)} Conf := ssh.ClientConfig{User: user, Auth: PassWd} Client, err := ssh.Dial("tcp", ip_port, &Conf) if err == nil { Ok <- fmt.Sprint(ip_port, " 连接状态:Ok") } else { Err <- fmt.Sprint(ip_port, " ErrorInfo:", err) return } defer Client.Close() for _, Command := range command { if session, err := Client.NewSession(); err == nil { defer session.Close() var Result bytes.Buffer session.Stderr = &Result session.Stdout = &Result err = session.Run(Command) if err == nil { Ok <- fmt.Sprint(ip_port, " 命令:", Command, " 执行状态:Ok") } else { Err <- fmt.Sprint(ip_port, " ErrorInfo:", err) } if P { Res <- fmt.Sprint(ip_port, " 执行结果\n", Result.String()) } } } }
zip.go 使用发送文件之前会调用此函数来进行压缩 package Zip_File import ( "archive/zip" "fmt" "io" "os" "path/filepath" //"strings" ) func AddFilesToZip(Path, Name string) { //var PathName string File, _ := os.Create(fmt.Sprintf("%s.zip", Name)) /* PS := strings.Split(Path, "/") if len(PS) == 2 { PathName = fmt.Sprintf("%s/", PS[0]) } else { PathName = strings.Join(PS[:len(PS)-1], "/") } os.Chdir(PathName) Path = PS[len(PS)-1] */ os.Chdir(filepath.Dir(Path)) Path = filepath.Base(Path) defer File.Close() Zip := zip.NewWriter(File) defer Zip.Close() walk := func(Path string, info os.FileInfo, err error) error { if err != nil { fmt.Println(err) return err } if info.IsDir() { return nil } Src, _ := os.Open(Path) defer Src.Close() h := &zip.FileHeader{Name: Path, Method: zip.Deflate, Flags: 0x800} FileName, _ := Zip.CreateHeader(h) io.Copy(FileName, Src) Zip.Flush() return nil } filepath.Walk(Path, walk) }
maste.go 入口程序 package main import ( "Getconf" "Maste" "flagparse" "fmt" "os" "os/exec" "path/filepath" "strings" "time" ) var Rm_cmd_path, _ = os.Getwd() var ( timeout int = 0 TimeOut int = 10 Ok chan string = make(chan string) Err chan string = make(chan string) Res chan string = make(chan string) Sta chan string = make(chan string) ) func main() { var Num int Sendfile, Global_command, SendAll, PrintLog := flagparse.Flag() config := Getconf.GetConfig() if *Sendfile != "" { TimeOut = 3600 Maste.Use_Scp_Send(SendAll, Sendfile, config, Ok, Err, Sta) } else { SendCommand(SendAll, Global_command, PrintLog, config) } if *SendAll == "" { Num = len(config) - 1 } else { Num = len(strings.Split(*SendAll, ",")) } defer RmFile(Sendfile) for { Check_status(*PrintLog, Num, Sendfile) } } //根据参数发送命令 func SendCommand(SendAll *string, Global_command, PrintLog *bool, config map[string][]string) { FlagList := strings.Split(*SendAll, ",") if *SendAll == "" { for _, i := range FlagList { Com := Global_cmd(config["0"]) go Maste.SSH_Client(config[i][0], config[i][1], config[i][2], Com, *PrintLog, Ok, Err, Res) } } else { for _, i := range FlagList { Com := Private_cmd(config["0"], config[i][3], *Global_command) go Maste.SSH_Client(config[i][0], config[i][1], config[i][2], Com, *PrintLog, Ok, Err, Res) } } } //解析ssh.conf中的command字段: func Global_cmd(Global []string) []string { return strings.Split(Global[0], ",") } func Private_cmd(Global []string, Private string, Globlcomand bool) []string { if Globlcomand { Private_cmd := strings.Split(Private, ",") var cmd []string = Global_cmd(Global) for _, i := range Private_cmd { cmd = append(cmd, i) } return cmd } else { return strings.Split(Private, ",") } } //获取chan管道的状态. func Check_status(P bool, Num int, Sendfile *string) { var Break int = 0 if P { for { select { case x := <-Err: fmt.Println(x) timeout = TimeOut - 2 case y := <-Ok: fmt.Println(y) timeout = 0 case z := <-Res: fmt.Println(z) timeout = 0 case <-Sta: Break = Break + 1 if Break >= Num { RmFile(Sendfile) os.Exit(1) } default: if timeout > TimeOut { os.Exit(2) } timeout = timeout + 1 time.Sleep(1e9) } } } else { for { select { case x := <-Err: fmt.Println(x) timeout = TimeOut - 2 case y := <-Ok: fmt.Println(y) timeout = 0 case <-Sta: Break = Break + 1 if Break >= Num { RmFile(Sendfile) os.Exit(3) } default: if timeout > TimeOut { os.Exit(4) } timeout = timeout + 1 time.Sleep(1e9) } } } } func RmFile(Sendfile *string) { os.Chdir(Rm_cmd_path) if info, err := os.Stat(*Sendfile); err == nil && info.IsDir() { Rm_Path := fmt.Sprintf("%s.zip", filepath.Base(*Sendfile)) cmd := exec.Command("Rm_tmp_cmd.exe", Rm_Path) cmd.Run() } }