mirror of https://gogs.blitter.com/RLabs/xs
Completed net.Conn interface implementation for hkex.Conn; some tests of Op protocol in server
This commit is contained in:
parent
e09f052f45
commit
9fb9d073ab
|
@ -4,11 +4,82 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
hkex "blitter.com/herradurakex"
|
||||
)
|
||||
|
||||
const (
|
||||
OpR = 'r' // read(file) (binary mode)
|
||||
OpW = 'w' // (over)write
|
||||
OpA = 'a' // append
|
||||
OpRm = 'd' // rm
|
||||
OpRmD = 'D' // rmdir (rm -rf)
|
||||
OpM = 'm' // mkdir (-p)
|
||||
OpN = 'n' // re(n)ame (mv)
|
||||
OpCm = 'c' // chmod
|
||||
OpCo = 'C' // chown
|
||||
OpX = 'x' // exec
|
||||
)
|
||||
|
||||
type Op uint8
|
||||
|
||||
type cmdRunner struct {
|
||||
op Op
|
||||
who string
|
||||
arg string
|
||||
authCookie string
|
||||
CloseHandler func(*cmdRunner)
|
||||
status int
|
||||
}
|
||||
|
||||
func testCloseHandler(r *cmdRunner) {
|
||||
fmt.Println("[testCloseHandler()]")
|
||||
r.arg = "/usr/bin/touch " + r.arg
|
||||
cmd(r)
|
||||
}
|
||||
|
||||
func cmd(r *cmdRunner) {
|
||||
switch r.op {
|
||||
case OpR:
|
||||
//Clean up r.cmd beforehand
|
||||
r.arg = strings.TrimSpace(r.arg)
|
||||
fmt.Printf("[cmd was:'%s']\n", r.arg)
|
||||
runCmdAs(r.who, r.arg)
|
||||
fmt.Println(r.arg)
|
||||
break
|
||||
default:
|
||||
fmt.Printf("[cmd %d ignored:%d]\n", int(r.op))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Run a command (via os.exec) as a specific user
|
||||
func runCmdAs(who string, cmd string) (err error) {
|
||||
u, _ := user.Lookup(who)
|
||||
var uid, gid uint32
|
||||
fmt.Sscanf(u.Uid, "%d", &uid)
|
||||
fmt.Sscanf(u.Gid, "%d", &gid)
|
||||
//fmt.Println("uid:", uid, "gid:", gid)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
arg0 := args[0]
|
||||
args = args[1:]
|
||||
c := exec.Command(arg0, args...)
|
||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
||||
err = c.Run()
|
||||
if err != nil {
|
||||
log.Printf("Command finished with error: %v", err)
|
||||
log.Printf("[%s]\n", cmd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Demo of a simple server that listens and spawns goroutines for each
|
||||
// connecting client. Note this code is identical to standard tcp
|
||||
// server code, save for declaring 'hkex' rather than 'net'
|
||||
|
@ -41,10 +112,10 @@ func main() {
|
|||
// The loop then returns to accepting, so that
|
||||
// multiple connections may be served concurrently.
|
||||
go func(c hkex.Conn) (e error) {
|
||||
defer c.Close()
|
||||
ch := make(chan []byte)
|
||||
chN := 0
|
||||
eCh := make(chan error)
|
||||
var connOp *byte = nil
|
||||
|
||||
// Start a goroutine to read from our net connection
|
||||
go func(ch chan []byte, eCh chan error) {
|
||||
|
@ -57,23 +128,14 @@ func main() {
|
|||
eCh <- err
|
||||
return
|
||||
}
|
||||
if connOp == nil {
|
||||
// Initial xmit - get op byte
|
||||
// (TODO: determine valid ops
|
||||
// for now 'e' (echo), 'i' (interactive), 'x' (exec), ... ?)
|
||||
connOp = new(byte)
|
||||
*connOp = data[0]
|
||||
data = data[1:]
|
||||
chN -= 1
|
||||
fmt.Printf("[* connOp '%c']\n", *connOp)
|
||||
}
|
||||
|
||||
// send data if we read some.
|
||||
ch <- data[0:chN]
|
||||
}
|
||||
}(ch, eCh)
|
||||
|
||||
ticker := time.Tick(time.Second / 100)
|
||||
var r cmdRunner
|
||||
var connOp *byte = nil
|
||||
Term:
|
||||
// continuously read from the connection
|
||||
for {
|
||||
|
@ -82,12 +144,32 @@ func main() {
|
|||
case data := <-ch:
|
||||
// Do something with the data
|
||||
fmt.Printf("Client sent %+v\n", data[0:chN])
|
||||
if connOp == nil {
|
||||
// Initial xmit - get op byte
|
||||
// (TODO: determine valid ops
|
||||
// for now 'e' (echo), 'i' (interactive), 'x' (exec), ... ?)
|
||||
connOp = new(byte)
|
||||
*connOp = data[0]
|
||||
data = data[1:chN]
|
||||
chN -= 1
|
||||
|
||||
fmt.Printf("[* connOp '%c']\n", *connOp)
|
||||
// The CloseHandler typically handles the
|
||||
// accumulated command data
|
||||
r = cmdRunner{op: Op(*connOp),
|
||||
who: "larissa", arg: string(data),
|
||||
authCookie: "c00ki3",
|
||||
CloseHandler: testCloseHandler,
|
||||
status: 0}
|
||||
}
|
||||
|
||||
//fmt.Printf("Client sent %s\n", string(data))
|
||||
// This case means we got an error and the goroutine has finished
|
||||
case err := <-eCh:
|
||||
// handle our error then exit for loop
|
||||
if err.Error() == "EOF" {
|
||||
fmt.Printf("[Client disconnected]\n")
|
||||
r.CloseHandler(&r)
|
||||
} else {
|
||||
fmt.Printf("Error reading client data! (%+v)\n", err)
|
||||
}
|
||||
|
@ -100,7 +182,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
// Shut down the connection.
|
||||
c.Close()
|
||||
//c.Close()
|
||||
return
|
||||
}(conn)
|
||||
}
|
||||
|
|
70
hkexnet.go
70
hkexnet.go
|
@ -34,7 +34,6 @@ import (
|
|||
|
||||
// Conn is a HKex connection - a drop-in replacement for net.Conn
|
||||
type Conn struct {
|
||||
//net.Conn
|
||||
c net.Conn // which also implements io.Reader, io.Writer, ...
|
||||
h *HerraduraKEx
|
||||
cipheropts uint32 // post-KEx cipher/hmac options
|
||||
|
@ -44,16 +43,12 @@ type Conn struct {
|
|||
w cipher.Stream
|
||||
}
|
||||
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
return c.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// ConnOpts returns the cipher/hmac options value, which is sent to the
|
||||
// peer but is not itself part of the KEx.
|
||||
//
|
||||
// (Used for protocol-level negotiations after KEx such as
|
||||
// cipher/HMAC algorithm options etc.)
|
||||
func (c *Conn) ConnOpts() uint32 {
|
||||
func (c Conn) ConnOpts() uint32 {
|
||||
return c.cipheropts
|
||||
}
|
||||
|
||||
|
@ -61,7 +56,7 @@ func (c *Conn) ConnOpts() uint32 {
|
|||
// peer as part of KEx but not part of the KEx itself.
|
||||
//
|
||||
// opts - bitfields for cipher and hmac alg. to use after KEx
|
||||
func (c *Conn) SetConnOpts(copts uint32) {
|
||||
func (c Conn) SetConnOpts(copts uint32) {
|
||||
c.cipheropts = copts
|
||||
}
|
||||
|
||||
|
@ -70,7 +65,7 @@ func (c *Conn) SetConnOpts(copts uint32) {
|
|||
//
|
||||
// Consumers of this lib may use this for protocol-level options not part
|
||||
// of the KEx or encryption info used by the connection.
|
||||
func (c *Conn) Opts() uint32 {
|
||||
func (c Conn) Opts() uint32 {
|
||||
return c.opts
|
||||
}
|
||||
|
||||
|
@ -81,7 +76,7 @@ func (c *Conn) Opts() uint32 {
|
|||
// of the KEx of encryption info used by the connection.
|
||||
//
|
||||
// opts - a uint32, caller-defined
|
||||
func (c *Conn) SetOpts(opts uint32) {
|
||||
func (c Conn) SetOpts(opts uint32) {
|
||||
c.opts = opts
|
||||
}
|
||||
|
||||
|
@ -90,7 +85,7 @@ func (c *Conn) SetOpts(opts uint32) {
|
|||
//
|
||||
// Consumers of this lib may use this to indicate connection-specific
|
||||
// operations not part of the KEx or encryption info used by the connection.
|
||||
func (c *Conn) Op() uint8 {
|
||||
func (c Conn) Op() uint8 {
|
||||
return c.op
|
||||
}
|
||||
|
||||
|
@ -101,11 +96,11 @@ func (c *Conn) Op() uint8 {
|
|||
// operations not part of the KEx or encryption info used by the connection.
|
||||
//
|
||||
// op - a uint8, caller-defined
|
||||
func (c *Conn) SetOp(op uint8) {
|
||||
func (c Conn) SetOp(op uint8) {
|
||||
c.op = op
|
||||
}
|
||||
|
||||
func (c *Conn) applyConnExtensions(extensions ...string) {
|
||||
func (c Conn) applyConnExtensions(extensions ...string) {
|
||||
for _, s := range extensions {
|
||||
switch s {
|
||||
case "C_AES_256":
|
||||
|
@ -177,12 +172,57 @@ func Dial(protocol string, ipport string, extensions ...string) (hc *Conn, err e
|
|||
}
|
||||
|
||||
// Close a hkex.Conn
|
||||
func (c *Conn) Close() (err error) {
|
||||
func (c Conn) Close() (err error) {
|
||||
err = c.c.Close()
|
||||
fmt.Println("[Conn Closing]")
|
||||
return
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address.
|
||||
func (c Conn) LocalAddr() net.Addr {
|
||||
return c.c.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (c Conn) RemoteAddr() net.Addr {
|
||||
return c.c.RemoteAddr()
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated
|
||||
// with the connection. It is equivalent to calling both
|
||||
// SetReadDeadline and SetWriteDeadline.
|
||||
//
|
||||
// A deadline is an absolute time after which I/O operations
|
||||
// fail with a timeout (see type Error) instead of
|
||||
// blocking. The deadline applies to all future and pending
|
||||
// I/O, not just the immediately following call to Read or
|
||||
// Write. After a deadline has been exceeded, the connection
|
||||
// can be refreshed by setting a deadline in the future.
|
||||
//
|
||||
// An idle timeout can be implemented by repeatedly extending
|
||||
// the deadline after successful Read or Write calls.
|
||||
//
|
||||
// A zero value for t means I/O operations will not time out.
|
||||
func (c Conn) SetDeadline(t time.Time) error {
|
||||
return c.SetDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for future Write calls
|
||||
// and any currently-blocked Write call.
|
||||
// Even if write times out, it may return n > 0, indicating that
|
||||
// some of the data was successfully written.
|
||||
// A zero value for t means Write will not time out.
|
||||
func (c Conn) SetWriteDeadline(t time.Time) error {
|
||||
return c.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls
|
||||
// and any currently-blocked Read call.
|
||||
// A zero value for t means Read will not time out.
|
||||
func (c Conn) SetReadDeadline(t time.Time) error {
|
||||
return c.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
// HKExListener is a Listener conforming to net.Listener
|
||||
|
@ -208,7 +248,7 @@ func Listen(protocol string, ipport string) (hl HKExListener, e error) {
|
|||
// Close a hkex Listener
|
||||
//
|
||||
// See go doc io.Close
|
||||
func (hl *HKExListener) Close() error {
|
||||
func (hl HKExListener) Close() error {
|
||||
fmt.Println("[Listener Closed]")
|
||||
return hl.l.Close()
|
||||
}
|
||||
|
@ -216,7 +256,7 @@ func (hl *HKExListener) Close() error {
|
|||
// Accept a client connection, conforming to net.Listener.Accept()
|
||||
//
|
||||
// See go doc net.Listener.Accept
|
||||
func (hl *HKExListener) Accept() (hc Conn, err error) {
|
||||
func (hl HKExListener) Accept() (hc Conn, err error) {
|
||||
c, err := hl.l.Accept()
|
||||
if err != nil {
|
||||
return Conn{c: nil, h: nil, cipheropts: 0, opts: 0,
|
||||
|
|
Loading…
Reference in New Issue