mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			Removed channel-based server loop goroutine, solving eaten initial byte issue.
Made receivers on hkex.Conn mutators *Conn again (whoops) TODO: Consider: padding (? probably not, XORKeyStream OFB/CBC/etc. modes prevent constant header/crib exposure, and would add lots of complexity to Read/Write) TODO: Add CTR, other modes
This commit is contained in:
		
							parent
							
								
									732005d9bf
								
							
						
					
					
						commit
						e3842e4219
					
				| 
						 | 
				
			
			@ -14,6 +14,14 @@ import (
 | 
			
		|||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cmdSpec struct {
 | 
			
		||||
	op         []byte
 | 
			
		||||
	who        []byte
 | 
			
		||||
	cmd        []byte
 | 
			
		||||
	authCookie []byte
 | 
			
		||||
	status     int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Demo of a simple client that dials up to a simple test server to
 | 
			
		||||
// send data.
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +47,7 @@ func main() {
 | 
			
		|||
	flag.StringVar(&server, "s", "localhost:2000", "server hostname/address[:port]")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	//log.SetOutput(os.Stdout)
 | 
			
		||||
	log.SetOutput(ioutil.Discard)
 | 
			
		||||
 | 
			
		||||
	conn, err := hkex.Dial("tcp", server, cAlg, hAlg)
 | 
			
		||||
| 
						 | 
				
			
			@ -60,6 +69,19 @@ func main() {
 | 
			
		|||
		fmt.Println("NOT A TTY")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rec := &cmdSpec{op: []byte{'s'},
 | 
			
		||||
		who:        []byte("ABCD"),
 | 
			
		||||
		cmd:        []byte("EFGH"),
 | 
			
		||||
		authCookie: []byte("99"),
 | 
			
		||||
		status:     0}
 | 
			
		||||
 | 
			
		||||
	_, err = fmt.Fprintf(conn, "%d %d %d %d\n", len(rec.op), len(rec.who), len(rec.cmd), len(rec.authCookie))
 | 
			
		||||
	_, err = conn.Write(rec.op)
 | 
			
		||||
	_, err = conn.Write(rec.who)
 | 
			
		||||
	_, err = conn.Write(rec.cmd)
 | 
			
		||||
	_, err = conn.Write(rec.authCookie)
 | 
			
		||||
 | 
			
		||||
	//client reader (from server) goroutine
 | 
			
		||||
	wg.Add(1)
 | 
			
		||||
	go func() {
 | 
			
		||||
		// By deferring a call to wg.Done(),
 | 
			
		||||
| 
						 | 
				
			
			@ -82,11 +104,12 @@ func main() {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if isInteractive {
 | 
			
		||||
			log.Println("[Got Write EOF]")
 | 
			
		||||
			wg.Done() // client hanging up, close WaitGroup to exit client
 | 
			
		||||
			log.Println("[Got EOF]")
 | 
			
		||||
			wg.Done() // server hung up, close WaitGroup to exit client
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// client writer (to server) goroutine
 | 
			
		||||
	wg.Add(1)
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer wg.Done()
 | 
			
		||||
| 
						 | 
				
			
			@ -100,8 +123,8 @@ func main() {
 | 
			
		|||
				os.Exit(2)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		log.Println("[Got Read EOF]")
 | 
			
		||||
		wg.Done() // server hung up, close WaitGroup to exit client
 | 
			
		||||
		log.Println("[Sent EOF]")
 | 
			
		||||
		wg.Done() // client hung up, close WaitGroup to exit client
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// Wait until both stdin and stdout goroutines finish
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ func main() {
 | 
			
		|||
				}
 | 
			
		||||
			}(ch, eCh)
 | 
			
		||||
 | 
			
		||||
			ticker := time.Tick(time.Second/100)
 | 
			
		||||
			ticker := time.Tick(time.Second / 100)
 | 
			
		||||
		Term:
 | 
			
		||||
			// continuously read from the connection
 | 
			
		||||
			for {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,13 +4,12 @@ import (
 | 
			
		|||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"os/user"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	hkex "blitter.com/herradurakex"
 | 
			
		||||
	"github.com/kr/pty"
 | 
			
		||||
| 
						 | 
				
			
			@ -32,13 +31,13 @@ const (
 | 
			
		|||
	OpX   = 'x' // exec
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Op uint8
 | 
			
		||||
//type Op uint8
 | 
			
		||||
 | 
			
		||||
type cmdRunner struct {
 | 
			
		||||
	op         Op
 | 
			
		||||
	who        string
 | 
			
		||||
	arg        string
 | 
			
		||||
	authCookie string
 | 
			
		||||
type cmdSpec struct {
 | 
			
		||||
	op         []byte
 | 
			
		||||
	who        []byte
 | 
			
		||||
	cmd        []byte
 | 
			
		||||
	authCookie []byte
 | 
			
		||||
	status     int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +94,7 @@ func main() {
 | 
			
		|||
	flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	log.SetOutput(ioutil.Discard)
 | 
			
		||||
	log.SetOutput(os.Stdout /*ioutil.Discard*/)
 | 
			
		||||
 | 
			
		||||
	// Listen on TCP port 2000 on all available unicast and
 | 
			
		||||
	// anycast IP addresses of the local system.
 | 
			
		||||
| 
						 | 
				
			
			@ -119,85 +118,63 @@ func main() {
 | 
			
		|||
		// multiple connections may be served concurrently.
 | 
			
		||||
		go func(c hkex.Conn) (e error) {
 | 
			
		||||
			defer c.Close()
 | 
			
		||||
			var connOp *byte = nil
 | 
			
		||||
			ch := make(chan []byte)
 | 
			
		||||
			chN := 0
 | 
			
		||||
			eCh := make(chan error)
 | 
			
		||||
 | 
			
		||||
			// Start a goroutine to read from our net connection
 | 
			
		||||
			go func(ch chan []byte, eCh chan error) {
 | 
			
		||||
				for {
 | 
			
		||||
					// try to read the data
 | 
			
		||||
					data := make([]byte, 512)
 | 
			
		||||
					chN, err = c.Read(data)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						// send an error if it's encountered
 | 
			
		||||
						eCh <- err
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
					// send data if we read some.
 | 
			
		||||
					ch <- data[0:chN]
 | 
			
		||||
				}
 | 
			
		||||
			}(ch, eCh)
 | 
			
		||||
			//We use io.ReadFull() here to guarantee we consume
 | 
			
		||||
			//just the data we want for the cmdSpec, and no more.
 | 
			
		||||
			//Otherwise data will be sitting in the channel that isn't
 | 
			
		||||
			//passed down to the command handlers.
 | 
			
		||||
			var rec cmdSpec
 | 
			
		||||
			var len1, len2, len3, len4 uint32
 | 
			
		||||
 | 
			
		||||
			ticker := time.Tick(time.Second / 100)
 | 
			
		||||
		Term:
 | 
			
		||||
			// continuously read from the connection
 | 
			
		||||
			for {
 | 
			
		||||
				select {
 | 
			
		||||
				// This case means we recieved data on the connection
 | 
			
		||||
				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
 | 
			
		||||
						// Have op here and first block of data[]
 | 
			
		||||
						connOp = new(byte)
 | 
			
		||||
						*connOp = data[0]
 | 
			
		||||
						fmt.Printf("[* connOp '%c']\n", *connOp)
 | 
			
		||||
					}
 | 
			
		||||
					if len(data) > 1 {
 | 
			
		||||
						data = data[1:chN]
 | 
			
		||||
						chN -= 1
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if len(data) > 0 {
 | 
			
		||||
						// From here, one could pass all subsequent data
 | 
			
		||||
						// between client/server attached to an exec.Cmd,
 | 
			
		||||
						// as data to/from a file, etc.
 | 
			
		||||
						if connOp != nil && *connOp == 's' {
 | 
			
		||||
							fmt.Println("[Running shell]")
 | 
			
		||||
							runCmdAs("larissa", "bash -l -i", conn)
 | 
			
		||||
							// Returned hopefully via an EOF or exit/logout;
 | 
			
		||||
							// Clear current op so user can enter next, or EOF
 | 
			
		||||
							connOp = nil
 | 
			
		||||
							fmt.Println("[Exiting shell]")
 | 
			
		||||
							conn.Close()
 | 
			
		||||
						}
 | 
			
		||||
						if strings.Trim(string(data), "\r\n") == "exit" {
 | 
			
		||||
							conn.Close()
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					//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")
 | 
			
		||||
					} else {
 | 
			
		||||
						fmt.Printf("Error reading client data! (%+v)\n", err)
 | 
			
		||||
					}
 | 
			
		||||
					break Term
 | 
			
		||||
				// This will timeout on the read.
 | 
			
		||||
				case <-ticker:
 | 
			
		||||
					// do nothing? this is just so we can time out if we need to.
 | 
			
		||||
					// you probably don't even need to have this here unless you want
 | 
			
		||||
					// do something specifically on the timeout.
 | 
			
		||||
				}
 | 
			
		||||
			n, err := fmt.Fscanf(c, "%d %d %d %d\n", &len1, &len2, &len3, &len4)
 | 
			
		||||
			if err != nil || n < 4 {
 | 
			
		||||
				fmt.Println("[Bad cmdSpec fmt]")
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Printf("  lens:%d %d %d %d\n", len1, len2, len3, len4)
 | 
			
		||||
 | 
			
		||||
			rec.op = make([]byte, len1, len1)
 | 
			
		||||
			_, err = io.ReadFull(c, rec.op)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Println("[Bad cmdSpec.op]")
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			rec.who = make([]byte, len2, len2)
 | 
			
		||||
			_, err = io.ReadFull(c, rec.who)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Println("[Bad cmdSpec.who]")
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			rec.cmd = make([]byte, len3, len3)
 | 
			
		||||
			_, err = io.ReadFull(c, rec.cmd)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Println("[Bad cmdSpec.cmd]")
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			rec.authCookie = make([]byte, len4, len4)
 | 
			
		||||
			_, err = io.ReadFull(c, rec.authCookie)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Println("[Bad cmdSpec.authCookie]")
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			fmt.Printf("[cmdSpec: op:%c who:%s cmd:%s auth:%s]\n",
 | 
			
		||||
				rec.op[0], string(rec.who), string(rec.cmd), string(rec.authCookie))
 | 
			
		||||
 | 
			
		||||
			if rec.op[0] == 's' {
 | 
			
		||||
				fmt.Println("[Running shell]")
 | 
			
		||||
				runCmdAs("larissa", "bash -l -i", conn)
 | 
			
		||||
				// Returned hopefully via an EOF or exit/logout;
 | 
			
		||||
				// Clear current op so user can enter next, or EOF
 | 
			
		||||
				rec.op[0] = 0
 | 
			
		||||
				fmt.Println("[Exiting shell]")
 | 
			
		||||
			} else {
 | 
			
		||||
				fmt.Println("[Bad cmdSpec]")
 | 
			
		||||
			}
 | 
			
		||||
			// Shut down the connection.
 | 
			
		||||
			//c.Close()
 | 
			
		||||
			return
 | 
			
		||||
		}(conn)
 | 
			
		||||
	}
 | 
			
		||||
	} //endfor
 | 
			
		||||
	fmt.Println("[Exiting]")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								hkexchan.go
								
								
								
								
							
							
						
						
									
										21
									
								
								hkexchan.go
								
								
								
								
							| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,16 +30,6 @@ const (
 | 
			
		|||
	HmacNoneDisallowed
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChanOp uint8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ChanOpNop  = '.'
 | 
			
		||||
	ChanOpEcho = 'e' // For testing - echo client data to stderr
 | 
			
		||||
	//ChanOpFileWrite = "w"
 | 
			
		||||
	//ChanOpFileRead = "r"
 | 
			
		||||
	//ChanOpRemoteCmd = "x"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*TODO: HMAC derived from HKEx FA.*/
 | 
			
		||||
/* Support functionality to set up encryption after a channel has
 | 
			
		||||
been negotiated via hkexnet.go
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +50,7 @@ func (hc Conn) getStream(keymat *big.Int) (ret cipher.Stream) {
 | 
			
		|||
		ivlen = aes.BlockSize
 | 
			
		||||
		iv := keymat.Bytes()[aes.BlockSize : aes.BlockSize+ivlen]
 | 
			
		||||
		ret = cipher.NewOFB(block, iv)
 | 
			
		||||
		fmt.Printf("[cipher AES_256 (%d)]\n", copts)
 | 
			
		||||
		log.Printf("[cipher AES_256 (%d)]\n", copts)
 | 
			
		||||
		break
 | 
			
		||||
	case CAlgTwofish128:
 | 
			
		||||
		key = keymat.Bytes()[0:twofish.BlockSize]
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +58,7 @@ func (hc Conn) getStream(keymat *big.Int) (ret cipher.Stream) {
 | 
			
		|||
		ivlen = twofish.BlockSize
 | 
			
		||||
		iv := keymat.Bytes()[twofish.BlockSize : twofish.BlockSize+ivlen]
 | 
			
		||||
		ret = cipher.NewOFB(block, iv)
 | 
			
		||||
		fmt.Printf("[cipher TWOFISH_128 (%d)]\n", copts)
 | 
			
		||||
		log.Printf("[cipher TWOFISH_128 (%d)]\n", copts)
 | 
			
		||||
		break
 | 
			
		||||
	case CAlgBlowfish64:
 | 
			
		||||
		key = keymat.Bytes()[0:blowfish.BlockSize]
 | 
			
		||||
| 
						 | 
				
			
			@ -84,9 +75,10 @@ func (hc Conn) getStream(keymat *big.Int) (ret cipher.Stream) {
 | 
			
		|||
		// copy what's needed whereas blowfish does no such check.
 | 
			
		||||
		iv := keymat.Bytes()[blowfish.BlockSize : blowfish.BlockSize+ivlen]
 | 
			
		||||
		ret = cipher.NewOFB(block, iv)
 | 
			
		||||
		fmt.Printf("[cipher BLOWFISH_64 (%d)]\n", copts)
 | 
			
		||||
		log.Printf("[cipher BLOWFISH_64 (%d)]\n", copts)
 | 
			
		||||
		break
 | 
			
		||||
	default:
 | 
			
		||||
		log.Printf("[invalid cipher (%d)]\n", copts)
 | 
			
		||||
		fmt.Printf("DOOFUS SET A VALID CIPHER ALG (%d)\n", copts)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -94,9 +86,10 @@ func (hc Conn) getStream(keymat *big.Int) (ret cipher.Stream) {
 | 
			
		|||
	hopts := (hc.cipheropts >> 8) & 0xFF
 | 
			
		||||
	switch hopts {
 | 
			
		||||
	case HmacSHA256:
 | 
			
		||||
		fmt.Printf("[nop HmacSHA256 (%d)]\n", hopts)
 | 
			
		||||
		log.Printf("[nop HmacSHA256 (%d)]\n", hopts)
 | 
			
		||||
		break
 | 
			
		||||
	default:
 | 
			
		||||
		log.Printf("[invalid hmac (%d)]\n", hopts)
 | 
			
		||||
		fmt.Printf("DOOFUS SET A VALID HMAC ALG (%d)\n", hopts)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								hkexnet.go
								
								
								
								
							
							
						
						
									
										47
									
								
								hkexnet.go
								
								
								
								
							| 
						 | 
				
			
			@ -39,7 +39,6 @@ type Conn struct {
 | 
			
		|||
	h          *HerraduraKEx
 | 
			
		||||
	cipheropts uint32 // post-KEx cipher/hmac options
 | 
			
		||||
	opts       uint32 // post-KEx protocol options (caller-defined)
 | 
			
		||||
	op         uint8  // post-KEx 'op' (caller-defined)
 | 
			
		||||
	r          cipher.Stream
 | 
			
		||||
	w          cipher.Stream
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -57,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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,31 +76,11 @@ 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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Op returns the 'op' value, which is sent to the peer
 | 
			
		||||
// but is not itself part of the KEx or connection (cipher/hmac) setup.
 | 
			
		||||
//
 | 
			
		||||
// 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 {
 | 
			
		||||
	return c.op
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetOp sets the 'op' value, which is sent to the peer
 | 
			
		||||
// but is not itself part of the KEx or connection (cipher/hmac) setup.
 | 
			
		||||
//
 | 
			
		||||
// Consumers of this lib may use this to indicate connection-specific
 | 
			
		||||
// operations not part of the KEx or encryption info used by the connection.
 | 
			
		||||
//
 | 
			
		||||
// op - a uint8, caller-defined
 | 
			
		||||
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":
 | 
			
		||||
| 
						 | 
				
			
			@ -143,20 +122,20 @@ func Dial(protocol string, ipport string, extensions ...string) (hc *Conn, err e
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	hc = &Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, op: 0, r: nil, w: nil}
 | 
			
		||||
	hc = &Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, r: nil, w: nil}
 | 
			
		||||
 | 
			
		||||
	hc.applyConnExtensions(extensions...)
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(c, "0x%s\n%08x:%08x:%02x\n", hc.h.d.Text(16),
 | 
			
		||||
		hc.cipheropts, hc.opts, hc.op)
 | 
			
		||||
	fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.d.Text(16),
 | 
			
		||||
		hc.cipheropts, hc.opts)
 | 
			
		||||
 | 
			
		||||
	d := big.NewInt(0)
 | 
			
		||||
	_, err = fmt.Fscanln(c, d)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = fmt.Fscanf(c, "%08x:%08x:%02x\n",
 | 
			
		||||
		&hc.cipheropts, &hc.opts, &hc.op)
 | 
			
		||||
	_, err = fmt.Fscanf(c, "%08x:%08x\n",
 | 
			
		||||
		&hc.cipheropts, &hc.opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -265,15 +244,15 @@ func (hl HKExListener) Accept() (hc Conn, err error) {
 | 
			
		|||
	}
 | 
			
		||||
	log.Println("[Accepted]")
 | 
			
		||||
 | 
			
		||||
	hc = Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, op: 0, r: nil, w: nil}
 | 
			
		||||
	hc = Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, r: nil, w: nil}
 | 
			
		||||
 | 
			
		||||
	d := big.NewInt(0)
 | 
			
		||||
	_, err = fmt.Fscanln(c, d)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return hc, err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = fmt.Fscanf(c, "%08x:%08x:%02x\n",
 | 
			
		||||
		&hc.cipheropts, &hc.opts, &hc.op)
 | 
			
		||||
	_, err = fmt.Fscanf(c, "%08x:%08x\n",
 | 
			
		||||
		&hc.cipheropts, &hc.opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return hc, err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -283,8 +262,8 @@ func (hl HKExListener) Accept() (hc Conn, err error) {
 | 
			
		|||
	hc.h.FA()
 | 
			
		||||
	log.Printf("**(s)** FA:%s\n", hc.h.fa)
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(c, "0x%s\n%08x:%08x:%02x\n", hc.h.d.Text(16),
 | 
			
		||||
		hc.cipheropts, hc.opts, hc.op)
 | 
			
		||||
	fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.d.Text(16),
 | 
			
		||||
		hc.cipheropts, hc.opts)
 | 
			
		||||
 | 
			
		||||
	hc.r = hc.getStream(hc.h.fa)
 | 
			
		||||
	hc.w = hc.getStream(hc.h.fa)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue