mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			
							parent
							
								
									9641fd3fff
								
							
						
					
					
						commit
						a0e90c14ba
					
				| 
						 | 
				
			
			@ -42,7 +42,6 @@ import (
 | 
			
		|||
	"math/big"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
| 
						 | 
				
			
			@ -56,32 +55,6 @@ import (
 | 
			
		|||
const PAD_SZ = 32     // max size of padding applied to each packet
 | 
			
		||||
const HMAC_CHK_SZ = 4 // leading bytes of HMAC to xmit for verification
 | 
			
		||||
 | 
			
		||||
const Bob = string("\r\n\r\n" +
 | 
			
		||||
	"@@@@@@@^^~~~~~~~~~~~~~~~~~~~~^@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@^     ~^  @  @@ @ @ @ I  ~^@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@            ~ ~~ ~I          @@@@@\r\n" +
 | 
			
		||||
	"@@@@'                  '  _,w@<    @@@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@w___,w@@@@@@@@  @  @@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@@@@@@@@@@@@@@@  I  @@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@@@@@@@@@@@@@*@[ i  @@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@@@@@@@@@@@@@[][ | ]@@@\r\n" +
 | 
			
		||||
	"@@@@     ~_,,_ ~@@@@@@@~ ____~ @    @@@\r\n" +
 | 
			
		||||
	"@@@@    _~ ,  ,  `@@@~  _  _`@ ]L  J@@@\r\n" +
 | 
			
		||||
	"@@@@  , @@w@ww+   @@@ww``,,@w@ ][  @@@@\r\n" +
 | 
			
		||||
	"@@@@,  @@@@www@@@ @@@@@@@ww@@@@@[  @@@@\r\n" +
 | 
			
		||||
	"@@@@@_|| @@@@@@P' @@P@@@@@@@@@@@[|c@@@@\r\n" +
 | 
			
		||||
	"@@@@@@w| '@@P~  P]@@@-~, ~Y@@^'],@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@[   _        _J@@Tk     ]]@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@,@ @@, c,,,,,,,y ,w@@[ ,@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@@ i @w   ====--_@@@@@  @@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@@@`,P~ _ ~^^^^Y@@@@@  @@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@^^=^@@^   ^' ,ww,w@@@@@ _@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@_xJ~ ~   ,    @@@@@@@P~_@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@   @,   ,@@@,_____   _,J@@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@L  `' ,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"\r\n")
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	WinSize struct {
 | 
			
		||||
		Rows uint16
 | 
			
		||||
| 
						 | 
				
			
			@ -122,9 +95,6 @@ type (
 | 
			
		|||
		wm        hash.Hash
 | 
			
		||||
		dBuf      *bytes.Buffer //decrypt buffer for Read()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EscHandler func(io.Writer)
 | 
			
		||||
	EscSeqs    map[byte]EscHandler
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
| 
						 | 
				
			
			@ -1114,115 +1084,3 @@ func (hc *Conn) chaffHelper() {
 | 
			
		|||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Copy copies from src to dst until either EOF is reached
 | 
			
		||||
// on src or an error occurs. It returns the number of bytes
 | 
			
		||||
// copied and the first error encountered while copying, if any.
 | 
			
		||||
//
 | 
			
		||||
// A successful Copy returns err == nil, not err == EOF.
 | 
			
		||||
// Because Copy is defined to read from src until EOF, it does
 | 
			
		||||
// not treat an EOF from Read as an error to be reported.
 | 
			
		||||
//
 | 
			
		||||
// If src implements the WriterTo interface,
 | 
			
		||||
// the copy is implemented by calling src.WriteTo(dst).
 | 
			
		||||
// Otherwise, if dst implements the ReaderFrom interface,
 | 
			
		||||
// the copy is implemented by calling dst.ReadFrom(src).
 | 
			
		||||
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
 | 
			
		||||
	written, err = copyBuffer(dst, src, nil)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// copyBuffer is the actual implementation of Copy and CopyBuffer.
 | 
			
		||||
// if buf is nil, one is allocated.
 | 
			
		||||
func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
 | 
			
		||||
	// NOTE: using dst.Write() in these esc funcs will cause the output
 | 
			
		||||
	// to function as a 'macro', outputting as if user typed the sequence.
 | 
			
		||||
	//
 | 
			
		||||
	// Using os.Stdout outputs to the client's term w/o it or the server
 | 
			
		||||
	// 'seeing' the output.
 | 
			
		||||
	//
 | 
			
		||||
	// TODO: Devise a way to signal to main client thread that
 | 
			
		||||
	// a goroutine should be spawned to do long-lived tasks for
 | 
			
		||||
	// some esc sequences (eg., a time ticker in the corner of terminal,
 | 
			
		||||
	// or tunnel traffic indicator - note we cannot just spawn a goroutine
 | 
			
		||||
	// here, as copyBuffer() returns after each burst of data. Scope must
 | 
			
		||||
	// outlive individual copyBuffer calls).
 | 
			
		||||
	// (Note that since this custom copyBuffer func is used only by
 | 
			
		||||
	// the hkexsh client, it should eventually be moved to client.)
 | 
			
		||||
	escs := EscSeqs{
 | 
			
		||||
		'i': func(io.Writer) { os.Stdout.Write([]byte("\x1b[s\x1b[2;1H\x1b[1;31m[HKEXSH]\x1b[39;49m\x1b[u")) },
 | 
			
		||||
		't': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m[HKEXSH]\x1b[39;49m")) },
 | 
			
		||||
		'B': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m" + Bob + "\x1b[39;49m")) },
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		// If the reader has a WriteTo method, use it to do the copy.
 | 
			
		||||
		// Avoids an allocation and a copy.
 | 
			
		||||
		if wt, ok := src.(io.WriterTo); ok {
 | 
			
		||||
			return wt.WriteTo(dst)
 | 
			
		||||
		}
 | 
			
		||||
		// Similarly, if the writer has a ReadFrom method, use it to do the copy.
 | 
			
		||||
		if rt, ok := dst.(io.ReaderFrom); ok {
 | 
			
		||||
			return rt.ReadFrom(src)
 | 
			
		||||
		}
 | 
			
		||||
	*/
 | 
			
		||||
	if buf == nil {
 | 
			
		||||
		size := 32 * 1024
 | 
			
		||||
		if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N {
 | 
			
		||||
			if l.N < 1 {
 | 
			
		||||
				size = 1
 | 
			
		||||
			} else {
 | 
			
		||||
				size = int(l.N)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		buf = make([]byte, size)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var seqPos int
 | 
			
		||||
	for {
 | 
			
		||||
		nr, er := src.Read(buf)
 | 
			
		||||
		if nr > 0 {
 | 
			
		||||
			// Look for sequences to trigger client-side diags
 | 
			
		||||
			// A repeat of 4 keys (conveniently 'dead' chars for most
 | 
			
		||||
			// interactive shells; here CTRL-]) shall introduce
 | 
			
		||||
			// some special responses or actions on the client side.
 | 
			
		||||
			if seqPos < 4 {
 | 
			
		||||
				if buf[0] == 0x1d {
 | 
			
		||||
					seqPos++
 | 
			
		||||
				}
 | 
			
		||||
			} else /* seqPos > 0 */ {
 | 
			
		||||
				if v, ok := escs[buf[0]]; ok {
 | 
			
		||||
					v(dst)
 | 
			
		||||
					nr--
 | 
			
		||||
					buf = buf[1:]
 | 
			
		||||
				}
 | 
			
		||||
				seqPos = 0
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			nw, ew := dst.Write(buf[0:nr])
 | 
			
		||||
			if nw > 0 {
 | 
			
		||||
				written += int64(nw)
 | 
			
		||||
			}
 | 
			
		||||
			if ew != nil {
 | 
			
		||||
				err = ew
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if nr != nw {
 | 
			
		||||
				err = io.ErrShortWrite
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if er != nil {
 | 
			
		||||
			if er != io.EOF {
 | 
			
		||||
				err = er
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	//_,_ = dst.Write([]byte{0x2f})
 | 
			
		||||
	return written, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										147
									
								
								hkexsh/hkexsh.go
								
								
								
								
							
							
						
						
									
										147
									
								
								hkexsh/hkexsh.go
								
								
								
								
							| 
						 | 
				
			
			@ -41,6 +41,149 @@ var (
 | 
			
		|||
	Log *logger.Writer
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
const Bob = string("\r\n\r\n" +
 | 
			
		||||
	"@@@@@@@^^~~~~~~~~~~~~~~~~~~~~^@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@^     ~^  @  @@ @ @ @ I  ~^@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@            ~ ~~ ~I          @@@@@\r\n" +
 | 
			
		||||
	"@@@@'                  '  _,w@<    @@@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@w___,w@@@@@@@@  @  @@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@@@@@@@@@@@@@@@  I  @@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@@@@@@@@@@@@@*@[ i  @@@\r\n" +
 | 
			
		||||
	"@@@@     @@@@@@@@@@@@@@@@@@@@[][ | ]@@@\r\n" +
 | 
			
		||||
	"@@@@     ~_,,_ ~@@@@@@@~ ____~ @    @@@\r\n" +
 | 
			
		||||
	"@@@@    _~ ,  ,  `@@@~  _  _`@ ]L  J@@@\r\n" +
 | 
			
		||||
	"@@@@  , @@w@ww+   @@@ww``,,@w@ ][  @@@@\r\n" +
 | 
			
		||||
	"@@@@,  @@@@www@@@ @@@@@@@ww@@@@@[  @@@@\r\n" +
 | 
			
		||||
	"@@@@@_|| @@@@@@P' @@P@@@@@@@@@@@[|c@@@@\r\n" +
 | 
			
		||||
	"@@@@@@w| '@@P~  P]@@@-~, ~Y@@^'],@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@[   _        _J@@Tk     ]]@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@,@ @@, c,,,,,,,y ,w@@[ ,@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@@ i @w   ====--_@@@@@  @@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@@@`,P~ _ ~^^^^Y@@@@@  @@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@^^=^@@^   ^' ,ww,w@@@@@ _@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@_xJ~ ~   ,    @@@@@@@P~_@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@   @,   ,@@@,_____   _,J@@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@L  `' ,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n" +
 | 
			
		||||
	"\r\n")
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	EscHandler func(io.Writer)
 | 
			
		||||
	EscSeqs    map[byte]EscHandler
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Copy copies from src to dst until either EOF is reached
 | 
			
		||||
// on src or an error occurs. It returns the number of bytes
 | 
			
		||||
// copied and the first error encountered while copying, if any.
 | 
			
		||||
//
 | 
			
		||||
// A successful Copy returns err == nil, not err == EOF.
 | 
			
		||||
// Because Copy is defined to read from src until EOF, it does
 | 
			
		||||
// not treat an EOF from Read as an error to be reported.
 | 
			
		||||
//
 | 
			
		||||
// If src implements the WriterTo interface,
 | 
			
		||||
// the copy is implemented by calling src.WriteTo(dst).
 | 
			
		||||
// Otherwise, if dst implements the ReaderFrom interface,
 | 
			
		||||
// the copy is implemented by calling dst.ReadFrom(src).
 | 
			
		||||
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
 | 
			
		||||
	written, err = copyBuffer(dst, src, nil)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// copyBuffer is the actual implementation of Copy and CopyBuffer.
 | 
			
		||||
// if buf is nil, one is allocated.
 | 
			
		||||
func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
 | 
			
		||||
	// NOTE: using dst.Write() in these esc funcs will cause the output
 | 
			
		||||
	// to function as a 'macro', outputting as if user typed the sequence.
 | 
			
		||||
	//
 | 
			
		||||
	// Using os.Stdout outputs to the client's term w/o it or the server
 | 
			
		||||
	// 'seeing' the output.
 | 
			
		||||
	//
 | 
			
		||||
	// TODO: Devise a way to signal to main client thread that
 | 
			
		||||
	// a goroutine should be spawned to do long-lived tasks for
 | 
			
		||||
	// some esc sequences (eg., a time ticker in the corner of terminal,
 | 
			
		||||
	// or tunnel traffic indicator - note we cannot just spawn a goroutine
 | 
			
		||||
	// here, as copyBuffer() returns after each burst of data. Scope must
 | 
			
		||||
	// outlive individual copyBuffer calls).
 | 
			
		||||
	// (Note that since this custom copyBuffer func is used only by
 | 
			
		||||
	// the hkexsh client, it should eventually be moved to client.)
 | 
			
		||||
	escs := EscSeqs{
 | 
			
		||||
		'i': func(io.Writer) { os.Stdout.Write([]byte("\x1b[s\x1b[2;1H\x1b[1;31m[HKEXSH]\x1b[39;49m\x1b[u")) },
 | 
			
		||||
		't': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m[HKEXSH]\x1b[39;49m")) },
 | 
			
		||||
		'B': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m" + Bob + "\x1b[39;49m")) },
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		// If the reader has a WriteTo method, use it to do the copy.
 | 
			
		||||
		// Avoids an allocation and a copy.
 | 
			
		||||
		if wt, ok := src.(io.WriterTo); ok {
 | 
			
		||||
			return wt.WriteTo(dst)
 | 
			
		||||
		}
 | 
			
		||||
		// Similarly, if the writer has a ReadFrom method, use it to do the copy.
 | 
			
		||||
		if rt, ok := dst.(io.ReaderFrom); ok {
 | 
			
		||||
			return rt.ReadFrom(src)
 | 
			
		||||
		}
 | 
			
		||||
	*/
 | 
			
		||||
	if buf == nil {
 | 
			
		||||
		size := 32 * 1024
 | 
			
		||||
		if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N {
 | 
			
		||||
			if l.N < 1 {
 | 
			
		||||
				size = 1
 | 
			
		||||
			} else {
 | 
			
		||||
				size = int(l.N)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		buf = make([]byte, size)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var seqPos int
 | 
			
		||||
	for {
 | 
			
		||||
		nr, er := src.Read(buf)
 | 
			
		||||
		if nr > 0 {
 | 
			
		||||
			// Look for sequences to trigger client-side diags
 | 
			
		||||
			// A repeat of 4 keys (conveniently 'dead' chars for most
 | 
			
		||||
			// interactive shells; here CTRL-]) shall introduce
 | 
			
		||||
			// some special responses or actions on the client side.
 | 
			
		||||
			if seqPos < 4 {
 | 
			
		||||
				if buf[0] == 0x1d {
 | 
			
		||||
					seqPos++
 | 
			
		||||
				}
 | 
			
		||||
			} else /* seqPos > 0 */ {
 | 
			
		||||
				if v, ok := escs[buf[0]]; ok {
 | 
			
		||||
					v(dst)
 | 
			
		||||
					nr--
 | 
			
		||||
					buf = buf[1:]
 | 
			
		||||
				}
 | 
			
		||||
				seqPos = 0
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			nw, ew := dst.Write(buf[0:nr])
 | 
			
		||||
			if nw > 0 {
 | 
			
		||||
				written += int64(nw)
 | 
			
		||||
			}
 | 
			
		||||
			if ew != nil {
 | 
			
		||||
				err = ew
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if nr != nw {
 | 
			
		||||
				err = io.ErrShortWrite
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if er != nil {
 | 
			
		||||
			if er != io.EOF {
 | 
			
		||||
				err = er
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	//_,_ = dst.Write([]byte{0x2f})
 | 
			
		||||
	return written, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// GetSize gets the terminal size using 'stty' command
 | 
			
		||||
func GetSize() (cols, rows int, err error) {
 | 
			
		||||
	cmd := exec.Command("stty", "size") // #nosec
 | 
			
		||||
| 
						 | 
				
			
			@ -288,7 +431,7 @@ func doShellMode(isInteractive bool, conn *hkexnet.Conn, oldState *hkexsh.State,
 | 
			
		|||
			_, outerr := func(conn *hkexnet.Conn, r io.Reader) (w int64, e error) {
 | 
			
		||||
				// Copy() expects EOF so this will
 | 
			
		||||
				// exit with outerr == nil
 | 
			
		||||
				w, e = hkexnet.Copy(conn, r)
 | 
			
		||||
				w, e = Copy(conn, r)
 | 
			
		||||
				return w, e
 | 
			
		||||
			}(conn, os.Stdin)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -728,7 +871,7 @@ func main() {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if rec.Status() != 0 {
 | 
			
		||||
			_ = hkexsh.Restore(int(os.Stdin.Fd()), oldState)    // nolint: errcheck,gosec
 | 
			
		||||
			_ = hkexsh.Restore(int(os.Stdin.Fd()), oldState)                     // nolint: errcheck,gosec
 | 
			
		||||
			fmt.Fprintln(os.Stderr, "Session exited with status:", rec.Status()) // nolint: errcheck
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue