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 <rmagee@gmail.com>
This commit is contained in:
Russ Magee 2019-08-13 20:54:58 -07:00
parent c9d478ff30
commit d7dbcd8fdf
3 changed files with 68 additions and 21 deletions

View File

@ -25,6 +25,7 @@ package hkexnet
import ( import (
"bytes" "bytes"
"crypto/cipher" "crypto/cipher"
"crypto/sha1"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors" "errors"
@ -40,6 +41,9 @@ import (
"sync" "sync"
"time" "time"
kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2"
hkex "blitter.com/go/herradurakex" hkex "blitter.com/go/herradurakex"
"blitter.com/go/hkexsh/logger" "blitter.com/go/hkexsh/logger"
kyber "git.schwanenlied.me/yawning/kyber.git" 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) Init(false, "client", logger.LOG_DAEMON|logger.LOG_DEBUG)
} }
// Open raw Conn c var c net.Conn
c, err := net.Dial(protocol, ipport) if protocol == "kcp" {
if err != nil { kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New)
return Conn{}, err 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 // Init hkexnet.Conn hc over net.Conn c
ret, err := _new(getkexalgnum(extensions...), &c) ret, err := _new(getkexalgnum(extensions...), &c)
if err != nil { if err != nil {
@ -819,23 +832,35 @@ func (hc *Conn) SetReadDeadline(t time.Time) error {
// //
// See go doc net.Listener // See go doc net.Listener
type HKExListener struct { type HKExListener struct {
l net.Listener l net.Listener
proto string
} }
// Listen for a connection // Listen for a connection
// //
// See go doc net.Listen // 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 { if Log == nil {
Init(false, "server", logger.LOG_DAEMON|logger.LOG_DEBUG) Init(false, "server", logger.LOG_DAEMON|logger.LOG_DEBUG)
} }
l, err := net.Listen(protocol, ipport) kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New)
if err != nil { //var block kcp.BlockCrypt
return HKExListener{nil}, err 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.l = l
hl.proto = proto
return return
} }
@ -859,13 +884,23 @@ func (hl HKExListener) Addr() net.Addr {
// //
// See go doc net.Listener.Accept // See go doc net.Listener.Accept
func (hl *HKExListener) Accept() (hc Conn, err error) { func (hl *HKExListener) Accept() (hc Conn, err error) {
// Open raw Conn c var c net.Conn
c, err := hl.l.Accept() if hl.proto == "kcp" {
if err != nil { c, err = hl.l.(*kcp.Listener).AcceptKCP()
return Conn{}, err if err != nil {
} return Conn{}, err
logger.LogDebug(fmt.Sprintln("[net.Listener Accepted]")) }
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 // Read KEx alg proposed by client
var kexAlg KEXAlg var kexAlg KEXAlg
//! NB. Was using fmt.FScanln() here, but integers with a leading zero //! NB. Was using fmt.FScanln() here, but integers with a leading zero

View File

@ -46,6 +46,9 @@ var (
// wg controls when the goroutines handling client I/O complete // wg controls when the goroutines handling client I/O complete
wg sync.WaitGroup wg sync.WaitGroup
kopt bool // set to use kcp (encrypted reliable UDP) instead of TCP
// Log defaults to regular syslog output (no -d) // Log defaults to regular syslog output (no -d)
Log *logger.Writer 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(&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(&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.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.UintVar(&port, "p", 2000, "`port`")
//flag.StringVar(&authCookie, "a", "", "auth cookie") //flag.StringVar(&authCookie, "a", "", "auth cookie")
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") 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 { if err != nil {
fmt.Println(err) fmt.Println(err)
exitWithStatus(3) exitWithStatus(3)

View File

@ -39,6 +39,7 @@ var (
gitCommit string // set in -ldflags by build gitCommit string // set in -ldflags by build
useSysLogin bool useSysLogin bool
kopt bool // set to use kcp (encrypted reliable UDP) instead of TCP
// Log - syslog output (with no -d) // Log - syslog output (with no -d)
Log *logger.Writer Log *logger.Writer
@ -443,6 +444,7 @@ func main() {
flag.BoolVar(&vopt, "v", false, "show version") flag.BoolVar(&vopt, "v", false, "show version")
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") 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(&useSysLogin, "L", false, "use system login")
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)") 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 proto := "tcp"
// anycast IP addresses of the local system. if kopt {
l, err := hkexnet.Listen("tcp", laddr) proto = "kcp"
}
l, err := hkexnet.Listen(proto, laddr)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }