Go Library to Execute Commands Over SSH at Scale

vSSH

Go library to handle tens of thousands SSH connections and execute the command(s) with higher-level API for building network device / server automation. Documentation and examples are available via godoc.

Test Status Go Report Card Coverage Status GoDoc PkgGoDev

Alt text

Features

  • Connect to multiple remote machines concurrently
  • Persistent SSH connection
  • DSL query based on the labels
  • Manage number of sessions per SSH connection
  • Limit amount of stdout and stderr data in bytes
  • Higher-level API for building automation

Sample query with label

labels := map[string]string {
  "POP" : "LAX",
  "OS" : "JUNOS",
}
// sets labels to a client
vs.AddClient(addr, config, vssh.SetLabels(labels))
// query with label
vs.RunWithLabel(ctx, cmd, timeout, "(POP == LAX || POP == DCA) && OS == JUNOS")

Basic example

vs := vssh.New().Start()
config := vssh.GetConfigUserPass("vssh", "vssh")
for _, addr := range []string{"54.193.17.197:22", "192.168.2.19:22"} {
  vs.AddClient(addr, config, vssh.SetMaxSessions(4))
}
vs.Wait()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

cmd:= "ping -c 4 192.168.55.10"
timeout, _ := time.ParseDuration("6s")
respChan := vs.Run(ctx, cmd, timeout)

for resp := range respChan {
  if err := resp.Err(); err != nil {
    log.Println(err)
      continue
    }

  outTxt, errTxt, _ := resp.GetText(vs)
  fmt.Println(outTxt, errTxt, resp.ExitStatus())
}

Stream example

vs := vssh.New().Start()
config, _ := vssh.GetConfigPEM("vssh", "mypem.pem")
vs.AddClient("54.193.17.197:22", config, vssh.SetMaxSessions(4))
vs.Wait()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

cmd:= "ping -c 4 192.168.55.10"
timeout, _ := time.ParseDuration("6s")
respChan := vs.Run(ctx, cmd, timeout)

resp := <- respChan
if err := resp.Err(); err != nil {
  log.Fatal(err)
}

stream := resp.GetStream()
defer stream.Close()

for stream.ScanStdout() {
  txt := stream.TextStdout()
  fmt.Println(txt)
}

Supported platform

  • Linux
  • Windows
  • Darwin
  • BSD
  • Solaris

License

Code is licensed under the Apache License, Version 2.0 (the "License"). Content is licensed under the CC BY 4.0 license. Terms available at https://creativecommons.org/licenses/by/4.0/.

Contribute

Welcomes any kind of contribution, please follow the next steps:

  • Fork the project on github.com.
  • Create a new branch.
  • Commit changes to the new branch.
  • Send a pull request.
Owner
Yahoo
Yahoo is a Verizon Media brand. This organization is the home to many of the active open source projects published by engineers at Yahoo and Verizon Media.
Yahoo
Comments
  • Feature: feed private key from memory

    Feature: feed private key from memory

    Currently vssh.GetConfigPEM() function expects to read the key from a file on disk via: key, err := ioutil.ReadFile(keyFile) but when using vssh as a library it can be not very convenient to generate a new key, write it to disk and then read it from disk again in GetConfigPEM(). Instead it would be great to have the option to generate a private key and feed it directly from memory to either GetConfigPEM() or a similar function like GetConfigFoo(user string, block *pem.Block) or GetConfigFoo(user string, block []byte). Let me know what are your thoughts :)

  • Fix typo in code of conduct section.

    Fix typo in code of conduct section.

    I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.

  • Race condition

    Race condition

    Hello everyone, there seems to be a race condition in the following places:

    WARNING: DATA RACE
    Read at 0x00c00130d650 by goroutine 43:
      github.com/yahoo/vssh.(*VSSH).reConnect()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:369 +0x128
    
    Previous write at 0x00c00130d650 by goroutine 280:
      github.com/yahoo/vssh.(*clientAttr).setErr()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:314 +0x564
      github.com/yahoo/vssh.(*clientAttr).connect()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:366 +0x42d
      github.com/yahoo/vssh.(*connect).run()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:403 +0x228
      github.com/yahoo/vssh.(*VSSH).process.func1()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:223 +0x20e
    
    Goroutine 43 (running) created at:
      github.com/yahoo/vssh.(*VSSH).Start()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:193 +0xbc
    
    Goroutine 280 (running) created at:
      github.com/yahoo/vssh.(*VSSH).process()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:216 +0x64
    ==================
    ==================
    WARNING: DATA RACE
    Read at 0x00c00130d648 by goroutine 43:
      github.com/yahoo/vssh.(*VSSH).reConnect()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:369 +0x32c
    
    Previous write at 0x00c00130d648 by goroutine 280:
      github.com/yahoo/vssh.(*clientAttr).setErr()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:311 +0x472
      github.com/yahoo/vssh.(*clientAttr).connect()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:366 +0x42d
      github.com/yahoo/vssh.(*connect).run()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:403 +0x228
      github.com/yahoo/vssh.(*VSSH).process.func1()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:223 +0x20e
    
    Goroutine 43 (running) created at:
      github.com/yahoo/vssh.(*VSSH).Start()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:193 +0xbc
    
    
    Goroutine 280 (running) created at:
      github.com/yahoo/vssh.(*VSSH).process()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:216 +0x64
    
  • Fix example

    Fix example

    The arguments of example's vssh.GetConfigPEM(user, keyFile string) look different.

    https://godoc.org/github.com/yahoo/vssh#GetConfigPEM

    I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.

  • Empty resp.ID()

    Empty resp.ID()

    Hello, seems like if a response contains an error then resp.ID() produces an empty string.

    for resp := range respChan {
      if err := resp.Err(); err != nil {
        log.Println(resp.ID())
        }
    }
    
  • Race conditions

    Race conditions

    Hello, i just found a couple of race conditions, seems like there could be more given that client write and read happens in multiple places so some access synchronization to this data structure would be needed. Please see below:

    WARNING: DATA RACE
    Write at 0x00c0002024a0 by goroutine 46:
      github.com/yahoo/vssh.(*clientAttr).connect()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:360 +0x5f7
      github.com/yahoo/vssh.(*connect).run()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:393 +0x20b
      github.com/yahoo/vssh.(*VSSH).process.func1()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:223 +0x1f1
    
    Previous read at 0x00c0002024a0 by main goroutine:
      github.com/yahoo/vssh.(*VSSH).Wait()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:425 +0xda
    
    Goroutine 46 (running) created at:
      github.com/yahoo/vssh.(*VSSH).process()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:216 +0x64
    ==================
    ==================
    WARNING: DATA RACE
    Read at 0x00c000202690 by goroutine 1104:
      github.com/yahoo/vssh.(*query).run.func1()
          go/pkg/mod/github.com/yahoo/[email protected]/query.go:74 +0xfd
    
    Previous write at 0x00c000202690 by goroutine 48:
      github.com/yahoo/vssh.(*clientAttr).connect()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:362 +0x69a
      github.com/yahoo/vssh.(*connect).run()
          go/pkg/mod/github.com/yahoo/[email protected]/client.go:393 +0x20b
      github.com/yahoo/vssh.(*VSSH).process.func1()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:223 +0x1f1
    
    Goroutine 1104 (running) created at:
      github.com/yahoo/vssh.(*query).run()
          go/pkg/mod/github.com/yahoo/[email protected]/query.go:63 +0x120
      github.com/yahoo/vssh.(*VSSH).process.func1()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:226 +0x27e
    
    Goroutine 48 (running) created at:
      github.com/yahoo/vssh.(*VSSH).process()
          go/pkg/mod/github.com/yahoo/[email protected]/vssh.go:216 +0x64
    
  • edit comments, trim whitespace

    edit comments, trim whitespace

    PR makes editorial changes to the comments (adding periods to sentences etc.) and truncates trailing whitespace (due to editor settings - will help to avoid such "spurious" diffs in the future).

    I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.

  • correct staticcheck issues

    correct staticcheck issues

    PR contains changes to fix the code issues flagged by staticcheck:

    $ staticcheck ./...
    
    client.go:273:2: should use 'return <expr>' instead of 'if <expr> { return <bool> }; return <bool>' (S1008)
    client.go:501:2: should use a simple channel send/receive instead of select with a single case (S1000)
    client.go:529:2: should use a simple channel send/receive instead of select with a single case (S1000)
    client_test.go:502:2: this value of session is never used (SA4006)
    example_test.go:119:20: session.New is deprecated: Use NewSession functions to create sessions instead. NewSession has the same functionality as New except an error can be returned when the func is called instead of waiting to receive an error until a request is made.  (SA1019)
    example_test.go:139:24: *&x will be simplified to x. It will not copy x. (SA4001)
    vssh.go:51:2: field ctx is unused (U1000)
    vssh.go:60:2: field errors is unused (U1000)
    vssh.go:62:2: field clients is unused (U1000)
    vssh.go:369:19: using time.Tick leaks the underlying ticker, consider using it only in endless functions, tests and the main package, and use time.NewTicker here (SA1015)
    

    I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.

  • Source ip/host?

    Source ip/host?

    In the following code provided in the examples, how to get the client ip/host which generated the outTxt

    	// get the resp channel for each client
    	for resp := range respChan {
    		// in case of the connectivity issue to client
    		if err := resp.Err(); err != nil {
    			log.Println(err)
    			continue
    		}
    
    		// get the returned data from client
    		outTxt, errTxt, err := resp.GetText(vs)
    
  • SetInitNumProc compile error

    SetInitNumProc compile error

    With the following code

            vs := vssh.New()
            vs.SetInitNumProc(2)
            vs.Start()
    

    I am getting the following output command-line-arguments ./main.go:13:4: vs.SetInitNumProc undefined (type *vssh.VSSH has no field or method SetInitNumProc)

  • Bogus example in comment/README.md

    Bogus example in comment/README.md

    The README.md file, and the vssh.go docstring available here both contain the following example:

    vs.RunWithLabel(ctx, cmd, timeout, "POP == LAX || POP == DCA) && OS == JUNOS")

    The expression there is malformed:

    POP == LAX || POP == DCA) && OS == JUNOS

    Notice the closing ), without an opening (.

  • Fix lost chunks during streaming of large volumes of data.

    Fix lost chunks during streaming of large volumes of data.

    The current streaming implementation allows for chunks of data to be lost in VSSH's default select{} cases, if volumes of data arrive at a rate too high to be processed. The default cases get selected when the write channel buffer becomes full and would block. This patch puts a client into a streaming mode when the GetStream() function is called, which causes a blocking select{} to be used until the streaming mode is ended.

    I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.

  • Provide direct access to ssh.Session.StdoutPipe

    Provide direct access to ssh.Session.StdoutPipe

    In situations where one needs to receive large amounts of binary data from a remote server, the only way to do so in vssh is for the remote server to send it in newline-terminated chunks <64k at a time.

    In client.go, ssh.Session.StdoutPipe gets connected to a bufio.Scanner, which is not suitable for binary data since its default buffer is limited to 64k. Ideally there should be a way to directly export ssh.Session.StdoutPipe so that scanning and reading can be left up to the implementation that's using vssh.

Gsshrun - Running commands via ssh on the server/hosting (if ssh support) specified in the connection file

Gsshrun - Running commands via ssh on the server/hosting (if ssh support) specified in the connection file

Sep 8, 2022
Extended ssh-agent which supports git commit signing over ssh

ssh-agentx ssh-agentx Rationale Requirements Configuration ssh-agentx Configuration ssh-gpg-signer Linux Windows Signing commits after configuration T

Jun 29, 2022
Golang `net/rpc` over SSH using installed SSH program

Golang net/rpc over SSH using installed SSH program This package implements a helper functions to launch an RPC client and server. It uses the install

Nov 16, 2022
one simple git ssh server (just for learning git over ssh )

wriet one simple git ssh server use golang write one simple git ssh server how to running starting service docker-compose up -d add authorized_keys i

Mar 5, 2022
The devs are over here at devzat, chat over SSH!

Devzat Where are the devs at? Devzat! Devzat is chat over SSH Try it out: ssh sshchat.hackclub.com Add this to ~/.ssh/config: Host chat HostName s

Jan 7, 2023
Feb 10, 2022
red-tldr is a lightweight text search tool, which is used to help red team staff quickly find the commands and key points they want to execute, so it is more suitable for use by red team personnel with certain experience.
red-tldr is a lightweight text search tool, which is used to help red team staff quickly find the commands and key points they want to execute, so it is more suitable for use by red team personnel with certain experience.

Red Team TL;DR English | ไธญๆ–‡็ฎ€ไฝ“ What is Red Team TL;DR ? red-tldr is a lightweight text search tool, which is used to help red team staff quickly find t

Jan 5, 2023
Helps you to send ssh commands to target machine in your local network from outside via gRPC
Helps you to send ssh commands to target machine in your local network from outside via gRPC

rpc-ssh In case, you don't want to make your ssh port accessible from outside local network. This repository helps you to send ssh commands to target

Nov 16, 2022
Lightweight rest api that allows users to run Powershell commands over HTTP.

Powershell Proxy Lightweight rest api that allows users to run Powershell commands over HTTP. Requests require a valid JWT and responses are returned

Mar 18, 2022
Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH.
Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH.

Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH. Single executable including both client and server. Written in Go (golang). Chisel is mainly useful for passing through firewalls, though it can also be used to provide a secure endpoint into your network.

Jan 1, 2023
Serve traffic (HTTP/gRPC) over SSH using Domain Sockets

Serve On SSH Introduction There is often a need to offer services for administrative purposes on servers or even for microservices that are running on

Nov 10, 2022
Chat over SSH.

ssh-chat Custom SSH server written in Go. Instead of a shell, you get a chat prompt. Demo Join the party: $ ssh ssh.chat Please abide by our project'

Jan 7, 2023
SSHWaiterUtil - Wait for file to appear over an SSH connection

SSHWaiterUtil Simple util to wait for a remote file to appear, over SSH using pr

Jan 11, 2022
Clidle - Wordle over SSH with golang
Clidle - Wordle over SSH with golang

clidle Wordle, now over SSH. Try it: ssh clidle.ddns.net -p 3000 Or, run it loca

Dec 28, 2022
A pokedex over SSH project.
A pokedex over SSH project.

Charmeleon A pokedex over SSH project. Installation Clone the repository to get the server and pokemon data: git clone https://github.com/sha65536/cha

Dec 17, 2022
Hedged Go GRPC client which helps to reduce tail latency at scale.

hedgedgrpc Hedged Go GRPC client which helps to reduce tail latency at scale. Rationale See paper Tail at Scale by Jeffrey Dean, Luiz Andrรฉ Barroso. I

Dec 16, 2022
ZheTian Powerful remote load and execute ShellCode tool
 ZheTian Powerful remote load and execute ShellCode tool

ZheTian ZheTian Powerful remote load and execute ShellCode tool ๅ…ๆ€shellcodeๅŠ ่ฝฝๆก†ๆžถ ๅ‘ฝไปค่ฏฆ่งฃ -u๏ผšไปŽ่ฟœ็จ‹ๆœๅŠกๅ™จๅŠ ่ฝฝbase64ๆททๆท†ๅŽ็š„ๅญ—่Š‚็ ใ€‚ -r๏ผšไปŽๆœฌๅœฐๆ–‡ไปถๅ†…่ฏปใ€‚ -s๏ผš่ฏปๅ–ๆ— ไฟฎๆ”น็š„ๅŽŸๅง‹ๆ–‡ไปถ๏ผŒๅช่ƒฝไปŽๆœฌๅœฐๅŠ ่ฝฝ -o๏ผšๅ‚ๆ•ฐ

Jan 9, 2023