diff --git a/.golangci.yml b/.golangci.yml index a4cad3d..38507bb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,8 +25,6 @@ linters-settings: #- style #- opinionated disabled-checks: - - commentFormatting - - commentedOutCode - dupImport # https://github.com/go-critic/go-critic/issues/845 - ifElseChain - octalLiteral diff --git a/xs/termsize_unix.go b/xs/termsize_unix.go index 112947a..c435d9a 100644 --- a/xs/termsize_unix.go +++ b/xs/termsize_unix.go @@ -31,7 +31,7 @@ func handleTermResizes(conn *xsnet.Conn) { log.Println(err) } termSzPacket := fmt.Sprintf("%d %d", rows, cols) - conn.WritePacket([]byte(termSzPacket), xsnet.CSOTermSize) //nolint:errcheck + conn.WritePacket([]byte(termSzPacket), xsnet.CSOTermSize) } }() ch <- syscall.SIGWINCH // Initial resize. diff --git a/xs/xs.go b/xs/xs.go index 3f8823f..2e142e1 100755 --- a/xs/xs.go +++ b/xs/xs.go @@ -14,6 +14,7 @@ import ( "flag" "fmt" "io" + "io/ioutil" "log" "math/rand" "os" @@ -56,18 +57,6 @@ var ( //////////////////////////////////////////////////// -const ( - CmdExitedEarly = 2 - XSNetDialFailed = 3 - ErrReadingAuthReply = 253 - ServerRejectedSecureProposal = 254 - GeneralProtocolErr = 255 -) - -const ( - DeadCharPrefix = 0x1d -) - // Praise Bob. Do not remove, lest ye lose Slack. const bob = string("\r\n\r\n" + "@@@@@@@^^~~~~~~~~~~~~~~~~~~~~^@@@@@@@@@\r\n" + @@ -165,7 +154,7 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er if rt, ok := dst.(io.ReaderFrom); ok { return rt.ReadFrom(src) } - */ //nolint:gocritic,nolintlint + */ if buf == nil { size := 32 * 1024 if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N { @@ -186,8 +175,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 // interactive shells; here CTRL-]) shall introduce // some special responses or actions on the client side. - if seqPos < 4 { //nolint:gomnd - if buf[0] == DeadCharPrefix { + if seqPos < 4 { + if buf[0] == 0x1d { seqPos++ } } else { @@ -234,7 +223,7 @@ func GetSize() (cols, rows int, err error) { if err != nil { log.Println(err) - cols, rows = 80, 24 // failsafe + cols, rows = 80, 24 //failsafe } else { n, err := fmt.Sscanf(string(out), "%d %d\n", &rows, &cols) if n < 2 || @@ -268,7 +257,7 @@ func buildCmdRemoteToLocal(copyQuiet bool, copyLimitBPS uint, destPath string) ( } else { // TODO: Query remote side for total file/dir size bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d ", copyLimitBPS) - displayOpts := " -pre " //nolint:goconst + displayOpts := " -pre " cmd = xs.GetTool("bash") args = []string{"-c", "pv " + displayOpts + bandwidthInBytesPerSec + "| tar -xz -C " + destPath} } @@ -316,7 +305,7 @@ func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (cap } else { captureStderr = copyQuiet bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d", copyLimitBPS) - displayOpts := " -pre " //nolint:goconst,nolintlint + displayOpts := " -pre " cmd = xs.GetTool("bash") args = []string{"-c", xs.GetTool("tar") + " -cz -f /dev/stdout "} files = strings.TrimSpace(files) @@ -366,9 +355,9 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, var c *exec.Cmd - // os.Clearenv() - // os.Setenv("HOME", u.HomeDir) - // os.Setenv("TERM", "vt102") // TODO: server or client option? + //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 @@ -401,7 +390,7 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, if err != nil { fmt.Println("cmd exited immediately. Cannot get cmd.Wait().ExitStatus()") err = errors.New("cmd exited prematurely") - exitStatus = uint32(CmdExitedEarly) + exitStatus = uint32(2) } else { if err = c.Wait(); err != nil { if exiterr, ok := err.(*exec.ExitError); ok { @@ -421,7 +410,7 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, } // send CSOExitStatus to inform remote (server) end cp is done log.Println("Sending local exitStatus:", exitStatus) - r := make([]byte, 4) //nolint:gomnd + r := make([]byte, 4) binary.BigEndian.PutUint32(r, exitStatus) _, we := conn.WritePacket(r, xsnet.CSOExitStatus) if we != nil { @@ -429,7 +418,7 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, } // Do a final read for remote's exit status - s := make([]byte, 4) //nolint:gomnd + s := make([]byte, 4) _, remErr := conn.Read(s) if remErr != io.EOF && !strings.Contains(remErr.Error(), "use of closed network") && @@ -489,8 +478,8 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool, // doShellMode begins an xs shell session (one-shot command or // interactive). func doShellMode(isInteractive bool, conn *xsnet.Conn, oldState *xs.State, rec *xs.Session) { - // Client reader (from server) goroutine - // Read remote end's stdout + //client reader (from server) goroutine + //Read remote end's stdout wg.Add(1) // #gv:s/label=\"doShellMode\$1\"/label=\"shellRemoteToStdin\"/ @@ -613,7 +602,7 @@ func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, other if strings.Contains(arg, ":") || strings.Contains(arg, "@") { fancyArg := strings.Split(flag.Arg(i), "@") var fancyHostPath []string - if len(fancyArg) < 2 { //nolint:gomnd + if len(fancyArg) < 2 { //TODO: no user specified, use current fancyUser = "[default:getUser]" fancyHostPath = strings.Split(fancyArg[0], ":") @@ -639,8 +628,8 @@ func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, other return fancyUser, fancyHost, fancyPath, isDest, otherArgs } -func launchTuns(conn *xsnet.Conn /*remoteHost string,*/, tuns string) { - /*remAddrs, _ := net.LookupHost(remoteHost)*/ //nolint:gocritic,nolintlint +func launchTuns(conn *xsnet.Conn, remoteHost string, tuns string) { + /*remAddrs, _ := net.LookupHost(remoteHost)*/ if tuns == "" { return @@ -689,12 +678,12 @@ func main() { //nolint: funlen, gocyclo var ( isInteractive bool vopt bool - gopt bool // true: login via password, asking server to generate authToken + gopt bool //login via password, asking server to generate authToken dbg bool - shellMode bool // true: act as shell, false: file copier - cipherAlg string - hmacAlg string - kexAlg string + shellMode bool // if true act as shell, else file copier + cipherAlg string //cipher alg + hmacAlg string //hmac alg + kexAlg string //KEX/KEM alg server string port uint cmdStr string @@ -714,7 +703,7 @@ func main() { //nolint: funlen, gocyclo op []byte ) - // === Common (xs and xc) option parsing + //=== Common (xs and xc) option parsing flag.BoolVar(&vopt, "v", false, "show version") flag.BoolVar(&dbg, "d", false, "debug logging") @@ -742,18 +731,18 @@ func main() { //nolint: funlen, gocyclo KEX_FRODOKEM_1344SHAKE KEX_FRODOKEM_976AES 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") //nolint:lll - flag.UintVar(&port, "p", 2000, "``port") //nolint:gomnd,lll - //nolint:gocritic,nolintlint // flag.StringVar(&authCookie, "a", "", "auth cookie") + 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.UintVar(&port, "p", 2000, "``port") + //flag.StringVar(&authCookie, "a", "", "auth cookie") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") - flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") //nolint:gomnd - flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max `msecs`") //nolint:gomnd - flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max `bytes`") //nolint:gomnd + flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") + flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max `msecs`") + flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max `bytes`") flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu 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) myPath := strings.Split(os.Args[0], string(os.PathSeparator)) @@ -770,7 +759,7 @@ func main() { //nolint: funlen, gocyclo 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") //nolint:gomnd + flag.UintVar(©LimitBPS, "L", 8589934592, "copy max rate in bytes per sec") flag.Usage = usageCp } flag.Parse() @@ -780,7 +769,7 @@ func main() { //nolint: funlen, gocyclo exitWithStatus(0) } - // === Profiling instrumentation + //=== Profiling instrumentation if cpuprofile != "" { f, err := os.Create(cpuprofile) @@ -790,19 +779,19 @@ func main() { //nolint: funlen, gocyclo defer f.Close() fmt.Println("StartCPUProfile()") if err := pprof.StartCPUProfile(f); err != nil { - log.Fatal("could not start CPU profile: ", err) //nolint:gocritic + log.Fatal("could not start CPU profile: ", err) } else { defer pprof.StopCPUProfile() } - go func() { http.ListenAndServe("localhost:6060", nil) }() //nolint:errcheck,gosec + go func() { http.ListenAndServe("localhost:6060", nil) }() } - // === 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 := parseNonSwitchArgs(flag.Args()) - //nolint:gocritic,nolintlint // fmt.Println("otherArgs:", otherArgs) + //fmt.Println("otherArgs:", otherArgs) // Set defaults if user doesn't specify user, path or port var uname string @@ -820,7 +809,7 @@ func main() { //nolint: funlen, gocyclo tmpPath = "." } - // === Copy mode arg and copy src/dest setup + //=== Copy mode arg and copy src/dest setup var fileArgs string if !shellMode /*&& tmpPath != ""*/ { @@ -853,15 +842,15 @@ func main() { //nolint: funlen, gocyclo } } - // === Do some final option consistency checks + //=== Do some final option consistency checks - //nolint:gocritic,nolintlint // fmt.Println("server finally is:", server) + //fmt.Println("server finally is:", server) if flag.NFlag() == 0 && server == "" { flag.Usage() exitWithStatus(0) } - if cmdStr != "" && (len(copySrc) != 0 || copyDst != "") { + if len(cmdStr) != 0 && (len(copySrc) != 0 || len(copyDst) != 0) { log.Fatal("incompatible options -- either cmd (-x) or copy ops but not both") } @@ -874,18 +863,18 @@ func main() { //nolint: funlen, gocyclo if dbg { log.SetOutput(Log) } else { - log.SetOutput(io.Discard) + log.SetOutput(ioutil.Discard) } - // === Auth token fetch for login + //=== Auth token fetch for login if !gopt { // See if we can log in via an auth token u, _ := user.Current() - ab, aerr := os.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir)) + ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir)) if aerr == nil { for _, line := range strings.Split(string(ab), "\n") { - line += "\n" + line = line + "\n" idx := strings.Index(line, remoteHost+":"+uname) if idx >= 0 { line = line[idx:] @@ -905,8 +894,8 @@ func main() { //nolint: funlen, gocyclo } runtime.GC() - // === Enforce some sane min/max vals on chaff flags - if chaffFreqMin < 2 { //nolint:gomnd + //=== Enforce some sane min/max vals on chaff flags + if chaffFreqMin < 2 { chaffFreqMin = 2 } if chaffFreqMax == 0 { @@ -916,7 +905,7 @@ func main() { //nolint: funlen, gocyclo chaffBytesMax = 64 } - // === Shell vs. Copy mode chaff and cmd setup + //=== Shell vs. Copy mode chaff and cmd setup if shellMode { // We must make the decision about interactivity before Dial() @@ -926,7 +915,7 @@ func main() { //nolint: funlen, gocyclo op = []byte{'A'} chaffFreqMin = 2 chaffFreqMax = 10 - } else if cmdStr == "" { + } else if len(cmdStr) == 0 { op = []byte{'s'} isInteractive = true } else { @@ -947,18 +936,18 @@ func main() { //nolint: funlen, gocyclo // client->server file copy // src file list is in copySrc op = []byte{'D'} - //nolint:gocritic,nolintlint // fmt.Println("client->server copy:", string(copySrc), "->", copyDst) + //fmt.Println("client->server copy:", string(copySrc), "->", copyDst) cmdStr = copyDst } else { // server->client file copy // remote src file(s) in copyDsr op = []byte{'S'} - //nolint:gocritic,nolintlint // fmt.Println("server->client copy:", string(copySrc), "->", copyDst) + //fmt.Println("server->client copy:", string(copySrc), "->", copyDst) cmdStr = string(copySrc) } } - // === TCP / KCP Dial setup + //=== TCP / KCP Dial setup proto := "tcp" if kcpMode != "unused" { @@ -967,10 +956,10 @@ func main() { //nolint: funlen, gocyclo conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode) if err != nil { fmt.Println(err) - exitWithStatus(XSNetDialFailed) + exitWithStatus(3) } - // === 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 // TODO: send flag to server side indicating this @@ -978,7 +967,7 @@ func main() { //nolint: funlen, gocyclo var oldState *xs.State 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 isatty.IsTerminal(os.Stdin.Fd()) { @@ -994,20 +983,20 @@ func main() { //nolint: funlen, gocyclo } } - // === Login phase + //=== Login phase // Start login timeout here and disconnect if user/pass phase stalls - // iloginImpatience := time.AfterFunc(20*time.Second, func() { - // i fmt.Printf(" .. [you still there? Waiting for a password.]") - // i}) - loginTimeout := time.AfterFunc(30*time.Second, func() { //nolint:gomnd + //iloginImpatience := time.AfterFunc(20*time.Second, func() { + //i fmt.Printf(" .. [you still there? Waiting for a password.]") + //i}) + loginTimeout := time.AfterFunc(30*time.Second, func() { restoreTermState(oldState) fmt.Printf(" .. [login timeout]\n") exitWithStatus(xsnet.CSOLoginTimeout) }) - if authCookie == "" { - // No auth token, prompt for password + if len(authCookie) == 0 { + //No auth token, prompt for password fmt.Printf("Gimme cookie:") ab, e := xs.ReadPassword(os.Stdin.Fd()) fmt.Printf("\r\n") @@ -1017,43 +1006,43 @@ func main() { //nolint: funlen, gocyclo authCookie = string(ab) } - //nolint:gocritic,nolintlint // i_ = loginImpatience.Stop() + //i_ = loginImpatience.Stop() _ = loginTimeout.Stop() // Security scrub runtime.GC() - // === Session param and TERM setup + //=== Session param and TERM setup // 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) sendErr := sendSessionParams(&conn, rec) if sendErr != nil { restoreTermState(oldState) - rec.SetStatus(ServerRejectedSecureProposal) + rec.SetStatus(254) fmt.Fprintln(os.Stderr, "Error: server rejected secure proposal params or login timed out") exitWithStatus(int(rec.Status())) - //nolint:gocritic,nolintlint // log.Fatal(sendErr) + //log.Fatal(sendErr) } - // Security scrub + //Security scrub authCookie = "" //nolint: ineffassign 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 _, err = conn.Read(authReply) if err != nil { - // === Exit if auth reply not received + //=== Exit if auth reply not received fmt.Fprintln(os.Stderr, "Error reading auth reply") - rec.SetStatus(ErrReadingAuthReply) + rec.SetStatus(255) } else if authReply[0] == 0 { - // === .. or if auth failed + //=== .. or if auth failed fmt.Fprintln(os.Stderr, rejectUserMsg()) - rec.SetStatus(GeneralProtocolErr) + rec.SetStatus(255) } else { - // === Set up chaffing to server + //=== Set up chaffing to server conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing if chaffEnabled { // #gv:s/label=\"main\$2\"/label=\"deferCloseChaff\"/ @@ -1063,16 +1052,16 @@ func main() { //nolint: funlen, gocyclo defer conn.ShutdownChaff() } - // === (goroutine) Start keepAliveWorker for tunnels + //=== (goroutine) Start keepAliveWorker for tunnels // #gv:s/label=\"main\$1\"/label=\"tunKeepAlive\"/ // TODO:.gv:main:1:tunKeepAlive - // [1]: better to always send tunnel keepAlives even if client didn't specify - // any, to prevent listeners from knowing this. - // [1] if tunSpecStr != "" { + //[1]: better to always send tunnel keepAlives even if client didn't specify + // any, to prevent listeners from knowing this. + //[1] if tunSpecStr != "" { keepAliveWorker := func() { for { // 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,gomnd + time.Sleep(time.Duration(2000-rand.Intn(200)) * time.Millisecond) //nolint:gosec // FIXME: keepAlives should probably have small random packet len/data as well // to further obscure them vs. interactive or tunnel data // keepAlives must be >=2 bytes, due to processing elsewhere @@ -1080,15 +1069,15 @@ func main() { //nolint: funlen, gocyclo } } go keepAliveWorker() - // [1]} + //[1]} - // === Session entry (shellMode or copyMode) + //=== Session entry (shellMode or copyMode) if shellMode { - // === (shell) launch tunnels - launchTuns(&conn /*remoteHost,*/, tunSpecStr) + //=== (shell) launch tunnels + launchTuns(&conn, remoteHost, tunSpecStr) doShellMode(isInteractive, &conn, oldState, rec) } else { - // === (.. or file copy) + //=== (.. or file copy) s, _ := doCopyMode(&conn, pathIsDest, fileArgs, copyQuiet, copyLimitBPS, rec) rec.SetStatus(s) } @@ -1104,7 +1093,7 @@ func main() { //nolint: funlen, gocyclo oldState = nil } - // === Exit + //=== Exit exitWithStatus(int(rec.Status())) } @@ -1139,7 +1128,7 @@ func exitWithStatus(status int) { defer f.Close() runtime.GC() // get up-to-date statistics if err := pprof.WriteHeapProfile(f); err != nil { - log.Fatal("could not write memory profile: ", err) //nolint:gocritic + log.Fatal("could not write memory profile: ", err) } } diff --git a/xsnet/net.go b/xsnet/net.go index 131c1cf..bfb002f 100644 --- a/xsnet/net.go +++ b/xsnet/net.go @@ -1195,7 +1195,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { var hmacIn [HMAC_CHK_SZ]uint8 var payloadLen uint32 - //------------- Read ctrl/status opcode -------------------- // Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch) err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp) if err != nil { @@ -1216,9 +1215,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { hc.Close() return 0, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **") } - //---------------------------------------------------------- - //------------------ Read HMAC len ------------------------ // Read the hmac and payload len first err = binary.Read(*hc.c, binary.BigEndian, &hmacIn) if err != nil { @@ -1233,9 +1230,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { logger.LogDebug(etxt) return 0, errors.New(etxt) } - //---------------------------------------------------------- - //------------------ Read Payload len --------------------- err = binary.Read(*hc.c, binary.BigEndian, &payloadLen) if err != nil { if err.Error() == "EOF" { @@ -1249,7 +1244,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { logger.LogDebug(etxt) return 0, errors.New(etxt) } - //---------------------------------------------------------- if payloadLen > MAX_PAYLOAD_LEN { logger.LogDebug(fmt.Sprintf("[Insane payloadLen:%v]\n", payloadLen)) @@ -1257,7 +1251,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { return 1, errors.New("Insane payloadLen") } - //-------------------- Read Payload ------------------------ var payloadBytes = make([]byte, payloadLen) n, err = io.ReadFull(*hc.c, payloadBytes) if err != nil { @@ -1272,14 +1265,12 @@ func (hc Conn) Read(b []byte) (n int, err error) { logger.LogDebug(etxt) return 0, errors.New(etxt) } - //---------------------------------------------------------- if hc.logCipherText { log.Printf(" <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) } //fmt.Printf(" <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) - //---------------- Verify Payload via HMAC ----------------- hc.rm.Write(payloadBytes) // Calc hmac on received data hTmp := hc.rm.Sum(nil)[0:HMAC_CHK_SZ] //log.Printf("<%04x) HMAC:(i)%s (c)%02x\r\n", decryptN, hex.EncodeToString([]byte(hmacIn[0:])), hTmp) @@ -1289,9 +1280,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { logger.LogDebug(fmt.Sprintln("** ALERT - detected HMAC mismatch, possible channel tampering **")) _, _ = (*hc.c).Write([]byte{CSOHmacInvalid}) } - //---------------------------------------------------------- - //------------------- Decrypt Payload ---------------------- db := bytes.NewBuffer(payloadBytes[:n]) //copying payloadBytes to db // The StreamReader acts like a pipe, decrypting // whatever is available and forwarding the result @@ -1300,7 +1289,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { // The caller isn't necessarily reading the full payload so we need // to decrypt to an intermediate buffer, draining it on demand of caller decryptN, err := rs.Read(payloadBytes) - //---------------------------------------------------------- if hc.logPlainText { log.Printf(" <:ptext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) @@ -1309,7 +1297,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { log.Println("xsnet.Read():", err) //panic(err) } else { - //------------ Discard Padding --------------------- // Padding: Read padSide, padLen, (padding | d) or (d | padding) padSide := payloadBytes[0] padLen := payloadBytes[1] @@ -1320,17 +1307,15 @@ func (hc Conn) Read(b []byte) (n int, err error) { } else { payloadBytes = payloadBytes[0 : len(payloadBytes)-int(padLen)] } - //-------------------------------------------------- - switch ctrlStatOp { - case CSOChaff: - // Throw away pkt if it's chaff (ie., caller to Read() won't see this data) + // Throw away pkt if it's chaff (ie., caller to Read() won't see this data) + if ctrlStatOp == CSOChaff { log.Printf("[Chaff pkt, discarded (len %d)]\n", decryptN) - case CSOTermSize: + } else if ctrlStatOp == CSOTermSize { fmt.Sscanf(string(payloadBytes), "%d %d", &hc.Rows, &hc.Cols) log.Printf("[TermSize pkt: rows %v cols %v]\n", hc.Rows, hc.Cols) hc.WinCh <- WinSize{hc.Rows, hc.Cols} - case CSOExitStatus: + } else if ctrlStatOp == CSOExitStatus { if len(payloadBytes) > 0 { hc.SetStatus(CSOType(binary.BigEndian.Uint32(payloadBytes))) } else { @@ -1338,7 +1323,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { hc.SetStatus(CSETruncCSO) } hc.Close() - case CSOTunSetup: + } else if ctrlStatOp == CSOTunSetup { // server side tunnel setup in response to client lport := binary.BigEndian.Uint16(payloadBytes[0:2]) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) @@ -1350,7 +1335,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { logger.LogDebug(fmt.Sprintf("[Server] Got CSOTunSetup [%d:%d]", lport, rport)) } (*hc.tuns)[rport].Ctl <- 'd' // Dial() rport - case CSOTunSetupAck: + } else if ctrlStatOp == CSOTunSetupAck { lport := binary.BigEndian.Uint16(payloadBytes[0:2]) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) if _, ok := (*hc.tuns)[rport]; !ok { @@ -1361,7 +1346,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { logger.LogDebug(fmt.Sprintf("[Client] Got CSOTunSetupAck [%d:%d]", lport, rport)) } (*hc.tuns)[rport].Ctl <- 'a' // Listen() for lport connection - case CSOTunRefused: + } else if ctrlStatOp == CSOTunRefused { // client side receiving CSOTunRefused means the remote side // could not dial() rport. So we cannot yet listen() // for client-side on lport. @@ -1373,7 +1358,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { } else { logger.LogDebug(fmt.Sprintf("[Client] CSOTunRefused on already-closed tun [%d:%d]", lport, rport)) } - case CSOTunDisconn: + } else if ctrlStatOp == CSOTunDisconn { // server side's rport has disconnected (server lost) lport := binary.BigEndian.Uint16(payloadBytes[0:2]) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) @@ -1383,7 +1368,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { } else { logger.LogDebug(fmt.Sprintf("[Client] CSOTunDisconn on already-closed tun [%d:%d]", lport, rport)) } - case CSOTunHangup: + } else if ctrlStatOp == CSOTunHangup { // client side's lport has hung up lport := binary.BigEndian.Uint16(payloadBytes[0:2]) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) @@ -1393,7 +1378,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { } else { logger.LogDebug(fmt.Sprintf("[Server] CSOTunHangup to already-closed tun [%d:%d]", lport, rport)) } - case CSOTunData: + } else if ctrlStatOp == CSOTunData { lport := binary.BigEndian.Uint16(payloadBytes[0:2]) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) //fmt.Printf("[Got CSOTunData: [lport %d:rport %d] data:%v\n", lport, rport, payloadBytes[4:]) @@ -1406,7 +1391,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { } else { logger.LogDebug(fmt.Sprintf("[Attempt to write data to closed tun [%d:%d]", lport, rport)) } - case CSOTunKeepAlive: + } else if ctrlStatOp == CSOTunKeepAlive { // client side has sent keepalive for tunnels -- if client // dies or exits unexpectedly the absence of this will // let the server know to hang up on Dial()ed server rports. @@ -1417,9 +1402,9 @@ func (hc Conn) Read(b []byte) (n int, err error) { t.KeepAlive = 0 hc.Unlock() } - case CSONone: + } else if ctrlStatOp == CSONone { hc.dBuf.Write(payloadBytes) - default: + } else { logger.LogDebug(fmt.Sprintf("[Unknown CSOType:%d]", ctrlStatOp)) } }