mirror of https://gogs.blitter.com/RLabs/xs
parent
9641fd3fff
commit
a0e90c14ba
|
@ -42,7 +42,6 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -56,32 +55,6 @@ import (
|
||||||
const PAD_SZ = 32 // max size of padding applied to each packet
|
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 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 (
|
type (
|
||||||
WinSize struct {
|
WinSize struct {
|
||||||
Rows uint16
|
Rows uint16
|
||||||
|
@ -122,9 +95,6 @@ type (
|
||||||
wm hash.Hash
|
wm hash.Hash
|
||||||
dBuf *bytes.Buffer //decrypt buffer for Read()
|
dBuf *bytes.Buffer //decrypt buffer for Read()
|
||||||
}
|
}
|
||||||
|
|
||||||
EscHandler func(io.Writer)
|
|
||||||
EscSeqs map[byte]EscHandler
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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
|
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
|
// GetSize gets the terminal size using 'stty' command
|
||||||
func GetSize() (cols, rows int, err error) {
|
func GetSize() (cols, rows int, err error) {
|
||||||
cmd := exec.Command("stty", "size") // #nosec
|
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) {
|
_, outerr := func(conn *hkexnet.Conn, r io.Reader) (w int64, e error) {
|
||||||
// Copy() expects EOF so this will
|
// Copy() expects EOF so this will
|
||||||
// exit with outerr == nil
|
// exit with outerr == nil
|
||||||
w, e = hkexnet.Copy(conn, r)
|
w, e = Copy(conn, r)
|
||||||
return w, e
|
return w, e
|
||||||
}(conn, os.Stdin)
|
}(conn, os.Stdin)
|
||||||
|
|
||||||
|
@ -728,7 +871,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if rec.Status() != 0 {
|
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
|
fmt.Fprintln(os.Stderr, "Session exited with status:", rec.Status()) // nolint: errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue