Skip to content

Instantly share code, notes, and snippets.

@indeedhat
Forked from brianm/.gitignore
Last active February 12, 2020 00:13
Show Gist options
  • Save indeedhat/dbdf1d426ccdf4617c07eb30d805095f to your computer and use it in GitHub Desktop.
Save indeedhat/dbdf1d426ccdf4617c07eb30d805095f to your computer and use it in GitHub Desktop.
Go net/rpc over ssh+netcat and unix domain sockets It would be nice if ssh.Session implemented io.ReaderWriter
local_client
server
client
ext
package main
import (
"fmt"
"golang.org/x/crypto/ssh"
"log"
"net"
"net/rpc"
"os"
"strings"
)
// RPC response container
type Response struct {
Greeting string
}
// RPC request container
type Request struct {
Name string
}
// ./client localhost:/tmp/foo {name} {password}
func main() {
parts := strings.Split(os.Args[1], ":")
host := parts[0]
path := parts[1]
name := os.Args[2]
passwd := os.Args[3]
// SSH setup, we assume current username and use the ssh agent
// for auth
agent_sock, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
log.Fatalf("sorry, this example requires the ssh agent: %s", err)
}
defer agent_sock.Close()
config := &ssh.ClientConfig{
User: os.Getenv("USER"),
Auth: []ssh.AuthMethod{
ssh.Password(passwd),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
ssh_client, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", host), config)
if err != nil {
panic("Failed to dial: " + err.Error())
}
defer ssh_client.Close()
s, err := ssh_client.Dial("unix", path)
if err != nil {
log.Fatalf("unable to connect to remote socket", err)
}
// now comes the RPC!
client := rpc.NewClient(s)
defer client.Close()
req := &Request{name}
var res Response
err = client.Call("Greeter.Greet", req, &res)
if err != nil {
log.Fatalf("error in rpc: %s", err)
}
fmt.Println(res.Greeting)
}
package main
import (
"fmt"
"log"
"net/rpc"
"os"
)
type Response struct {
Greeting string
}
type Request struct {
Name string
}
// ./local_client /tmp/foo Brian
func main() {
client, err := rpc.Dial("unix", os.Args[1])
if err != nil {
log.Fatalf("failed: %s", err)
}
req := &Request{os.Args[2]}
var res Response
err = client.Call("Greeter.Greet", req, &res)
if err != nil {
log.Fatalf("error in rpc: %s", err)
}
fmt.Println(res.Greeting)
}
build: setup
GOPATH=$(PWD):$(PWD)/ext go build server.go
GOPATH=$(PWD):$(PWD)/ext go build client.go
GOPATH=$(PWD):$(PWD)/ext go build local_client.go
fmt:
GOPATH=$(PWD) go fmt *.go
clean:
rm -rf server client local_client ext/pkg
setup:
GOPATH=$(PWD)/ext go get golang.org/x/crypto/ssh
godoc:
GOPATH=$(PWD):$(PWD)/ext godoc -http=:6060
package main
import (
"fmt"
"log"
"net"
"net/rpc"
"os"
"os/signal"
"syscall"
)
// rpc response
type Response struct {
Greeting string
}
// rpc request
type Request struct {
Name string
}
// rpc host struct thing
type Greeter struct{}
// our remotely invocable function
func (g *Greeter) Greet(req Request, res *Response) (err error) {
res.Greeting = fmt.Sprintf("Hello %s", req.Name)
return
}
// start up rpc listener at path
func ServeAt(path string) (err error) {
rpc.Register(&Greeter{})
listener, err := net.Listen("unix", path)
if err != nil {
return fmt.Errorf("unable to listen at %s: %s", path, err)
}
go rpc.Accept(listener)
return
}
// ./server /tmp/foo
func main() {
path := os.Args[1]
err := ServeAt(path)
if err != nil {
log.Fatalf("failed: %s", err)
}
defer os.Remove(path)
// block until we are signalled to quit
wait()
}
func wait() {
signals := make(chan os.Signal)
signal.Notify(signals, syscall.SIGINT, syscall.SIGKILL, syscall.SIGHUP)
<-signals
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment