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