mirror of https://gogs.blitter.com/RLabs/xs
Fixed misuse of iota in xsnet/consts.go that broke channel status opcodes
Cleaned up var declarations and added some greppable comments to show xs setup & flow
This commit is contained in:
parent
1b01ed14f2
commit
eb373ff37b
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
||||||
VERSION := 0.8.23
|
VERSION := 0.8.24
|
||||||
.PHONY: lint vis clean common client server passwd subpkgs install uninstall reinstall
|
.PHONY: lint vis clean common client server passwd subpkgs install uninstall reinstall
|
||||||
|
|
||||||
## Tag version of binaries with build info wrt.
|
## Tag version of binaries with build info wrt.
|
||||||
|
|
91
xs/xs.go
91
xs/xs.go
|
@ -678,31 +678,35 @@ func sendSessionParams(conn io.Writer /* *xsnet.Conn*/, rec *xs.Session) (e erro
|
||||||
|
|
||||||
// TODO: reduce gocyclo
|
// TODO: reduce gocyclo
|
||||||
func main() {
|
func main() {
|
||||||
var vopt bool
|
var (
|
||||||
var gopt bool //login via password, asking server to generate authToken
|
isInteractive bool
|
||||||
var dbg bool
|
vopt bool
|
||||||
var shellMode bool // if true act as shell, else file copier
|
gopt bool //login via password, asking server to generate authToken
|
||||||
var cipherAlg string //cipher alg
|
dbg bool
|
||||||
var hmacAlg string //hmac alg
|
shellMode bool // if true act as shell, else file copier
|
||||||
var kexAlg string //KEX/KEM alg
|
cipherAlg string //cipher alg
|
||||||
var server string
|
hmacAlg string //hmac alg
|
||||||
var port uint
|
kexAlg string //KEX/KEM alg
|
||||||
var cmdStr string
|
server string
|
||||||
var tunSpecStr string // lport1:rport1[,lport2:rport2,...]
|
port uint
|
||||||
|
cmdStr string
|
||||||
|
tunSpecStr string // lport1:rport1[,lport2:rport2,...]
|
||||||
|
|
||||||
var copySrc []byte
|
copySrc []byte
|
||||||
var copyDst string
|
copyDst string
|
||||||
var copyQuiet bool
|
copyQuiet bool
|
||||||
var copyLimitBPS uint
|
copyLimitBPS uint
|
||||||
|
|
||||||
var authCookie string
|
authCookie string
|
||||||
var chaffEnabled bool
|
chaffEnabled bool
|
||||||
var chaffFreqMin uint
|
chaffFreqMin uint
|
||||||
var chaffFreqMax uint
|
chaffFreqMax uint
|
||||||
var chaffBytesMax uint
|
chaffBytesMax uint
|
||||||
|
|
||||||
var op []byte
|
op []byte
|
||||||
isInteractive := false
|
)
|
||||||
|
|
||||||
|
//=== 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")
|
||||||
|
@ -720,6 +724,8 @@ func main() {
|
||||||
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
|
||||||
|
|
||||||
// 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))
|
||||||
if myPath[len(myPath)-1] != "xc" &&
|
if myPath[len(myPath)-1] != "xc" &&
|
||||||
|
@ -745,6 +751,8 @@ func main() {
|
||||||
exitWithStatus(0)
|
exitWithStatus(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== Profiling instrumentation
|
||||||
|
|
||||||
if cpuprofile != "" {
|
if cpuprofile != "" {
|
||||||
f, err := os.Create(cpuprofile)
|
f, err := os.Create(cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -761,6 +769,8 @@ func main() {
|
||||||
go func() { http.ListenAndServe("localhost:6060", nil) }()
|
go func() { http.ListenAndServe("localhost:6060", nil) }()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== 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)
|
//fmt.Println("otherArgs:", otherArgs)
|
||||||
|
@ -781,6 +791,8 @@ func main() {
|
||||||
tmpPath = "."
|
tmpPath = "."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== Copy mode arg and copy src/dest setup
|
||||||
|
|
||||||
var fileArgs string
|
var fileArgs string
|
||||||
if !shellMode /*&& tmpPath != ""*/ {
|
if !shellMode /*&& tmpPath != ""*/ {
|
||||||
// -if pathIsSrc && len(otherArgs) > 1 ERROR
|
// -if pathIsSrc && len(otherArgs) > 1 ERROR
|
||||||
|
@ -812,7 +824,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do some more option consistency checks
|
//=== Do some final option consistency checks
|
||||||
|
|
||||||
//fmt.Println("server finally is:", server)
|
//fmt.Println("server finally is:", server)
|
||||||
if flag.NFlag() == 0 && server == "" {
|
if flag.NFlag() == 0 && server == "" {
|
||||||
|
@ -824,7 +836,6 @@ func main() {
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
|
||||||
// Here we have parsed all options and can now carry out
|
// Here we have parsed all options and can now carry out
|
||||||
// either the shell session or copy operation.
|
// either the shell session or copy operation.
|
||||||
_ = shellMode
|
_ = shellMode
|
||||||
|
@ -837,6 +848,8 @@ func main() {
|
||||||
log.SetOutput(ioutil.Discard)
|
log.SetOutput(ioutil.Discard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== 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() // nolint: gosec
|
u, _ := user.Current() // nolint: gosec
|
||||||
|
@ -858,7 +871,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce some sane min/max vals on chaff flags
|
//=== Enforce some sane min/max vals on chaff flags
|
||||||
if chaffFreqMin < 2 {
|
if chaffFreqMin < 2 {
|
||||||
chaffFreqMin = 2
|
chaffFreqMin = 2
|
||||||
}
|
}
|
||||||
|
@ -869,6 +882,8 @@ func main() {
|
||||||
chaffBytesMax = 64
|
chaffBytesMax = 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== 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()
|
||||||
// as it affects chaffing behaviour. 20180805
|
// as it affects chaffing behaviour. 20180805
|
||||||
|
@ -909,6 +924,8 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== TCP / KCP Dial setup
|
||||||
|
|
||||||
proto := "tcp"
|
proto := "tcp"
|
||||||
if kcpMode != "unused" {
|
if kcpMode != "unused" {
|
||||||
proto = "kcp"
|
proto = "kcp"
|
||||||
|
@ -919,13 +936,15 @@ func main() {
|
||||||
exitWithStatus(3)
|
exitWithStatus(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== 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
|
||||||
// affects shell command used
|
// affects shell command used
|
||||||
var oldState *xs.State
|
var oldState *xs.State
|
||||||
defer conn.Close() // nolint: errcheck
|
defer conn.Close() // nolint: errcheck
|
||||||
|
|
||||||
// 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()) {
|
||||||
|
@ -941,6 +960,8 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== 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.]")
|
||||||
|
@ -967,6 +988,8 @@ func main() {
|
||||||
// Security scrub
|
// Security scrub
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
|
//=== 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)
|
||||||
|
@ -982,17 +1005,21 @@ func main() {
|
||||||
authCookie = "" // nolint: ineffassign
|
authCookie = "" // nolint: ineffassign
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
// Read auth reply from server
|
//=== Login Auth
|
||||||
|
|
||||||
|
//=== 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
|
||||||
fmt.Fprintln(os.Stderr, "Error reading auth reply") // nolint: errcheck
|
fmt.Fprintln(os.Stderr, "Error reading auth reply") // nolint: errcheck
|
||||||
rec.SetStatus(255)
|
rec.SetStatus(255)
|
||||||
} else if authReply[0] == 0 {
|
} else if authReply[0] == 0 {
|
||||||
|
//=== .. or if auth failed
|
||||||
fmt.Fprintln(os.Stderr, rejectUserMsg()) // nolint: errcheck
|
fmt.Fprintln(os.Stderr, rejectUserMsg()) // nolint: errcheck
|
||||||
rec.SetStatus(255)
|
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\"/
|
||||||
|
@ -1002,7 +1029,7 @@ func main() {
|
||||||
defer conn.ShutdownChaff()
|
defer conn.ShutdownChaff()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keepalive for any tunnels that may exist
|
//=== (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
|
||||||
|
@ -1021,10 +1048,13 @@ func main() {
|
||||||
go keepAliveWorker()
|
go keepAliveWorker()
|
||||||
//[1]}
|
//[1]}
|
||||||
|
|
||||||
|
//=== Session entry (shellMode or copyMode)
|
||||||
if shellMode {
|
if shellMode {
|
||||||
|
//=== (shell) launch tunnels
|
||||||
launchTuns(&conn, remoteHost, tunSpecStr)
|
launchTuns(&conn, remoteHost, tunSpecStr)
|
||||||
doShellMode(isInteractive, &conn, oldState, rec)
|
doShellMode(isInteractive, &conn, oldState, rec)
|
||||||
} else { // copyMode
|
} else {
|
||||||
|
//=== (.. or file copy)
|
||||||
s, _ := doCopyMode(&conn, pathIsDest, fileArgs, copyQuiet, copyLimitBPS, rec) // nolint: errcheck,gosec
|
s, _ := doCopyMode(&conn, pathIsDest, fileArgs, copyQuiet, copyLimitBPS, rec) // nolint: errcheck,gosec
|
||||||
rec.SetStatus(s)
|
rec.SetStatus(s)
|
||||||
}
|
}
|
||||||
|
@ -1040,6 +1070,7 @@ func main() {
|
||||||
oldState = nil
|
oldState = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=== Exit
|
||||||
exitWithStatus(int(rec.Status()))
|
exitWithStatus(int(rec.Status()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,10 @@ const (
|
||||||
CSOChaff // Dummy packet, do not pass beyond decryption
|
CSOChaff // Dummy packet, do not pass beyond decryption
|
||||||
|
|
||||||
// Client side errors
|
// Client side errors
|
||||||
CSOLoginTimeout = 16
|
CSOLoginTimeout
|
||||||
|
|
||||||
// Tunnel setup/control/status
|
// Tunnel setup/control/status
|
||||||
CSOTunSetup = 32 // client -> server tunnel setup request (dstport)
|
CSOTunSetup // client -> server tunnel setup request (dstport)
|
||||||
CSOTunSetupAck // server -> client tunnel setup ack
|
CSOTunSetupAck // server -> client tunnel setup ack
|
||||||
CSOTunRefused // server -> client: tunnel rport connection refused
|
CSOTunRefused // server -> client: tunnel rport connection refused
|
||||||
CSOTunData // packet contains tunnel data [rport:data]
|
CSOTunData // packet contains tunnel data [rport:data]
|
||||||
|
|
Loading…
Reference in New Issue