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"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
hkex "blitter.com/herradurakex"
|
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
|
// Demo of a simple server that listens and spawns goroutines for each
|
||||||
// connecting client. Note this code is identical to standard tcp
|
// connecting client. Note this code is identical to standard tcp
|
||||||
// server code, save for declaring 'hkex' rather than 'net'
|
// server code, save for declaring 'hkex' rather than 'net'
|
||||||
|
@ -41,10 +112,10 @@ func main() {
|
||||||
// The loop then returns to accepting, so that
|
// The loop then returns to accepting, so that
|
||||||
// multiple connections may be served concurrently.
|
// multiple connections may be served concurrently.
|
||||||
go func(c hkex.Conn) (e error) {
|
go func(c hkex.Conn) (e error) {
|
||||||
|
defer c.Close()
|
||||||
ch := make(chan []byte)
|
ch := make(chan []byte)
|
||||||
chN := 0
|
chN := 0
|
||||||
eCh := make(chan error)
|
eCh := make(chan error)
|
||||||
var connOp *byte = nil
|
|
||||||
|
|
||||||
// Start a goroutine to read from our net connection
|
// Start a goroutine to read from our net connection
|
||||||
go func(ch chan []byte, eCh chan error) {
|
go func(ch chan []byte, eCh chan error) {
|
||||||
|
@ -57,23 +128,14 @@ func main() {
|
||||||
eCh <- err
|
eCh <- err
|
||||||
return
|
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.
|
// send data if we read some.
|
||||||
ch <- data[0:chN]
|
ch <- data[0:chN]
|
||||||
}
|
}
|
||||||
}(ch, eCh)
|
}(ch, eCh)
|
||||||
|
|
||||||
ticker := time.Tick(time.Second / 100)
|
ticker := time.Tick(time.Second / 100)
|
||||||
|
var r cmdRunner
|
||||||
|
var connOp *byte = nil
|
||||||
Term:
|
Term:
|
||||||
// continuously read from the connection
|
// continuously read from the connection
|
||||||
for {
|
for {
|
||||||
|
@ -82,12 +144,32 @@ func main() {
|
||||||
case data := <-ch:
|
case data := <-ch:
|
||||||
// Do something with the data
|
// Do something with the data
|
||||||
fmt.Printf("Client sent %+v\n", data[0:chN])
|
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))
|
//fmt.Printf("Client sent %s\n", string(data))
|
||||||
// This case means we got an error and the goroutine has finished
|
// This case means we got an error and the goroutine has finished
|
||||||
case err := <-eCh:
|
case err := <-eCh:
|
||||||
// handle our error then exit for loop
|
// handle our error then exit for loop
|
||||||
if err.Error() == "EOF" {
|
if err.Error() == "EOF" {
|
||||||
fmt.Printf("[Client disconnected]\n")
|
fmt.Printf("[Client disconnected]\n")
|
||||||
|
r.CloseHandler(&r)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Error reading client data! (%+v)\n", err)
|
fmt.Printf("Error reading client data! (%+v)\n", err)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +182,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Shut down the connection.
|
// Shut down the connection.
|
||||||
c.Close()
|
//c.Close()
|
||||||
return
|
return
|
||||||
}(conn)
|
}(conn)
|
||||||
}
|
}
|
||||||
|
|
70
hkexnet.go
70
hkexnet.go
|
@ -34,7 +34,6 @@ import (
|
||||||
|
|
||||||
// Conn is a HKex connection - a drop-in replacement for net.Conn
|
// Conn is a HKex connection - a drop-in replacement for net.Conn
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
//net.Conn
|
|
||||||
c net.Conn // which also implements io.Reader, io.Writer, ...
|
c net.Conn // which also implements io.Reader, io.Writer, ...
|
||||||
h *HerraduraKEx
|
h *HerraduraKEx
|
||||||
cipheropts uint32 // post-KEx cipher/hmac options
|
cipheropts uint32 // post-KEx cipher/hmac options
|
||||||
|
@ -44,16 +43,12 @@ type Conn struct {
|
||||||
w cipher.Stream
|
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
|
// ConnOpts returns the cipher/hmac options value, which is sent to the
|
||||||
// peer but is not itself part of the KEx.
|
// peer but is not itself part of the KEx.
|
||||||
//
|
//
|
||||||
// (Used for protocol-level negotiations after KEx such as
|
// (Used for protocol-level negotiations after KEx such as
|
||||||
// cipher/HMAC algorithm options etc.)
|
// cipher/HMAC algorithm options etc.)
|
||||||
func (c *Conn) ConnOpts() uint32 {
|
func (c Conn) ConnOpts() uint32 {
|
||||||
return c.cipheropts
|
return c.cipheropts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +56,7 @@ func (c *Conn) ConnOpts() uint32 {
|
||||||
// peer as part of KEx but not part of the KEx itself.
|
// peer as part of KEx but not part of the KEx itself.
|
||||||
//
|
//
|
||||||
// opts - bitfields for cipher and hmac alg. to use after KEx
|
// 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
|
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
|
// Consumers of this lib may use this for protocol-level options not part
|
||||||
// of the KEx or encryption info used by the connection.
|
// of the KEx or encryption info used by the connection.
|
||||||
func (c *Conn) Opts() uint32 {
|
func (c Conn) Opts() uint32 {
|
||||||
return c.opts
|
return c.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +76,7 @@ func (c *Conn) Opts() uint32 {
|
||||||
// of the KEx of encryption info used by the connection.
|
// of the KEx of encryption info used by the connection.
|
||||||
//
|
//
|
||||||
// opts - a uint32, caller-defined
|
// opts - a uint32, caller-defined
|
||||||
func (c *Conn) SetOpts(opts uint32) {
|
func (c Conn) SetOpts(opts uint32) {
|
||||||
c.opts = opts
|
c.opts = opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +85,7 @@ func (c *Conn) SetOpts(opts uint32) {
|
||||||
//
|
//
|
||||||
// Consumers of this lib may use this to indicate connection-specific
|
// Consumers of this lib may use this to indicate connection-specific
|
||||||
// operations not part of the KEx or encryption info used by the connection.
|
// 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
|
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.
|
// operations not part of the KEx or encryption info used by the connection.
|
||||||
//
|
//
|
||||||
// op - a uint8, caller-defined
|
// op - a uint8, caller-defined
|
||||||
func (c *Conn) SetOp(op uint8) {
|
func (c Conn) SetOp(op uint8) {
|
||||||
c.op = op
|
c.op = op
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) applyConnExtensions(extensions ...string) {
|
func (c Conn) applyConnExtensions(extensions ...string) {
|
||||||
for _, s := range extensions {
|
for _, s := range extensions {
|
||||||
switch s {
|
switch s {
|
||||||
case "C_AES_256":
|
case "C_AES_256":
|
||||||
|
@ -177,12 +172,57 @@ func Dial(protocol string, ipport string, extensions ...string) (hc *Conn, err e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close a hkex.Conn
|
// Close a hkex.Conn
|
||||||
func (c *Conn) Close() (err error) {
|
func (c Conn) Close() (err error) {
|
||||||
err = c.c.Close()
|
err = c.c.Close()
|
||||||
fmt.Println("[Conn Closing]")
|
fmt.Println("[Conn Closing]")
|
||||||
return
|
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
|
// 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
|
// Close a hkex Listener
|
||||||
//
|
//
|
||||||
// See go doc io.Close
|
// See go doc io.Close
|
||||||
func (hl *HKExListener) Close() error {
|
func (hl HKExListener) Close() error {
|
||||||
fmt.Println("[Listener Closed]")
|
fmt.Println("[Listener Closed]")
|
||||||
return hl.l.Close()
|
return hl.l.Close()
|
||||||
}
|
}
|
||||||
|
@ -216,7 +256,7 @@ func (hl *HKExListener) Close() error {
|
||||||
// Accept a client connection, conforming to net.Listener.Accept()
|
// Accept a client connection, conforming to net.Listener.Accept()
|
||||||
//
|
//
|
||||||
// See go doc 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()
|
c, err := hl.l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Conn{c: nil, h: nil, cipheropts: 0, opts: 0,
|
return Conn{c: nil, h: nil, cipheropts: 0, opts: 0,
|
||||||
|
|
Loading…
Reference in New Issue