mirror of
				https://gogs.blitter.com/RLabs/xs
				synced 2024-08-14 10:26:42 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "b2e43f4bad256f24aa2c4ebb02c759c22108ad47" and "0f28d2c023283838d79c5a94be5ff1dba7d332f0" have entirely different histories.
		
	
	
		
			b2e43f4bad
			...
			0f28d2c023
		
	
		
					 4 changed files with 100 additions and 128 deletions
				
			
		|  | @ -25,8 +25,6 @@ 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 | ||||||
|  |  | ||||||
|  | @ -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) //nolint:errcheck | 			conn.WritePacket([]byte(termSzPacket), xsnet.CSOTermSize) | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| 	ch <- syscall.SIGWINCH // Initial resize. | 	ch <- syscall.SIGWINCH // Initial resize. | ||||||
|  |  | ||||||
							
								
								
									
										183
									
								
								xs/xs.go
									
										
									
									
									
								
							
							
						
						
									
										183
									
								
								xs/xs.go
									
										
									
									
									
								
							|  | @ -14,6 +14,7 @@ import ( | ||||||
| 	"flag" | 	"flag" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"log" | 	"log" | ||||||
| 	"math/rand" | 	"math/rand" | ||||||
| 	"os" | 	"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. | // 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" + | ||||||
|  | @ -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 { | 		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 { | ||||||
|  | @ -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 | 			// 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 { //nolint:gomnd | 			if seqPos < 4 { | ||||||
| 				if buf[0] == DeadCharPrefix { | 				if buf[0] == 0x1d { | ||||||
| 					seqPos++ | 					seqPos++ | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
|  | @ -234,7 +223,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 || | ||||||
|  | @ -268,7 +257,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 " //nolint:goconst | 		displayOpts := " -pre " | ||||||
| 		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} | ||||||
| 	} | 	} | ||||||
|  | @ -316,7 +305,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 " //nolint:goconst,nolintlint | 		displayOpts := " -pre " | ||||||
| 		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) | ||||||
|  | @ -366,9 +355,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 | ||||||
|  | @ -401,7 +390,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(CmdExitedEarly) | 			exitStatus = uint32(2) | ||||||
| 		} 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 { | ||||||
|  | @ -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 | 			// 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) //nolint:gomnd | 			r := make([]byte, 4) | ||||||
| 			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 { | ||||||
|  | @ -429,7 +418,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) //nolint:gomnd | 			s := make([]byte, 4) | ||||||
| 			_, 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") && | ||||||
|  | @ -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 | // 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\"/ | ||||||
|  | @ -613,7 +602,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 { //nolint:gomnd | 			if len(fancyArg) < 2 { | ||||||
| 				//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], ":") | ||||||
|  | @ -639,8 +628,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)*/ //nolint:gocritic,nolintlint | 	/*remAddrs, _ := net.LookupHost(remoteHost)*/ | ||||||
| 
 | 
 | ||||||
| 	if tuns == "" { | 	if tuns == "" { | ||||||
| 		return | 		return | ||||||
|  | @ -689,12 +678,12 @@ func main() { //nolint: funlen, gocyclo | ||||||
| 	var ( | 	var ( | ||||||
| 		isInteractive bool | 		isInteractive bool | ||||||
| 		vopt          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 | 		dbg           bool | ||||||
| 		shellMode     bool // true: act as shell, false: file copier | 		shellMode     bool   // if true act as shell, else file copier | ||||||
| 		cipherAlg     string | 		cipherAlg     string //cipher alg | ||||||
| 		hmacAlg       string | 		hmacAlg       string //hmac alg | ||||||
| 		kexAlg        string | 		kexAlg        string //KEX/KEM alg | ||||||
| 		server        string | 		server        string | ||||||
| 		port          uint | 		port          uint | ||||||
| 		cmdStr        string | 		cmdStr        string | ||||||
|  | @ -714,7 +703,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") | ||||||
|  | @ -742,18 +731,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") //nolint:lll | 	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")                                                                                                                                                                                                                            //nolint:gomnd,lll | 	flag.UintVar(&port, "p", 2000, "``port") | ||||||
| 	//nolint:gocritic,nolintlint // flag.StringVar(&authCookie, "a", "", "auth cookie") | 	//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`")  //nolint:gomnd | 	flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") | ||||||
| 	flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max `msecs`") //nolint:gomnd | 	flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max `msecs`") | ||||||
| 	flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max `bytes`")  //nolint:gomnd | 	flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max `bytes`") | ||||||
| 
 | 
 | ||||||
| 	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)) | ||||||
|  | @ -770,7 +759,7 @@ func main() { //nolint: funlen, gocyclo | ||||||
| 		flag.Usage = usageShell | 		flag.Usage = usageShell | ||||||
| 	} else { | 	} else { | ||||||
| 		flag.BoolVar(©Quiet, "q", false, "do not output progress bar during copy") | 		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.Usage = usageCp | ||||||
| 	} | 	} | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
|  | @ -780,7 +769,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) | ||||||
|  | @ -790,19 +779,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) //nolint:gocritic | 			log.Fatal("could not start CPU profile: ", err) | ||||||
| 		} else { | 		} else { | ||||||
| 			defer pprof.StopCPUProfile() | 			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 := | 	remoteUser, remoteHost, tmpPath, pathIsDest, otherArgs := | ||||||
| 		parseNonSwitchArgs(flag.Args()) | 		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 | 	// Set defaults if user doesn't specify user, path or port | ||||||
| 	var uname string | 	var uname string | ||||||
|  | @ -820,7 +809,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 != ""*/ { | ||||||
|  | @ -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 == "" { | 	if flag.NFlag() == 0 && server == "" { | ||||||
| 		flag.Usage() | 		flag.Usage() | ||||||
| 		exitWithStatus(0) | 		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") | 		log.Fatal("incompatible options -- either cmd (-x) or copy ops but not both") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -874,18 +863,18 @@ func main() { //nolint: funlen, gocyclo | ||||||
| 	if dbg { | 	if dbg { | ||||||
| 		log.SetOutput(Log) | 		log.SetOutput(Log) | ||||||
| 	} else { | 	} else { | ||||||
| 		log.SetOutput(io.Discard) | 		log.SetOutput(ioutil.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 := os.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir)) | 		ab, aerr := ioutil.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 += "\n" | 				line = 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:] | ||||||
|  | @ -905,8 +894,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 { //nolint:gomnd | 	if chaffFreqMin < 2 { | ||||||
| 		chaffFreqMin = 2 | 		chaffFreqMin = 2 | ||||||
| 	} | 	} | ||||||
| 	if chaffFreqMax == 0 { | 	if chaffFreqMax == 0 { | ||||||
|  | @ -916,7 +905,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() | ||||||
|  | @ -926,7 +915,7 @@ func main() { //nolint: funlen, gocyclo | ||||||
| 			op = []byte{'A'} | 			op = []byte{'A'} | ||||||
| 			chaffFreqMin = 2 | 			chaffFreqMin = 2 | ||||||
| 			chaffFreqMax = 10 | 			chaffFreqMax = 10 | ||||||
| 		} else if cmdStr == "" { | 		} else if len(cmdStr) == 0 { | ||||||
| 			op = []byte{'s'} | 			op = []byte{'s'} | ||||||
| 			isInteractive = true | 			isInteractive = true | ||||||
| 		} else { | 		} else { | ||||||
|  | @ -947,18 +936,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'} | ||||||
| 			//nolint:gocritic,nolintlint // fmt.Println("client->server copy:", string(copySrc), "->", copyDst) | 			//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'} | ||||||
| 			//nolint:gocritic,nolintlint // fmt.Println("server->client copy:", string(copySrc), "->", copyDst) | 			//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" { | ||||||
|  | @ -967,10 +956,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(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 | 	// 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 | ||||||
|  | @ -978,7 +967,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()) { | ||||||
|  | @ -994,20 +983,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() { //nolint:gomnd | 	loginTimeout := time.AfterFunc(30*time.Second, func() { | ||||||
| 		restoreTermState(oldState) | 		restoreTermState(oldState) | ||||||
| 		fmt.Printf(" .. [login timeout]\n") | 		fmt.Printf(" .. [login timeout]\n") | ||||||
| 		exitWithStatus(xsnet.CSOLoginTimeout) | 		exitWithStatus(xsnet.CSOLoginTimeout) | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	if authCookie == "" { | 	if len(authCookie) == 0 { | ||||||
| 		// 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") | ||||||
|  | @ -1017,43 +1006,43 @@ func main() { //nolint: funlen, gocyclo | ||||||
| 		authCookie = string(ab) | 		authCookie = string(ab) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	//nolint:gocritic,nolintlint // i_ = loginImpatience.Stop() | 	//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(ServerRejectedSecureProposal) | 		rec.SetStatus(254) | ||||||
| 		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())) | ||||||
| 		//nolint:gocritic,nolintlint // log.Fatal(sendErr) | 		//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(ErrReadingAuthReply) | 		rec.SetStatus(255) | ||||||
| 	} 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(GeneralProtocolErr) | 		rec.SetStatus(255) | ||||||
| 	} 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\"/ | ||||||
|  | @ -1063,16 +1052,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,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 | 				// 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 | ||||||
|  | @ -1080,15 +1069,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) | ||||||
| 		} | 		} | ||||||
|  | @ -1104,7 +1093,7 @@ func main() { //nolint: funlen, gocyclo | ||||||
| 		oldState = nil | 		oldState = nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// === Exit | 	//=== Exit | ||||||
| 	exitWithStatus(int(rec.Status())) | 	exitWithStatus(int(rec.Status())) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1139,7 +1128,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) //nolint:gocritic | 			log.Fatal("could not write memory profile: ", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								xsnet/net.go
									
										
									
									
									
								
							
							
						
						
									
										41
									
								
								xsnet/net.go
									
										
									
									
									
								
							|  | @ -1195,7 +1195,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 		var hmacIn [HMAC_CHK_SZ]uint8 | 		var hmacIn [HMAC_CHK_SZ]uint8 | ||||||
| 		var payloadLen uint32 | 		var payloadLen uint32 | ||||||
| 
 | 
 | ||||||
| 		//------------- Read ctrl/status opcode -------------------- |  | ||||||
| 		// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch) | 		// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch) | ||||||
| 		err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp) | 		err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -1216,9 +1215,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 			hc.Close() | 			hc.Close() | ||||||
| 			return 0, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **") | 			return 0, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **") | ||||||
| 		} | 		} | ||||||
| 		//---------------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 		//------------------ Read HMAC len  ------------------------ |  | ||||||
| 		// Read the hmac and payload len first | 		// Read the hmac and payload len first | ||||||
| 		err = binary.Read(*hc.c, binary.BigEndian, &hmacIn) | 		err = binary.Read(*hc.c, binary.BigEndian, &hmacIn) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -1233,9 +1230,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 			logger.LogDebug(etxt) | 			logger.LogDebug(etxt) | ||||||
| 			return 0, errors.New(etxt) | 			return 0, errors.New(etxt) | ||||||
| 		} | 		} | ||||||
| 		//---------------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 		//------------------ Read Payload len  --------------------- |  | ||||||
| 		err = binary.Read(*hc.c, binary.BigEndian, &payloadLen) | 		err = binary.Read(*hc.c, binary.BigEndian, &payloadLen) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if err.Error() == "EOF" { | 			if err.Error() == "EOF" { | ||||||
|  | @ -1249,7 +1244,6 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 			logger.LogDebug(etxt) | 			logger.LogDebug(etxt) | ||||||
| 			return 0, errors.New(etxt) | 			return 0, errors.New(etxt) | ||||||
| 		} | 		} | ||||||
| 		//---------------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 		if payloadLen > MAX_PAYLOAD_LEN { | 		if payloadLen > MAX_PAYLOAD_LEN { | ||||||
| 			logger.LogDebug(fmt.Sprintf("[Insane payloadLen:%v]\n", payloadLen)) | 			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") | 			return 1, errors.New("Insane payloadLen") | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		//-------------------- Read Payload ------------------------ |  | ||||||
| 		var payloadBytes = make([]byte, payloadLen) | 		var payloadBytes = make([]byte, payloadLen) | ||||||
| 		n, err = io.ReadFull(*hc.c, payloadBytes) | 		n, err = io.ReadFull(*hc.c, payloadBytes) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -1272,14 +1265,12 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 			logger.LogDebug(etxt) | 			logger.LogDebug(etxt) | ||||||
| 			return 0, errors.New(etxt) | 			return 0, errors.New(etxt) | ||||||
| 		} | 		} | ||||||
| 		//---------------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 		if hc.logCipherText { | 		if hc.logCipherText { | ||||||
| 			log.Printf("  <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) | 			log.Printf("  <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) | ||||||
| 		} | 		} | ||||||
| 		//fmt.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 | 		hc.rm.Write(payloadBytes) // Calc hmac on received data | ||||||
| 		hTmp := hc.rm.Sum(nil)[0:HMAC_CHK_SZ] | 		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) | 		//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 **")) | 			logger.LogDebug(fmt.Sprintln("** ALERT - detected HMAC mismatch, possible channel tampering **")) | ||||||
| 			_, _ = (*hc.c).Write([]byte{CSOHmacInvalid}) | 			_, _ = (*hc.c).Write([]byte{CSOHmacInvalid}) | ||||||
| 		} | 		} | ||||||
| 		//---------------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 		//------------------- Decrypt Payload ---------------------- |  | ||||||
| 		db := bytes.NewBuffer(payloadBytes[:n]) //copying payloadBytes to db | 		db := bytes.NewBuffer(payloadBytes[:n]) //copying payloadBytes to db | ||||||
| 		// The StreamReader acts like a pipe, decrypting | 		// The StreamReader acts like a pipe, decrypting | ||||||
| 		// whatever is available and forwarding the result | 		// 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 | 		// The caller isn't necessarily reading the full payload so we need | ||||||
| 		// to decrypt to an intermediate buffer, draining it on demand of caller | 		// to decrypt to an intermediate buffer, draining it on demand of caller | ||||||
| 		decryptN, err := rs.Read(payloadBytes) | 		decryptN, err := rs.Read(payloadBytes) | ||||||
| 		//---------------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 		if hc.logPlainText { | 		if hc.logPlainText { | ||||||
| 			log.Printf("  <:ptext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) | 			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) | 			log.Println("xsnet.Read():", err) | ||||||
| 			//panic(err) | 			//panic(err) | ||||||
| 		} else { | 		} else { | ||||||
| 			//------------ Discard Padding --------------------- |  | ||||||
| 			// Padding: Read padSide, padLen, (padding | d) or (d | padding) | 			// Padding: Read padSide, padLen, (padding | d) or (d | padding) | ||||||
| 			padSide := payloadBytes[0] | 			padSide := payloadBytes[0] | ||||||
| 			padLen := payloadBytes[1] | 			padLen := payloadBytes[1] | ||||||
|  | @ -1320,17 +1307,15 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 			} else { | 			} else { | ||||||
| 				payloadBytes = payloadBytes[0 : len(payloadBytes)-int(padLen)] | 				payloadBytes = payloadBytes[0 : len(payloadBytes)-int(padLen)] | ||||||
| 			} | 			} | ||||||
| 			//-------------------------------------------------- |  | ||||||
| 
 | 
 | ||||||
