mirror of
https://gogs.blitter.com/RLabs/xs
synced 2024-08-14 10:26:42 +00:00
Compare commits
37 commits
Author | SHA1 | Date | |
---|---|---|---|
|
12409319e7 | ||
|
bfcd097a14 | ||
|
136f37e209 | ||
|
ec9b4fe2f4 | ||
|
aa33a3b8a0 | ||
|
7e4aeba93a | ||
|
91bb0778b2 | ||
|
952279a108 | ||
|
dbaa8b5b62 | ||
|
77c9b8654f | ||
|
e42645a2b3 | ||
|
057a3c01c7 | ||
|
540cb8ff3a | ||
|
ae67ee6201 | ||
|
8827d67cc6 | ||
|
17d7bc01ef | ||
|
89ad0e0998 | ||
|
713f44086a | ||
|
08cccb6929 | ||
|
6212119621 | ||
|
faf8769ac4 | ||
|
32b669192b | ||
|
e82d968381 | ||
|
032baf63d6 | ||
|
c569a5a3c9 | ||
|
36799ba9e7 | ||
|
f0dc681a4c | ||
|
871f9a200c | ||
|
908a1bcda2 | ||
|
39a8bd2f03 | ||
|
9244cc9785 | ||
|
d0f8751b2b | ||
|
a3d8543816 | ||
|
bcea6d713f | ||
|
580053adbd | ||
|
74be6173b6 | ||
|
119c039b91 |
14 changed files with 459 additions and 354 deletions
6
Makefile
6
Makefile
|
@ -1,7 +1,7 @@
|
||||||
VERSION := 0.9.5.4
|
VERSION := 0.9.11
|
||||||
.PHONY: lint vis clean common client server passwd\
|
.PHONY: lint vis clean common client server passwd\
|
||||||
subpkgs install uninstall reinstall scc
|
subpkgs install uninstall reinstall scc
|
||||||
|
|
||||||
## Tag version of binaries with build info wrt.
|
## Tag version of binaries with build info wrt.
|
||||||
## GO111MODULE(=on) and vendor/ setup vs. $GOPATH pkg builds
|
## GO111MODULE(=on) and vendor/ setup vs. $GOPATH pkg builds
|
||||||
############################################################
|
############################################################
|
||||||
|
@ -73,7 +73,7 @@ tools:
|
||||||
|
|
||||||
common:
|
common:
|
||||||
$(GO) build .
|
$(GO) build .
|
||||||
go install .
|
go install -a .
|
||||||
|
|
||||||
|
|
||||||
client: common
|
client: common
|
||||||
|
|
24
README.md
24
README.md
|
@ -44,10 +44,12 @@ Currently supported session algorithms:
|
||||||
* Blowfish-64
|
* Blowfish-64
|
||||||
* CryptMTv1 (64bit) (https://eprint.iacr.org/2005/165.pdf)
|
* CryptMTv1 (64bit) (https://eprint.iacr.org/2005/165.pdf)
|
||||||
* ChaCha20 (https://github.com/aead/chacha20)
|
* ChaCha20 (https://github.com/aead/chacha20)
|
||||||
|
* HOPSCOTCH (https://gogs.blitter.com/Russtopia/hopscotch)
|
||||||
|
|
||||||
[HMAC]
|
[HMAC]
|
||||||
* HMAC-SHA256
|
* HMAC-SHA256
|
||||||
* HMAC-SHA512
|
* HMAC-SHA512
|
||||||
|
* WHIRLPOOL
|
||||||
|
|
||||||
***
|
***
|
||||||
**A Note on 'cryptographic agility'**
|
**A Note on 'cryptographic agility'**
|
||||||
|
@ -92,18 +94,6 @@ KYBER IND-CCA-2 KEM
|
||||||
|
|
||||||
As of this time (Oct 2018) Kyber is one of the candidate algorithms submitted to the [NIST post-quantum cryptography project](https://csrc.nist.gov/Projects/Post-Quantum-Cryptography). The authors recommend using it in "... so-called hybrid mode in combination with established "pre-quantum" security; for example in combination with elliptic-curve Diffie-Hellman." THIS PROJECT DOES NOT DO THIS (in case you didn't notice yet, THIS PROJECT IS EXPERIMENTAL.)
|
As of this time (Oct 2018) Kyber is one of the candidate algorithms submitted to the [NIST post-quantum cryptography project](https://csrc.nist.gov/Projects/Post-Quantum-Cryptography). The authors recommend using it in "... so-called hybrid mode in combination with established "pre-quantum" security; for example in combination with elliptic-curve Diffie-Hellman." THIS PROJECT DOES NOT DO THIS (in case you didn't notice yet, THIS PROJECT IS EXPERIMENTAL.)
|
||||||
|
|
||||||
### Dependencies:
|
|
||||||
|
|
||||||
* Recent version of go (tested, at various times, with go-1.9 to go-1.12.4)
|
|
||||||
* [github.com/mattn/go-isatty](http://github.com/mattn/go-isatty) //terminal tty detection
|
|
||||||
* [github.com/kr/pty](http://github.com/kr/pty) //unix pty control (server pty connections)
|
|
||||||
* [github.com/jameskeane/bcrypt](http://github.com/jameskeane/bcrypt) //password storage/auth
|
|
||||||
* [blitter.com/go/goutmp](https://gogs.blitter.com/RLabs/goutmp) // wtmp/lastlog C bindings for user accounting
|
|
||||||
* [https://gitlab.com/yawning/kyber](https://gogs.blitter.com/RLabs/kyber) // golang Kyber KEM
|
|
||||||
* [https://gitlab.com/yawning/kyber](https://gogs.blitter.com/RLabs/newhope) // golang NEWHOPE,NEWHOPE-SIMPLE KEX
|
|
||||||
* [blitter.com/go/mtwist](https://gogs.blitter.com/RLabs/mtwist) // 64-bit Mersenne Twister PRNG
|
|
||||||
* [blitter.com/go/cryptmt](https://gogs.blitter.com/RLabs/cryptmt) // CryptMTv1 stream cipher
|
|
||||||
|
|
||||||
|
|
||||||
### Installing
|
### Installing
|
||||||
|
|
||||||
|
@ -197,15 +187,17 @@ or is interrupted.
|
||||||
### Setting up an 'authtoken' for scripted (password-free) logins
|
### Setting up an 'authtoken' for scripted (password-free) logins
|
||||||
|
|
||||||
Use the -g option of xs to request a token from the remote server, which will return a
|
Use the -g option of xs to request a token from the remote server, which will return a
|
||||||
hostname:token string. Place this string into $HOME/.xs_id to allow logins without
|
hostname:token string. Place this string into $HOME/.config/xs/.xs_id to allow logins without
|
||||||
entering a password (obviously, $HOME/.xs_id on both server and client for the user
|
entering a password (obviously, $HOME/.config/xs/.xs_id on both server and client for the user
|
||||||
should *not* be world-readable.)
|
should *not* be world-readable.)
|
||||||
|
|
||||||
```
|
```
|
||||||
$ xs -g user@host.net >~/.xs_id
|
$ xs -g user@host.net >>~/.config/xs/.xs_id
|
||||||
```
|
```
|
||||||
[enter password blindly, authtoken entry will be stored in ~/.xs_id]
|
[enter password blindly, authtoken entry will be stored in ~/.config/xs/.xs_id]
|
||||||
|
|
||||||
|
NOTE you may need to remove older entries for the same host if this is not the first time you have added
|
||||||
|
it to your .xs_id file.
|
||||||
|
|
||||||
### File Copying using xc
|
### File Copying using xc
|
||||||
|
|
||||||
|
|
9
auth.go
9
auth.go
|
@ -23,6 +23,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"blitter.com/go/xs/xsnet"
|
||||||
"github.com/jameskeane/bcrypt"
|
"github.com/jameskeane/bcrypt"
|
||||||
passlib "gopkg.in/hlandau/passlib.v1"
|
passlib "gopkg.in/hlandau/passlib.v1"
|
||||||
)
|
)
|
||||||
|
@ -52,7 +53,7 @@ func VerifyPass(ctx *AuthCtx, user, password string) (bool, error) {
|
||||||
} else if runtime.GOOS == "freebsd" {
|
} else if runtime.GOOS == "freebsd" {
|
||||||
pwFileName = "/etc/master.passwd"
|
pwFileName = "/etc/master.passwd"
|
||||||
} else {
|
} else {
|
||||||
pwFileName = "unsupported"
|
return false, errors.New("Unsupported platform")
|
||||||
}
|
}
|
||||||
pwFileData, e := ctx.reader(pwFileName)
|
pwFileData, e := ctx.reader(pwFileName)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
@ -154,7 +155,7 @@ func AuthUserByPasswd(ctx *AuthCtx, username string, auth string, fname string)
|
||||||
// ------------- End xs-local passwd auth routine(s) -----------
|
// ------------- End xs-local passwd auth routine(s) -----------
|
||||||
|
|
||||||
// AuthUserByToken checks user login information against an auth token.
|
// AuthUserByToken checks user login information against an auth token.
|
||||||
// Auth tokens are stored in each user's $HOME/.xs_id and are requested
|
// Auth tokens are stored in each user's $HOME/.config/xs/.xs_id and are requested
|
||||||
// via the -g option.
|
// via the -g option.
|
||||||
// The function also check system /etc/passwd to cross-check the user
|
// The function also check system /etc/passwd to cross-check the user
|
||||||
// actually exists.
|
// actually exists.
|
||||||
|
@ -172,9 +173,9 @@ func AuthUserByToken(ctx *AuthCtx, username string, connhostname string, auth st
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
b, e := ctx.reader(fmt.Sprintf("%s/.xs_id", u.HomeDir))
|
b, e := ctx.reader(fmt.Sprintf("%s/%s", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Printf("INFO: Cannot read %s/.xs_id\n", u.HomeDir)
|
log.Printf("INFO: Cannot read %s/%s\n", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
export GOPATH="${HOME}/go"
|
export GOPATH="${HOME}/go"
|
||||||
export PATH=/usr/local/bin:/usr/bin:/usr/lib/ccache/bin:/bin:$GOPATH/bin
|
export PATH=/usr/local/bin:/usr/bin:/usr/lib/ccache/bin:/bin:$GOPATH/bin
|
||||||
unset GO111MODULE
|
unset GO111MODULE
|
||||||
export GOPROXY="direct"
|
#export GOPROXY="direct"
|
||||||
#!# GOCACHE will be phased out in v1.12. [github.com/golang/go/issues/26809]
|
#!# GOCACHE will be phased out in v1.12. [github.com/golang/go/issues/26809]
|
||||||
#!export GOCACHE="${HOME}/.cache/go-build"
|
#!export GOCACHE="${HOME}/.cache/go-build"
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ echo "Building most recent push on branch $branch"
|
||||||
git checkout "$branch"
|
git checkout "$branch"
|
||||||
ls
|
ls
|
||||||
|
|
||||||
|
go mod init
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
############
|
############
|
||||||
stage "Build"
|
stage "Build"
|
||||||
############
|
############
|
||||||
|
@ -46,12 +49,12 @@ go test -v .
|
||||||
############
|
############
|
||||||
stage "Test(Authtoken)"
|
stage "Test(Authtoken)"
|
||||||
############
|
############
|
||||||
if [ -f ~/.xs_id ]; then
|
if [ -f ~/.config/xs/.xs_id ]; then
|
||||||
echo "Clearing test user $USER ~/.xs_id file ..."
|
echo "Clearing test user $USER .xs_id file ..."
|
||||||
mv ~/.xs_id ~/.xs_id.bak
|
mv ~/.config/xs/.xs_id ~/.config/xs/.xs_id.bak
|
||||||
fi
|
fi
|
||||||
echo "Setting dummy authtoken in ~/.xs_id ..."
|
echo "Setting dummy authtoken in .xs_id ..."
|
||||||
echo "localhost:${USER}:asdfasdfasdf" >~/.xs_id
|
echo "localhost:${USER}:asdfasdfasdf" >~/.config/xs/.xs_id
|
||||||
echo "Performing remote command on @localhost via authtoken login ..."
|
echo "Performing remote command on @localhost via authtoken login ..."
|
||||||
tokentest=$(timeout 10 xs -x "echo -n FOO" @localhost)
|
tokentest=$(timeout 10 xs -x "echo -n FOO" @localhost)
|
||||||
if [ "${tokentest}" != "FOO" ]; then
|
if [ "${tokentest}" != "FOO" ]; then
|
||||||
|
@ -91,9 +94,9 @@ stage "Test(xc C->S)"
|
||||||
############
|
############
|
||||||
echo "TODO ..."
|
echo "TODO ..."
|
||||||
|
|
||||||
if [ -f ~/.xs_id.bak ]; then
|
if [ -f ~/.config/xs/.xs_id.bak ]; then
|
||||||
echo "Restoring test user $USER ~/.xs_id file ..."
|
echo "Restoring test user $USER .xs_id file ..."
|
||||||
mv ~/.xs_id.bak ~/.xs_id
|
mv ~/.config/xs/.xs_id.bak ~/.config/xs/.xs_id
|
||||||
fi
|
fi
|
||||||
|
|
||||||
############
|
############
|
||||||
|
|
38
go.mod
38
go.mod
|
@ -1,38 +0,0 @@
|
||||||
module blitter.com/go/xs
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require (
|
|
||||||
blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c
|
|
||||||
blitter.com/go/cryptmt v1.0.2
|
|
||||||
blitter.com/go/goutmp v1.0.6
|
|
||||||
blitter.com/go/groestl v0.0.0-20220410000905-c4decbf31d64
|
|
||||||
blitter.com/go/herradurakex v1.0.0
|
|
||||||
blitter.com/go/hopscotch v0.1.1
|
|
||||||
blitter.com/go/kyber v0.0.0-20200130200857-6f2021cb88d9
|
|
||||||
blitter.com/go/mtwist v1.0.1
|
|
||||||
blitter.com/go/newhope v0.0.0-20200130200750-192fc08a8aae
|
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
|
|
||||||
github.com/creack/pty v1.1.18
|
|
||||||
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5
|
|
||||||
github.com/klauspost/reedsolomon v1.11.8
|
|
||||||
github.com/kuking/go-frodokem v1.0.2
|
|
||||||
github.com/mattn/go-isatty v0.0.19
|
|
||||||
github.com/pkg/errors v0.9.1
|
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161
|
|
||||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b
|
|
||||||
github.com/tjfoc/gmsm v1.4.1
|
|
||||||
github.com/xtaci/kcp-go v5.4.20+incompatible
|
|
||||||
golang.org/x/crypto v0.13.0
|
|
||||||
golang.org/x/net v0.15.0
|
|
||||||
golang.org/x/sys v0.12.0
|
|
||||||
gopkg.in/hlandau/easymetric.v1 v1.0.0
|
|
||||||
gopkg.in/hlandau/measurable.v1 v1.0.1
|
|
||||||
gopkg.in/hlandau/passlib.v1 v1.0.11
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
|
|
||||||
golang.org/x/text v0.13.0 // indirect
|
|
||||||
)
|
|
145
go.sum
145
go.sum
|
@ -1,145 +0,0 @@
|
||||||
blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c h1:LcnFFg6MCIJHf26P7eOUST45fNLHJI5erq0gWZaDLCo=
|
|
||||||
blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c/go.mod h1:EMJtRcf22WCtHGiXCw+NB/Sb/PYcXtUgUql6LDEwyXo=
|
|
||||||
blitter.com/go/cryptmt v1.0.2 h1:ZcLhQk7onUssXyQwG3GdXDXctCVnNL+b7aFuvwOdKXc=
|
|
||||||
blitter.com/go/cryptmt v1.0.2/go.mod h1:tdME2J3O4agaDAYIYNQzzuB28yVGnPSMmV3a/ucSU84=
|
|
||||||
blitter.com/go/goutmp v1.0.6 h1:jRKRw2WalVBza4T50etAfbvT2xp9G5uykIHTvyB5r0k=
|
|
||||||
blitter.com/go/goutmp v1.0.6/go.mod h1:DnK/uLBu1/1yLFiuVlmwvWErzAWVp+pDv7t6ZaQRLNc=
|
|
||||||
blitter.com/go/groestl v0.0.0-20220410000905-c4decbf31d64 h1:SH6cZ4JiOTmWGeVd5hCgt8gsMvfPPHWpEwNdxfsBugM=
|
|
||||||
blitter.com/go/groestl v0.0.0-20220410000905-c4decbf31d64/go.mod h1:YMdIR/gCtFwU/a09jyWAwUu2J9CQejUFwkfD+PyVg+4=
|
|
||||||
blitter.com/go/herradurakex v1.0.0 h1:6XaxY+JLT1HUWPF0gYJnjX3pVjrw4YhYZEzZ1U0wkyc=
|
|
||||||
blitter.com/go/herradurakex v1.0.0/go.mod h1:m3+vYZX+2dDjdo+n/HDnXEYJX9pwmNeQLgAfJM8mtxw=
|
|
||||||
blitter.com/go/hopscotch v0.1.1 h1:hh809THr3I52J5G5QozNhDSd+qGwXWGqLh3FJBGrp+o=
|
|
||||||
blitter.com/go/hopscotch v0.1.1/go.mod h1:hCz7oE31KjaO9M6+s2DcyVNlAA8saE/AaVYKFs7hl1I=
|
|
||||||
blitter.com/go/kyber v0.0.0-20200130200857-6f2021cb88d9 h1:D45AnrNphtvczBXRp5JQicZRTgaK/Is5bgPDDvRKhTc=
|
|
||||||
blitter.com/go/kyber v0.0.0-20200130200857-6f2021cb88d9/go.mod h1:SK6QfGG72lIfKW1Td0wH7f0wwN5nSIhV3K+wvzGNjrw=
|
|
||||||
blitter.com/go/mtwist v1.0.1 h1:PxmoWexfMpLmc8neHP/PcRc3s17ct7iz4d5W/qJVt04=
|
|
||||||
blitter.com/go/mtwist v1.0.1/go.mod h1:aU82Nx8+b1v8oZRNqImfEDzDTPim81rY0ACKAIclV18=
|
|
||||||
blitter.com/go/newhope v0.0.0-20200130200750-192fc08a8aae h1:YBBaCcdYRrI1btsmcMTv1VMPmaSXXz0RwKOTgMJYSRU=
|
|
||||||
blitter.com/go/newhope v0.0.0-20200130200750-192fc08a8aae/go.mod h1:ywoxfDBqInPsqtnxYsmS4SYMJ5D/kNcrFgpvI+Xcun0=
|
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
|
||||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f h1:UWGE8Vi+1Agt0lrvnd7UsmvwqWKRzb9byK9iQmsbY0Y=
|
|
||||||
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f/go.mod h1:u+9Snq0w+ZdYKi8BBoaxnEwWu0fY4Kvu9ByFpM51t1s=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
|
||||||
github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY=
|
|
||||||
github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
|
|
||||||
github.com/kuking/go-frodokem v1.0.2 h1:sxdguENCyr6WnLbJ/cjz0AYCW75H1b+E6zXY2ldZnUU=
|
|
||||||
github.com/kuking/go-frodokem v1.0.2/go.mod h1:83ZX1kHOd72ouCsvbffCqJIj7Ih83MQTAjH2QbqzLZk=
|
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
|
||||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
|
||||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
|
||||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
|
||||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
|
||||||
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
|
|
||||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
|
||||||
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
|
|
||||||
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
|
||||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
|
|
||||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/hlandau/easymetric.v1 v1.0.0 h1:ZbfbH7W3giuVDjWUoFhDOjjv20hiPr5HZ2yMV5f9IeE=
|
|
||||||
gopkg.in/hlandau/easymetric.v1 v1.0.0/go.mod h1:yh75hypuFzAxmvECh3ZKGCvFnIfapYJh2wv7ASaX2RE=
|
|
||||||
gopkg.in/hlandau/measurable.v1 v1.0.1 h1:wH5UZKCRUnRr1iD+xIZfwhtxhmr+bprRJttqA1Rklf4=
|
|
||||||
gopkg.in/hlandau/measurable.v1 v1.0.1/go.mod h1:6N+SYJGMTmetsx7wskULP+juuO+++tsHJkAgzvzsbuM=
|
|
||||||
gopkg.in/hlandau/passlib.v1 v1.0.11 h1:vKeHwGRdWBD9mm4bJ56GAAdBXpFUYvg/BYYkmphjnmA=
|
|
||||||
gopkg.in/hlandau/passlib.v1 v1.0.11/go.mod h1:wxGAv2CtQHlzWY8NJp+p045yl4WHyX7v2T6XbOcmqjM=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
## This wrapper may be used within the MSYS/mintty Windows
|
## This wrapper may be used within the MSYS/mintty Windows
|
||||||
## shell environment to have a functioning hkexsh client with
|
## shell environment to have a functioning xs client with
|
||||||
## working 'raw' mode and hidden password entry.
|
## working 'raw' mode and hidden password entry.
|
||||||
##
|
##
|
||||||
## mintty uses named pipes and ptys to get a more POSIX-like
|
## mintty uses named pipes and ptys to get a more POSIX-like
|
||||||
|
|
80
xs/xs.go
80
xs/xs.go
|
@ -102,6 +102,14 @@ type (
|
||||||
escSeqs map[byte]escHandler
|
escSeqs map[byte]escHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
escs = escSeqs{
|
||||||
|
'i': func(io.Writer) { os.Stdout.Write([]byte("\x1b[s\x1b[2;1H\x1b[1;31m[HKEXSH]\x1b[39;49m\x1b[u")) },
|
||||||
|
't': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m[HKEXSH]\x1b[39;49m")) },
|
||||||
|
'B': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m" + bob + "\x1b[39;49m")) },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Copy copies from src to dst until either EOF is reached
|
// Copy copies from src to dst until either EOF is reached
|
||||||
// on src or an error occurs. It returns the number of bytes
|
// on src or an error occurs. It returns the number of bytes
|
||||||
// copied and the first error encountered while copying, if any.
|
// copied and the first error encountered while copying, if any.
|
||||||
|
@ -149,11 +157,6 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er
|
||||||
// or tunnel traffic indicator - note we cannot just spawn a goroutine
|
// or tunnel traffic indicator - note we cannot just spawn a goroutine
|
||||||
// here, as copyBuffer() returns after each burst of data. Scope must
|
// here, as copyBuffer() returns after each burst of data. Scope must
|
||||||
// outlive individual copyBuffer calls).
|
// outlive individual copyBuffer calls).
|
||||||
escs := escSeqs{
|
|
||||||
'i': func(io.Writer) { os.Stdout.Write([]byte("\x1b[s\x1b[2;1H\x1b[1;31m[HKEXSH]\x1b[39;49m\x1b[u")) },
|
|
||||||
't': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m[HKEXSH]\x1b[39;49m")) },
|
|
||||||
'B': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m" + bob + "\x1b[39;49m")) },
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// If the reader has a WriteTo method, use it to do the copy.
|
// If the reader has a WriteTo method, use it to do the copy.
|
||||||
|
@ -544,6 +547,8 @@ func doShellMode(isInteractive bool, conn *xsnet.Conn, oldState *xs.State, rec *
|
||||||
_, outerr := func(conn *xsnet.Conn, r io.Reader) (w int64, e error) {
|
_, outerr := func(conn *xsnet.Conn, r io.Reader) (w int64, e error) {
|
||||||
// Copy() expects EOF so this will
|
// Copy() expects EOF so this will
|
||||||
// exit with outerr == nil
|
// exit with outerr == nil
|
||||||
|
// NOTE we use a local implementation of Copy() to allow
|
||||||
|
// for custom key sequences to trigger local actions
|
||||||
w, e = Copy(conn, r)
|
w, e = Copy(conn, r)
|
||||||
return w, e
|
return w, e
|
||||||
}(conn, os.Stdin)
|
}(conn, os.Stdin)
|
||||||
|
@ -687,23 +692,24 @@ func sendSessionParams(conn io.Writer /* *xsnet.Conn*/, rec *xs.Session) (e erro
|
||||||
// TODO: reduce gocyclo
|
// TODO: reduce gocyclo
|
||||||
func main() { //nolint: funlen, gocyclo
|
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 // true: login via password, asking server to generate authToken
|
||||||
dbg bool
|
dbg bool
|
||||||
shellMode bool // true: act as shell, false: file copier
|
shellMode bool // true: act as shell, false: file copier
|
||||||
cipherAlg string
|
cipherAlg string
|
||||||
hmacAlg string
|
hmacAlg string
|
||||||
kexAlg string
|
kexAlg string
|
||||||
server string
|
server string
|
||||||
port uint
|
port uint
|
||||||
cmdStr string
|
cmdStr string
|
||||||
tunSpecStr string // lport1:rport1[,lport2:rport2,...]
|
tunSpecStr string // lport1:rport1[,lport2:rport2,...]
|
||||||
|
rekeySecs uint
|
||||||
copySrc []byte
|
remodRequested bool // true: when rekeying, switch to random cipher/hmac alg
|
||||||
copyDst string
|
copySrc []byte
|
||||||
copyQuiet bool
|
copyDst string
|
||||||
copyLimitBPS uint
|
copyQuiet bool
|
||||||
|
copyLimitBPS uint
|
||||||
|
|
||||||
authCookie string
|
authCookie string
|
||||||
chaffEnabled bool
|
chaffEnabled bool
|
||||||
|
@ -727,7 +733,8 @@ func main() { //nolint: funlen, gocyclo
|
||||||
C_CHACHA20_12`)
|
C_CHACHA20_12`)
|
||||||
flag.StringVar(&hmacAlg, "m", "H_SHA256", "session `HMAC`"+`
|
flag.StringVar(&hmacAlg, "m", "H_SHA256", "session `HMAC`"+`
|
||||||
H_SHA256
|
H_SHA256
|
||||||
H_SHA512`)
|
H_SHA512
|
||||||
|
H_WHIRLPOOL`)
|
||||||
flag.StringVar(&kexAlg, "k", "KEX_HERRADURA512", "KEx `alg`"+`
|
flag.StringVar(&kexAlg, "k", "KEX_HERRADURA512", "KEx `alg`"+`
|
||||||
KEX_HERRADURA256
|
KEX_HERRADURA256
|
||||||
KEX_HERRADURA512
|
KEX_HERRADURA512
|
||||||
|
@ -744,6 +751,8 @@ func main() { //nolint: funlen, gocyclo
|
||||||
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") //nolint:lll
|
||||||
flag.UintVar(&port, "p", 2000, "``port") //nolint:gomnd,lll
|
flag.UintVar(&port, "p", 2000, "``port") //nolint:gomnd,lll
|
||||||
|
flag.UintVar(&rekeySecs, "r", 300, "rekey interval in `secs`")
|
||||||
|
flag.BoolVar(&remodRequested, "R", false, "Borg Countermeasures (remodulate cipher/hmac alg on each rekey)")
|
||||||
//nolint:gocritic,nolintlint // 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`") //nolint:gomnd
|
flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") //nolint:gomnd
|
||||||
|
@ -882,7 +891,7 @@ func main() { //nolint: funlen, gocyclo
|
||||||
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 := os.ReadFile(fmt.Sprintf("%s/%s", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE))
|
||||||
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 += "\n"
|
||||||
|
@ -900,7 +909,7 @@ func main() { //nolint: funlen, gocyclo
|
||||||
_, _ = fmt.Fprintln(os.Stderr, "[no authtoken, use -g to request one from server]")
|
_, _ = fmt.Fprintln(os.Stderr, "[no authtoken, use -g to request one from server]")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[cannot read %s/.xs_id]\n", u.HomeDir)
|
log.Printf("[cannot read %s/%s]\n", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
@ -964,12 +973,21 @@ func main() { //nolint: funlen, gocyclo
|
||||||
if kcpMode != "unused" {
|
if kcpMode != "unused" {
|
||||||
proto = "kcp"
|
proto = "kcp"
|
||||||
}
|
}
|
||||||
conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode)
|
|
||||||
|
remodExtArg := ""
|
||||||
|
if remodRequested {
|
||||||
|
remodExtArg = "OPT_REMOD"
|
||||||
|
}
|
||||||
|
// Pass opt to Dial() via extensions arg
|
||||||
|
conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode, remodExtArg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
exitWithStatus(XSNetDialFailed)
|
exitWithStatus(XSNetDialFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn.RekeyHelper(rekeySecs)
|
||||||
|
defer conn.ShutdownRekey()
|
||||||
|
|
||||||
// === 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
|
||||||
|
@ -1003,7 +1021,7 @@ func main() { //nolint: funlen, gocyclo
|
||||||
loginTimeout := time.AfterFunc(30*time.Second, func() { //nolint:gomnd
|
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.CSELoginTimeout)
|
||||||
})
|
})
|
||||||
|
|
||||||
if authCookie == "" {
|
if authCookie == "" {
|
||||||
|
@ -1057,13 +1075,16 @@ func main() { //nolint: funlen, gocyclo
|
||||||
fmt.Fprintln(os.Stderr, rejectUserMsg())
|
fmt.Fprintln(os.Stderr, rejectUserMsg())
|
||||||
rec.SetStatus(GeneralProtocolErr)
|
rec.SetStatus(GeneralProtocolErr)
|
||||||
} else {
|
} else {
|
||||||
|
// === Set up connection keepalive to server
|
||||||
|
conn.StartupKeepAlive() // goroutine, returns immediately
|
||||||
|
defer conn.ShutdownKeepAlive()
|
||||||
|
|
||||||
// === 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\"/
|
||||||
// TODO:.gv:main:2:deferCloseChaff
|
// TODO:.gv:main:2:deferCloseChaff
|
||||||
conn.EnableChaff() // goroutine, returns immediately
|
conn.StartupChaff() // goroutine, returns immediately
|
||||||
defer conn.DisableChaff()
|
|
||||||
defer conn.ShutdownChaff()
|
defer conn.ShutdownChaff()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1146,6 +1167,5 @@ func exitWithStatus(status int) {
|
||||||
log.Fatal("could not write memory profile: ", err) //nolint:gocritic
|
log.Fatal("could not write memory profile: ", err) //nolint:gocritic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Exit(status)
|
os.Exit(status)
|
||||||
}
|
}
|
||||||
|
|
184
xsd/xsd.go
184
xsd/xsd.go
|
@ -17,11 +17,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -44,6 +47,9 @@ var (
|
||||||
|
|
||||||
// Log - syslog output (with no -d)
|
// Log - syslog output (with no -d)
|
||||||
Log *logger.Writer
|
Log *logger.Writer
|
||||||
|
|
||||||
|
cpuprofile string
|
||||||
|
memprofile string
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -77,12 +83,7 @@ func runClientToServerCopyAs(who, ttype string, conn *xsnet.Conn, fpath string,
|
||||||
log.Println("uid:", uid, "gid:", gid)
|
log.Println("uid:", uid, "gid:", gid)
|
||||||
|
|
||||||
// Need to clear server's env and set key vars of the
|
// Need to clear server's env and set key vars of the
|
||||||
// target user. This isn't perfect (TERM doesn't seem to
|
// target user.
|
||||||
// work 100%; ANSI/xterm colour isn't working even
|
|
||||||
// if we set "xterm" or "ansi" here; and line count
|
|
||||||
// reported by 'stty -a' defaults to 24 regardless
|
|
||||||
// of client shell window used to run client.
|
|
||||||
// Investigate -- rlm 2018-01-26)
|
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HOME", u.HomeDir)
|
os.Setenv("HOME", u.HomeDir)
|
||||||
os.Setenv("TERM", ttype)
|
os.Setenv("TERM", ttype)
|
||||||
|
@ -109,9 +110,10 @@ func runClientToServerCopyAs(who, ttype string, conn *xsnet.Conn, fpath string,
|
||||||
|
|
||||||
c.Dir = destDir
|
c.Dir = destDir
|
||||||
|
|
||||||
//If os.Clearenv() isn't called by server above these will be seen in the
|
//If os.Clearenv() isn't called by server above these will be seen
|
||||||
//client's session env.
|
//in the client's session env.
|
||||||
//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=", "SUDO_USER=", "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
|
//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=",
|
||||||
|
// "SUDO_USER=", "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
|
||||||
//c.Dir = u.HomeDir
|
//c.Dir = u.HomeDir
|
||||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
||||||
|
@ -119,10 +121,13 @@ func runClientToServerCopyAs(who, ttype string, conn *xsnet.Conn, fpath string,
|
||||||
c.Stdout = os.Stdout
|
c.Stdout = os.Stdout
|
||||||
c.Stderr = os.Stderr
|
c.Stderr = os.Stderr
|
||||||
|
|
||||||
|
// === Set up connection keepalive to client
|
||||||
|
conn.StartupKeepAlive() // goroutine, returns immediately
|
||||||
|
defer conn.ShutdownKeepAlive()
|
||||||
|
|
||||||
if chaffing {
|
if chaffing {
|
||||||
conn.EnableChaff()
|
conn.StartupChaff()
|
||||||
}
|
}
|
||||||
defer conn.DisableChaff()
|
|
||||||
defer conn.ShutdownChaff()
|
defer conn.ShutdownChaff()
|
||||||
|
|
||||||
// Start the command (no pty)
|
// Start the command (no pty)
|
||||||
|
@ -182,12 +187,7 @@ func runServerToClientCopyAs(who, ttype string, conn *xsnet.Conn, srcPath string
|
||||||
log.Println("uid:", uid, "gid:", gid)
|
log.Println("uid:", uid, "gid:", gid)
|
||||||
|
|
||||||
// Need to clear server's env and set key vars of the
|
// Need to clear server's env and set key vars of the
|
||||||
// target user. This isn't perfect (TERM doesn't seem to
|
// target user.
|
||||||
// work 100%; ANSI/xterm colour isn't working even
|
|
||||||
// if we set "xterm" or "ansi" here; and line count
|
|
||||||
// reported by 'stty -a' defaults to 24 regardless
|
|
||||||
// of client shell window used to run client.
|
|
||||||
// Investigate -- rlm 2018-01-26)
|
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
_ = os.Setenv("HOME", u.HomeDir)
|
_ = os.Setenv("HOME", u.HomeDir)
|
||||||
_ = os.Setenv("TERM", ttype)
|
_ = os.Setenv("TERM", ttype)
|
||||||
|
@ -204,9 +204,10 @@ func runServerToClientCopyAs(who, ttype string, conn *xsnet.Conn, srcPath string
|
||||||
|
|
||||||
c = exec.Command(cmdName, cmdArgs...)
|
c = exec.Command(cmdName, cmdArgs...)
|
||||||
|
|
||||||
//If os.Clearenv() isn't called by server above these will be seen in the
|
//If os.Clearenv() isn't called by server above these will be seen
|
||||||
//client's session env.
|
//in the client's session env.
|
||||||
//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=", "SUDO_USER=", "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
|
//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=", "SUDO_USER=",
|
||||||
|
// "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
|
||||||
c.Dir = u.HomeDir
|
c.Dir = u.HomeDir
|
||||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
||||||
|
@ -220,11 +221,14 @@ func runServerToClientCopyAs(who, ttype string, conn *xsnet.Conn, srcPath string
|
||||||
c.Stderr = stdErrBuffer
|
c.Stderr = stdErrBuffer
|
||||||
//c.Stderr = nil
|
//c.Stderr = nil
|
||||||
|
|
||||||
|
// === Set up connection keepalive to client
|
||||||
|
conn.StartupKeepAlive() // goroutine, returns immediately
|
||||||
|
defer conn.ShutdownKeepAlive()
|
||||||
|
|
||||||
if chaffing {
|
if chaffing {
|
||||||
conn.EnableChaff()
|
conn.StartupChaff()
|
||||||
}
|
}
|
||||||
//defer conn.Close()
|
//defer conn.Close()
|
||||||
defer conn.DisableChaff()
|
|
||||||
defer conn.ShutdownChaff()
|
defer conn.ShutdownChaff()
|
||||||
|
|
||||||
// Start the command (no pty)
|
// Start the command (no pty)
|
||||||
|
@ -272,12 +276,7 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
|
||||||
log.Println("uid:", uid, "gid:", gid)
|
log.Println("uid:", uid, "gid:", gid)
|
||||||
|
|
||||||
// Need to clear server's env and set key vars of the
|
// Need to clear server's env and set key vars of the
|
||||||
// target user. This isn't perfect (TERM doesn't seem to
|
// target user.
|
||||||
// work 100%; ANSI/xterm colour isn't working even
|
|
||||||
// if we set "xterm" or "ansi" here; and line count
|
|
||||||
// reported by 'stty -a' defaults to 24 regardless
|
|
||||||
// of client shell window used to run client.
|
|
||||||
// Investigate -- rlm 2018-01-26)
|
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
_ = os.Setenv("HOME", u.HomeDir)
|
_ = os.Setenv("HOME", u.HomeDir)
|
||||||
_ = os.Setenv("TERM", ttype)
|
_ = os.Setenv("TERM", ttype)
|
||||||
|
@ -287,21 +286,28 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
|
||||||
|
|
||||||
if interactive {
|
if interactive {
|
||||||
if useSysLogin {
|
if useSysLogin {
|
||||||
// Use the server's login binary (post-auth, which
|
// Use the server's login binary (post-auth)
|
||||||
// is still done via our own bcrypt file)
|
|
||||||
//
|
|
||||||
// Note login will drop privs to the intended user for us
|
|
||||||
//
|
//
|
||||||
// Things UNIX login does, like print the 'motd',
|
// Things UNIX login does, like print the 'motd',
|
||||||
// and use the shell specified by /etc/passwd, will be done
|
// and use the shell specified by /etc/passwd, will be done
|
||||||
// automagically, at the cost of another external tool
|
// automagically, at the cost of another external tool
|
||||||
// dependency.
|
// dependency.
|
||||||
//
|
//
|
||||||
|
// One drawback of using 'login' is that the remote side
|
||||||
|
// cannot give us back the shell's exit code, since it
|
||||||
|
// exits back to 'login', which usually returns its own
|
||||||
|
// 0 status back to us.
|
||||||
|
//
|
||||||
|
// Note login will drop privs to the intended user for us.
|
||||||
|
//
|
||||||
c = exec.Command(xs.GetTool("login"), "-f", "-p", who) //nolint:gosec
|
c = exec.Command(xs.GetTool("login"), "-f", "-p", who) //nolint:gosec
|
||||||
} else {
|
} else {
|
||||||
// Using our separate login via local passwd file
|
// Run shell directly (which allows nonzero exit codes back to
|
||||||
|
// the local system upon shell exit, whereas 'login' does not.)
|
||||||
//
|
//
|
||||||
// Note we must drop privs ourselves for the user shell
|
// Note we must drop privs ourselves for the user shell since
|
||||||
|
// we aren't using 'login' on the remote end which would do it
|
||||||
|
// for us.
|
||||||
//
|
//
|
||||||
c = exec.Command(xs.GetTool("bash"), "-i", "-l") //nolint:gosec
|
c = exec.Command(xs.GetTool("bash"), "-i", "-l") //nolint:gosec
|
||||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
|
@ -312,9 +318,10 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
|
||||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
||||||
}
|
}
|
||||||
//If os.Clearenv() isn't called by server above these will be seen in the
|
//If os.Clearenv() isn't called by server above these will be seen
|
||||||
//client's session env.
|
//in the client's session env.
|
||||||
//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=", "SUDO_USER=", "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
|
//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=",
|
||||||
|
// "SUDO_USER=", "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
|
||||||
c.Dir = u.HomeDir
|
c.Dir = u.HomeDir
|
||||||
|
|
||||||
// Start the command with a pty.
|
// Start the command with a pty.
|
||||||
|
@ -339,6 +346,9 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
|
||||||
defer func() { goutmp.Unput_utmp(utmpx) }()
|
defer func() { goutmp.Unput_utmp(utmpx) }()
|
||||||
goutmp.Put_lastlog_entry("xs", who, pts, hname)
|
goutmp.Put_lastlog_entry("xs", who, pts, hname)
|
||||||
|
|
||||||
|
conn.Pproc = c.Process.Pid
|
||||||
|
//fmt.Printf("[process %d started]\n", c.Process.Pid)
|
||||||
|
|
||||||
log.Printf("[%s]\n", cmd)
|
log.Printf("[%s]\n", cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Command finished with error: %v", err)
|
log.Printf("Command finished with error: %v", err)
|
||||||
|
@ -364,12 +374,15 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// === Set up connection keepalive to client
|
||||||
|
conn.StartupKeepAlive() // goroutine, returns immediately
|
||||||
|
defer conn.ShutdownKeepAlive()
|
||||||
|
|
||||||
if chaffing {
|
if chaffing {
|
||||||
conn.EnableChaff()
|
conn.StartupChaff()
|
||||||
}
|
}
|
||||||
// #gv:s/label=\"runShellAs\$4\"/label=\"deferChaffShutdown\"/
|
// #gv:s/label=\"runShellAs\$4\"/label=\"deferChaffShutdown\"/
|
||||||
defer func() {
|
defer func() {
|
||||||
conn.DisableChaff()
|
|
||||||
conn.ShutdownChaff()
|
conn.ShutdownChaff()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -409,7 +422,7 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
|
||||||
}
|
}
|
||||||
conn.SetStatus(xsnet.CSOType(exitStatus))
|
conn.SetStatus(xsnet.CSOType(exitStatus))
|
||||||
} else {
|
} else {
|
||||||
logger.LogDebug("*** Main proc has exited. ***") //nolint:errcheck
|
logger.LogDebug(fmt.Sprintf("*** Main proc has exited (%d) ***", c.ProcessState.ExitCode())) //nolint:errcheck
|
||||||
// Background jobs still may be running; close the
|
// Background jobs still may be running; close the
|
||||||
// pty anyway, so the client can return before
|
// pty anyway, so the client can return before
|
||||||
// wg.Wait() below completes (Issue #18)
|
// wg.Wait() below completes (Issue #18)
|
||||||
|
@ -516,11 +529,15 @@ func main() { //nolint:funlen,gocyclo
|
||||||
var chaffBytesMax uint
|
var chaffBytesMax uint
|
||||||
var dbg bool
|
var dbg bool
|
||||||
var laddr string
|
var laddr string
|
||||||
|
var rekeySecs uint
|
||||||
|
var remodSupported bool // true: when rekeying, switch to random cipher/hmac alg
|
||||||
|
|
||||||
var useSystemPasswd bool
|
var useSystemPasswd bool
|
||||||
|
|
||||||
flag.BoolVar(&vopt, "v", false, "show version")
|
flag.BoolVar(&vopt, "v", false, "show version")
|
||||||
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen")
|
flag.UintVar(&rekeySecs, "r", 300, "rekey interval in `secs`")
|
||||||
|
flag.BoolVar(&remodSupported, "R", false, "Borg Countermeasures (remodulate cipher/hmac alg on each rekey)")
|
||||||
|
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") //nolint:gomnd,lll
|
||||||
flag.StringVar(&kcpMode, "K", "unused", `set to 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", `set to 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.BoolVar(&useSysLogin, "L", false, "use system login")
|
flag.BoolVar(&useSysLogin, "L", false, "use system login")
|
||||||
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
|
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
|
||||||
|
@ -555,7 +572,11 @@ func main() { //nolint:funlen,gocyclo
|
||||||
flag.Var(&aHMACAlgs, "aH", "Allowed `HMAC`s (eg. '-aH HMACAlgA -aH HMACAlgB ...')"+`
|
flag.Var(&aHMACAlgs, "aH", "Allowed `HMAC`s (eg. '-aH HMACAlgA -aH HMACAlgB ...')"+`
|
||||||
H_all
|
H_all
|
||||||
H_SHA256
|
H_SHA256
|
||||||
H_SHA512`)
|
H_SHA512
|
||||||
|
H_WHIRLPOOL`)
|
||||||
|
|
||||||
|
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to <`file`>")
|
||||||
|
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to <`file`>")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
@ -571,6 +592,24 @@ func main() { //nolint:funlen,gocyclo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Profiling instrumentation
|
||||||
|
|
||||||
|
if cpuprofile != "" {
|
||||||
|
f, err := os.Create(cpuprofile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("could not create CPU profile: ", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
fmt.Println("StartCPUProfile()")
|
||||||
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
|
log.Fatal("could not start CPU profile: ", err) //nolint:gocritic
|
||||||
|
} else {
|
||||||
|
defer pprof.StopCPUProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() { http.ListenAndServe("localhost:6060", nil) }() //nolint:errcheck,gosec
|
||||||
|
}
|
||||||
|
|
||||||
// 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 { //nolint:gomnd
|
||||||
chaffFreqMin = 2
|
chaffFreqMin = 2
|
||||||
|
@ -612,19 +651,22 @@ func main() { //nolint:funlen,gocyclo
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
sig := <-exitCh
|
sig := <-exitCh
|
||||||
switch sig.String() {
|
switch sig {
|
||||||
case "terminated":
|
case syscall.SIGTERM: //"terminated":
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig)) //nolint:errcheck
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig.String())) //nolint:errcheck
|
||||||
signal.Reset()
|
signal.Reset()
|
||||||
syscall.Kill(0, syscall.SIGTERM) //nolint:errcheck
|
syscall.Kill(0, syscall.SIGTERM) //nolint:errcheck
|
||||||
case "interrupt":
|
case syscall.SIGINT: //"interrupt":
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig)) //nolint:errcheck
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig.String())) //nolint:errcheck
|
||||||
signal.Reset()
|
signal.Reset()
|
||||||
syscall.Kill(0, syscall.SIGINT) //nolint:errcheck
|
syscall.Kill(0, syscall.SIGINT) //nolint:errcheck
|
||||||
case "hangup":
|
case syscall.SIGHUP: //"hangup":
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s - nop]", sig)) //nolint:errcheck
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s - nop]", sig.String())) //nolint:errcheck
|
||||||
|
if cpuprofile != "" || memprofile != "" {
|
||||||
|
dumpProf()
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s - ignored]", sig)) //nolint:errcheck
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s - ignored]", sig.String())) //nolint:errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -644,6 +686,7 @@ func main() { //nolint:funlen,gocyclo
|
||||||
// Wait for a connection.
|
// Wait for a connection.
|
||||||
// Then check if client-proposed algs are allowed
|
// Then check if client-proposed algs are allowed
|
||||||
conn, err := l.Accept()
|
conn, err := l.Accept()
|
||||||
|
//logger.LogDebug(fmt.Sprintf("l.Accept()\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Accept() got error(%v), hanging up.\n", err)
|
log.Printf("Accept() got error(%v), hanging up.\n", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -662,6 +705,24 @@ func main() { //nolint:funlen,gocyclo
|
||||||
} else {
|
} else {
|
||||||
log.Println("Accepted client")
|
log.Println("Accepted client")
|
||||||
|
|
||||||
|
// Only enable cipher alg changes on re-key if we were told
|
||||||
|
// to support it (launching xsd with -R), *and* the client
|
||||||
|
// proposes to use it.
|
||||||
|
if !remodSupported {
|
||||||
|
if (conn.Opts() & xsnet.CORemodulateShields) != 0 {
|
||||||
|
logger.LogDebug("[client proposed cipher/hmac remod, but we don't support it.]")
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if conn.Opts()&xsnet.CORemodulateShields != 0 {
|
||||||
|
logger.LogDebug("[cipher/hmac remodulation active]")
|
||||||
|
} else {
|
||||||
|
logger.LogDebug("[cipher/hmac remodulation inactive]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.RekeyHelper(rekeySecs)
|
||||||
|
|
||||||
// Set up chaffing to client
|
// Set up chaffing to client
|
||||||
// Will only start when runShellAs() is called
|
// Will only start when runShellAs() is called
|
||||||
// after stdin/stdout are hooked up
|
// after stdin/stdout are hooked up
|
||||||
|
@ -671,6 +732,7 @@ func main() { //nolint:funlen,gocyclo
|
||||||
// The loop then returns to accepting, so that
|
// The loop then returns to accepting, so that
|
||||||
// multiple connections may be served concurrently.
|
// multiple connections may be served concurrently.
|
||||||
go func(hc *xsnet.Conn) (e error) {
|
go func(hc *xsnet.Conn) (e error) {
|
||||||
|
defer hc.ShutdownRekey()
|
||||||
defer hc.Close()
|
defer hc.Close()
|
||||||
|
|
||||||
// Start login timeout here and disconnect if user/pass phase stalls
|
// Start login timeout here and disconnect if user/pass phase stalls
|
||||||
|
@ -780,7 +842,7 @@ func main() { //nolint:funlen,gocyclo
|
||||||
hname := goutmp.GetHost(addr.String())
|
hname := goutmp.GetHost(addr.String())
|
||||||
logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)) //nolint:errcheck
|
logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)) //nolint:errcheck
|
||||||
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
|
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
|
||||||
tokenCmd := fmt.Sprintf("echo %q | tee -a ~/.xs_id", token)
|
tokenCmd := fmt.Sprintf("echo %q | tee -a ~/%s", token, xsnet.XS_ID_AUTHTOKFILE)
|
||||||
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
|
@ -876,3 +938,23 @@ func main() { //nolint:funlen,gocyclo
|
||||||
} //endfor
|
} //endfor
|
||||||
//logger.LogNotice(fmt.Sprintln("[Exiting]")) //nolint:errcheck
|
//logger.LogNotice(fmt.Sprintln("[Exiting]")) //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dumpProf() {
|
||||||
|
if cpuprofile != "" {
|
||||||
|
pprof.StopCPUProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
if memprofile != "" {
|
||||||
|
f, err := os.Create(memprofile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("could not create memory profile: ", err)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//os.Exit(status)
|
||||||
|
}
|
||||||
|
|
|
@ -22,10 +22,11 @@ import (
|
||||||
|
|
||||||
"blitter.com/go/cryptmt"
|
"blitter.com/go/cryptmt"
|
||||||
"blitter.com/go/hopscotch"
|
"blitter.com/go/hopscotch"
|
||||||
|
"blitter.com/go/xs/logger"
|
||||||
"github.com/aead/chacha20/chacha"
|
"github.com/aead/chacha20/chacha"
|
||||||
"golang.org/x/crypto/blowfish"
|
"golang.org/x/crypto/blowfish"
|
||||||
"golang.org/x/crypto/twofish"
|
"golang.org/x/crypto/twofish"
|
||||||
|
whirlpool "github.com/jzelinskie/whirlpool"
|
||||||
// hash algos must be manually imported thusly:
|
// hash algos must be manually imported thusly:
|
||||||
// (Would be nice if the golang pkg docs were more clear
|
// (Would be nice if the golang pkg docs were more clear
|
||||||
// on this...)
|
// on this...)
|
||||||
|
@ -57,9 +58,19 @@ func expandKeyMat(keymat []byte, blocksize int) []byte {
|
||||||
return keymat
|
return keymat
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Support functionality to set up encryption after a channel has
|
// Choose a cipher and hmac alg from supported sets, given two uint8 values
|
||||||
been negotiated via xsnet.go
|
func getNewStreamAlgs(cb uint8, hb uint8) (config uint32) {
|
||||||
*/
|
// Get new cipher and hash algs (clamped to valid values) based on
|
||||||
|
// the input rekeying data
|
||||||
|
c := (cb % CAlgNoneDisallowed)
|
||||||
|
h := (hb % HmacNoneDisallowed)
|
||||||
|
config = uint32(h<<8) | uint32(c)
|
||||||
|
logger.LogDebug(fmt.Sprintf("[Chose new algs [%d:%d]", h, c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// (Re-)initialize the keystream and hmac state for an xsnet.Conn, returning
|
||||||
|
// a cipherStream and hash
|
||||||
func (hc *Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err error) {
|
func (hc *Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err error) {
|
||||||
var key []byte
|
var key []byte
|
||||||
var block cipher.Block
|
var block cipher.Block
|
||||||
|
@ -146,6 +157,9 @@ func (hc *Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err er
|
||||||
if !halg.Available() {
|
if !halg.Available() {
|
||||||
log.Fatal("hash not available!")
|
log.Fatal("hash not available!")
|
||||||
}
|
}
|
||||||
|
case HmacWHIRLPOOL:
|
||||||
|
log.Printf("[hash HmacWHIRLPOOL (%d)]\n", hopts)
|
||||||
|
mc = whirlpool.New()
|
||||||
default:
|
default:
|
||||||
log.Printf("[invalid hmac (%d)]\n", hopts)
|
log.Printf("[invalid hmac (%d)]\n", hopts)
|
||||||
fmt.Printf("DOOFUS SET A VALID HMAC ALG (%d)\n", hopts)
|
fmt.Printf("DOOFUS SET A VALID HMAC ALG (%d)\n", hopts)
|
||||||
|
|
|
@ -52,6 +52,8 @@ const (
|
||||||
CSEKEXAlgDenied // server rejected proposed KEX alg
|
CSEKEXAlgDenied // server rejected proposed KEX alg
|
||||||
CSECipherAlgDenied // server rejected proposed Cipher alg
|
CSECipherAlgDenied // server rejected proposed Cipher alg
|
||||||
CSEHMACAlgDenied // server rejected proposed HMAC alg
|
CSEHMACAlgDenied // server rejected proposed HMAC alg
|
||||||
|
CSEConnDead // connection keepalives expired
|
||||||
|
CSELoginTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
// Extended (>255 UNIX exit status) codes
|
// Extended (>255 UNIX exit status) codes
|
||||||
|
@ -67,9 +69,6 @@ const (
|
||||||
CSOExitStatus // Remote cmd exit status
|
CSOExitStatus // Remote cmd exit status
|
||||||
CSOChaff // Dummy packet, do not pass beyond decryption
|
CSOChaff // Dummy packet, do not pass beyond decryption
|
||||||
|
|
||||||
// Client side errors
|
|
||||||
CSOLoginTimeout
|
|
||||||
|
|
||||||
// Tunnel setup/control/status
|
// Tunnel setup/control/status
|
||||||
CSOTunSetup // 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
|
||||||
|
@ -78,6 +77,8 @@ const (
|
||||||
CSOTunKeepAlive // client tunnel heartbeat
|
CSOTunKeepAlive // client tunnel heartbeat
|
||||||
CSOTunDisconn // server -> client: tunnel rport disconnected
|
CSOTunDisconn // server -> client: tunnel rport disconnected
|
||||||
CSOTunHangup // client -> server: tunnel lport hung up
|
CSOTunHangup // client -> server: tunnel lport hung up
|
||||||
|
CSOKeepAlive // bidir keepalive packet to monitor main connection
|
||||||
|
CSORekey // TODO: rekey/re-select session cipher/hash algs
|
||||||
)
|
)
|
||||||
|
|
||||||
// TunEndpoint.tunCtl control values - used to control workers for client
|
// TunEndpoint.tunCtl control values - used to control workers for client
|
||||||
|
@ -97,7 +98,7 @@ const (
|
||||||
// Channel status Op byte type (see CSONone, ... and CSENone, ...)
|
// Channel status Op byte type (see CSONone, ... and CSENone, ...)
|
||||||
type CSOType uint32
|
type CSOType uint32
|
||||||
|
|
||||||
//TODO: this should be small (max unfragmented packet size?)
|
// TODO: this should be small (max unfragmented packet size?)
|
||||||
const MAX_PAYLOAD_LEN = 2*1024*1024*1024 - 1
|
const MAX_PAYLOAD_LEN = 2*1024*1024*1024 - 1
|
||||||
|
|
||||||
// Session symmetric crypto algs
|
// Session symmetric crypto algs
|
||||||
|
@ -118,8 +119,27 @@ type CSCipherAlg uint32
|
||||||
const (
|
const (
|
||||||
HmacSHA256 = iota
|
HmacSHA256 = iota
|
||||||
HmacSHA512
|
HmacSHA512
|
||||||
|
HmacWHIRLPOOL
|
||||||
HmacNoneDisallowed
|
HmacNoneDisallowed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Conn opts outside of basic kex/cipher/hmac connect config
|
||||||
|
const (
|
||||||
|
CONone = iota
|
||||||
|
CORemodulateShields // if set, rekeying also reselects random cipher/hmac alg
|
||||||
|
)
|
||||||
|
|
||||||
|
type COValue uint32
|
||||||
|
|
||||||
// Available HMACs for hkex.Conn
|
// Available HMACs for hkex.Conn
|
||||||
type CSHmacAlg uint32
|
type CSHmacAlg uint32
|
||||||
|
|
||||||
|
// Some bounds-checking consts
|
||||||
|
const (
|
||||||
|
REKEY_SECS_MIN = 1
|
||||||
|
REKEY_SECS_MAX = 28800 // 8 hours
|
||||||
|
CHAFF_FREQ_MSECS_MIN = 1
|
||||||
|
CHAFF_FREQ_MSECS_MAX = 300000 // 5 minutes
|
||||||
|
)
|
||||||
|
|
||||||
|
const XS_ID_AUTHTOKFILE = ".config/xs/.xs_id"
|
||||||
|
|
250
xsnet/net.go
250
xsnet/net.go
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
package xsnet
|
package xsnet
|
||||||
|
|
||||||
// Implementation of HKEx-wrapped versions of the golang standard
|
// Implementation of key-exchange-wrapped versions of the golang standard
|
||||||
// net package interfaces, allowing clients and servers to simply replace
|
// net package interfaces, allowing clients and servers to simply replace
|
||||||
// 'net.Dial' and 'net.Listen' with 'hkex.Dial' and 'hkex.Listen'
|
// 'net.Dial' and 'net.Listen' with 'hkex.Dial' and 'hkex.Listen'
|
||||||
// (though some extra methods are implemented and must be used
|
// (though some extra methods are implemented and must be used
|
||||||
|
@ -39,6 +39,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
hkex "blitter.com/go/herradurakex"
|
hkex "blitter.com/go/herradurakex"
|
||||||
|
@ -64,7 +65,6 @@ type (
|
||||||
// see: https://en.wikipedia.org/wiki/chaff_(countermeasure)
|
// see: https://en.wikipedia.org/wiki/chaff_(countermeasure)
|
||||||
ChaffConfig struct {
|
ChaffConfig struct {
|
||||||
shutdown bool //set to inform chaffHelper to shut down
|
shutdown bool //set to inform chaffHelper to shut down
|
||||||
enabled bool
|
|
||||||
msecsMin uint //msecs min interval
|
msecsMin uint //msecs min interval
|
||||||
msecsMax uint //msecs max interval
|
msecsMax uint //msecs max interval
|
||||||
szMax uint // max size in bytes
|
szMax uint // max size in bytes
|
||||||
|
@ -87,8 +87,11 @@ type (
|
||||||
Rows uint16
|
Rows uint16
|
||||||
Cols uint16
|
Cols uint16
|
||||||
|
|
||||||
chaff ChaffConfig
|
keepalive uint // if this reaches zero, conn is considered dead
|
||||||
tuns *map[uint16](*TunEndpoint)
|
rekey uint // if nonzero, rekeying interval in seconds
|
||||||
|
Pproc int // proc ID of command run on this conn
|
||||||
|
chaff ChaffConfig
|
||||||
|
tuns *map[uint16](*TunEndpoint)
|
||||||
|
|
||||||
closeStat *CSOType // close status (CSOExitStatus)
|
closeStat *CSOType // close status (CSOExitStatus)
|
||||||
r cipher.Stream //read cipherStream
|
r cipher.Stream //read cipherStream
|
||||||
|
@ -174,6 +177,8 @@ func (h *CSHmacAlg) String() string {
|
||||||
return "H_SHA256"
|
return "H_SHA256"
|
||||||
case HmacSHA512:
|
case HmacSHA512:
|
||||||
return "H_SHA512"
|
return "H_SHA512"
|
||||||
|
case HmacWHIRLPOOL:
|
||||||
|
return "H_WHIRLPOOL"
|
||||||
default:
|
default:
|
||||||
return "H_ERR_UNK"
|
return "H_ERR_UNK"
|
||||||
}
|
}
|
||||||
|
@ -238,7 +243,7 @@ func (hc *Conn) SetConnOpts(copts uint32) {
|
||||||
//
|
//
|
||||||
// Consumers of this lib may use this for protocol-level options not part
|
// Consumers of this lib may use this for protocol-level options not part
|
||||||
// of the KEx or encryption info used by the connection.
|
// of the KEx or encryption info used by the connection.
|
||||||
func (hc Conn) Opts() uint32 {
|
func (hc *Conn) Opts() uint32 {
|
||||||
return hc.opts
|
return hc.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,9 +313,9 @@ func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) {
|
||||||
// applyConnExtensions processes optional Dial() negotiation
|
// applyConnExtensions processes optional Dial() negotiation
|
||||||
// parameters. See also getkexalgnum().
|
// parameters. See also getkexalgnum().
|
||||||
//
|
//
|
||||||
// Currently defined extension values
|
// # Currently defined extension values
|
||||||
//
|
//
|
||||||
// KEx algs
|
// # KEx algs
|
||||||
//
|
//
|
||||||
// KEX_HERRADURA256 KEX_HERRADURA512 KEX_HERRADURA1024 KEX_HERRADURA2048
|
// KEX_HERRADURA256 KEX_HERRADURA512 KEX_HERRADURA1024 KEX_HERRADURA2048
|
||||||
//
|
//
|
||||||
|
@ -318,11 +323,11 @@ func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) {
|
||||||
//
|
//
|
||||||
// KEX_NEWHOPE KEX_NEWHOPE_SIMPLE
|
// KEX_NEWHOPE KEX_NEWHOPE_SIMPLE
|
||||||
//
|
//
|
||||||
// Session (symmetric) crypto
|
// # Session (symmetric) crypto
|
||||||
//
|
//
|
||||||
// C_AES_256 C_TWOFISH_128 C_BLOWFISH_128 C_CRYPTMT1 C_CHACHA20_12 C_HOPSCOTCH
|
// C_AES_256 C_TWOFISH_128 C_BLOWFISH_128 C_CRYPTMT1 C_CHACHA20_12 C_HOPSCOTCH
|
||||||
//
|
//
|
||||||
// Session HMACs
|
// # Session HMACs
|
||||||
//
|
//
|
||||||
// H_SHA256 H_SHA512
|
// H_SHA256 H_SHA512
|
||||||
func (hc *Conn) applyConnExtensions(extensions ...string) {
|
func (hc *Conn) applyConnExtensions(extensions ...string) {
|
||||||
|
@ -360,6 +365,13 @@ func (hc *Conn) applyConnExtensions(extensions ...string) {
|
||||||
log.Println("[extension arg = H_SHA512]")
|
log.Println("[extension arg = H_SHA512]")
|
||||||
hc.cipheropts &= (0xFFFF00FF)
|
hc.cipheropts &= (0xFFFF00FF)
|
||||||
hc.cipheropts |= (HmacSHA512 << 8)
|
hc.cipheropts |= (HmacSHA512 << 8)
|
||||||
|
case "H_WHIRLPOOL":
|
||||||
|
log.Println("[extension arg = H_WHIRLPOOL]")
|
||||||
|
hc.cipheropts &= (0xFFFF00FF)
|
||||||
|
hc.cipheropts |= (HmacWHIRLPOOL << 8)
|
||||||
|
case "OPT_REMOD":
|
||||||
|
log.Println("[extension arg = OPT_REMOD]")
|
||||||
|
hc.opts |= CORemodulateShields
|
||||||
//default:
|
//default:
|
||||||
// log.Printf("[Dial ext \"%s\" ignored]\n", s)
|
// log.Printf("[Dial ext \"%s\" ignored]\n", s)
|
||||||
}
|
}
|
||||||
|
@ -882,12 +894,12 @@ func HKExAcceptSetup(c *net.Conn, hc *Conn) (err error) {
|
||||||
// Dial as net.Dial(), but with implicit key exchange to set up secure
|
// Dial as net.Dial(), but with implicit key exchange to set up secure
|
||||||
// channel on connect
|
// channel on connect
|
||||||
//
|
//
|
||||||
// Can be called like net.Dial(), defaulting to C_AES_256/H_SHA256,
|
// Can be called like net.Dial(), defaulting to C_AES_256/H_SHA256,
|
||||||
// or additional extensions can be passed amongst the following:
|
// or additional extensions can be passed amongst the following:
|
||||||
//
|
//
|
||||||
// "C_AES_256" | "C_TWOFISH_128" | ...
|
// "C_AES_256" | "C_TWOFISH_128" | ...
|
||||||
//
|
//
|
||||||
// "H_SHA256" | "H_SHA512" | ...
|
// "H_SHA256" | "H_SHA512" | ...
|
||||||
//
|
//
|
||||||
// See go doc -u xsnet.applyConnExtensions
|
// See go doc -u xsnet.applyConnExtensions
|
||||||
func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err error) {
|
func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err error) {
|
||||||
|
@ -971,7 +983,7 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er
|
||||||
|
|
||||||
// Close a hkex.Conn
|
// Close a hkex.Conn
|
||||||
func (hc *Conn) Close() (err error) {
|
func (hc *Conn) Close() (err error) {
|
||||||
hc.DisableChaff()
|
hc.ShutdownChaff()
|
||||||
s := make([]byte, 4)
|
s := make([]byte, 4)
|
||||||
binary.BigEndian.PutUint32(s, uint32(*hc.closeStat))
|
binary.BigEndian.PutUint32(s, uint32(*hc.closeStat))
|
||||||
log.Printf("** Writing closeStat %d at Close()\n", *hc.closeStat)
|
log.Printf("** Writing closeStat %d at Close()\n", *hc.closeStat)
|
||||||
|
@ -1084,7 +1096,7 @@ func (hl HKExListener) Close() error {
|
||||||
return hl.l.Close()
|
return hl.l.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addr returns a the listener's network address.
|
// Addr returns the listener's network address.
|
||||||
//
|
//
|
||||||
// See go doc net.Listener.Addr
|
// See go doc net.Listener.Addr
|
||||||
func (hl HKExListener) Addr() net.Addr {
|
func (hl HKExListener) Addr() net.Addr {
|
||||||
|
@ -1109,7 +1121,7 @@ func (hl *HKExListener) Accept() (hc Conn, err error) {
|
||||||
return Conn{}, err
|
return Conn{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogDebug(fmt.Sprintln("[net.Listener Accepted]"))
|
logger.LogDebug(fmt.Sprintf("[net.Listener Accepted %v]\n", c.RemoteAddr()))
|
||||||
}
|
}
|
||||||
// Read KEx alg proposed by client
|
// Read KEx alg proposed by client
|
||||||
var kexAlg KEXAlg
|
var kexAlg KEXAlg
|
||||||
|
@ -1196,7 +1208,7 @@ func (hl *HKExListener) Accept() (hc Conn, err error) {
|
||||||
// packet processing.
|
// packet processing.
|
||||||
//
|
//
|
||||||
// See go doc io.Reader
|
// See go doc io.Reader
|
||||||
func (hc Conn) Read(b []byte) (n int, err error) {
|
func (hc *Conn) Read(b []byte) (n int, err error) {
|
||||||
for {
|
for {
|
||||||
if hc.dBuf.Len() > 0 {
|
if hc.dBuf.Len() > 0 {
|
||||||
break
|
break
|
||||||
|
@ -1214,7 +1226,8 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
logger.LogDebug(fmt.Sprintln("[Client hung up]"))
|
logger.LogDebug(fmt.Sprintln("[Client hung up(1)]"))
|
||||||
|
//!rlm hc.SetStatus(CSENone) //FIXME: re-examine this (exit 9 w/o it - 2023-11-05)
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "ctrlStatOp", err)
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "ctrlStatOp", err)
|
||||||
|
@ -1237,7 +1250,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
logger.LogDebug(fmt.Sprintln("[Client hung up]"))
|
logger.LogDebug(fmt.Sprintln("[Client hung up(2)]"))
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "HMAC", err)
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "HMAC", err)
|
||||||
|
@ -1253,7 +1266,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
logger.LogDebug(fmt.Sprintln("[Client hung up]"))
|
logger.LogDebug(fmt.Sprintln("[Client hung up(3)]"))
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadLen", err)
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadLen", err)
|
||||||
|
@ -1276,7 +1289,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
logger.LogDebug(fmt.Sprintln("[Client hung up]"))
|
logger.LogDebug(fmt.Sprintln("[Client hung up(4)]"))
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadBytes", err)
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadBytes", err)
|
||||||
|
@ -1337,6 +1350,22 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
case CSOChaff:
|
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)
|
||||||
log.Printf("[Chaff pkt, discarded (len %d)]\n", decryptN)
|
log.Printf("[Chaff pkt, discarded (len %d)]\n", decryptN)
|
||||||
|
case CSOKeepAlive:
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[got keepAlive pkt, discarded (len %d)]\n", decryptN))
|
||||||
|
// payload of keepalive (2 bytes) is not currently used (0x55aa fixed)
|
||||||
|
_ = binary.BigEndian.Uint16(payloadBytes[0:2])
|
||||||
|
hc.ResetKeepAlive()
|
||||||
|
case CSORekey:
|
||||||
|
// rekey
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[Got rekey [%02x %02x %02x ...]\n",
|
||||||
|
// payloadBytes[0], payloadBytes[1], payloadBytes[2]))
|
||||||
|
rekeyData := payloadBytes
|
||||||
|
if (hc.opts & CORemodulateShields) != 0 {
|
||||||
|
hc.Lock()
|
||||||
|
hc.cipheropts = getNewStreamAlgs(rekeyData[0], rekeyData[1])
|
||||||
|
hc.Unlock()
|
||||||
|
}
|
||||||
|
hc.r, hc.rm, err = hc.getStream(rekeyData)
|
||||||
case CSOTermSize:
|
case 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)
|
||||||
|
@ -1423,6 +1452,9 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
// let the server know to hang up on Dial()ed server rports.
|
// let the server know to hang up on Dial()ed server rports.
|
||||||
_ = binary.BigEndian.Uint16(payloadBytes[0:2])
|
_ = binary.BigEndian.Uint16(payloadBytes[0:2])
|
||||||
//logger.LogDebug(fmt.Sprintf("[Server] Got CSOTunKeepAlive"))
|
//logger.LogDebug(fmt.Sprintf("[Server] Got CSOTunKeepAlive"))
|
||||||
|
// though CSOTunKeepAlive sends an endp (uint16), we don't use it,
|
||||||
|
// preferring to refresh *all* tunnels on the message.
|
||||||
|
// (?rlm 2023-11-04 -- TODO: verify this, it's been a while.)
|
||||||
for _, t := range *hc.tuns {
|
for _, t := range *hc.tuns {
|
||||||
hc.Lock()
|
hc.Lock()
|
||||||
t.KeepAlive = 0
|
t.KeepAlive = 0
|
||||||
|
@ -1450,13 +1482,18 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
// Write a byte slice
|
// Write a byte slice
|
||||||
//
|
//
|
||||||
// See go doc io.Writer
|
// See go doc io.Writer
|
||||||
func (hc Conn) Write(b []byte) (n int, err error) {
|
func (hc *Conn) Write(b []byte) (n int, err error) {
|
||||||
|
//logger.LogDebug("[+Write]")
|
||||||
n, err = hc.WritePacket(b, CSONone)
|
n, err = hc.WritePacket(b, CSONone)
|
||||||
|
//logger.LogDebug("[-Write]")
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a byte slice with specified ctrlStatOp byte
|
// Write a byte slice with specified ctrlStatOp byte
|
||||||
func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
|
func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
|
||||||
|
hc.Lock()
|
||||||
|
defer hc.Unlock()
|
||||||
|
|
||||||
//log.Printf("[Encrypting...]\r\n")
|
//log.Printf("[Encrypting...]\r\n")
|
||||||
var hmacOut []uint8
|
var hmacOut []uint8
|
||||||
var payloadLen uint32
|
var payloadLen uint32
|
||||||
|
@ -1484,15 +1521,6 @@ func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
|
||||||
b = append([]byte{byte(padSide)}, append([]byte{byte(padLen)}, append(b, padBytes...)...)...)
|
b = append([]byte{byte(padSide)}, append([]byte{byte(padLen)}, append(b, padBytes...)...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// N.B. Originally this Lock() surrounded only the
|
|
||||||
// calls to binary.Write(hc.c ..) however there appears
|
|
||||||
// to be some other unshareable state in the Conn
|
|
||||||
// struct that must be protected to serialize main and
|
|
||||||
// chaff data written to it.
|
|
||||||
//
|
|
||||||
// Would be nice to determine if the mutex scope
|
|
||||||
// could be tightened.
|
|
||||||
hc.Lock()
|
|
||||||
payloadLen = uint32(len(b))
|
payloadLen = uint32(len(b))
|
||||||
if hc.logPlainText {
|
if hc.logPlainText {
|
||||||
log.Printf(" >:ptext:\r\n%s\r\n", hex.Dump(b[0:payloadLen]))
|
log.Printf(" >:ptext:\r\n%s\r\n", hex.Dump(b[0:payloadLen]))
|
||||||
|
@ -1550,7 +1578,6 @@ func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
|
||||||
} else {
|
} else {
|
||||||
//fmt.Println("[a]WriteError!")
|
//fmt.Println("[a]WriteError!")
|
||||||
}
|
}
|
||||||
hc.Unlock()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
@ -1565,53 +1592,180 @@ func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
|
||||||
return retN, err
|
return retN, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hc *Conn) EnableChaff() {
|
func (hc *Conn) StartupChaff() {
|
||||||
hc.chaff.shutdown = false
|
hc.chaff.shutdown = false
|
||||||
hc.chaff.enabled = true
|
|
||||||
log.Println("Chaffing ENABLED")
|
log.Println("Chaffing ENABLED")
|
||||||
hc.chaffHelper()
|
hc.chaffHelper()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hc *Conn) DisableChaff() {
|
|
||||||
hc.chaff.enabled = false
|
|
||||||
log.Println("Chaffing DISABLED")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *Conn) ShutdownChaff() {
|
func (hc *Conn) ShutdownChaff() {
|
||||||
|
hc.Lock()
|
||||||
hc.chaff.shutdown = true
|
hc.chaff.shutdown = true
|
||||||
|
hc.Unlock()
|
||||||
log.Println("Chaffing SHUTDOWN")
|
log.Println("Chaffing SHUTDOWN")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hc *Conn) SetupChaff(msecsMin uint, msecsMax uint, szMax uint) {
|
func (hc *Conn) SetupChaff(msecsMin uint, msecsMax uint, szMax uint) {
|
||||||
|
// Enforce bounds on chaff frequency and pkt size
|
||||||
|
hc.Lock()
|
||||||
|
if hc.chaff.msecsMin < CHAFF_FREQ_MSECS_MIN {
|
||||||
|
hc.chaff.msecsMin = CHAFF_FREQ_MSECS_MIN
|
||||||
|
}
|
||||||
|
if hc.chaff.msecsMax > CHAFF_FREQ_MSECS_MAX {
|
||||||
|
hc.chaff.msecsMax = CHAFF_FREQ_MSECS_MAX
|
||||||
|
}
|
||||||
|
hc.Unlock()
|
||||||
|
|
||||||
hc.chaff.msecsMin = msecsMin //move these to params of chaffHelper() ?
|
hc.chaff.msecsMin = msecsMin //move these to params of chaffHelper() ?
|
||||||
hc.chaff.msecsMax = msecsMax
|
hc.chaff.msecsMax = msecsMax
|
||||||
hc.chaff.szMax = szMax
|
hc.chaff.szMax = szMax
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) ShutdownRekey() {
|
||||||
|
hc.Lock()
|
||||||
|
hc.rekey = 0
|
||||||
|
hc.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) RekeyHelper(intervalSecs uint) {
|
||||||
|
if intervalSecs < REKEY_SECS_MIN {
|
||||||
|
intervalSecs = REKEY_SECS_MIN
|
||||||
|
}
|
||||||
|
if intervalSecs > REKEY_SECS_MAX {
|
||||||
|
intervalSecs = REKEY_SECS_MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
hc.Lock()
|
||||||
|
hc.rekey = intervalSecs
|
||||||
|
hc.Unlock()
|
||||||
|
|
||||||
|
for {
|
||||||
|
hc.Lock()
|
||||||
|
rekey := hc.rekey
|
||||||
|
hc.Unlock()
|
||||||
|
|
||||||
|
if rekey != 0 {
|
||||||
|
jitter := rand.Intn(int(rekey)) / 4
|
||||||
|
rekey = rekey - uint(jitter)
|
||||||
|
if rekey < 1 {
|
||||||
|
rekey = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[rekeyHelper Loop]\n"))
|
||||||
|
time.Sleep(time.Duration(rekey) * time.Second)
|
||||||
|
|
||||||
|
// Send rekey to other end
|
||||||
|
rekeyData := make([]byte, 64)
|
||||||
|
_, err := crand.Read(rekeyData)
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[rekey [%02x %02x %02x ...]\n",
|
||||||
|
// rekeyData[0], rekeyData[1], rekeyData[2]))
|
||||||
|
//logger.LogDebug("[+rekeyHelper]")
|
||||||
|
_, err = hc.WritePacket(rekeyData, CSORekey)
|
||||||
|
hc.Lock()
|
||||||
|
if (hc.opts & CORemodulateShields) != 0 {
|
||||||
|
hc.cipheropts = getNewStreamAlgs(rekeyData[0], rekeyData[1])
|
||||||
|
}
|
||||||
|
hc.w, hc.wm, err = hc.getStream(rekeyData)
|
||||||
|
//logger.LogDebug("[-rekeyHelper]")
|
||||||
|
hc.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[rekey WritePacket err! (%v) rekey dying ...]\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// Helper routine to spawn a chaffing goroutine for each Conn
|
// Helper routine to spawn a chaffing goroutine for each Conn
|
||||||
func (hc *Conn) chaffHelper() {
|
func (hc *Conn) chaffHelper() {
|
||||||
go func() {
|
go func() {
|
||||||
|
var nextDuration int
|
||||||
for {
|
for {
|
||||||
var nextDuration int
|
//logger.LogDebug(fmt.Sprintf("[chaffHelper Loop]\n"))
|
||||||
if hc.chaff.enabled {
|
hc.Lock()
|
||||||
|
shutdown := hc.chaff.shutdown
|
||||||
|
hc.Unlock()
|
||||||
|
if !shutdown {
|
||||||
var bufTmp []byte
|
var bufTmp []byte
|
||||||
bufTmp = make([]byte, rand.Intn(int(hc.chaff.szMax)))
|
bufTmp = make([]byte, rand.Intn(int(hc.chaff.szMax)))
|
||||||
min := int(hc.chaff.msecsMin)
|
min := int(hc.chaff.msecsMin)
|
||||||
nextDuration = rand.Intn(int(hc.chaff.msecsMax)-min) + min
|
nextDuration = rand.Intn(int(hc.chaff.msecsMax)-min) + min
|
||||||
_, _ = rand.Read(bufTmp)
|
_, _ = rand.Read(bufTmp)
|
||||||
|
//logger.LogDebug("[+chaffHelper]")
|
||||||
_, err := hc.WritePacket(bufTmp, CSOChaff)
|
_, err := hc.WritePacket(bufTmp, CSOChaff)
|
||||||
|
//logger.LogDebug("[-chaffHelper]")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[ *** error - chaffHelper quitting *** ]")
|
log.Println("[ *** error - chaffHelper shutting down *** ]")
|
||||||
hc.chaff.enabled = false
|
hc.Lock()
|
||||||
|
hc.chaff.shutdown = true
|
||||||
|
hc.Unlock()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
time.Sleep(time.Duration(nextDuration) * time.Millisecond)
|
log.Println("[ *** chaffHelper shutting down *** ]")
|
||||||
if hc.chaff.shutdown {
|
break
|
||||||
log.Println("*** chaffHelper shutting down")
|
}
|
||||||
|
time.Sleep(time.Duration(nextDuration) * time.Millisecond)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) StartupKeepAlive() {
|
||||||
|
hc.ResetKeepAlive()
|
||||||
|
log.Println("KeepAlive ENABLED")
|
||||||
|
hc.keepaliveHelper()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) ShutdownKeepAlive() {
|
||||||
|
log.Println("Conn SHUTDOWN")
|
||||||
|
hc.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) ResetKeepAlive() {
|
||||||
|
hc.Lock()
|
||||||
|
hc.keepalive = 3
|
||||||
|
hc.Unlock()
|
||||||
|
log.Println("KeepAlive RESET")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper routine to spawn a keepalive goroutine for each Conn
|
||||||
|
func (hc *Conn) keepaliveHelper() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
nextDuration := 10000
|
||||||
|
bufTmp := []byte{0x55, 0xaa}
|
||||||
|
//logger.LogDebug("[+keepaliveHelper]")
|
||||||
|
_, err := hc.WritePacket(bufTmp, CSOKeepAlive)
|
||||||
|
//logger.LogDebug("[-keepaliveHelper]")
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[keepalive]\n"))
|
||||||
|
if err != nil {
|
||||||
|
logger.LogDebug(fmt.Sprintf("[ *** error - keepaliveHelper quitting *** ]\n"))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(nextDuration) * time.Millisecond)
|
||||||
|
hc.Lock()
|
||||||
|
hc.keepalive -= 1
|
||||||
|
hc.Unlock()
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[keepAlive is now %d]\n", hc.keepalive))
|
||||||
|
|
||||||
|
//if rand.Intn(8) == 0 {
|
||||||
|
// hc.keepalive = 0
|
||||||
|
//}
|
||||||
|
|
||||||
|
if hc.keepalive == 0 {
|
||||||
|
logger.LogDebug(fmt.Sprintf("*** keepaliveHelper shutting down\n"))
|
||||||
|
hc.SetStatus(CSEConnDead)
|
||||||
|
hc.ShutdownKeepAlive()
|
||||||
|
if hc.Pproc != 0 {
|
||||||
|
//fmt.Printf("[pid %d needs to be killed]\n", hc.Pproc)
|
||||||
|
syscall.Kill(hc.Pproc, syscall.SIGABRT) //nolint:errcheck
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ type (
|
||||||
// client starts worker to receive/send data using lport
|
// client starts worker to receive/send data using lport
|
||||||
// ... client disconnects: sends remhost [CSOTunClose:rport]
|
// ... client disconnects: sends remhost [CSOTunClose:rport]
|
||||||
// ... or server disconnects: sends client [CSOTunClose:lport]
|
// ... or server disconnects: sends client [CSOTunClose:lport]
|
||||||
|
// ... or server disconnects: due to client failing to send TunKeepAlive
|
||||||
|
// events for too long
|
||||||
// server at any time sends [CSOTunRefused:rport] if daemon died
|
// server at any time sends [CSOTunRefused:rport] if daemon died
|
||||||
// --
|
// --
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Util to generate/store passwords for users in a file akin to /etc/passwd
|
// Util to generate/store passwords for users in a file akin to /etc/passwd
|
||||||
// suitable for the demo hkexsh server, using bcrypt.
|
// suitable for the xs server, using bcrypt.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017-2020 Russell Magee
|
// Copyright (c) 2017-2020 Russell Magee
|
||||||
// Licensed under the terms of the MIT license (see LICENSE.mit in this
|
// Licensed under the terms of the MIT license (see LICENSE.mit in this
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue