From f6910162b411000e80d994bffed0a63dde1b9ffb Mon Sep 17 00:00:00 2001 From: Russtopia Date: Mon, 24 Feb 2020 16:50:55 -0800 Subject: [PATCH 1/5] Update 'README.md' ChaCha20 support --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7b59dba..4112d98 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Currently supported session algorithms: * Twofish-128 * Blowfish-64 * CryptMTv1 (64bit) (https://eprint.iacr.org/2005/165.pdf) +* ChaCha20 (https://github.com/aead/chacha20) [HMAC] * HMAC-SHA256 From 64a314df113226fe3cbe9d04554961c1138d6210 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Tue, 25 Feb 2020 21:16:55 -0800 Subject: [PATCH 2/5] Client->Remote xc progress indication using pv Signed-off-by: Russ Magee --- xs/xs.go | 98 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/xs/xs.go b/xs/xs.go index ce924bc..df97811 100755 --- a/xs/xs.go +++ b/xs/xs.go @@ -240,21 +240,21 @@ func GetSize() (cols, rows int, err error) { return } -// doCopyMode begins a secure xs local<->remote file copy operation. -// -// TODO: reduce gocyclo -func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, rec *xs.Session) (exitStatus uint32, err error) { - if remoteDest { - log.Println("local files:", files, "remote filepath:", string(rec.Cmd())) +func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (captureStderr bool, cmd string, args []string) { + // TODO: detect if we have 'pv' + // pipeview http://www.ivarch.com/programs/pv.shtml + // and use it for nice client progress display. + _, pverr := os.Stat("/usr/bin/pv") + if pverr != nil { + _, pverr = os.Stat("/usr/local/bin/pv") + } - var c *exec.Cmd + if pverr != nil { + // copyQuiet and copyLimitBPS are not applicable in dumb copy mode - //os.Clearenv() - //os.Setenv("HOME", u.HomeDir) - //os.Setenv("TERM", "vt102") // TODO: server or client option? - - cmdName := "/bin/tar" - cmdArgs := []string{"-cz", "-f", "/dev/stdout"} + captureStderr = true + cmd = "/bin/tar" + args = []string{"-cz", "-f", "/dev/stdout"} files = strings.TrimSpace(files) // Awesome fact: tar actually can take multiple -C args, and // changes to the dest dir *as it sees each one*. This enables @@ -272,22 +272,70 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, rec *xs.Session v, _ = filepath.Abs(v) // #nosec dirTmp, fileTmp := path.Split(v) if dirTmp == "" { - cmdArgs = append(cmdArgs, fileTmp) + args = append(args, fileTmp) } else { - cmdArgs = append(cmdArgs, "-C", dirTmp, fileTmp) + args = append(args, "-C", dirTmp, fileTmp) } } + } else { + captureStderr = copyQuiet + bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d", copyLimitBPS) + displayOpts := " -f -pr " + cmd = "/bin/bash" + args = []string{"-c", "/bin/tar -cz -f /dev/stdout "} + files = strings.TrimSpace(files) + // Awesome fact: tar actually can take multiple -C args, and + // changes to the dest dir *as it sees each one*. This enables + // its use below, where clients can send scattered sets of source + // files and dirs to be extracted to a single dest dir server-side, + // whilst preserving the subtrees of dirs on the other side. + // Eg., tar -c -f /dev/stdout -C /dirA fileInA -C /some/where/dirB fileInB /foo/dirC + // packages fileInA, fileInB, and dirC at a single toplevel in the tar. + // The tar authors are/were real smarties :) + // + // This is the 'scatter/gather' logic to allow specification of + // files and dirs in different trees to be deposited in a single + // remote destDir. + for _, v := range strings.Split(files, " ") { + v, _ = filepath.Abs(v) // #nosec + dirTmp, fileTmp := path.Split(v) + if dirTmp == "" { + args[1] = args[1] + fileTmp + " " + } else { + args[1] = args[1] + " -C " + dirTmp + " " + fileTmp + " " + } + } + args[1] = args[1] + "| pv" + displayOpts + bandwidthInBytesPerSec + " -s $(du -cb " + files + " | tail -1 | cut -f 1) -c" + } - log.Printf("[%v %v]\n", cmdName, cmdArgs) - // NOTE the lack of quotes around --xform option's sed expression. - // When args are passed in exec() format, no quoting is required - // (as this isn't input from a shell) (right? -rlm 20180823) + log.Printf("[%v %v]\n", cmd, args) + return +} + +// doCopyMode begins a secure xs local<->remote file copy operation. +// +// TODO: reduce gocyclo +func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, copyLimitBPS uint, rec *xs.Session) (exitStatus uint32, err error) { + if remoteDest { + log.Println("local files:", files, "remote filepath:", string(rec.Cmd())) + + var c *exec.Cmd + + //os.Clearenv() + //os.Setenv("HOME", u.HomeDir) + //os.Setenv("TERM", "vt102") // TODO: server or client option? + + captureStderr, cmdName, cmdArgs := buildCmdLocalToRemote(copyQuiet, copyLimitBPS, strings.TrimSpace(files)) c = exec.Command(cmdName, cmdArgs...) // #nosec c.Dir, _ = os.Getwd() // #nosec log.Println("[wd:", c.Dir, "]") c.Stdout = conn stdErrBuffer := new(bytes.Buffer) - c.Stderr = stdErrBuffer + if captureStderr { + c.Stderr = stdErrBuffer + } else { + c.Stderr = os.Stderr + } // Start the command (no pty) err = c.Start() // returns immediately @@ -320,7 +368,9 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, rec *xs.Session // an ExitStatus() method with the same signature. if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { exitStatus = uint32(status.ExitStatus()) - fmt.Print(stdErrBuffer) + if captureStderr { + fmt.Print(stdErrBuffer) + } } } } @@ -612,6 +662,8 @@ func main() { var copySrc []byte var copyDst string + var copyQuiet bool + var copyLimitBPS uint var authCookie string var chaffEnabled bool @@ -649,6 +701,8 @@ func main() { shellMode = true flag.Usage = usageShell } else { + flag.BoolVar(©Quiet, "q", false, "do not output progress bar during copy") + flag.UintVar(©LimitBPS, "L", 8589934592, "copy max rate in bytes per sec") flag.Usage = usageCp } flag.Parse() @@ -932,7 +986,7 @@ func main() { launchTuns(&conn, remoteHost, tunSpecStr) doShellMode(isInteractive, &conn, oldState, rec) } else { // copyMode - s, _ := doCopyMode(&conn, pathIsDest, fileArgs, rec) // nolint: errcheck,gosec + s, _ := doCopyMode(&conn, pathIsDest, fileArgs, copyQuiet, copyLimitBPS, rec) // nolint: errcheck,gosec rec.SetStatus(s) } From 2e16c9a692d9724eba20347476758b49f1e56e29 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Tue, 25 Feb 2020 23:08:42 -0800 Subject: [PATCH 3/5] Remote->Client cp with pv status TODO: Remote total bytesize estimate Signed-off-by: Russ Magee --- xs/xs.go | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/xs/xs.go b/xs/xs.go index df97811..07f64d5 100755 --- a/xs/xs.go +++ b/xs/xs.go @@ -240,8 +240,34 @@ func GetSize() (cols, rows int, err error) { return } +func buildCmdRemoteToLocal(copyQuiet bool, copyLimitBPS uint, destPath, files string) (captureStderr bool, cmd string, args []string) { + // Detect if we have 'pv' + // pipeview http://www.ivarch.com/programs/pv.shtml + // and use it for nice client progress display. + _, pverr := os.Stat("/usr/bin/pv") + if pverr != nil { + _, pverr = os.Stat("/usr/local/bin/pv") + } + + if copyQuiet || pverr != nil { + // copyQuiet and copyLimitBPS are not applicable in dumb copy mode + captureStderr = true + cmd = "/bin/tar" + + args = []string{"-xz", "-C", destPath} +} else { + // TODO: Query remote side for total file/dir size + bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d ", copyLimitBPS) + displayOpts := " -f -pr " + cmd = "/bin/bash" + args = []string{"-c", "pv " + displayOpts + bandwidthInBytesPerSec + "| tar -xz -C " + destPath} + } + log.Printf("[%v %v]\n", cmd, args) + return +} + func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (captureStderr bool, cmd string, args []string) { - // TODO: detect if we have 'pv' + // Detect if we have 'pv' // pipeview http://www.ivarch.com/programs/pv.shtml // and use it for nice client progress display. _, pverr := os.Stat("/usr/bin/pv") @@ -403,17 +429,11 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, } } else { log.Println("remote filepath:", string(rec.Cmd()), "local files:", files) - var c *exec.Cmd - - cmdName := "/bin/tar" destPath := files - cmdArgs := []string{"-xz", "-C", destPath} - log.Printf("[%v %v]\n", cmdName, cmdArgs) - // NOTE the lack of quotes around --xform option's sed expression. - // When args are passed in exec() format, no quoting is required - // (as this isn't input from a shell) (right? -rlm 20180823) - //cmdArgs := []string{"-xvz", "-C", destPath, `--xform=s#.*/\(.*\)#\1#`} + _, cmdName, cmdArgs := buildCmdRemoteToLocal(copyQuiet, copyLimitBPS, destPath, strings.TrimSpace(files)) + + var c *exec.Cmd c = exec.Command(cmdName, cmdArgs...) // #nosec c.Stdin = conn c.Stdout = os.Stdout From d1076c9bd9c835deaf93c3176c5e5a23bb7e697a Mon Sep 17 00:00:00 2001 From: Russtopia Date: Tue, 25 Feb 2020 23:25:39 -0800 Subject: [PATCH 4/5] Update 'README.md' with xc progress info 'pv' util progress notes added --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4112d98..6014981 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,8 @@ xc uses a 'tarpipe' to send file data over the encrypted channel. Use the -d fla NOTE: Renaming while copying (eg., 'cp /foo/bar/fileA ./fileB') is NOT supported. Put another way, the destination (whether local or remote) must ALWAYS be a directory. +If the 'pv' pipeview utility is available (http://www.ivarch.com/programs/pv.shtml) file transfer progress and bandwidth control will be available (suppress the former with the -q option, set the latter with -L <bytes_per_second>). + ### Tunnels Simple tunnels (client -> server, no reverse tunnels for now) are supported. From b3ebd0db17adea71e1ee7468f5e002a3c201bbfb Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Tue, 25 Feb 2020 23:33:09 -0800 Subject: [PATCH 5/5] Bumped version Signed-off-by: Russ Magee --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eeb9f77..b919883 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := 0.8.19 +VERSION := 0.8.20 .PHONY: lint vis clean common client server passwd subpkgs install uninstall reinstall ## Tag version of binaries with build info wrt.