| 			switch ctrlStatOp { | 			// Throw away pkt if it's chaff (ie., caller to Read() won't see this data) | ||||||
| 			case CSOChaff: | 			if ctrlStatOp == CSOChaff { | ||||||
| 				// Throw away pkt if it's chaff (ie., caller to Read() won't see this data) |  | ||||||
| 				log.Printf("[Chaff pkt, discarded (len %d)]\n", decryptN) | 				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) | 				fmt.Sscanf(string(payloadBytes), "%d %d", &hc.Rows, &hc.Cols) | ||||||
| 				log.Printf("[TermSize pkt: rows %v cols %v]\n", hc.Rows, hc.Cols) | 				log.Printf("[TermSize pkt: rows %v cols %v]\n", hc.Rows, hc.Cols) | ||||||
| 				hc.WinCh <- WinSize{hc.Rows, hc.Cols} | 				hc.WinCh <- WinSize{hc.Rows, hc.Cols} | ||||||
| 			case CSOExitStatus: | 			} else if ctrlStatOp == CSOExitStatus { | ||||||
| 				if len(payloadBytes) > 0 { | 				if len(payloadBytes) > 0 { | ||||||
| 					hc.SetStatus(CSOType(binary.BigEndian.Uint32(payloadBytes))) | 					hc.SetStatus(CSOType(binary.BigEndian.Uint32(payloadBytes))) | ||||||
| 				} else { | 				} else { | ||||||
|  | @ -1338,7 +1323,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 					hc.SetStatus(CSETruncCSO) | 					hc.SetStatus(CSETruncCSO) | ||||||
| 				} | 				} | ||||||
| 				hc.Close() | 				hc.Close() | ||||||
| 			case CSOTunSetup: | 			} else if ctrlStatOp == CSOTunSetup { | ||||||
| 				// server side tunnel setup in response to client | 				// server side tunnel setup in response to client | ||||||
| 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				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)) | 					logger.LogDebug(fmt.Sprintf("[Server] Got CSOTunSetup [%d:%d]", lport, rport)) | ||||||
| 				} | 				} | ||||||
| 				(*hc.tuns)[rport].Ctl <- 'd' // Dial() rport | 				(*hc.tuns)[rport].Ctl <- 'd' // Dial() rport | ||||||
| 			case CSOTunSetupAck: | 			} else if ctrlStatOp == CSOTunSetupAck { | ||||||
| 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | ||||||
| 				if _, ok := (*hc.tuns)[rport]; !ok { | 				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)) | 					logger.LogDebug(fmt.Sprintf("[Client] Got CSOTunSetupAck [%d:%d]", lport, rport)) | ||||||
| 				} | 				} | ||||||
| 				(*hc.tuns)[rport].Ctl <- 'a' // Listen() for lport connection | 				(*hc.tuns)[rport].Ctl <- 'a' // Listen() for lport connection | ||||||
| 			case CSOTunRefused: | 			} else if ctrlStatOp == CSOTunRefused { | ||||||
| 				// client side receiving CSOTunRefused means the remote side | 				// client side receiving CSOTunRefused means the remote side | ||||||
| 				// could not dial() rport. So we cannot yet listen() | 				// could not dial() rport. So we cannot yet listen() | ||||||
| 				// for client-side on lport. | 				// for client-side on lport. | ||||||
|  | @ -1373,7 +1358,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 				} else { | 				} else { | ||||||
| 					logger.LogDebug(fmt.Sprintf("[Client] CSOTunRefused on already-closed tun [%d:%d]", lport, rport)) | 					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) | 				// server side's rport has disconnected (server lost) | ||||||
| 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | ||||||
|  | @ -1383,7 +1368,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 				} else { | 				} else { | ||||||
| 					logger.LogDebug(fmt.Sprintf("[Client] CSOTunDisconn on already-closed tun [%d:%d]", lport, rport)) | 					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 | 				// client side's lport has hung up | ||||||
| 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | ||||||
|  | @ -1393,7 +1378,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { | ||||||
| 				} else { | 				} else { | ||||||
| 					logger.LogDebug(fmt.Sprintf("[Server] CSOTunHangup to already-closed tun [%d:%d]", lport, rport)) | 					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]) | 				lport := binary.BigEndian.Uint16(payloadBytes[0:2]) | ||||||
| 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | 				rport := binary.BigEndian.Uint16(payloadBytes[2:4]) | ||||||
| 				//fmt.Printf("[Got CSOTunData: [lport %d:rport %d] data:%v\n", lport, rport, payloadBytes[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 { | 				} else { | ||||||
| 					logger.LogDebug(fmt.Sprintf("[Attempt to write data to closed tun [%d:%d]", lport, rport)) | 					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 | 				// client side has sent keepalive for tunnels -- if client | ||||||
| 				// dies or exits unexpectedly the absence of this will | 				// dies or exits unexpectedly the absence of this will | ||||||
| 				// let the server know to hang up on Dial()ed server rports. | 				// 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 | 					t.KeepAlive = 0 | ||||||
| 					hc.Unlock() | 					hc.Unlock() | ||||||
| 				} | 				} | ||||||
| 			case CSONone: | 			} else if ctrlStatOp == CSONone { | ||||||
| 				hc.dBuf.Write(payloadBytes) | 				hc.dBuf.Write(payloadBytes) | ||||||
| 			default: | 			} else { | ||||||
| 				logger.LogDebug(fmt.Sprintf("[Unknown CSOType:%d]", ctrlStatOp)) | 				logger.LogDebug(fmt.Sprintf("[Unknown CSOType:%d]", ctrlStatOp)) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue