Compare commits

...

37 commits

Author SHA1 Message Date
Russ Magee
12409319e7 Removed go.mod, go.sum 2024-07-15 02:06:26 -07:00
Russtopia
bfcd097a14 Bump version to v0.9.11 2024-05-02 00:48:50 -07:00
Russtopia
136f37e209 Update 'README.md' 2024-05-01 23:58:44 -07:00
Russtopia
ec9b4fe2f4 Merge branch 'whirlpool-hash' of RLabs/xs into master 2024-05-01 23:49:36 -07:00
Russtopia
aa33a3b8a0 Merge branch 'log-listener-ipaddr' of RLabs/xs into master 2024-05-01 23:48:18 -07:00
Russ Magee
7e4aeba93a Add remote IP to net.Listener Accept logmsg 2024-05-01 23:46:43 -07:00
Russ Magee
91bb0778b2 Addition of WHIRLPOOL hash 2024-05-01 23:43:24 -07:00
Russ Magee
952279a108 Moved esc seq table out of copyBuffer to avoid redecls 2024-04-27 22:01:43 -07:00
Russ Magee
dbaa8b5b62 Ensure auth fails if server is somehow built for unsupported platform 2024-03-30 00:48:46 -07:00
Russ Magee
77c9b8654f Left GOPROXY alone 2024-03-02 14:46:15 -08:00
Russ Magee
e42645a2b3 Refreshed go.{mod,sum} and bumped semver in Makefile 2024-03-01 23:34:14 -08:00
Russ Magee
057a3c01c7 Updated go.{mod,sum} 2024-02-25 21:14:20 -08:00
Russ Magee
540cb8ff3a gofmt 2024-02-25 21:14:00 -08:00
Russ Magee
ae67ee6201 Fixed CI script 2024-01-29 21:47:03 -08:00
Russ Magee
8827d67cc6 unified refs to authtoken file to a const string 2024-01-29 21:37:07 -08:00
Russtopia
17d7bc01ef Update 'README.md'
Updated references to .xs_id location
2024-01-29 19:03:13 -08:00
Russ Magee
89ad0e0998 Fixed missed authtoken file ref in auth.go 2024-01-29 18:56:21 -08:00
Russ Magee
713f44086a Bumped version 2024-01-29 18:43:24 -08:00
Russ Magee
08cccb6929 Moved .xs_id to ~/.config/xs 2024-01-29 18:40:26 -08:00
Russ Magee
6212119621 Added max bounds for chaff, rekey intervals and random jitter for rekey interval 2023-12-03 19:22:05 -08:00
Russtopia
faf8769ac4 Merge branch 'remodulate-on-rekey' of RLabs/xs into master
Add optional cipher/hmac algo remodulate on rekey
2023-12-02 02:00:17 -08:00
Russ Magee
32b669192b Add optional cipher/hmac algo remodulate on rekey 2023-12-02 01:58:30 -08:00
Russtopia
e82d968381 Merge branch 'rekeying' of RLabs/xs into master 2023-11-15 00:43:36 -08:00
Russ Magee
032baf63d6 Added rekeying (-r secs) client/server 2023-11-15 00:32:50 -08:00
Russ Magee
c569a5a3c9 Removed debug stmts to do with keepalive 2023-11-07 00:38:51 -08:00
Russtopia
36799ba9e7 Merge branch 'conn-keepalive' of RLabs/xs into master
Merge of branch conn-keepalive
2023-11-06 23:48:51 -08:00
Russ Magee
f0dc681a4c Merge branch 'master' into conn-keepalive 2023-11-06 23:41:59 -08:00
Russ Magee
871f9a200c Experimental dead conn process kill logic 2023-11-06 23:17:13 -08:00
Russ Magee
908a1bcda2 Fix for ConnDead status 2023-11-06 21:57:19 -08:00
Russ Magee
39a8bd2f03 Bump 2023-11-05 19:05:23 -08:00
Russ Magee
9244cc9785 KeepAlive WIP. TODO: check exitStatus logic for shell 'exit' clean exit 2023-11-05 18:53:49 -08:00
Russ Magee
d0f8751b2b debugging 2023-11-05 16:40:12 -08:00
Russ Magee
a3d8543816 Disabled test code 2023-11-05 15:08:31 -08:00
Russ Magee
bcea6d713f Connection keepalive/disconnect 2023-11-05 15:06:43 -08:00
Russ Magee
580053adbd Connection keepalive/disconnect 2023-11-05 14:58:24 -08:00
Russ Magee
74be6173b6 Comment cleanup 2023-11-03 23:57:55 -07:00
Russ Magee
119c039b91 Fixed up mentions of old name hkexsh 2023-10-18 00:52:08 -07:00
14 changed files with 459 additions and 354 deletions

View file

@ -1,4 +1,4 @@
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
@ -73,7 +73,7 @@ tools:
common: common:
$(GO) build . $(GO) build .
go install . go install -a .
client: common client: common

View file

@ -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

View file

@ -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
} }

View file

@ -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
View file

@ -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
View file

@ -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=

View file

@ -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

View file

@ -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)
@ -699,7 +704,8 @@ func main() { //nolint: funlen, gocyclo
port uint port uint
cmdStr string cmdStr string
tunSpecStr string // lport1:rport1[,lport2:rport2,...] tunSpecStr string // lport1:rport1[,lport2:rport2,...]
rekeySecs uint
remodRequested bool // true: when rekeying, switch to random cipher/hmac alg
copySrc []byte copySrc []byte
copyDst string copyDst string
copyQuiet bool copyQuiet 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)
} }

View file

@ -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)
}

View file

@ -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)

View file

@ -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"

View file

@ -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,6 +87,9 @@ type (
Rows uint16 Rows uint16
Cols uint16 Cols uint16
keepalive uint // if this reaches zero, conn is considered dead
rekey uint // if nonzero, rekeying interval in seconds
Pproc int // proc ID of command run on this conn
chaff ChaffConfig chaff ChaffConfig
tuns *map[uint16](*TunEndpoint) tuns *map[uint16](*TunEndpoint)
@ -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)
} }
@ -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() {
for {
var nextDuration int var nextDuration int
if hc.chaff.enabled { for {
//logger.LogDebug(fmt.Sprintf("[chaffHelper Loop]\n"))
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 {
log.Println("[ *** chaffHelper shutting down *** ]")
break
} }
time.Sleep(time.Duration(nextDuration) * time.Millisecond) time.Sleep(time.Duration(nextDuration) * time.Millisecond)
if hc.chaff.shutdown { }
log.Println("*** chaffHelper shutting down") }()
break }
}
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
}
} }
}() }()
} }

View file

@ -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
// -- // --

View file

@ -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