mirror of https://gogs.blitter.com/RLabs/xs
Merge branch 'rekeying' of RLabs/xs into master
This commit is contained in:
commit
e82d968381
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
||||||
VERSION := 0.9.5.6-rc
|
VERSION := 0.9.6
|
||||||
.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
|
||||||
|
|
||||||
|
|
16
xs/xs.go
16
xs/xs.go
|
@ -701,11 +701,11 @@ 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
|
||||||
copySrc []byte
|
copySrc []byte
|
||||||
copyDst string
|
copyDst string
|
||||||
copyQuiet bool
|
copyQuiet bool
|
||||||
copyLimitBPS uint
|
copyLimitBPS uint
|
||||||
|
|
||||||
authCookie string
|
authCookie string
|
||||||
chaffEnabled bool
|
chaffEnabled bool
|
||||||
|
@ -745,7 +745,8 @@ func main() { //nolint: funlen, gocyclo
|
||||||
KEX_FRODOKEM_976AES
|
KEX_FRODOKEM_976AES
|
||||||
KEX_FRODOKEM_976SHAKE`)
|
KEX_FRODOKEM_976SHAKE`)
|
||||||
flag.StringVar(&kcpMode, "K", "unused", "KCP `alg`, one of [KCP_NONE | KCP_AES | KCP_BLOWFISH | KCP_CAST5 | KCP_SM4 | KCP_SALSA20 | KCP_SIMPLEXOR | KCP_TEA | KCP_3DES | KCP_TWOFISH | KCP_XTEA] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") //nolint:lll
|
flag.StringVar(&kcpMode, "K", "unused", "KCP `alg`, one of [KCP_NONE | KCP_AES | KCP_BLOWFISH | KCP_CAST5 | KCP_SM4 | KCP_SALSA20 | KCP_SIMPLEXOR | KCP_TEA | KCP_3DES | KCP_TWOFISH | KCP_XTEA] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") //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`")
|
||||||
//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
|
||||||
|
@ -972,6 +973,9 @@ func main() { //nolint: funlen, gocyclo
|
||||||
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
|
||||||
|
|
23
xsd/xsd.go
23
xsd/xsd.go
|
@ -529,11 +529,13 @@ 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 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.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")
|
||||||
|
@ -646,22 +648,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 != "" {
|
if cpuprofile != "" || memprofile != "" {
|
||||||
dumpProf()
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -700,6 +702,8 @@ func main() { //nolint:funlen,gocyclo
|
||||||
} else {
|
} else {
|
||||||
log.Println("Accepted client")
|
log.Println("Accepted client")
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -709,6 +713,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
|
||||||
|
|
|
@ -57,9 +57,9 @@ func expandKeyMat(keymat []byte, blocksize int) []byte {
|
||||||
return keymat
|
return keymat
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Support functionality to set up encryption after a channel has
|
/* (Re-)initialize the keystream and hmac state for an xsnet.Conn, returning
|
||||||
been negotiated via xsnet.go
|
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
|
||||||
|
|
|
@ -78,6 +78,7 @@ const (
|
||||||
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
|
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
|
||||||
|
|
62
xsnet/net.go
62
xsnet/net.go
|
@ -88,6 +88,7 @@ type (
|
||||||
Cols uint16
|
Cols uint16
|
||||||
|
|
||||||
keepalive uint // if this reaches zero, conn is considered dead
|
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
|
Pproc int // proc ID of command run on this conn
|
||||||
chaff ChaffConfig
|
chaff ChaffConfig
|
||||||
tuns *map[uint16](*TunEndpoint)
|
tuns *map[uint16](*TunEndpoint)
|
||||||
|
@ -1345,6 +1346,12 @@ func (hc *Conn) Read(b []byte) (n int, err error) {
|
||||||
// payload of keepalive (2 bytes) is not currently used (0x55aa fixed)
|
// payload of keepalive (2 bytes) is not currently used (0x55aa fixed)
|
||||||
_ = binary.BigEndian.Uint16(payloadBytes[0:2])
|
_ = binary.BigEndian.Uint16(payloadBytes[0:2])
|
||||||
hc.ResetKeepAlive()
|
hc.ResetKeepAlive()
|
||||||
|
case CSORekey:
|
||||||
|
// rekey
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[Got rekey [%02x %02x %02x ...]\n",
|
||||||
|
// payloadBytes[0], payloadBytes[1], payloadBytes[2]))
|
||||||
|
rekeyData := payloadBytes
|
||||||
|
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)
|
||||||
|
@ -1461,13 +1468,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
|
||||||
|
@ -1495,15 +1507,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]))
|
||||||
|
@ -1561,7 +1564,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)
|
||||||
|
@ -1593,6 +1595,40 @@ func (hc *Conn) SetupChaff(msecsMin uint, msecsMax uint, szMax uint) {
|
||||||
hc.chaff.szMax = szMax
|
hc.chaff.szMax = szMax
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) ShutdownRekey() {
|
||||||
|
hc.rekey = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *Conn) RekeyHelper(intervalSecs uint) {
|
||||||
|
go func() {
|
||||||
|
hc.rekey = intervalSecs
|
||||||
|
for {
|
||||||
|
if hc.rekey != 0 {
|
||||||
|
//logger.LogDebug(fmt.Sprintf("[rekeyHelper Loop]\n"))
|
||||||
|
time.Sleep(time.Duration(hc.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()
|
||||||
|
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() {
|
||||||
|
@ -1605,7 +1641,9 @@ func (hc *Conn) chaffHelper() {
|
||||||
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 shutting down *** ]")
|
log.Println("[ *** error - chaffHelper shutting down *** ]")
|
||||||
hc.chaff.shutdown = true
|
hc.chaff.shutdown = true
|
||||||
|
@ -1642,7 +1680,9 @@ func (hc *Conn) keepaliveHelper() {
|
||||||
for {
|
for {
|
||||||
nextDuration := 10000
|
nextDuration := 10000
|
||||||
bufTmp := []byte{0x55, 0xaa}
|
bufTmp := []byte{0x55, 0xaa}
|
||||||
|
//logger.LogDebug("[+keepaliveHelper]")
|
||||||
_, err := hc.WritePacket(bufTmp, CSOKeepAlive)
|
_, err := hc.WritePacket(bufTmp, CSOKeepAlive)
|
||||||
|
//logger.LogDebug("[-keepaliveHelper]")
|
||||||
//logger.LogDebug(fmt.Sprintf("[keepalive]\n"))
|
//logger.LogDebug(fmt.Sprintf("[keepalive]\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogDebug(fmt.Sprintf("[ *** error - keepaliveHelper quitting *** ]\n"))
|
logger.LogDebug(fmt.Sprintf("[ *** error - keepaliveHelper quitting *** ]\n"))
|
||||||
|
|
Loading…
Reference in New Issue