mirror of https://gogs.blitter.com/RLabs/xs
Added rekeying (-r secs) client/server
This commit is contained in:
parent
c569a5a3c9
commit
032baf63d6
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\
|
||||
subpkgs install uninstall reinstall scc
|
||||
|
||||
|
|
16
xs/xs.go
16
xs/xs.go
|
@ -701,11 +701,11 @@ func main() { //nolint: funlen, gocyclo
|
|||
port uint
|
||||
cmdStr string
|
||||
tunSpecStr string // lport1:rport1[,lport2:rport2,...]
|
||||
|
||||
copySrc []byte
|
||||
copyDst string
|
||||
copyQuiet bool
|
||||
copyLimitBPS uint
|
||||
rekeySecs uint
|
||||
copySrc []byte
|
||||
copyDst string
|
||||
copyQuiet bool
|
||||
copyLimitBPS uint
|
||||
|
||||
authCookie string
|
||||
chaffEnabled bool
|
||||
|
@ -745,7 +745,8 @@ func main() { //nolint: funlen, gocyclo
|
|||
KEX_FRODOKEM_976AES
|
||||
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.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")
|
||||
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
|
||||
flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`") //nolint:gomnd
|
||||
|
@ -972,6 +973,9 @@ func main() { //nolint: funlen, gocyclo
|
|||
exitWithStatus(XSNetDialFailed)
|
||||
}
|
||||
|
||||
conn.RekeyHelper(rekeySecs)
|
||||
defer conn.ShutdownRekey()
|
||||
|
||||
// === Shell terminal mode (Shell vs. Copy) setup
|
||||
|
||||
// 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 dbg bool
|
||||
var laddr string
|
||||
var rekeySecs uint
|
||||
|
||||
var useSystemPasswd bool
|
||||
|
||||
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.BoolVar(&useSysLogin, "L", false, "use system login")
|
||||
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
|
||||
|
@ -646,22 +648,22 @@ func main() { //nolint:funlen,gocyclo
|
|||
go func() {
|
||||
for {
|
||||
sig := <-exitCh
|
||||
switch sig.String() {
|
||||
case "terminated":
|
||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig)) //nolint:errcheck
|
||||
switch sig {
|
||||
case syscall.SIGTERM: //"terminated":
|
||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig.String())) //nolint:errcheck
|
||||
signal.Reset()
|
||||
syscall.Kill(0, syscall.SIGTERM) //nolint:errcheck
|
||||
case "interrupt":
|
||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig)) //nolint:errcheck
|
||||
case syscall.SIGINT: //"interrupt":
|
||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig.String())) //nolint:errcheck
|
||||
signal.Reset()
|
||||
syscall.Kill(0, syscall.SIGINT) //nolint:errcheck
|
||||
case "hangup":
|
||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s - nop]", sig)) //nolint:errcheck
|
||||
case syscall.SIGHUP: //"hangup":
|
||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s - nop]", sig.String())) //nolint:errcheck
|
||||
if cpuprofile != "" || memprofile != "" {
|
||||
dumpProf()
|
||||
}
|
||||
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 {
|
||||
log.Println("Accepted client")
|
||||
|
||||
conn.RekeyHelper(rekeySecs)
|
||||
|
||||
// Set up chaffing to client
|
||||
// Will only start when runShellAs() is called
|
||||
// after stdin/stdout are hooked up
|
||||
|
@ -709,6 +713,7 @@ func main() { //nolint:funlen,gocyclo
|
|||
// The loop then returns to accepting, so that
|
||||
// multiple connections may be served concurrently.
|
||||
go func(hc *xsnet.Conn) (e error) {
|
||||
defer hc.ShutdownRekey()
|
||||
defer hc.Close()
|
||||
|
||||
// Start login timeout here and disconnect if user/pass phase stalls
|
||||
|
|
|
@ -57,9 +57,9 @@ func expandKeyMat(keymat []byte, blocksize int) []byte {
|
|||
return keymat
|
||||
}
|
||||
|
||||
/* Support functionality to set up encryption after a channel has
|
||||
been negotiated via xsnet.go
|
||||
*/
|
||||
/* (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) {
|
||||
var key []byte
|
||||
var block cipher.Block
|
||||
|
|
|
@ -78,6 +78,7 @@ const (
|
|||
CSOTunDisconn // server -> client: tunnel rport disconnected
|
||||
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
|
||||
|
|
62
xsnet/net.go
62
xsnet/net.go
|
@ -88,6 +88,7 @@ type (
|
|||
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
|
||||
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)
|
||||
_ = 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
|
||||
hc.r, hc.rm, err = hc.getStream(rekeyData)
|
||||
case CSOTermSize:
|
||||
fmt.Sscanf(string(payloadBytes), "%d %d", &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
|
||||
//
|
||||
// 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)
|
||||
//logger.LogDebug("[-Write]")
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Write a byte slice with specified ctrlStatOp byte
|
||||
func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) {
|
||||
hc.Lock()
|
||||
defer hc.Unlock()
|
||||
|
||||
//log.Printf("[Encrypting...]\r\n")
|
||||
var hmacOut []uint8
|
||||
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...)...)...)
|
||||
}
|
||||
|
||||
// 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))
|
||||
if hc.logPlainText {
|
||||
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 {
|
||||
//fmt.Println("[a]WriteError!")
|
||||
}
|
||||
hc.Unlock()
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@ -1593,6 +1595,40 @@ func (hc *Conn) SetupChaff(msecsMin uint, msecsMax uint, szMax uint) {
|
|||
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
|
||||
func (hc *Conn) chaffHelper() {
|
||||
go func() {
|
||||
|
@ -1605,7 +1641,9 @@ func (hc *Conn) chaffHelper() {
|
|||
min := int(hc.chaff.msecsMin)
|
||||
nextDuration = rand.Intn(int(hc.chaff.msecsMax)-min) + min
|
||||
_, _ = rand.Read(bufTmp)
|
||||
//logger.LogDebug("[+chaffHelper]")
|
||||
_, err := hc.WritePacket(bufTmp, CSOChaff)
|
||||
//logger.LogDebug("[-chaffHelper]")
|
||||
if err != nil {
|
||||
log.Println("[ *** error - chaffHelper shutting down *** ]")
|
||||
hc.chaff.shutdown = true
|
||||
|
@ -1642,7 +1680,9 @@ func (hc *Conn) keepaliveHelper() {
|
|||
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"))
|
||||
|
|
Loading…
Reference in New Issue