From d7dbcd8fdf3bec4f4eba42d42b4b65d812279672 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Tue, 13 Aug 2019 20:54:58 -0700 Subject: [PATCH] Added experimental support (-K) for kcp-go reliable-UDP instead of TCP github.com/xtaci/kcp-go ** Note: hkexcp appears to hang (client-side) on completion w/complete file copy (Note server-side logs on final missed ctrlStatOp msg) Signed-off-by: Russ Magee --- hkexnet/hkexnet.go | 69 ++++++++++++++++++++++++++++++++++------------ hkexsh/hkexsh.go | 10 ++++++- hkexshd/hkexshd.go | 10 +++++-- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index 91d8c4e..c557589 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -25,6 +25,7 @@ package hkexnet import ( "bytes" "crypto/cipher" + "crypto/sha1" "encoding/binary" "encoding/hex" "errors" @@ -40,6 +41,9 @@ import ( "sync" "time" + kcp "github.com/xtaci/kcp-go" + "golang.org/x/crypto/pbkdf2" + hkex "blitter.com/go/herradurakex" "blitter.com/go/hkexsh/logger" kyber "git.schwanenlied.me/yawning/kyber.git" @@ -693,12 +697,21 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er Init(false, "client", logger.LOG_DAEMON|logger.LOG_DEBUG) } - // Open raw Conn c - c, err := net.Dial(protocol, ipport) - if err != nil { - return Conn{}, err + var c net.Conn + if protocol == "kcp" { + kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) + block, _ := kcp.NewNoneBlockCrypt(kcpKey) + c, err = kcp.DialWithOptions(ipport, block, 10, 3) + if err != nil { + return Conn{}, err + } + } else { + // Open raw Conn c + c, err = net.Dial(protocol, ipport) + if err != nil { + return Conn{}, err + } } - // Init hkexnet.Conn hc over net.Conn c ret, err := _new(getkexalgnum(extensions...), &c) if err != nil { @@ -819,23 +832,35 @@ func (hc *Conn) SetReadDeadline(t time.Time) error { // // See go doc net.Listener type HKExListener struct { - l net.Listener + l net.Listener + proto string } // Listen for a connection // // See go doc net.Listen -func Listen(protocol string, ipport string) (hl HKExListener, e error) { +func Listen(proto string, ipport string) (hl HKExListener, e error) { if Log == nil { Init(false, "server", logger.LOG_DAEMON|logger.LOG_DEBUG) } - l, err := net.Listen(protocol, ipport) - if err != nil { - return HKExListener{nil}, err + kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) + //var block kcp.BlockCrypt + var lErr error + var l net.Listener + + if proto == "kcp" { + block, _ := kcp.NewNoneBlockCrypt(kcpKey) + l, lErr = kcp.ListenWithOptions(ipport, block, 10, 3) + } else { + l, lErr = net.Listen(proto, ipport) } - logger.LogDebug(fmt.Sprintf("[Listening on %s]\n", ipport)) + if lErr != nil { + return HKExListener{nil, proto}, lErr + } + logger.LogDebug(fmt.Sprintf("[Listening (proto '%s') on %s]\n", proto, ipport)) hl.l = l + hl.proto = proto return } @@ -859,13 +884,23 @@ func (hl HKExListener) Addr() net.Addr { // // See go doc net.Listener.Accept func (hl *HKExListener) Accept() (hc Conn, err error) { - // Open raw Conn c - c, err := hl.l.Accept() - if err != nil { - return Conn{}, err - } - logger.LogDebug(fmt.Sprintln("[net.Listener Accepted]")) + var c net.Conn + if hl.proto == "kcp" { + c, err = hl.l.(*kcp.Listener).AcceptKCP() + if err != nil { + return Conn{}, err + } + logger.LogDebug(fmt.Sprintln("[kcp.Listener Accepted]")) + } else { + // Open raw Conn c + c, err = hl.l.Accept() + if err != nil { + return Conn{}, err + } + + logger.LogDebug(fmt.Sprintln("[net.Listener Accepted]")) + } // Read KEx alg proposed by client var kexAlg KEXAlg //! NB. Was using fmt.FScanln() here, but integers with a leading zero diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index d8a7f13..597559e 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -46,6 +46,9 @@ var ( // wg controls when the goroutines handling client I/O complete wg sync.WaitGroup + + kopt bool // set to use kcp (encrypted reliable UDP) instead of TCP + // Log defaults to regular syslog output (no -d) Log *logger.Writer @@ -624,6 +627,7 @@ func main() { flag.StringVar(&cipherAlg, "c", "C_AES_256", "`cipher` [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\" | \"C_CRYPTMT1\"]") flag.StringVar(&hmacAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\" | \"H_SHA512\"]") flag.StringVar(&kexAlg, "k", "KEX_HERRADURA512", "`kex` [\"KEX_HERRADURA{256/512/1024/2048}\" | \"KEX_KYBER{512/768/1024}\" | \"KEX_NEWHOPE\" | \"KEX_NEWHOPE_SIMPLE\"]") + flag.BoolVar(&kopt, "K", false, "set true to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") flag.UintVar(&port, "p", 2000, "`port`") //flag.StringVar(&authCookie, "a", "", "auth cookie") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") @@ -818,7 +822,11 @@ func main() { } } - conn, err := hkexnet.Dial("tcp", server, cipherAlg, hmacAlg, kexAlg) + proto := "tcp" + if kopt { + proto = "kcp" + } + conn, err := hkexnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg) if err != nil { fmt.Println(err) exitWithStatus(3) diff --git a/hkexshd/hkexshd.go b/hkexshd/hkexshd.go index 05aa355..b4ae354 100755 --- a/hkexshd/hkexshd.go +++ b/hkexshd/hkexshd.go @@ -39,6 +39,7 @@ var ( gitCommit string // set in -ldflags by build useSysLogin bool + kopt bool // set to use kcp (encrypted reliable UDP) instead of TCP // Log - syslog output (with no -d) Log *logger.Writer @@ -443,6 +444,7 @@ func main() { flag.BoolVar(&vopt, "v", false, "show version") flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") + flag.BoolVar(&kopt, "K", false, "set true to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") flag.BoolVar(&useSysLogin, "L", false, "use system login") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min (msecs)") @@ -505,9 +507,11 @@ func main() { } }() - // Listen on TCP port 2000 on all available unicast and - // anycast IP addresses of the local system. - l, err := hkexnet.Listen("tcp", laddr) + proto := "tcp" + if kopt { + proto = "kcp" + } + l, err := hkexnet.Listen(proto, laddr) if err != nil { log.Fatal(err) }