mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			Implemented rekeying (-r secs)
This commit is contained in:
		
							parent
							
								
									c569a5a3c9
								
							
						
					
					
						commit
						08a9c8ab40
					
				
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
VERSION := 0.9.5.6-rc
 | 
			
		||||
VERSION := 0.9.5.7-rc
 | 
			
		||||
.PHONY: lint vis clean common client server passwd\
 | 
			
		||||
 subpkgs install uninstall reinstall scc
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								xs/xs.go
								
								
								
								
							
							
						
						
									
										6
									
								
								xs/xs.go
								
								
								
								
							| 
						 | 
				
			
			@ -701,7 +701,7 @@ func main() { //nolint: funlen, gocyclo
 | 
			
		|||
		port          uint
 | 
			
		||||
		cmdStr        string
 | 
			
		||||
		tunSpecStr    string // lport1:rport1[,lport2:rport2,...]
 | 
			
		||||
 | 
			
		||||
		rekeySecs     uint
 | 
			
		||||
		copySrc       []byte
 | 
			
		||||
		copyDst       string
 | 
			
		||||
		copyQuiet     bool
 | 
			
		||||
| 
						 | 
				
			
			@ -746,6 +746,7 @@ func main() { //nolint: funlen, gocyclo
 | 
			
		|||
      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(&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,8 +57,8 @@ 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								xsnet/net.go
								
								
								
								
							
							
						
						
									
										63
									
								
								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,13 @@ 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
 | 
			
		||||
				//fmt.Printf("rekeyData:%v\n", rekeyData)
 | 
			
		||||
				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 +1469,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 +1508,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 +1565,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 +1596,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 +1642,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 +1681,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