xs/ lint cleanups

This commit is contained in:
Russ Magee 2022-09-24 20:01:16 -07:00
parent 0f28d2c023
commit 667328a91c
3 changed files with 100 additions and 87 deletions

View File

@ -25,6 +25,8 @@ linters-settings:
#- style #- style
#- opinionated #- opinionated
disabled-checks: disabled-checks:
- commentFormatting
- commentedOutCode
- dupImport # https://github.com/go-critic/go-critic/issues/845 - dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain - ifElseChain
- octalLiteral - octalLiteral

View File

@ -31,7 +31,7 @@ func handleTermResizes(conn *xsnet.Conn) {
log.Println(err) log.Println(err)
} }
termSzPacket := fmt.Sprintf("%d %d", rows, cols) termSzPacket := fmt.Sprintf("%d %d", rows, cols)
conn.WritePacket([]byte(termSzPacket), xsnet.CSOTermSize) conn.WritePacket([]byte(termSzPacket), xsnet.CSOTermSize) //nolint:errcheck
} }
}() }()
ch <- syscall.SIGWINCH // Initial resize. ch <- syscall.SIGWINCH // Initial resize.

183
xs/xs.go
View File

@ -14,7 +14,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"math/rand" "math/rand"
"os" "os"
@ -57,6 +56,18 @@ var (
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
const (
CmdExitedEarly = 2
XSNetDialFailed = 3
ErrReadingAuthReply = 253
ServerRejectedSecureProposal = 254
GeneralProtocolErr = 255
)
const (
DeadCharPrefix = 0x1d
)
// Praise Bob. Do not remove, lest ye lose Slack. // Praise Bob. Do not remove, lest ye lose Slack.
const bob = string("\r\n\r\n" + const bob = string("\r\n\r\n" +
"@@@@@@@^^~~~~~~~~~~~~~~~~~~~~^@@@@@@@@@\r\n" + "@@@@@@@^^~~~~~~~~~~~~~~~~~~~~^@@@@@@@@@\r\n" +
@ -154,7 +165,7 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er
if rt, ok := dst.(io.ReaderFrom); ok { if rt, ok := dst.(io.ReaderFrom); ok {
return rt.ReadFrom(src) return rt.ReadFrom(src)
} }
*/ */ //nolint:gocritic,nolintlint
if buf == nil { if buf == nil {
size := 32 * 1024 size := 32 * 1024
if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N { if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N {
@ -175,8 +186,8 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er
// A repeat of 4 keys (conveniently 'dead' chars for most // A repeat of 4 keys (conveniently 'dead' chars for most
// interactive shells; here CTRL-]) shall introduce // interactive shells; here CTRL-]) shall introduce
// some special responses or actions on the client side. // some special responses or actions on the client side.
if seqPos < 4 { if seqPos < 4 { //nolint:gomnd
if buf[0] == 0x1d { if buf[0] == DeadCharPrefix {
seqPos++ seqPos++
} }
} else { } else {
@ -223,7 +234,7 @@ func GetSize() (cols, rows int, err error) {
if err != nil { if err != nil {
log.Println(err) log.Println(err)
cols, rows = 80, 24 //failsafe cols, rows = 80, 24 // failsafe
} else { } else {
n, err := fmt.Sscanf(string(out), "%d %d\n", &rows, &cols) n, err := fmt.Sscanf(string(out), "%d %d\n", &rows, &cols)
if n < 2 || if n < 2 ||
@ -257,7 +268,7 @@ func buildCmdRemoteToLocal(copyQuiet bool, copyLimitBPS uint, destPath string) (
} else { } else {
// TODO: Query remote side for total file/dir size // TODO: Query remote side for total file/dir size
bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d ", copyLimitBPS) bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d ", copyLimitBPS)
displayOpts := " -pre " displayOpts := " -pre " //nolint:goconst
cmd = xs.GetTool("bash") cmd = xs.GetTool("bash")
args = []string{"-c", "pv " + displayOpts + bandwidthInBytesPerSec + "| tar -xz -C " + destPath} args = []string{"-c", "pv " + displayOpts + bandwidthInBytesPerSec + "| tar -xz -C " + destPath}
} }
@ -305,7 +316,7 @@ func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (cap
} else { } else {
captureStderr = copyQuiet captureStderr = copyQuiet
bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d", copyLimitBPS) bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d", copyLimitBPS)
displayOpts := " -pre " displayOpts := " -pre " //nolint:goconst,nolintlint
cmd = xs.GetTool("bash") cmd = xs.GetTool("bash")
args = []string{"-c", xs.GetTool("tar") + " -cz -f /dev/stdout "} args = []string{"-c", xs.GetTool("tar") + " -cz -f /dev/stdout "}
files = strings.TrimSpace(files) files = strings.TrimSpace(files)
@ -355,9 +366,9 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool,
var c *exec.Cmd var c *exec.Cmd
//os.Clearenv() // os.Clearenv()
//os.Setenv("HOME", u.HomeDir) // os.Setenv("HOME", u.HomeDir)
//os.Setenv("TERM", "vt102") // TODO: server or client option? // os.Setenv("TERM", "vt102") // TODO: server or client option?
captureStderr, cmdName, cmdArgs := buildCmdLocalToRemote(copyQuiet, copyLimitBPS, strings.TrimSpace(files)) captureStderr, cmdName, cmdArgs := buildCmdLocalToRemote(copyQuiet, copyLimitBPS, strings.TrimSpace(files))
c = exec.Command(cmdName, cmdArgs...) // #nosec c = exec.Command(cmdName, cmdArgs...) // #nosec
@ -390,7 +401,7 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool,
if err != nil { if err != nil {
fmt.Println("cmd exited immediately. Cannot get cmd.Wait().ExitStatus()") fmt.Println("cmd exited immediately. Cannot get cmd.Wait().ExitStatus()")
err = errors.New("cmd exited prematurely") err = errors.New("cmd exited prematurely")
exitStatus = uint32(2) exitStatus = uint32(CmdExitedEarly)
} else { } else {
if err = c.Wait(); err != nil { if err = c.Wait(); err != nil {
if exiterr, ok := err.(*exec.ExitError); ok { if exiterr, ok := err.(*exec.ExitError); ok {
@ -410,7 +421,7 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool,
} }
// send CSOExitStatus to inform remote (server) end cp is done // send CSOExitStatus to inform remote (server) end cp is done
log.Println("Sending local exitStatus:", exitStatus) log.Println("Sending local exitStatus:", exitStatus)
r := make([]byte, 4) r := make([]byte, 4) //nolint:gomnd
binary.BigEndian.PutUint32(r, exitStatus) binary.BigEndian.PutUint32(r, exitStatus)
_, we := conn.WritePacket(r, xsnet.CSOExitStatus) _, we := conn.WritePacket(r, xsnet.CSOExitStatus)
if we != nil { if we != nil {
@ -418,7 +429,7 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool,
} }
// Do a final read for remote's exit status // Do a final read for remote's exit status
s := make([]byte, 4) s := make([]byte, 4) //nolint:gomnd
_, remErr := conn.Read(s) _, remErr := conn.Read(s)
if remErr != io.EOF && if remErr != io.EOF &&
!strings.Contains(remErr.Error(), "use of closed network") && !strings.Contains(remErr.Error(), "use of closed network") &&
@ -478,8 +489,8 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool,
// doShellMode begins an xs shell session (one-shot command or // doShellMode begins an xs shell session (one-shot command or
// interactive). // interactive).
func doShellMode(isInteractive bool, conn *xsnet.Conn, oldState *xs.State, rec *xs.Session) { func doShellMode(isInteractive bool, conn *xsnet.Conn, oldState *xs.State, rec *xs.Session) {
//client reader (from server) goroutine // Client reader (from server) goroutine
//Read remote end's stdout // Read remote end's stdout
wg.Add(1) wg.Add(1)
// #gv:s/label=\"doShellMode\$1\"/label=\"shellRemoteToStdin\"/ // #gv:s/label=\"doShellMode\$1\"/label=\"shellRemoteToStdin\"/
@ -602,7 +613,7 @@ func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, other
if strings.Contains(arg, ":") || strings.Contains(arg, "@") { if strings.Contains(arg, ":") || strings.Contains(arg, "@") {
fancyArg := strings.Split(flag.Arg(i), "@") fancyArg := strings.Split(flag.Arg(i), "@")
var fancyHostPath []string var fancyHostPath []string
if len(fancyArg) < 2 { if len(fancyArg) < 2 { //nolint:gomnd
//TODO: no user specified, use current //TODO: no user specified, use current
fancyUser = "[default:getUser]" fancyUser = "[default:getUser]"
fancyHostPath = strings.Split(fancyArg[0], ":") fancyHostPath = strings.Split(fancyArg[0], ":")
@ -628,8 +639,8 @@ func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, other
return fancyUser, fancyHost, fancyPath, isDest, otherArgs return fancyUser, fancyHost, fancyPath, isDest, otherArgs
} }
func launchTuns(conn *xsnet.Conn, remoteHost string, tuns string) { func launchTuns(conn *xsnet.Conn /*remoteHost string,*/, tuns string) {
/*remAddrs, _ := net.LookupHost(remoteHost)*/ /*remAddrs, _ := net.LookupHost(remoteHost)*/ //nolint:gocritic,nolintlint
if tuns == "" { if tuns == "" {
return return
@ -678,12 +689,12 @@ func main() { //nolint: funlen, gocyclo
var ( var (
isInteractive bool isInteractive bool
vopt bool vopt bool
gopt bool //login via password, asking server to generate authToken gopt bool // true: login via password, asking server to generate authToken
dbg bool dbg bool
shellMode bool // if true act as shell, else file copier shellMode bool // true: act as shell, false: file copier
cipherAlg string //cipher alg cipherAlg string
hmacAlg string //hmac alg hmacAlg string
kexAlg string //KEX/KEM alg kexAlg string
server string server string
port uint port uint
cmdStr string cmdStr string
@ -703,7 +714,7 @@ func main() { //nolint: funlen, gocyclo
op []byte op []byte
) )
//=== Common (xs and xc) option parsing // === Common (xs and xc) option parsing
flag.BoolVar(&vopt, "v", false, "show version") flag.BoolVar(&vopt, "v", false, "show version")
flag.BoolVar(&dbg, "d", false, "debug logging") flag.BoolVar(&dbg, "d", false, "debug logging")
@ -731,18 +742,18 @@ func main() { //nolint: funlen, gocyclo
KEX_FRODOKEM_1344SHAKE KEX_FRODOKEM_1344SHAKE
KEX_FRODOKEM_976AES KEX_FRODOKEM_976AES
KEX_FRODOKEM_976SHAKE`) KEX_FRODOKEM_976SHAKE`)
flag.StringVar(&kcpMode, "K", "unused", "KCP `alg`, one of [KCP_NONE | KCP_AES | KCP_BLOWFISH | KCP_CAST5 | KCP_SM4 | KCP_SALSA20 | KCP_SIMPLEXOR | KCP_TEA | KCP_3DES | KCP_TWOFISH | KCP_XTEA] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") flag.StringVar(&kcpMode, "K", "unused", "KCP `alg`, one of [KCP_NONE | KCP_AES | KCP_BLOWFISH | KCP_CAST5 | KCP_SM4 | KCP_SALSA20 | KCP_SIMPLEXOR | KCP_TEA | KCP_3DES | KCP_TWOFISH | KCP_XTEA] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") //nolint:lll
flag.UintVar(&port, "p", 2000, "``port") flag.UintVar(&port, "p", 2000, "``port") //nolint:gomnd,lll
//flag.StringVar(&authCookie, "a", "", "auth cookie") //nolint:gocritic,nolintlint // flag.StringVar(&authCookie, "a", "", "auth cookie")
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") //nolint:gomnd
flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max `msecs`") flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max `msecs`") //nolint:gomnd
flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max `bytes`") flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max `bytes`") //nolint:gomnd
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to <`file`>") flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to <`file`>")
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to <`file`>") flag.StringVar(&memprofile, "memprofile", "", "write memory profile to <`file`>")
//=== xc vs. xs option parsing // === xc vs. xs option parsing
// Find out what program we are (shell or copier) // Find out what program we are (shell or copier)
myPath := strings.Split(os.Args[0], string(os.PathSeparator)) myPath := strings.Split(os.Args[0], string(os.PathSeparator))
@ -759,7 +770,7 @@ func main() { //nolint: funlen, gocyclo
flag.Usage = usageShell flag.Usage = usageShell
} else { } else {
flag.BoolVar(&copyQuiet, "q", false, "do not output progress bar during copy") flag.BoolVar(&copyQuiet, "q", false, "do not output progress bar during copy")
flag.UintVar(&copyLimitBPS, "L", 8589934592, "copy max rate in bytes per sec") flag.UintVar(&copyLimitBPS, "L", 8589934592, "copy max rate in bytes per sec") //nolint:gomnd
flag.Usage = usageCp flag.Usage = usageCp
} }
flag.Parse() flag.Parse()
@ -769,7 +780,7 @@ func main() { //nolint: funlen, gocyclo
exitWithStatus(0) exitWithStatus(0)
} }
//=== Profiling instrumentation // === Profiling instrumentation
if cpuprofile != "" { if cpuprofile != "" {
f, err := os.Create(cpuprofile) f, err := os.Create(cpuprofile)
@ -779,19 +790,19 @@ func main() { //nolint: funlen, gocyclo
defer f.Close() defer f.Close()
fmt.Println("StartCPUProfile()") fmt.Println("StartCPUProfile()")
if err := pprof.StartCPUProfile(f); err != nil { if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err) log.Fatal("could not start CPU profile: ", err) //nolint:gocritic
} else { } else {
defer pprof.StopCPUProfile() defer pprof.StopCPUProfile()
} }
go func() { http.ListenAndServe("localhost:6060", nil) }() go func() { http.ListenAndServe("localhost:6060", nil) }() //nolint:errcheck,gosec
} }
//=== User, host, port and path args for file operations, if applicable // === User, host, port and path args for file operations, if applicable
remoteUser, remoteHost, tmpPath, pathIsDest, otherArgs := remoteUser, remoteHost, tmpPath, pathIsDest, otherArgs :=
parseNonSwitchArgs(flag.Args()) parseNonSwitchArgs(flag.Args())
//fmt.Println("otherArgs:", otherArgs) //nolint:gocritic,nolintlint // fmt.Println("otherArgs:", otherArgs)
// Set defaults if user doesn't specify user, path or port // Set defaults if user doesn't specify user, path or port
var uname string var uname string
@ -809,7 +820,7 @@ func main() { //nolint: funlen, gocyclo
tmpPath = "." tmpPath = "."
} }
//=== Copy mode arg and copy src/dest setup // === Copy mode arg and copy src/dest setup
var fileArgs string var fileArgs string
if !shellMode /*&& tmpPath != ""*/ { if !shellMode /*&& tmpPath != ""*/ {
@ -842,15 +853,15 @@ func main() { //nolint: funlen, gocyclo
} }
} }
//=== Do some final option consistency checks // === Do some final option consistency checks
//fmt.Println("server finally is:", server) //nolint:gocritic,nolintlint // fmt.Println("server finally is:", server)
if flag.NFlag() == 0 && server == "" { if flag.NFlag() == 0 && server == "" {
flag.Usage() flag.Usage()
exitWithStatus(0) exitWithStatus(0)
} }
if len(cmdStr) != 0 && (len(copySrc) != 0 || len(copyDst) != 0) { if cmdStr != "" && (len(copySrc) != 0 || copyDst != "") {
log.Fatal("incompatible options -- either cmd (-x) or copy ops but not both") log.Fatal("incompatible options -- either cmd (-x) or copy ops but not both")
} }
@ -863,18 +874,18 @@ func main() { //nolint: funlen, gocyclo
if dbg { if dbg {
log.SetOutput(Log) log.SetOutput(Log)
} else { } else {
log.SetOutput(ioutil.Discard) log.SetOutput(io.Discard)
} }
//=== Auth token fetch for login // === Auth token fetch for login
if !gopt { if !gopt {
// See if we can log in via an auth token // See if we can log in via an auth token
u, _ := user.Current() u, _ := user.Current()
ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir)) ab, aerr := os.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir))
if aerr == nil { if aerr == nil {
for _, line := range strings.Split(string(ab), "\n") { for _, line := range strings.Split(string(ab), "\n") {
line = line + "\n" line += "\n"
idx := strings.Index(line, remoteHost+":"+uname) idx := strings.Index(line, remoteHost+":"+uname)
if idx >= 0 { if idx >= 0 {
line = line[idx:] line = line[idx:]
@ -894,8 +905,8 @@ func main() { //nolint: funlen, gocyclo
} }
runtime.GC() runtime.GC()
//=== Enforce some sane min/max vals on chaff flags // === Enforce some sane min/max vals on chaff flags
if chaffFreqMin < 2 { if chaffFreqMin < 2 { //nolint:gomnd
chaffFreqMin = 2 chaffFreqMin = 2
} }
if chaffFreqMax == 0 { if chaffFreqMax == 0 {
@ -905,7 +916,7 @@ func main() { //nolint: funlen, gocyclo
chaffBytesMax = 64 chaffBytesMax = 64
} }
//=== Shell vs. Copy mode chaff and cmd setup // === Shell vs. Copy mode chaff and cmd setup
if shellMode { if shellMode {
// We must make the decision about interactivity before Dial() // We must make the decision about interactivity before Dial()
@ -915,7 +926,7 @@ func main() { //nolint: funlen, gocyclo
op = []byte{'A'} op = []byte{'A'}
chaffFreqMin = 2 chaffFreqMin = 2
chaffFreqMax = 10 chaffFreqMax = 10
} else if len(cmdStr) == 0 { } else if cmdStr == "" {
op = []byte{'s'} op = []byte{'s'}
isInteractive = true isInteractive = true
} else { } else {
@ -936,18 +947,18 @@ func main() { //nolint: funlen, gocyclo
// client->server file copy // client->server file copy
// src file list is in copySrc // src file list is in copySrc
op = []byte{'D'} op = []byte{'D'}
//fmt.Println("client->server copy:", string(copySrc), "->", copyDst) //nolint:gocritic,nolintlint // fmt.Println("client->server copy:", string(copySrc), "->", copyDst)
cmdStr = copyDst cmdStr = copyDst
} else { } else {
// server->client file copy // server->client file copy
// remote src file(s) in copyDsr // remote src file(s) in copyDsr
op = []byte{'S'} op = []byte{'S'}
//fmt.Println("server->client copy:", string(copySrc), "->", copyDst) //nolint:gocritic,nolintlint // fmt.Println("server->client copy:", string(copySrc), "->", copyDst)
cmdStr = string(copySrc) cmdStr = string(copySrc)
} }
} }
//=== TCP / KCP Dial setup // === TCP / KCP Dial setup
proto := "tcp" proto := "tcp"
if kcpMode != "unused" { if kcpMode != "unused" {
@ -956,10 +967,10 @@ func main() { //nolint: funlen, gocyclo
conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode) conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
exitWithStatus(3) exitWithStatus(XSNetDialFailed)
} }
//=== Shell terminal mode (Shell vs. Copy) setup // === Shell terminal mode (Shell vs. Copy) setup
// Set stdin in raw mode if it's an interactive session // Set stdin in raw mode if it's an interactive session
// TODO: send flag to server side indicating this // TODO: send flag to server side indicating this
@ -967,7 +978,7 @@ func main() { //nolint: funlen, gocyclo
var oldState *xs.State var oldState *xs.State
defer conn.Close() defer conn.Close()
//=== From this point on, conn is a secure encrypted channel // === From this point on, conn is a secure encrypted channel
if shellMode { if shellMode {
if isatty.IsTerminal(os.Stdin.Fd()) { if isatty.IsTerminal(os.Stdin.Fd()) {
@ -983,20 +994,20 @@ func main() { //nolint: funlen, gocyclo
} }
} }
//=== Login phase // === Login phase
// Start login timeout here and disconnect if user/pass phase stalls // Start login timeout here and disconnect if user/pass phase stalls
//iloginImpatience := time.AfterFunc(20*time.Second, func() { // iloginImpatience := time.AfterFunc(20*time.Second, func() {
//i fmt.Printf(" .. [you still there? Waiting for a password.]") // i fmt.Printf(" .. [you still there? Waiting for a password.]")
//i}) // i})
loginTimeout := time.AfterFunc(30*time.Second, func() { loginTimeout := time.AfterFunc(30*time.Second, func() { //nolint:gomnd
restoreTermState(oldState) restoreTermState(oldState)
fmt.Printf(" .. [login timeout]\n") fmt.Printf(" .. [login timeout]\n")
exitWithStatus(xsnet.CSOLoginTimeout) exitWithStatus(xsnet.CSOLoginTimeout)
}) })
if len(authCookie) == 0 { if authCookie == "" {
//No auth token, prompt for password // No auth token, prompt for password
fmt.Printf("Gimme cookie:") fmt.Printf("Gimme cookie:")
ab, e := xs.ReadPassword(os.Stdin.Fd()) ab, e := xs.ReadPassword(os.Stdin.Fd())
fmt.Printf("\r\n") fmt.Printf("\r\n")
@ -1006,43 +1017,43 @@ func main() { //nolint: funlen, gocyclo
authCookie = string(ab) authCookie = string(ab)
} }
//i_ = loginImpatience.Stop() //nolint:gocritic,nolintlint // i_ = loginImpatience.Stop()
_ = loginTimeout.Stop() _ = loginTimeout.Stop()
// Security scrub // Security scrub
runtime.GC() runtime.GC()
//=== Session param and TERM setup // === Session param and TERM setup
// Set up session params and send over to server // Set up session params and send over to server
rec := xs.NewSession(op, []byte(uname), []byte(remoteHost), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie), 0) rec := xs.NewSession(op, []byte(uname), []byte(remoteHost), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie), 0)
sendErr := sendSessionParams(&conn, rec) sendErr := sendSessionParams(&conn, rec)
if sendErr != nil { if sendErr != nil {
restoreTermState(oldState) restoreTermState(oldState)
rec.SetStatus(254) rec.SetStatus(ServerRejectedSecureProposal)
fmt.Fprintln(os.Stderr, "Error: server rejected secure proposal params or login timed out") fmt.Fprintln(os.Stderr, "Error: server rejected secure proposal params or login timed out")
exitWithStatus(int(rec.Status())) exitWithStatus(int(rec.Status()))
//log.Fatal(sendErr) //nolint:gocritic,nolintlint // log.Fatal(sendErr)
} }
//Security scrub // Security scrub
authCookie = "" //nolint: ineffassign authCookie = "" //nolint: ineffassign
runtime.GC() runtime.GC()
//=== Login Auth // === Login Auth
//=== Read auth reply from server // === Read auth reply from server
authReply := make([]byte, 1) // bool: 0 = fail, 1 = pass authReply := make([]byte, 1) // bool: 0 = fail, 1 = pass
_, err = conn.Read(authReply) _, err = conn.Read(authReply)
if err != nil { if err != nil {
//=== Exit if auth reply not received // === Exit if auth reply not received
fmt.Fprintln(os.Stderr, "Error reading auth reply") fmt.Fprintln(os.Stderr, "Error reading auth reply")
rec.SetStatus(255) rec.SetStatus(ErrReadingAuthReply)
} else if authReply[0] == 0 { } else if authReply[0] == 0 {
//=== .. or if auth failed // === .. or if auth failed
fmt.Fprintln(os.Stderr, rejectUserMsg()) fmt.Fprintln(os.Stderr, rejectUserMsg())
rec.SetStatus(255) rec.SetStatus(GeneralProtocolErr)
} else { } else {
//=== Set up chaffing to server // === Set up chaffing to server
conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing
if chaffEnabled { if chaffEnabled {
// #gv:s/label=\"main\$2\"/label=\"deferCloseChaff\"/ // #gv:s/label=\"main\$2\"/label=\"deferCloseChaff\"/
@ -1052,16 +1063,16 @@ func main() { //nolint: funlen, gocyclo
defer conn.ShutdownChaff() defer conn.ShutdownChaff()
} }
//=== (goroutine) Start keepAliveWorker for tunnels // === (goroutine) Start keepAliveWorker for tunnels
// #gv:s/label=\"main\$1\"/label=\"tunKeepAlive\"/ // #gv:s/label=\"main\$1\"/label=\"tunKeepAlive\"/
// TODO:.gv:main:1:tunKeepAlive // TODO:.gv:main:1:tunKeepAlive
//[1]: better to always send tunnel keepAlives even if client didn't specify // [1]: better to always send tunnel keepAlives even if client didn't specify
// any, to prevent listeners from knowing this. // any, to prevent listeners from knowing this.
//[1] if tunSpecStr != "" { // [1] if tunSpecStr != "" {
keepAliveWorker := func() { keepAliveWorker := func() {
for { for {
// Add a bit of jitter to keepAlive so it doesn't stand out quite as much // Add a bit of jitter to keepAlive so it doesn't stand out quite as much
time.Sleep(time.Duration(2000-rand.Intn(200)) * time.Millisecond) //nolint:gosec time.Sleep(time.Duration(2000-rand.Intn(200)) * time.Millisecond) //nolint:gosec,gomnd
// FIXME: keepAlives should probably have small random packet len/data as well // FIXME: keepAlives should probably have small random packet len/data as well
// to further obscure them vs. interactive or tunnel data // to further obscure them vs. interactive or tunnel data
// keepAlives must be >=2 bytes, due to processing elsewhere // keepAlives must be >=2 bytes, due to processing elsewhere
@ -1069,15 +1080,15 @@ func main() { //nolint: funlen, gocyclo
} }
} }
go keepAliveWorker() go keepAliveWorker()
//[1]} // [1]}
//=== Session entry (shellMode or copyMode) // === Session entry (shellMode or copyMode)
if shellMode { if shellMode {
//=== (shell) launch tunnels // === (shell) launch tunnels
launchTuns(&conn, remoteHost, tunSpecStr) launchTuns(&conn /*remoteHost,*/, tunSpecStr)
doShellMode(isInteractive, &conn, oldState, rec) doShellMode(isInteractive, &conn, oldState, rec)
} else { } else {
//=== (.. or file copy) // === (.. or file copy)
s, _ := doCopyMode(&conn, pathIsDest, fileArgs, copyQuiet, copyLimitBPS, rec) s, _ := doCopyMode(&conn, pathIsDest, fileArgs, copyQuiet, copyLimitBPS, rec)
rec.SetStatus(s) rec.SetStatus(s)
} }
@ -1093,7 +1104,7 @@ func main() { //nolint: funlen, gocyclo
oldState = nil oldState = nil
} }
//=== Exit // === Exit
exitWithStatus(int(rec.Status())) exitWithStatus(int(rec.Status()))
} }
@ -1128,7 +1139,7 @@ func exitWithStatus(status int) {
defer f.Close() defer f.Close()
runtime.GC() // get up-to-date statistics runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil { if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write memory profile: ", err) log.Fatal("could not write memory profile: ", err) //nolint:gocritic
} }
} }