|
package main |
|
|
|
import ( |
|
"code.google.com/p/go.crypto/ssh" |
|
"fmt" |
|
"io" |
|
"log" |
|
"net" |
|
"net/rpc" |
|
"os" |
|
"strings" |
|
) |
|
|
|
// RPC response container |
|
type Response struct { |
|
Greeting string |
|
} |
|
|
|
// RPC request container |
|
type Request struct { |
|
Name string |
|
} |
|
|
|
// It would be nice if ssh.Session was an io.ReaderWriter |
|
// proposal submitted :-) |
|
type NetCatSession struct { |
|
*ssh.Session // define Close() |
|
writer io.Writer |
|
reader io.Reader |
|
} |
|
|
|
// io.Reader |
|
func (s NetCatSession) Read(p []byte) (n int, err error) { |
|
return s.reader.Read(p) |
|
} |
|
|
|
// io.Writer |
|
func (s NetCatSession) Write(p []byte) (n int, err error) { |
|
return s.writer.Write(p) |
|
} |
|
|
|
// given the established ssh connection, start a session against netcat and |
|
// return a io.ReaderWriterCloser appropriate for rpc.NewClient(...) |
|
func StartNetCat(client *ssh.ClientConn, path string) (rwc *NetCatSession, err error) { |
|
session, err := client.NewSession() |
|
if err != nil { |
|
return |
|
} |
|
|
|
cmd := fmt.Sprintf("/usr/bin/nc -U %s", path) |
|
in, err := session.StdinPipe() |
|
if err != nil { |
|
return nil, fmt.Errorf("unable to get stdin: %s", err) |
|
} |
|
|
|
out, err := session.StdoutPipe() |
|
if err != nil { |
|
return nil, fmt.Errorf("unable to get stdout: %s", err) |
|
} |
|
|
|
err = session.Start(cmd) |
|
if err != nil { |
|
return nil, fmt.Errorf("unable to start '%s': %s", cmd, err) |
|
} |
|
|
|
return &NetCatSession{session, in, out}, nil |
|
} |
|
|
|
// ./client localhost:/tmp/foo Brian |
|
func main() { |
|
parts := strings.Split(os.Args[1], ":") |
|
host := parts[0] |
|
path := parts[1] |
|
name := os.Args[2] |
|
|
|
// 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.ClientAuth{ |
|
ssh.ClientAuthAgent(ssh.NewAgentClient(agent_sock)), |
|
}, |
|
} |
|
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() |
|
|
|
// Establish sesstion to netcat talking to the domain socket |
|
s, err := StartNetCat(ssh_client, path) |
|
if err != nil { |
|
log.Fatalf("unable to start netcat session: %s", 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) |
|
} |