From fc48a15438f817aeacdcfe6759c894555e710c1e Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Fri, 30 Apr 2021 22:58:58 +0900 Subject: [PATCH 01/21] =?UTF-8?q?refactor:=20encrypt=5Fduplex=20=E2=86=92?= =?UTF-8?q?=20aes=5Fctr=5Fduplex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aes_ctr.go => aes_ctr_duplex/aes_ctr_duplex.go | 4 ++-- cmd/shared.go | 4 ++-- pmux/pmux.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) rename crypto_duplex/aes_ctr.go => aes_ctr_duplex/aes_ctr_duplex.go (93%) diff --git a/crypto_duplex/aes_ctr.go b/aes_ctr_duplex/aes_ctr_duplex.go similarity index 93% rename from crypto_duplex/aes_ctr.go rename to aes_ctr_duplex/aes_ctr_duplex.go index fea4ab4..0d4eee1 100644 --- a/crypto_duplex/aes_ctr.go +++ b/aes_ctr_duplex/aes_ctr_duplex.go @@ -1,4 +1,4 @@ -package crypto_duplex +package aes_ctr_duplex import ( "crypto" @@ -19,7 +19,7 @@ type aesCtrDuplex struct { closeBaseReader func() error } -func EncryptDuplexWithAesCtr(baseWriter io.WriteCloser, baseReader io.ReadCloser, passphrase []byte) (*aesCtrDuplex, error) { +func Duplex(baseWriter io.WriteCloser, baseReader io.ReadCloser, passphrase []byte) (*aesCtrDuplex, error) { // Generate salt salt1, err := util.GenerateRandomBytes(saltLen) if err != nil { diff --git a/cmd/shared.go b/cmd/shared.go index b90f11d..cb5d313 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -2,7 +2,7 @@ package cmd import ( "fmt" - "github.com/nwtgck/go-piping-tunnel/crypto_duplex" + "github.com/nwtgck/go-piping-tunnel/aes_ctr_duplex" "github.com/nwtgck/go-piping-tunnel/io_progress" "github.com/nwtgck/go-piping-tunnel/openpgp_duplex" "github.com/nwtgck/go-piping-tunnel/piping_util" @@ -100,7 +100,7 @@ func makeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encryp switch cipherType { case piping_util.CipherTypeAesCtr: // Encrypt with AES-CTR - duplex, err = crypto_duplex.EncryptDuplexWithAesCtr(duplex, duplex, []byte(passphrase)) + duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(passphrase)) cipherName = "AES-CTR" case piping_util.CipherTypeOpenpgp: duplex, err = openpgp_duplex.SymmetricallyEncryptDuplexWithOpenPGP(duplex, duplex, []byte(passphrase)) diff --git a/pmux/pmux.go b/pmux/pmux.go index e732ae7..efa8303 100644 --- a/pmux/pmux.go +++ b/pmux/pmux.go @@ -7,8 +7,8 @@ import ( "encoding/binary" "encoding/json" "fmt" + "github.com/nwtgck/go-piping-tunnel/aes_ctr_duplex" "github.com/nwtgck/go-piping-tunnel/backoff" - "github.com/nwtgck/go-piping-tunnel/crypto_duplex" "github.com/nwtgck/go-piping-tunnel/early_piping_duplex" "github.com/nwtgck/go-piping-tunnel/hb_duplex" "github.com/nwtgck/go-piping-tunnel/openpgp_duplex" @@ -193,7 +193,7 @@ func (s *server) Accept() (io.ReadWriteCloser, error) { switch s.cipherType { case piping_util.CipherTypeAesCtr: // Encrypt with AES-CTR - duplex, err = crypto_duplex.EncryptDuplexWithAesCtr(duplex, duplex, []byte(s.passphrase)) + duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(s.passphrase)) case piping_util.CipherTypeOpenpgp: duplex, err = openpgp_duplex.SymmetricallyEncryptDuplexWithOpenPGP(duplex, duplex, []byte(s.passphrase)) default: @@ -329,7 +329,7 @@ func (c *client) Open() (io.ReadWriteCloser, error) { switch c.cipherType { case piping_util.CipherTypeAesCtr: // Encrypt with AES-CTR - duplex, err = crypto_duplex.EncryptDuplexWithAesCtr(duplex, duplex, []byte(c.passphrase)) + duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(c.passphrase)) case piping_util.CipherTypeOpenpgp: duplex, err = openpgp_duplex.SymmetricallyEncryptDuplexWithOpenPGP(duplex, duplex, []byte(c.passphrase)) default: From c5c393b2abe82bb1c9e04f613562e78fd54f63b9 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Fri, 30 Apr 2021 23:53:08 +0900 Subject: [PATCH 02/21] fix: return error when cipher-type is invalid --- cmd/client.go | 2 +- cmd/server.go | 2 +- cmd/socks.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/client.go b/cmd/client.go index c704bac..84d8a9c 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -47,7 +47,7 @@ var clientCmd = &cobra.Command{ // Validate cipher-type if clientSymmetricallyEncrypts { if err := validateClientCipher(clientCipherType); err != nil { - return nil + return err } } clientToServerPath, serverToClientPath, err := generatePaths(args) diff --git a/cmd/server.go b/cmd/server.go index 27c717e..8b78617 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -49,7 +49,7 @@ var serverCmd = &cobra.Command{ // Validate cipher-type if serverSymmetricallyEncrypts { if err := validateClientCipher(serverCipherType); err != nil { - return nil + return err } } clientToServerPath, serverToClientPath, err := generatePaths(args) diff --git a/cmd/socks.go b/cmd/socks.go index bdd8c11..aa3a7e3 100644 --- a/cmd/socks.go +++ b/cmd/socks.go @@ -39,7 +39,7 @@ var socksCmd = &cobra.Command{ // Validate cipher-type if socksSymmetricallyEncrypts { if err := validateClientCipher(socksCipherType); err != nil { - return nil + return err } } clientToServerPath, serverToClientPath, err := generatePaths(args) From 59cd1070d83f0503b14bb629f133fce7c4910915 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Fri, 30 Apr 2021 23:15:57 +0900 Subject: [PATCH 03/21] implement openssl-aes-ctr-compatible encryption duplex --- openssl_aes_ctr_duplex/openssl_aes_ctr.go | 71 +++++++++++++++++++ .../openssl_aes_ctr_duplex.go | 39 ++++++++++ 2 files changed, 110 insertions(+) create mode 100644 openssl_aes_ctr_duplex/openssl_aes_ctr.go create mode 100644 openssl_aes_ctr_duplex/openssl_aes_ctr_duplex.go diff --git a/openssl_aes_ctr_duplex/openssl_aes_ctr.go b/openssl_aes_ctr_duplex/openssl_aes_ctr.go new file mode 100644 index 0000000..12ef0c5 --- /dev/null +++ b/openssl_aes_ctr_duplex/openssl_aes_ctr.go @@ -0,0 +1,71 @@ +package openssl_aes_ctr_duplex + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "github.com/pkg/errors" + "golang.org/x/crypto/pbkdf2" + "hash" + "io" +) + +type KeyAndIV struct { + Key []byte + Iv []byte +} + +const ivLen = 16 + +func DeriveKeyAndIvByPbkdf2(password []byte, salt []byte, iter int, keyLen int, h func() hash.Hash) KeyAndIV { + keyAndIv := pbkdf2.Key(password, salt, iter, keyLen+ivLen, h) + return KeyAndIV{ + Key: keyAndIv[:keyLen], + Iv: keyAndIv[keyLen:], + } +} + +func AesCtrEncryptWithPbkdf2(w io.Writer, password []byte, pbkdf2Iter int, keyLen int, h func() hash.Hash) (io.WriteCloser, error) { + var salt [8]byte + if _, err := io.ReadFull(rand.Reader, salt[:]); err != nil { + return nil, err + } + keyAndIV := DeriveKeyAndIvByPbkdf2(password, salt[:], pbkdf2Iter, keyLen, h) + block, err := aes.NewCipher(keyAndIV.Key) + if err != nil { + return nil, err + } + if _, err := w.Write(append([]byte("Salted__"), salt[:]...)); err != nil { + return nil, err + } + encryptingWriter := &cipher.StreamWriter{ + S: cipher.NewCTR(block, keyAndIV.Iv), + W: w, + } + return encryptingWriter, nil +} + +func AesCtrDecryptWithPbkdf2(encryptedReader io.Reader, password []byte, pbkdf2Iter int, keyLen int, h func() hash.Hash) (io.Reader, error) { + var eightBytes [8]byte + if _, err := io.ReadFull(encryptedReader, eightBytes[:]); err != nil { + return nil, err + } + if string(eightBytes[:]) != "Salted__" { + return nil, errors.New("not start with Salted__") + } + // Read salt + if _, err := io.ReadFull(encryptedReader, eightBytes[:]); err != nil { + return nil, err + } + // Derive key and IV + keyAndIV := DeriveKeyAndIvByPbkdf2(password, eightBytes[:], pbkdf2Iter, keyLen, h) + block, err := aes.NewCipher(keyAndIV.Key) + if err != nil { + return nil, err + } + decryptedReader := &cipher.StreamReader{ + S: cipher.NewCTR(block, keyAndIV.Iv), + R: encryptedReader, + } + return decryptedReader, nil +} diff --git a/openssl_aes_ctr_duplex/openssl_aes_ctr_duplex.go b/openssl_aes_ctr_duplex/openssl_aes_ctr_duplex.go new file mode 100644 index 0000000..29ce7b1 --- /dev/null +++ b/openssl_aes_ctr_duplex/openssl_aes_ctr_duplex.go @@ -0,0 +1,39 @@ +package openssl_aes_ctr_duplex + +import ( + "github.com/nwtgck/go-piping-tunnel/util" + "hash" + "io" +) + +type opensslAesCtrDuplex struct { + encryptWriter io.WriteCloser + decryptedReader io.Reader + closeBaseReader func() error +} + +func Duplex(baseWriter io.WriteCloser, baseReader io.ReadCloser, passphrase []byte, pbkdf2Iter int, keyLen int, h func() hash.Hash) (*opensslAesCtrDuplex, error) { + encryptWriter, err := AesCtrEncryptWithPbkdf2(baseWriter, passphrase, pbkdf2Iter, keyLen, h) + if err != nil { + return nil, err + } + decryptedReader, err := AesCtrDecryptWithPbkdf2(baseReader, passphrase, pbkdf2Iter, keyLen, h) + if err != nil { + return nil, err + } + return &opensslAesCtrDuplex{encryptWriter: encryptWriter, decryptedReader: decryptedReader, closeBaseReader: baseReader.Close}, nil +} + +func (d *opensslAesCtrDuplex) Write(p []byte) (int, error) { + return d.encryptWriter.Write(p) +} + +func (d *opensslAesCtrDuplex) Read(p []byte) (int, error) { + return d.decryptedReader.Read(p) +} + +func (d *opensslAesCtrDuplex) Close() error { + wErr := d.encryptWriter.Close() + rErr := d.closeBaseReader() + return util.CombineErrors(wErr, rErr) +} From 50222781422d2ad5f69378dc5b0fcd4394fed7a7 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 00:03:06 +0900 Subject: [PATCH 04/21] feat: support openssl-aes-128-ctr and openssl-aes-256-ctr for --cipher-type and --pbkdf2 --- cmd/client.go | 8 ++-- cmd/server.go | 8 ++-- cmd/shared.go | 71 ++++++++++++++++++++++++++++++- cmd/socks.go | 6 ++- piping_util/piping_tunnel_util.go | 6 ++- pmux/pmux.go | 2 + 6 files changed, 90 insertions(+), 11 deletions(-) diff --git a/cmd/client.go b/cmd/client.go index 84d8a9c..f1f60e7 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -26,6 +26,7 @@ var clientPmuxConfig string var clientSymmetricallyEncrypts bool var clientSymmetricallyEncryptPassphrase string var clientCipherType string +var clientPbkdf2JsonString string func init() { RootCmd.AddCommand(clientCmd) @@ -37,7 +38,8 @@ func init() { clientCmd.Flags().StringVarP(&clientPmuxConfig, pmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") clientCmd.Flags().BoolVarP(&clientSymmetricallyEncrypts, symmetricallyEncryptsFlagLongName, symmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") clientCmd.Flags().StringVarP(&clientSymmetricallyEncryptPassphrase, symmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - clientCmd.Flags().StringVarP(&clientCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpenpgp)) + clientCmd.Flags().StringVarP(&clientCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + clientCmd.Flags().StringVarP(&clientPbkdf2JsonString, pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", examplePbkdf2JsonStr())) } var clientCmd = &cobra.Command{ @@ -113,7 +115,7 @@ var clientCmd = &cobra.Command{ if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType) + duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) if err != nil { return err } @@ -214,7 +216,7 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType) + duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) if err != nil { return err } diff --git a/cmd/server.go b/cmd/server.go index 8b78617..eb5c3a0 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -27,6 +27,7 @@ var serverPmuxConfig string var serverSymmetricallyEncrypts bool var serverSymmetricallyEncryptPassphrase string var serverCipherType string +var serverPbkdf2JsonString string func init() { RootCmd.AddCommand(serverCmd) @@ -39,7 +40,8 @@ func init() { serverCmd.Flags().StringVarP(&serverPmuxConfig, pmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") serverCmd.Flags().BoolVarP(&serverSymmetricallyEncrypts, symmetricallyEncryptsFlagLongName, symmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") serverCmd.Flags().StringVarP(&serverSymmetricallyEncryptPassphrase, symmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - serverCmd.Flags().StringVarP(&serverCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpenpgp)) + serverCmd.Flags().StringVarP(&serverCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + serverCmd.Flags().StringVarP(&serverPbkdf2JsonString, pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", examplePbkdf2JsonStr())) } var serverCmd = &cobra.Command{ @@ -106,7 +108,7 @@ var serverCmd = &cobra.Command{ if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType) + duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) if err != nil { return err } @@ -198,7 +200,7 @@ func serverHandleWithYamux(httpClient *http.Client, headers []piping_util.KeyVal if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType) + duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) if err != nil { return err } diff --git a/cmd/shared.go b/cmd/shared.go index cb5d313..59bc5c0 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -1,14 +1,21 @@ package cmd import ( + "crypto" + _ "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" + "encoding/json" "fmt" "github.com/nwtgck/go-piping-tunnel/aes_ctr_duplex" "github.com/nwtgck/go-piping-tunnel/io_progress" "github.com/nwtgck/go-piping-tunnel/openpgp_duplex" + "github.com/nwtgck/go-piping-tunnel/openssl_aes_ctr_duplex" "github.com/nwtgck/go-piping-tunnel/piping_util" "github.com/nwtgck/go-piping-tunnel/util" "github.com/nwtgck/go-piping-tunnel/verbose_logger" "github.com/pkg/errors" + "hash" "io" "os" "time" @@ -24,6 +31,7 @@ const ( symmetricallyEncryptsFlagShortName = "c" symmetricallyEncryptPassphraseFlagLongName = "passphrase" cipherTypeFlagLongName = "cipher-type" + pbkdf2FlagLongName = "pbkdf2" ) const yamuxMimeType = "application/yamux" @@ -36,6 +44,16 @@ type clientPmuxConfigJson struct { Hb bool `json:"hb"` } +type pbkdf2ConfigJson struct { + Iter int `json:"iter"` + Hash string `json:"hash"` +} + +type pbkdf2Config struct { + Iter int + Hash func() hash.Hash +} + var vlog *verbose_logger.Logger func init() { @@ -46,6 +64,10 @@ func validateClientCipher(str string) error { switch str { case piping_util.CipherTypeAesCtr: return nil + case piping_util.CipherTypeOpensslAes128Ctr: + return nil + case piping_util.CipherTypeOpensslAes256Ctr: + return nil case piping_util.CipherTypeOpenpgp: return nil default: @@ -53,6 +75,39 @@ func validateClientCipher(str string) error { } } +func validateHashFunctionName(str string) (func() hash.Hash, error) { + switch str { + case "sha1": + return crypto.SHA1.New, nil + case "sha256": + return crypto.SHA256.New, nil + case "sha512": + return crypto.SHA512.New, nil + default: + return nil, errors.Errorf("unsupported hash: %s", str) + } +} + +func parsePbkdf2(str string) (*pbkdf2Config, error) { + var configJson pbkdf2ConfigJson + if json.Unmarshal([]byte(str), &configJson) != nil { + return nil, errors.Errorf("invalid pbkdf2 JSON format: e.g. --%s='%s'", pbkdf2FlagLongName, examplePbkdf2JsonStr()) + } + h, err := validateHashFunctionName(configJson.Hash) + if err != nil { + return nil, err + } + return &pbkdf2Config{Iter: configJson.Iter, Hash: h}, nil +} + +func examplePbkdf2JsonStr() string { + b, err := json.Marshal(&pbkdf2ConfigJson{Iter: 100000, Hash: "sha256"}) + if err != nil { + panic(err) + } + return string(b) +} + func generatePaths(args []string) (string, string, error) { var clientToServerPath string var serverToClientPath string @@ -92,7 +147,7 @@ func makeUserInputPassphraseIfEmpty(passphrase *string) (err error) { return nil } -func makeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encrypts bool, passphrase string, cipherType string) (io.ReadWriteCloser, error) { +func makeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encrypts bool, passphrase string, cipherType string, pbkdf2JsonStr string) (io.ReadWriteCloser, error) { var err error // If encryption is enabled if encrypts { @@ -102,6 +157,20 @@ func makeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encryp // Encrypt with AES-CTR duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(passphrase)) cipherName = "AES-CTR" + case piping_util.CipherTypeOpensslAes128Ctr: + pbkdf2, err := parsePbkdf2(pbkdf2JsonStr) + if err != nil { + return nil, err + } + duplex, err = openssl_aes_ctr_duplex.Duplex(duplex, duplex, []byte(passphrase), pbkdf2.Iter, 128/8, pbkdf2.Hash) + cipherName = "OpenSSL-AES-128-CTR-compatible" + case piping_util.CipherTypeOpensslAes256Ctr: + pbkdf2, err := parsePbkdf2(pbkdf2JsonStr) + if err != nil { + return nil, err + } + duplex, err = openssl_aes_ctr_duplex.Duplex(duplex, duplex, []byte(passphrase), pbkdf2.Iter, 256/8, pbkdf2.Hash) + cipherName = "OpenSSL-AES-256-CTR-compatible" case piping_util.CipherTypeOpenpgp: duplex, err = openpgp_duplex.SymmetricallyEncryptDuplexWithOpenPGP(duplex, duplex, []byte(passphrase)) cipherName = "OpenPGP" diff --git a/cmd/socks.go b/cmd/socks.go index aa3a7e3..09b186e 100644 --- a/cmd/socks.go +++ b/cmd/socks.go @@ -21,6 +21,7 @@ var socksPmuxConfig string var socksSymmetricallyEncrypts bool var socksSymmetricallyEncryptPassphrase string var socksCipherType string +var socksPbkdf2JsonString string func init() { RootCmd.AddCommand(socksCmd) @@ -29,7 +30,8 @@ func init() { socksCmd.Flags().StringVarP(&socksPmuxConfig, pmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") socksCmd.Flags().BoolVarP(&socksSymmetricallyEncrypts, symmetricallyEncryptsFlagLongName, symmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") socksCmd.Flags().StringVarP(&socksSymmetricallyEncryptPassphrase, symmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - socksCmd.Flags().StringVarP(&socksCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpenpgp)) + socksCmd.Flags().StringVarP(&socksCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + socksCmd.Flags().StringVarP(&socksPbkdf2JsonString, pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", examplePbkdf2JsonStr())) } var socksCmd = &cobra.Command{ @@ -144,7 +146,7 @@ func socksHandleWithYamux(socksServer *socks.Server, httpClient *http.Client, he return res, nil }, ) - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, socksSymmetricallyEncrypts, socksSymmetricallyEncryptPassphrase, socksCipherType) + duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, socksSymmetricallyEncrypts, socksSymmetricallyEncryptPassphrase, socksCipherType, socksPbkdf2JsonString) if err != nil { return err } diff --git a/piping_util/piping_tunnel_util.go b/piping_util/piping_tunnel_util.go index 8c210aa..a626804 100644 --- a/piping_util/piping_tunnel_util.go +++ b/piping_util/piping_tunnel_util.go @@ -10,8 +10,10 @@ import ( ) const ( - CipherTypeOpenpgp string = "openpgp" - CipherTypeAesCtr = "aes-ctr" + CipherTypeOpenpgp string = "openpgp" + CipherTypeAesCtr = "aes-ctr" + CipherTypeOpensslAes128Ctr = "openssl-aes-128-ctr" + CipherTypeOpensslAes256Ctr = "openssl-aes-256-ctr" ) type KeyValue struct { diff --git a/pmux/pmux.go b/pmux/pmux.go index efa8303..936a33c 100644 --- a/pmux/pmux.go +++ b/pmux/pmux.go @@ -196,6 +196,7 @@ func (s *server) Accept() (io.ReadWriteCloser, error) { duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(s.passphrase)) case piping_util.CipherTypeOpenpgp: duplex, err = openpgp_duplex.SymmetricallyEncryptDuplexWithOpenPGP(duplex, duplex, []byte(s.passphrase)) + // NOTE: pmux does not support openssl-compatible encryption default: return nil, errors.Errorf("unexpected cipher type: %s", s.cipherType) } @@ -332,6 +333,7 @@ func (c *client) Open() (io.ReadWriteCloser, error) { duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(c.passphrase)) case piping_util.CipherTypeOpenpgp: duplex, err = openpgp_duplex.SymmetricallyEncryptDuplexWithOpenPGP(duplex, duplex, []byte(c.passphrase)) + // NOTE: pmux does not support openssl-compatible encryption default: return nil, errors.Errorf("unexpected cipher type: %s", c.cipherType) } From 6074667d18839df056a966d6886ba1497ac332ba Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 00:16:16 +0900 Subject: [PATCH 05/21] ci: add "OpenSSL-compabile AES-CTR" --- .github/workflows/ci.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9a5e63..dcaaddb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,11 +100,24 @@ jobs: - name: Encrypt with AES-CTR run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa bbb & - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa bbb & + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa bbb & echo $! > pid1 + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa bbb & echo $! > pid2 sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname + # FIXME: normal tunnel should be finished but not finished in ecryption + kill $(cat pid1) && kill $(cat pid2) + + - name: Encrypt with OpenSSL-compabile AES-CTR + run: | + set -eux + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & echo $! > pid1 + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & echo $! > pid2 + sleep 1 + # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) + ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname + # FIXME: normal tunnel should be finished but not finished in ecryption + kill $(cat pid1) && kill $(cat pid2) - name: yamux run: | From fc23c80646ab4943117293a16eb0d84f88e11cab Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 00:40:37 +0900 Subject: [PATCH 06/21] ci: add "Encrypt with OpenSSL-compabile AES-CTR using real openssl" --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcaaddb..a826ace 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,15 @@ jobs: # FIXME: normal tunnel should be finished but not finished in ecryption kill $(cat pid1) && kill $(cat pid2) + - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl + run: | + set -eux + curl -sSN http://localhost:8080/aaa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc localhost 2022 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - http://localhost:8080/bbb & + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & + sleep 1 + # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) + ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname + - name: yamux run: | set -eux From f68437639c3c333d84a3202845c0c5eebddf3cd0 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 00:54:20 +0900 Subject: [PATCH 07/21] ci: add "Encrypt with OpenSSL-compabile AES-CTR using real openssl in client host" --- .github/workflows/ci.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a826ace..0e4f11d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,7 +119,7 @@ jobs: # FIXME: normal tunnel should be finished but not finished in ecryption kill $(cat pid1) && kill $(cat pid2) - - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl + - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl in server host run: | set -eux curl -sSN http://localhost:8080/aaa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc localhost 2022 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - http://localhost:8080/bbb & @@ -128,6 +128,15 @@ jobs: # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname + - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl in client host + run: | + set -eux + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & + curl -NsS http://localhost:8080/bbb | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc -l -p 3322 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -NsST - http://localhost:8080/aaa & + sleep 1 + # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) + ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname + - name: yamux run: | set -eux From df62a6606bb73535876ffeaac697b0ea27decea8 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 01:00:54 +0900 Subject: [PATCH 08/21] ci: add prefix "openssl" for avoid duplicate path --- .github/workflows/ci.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e4f11d..79c04a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,19 +111,17 @@ jobs: - name: Encrypt with OpenSSL-compabile AES-CTR run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & echo $! > pid1 - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & echo $! > pid2 + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl1aaa openssl1bbb & echo $! > pid1 + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl1aaa openssl1bbb & echo $! > pid2 sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname - # FIXME: normal tunnel should be finished but not finished in ecryption - kill $(cat pid1) && kill $(cat pid2) - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl in server host run: | set -eux - curl -sSN http://localhost:8080/aaa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc localhost 2022 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - http://localhost:8080/bbb & - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & + curl -sSN http://localhost:8080/openssl2aaa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc localhost 2022 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - http://localhost:8080/openssl2bbb & + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl2aaa openssl2bbb & sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname @@ -131,8 +129,8 @@ jobs: - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl in client host run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass aaa bbb & - curl -NsS http://localhost:8080/bbb | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc -l -p 3322 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -NsST - http://localhost:8080/aaa & + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl3aaa openssl3bbb & + curl -NsS http://localhost:8080/openssl3bbb | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc -l -p 3322 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -NsST - http://localhost:8080/openssl3aaa & sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname From 864da7f8a8761721ca95419ca8af679096f1452e Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 01:11:22 +0900 Subject: [PATCH 09/21] ci: add "aesctr" prefix for avoiding duplicate path --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79c04a0..8cda9cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,13 +100,11 @@ jobs: - name: Encrypt with AES-CTR run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa bbb & echo $! > pid1 - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa bbb & echo $! > pid2 + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=aes-ctr --passphrase=mypass aesctraaa aesctrbbb & + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=aes-ctr --passphrase=mypass aesctraaa aesctrbbb & sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname - # FIXME: normal tunnel should be finished but not finished in ecryption - kill $(cat pid1) && kill $(cat pid2) - name: Encrypt with OpenSSL-compabile AES-CTR run: | From 5c2043207145fcf37de0cdf037eed00267246056 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 08:48:02 +0900 Subject: [PATCH 10/21] refactor: narrow local variable visibility in each sub command --- cmd/{ => client}/client.go | 73 +++++++++++++++++++------------------- cmd/root.go | 30 ++++++++-------- cmd/{ => server}/server.go | 67 +++++++++++++++++----------------- cmd/shared.go | 50 +++++++++++++------------- cmd/{ => socks}/socks.go | 61 +++++++++++++++---------------- main/main.go | 3 ++ 6 files changed, 145 insertions(+), 139 deletions(-) rename cmd/{ => client}/client.go (72%) rename cmd/{ => server}/server.go (70%) rename cmd/{ => socks}/socks.go (63%) diff --git a/cmd/client.go b/cmd/client/client.go similarity index 72% rename from cmd/client.go rename to cmd/client/client.go index f1f60e7..ec17464 100644 --- a/cmd/client.go +++ b/cmd/client/client.go @@ -1,9 +1,10 @@ -package cmd +package client import ( "encoding/json" "fmt" "github.com/hashicorp/yamux" + "github.com/nwtgck/go-piping-tunnel/cmd" "github.com/nwtgck/go-piping-tunnel/piping_util" "github.com/nwtgck/go-piping-tunnel/pmux" "github.com/nwtgck/go-piping-tunnel/util" @@ -29,47 +30,47 @@ var clientCipherType string var clientPbkdf2JsonString string func init() { - RootCmd.AddCommand(clientCmd) + cmd.RootCmd.AddCommand(clientCmd) clientCmd.Flags().IntVarP(&clientHostPort, "port", "p", 0, "TCP port of client host") clientCmd.Flags().StringVarP(&clientHostUnixSocket, "unix-socket", "", "", "Unix socket of client host") clientCmd.Flags().UintVarP(&clientServerToClientBufSize, "sc-buf-size", "", 16, "Buffer size of server-to-client in bytes") - clientCmd.Flags().BoolVarP(&clientYamux, yamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") - clientCmd.Flags().BoolVarP(&clientPmux, pmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") - clientCmd.Flags().StringVarP(&clientPmuxConfig, pmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") - clientCmd.Flags().BoolVarP(&clientSymmetricallyEncrypts, symmetricallyEncryptsFlagLongName, symmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") - clientCmd.Flags().StringVarP(&clientSymmetricallyEncryptPassphrase, symmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - clientCmd.Flags().StringVarP(&clientCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) - clientCmd.Flags().StringVarP(&clientPbkdf2JsonString, pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", examplePbkdf2JsonStr())) + clientCmd.Flags().BoolVarP(&clientYamux, cmd.YamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") + clientCmd.Flags().BoolVarP(&clientPmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") + clientCmd.Flags().StringVarP(&clientPmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") + clientCmd.Flags().BoolVarP(&clientSymmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") + clientCmd.Flags().StringVarP(&clientSymmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") + clientCmd.Flags().StringVarP(&clientCipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + clientCmd.Flags().StringVarP(&clientPbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } var clientCmd = &cobra.Command{ Use: "client", Short: "Run client-host", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, args []string) error { // Validate cipher-type if clientSymmetricallyEncrypts { - if err := validateClientCipher(clientCipherType); err != nil { + if err := cmd.ValidateClientCipher(clientCipherType); err != nil { return err } } - clientToServerPath, serverToClientPath, err := generatePaths(args) + clientToServerPath, serverToClientPath, err := cmd.GeneratePaths(args) if err != nil { return err } - headers, err := piping_util.ParseKeyValueStrings(headerKeyValueStrs) + headers, err := piping_util.ParseKeyValueStrings(cmd.HeaderKeyValueStrs) if err != nil { return err } - httpClient := util.CreateHttpClient(insecure, httpWriteBufSize, httpReadBufSize) - if dnsServer != "" { + httpClient := util.CreateHttpClient(cmd.Insecure, cmd.HttpWriteBufSize, cmd.HttpReadBufSize) + if cmd.DnsServer != "" { // Set DNS resolver - httpClient.Transport.(*http.Transport).DialContext = util.CreateDialContext(dnsServer) + httpClient.Transport.(*http.Transport).DialContext = util.CreateDialContext(cmd.DnsServer) } - clientToServerUrl, err := util.UrlJoin(serverUrl, clientToServerPath) + clientToServerUrl, err := util.UrlJoin(cmd.ServerUrl, clientToServerPath) if err != nil { return err } - serverToClientUrl, err := util.UrlJoin(serverUrl, serverToClientPath) + serverToClientUrl, err := util.UrlJoin(cmd.ServerUrl, serverToClientPath) if err != nil { return err } @@ -86,7 +87,7 @@ var clientCmd = &cobra.Command{ printHintForServerHost(ln, clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty if clientSymmetricallyEncrypts { - err = makeUserInputPassphraseIfEmpty(&clientSymmetricallyEncryptPassphrase) + err = cmd.MakeUserInputPassphraseIfEmpty(&clientSymmetricallyEncryptPassphrase) if err != nil { return err } @@ -115,7 +116,7 @@ var clientCmd = &cobra.Command{ if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) if err != nil { return err } @@ -134,7 +135,7 @@ var clientCmd = &cobra.Command{ }() return util.CombineErrors(<-fin, <-fin) } - err = piping_util.HandleDuplex(httpClient, conn, headers, clientToServerUrl, serverToClientUrl, clientServerToClientBufSize, nil, showProgress, makeProgressMessage) + err = piping_util.HandleDuplex(httpClient, conn, headers, clientToServerUrl, serverToClientUrl, clientServerToClientBufSize, nil, cmd.ShowProgress, cmd.MakeProgressMessage) fmt.Println() if err != nil { return err @@ -166,20 +167,20 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC fmt.Println("[INFO] Hint: Server host (piping-tunnel)") flags := "" if clientSymmetricallyEncrypts { - flags += fmt.Sprintf("-%s ", symmetricallyEncryptsFlagShortName) - if clientCipherType != defaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cipherTypeFlagLongName, clientCipherType) + flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) + if clientCipherType != cmd.DefaultCipherType { + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, clientCipherType) } } if clientYamux { - flags += fmt.Sprintf("--%s ", yamuxFlagLongName) + flags += fmt.Sprintf("--%s ", cmd.YamuxFlagLongName) } if clientPmux { - flags += fmt.Sprintf("--%s ", pmuxFlagLongName) + flags += fmt.Sprintf("--%s ", cmd.PmuxFlagLongName) } fmt.Printf( " piping-tunnel -s %s server -p %s%s %s\n", - serverUrl, + cmd.ServerUrl, flags, clientToServerPath, serverToClientPath, @@ -187,7 +188,7 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC fmt.Println(" OR") fmt.Printf( " piping-tunnel -s %s socks %s%s %s\n", - serverUrl, + cmd.ServerUrl, flags, clientToServerPath, serverToClientPath, @@ -198,7 +199,7 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p var duplex io.ReadWriteCloser duplex, err := piping_util.DuplexConnectWithHandlers( func(body io.Reader) (*http.Response, error) { - return piping_util.PipingSend(httpClient, headersWithYamux(headers), clientToServerUrl, body) + return piping_util.PipingSend(httpClient, cmd.HeadersWithYamux(headers), clientToServerUrl, body) }, func() (*http.Response, error) { res, err := piping_util.PipingGet(httpClient, headers, serverToClientUrl) @@ -207,7 +208,7 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p } contentType := res.Header.Get("Content-Type") // NOTE: application/octet-stream is for compatibility - if contentType != yamuxMimeType && contentType != "application/octet-stream" { + if contentType != cmd.YamuxMimeType && contentType != "application/octet-stream" { return nil, errors.Errorf("invalid content-type: %s", contentType) } return res, nil @@ -216,7 +217,7 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) if err != nil { return err } @@ -258,14 +259,14 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p } func clientHandleWithPmux(ln net.Listener, httpClient *http.Client, headers []piping_util.KeyValue, clientToServerUrl string, serverToClientUrl string) error { - var config clientPmuxConfigJson + var config cmd.ClientPmuxConfigJson if json.Unmarshal([]byte(clientPmuxConfig), &config) != nil { return errors.Errorf("invalid pmux config format") } pmuxClient, err := pmux.Client(httpClient, headers, clientToServerUrl, serverToClientUrl, config.Hb, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType) if err != nil { if err == pmux.NonPmuxMimeTypeError { - return errors.Errorf("--%s may be missing in server", pmuxFlagLongName) + return errors.Errorf("--%s may be missing in server", cmd.PmuxFlagLongName) } if err == pmux.IncompatiblePmuxVersion { return errors.Errorf("%s, hint: use the same piping-tunnel version (current: %s)", err.Error(), version.Version) @@ -282,7 +283,7 @@ func clientHandleWithPmux(ln net.Listener, httpClient *http.Client, headers []pi } stream, err := pmuxClient.Open() if err != nil { - vlog.Log( + cmd.Vlog.Log( fmt.Sprintf("error(pmux open): %v", errors.WithStack(err)), fmt.Sprintf("error(pmux open): %+v", errors.WithStack(err)), ) @@ -295,7 +296,7 @@ func clientHandleWithPmux(ln net.Listener, httpClient *http.Client, headers []pi _, err := io.CopyBuffer(conn, stream, buf) fin <- struct{}{} if err != nil { - vlog.Log( + cmd.Vlog.Log( fmt.Sprintf("error(pmux stream → conn): %v", errors.WithStack(err)), fmt.Sprintf("error(pmux stream → conn): %+v", errors.WithStack(err)), ) @@ -309,7 +310,7 @@ func clientHandleWithPmux(ln net.Listener, httpClient *http.Client, headers []pi _, err := io.CopyBuffer(stream, conn, buf) fin <- struct{}{} if err != nil { - vlog.Log( + cmd.Vlog.Log( fmt.Sprintf("error(conn → pmux stream): %v", errors.WithStack(err)), fmt.Sprintf("error(conn → pmux stream): %+v", errors.WithStack(err)), ) diff --git a/cmd/root.go b/cmd/root.go index 8677c14..cd75421 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -11,14 +11,14 @@ const ( ServerUrlEnvName = "PIPING_SERVER" ) -var serverUrl string -var insecure bool -var dnsServer string +var ServerUrl string +var Insecure bool +var DnsServer string var showsVersion bool -var showProgress bool -var headerKeyValueStrs []string -var httpWriteBufSize int -var httpReadBufSize int +var ShowProgress bool +var HeaderKeyValueStrs []string +var HttpWriteBufSize int +var HttpReadBufSize int var verboseLoggerLevel int func init() { @@ -27,14 +27,14 @@ func init() { if !ok { defaultServer = "https://ppng.io" } - RootCmd.PersistentFlags().StringVarP(&serverUrl, "server", "s", defaultServer, "Piping Server URL") - RootCmd.PersistentFlags().StringVar(&dnsServer, "dns-server", "", "DNS server (e.g. 1.1.1.1:53)") + RootCmd.PersistentFlags().StringVarP(&ServerUrl, "server", "s", defaultServer, "Piping Server URL") + RootCmd.PersistentFlags().StringVar(&DnsServer, "dns-server", "", "DNS server (e.g. 1.1.1.1:53)") // NOTE: --insecure, -k is inspired by curl - RootCmd.PersistentFlags().BoolVarP(&insecure, "insecure", "k", false, "Allow insecure server connections when using SSL") - RootCmd.PersistentFlags().StringArrayVarP(&headerKeyValueStrs, "header", "H", []string{}, "HTTP header") - RootCmd.PersistentFlags().IntVarP(&httpWriteBufSize, "http-write-buf-size", "", 16, "HTTP write-buffer size in bytes") - RootCmd.PersistentFlags().IntVarP(&httpReadBufSize, "http-read-buf-size", "", 16, "HTTP read-buffer size in bytes") - RootCmd.PersistentFlags().BoolVarP(&showProgress, "progress", "", true, "Show progress") + RootCmd.PersistentFlags().BoolVarP(&Insecure, "insecure", "k", false, "Allow insecure server connections when using SSL") + RootCmd.PersistentFlags().StringArrayVarP(&HeaderKeyValueStrs, "header", "H", []string{}, "HTTP header") + RootCmd.PersistentFlags().IntVarP(&HttpWriteBufSize, "http-write-buf-size", "", 16, "HTTP write-buffer size in bytes") + RootCmd.PersistentFlags().IntVarP(&HttpReadBufSize, "http-read-buf-size", "", 16, "HTTP read-buffer size in bytes") + RootCmd.PersistentFlags().BoolVarP(&ShowProgress, "progress", "", true, "Show progress") RootCmd.Flags().BoolVarP(&showsVersion, "version", "v", false, "show version") RootCmd.PersistentFlags().IntVarP(&verboseLoggerLevel, "verbose", "", 0, "Verbose logging level") } @@ -72,6 +72,6 @@ Environment variable: return cmd.Help() }, PersistentPreRun: func(cmd *cobra.Command, args []string) { - vlog.Level = verboseLoggerLevel + Vlog.Level = verboseLoggerLevel }, } diff --git a/cmd/server.go b/cmd/server/server.go similarity index 70% rename from cmd/server.go rename to cmd/server/server.go index eb5c3a0..87843c5 100644 --- a/cmd/server.go +++ b/cmd/server/server.go @@ -1,10 +1,11 @@ -package cmd +package server import ( "encoding/json" "fmt" "github.com/hashicorp/yamux" "github.com/nwtgck/go-piping-tunnel/backoff" + "github.com/nwtgck/go-piping-tunnel/cmd" "github.com/nwtgck/go-piping-tunnel/piping_util" "github.com/nwtgck/go-piping-tunnel/pmux" "github.com/nwtgck/go-piping-tunnel/util" @@ -30,48 +31,48 @@ var serverCipherType string var serverPbkdf2JsonString string func init() { - RootCmd.AddCommand(serverCmd) + cmd.RootCmd.AddCommand(serverCmd) serverCmd.Flags().StringVarP(&serverTargetHost, "host", "", "localhost", "Target host") serverCmd.Flags().IntVarP(&serverHostPort, "port", "p", 0, "TCP port of server host") serverCmd.Flags().StringVarP(&serverHostUnixSocket, "unix-socket", "", "", "Unix socket of server host") serverCmd.Flags().UintVarP(&serverClientToServerBufSize, "cs-buf-size", "", 16, "Buffer size of client-to-server in bytes") - serverCmd.Flags().BoolVarP(&serverYamux, yamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") - serverCmd.Flags().BoolVarP(&serverPmux, pmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") - serverCmd.Flags().StringVarP(&serverPmuxConfig, pmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") - serverCmd.Flags().BoolVarP(&serverSymmetricallyEncrypts, symmetricallyEncryptsFlagLongName, symmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") - serverCmd.Flags().StringVarP(&serverSymmetricallyEncryptPassphrase, symmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - serverCmd.Flags().StringVarP(&serverCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) - serverCmd.Flags().StringVarP(&serverPbkdf2JsonString, pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", examplePbkdf2JsonStr())) + serverCmd.Flags().BoolVarP(&serverYamux, cmd.YamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") + serverCmd.Flags().BoolVarP(&serverPmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") + serverCmd.Flags().StringVarP(&serverPmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") + serverCmd.Flags().BoolVarP(&serverSymmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") + serverCmd.Flags().StringVarP(&serverSymmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") + serverCmd.Flags().StringVarP(&serverCipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + serverCmd.Flags().StringVarP(&serverPbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } var serverCmd = &cobra.Command{ Use: "server", Short: "Run server-host", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, args []string) error { // Validate cipher-type if serverSymmetricallyEncrypts { - if err := validateClientCipher(serverCipherType); err != nil { + if err := cmd.ValidateClientCipher(serverCipherType); err != nil { return err } } - clientToServerPath, serverToClientPath, err := generatePaths(args) + clientToServerPath, serverToClientPath, err := cmd.GeneratePaths(args) if err != nil { return err } - headers, err := piping_util.ParseKeyValueStrings(headerKeyValueStrs) + headers, err := piping_util.ParseKeyValueStrings(cmd.HeaderKeyValueStrs) if err != nil { return err } - httpClient := util.CreateHttpClient(insecure, httpWriteBufSize, httpReadBufSize) - if dnsServer != "" { + httpClient := util.CreateHttpClient(cmd.Insecure, cmd.HttpWriteBufSize, cmd.HttpReadBufSize) + if cmd.DnsServer != "" { // Set DNS resolver - httpClient.Transport.(*http.Transport).DialContext = util.CreateDialContext(dnsServer) + httpClient.Transport.(*http.Transport).DialContext = util.CreateDialContext(cmd.DnsServer) } - serverToClientUrl, err := util.UrlJoin(serverUrl, serverToClientPath) + serverToClientUrl, err := util.UrlJoin(cmd.ServerUrl, serverToClientPath) if err != nil { return err } - clientToServerUrl, err := util.UrlJoin(serverUrl, clientToServerPath) + clientToServerUrl, err := util.UrlJoin(cmd.ServerUrl, clientToServerPath) if err != nil { return err } @@ -79,7 +80,7 @@ var serverCmd = &cobra.Command{ printHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty if serverSymmetricallyEncrypts { - err = makeUserInputPassphraseIfEmpty(&serverSymmetricallyEncryptPassphrase) + err = cmd.MakeUserInputPassphraseIfEmpty(&serverSymmetricallyEncryptPassphrase) if err != nil { return err } @@ -108,7 +109,7 @@ var serverCmd = &cobra.Command{ if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) if err != nil { return err } @@ -127,7 +128,7 @@ var serverCmd = &cobra.Command{ }() return util.CombineErrors(<-fin, <-fin) } - err = piping_util.HandleDuplex(httpClient, conn, headers, serverToClientUrl, clientToServerUrl, serverClientToServerBufSize, nil, showProgress, makeProgressMessage) + err = piping_util.HandleDuplex(httpClient, conn, headers, serverToClientUrl, clientToServerUrl, serverClientToServerBufSize, nil, cmd.ShowProgress, cmd.MakeProgressMessage) fmt.Println() if err != nil { return err @@ -157,21 +158,21 @@ func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, } flags := "" if serverSymmetricallyEncrypts { - flags += fmt.Sprintf("-%s ", symmetricallyEncryptsFlagShortName) - if serverCipherType != defaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cipherTypeFlagLongName, serverCipherType) + flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) + if serverCipherType != cmd.DefaultCipherType { + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, serverCipherType) } } if serverYamux { - flags += fmt.Sprintf("--%s ", yamuxFlagLongName) + flags += fmt.Sprintf("--%s ", cmd.YamuxFlagLongName) } if serverPmux { - flags += fmt.Sprintf("--%s ", pmuxFlagLongName) + flags += fmt.Sprintf("--%s ", cmd.PmuxFlagLongName) } fmt.Println("[INFO] Hint: Client host (piping-tunnel)") fmt.Printf( " piping-tunnel -s %s client -p 31376 %s%s %s\n", - serverUrl, + cmd.ServerUrl, flags, clientToServerPath, serverToClientPath, @@ -182,7 +183,7 @@ func serverHandleWithYamux(httpClient *http.Client, headers []piping_util.KeyVal var duplex io.ReadWriteCloser duplex, err := piping_util.DuplexConnectWithHandlers( func(body io.Reader) (*http.Response, error) { - return piping_util.PipingSend(httpClient, headersWithYamux(headers), serverToClientUrl, body) + return piping_util.PipingSend(httpClient, cmd.HeadersWithYamux(headers), serverToClientUrl, body) }, func() (*http.Response, error) { res, err := piping_util.PipingGet(httpClient, headers, clientToServerUrl) @@ -191,7 +192,7 @@ func serverHandleWithYamux(httpClient *http.Client, headers []piping_util.KeyVal } contentType := res.Header.Get("Content-Type") // NOTE: application/octet-stream is for compatibility - if contentType != yamuxMimeType && contentType != "application/octet-stream" { + if contentType != cmd.YamuxMimeType && contentType != "application/octet-stream" { return nil, errors.Errorf("invalid content-type: %s", contentType) } return res, nil @@ -200,7 +201,7 @@ func serverHandleWithYamux(httpClient *http.Client, headers []piping_util.KeyVal if err != nil { return err } - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) if err != nil { return err } @@ -254,7 +255,7 @@ func dialLoop() net.Conn { } func serverHandleWithPmux(httpClient *http.Client, headers []piping_util.KeyValue, clientToServerUrl string, serverToClientUrl string) error { - var config serverPmuxConfigJson + var config cmd.ServerPmuxConfigJson if json.Unmarshal([]byte(serverPmuxConfig), &config) != nil { return errors.Errorf("invalid pmux config format") } @@ -270,7 +271,7 @@ func serverHandleWithPmux(httpClient *http.Client, headers []piping_util.KeyValu var buf = make([]byte, 16) _, err := io.CopyBuffer(conn, stream, buf) if err != nil { - vlog.Log( + cmd.Vlog.Log( fmt.Sprintf("error(pmux stream → conn): %v", errors.WithStack(err)), fmt.Sprintf("error(pmux stream → conn): %+v", errors.WithStack(err)), ) @@ -284,7 +285,7 @@ func serverHandleWithPmux(httpClient *http.Client, headers []piping_util.KeyValu var buf = make([]byte, 16) _, err := io.CopyBuffer(stream, conn, buf) if err != nil { - vlog.Log( + cmd.Vlog.Log( fmt.Sprintf("error(conn → pmux stream): %v", errors.WithStack(err)), fmt.Sprintf("error(conn → pmux stream): %+v", errors.WithStack(err)), ) diff --git a/cmd/shared.go b/cmd/shared.go index 59bc5c0..e2dc13f 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -21,26 +21,26 @@ import ( "time" ) -const defaultCipherType = piping_util.CipherTypeAesCtr +const DefaultCipherType = piping_util.CipherTypeAesCtr const ( - yamuxFlagLongName = "yamux" - pmuxFlagLongName = "pmux" - pmuxConfigFlagLongName = "pmux-config" - symmetricallyEncryptsFlagLongName = "symmetric" - symmetricallyEncryptsFlagShortName = "c" - symmetricallyEncryptPassphraseFlagLongName = "passphrase" - cipherTypeFlagLongName = "cipher-type" - pbkdf2FlagLongName = "pbkdf2" + YamuxFlagLongName = "yamux" + PmuxFlagLongName = "pmux" + PmuxConfigFlagLongName = "pmux-config" + SymmetricallyEncryptsFlagLongName = "symmetric" + SymmetricallyEncryptsFlagShortName = "c" + SymmetricallyEncryptPassphraseFlagLongName = "passphrase" + CipherTypeFlagLongName = "cipher-type" + Pbkdf2FlagLongName = "pbkdf2" ) -const yamuxMimeType = "application/yamux" +const YamuxMimeType = "application/yamux" -type serverPmuxConfigJson struct { +type ServerPmuxConfigJson struct { Hb bool `json:"hb"` } -type clientPmuxConfigJson struct { +type ClientPmuxConfigJson struct { Hb bool `json:"hb"` } @@ -54,13 +54,13 @@ type pbkdf2Config struct { Hash func() hash.Hash } -var vlog *verbose_logger.Logger +var Vlog *verbose_logger.Logger func init() { - vlog = &verbose_logger.Logger{} + Vlog = &verbose_logger.Logger{} } -func validateClientCipher(str string) error { +func ValidateClientCipher(str string) error { switch str { case piping_util.CipherTypeAesCtr: return nil @@ -91,7 +91,7 @@ func validateHashFunctionName(str string) (func() hash.Hash, error) { func parsePbkdf2(str string) (*pbkdf2Config, error) { var configJson pbkdf2ConfigJson if json.Unmarshal([]byte(str), &configJson) != nil { - return nil, errors.Errorf("invalid pbkdf2 JSON format: e.g. --%s='%s'", pbkdf2FlagLongName, examplePbkdf2JsonStr()) + return nil, errors.Errorf("invalid pbkdf2 JSON format: e.g. --%s='%s'", Pbkdf2FlagLongName, ExamplePbkdf2JsonStr()) } h, err := validateHashFunctionName(configJson.Hash) if err != nil { @@ -100,7 +100,7 @@ func parsePbkdf2(str string) (*pbkdf2Config, error) { return &pbkdf2Config{Iter: configJson.Iter, Hash: h}, nil } -func examplePbkdf2JsonStr() string { +func ExamplePbkdf2JsonStr() string { b, err := json.Marshal(&pbkdf2ConfigJson{Iter: 100000, Hash: "sha256"}) if err != nil { panic(err) @@ -108,7 +108,7 @@ func examplePbkdf2JsonStr() string { return string(b) } -func generatePaths(args []string) (string, string, error) { +func GeneratePaths(args []string) (string, string, error) { var clientToServerPath string var serverToClientPath string @@ -127,7 +127,7 @@ func generatePaths(args []string) (string, string, error) { return clientToServerPath, serverToClientPath, nil } -func makeProgressMessage(progress *io_progress.IOProgress) string { +func MakeProgressMessage(progress *io_progress.IOProgress) string { return fmt.Sprintf( "↑ %s (%s/s) | ↓ %s (%s/s)", util.HumanizeBytes(float64(progress.CurrReadBytes)), @@ -137,7 +137,7 @@ func makeProgressMessage(progress *io_progress.IOProgress) string { ) } -func makeUserInputPassphraseIfEmpty(passphrase *string) (err error) { +func MakeUserInputPassphraseIfEmpty(passphrase *string) (err error) { // If the passphrase is empty if *passphrase == "" { // Get user-input passphrase @@ -147,7 +147,7 @@ func makeUserInputPassphraseIfEmpty(passphrase *string) (err error) { return nil } -func makeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encrypts bool, passphrase string, cipherType string, pbkdf2JsonStr string) (io.ReadWriteCloser, error) { +func MakeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encrypts bool, passphrase string, cipherType string, pbkdf2JsonStr string) (io.ReadWriteCloser, error) { var err error // If encryption is enabled if encrypts { @@ -182,12 +182,12 @@ func makeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encryp } fmt.Printf("[INFO] End-to-end encryption with %s\n", cipherName) } - if showProgress { - duplex = io_progress.NewIOProgress(duplex, duplex, os.Stderr, makeProgressMessage) + if ShowProgress { + duplex = io_progress.NewIOProgress(duplex, duplex, os.Stderr, MakeProgressMessage) } return duplex, nil } -func headersWithYamux(headers []piping_util.KeyValue) []piping_util.KeyValue { - return append(headers, piping_util.KeyValue{Key: "Content-Type", Value: yamuxMimeType}) +func HeadersWithYamux(headers []piping_util.KeyValue) []piping_util.KeyValue { + return append(headers, piping_util.KeyValue{Key: "Content-Type", Value: YamuxMimeType}) } diff --git a/cmd/socks.go b/cmd/socks/socks.go similarity index 63% rename from cmd/socks.go rename to cmd/socks/socks.go index 09b186e..1ab25b8 100644 --- a/cmd/socks.go +++ b/cmd/socks/socks.go @@ -1,9 +1,10 @@ -package cmd +package socks import ( "encoding/json" "fmt" "github.com/hashicorp/yamux" + "github.com/nwtgck/go-piping-tunnel/cmd" "github.com/nwtgck/go-piping-tunnel/piping_util" "github.com/nwtgck/go-piping-tunnel/pmux" "github.com/nwtgck/go-piping-tunnel/util" @@ -24,44 +25,44 @@ var socksCipherType string var socksPbkdf2JsonString string func init() { - RootCmd.AddCommand(socksCmd) + cmd.RootCmd.AddCommand(socksCmd) socksCmd.Flags().BoolVarP(&socksYamux, "yamux", "", false, "Multiplex connection by hashicorp/yamux") - socksCmd.Flags().BoolVarP(&socksPmux, pmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") - socksCmd.Flags().StringVarP(&socksPmuxConfig, pmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") - socksCmd.Flags().BoolVarP(&socksSymmetricallyEncrypts, symmetricallyEncryptsFlagLongName, symmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") - socksCmd.Flags().StringVarP(&socksSymmetricallyEncryptPassphrase, symmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - socksCmd.Flags().StringVarP(&socksCipherType, cipherTypeFlagLongName, "", defaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) - socksCmd.Flags().StringVarP(&socksPbkdf2JsonString, pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", examplePbkdf2JsonStr())) + socksCmd.Flags().BoolVarP(&socksPmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") + socksCmd.Flags().StringVarP(&socksPmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") + socksCmd.Flags().BoolVarP(&socksSymmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") + socksCmd.Flags().StringVarP(&socksSymmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") + socksCmd.Flags().StringVarP(&socksCipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + socksCmd.Flags().StringVarP(&socksPbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } var socksCmd = &cobra.Command{ Use: "socks", Short: "Run SOCKS server", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, args []string) error { // Validate cipher-type if socksSymmetricallyEncrypts { - if err := validateClientCipher(socksCipherType); err != nil { + if err := cmd.ValidateClientCipher(socksCipherType); err != nil { return err } } - clientToServerPath, serverToClientPath, err := generatePaths(args) + clientToServerPath, serverToClientPath, err := cmd.GeneratePaths(args) if err != nil { return err } - headers, err := piping_util.ParseKeyValueStrings(headerKeyValueStrs) + headers, err := piping_util.ParseKeyValueStrings(cmd.HeaderKeyValueStrs) if err != nil { return err } - httpClient := util.CreateHttpClient(insecure, httpWriteBufSize, httpReadBufSize) - if dnsServer != "" { + httpClient := util.CreateHttpClient(cmd.Insecure, cmd.HttpWriteBufSize, cmd.HttpReadBufSize) + if cmd.DnsServer != "" { // Set DNS resolver - httpClient.Transport.(*http.Transport).DialContext = util.CreateDialContext(dnsServer) + httpClient.Transport.(*http.Transport).DialContext = util.CreateDialContext(cmd.DnsServer) } - serverToClientUrl, err := util.UrlJoin(serverUrl, serverToClientPath) + serverToClientUrl, err := util.UrlJoin(cmd.ServerUrl, serverToClientPath) if err != nil { return err } - clientToServerUrl, err := util.UrlJoin(serverUrl, clientToServerPath) + clientToServerUrl, err := util.UrlJoin(cmd.ServerUrl, clientToServerPath) if err != nil { return err } @@ -69,7 +70,7 @@ var socksCmd = &cobra.Command{ socksPrintHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty if socksSymmetricallyEncrypts { - err = makeUserInputPassphraseIfEmpty(&socksSymmetricallyEncryptPassphrase) + err = cmd.MakeUserInputPassphraseIfEmpty(&socksSymmetricallyEncryptPassphrase) if err != nil { return err } @@ -77,7 +78,7 @@ var socksCmd = &cobra.Command{ // If not using multiplexer if !socksYamux && !socksPmux { - return errors.Errorf("--%s or --%s must be specified", yamuxFlagLongName, pmuxFlagLongName) + return errors.Errorf("--%s or --%s must be specified", cmd.YamuxFlagLongName, cmd.PmuxFlagLongName) } socksConf := &socks.Config{} @@ -106,21 +107,21 @@ func socksPrintHintForClientHost(clientToServerUrl string, serverToClientUrl str } flags := "" if socksSymmetricallyEncrypts { - flags += fmt.Sprintf("-%s ", symmetricallyEncryptsFlagShortName) - if socksCipherType != defaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cipherTypeFlagLongName, socksCipherType) + flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) + if socksCipherType != cmd.DefaultCipherType { + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, socksCipherType) } } if socksYamux { - flags += fmt.Sprintf("--%s ", yamuxFlagLongName) + flags += fmt.Sprintf("--%s ", cmd.YamuxFlagLongName) } if socksPmux { - flags += fmt.Sprintf("--%s ", pmuxFlagLongName) + flags += fmt.Sprintf("--%s ", cmd.PmuxFlagLongName) } fmt.Println("[INFO] Hint: Client host (piping-tunnel)") fmt.Printf( " piping-tunnel -s %s client -p 1080 %s%s %s\n", - serverUrl, + cmd.ServerUrl, flags, clientToServerPath, serverToClientPath, @@ -131,7 +132,7 @@ func socksHandleWithYamux(socksServer *socks.Server, httpClient *http.Client, he var duplex io.ReadWriteCloser duplex, err := piping_util.DuplexConnectWithHandlers( func(body io.Reader) (*http.Response, error) { - return piping_util.PipingSend(httpClient, headersWithYamux(headers), serverToClientUrl, body) + return piping_util.PipingSend(httpClient, cmd.HeadersWithYamux(headers), serverToClientUrl, body) }, func() (*http.Response, error) { res, err := piping_util.PipingGet(httpClient, headers, clientToServerUrl) @@ -140,13 +141,13 @@ func socksHandleWithYamux(socksServer *socks.Server, httpClient *http.Client, he } contentType := res.Header.Get("Content-Type") // NOTE: application/octet-stream is for compatibility - if contentType != yamuxMimeType && contentType != "application/octet-stream" { + if contentType != cmd.YamuxMimeType && contentType != "application/octet-stream" { return nil, errors.Errorf("invalid content-type: %s", contentType) } return res, nil }, ) - duplex, err = makeDuplexWithEncryptionAndProgressIfNeed(duplex, socksSymmetricallyEncrypts, socksSymmetricallyEncryptPassphrase, socksCipherType, socksPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, socksSymmetricallyEncrypts, socksSymmetricallyEncryptPassphrase, socksCipherType, socksPbkdf2JsonString) if err != nil { return err } @@ -164,7 +165,7 @@ func socksHandleWithYamux(socksServer *socks.Server, httpClient *http.Client, he } func socksHandleWithPmux(socksServer *socks.Server, httpClient *http.Client, headers []piping_util.KeyValue, clientToServerUrl string, serverToClientUrl string) error { - var config serverPmuxConfigJson + var config cmd.ServerPmuxConfigJson if json.Unmarshal([]byte(socksPmuxConfig), &config) != nil { return errors.Errorf("invalid pmux config format") } @@ -177,7 +178,7 @@ func socksHandleWithPmux(socksServer *socks.Server, httpClient *http.Client, hea go func() { err := socksServer.ServeConn(util.NewDuplexConn(stream)) if err != nil { - vlog.Log( + cmd.Vlog.Log( fmt.Sprintf("error(serve conn): %v", errors.WithStack(err)), fmt.Sprintf("error(serve conn): %+v", errors.WithStack(err)), ) diff --git a/main/main.go b/main/main.go index 6ae7fd5..53e2d97 100644 --- a/main/main.go +++ b/main/main.go @@ -3,6 +3,9 @@ package main import ( "fmt" "github.com/nwtgck/go-piping-tunnel/cmd" + _ "github.com/nwtgck/go-piping-tunnel/cmd/client" + _ "github.com/nwtgck/go-piping-tunnel/cmd/server" + _ "github.com/nwtgck/go-piping-tunnel/cmd/socks" "os" ) From 8636f908cb416036e49e60f40ed6610c28bd0cb5 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 09:31:20 +0900 Subject: [PATCH 11/21] refactor: clarify flag variables --- cmd/client/client.go | 88 ++++++++++++++++++++++---------------------- cmd/server/server.go | 88 ++++++++++++++++++++++---------------------- cmd/socks/socks.go | 60 +++++++++++++++--------------- 3 files changed, 121 insertions(+), 115 deletions(-) diff --git a/cmd/client/client.go b/cmd/client/client.go index ec17464..7e2e441 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -18,29 +18,31 @@ import ( "strings" ) -var clientHostPort int -var clientHostUnixSocket string -var clientServerToClientBufSize uint -var clientYamux bool -var clientPmux bool -var clientPmuxConfig string -var clientSymmetricallyEncrypts bool -var clientSymmetricallyEncryptPassphrase string -var clientCipherType string -var clientPbkdf2JsonString string +var flag struct { + clientHostPort int + clientHostUnixSocket string + serverToClientBufSize uint + yamux bool + pmux bool + pmuxConfig string + symmetricallyEncrypts bool + symmetricallyEncryptPassphrase string + cipherType string + pbkdf2JsonString string +} func init() { cmd.RootCmd.AddCommand(clientCmd) - clientCmd.Flags().IntVarP(&clientHostPort, "port", "p", 0, "TCP port of client host") - clientCmd.Flags().StringVarP(&clientHostUnixSocket, "unix-socket", "", "", "Unix socket of client host") - clientCmd.Flags().UintVarP(&clientServerToClientBufSize, "sc-buf-size", "", 16, "Buffer size of server-to-client in bytes") - clientCmd.Flags().BoolVarP(&clientYamux, cmd.YamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") - clientCmd.Flags().BoolVarP(&clientPmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") - clientCmd.Flags().StringVarP(&clientPmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") - clientCmd.Flags().BoolVarP(&clientSymmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") - clientCmd.Flags().StringVarP(&clientSymmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - clientCmd.Flags().StringVarP(&clientCipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) - clientCmd.Flags().StringVarP(&clientPbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) + clientCmd.Flags().IntVarP(&flag.clientHostPort, "port", "p", 0, "TCP port of client host") + clientCmd.Flags().StringVarP(&flag.clientHostUnixSocket, "unix-socket", "", "", "Unix socket of client host") + clientCmd.Flags().UintVarP(&flag.serverToClientBufSize, "sc-buf-size", "", 16, "Buffer size of server-to-client in bytes") + clientCmd.Flags().BoolVarP(&flag.yamux, cmd.YamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") + clientCmd.Flags().BoolVarP(&flag.pmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") + clientCmd.Flags().StringVarP(&flag.pmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") + clientCmd.Flags().BoolVarP(&flag.symmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") + clientCmd.Flags().StringVarP(&flag.symmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") + clientCmd.Flags().StringVarP(&flag.cipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + clientCmd.Flags().StringVarP(&flag.pbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } var clientCmd = &cobra.Command{ @@ -48,8 +50,8 @@ var clientCmd = &cobra.Command{ Short: "Run client-host", RunE: func(_ *cobra.Command, args []string) error { // Validate cipher-type - if clientSymmetricallyEncrypts { - if err := cmd.ValidateClientCipher(clientCipherType); err != nil { + if flag.symmetricallyEncrypts { + if err := cmd.ValidateClientCipher(flag.cipherType); err != nil { return err } } @@ -75,10 +77,10 @@ var clientCmd = &cobra.Command{ return err } var ln net.Listener - if clientHostUnixSocket == "" { - ln, err = net.Listen("tcp", fmt.Sprintf(":%d", clientHostPort)) + if flag.clientHostUnixSocket == "" { + ln, err = net.Listen("tcp", fmt.Sprintf(":%d", flag.clientHostPort)) } else { - ln, err = net.Listen("unix", clientHostUnixSocket) + ln, err = net.Listen("unix", flag.clientHostUnixSocket) } if err != nil { return err @@ -86,19 +88,19 @@ var clientCmd = &cobra.Command{ // Print hint printHintForServerHost(ln, clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty - if clientSymmetricallyEncrypts { - err = cmd.MakeUserInputPassphraseIfEmpty(&clientSymmetricallyEncryptPassphrase) + if flag.symmetricallyEncrypts { + err = cmd.MakeUserInputPassphraseIfEmpty(&flag.symmetricallyEncryptPassphrase) if err != nil { return err } } // Use multiplexer with yamux - if clientYamux { + if flag.yamux { fmt.Println("[INFO] Multiplexing with hashicorp/yamux") return clientHandleWithYamux(ln, httpClient, headers, clientToServerUrl, serverToClientUrl) } // If pmux is enabled - if clientPmux { + if flag.pmux { fmt.Println("[INFO] Multiplexing with pmux") return clientHandleWithPmux(ln, httpClient, headers, clientToServerUrl, serverToClientUrl) } @@ -110,13 +112,13 @@ var clientCmd = &cobra.Command{ // Refuse another new connection ln.Close() // If encryption is enabled - if clientSymmetricallyEncrypts { + if flag.symmetricallyEncrypts { var duplex io.ReadWriteCloser duplex, err := piping_util.DuplexConnect(httpClient, headers, clientToServerUrl, serverToClientUrl) if err != nil { return err } - duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType, flag.pbkdf2JsonString) if err != nil { return err } @@ -135,7 +137,7 @@ var clientCmd = &cobra.Command{ }() return util.CombineErrors(<-fin, <-fin) } - err = piping_util.HandleDuplex(httpClient, conn, headers, clientToServerUrl, serverToClientUrl, clientServerToClientBufSize, nil, cmd.ShowProgress, cmd.MakeProgressMessage) + err = piping_util.HandleDuplex(httpClient, conn, headers, clientToServerUrl, serverToClientUrl, flag.serverToClientBufSize, nil, cmd.ShowProgress, cmd.MakeProgressMessage) fmt.Println() if err != nil { return err @@ -150,13 +152,13 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC var listeningOn string if addr, ok := ln.Addr().(*net.TCPAddr); ok { // (base: https://stackoverflow.com/a/43425461) - clientHostPort = addr.Port + flag.clientHostPort = addr.Port listeningOn = strconv.Itoa(addr.Port) } else { - listeningOn = clientHostUnixSocket + listeningOn = flag.clientHostUnixSocket } fmt.Printf("[INFO] Client host listening on %s ...\n", listeningOn) - if !clientYamux && !clientPmux { + if !flag.yamux && !flag.pmux { fmt.Println("[INFO] Hint: Server host (socat + curl)") fmt.Printf( " socat 'EXEC:curl -NsS %s!!EXEC:curl -NsST - %s' TCP:127.0.0.1:\n", @@ -166,16 +168,16 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC } fmt.Println("[INFO] Hint: Server host (piping-tunnel)") flags := "" - if clientSymmetricallyEncrypts { + if flag.symmetricallyEncrypts { flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) - if clientCipherType != cmd.DefaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, clientCipherType) + if flag.cipherType != cmd.DefaultCipherType { + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) } } - if clientYamux { + if flag.yamux { flags += fmt.Sprintf("--%s ", cmd.YamuxFlagLongName) } - if clientPmux { + if flag.pmux { flags += fmt.Sprintf("--%s ", cmd.PmuxFlagLongName) } fmt.Printf( @@ -217,7 +219,7 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p if err != nil { return err } - duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType, clientPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType, flag.pbkdf2JsonString) if err != nil { return err } @@ -260,10 +262,10 @@ func clientHandleWithYamux(ln net.Listener, httpClient *http.Client, headers []p func clientHandleWithPmux(ln net.Listener, httpClient *http.Client, headers []piping_util.KeyValue, clientToServerUrl string, serverToClientUrl string) error { var config cmd.ClientPmuxConfigJson - if json.Unmarshal([]byte(clientPmuxConfig), &config) != nil { + if json.Unmarshal([]byte(flag.pmuxConfig), &config) != nil { return errors.Errorf("invalid pmux config format") } - pmuxClient, err := pmux.Client(httpClient, headers, clientToServerUrl, serverToClientUrl, config.Hb, clientSymmetricallyEncrypts, clientSymmetricallyEncryptPassphrase, clientCipherType) + pmuxClient, err := pmux.Client(httpClient, headers, clientToServerUrl, serverToClientUrl, config.Hb, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType) if err != nil { if err == pmux.NonPmuxMimeTypeError { return errors.Errorf("--%s may be missing in server", cmd.PmuxFlagLongName) diff --git a/cmd/server/server.go b/cmd/server/server.go index 87843c5..1409e9c 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -18,31 +18,33 @@ import ( "time" ) -var serverTargetHost string -var serverHostPort int -var serverHostUnixSocket string -var serverClientToServerBufSize uint -var serverYamux bool -var serverPmux bool -var serverPmuxConfig string -var serverSymmetricallyEncrypts bool -var serverSymmetricallyEncryptPassphrase string -var serverCipherType string -var serverPbkdf2JsonString string +var flag struct { + targetHost string + serverHostPort int + serverHostUnixSocket string + clientToServerBufSize uint + yamux bool + pmux bool + pmuxConfig string + symmetricallyEncrypts bool + symmetricallyEncryptPassphrase string + cipherType string + pbkdf2JsonString string +} func init() { cmd.RootCmd.AddCommand(serverCmd) - serverCmd.Flags().StringVarP(&serverTargetHost, "host", "", "localhost", "Target host") - serverCmd.Flags().IntVarP(&serverHostPort, "port", "p", 0, "TCP port of server host") - serverCmd.Flags().StringVarP(&serverHostUnixSocket, "unix-socket", "", "", "Unix socket of server host") - serverCmd.Flags().UintVarP(&serverClientToServerBufSize, "cs-buf-size", "", 16, "Buffer size of client-to-server in bytes") - serverCmd.Flags().BoolVarP(&serverYamux, cmd.YamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") - serverCmd.Flags().BoolVarP(&serverPmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") - serverCmd.Flags().StringVarP(&serverPmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") - serverCmd.Flags().BoolVarP(&serverSymmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") - serverCmd.Flags().StringVarP(&serverSymmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - serverCmd.Flags().StringVarP(&serverCipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) - serverCmd.Flags().StringVarP(&serverPbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) + serverCmd.Flags().StringVarP(&flag.targetHost, "host", "", "localhost", "Target host") + serverCmd.Flags().IntVarP(&flag.serverHostPort, "port", "p", 0, "TCP port of server host") + serverCmd.Flags().StringVarP(&flag.serverHostUnixSocket, "unix-socket", "", "", "Unix socket of server host") + serverCmd.Flags().UintVarP(&flag.clientToServerBufSize, "cs-buf-size", "", 16, "Buffer size of client-to-server in bytes") + serverCmd.Flags().BoolVarP(&flag.yamux, cmd.YamuxFlagLongName, "", false, "Multiplex connection by hashicorp/yamux") + serverCmd.Flags().BoolVarP(&flag.pmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") + serverCmd.Flags().StringVarP(&flag.pmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") + serverCmd.Flags().BoolVarP(&flag.symmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") + serverCmd.Flags().StringVarP(&flag.symmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") + serverCmd.Flags().StringVarP(&flag.cipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + serverCmd.Flags().StringVarP(&flag.pbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } var serverCmd = &cobra.Command{ @@ -50,8 +52,8 @@ var serverCmd = &cobra.Command{ Short: "Run server-host", RunE: func(_ *cobra.Command, args []string) error { // Validate cipher-type - if serverSymmetricallyEncrypts { - if err := cmd.ValidateClientCipher(serverCipherType); err != nil { + if flag.symmetricallyEncrypts { + if err := cmd.ValidateClientCipher(flag.cipherType); err != nil { return err } } @@ -79,20 +81,20 @@ var serverCmd = &cobra.Command{ // Print hint printHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty - if serverSymmetricallyEncrypts { - err = cmd.MakeUserInputPassphraseIfEmpty(&serverSymmetricallyEncryptPassphrase) + if flag.symmetricallyEncrypts { + err = cmd.MakeUserInputPassphraseIfEmpty(&flag.symmetricallyEncryptPassphrase) if err != nil { return err } } // Use multiplexer with yamux - if serverYamux { + if flag.yamux { fmt.Println("[INFO] Multiplexing with hashicorp/yamux") return serverHandleWithYamux(httpClient, headers, clientToServerUrl, serverToClientUrl) } // If pmux is enabled - if serverPmux { + if flag.pmux { fmt.Println("[INFO] Multiplexing with pmux") return serverHandleWithPmux(httpClient, headers, clientToServerUrl, serverToClientUrl) } @@ -103,13 +105,13 @@ var serverCmd = &cobra.Command{ } defer conn.Close() // If encryption is enabled - if serverSymmetricallyEncrypts { + if flag.symmetricallyEncrypts { var duplex io.ReadWriteCloser duplex, err := piping_util.DuplexConnect(httpClient, headers, serverToClientUrl, clientToServerUrl) if err != nil { return err } - duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType, flag.pbkdf2JsonString) if err != nil { return err } @@ -128,7 +130,7 @@ var serverCmd = &cobra.Command{ }() return util.CombineErrors(<-fin, <-fin) } - err = piping_util.HandleDuplex(httpClient, conn, headers, serverToClientUrl, clientToServerUrl, serverClientToServerBufSize, nil, cmd.ShowProgress, cmd.MakeProgressMessage) + err = piping_util.HandleDuplex(httpClient, conn, headers, serverToClientUrl, clientToServerUrl, flag.clientToServerBufSize, nil, cmd.ShowProgress, cmd.MakeProgressMessage) fmt.Println() if err != nil { return err @@ -140,15 +142,15 @@ var serverCmd = &cobra.Command{ } func serverHostDial() (net.Conn, error) { - if serverHostUnixSocket == "" { - return net.Dial("tcp", fmt.Sprintf("%s:%d", serverTargetHost, serverHostPort)) + if flag.serverHostUnixSocket == "" { + return net.Dial("tcp", fmt.Sprintf("%s:%d", flag.targetHost, flag.serverHostPort)) } else { - return net.Dial("unix", serverHostUnixSocket) + return net.Dial("unix", flag.serverHostUnixSocket) } } func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string) { - if !serverYamux && !serverPmux { + if !flag.yamux && !flag.pmux { fmt.Println("[INFO] Hint: Client host (socat + curl)") fmt.Printf( " socat TCP-LISTEN:31376 'EXEC:curl -NsS %s!!EXEC:curl -NsST - %s'\n", @@ -157,16 +159,16 @@ func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, ) } flags := "" - if serverSymmetricallyEncrypts { + if flag.symmetricallyEncrypts { flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) - if serverCipherType != cmd.DefaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, serverCipherType) + if flag.cipherType != cmd.DefaultCipherType { + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) } } - if serverYamux { + if flag.yamux { flags += fmt.Sprintf("--%s ", cmd.YamuxFlagLongName) } - if serverPmux { + if flag.pmux { flags += fmt.Sprintf("--%s ", cmd.PmuxFlagLongName) } fmt.Println("[INFO] Hint: Client host (piping-tunnel)") @@ -201,7 +203,7 @@ func serverHandleWithYamux(httpClient *http.Client, headers []piping_util.KeyVal if err != nil { return err } - duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType, serverPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType, flag.pbkdf2JsonString) if err != nil { return err } @@ -256,10 +258,10 @@ func dialLoop() net.Conn { func serverHandleWithPmux(httpClient *http.Client, headers []piping_util.KeyValue, clientToServerUrl string, serverToClientUrl string) error { var config cmd.ServerPmuxConfigJson - if json.Unmarshal([]byte(serverPmuxConfig), &config) != nil { + if json.Unmarshal([]byte(flag.pmuxConfig), &config) != nil { return errors.Errorf("invalid pmux config format") } - pmuxServer := pmux.Server(httpClient, headers, serverToClientUrl, clientToServerUrl, config.Hb, serverSymmetricallyEncrypts, serverSymmetricallyEncryptPassphrase, serverCipherType) + pmuxServer := pmux.Server(httpClient, headers, serverToClientUrl, clientToServerUrl, config.Hb, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType) for { stream, err := pmuxServer.Accept() if err != nil { diff --git a/cmd/socks/socks.go b/cmd/socks/socks.go index 1ab25b8..b435a9f 100644 --- a/cmd/socks/socks.go +++ b/cmd/socks/socks.go @@ -16,23 +16,25 @@ import ( "strings" ) -var socksYamux bool -var socksPmux bool -var socksPmuxConfig string -var socksSymmetricallyEncrypts bool -var socksSymmetricallyEncryptPassphrase string -var socksCipherType string -var socksPbkdf2JsonString string +var flag struct { + yamux bool + pmux bool + pmuxConfig string + symmetricallyEncrypts bool + symmetricallyEncryptPassphrase string + cipherType string + pbkdf2JsonString string +} func init() { cmd.RootCmd.AddCommand(socksCmd) - socksCmd.Flags().BoolVarP(&socksYamux, "yamux", "", false, "Multiplex connection by hashicorp/yamux") - socksCmd.Flags().BoolVarP(&socksPmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") - socksCmd.Flags().StringVarP(&socksPmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") - socksCmd.Flags().BoolVarP(&socksSymmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") - socksCmd.Flags().StringVarP(&socksSymmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") - socksCmd.Flags().StringVarP(&socksCipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) - socksCmd.Flags().StringVarP(&socksPbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) + socksCmd.Flags().BoolVarP(&flag.yamux, "yamux", "", false, "Multiplex connection by hashicorp/yamux") + socksCmd.Flags().BoolVarP(&flag.pmux, cmd.PmuxFlagLongName, "", false, "Multiplex connection by pmux (experimental)") + socksCmd.Flags().StringVarP(&flag.pmuxConfig, cmd.PmuxConfigFlagLongName, "", `{"hb": true}`, "pmux config in JSON (experimental)") + socksCmd.Flags().BoolVarP(&flag.symmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") + socksCmd.Flags().StringVarP(&flag.symmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") + socksCmd.Flags().StringVarP(&flag.cipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + socksCmd.Flags().StringVarP(&flag.pbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } var socksCmd = &cobra.Command{ @@ -40,8 +42,8 @@ var socksCmd = &cobra.Command{ Short: "Run SOCKS server", RunE: func(_ *cobra.Command, args []string) error { // Validate cipher-type - if socksSymmetricallyEncrypts { - if err := cmd.ValidateClientCipher(socksCipherType); err != nil { + if flag.symmetricallyEncrypts { + if err := cmd.ValidateClientCipher(flag.cipherType); err != nil { return err } } @@ -69,15 +71,15 @@ var socksCmd = &cobra.Command{ // Print hint socksPrintHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty - if socksSymmetricallyEncrypts { - err = cmd.MakeUserInputPassphraseIfEmpty(&socksSymmetricallyEncryptPassphrase) + if flag.symmetricallyEncrypts { + err = cmd.MakeUserInputPassphraseIfEmpty(&flag.symmetricallyEncryptPassphrase) if err != nil { return err } } // If not using multiplexer - if !socksYamux && !socksPmux { + if !flag.yamux && !flag.pmux { return errors.Errorf("--%s or --%s must be specified", cmd.YamuxFlagLongName, cmd.PmuxFlagLongName) } @@ -85,7 +87,7 @@ var socksCmd = &cobra.Command{ socksServer, err := socks.New(socksConf) // If yamux is enabled - if socksYamux { + if flag.yamux { fmt.Println("[INFO] Multiplexing with hashicorp/yamux") return socksHandleWithYamux(socksServer, httpClient, headers, clientToServerUrl, serverToClientUrl) } @@ -97,7 +99,7 @@ var socksCmd = &cobra.Command{ } func socksPrintHintForClientHost(clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string) { - if !socksYamux && !socksPmux { + if !flag.yamux && !flag.pmux { fmt.Println("[INFO] Hint: Client host (socat + curl)") fmt.Printf( " socat TCP-LISTEN:31376 'EXEC:curl -NsS %s!!EXEC:curl -NsST - %s'\n", @@ -106,16 +108,16 @@ func socksPrintHintForClientHost(clientToServerUrl string, serverToClientUrl str ) } flags := "" - if socksSymmetricallyEncrypts { + if flag.symmetricallyEncrypts { flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) - if socksCipherType != cmd.DefaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, socksCipherType) + if flag.cipherType != cmd.DefaultCipherType { + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) } } - if socksYamux { + if flag.yamux { flags += fmt.Sprintf("--%s ", cmd.YamuxFlagLongName) } - if socksPmux { + if flag.pmux { flags += fmt.Sprintf("--%s ", cmd.PmuxFlagLongName) } fmt.Println("[INFO] Hint: Client host (piping-tunnel)") @@ -147,7 +149,7 @@ func socksHandleWithYamux(socksServer *socks.Server, httpClient *http.Client, he return res, nil }, ) - duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, socksSymmetricallyEncrypts, socksSymmetricallyEncryptPassphrase, socksCipherType, socksPbkdf2JsonString) + duplex, err = cmd.MakeDuplexWithEncryptionAndProgressIfNeed(duplex, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType, flag.pbkdf2JsonString) if err != nil { return err } @@ -166,10 +168,10 @@ func socksHandleWithYamux(socksServer *socks.Server, httpClient *http.Client, he func socksHandleWithPmux(socksServer *socks.Server, httpClient *http.Client, headers []piping_util.KeyValue, clientToServerUrl string, serverToClientUrl string) error { var config cmd.ServerPmuxConfigJson - if json.Unmarshal([]byte(socksPmuxConfig), &config) != nil { + if json.Unmarshal([]byte(flag.pmuxConfig), &config) != nil { return errors.Errorf("invalid pmux config format") } - pmuxServer := pmux.Server(httpClient, headers, serverToClientUrl, clientToServerUrl, config.Hb, socksSymmetricallyEncrypts, socksSymmetricallyEncryptPassphrase, socksCipherType) + pmuxServer := pmux.Server(httpClient, headers, serverToClientUrl, clientToServerUrl, config.Hb, flag.symmetricallyEncrypts, flag.symmetricallyEncryptPassphrase, flag.cipherType) for { stream, err := pmuxServer.Accept() if err != nil { From efe6627f0b4f831f62cd3f3b9612cc5e1f4609b7 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 20:35:34 +0900 Subject: [PATCH 12/21] update command hint using nc and Unix pipe --- cmd/client/client.go | 9 ++------- cmd/server/server.go | 8 ++------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/cmd/client/client.go b/cmd/client/client.go index 7e2e441..3cc5848 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -15,7 +15,6 @@ import ( "net" "net/http" "strconv" - "strings" ) var flag struct { @@ -159,12 +158,8 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC } fmt.Printf("[INFO] Client host listening on %s ...\n", listeningOn) if !flag.yamux && !flag.pmux { - fmt.Println("[INFO] Hint: Server host (socat + curl)") - fmt.Printf( - " socat 'EXEC:curl -NsS %s!!EXEC:curl -NsST - %s' TCP:127.0.0.1:\n", - strings.Replace(clientToServerUrl, ":", "\\:", -1), - strings.Replace(serverToClientUrl, ":", "\\:", -1), - ) + fmt.Println("[INFO] Hint: Server host (nc + curl)") + fmt.Printf(" curl -sSN %s | nc 127.0.0.1 | curl -sSNT - %s\n", clientToServerUrl, serverToClientUrl) } fmt.Println("[INFO] Hint: Server host (piping-tunnel)") flags := "" diff --git a/cmd/server/server.go b/cmd/server/server.go index 1409e9c..04aa58f 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -14,7 +14,6 @@ import ( "io" "net" "net/http" - "strings" "time" ) @@ -152,11 +151,8 @@ func serverHostDial() (net.Conn, error) { func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string) { if !flag.yamux && !flag.pmux { fmt.Println("[INFO] Hint: Client host (socat + curl)") - fmt.Printf( - " socat TCP-LISTEN:31376 'EXEC:curl -NsS %s!!EXEC:curl -NsST - %s'\n", - strings.Replace(serverToClientUrl, ":", "\\:", -1), - strings.Replace(clientToServerUrl, ":", "\\:", -1), - ) + // NOTE: nc can be used instead of socat but nc has variant: `nc -l 31376` in BSD version, `nc -l -p 31376` in GNU version. + fmt.Printf(" curl -NsS %s | socat TCP-LISTEN:31376 - | curl -NsST - %s\n", serverToClientUrl, clientToServerUrl) } flags := "" if flag.symmetricallyEncrypts { From 28d9fa5fb47190f5f7258ee2878ea3794cd6a06b Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 21:43:23 +0900 Subject: [PATCH 13/21] command hint for openssl aes ctr using nc/socat + curl + openssl --- cmd/client/client.go | 32 ++++++++++++++++++++++++++++---- cmd/server/server.go | 34 +++++++++++++++++++++++++++++----- cmd/shared.go | 41 ++++++++++++++++++++++++++++++++++------- 3 files changed, 91 insertions(+), 16 deletions(-) diff --git a/cmd/client/client.go b/cmd/client/client.go index 3cc5848..5fede17 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -84,8 +84,15 @@ var clientCmd = &cobra.Command{ if err != nil { return err } + var opensslAesCtrParams *cmd.OpensslAesCtrParams = nil + if flag.symmetricallyEncrypts { + opensslAesCtrParams, err = cmd.ParseOpensslAesCtrParams(flag.cipherType, flag.pbkdf2JsonString) + if err != nil { + return err + } + } // Print hint - printHintForServerHost(ln, clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) + printHintForServerHost(ln, clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath, opensslAesCtrParams) // Make user input passphrase if it is empty if flag.symmetricallyEncrypts { err = cmd.MakeUserInputPassphraseIfEmpty(&flag.symmetricallyEncryptPassphrase) @@ -147,7 +154,7 @@ var clientCmd = &cobra.Command{ }, } -func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string) { +func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string, opensslAesCtrParams *cmd.OpensslAesCtrParams) { var listeningOn string if addr, ok := ln.Addr().(*net.TCPAddr); ok { // (base: https://stackoverflow.com/a/43425461) @@ -158,8 +165,25 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC } fmt.Printf("[INFO] Client host listening on %s ...\n", listeningOn) if !flag.yamux && !flag.pmux { - fmt.Println("[INFO] Hint: Server host (nc + curl)") - fmt.Printf(" curl -sSN %s | nc 127.0.0.1 | curl -sSNT - %s\n", clientToServerUrl, serverToClientUrl) + if flag.symmetricallyEncrypts { + if opensslAesCtrParams != nil { + fmt.Println("[INFO] Hint: Server host (nc + curl + openssl)") + fmt.Printf( + " curl -sSN %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | nc 127.0.0.1 | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -sSNT - %s\n", + clientToServerUrl, + opensslAesCtrParams.KeyBits, + opensslAesCtrParams.Pbkdf2.Iter, + opensslAesCtrParams.Pbkdf2.HashNameForCommandHint, + opensslAesCtrParams.KeyBits, + opensslAesCtrParams.Pbkdf2.Iter, + opensslAesCtrParams.Pbkdf2.HashNameForCommandHint, + serverToClientUrl, + ) + } + } else { + fmt.Println("[INFO] Hint: Server host (nc + curl)") + fmt.Printf(" curl -sSN %s | nc 127.0.0.1 | curl -sSNT - %s\n", clientToServerUrl, serverToClientUrl) + } } fmt.Println("[INFO] Hint: Server host (piping-tunnel)") flags := "" diff --git a/cmd/server/server.go b/cmd/server/server.go index 04aa58f..4b3b7c9 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -77,8 +77,15 @@ var serverCmd = &cobra.Command{ if err != nil { return err } + var opensslAesCtrParams *cmd.OpensslAesCtrParams = nil + if flag.symmetricallyEncrypts { + opensslAesCtrParams, err = cmd.ParseOpensslAesCtrParams(flag.cipherType, flag.pbkdf2JsonString) + if err != nil { + return err + } + } // Print hint - printHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) + printHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath, opensslAesCtrParams) // Make user input passphrase if it is empty if flag.symmetricallyEncrypts { err = cmd.MakeUserInputPassphraseIfEmpty(&flag.symmetricallyEncryptPassphrase) @@ -148,11 +155,28 @@ func serverHostDial() (net.Conn, error) { } } -func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string) { +func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string, opensslAesCtrParams *cmd.OpensslAesCtrParams) { if !flag.yamux && !flag.pmux { - fmt.Println("[INFO] Hint: Client host (socat + curl)") - // NOTE: nc can be used instead of socat but nc has variant: `nc -l 31376` in BSD version, `nc -l -p 31376` in GNU version. - fmt.Printf(" curl -NsS %s | socat TCP-LISTEN:31376 - | curl -NsST - %s\n", serverToClientUrl, clientToServerUrl) + if flag.symmetricallyEncrypts { + if opensslAesCtrParams != nil { + fmt.Println("[INFO] Hint: Client host (socat + curl + openssl)") + fmt.Printf( + " curl -NsS %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | socat TCP-LISTEN:31376 - | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -NsST - %s\n", + serverToClientUrl, + opensslAesCtrParams.KeyBits, + opensslAesCtrParams.Pbkdf2.Iter, + opensslAesCtrParams.Pbkdf2.HashNameForCommandHint, + opensslAesCtrParams.KeyBits, + opensslAesCtrParams.Pbkdf2.Iter, + opensslAesCtrParams.Pbkdf2.HashNameForCommandHint, + clientToServerUrl, + ) + } + } else { + fmt.Println("[INFO] Hint: Client host (socat + curl)") + // NOTE: nc can be used instead of socat but nc has variant: `nc -l 31376` in BSD version, `nc -l -p 31376` in GNU version. + fmt.Printf(" curl -NsS %s | socat TCP-LISTEN:31376 - | curl -NsST - %s\n", serverToClientUrl, clientToServerUrl) + } } flags := "" if flag.symmetricallyEncrypts { diff --git a/cmd/shared.go b/cmd/shared.go index e2dc13f..a7926fc 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -49,9 +49,15 @@ type pbkdf2ConfigJson struct { Hash string `json:"hash"` } -type pbkdf2Config struct { - Iter int - Hash func() hash.Hash +type Pbkdf2Config struct { + Iter int + Hash func() hash.Hash + HashNameForCommandHint string // for command hint +} + +type OpensslAesCtrParams struct { + KeyBits uint16 + Pbkdf2 *Pbkdf2Config } var Vlog *verbose_logger.Logger @@ -88,7 +94,7 @@ func validateHashFunctionName(str string) (func() hash.Hash, error) { } } -func parsePbkdf2(str string) (*pbkdf2Config, error) { +func ParsePbkdf2(str string) (*Pbkdf2Config, error) { var configJson pbkdf2ConfigJson if json.Unmarshal([]byte(str), &configJson) != nil { return nil, errors.Errorf("invalid pbkdf2 JSON format: e.g. --%s='%s'", Pbkdf2FlagLongName, ExamplePbkdf2JsonStr()) @@ -97,7 +103,28 @@ func parsePbkdf2(str string) (*pbkdf2Config, error) { if err != nil { return nil, err } - return &pbkdf2Config{Iter: configJson.Iter, Hash: h}, nil + return &Pbkdf2Config{Iter: configJson.Iter, Hash: h, HashNameForCommandHint: configJson.Hash}, nil +} + +func ParseOpensslAesCtrParams(cipherType string, pbkdf2ConfigJsonStr string) (*OpensslAesCtrParams, error) { + var keyBits uint16 + switch cipherType { + case piping_util.CipherTypeOpensslAes128Ctr: + keyBits = 128 + case piping_util.CipherTypeOpensslAes256Ctr: + keyBits = 256 + } + switch cipherType { + case piping_util.CipherTypeOpensslAes128Ctr: + fallthrough + case piping_util.CipherTypeOpensslAes256Ctr: + pbkdf2Config, err := ParsePbkdf2(pbkdf2ConfigJsonStr) + if err != nil { + return nil, err + } + return &OpensslAesCtrParams{KeyBits: keyBits, Pbkdf2: pbkdf2Config}, nil + } + return nil, nil } func ExamplePbkdf2JsonStr() string { @@ -158,14 +185,14 @@ func MakeDuplexWithEncryptionAndProgressIfNeed(duplex io.ReadWriteCloser, encryp duplex, err = aes_ctr_duplex.Duplex(duplex, duplex, []byte(passphrase)) cipherName = "AES-CTR" case piping_util.CipherTypeOpensslAes128Ctr: - pbkdf2, err := parsePbkdf2(pbkdf2JsonStr) + pbkdf2, err := ParsePbkdf2(pbkdf2JsonStr) if err != nil { return nil, err } duplex, err = openssl_aes_ctr_duplex.Duplex(duplex, duplex, []byte(passphrase), pbkdf2.Iter, 128/8, pbkdf2.Hash) cipherName = "OpenSSL-AES-128-CTR-compatible" case piping_util.CipherTypeOpensslAes256Ctr: - pbkdf2, err := parsePbkdf2(pbkdf2JsonStr) + pbkdf2, err := ParsePbkdf2(pbkdf2JsonStr) if err != nil { return nil, err } From 46165ac657d2dd7beba35390a1d8fa321b3ef63c Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sat, 1 May 2021 22:06:13 +0900 Subject: [PATCH 14/21] command hint for openssl aes ctr using piping-tunnel --- cmd/client/client.go | 8 ++++++-- cmd/server/server.go | 8 ++++++-- cmd/socks/socks.go | 22 +++++++++------------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/cmd/client/client.go b/cmd/client/client.go index 5fede17..8d9748e 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -189,8 +189,12 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC flags := "" if flag.symmetricallyEncrypts { flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) - if flag.cipherType != cmd.DefaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) + switch flag.cipherType { + case piping_util.CipherTypeOpensslAes128Ctr: + fallthrough + case piping_util.CipherTypeOpensslAes256Ctr: + flags += fmt.Sprintf("--%s='%s' ", cmd.Pbkdf2FlagLongName, flag.pbkdf2JsonString) } } if flag.yamux { diff --git a/cmd/server/server.go b/cmd/server/server.go index 4b3b7c9..9d3a19d 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -181,8 +181,12 @@ func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, flags := "" if flag.symmetricallyEncrypts { flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) - if flag.cipherType != cmd.DefaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) + switch flag.cipherType { + case piping_util.CipherTypeOpensslAes128Ctr: + fallthrough + case piping_util.CipherTypeOpensslAes256Ctr: + flags += fmt.Sprintf("--%s='%s' ", cmd.Pbkdf2FlagLongName, flag.pbkdf2JsonString) } } if flag.yamux { diff --git a/cmd/socks/socks.go b/cmd/socks/socks.go index b435a9f..d94ea62 100644 --- a/cmd/socks/socks.go +++ b/cmd/socks/socks.go @@ -13,7 +13,6 @@ import ( "github.com/spf13/cobra" "io" "net/http" - "strings" ) var flag struct { @@ -69,7 +68,7 @@ var socksCmd = &cobra.Command{ return err } // Print hint - socksPrintHintForClientHost(clientToServerUrl, serverToClientUrl, clientToServerPath, serverToClientPath) + socksPrintHintForClientHost(clientToServerPath, serverToClientPath) // Make user input passphrase if it is empty if flag.symmetricallyEncrypts { err = cmd.MakeUserInputPassphraseIfEmpty(&flag.symmetricallyEncryptPassphrase) @@ -98,20 +97,17 @@ var socksCmd = &cobra.Command{ }, } -func socksPrintHintForClientHost(clientToServerUrl string, serverToClientUrl string, clientToServerPath string, serverToClientPath string) { - if !flag.yamux && !flag.pmux { - fmt.Println("[INFO] Hint: Client host (socat + curl)") - fmt.Printf( - " socat TCP-LISTEN:31376 'EXEC:curl -NsS %s!!EXEC:curl -NsST - %s'\n", - strings.Replace(serverToClientUrl, ":", "\\:", -1), - strings.Replace(clientToServerUrl, ":", "\\:", -1), - ) - } +// NOTE: multiplexing should be enabled, so there is no socat-curl hint +func socksPrintHintForClientHost(clientToServerPath string, serverToClientPath string) { flags := "" if flag.symmetricallyEncrypts { flags += fmt.Sprintf("-%s ", cmd.SymmetricallyEncryptsFlagShortName) - if flag.cipherType != cmd.DefaultCipherType { - flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) + flags += fmt.Sprintf("--%s=%s ", cmd.CipherTypeFlagLongName, flag.cipherType) + switch flag.cipherType { + case piping_util.CipherTypeOpensslAes128Ctr: + fallthrough + case piping_util.CipherTypeOpensslAes256Ctr: + flags += fmt.Sprintf("--%s='%s' ", cmd.Pbkdf2FlagLongName, flag.pbkdf2JsonString) } } if flag.yamux { From eacf13fbaa8429507d68a000f42e3f5fdf7fd051 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sun, 2 May 2021 11:36:00 +0900 Subject: [PATCH 15/21] add "NOTE: " comment for --pbkdf2 flag --- cmd/client/client.go | 1 + cmd/server/server.go | 1 + cmd/socks/socks.go | 1 + 3 files changed, 3 insertions(+) diff --git a/cmd/client/client.go b/cmd/client/client.go index 8d9748e..3e64b24 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -41,6 +41,7 @@ func init() { clientCmd.Flags().BoolVarP(&flag.symmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") clientCmd.Flags().StringVarP(&flag.symmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") clientCmd.Flags().StringVarP(&flag.cipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + // NOTE: default value of --pbkdf2 should be empty to detect key derive derivation from multiple algorithms in the future. clientCmd.Flags().StringVarP(&flag.pbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } diff --git a/cmd/server/server.go b/cmd/server/server.go index 9d3a19d..7d40b6f 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -43,6 +43,7 @@ func init() { serverCmd.Flags().BoolVarP(&flag.symmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") serverCmd.Flags().StringVarP(&flag.symmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") serverCmd.Flags().StringVarP(&flag.cipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + // NOTE: default value of --pbkdf2 should be empty to detect key derive derivation from multiple algorithms in the future. serverCmd.Flags().StringVarP(&flag.pbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } diff --git a/cmd/socks/socks.go b/cmd/socks/socks.go index d94ea62..4850349 100644 --- a/cmd/socks/socks.go +++ b/cmd/socks/socks.go @@ -33,6 +33,7 @@ func init() { socksCmd.Flags().BoolVarP(&flag.symmetricallyEncrypts, cmd.SymmetricallyEncryptsFlagLongName, cmd.SymmetricallyEncryptsFlagShortName, false, "Encrypt symmetrically") socksCmd.Flags().StringVarP(&flag.symmetricallyEncryptPassphrase, cmd.SymmetricallyEncryptPassphraseFlagLongName, "", "", "Passphrase for encryption") socksCmd.Flags().StringVarP(&flag.cipherType, cmd.CipherTypeFlagLongName, "", cmd.DefaultCipherType, fmt.Sprintf("Cipher type: %s, %s, %s, %s ", piping_util.CipherTypeAesCtr, piping_util.CipherTypeOpensslAes128Ctr, piping_util.CipherTypeOpensslAes256Ctr, piping_util.CipherTypeOpenpgp)) + // NOTE: default value of --pbkdf2 should be empty to detect key derive derivation from multiple algorithms in the future. socksCmd.Flags().StringVarP(&flag.pbkdf2JsonString, cmd.Pbkdf2FlagLongName, "", "", fmt.Sprintf("e.g. %s", cmd.ExamplePbkdf2JsonStr())) } From 29d51181732982dfeb11588f23b7b686a69beeb1 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sun, 2 May 2021 12:00:29 +0900 Subject: [PATCH 16/21] use read command to allow user input passphrase --- cmd/client/client.go | 4 ++-- cmd/server/server.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/client/client.go b/cmd/client/client.go index 3e64b24..abdd604 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -168,9 +168,9 @@ func printHintForServerHost(ln net.Listener, clientToServerUrl string, serverToC if !flag.yamux && !flag.pmux { if flag.symmetricallyEncrypts { if opensslAesCtrParams != nil { - fmt.Println("[INFO] Hint: Server host (nc + curl + openssl)") + fmt.Println("[INFO] Hint: Server host. should be replaced (nc + curl + openssl)") fmt.Printf( - " curl -sSN %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | nc 127.0.0.1 | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -sSNT - %s\n", + " read -p \"passphrase: \" -s pass && curl -sSN %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:$pass\" -bufsize 1 -pbkdf2 -iter %d -md %s | nc 127.0.0.1 | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:$pass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -sSNT - %s; unset pass\n", clientToServerUrl, opensslAesCtrParams.KeyBits, opensslAesCtrParams.Pbkdf2.Iter, diff --git a/cmd/server/server.go b/cmd/server/server.go index 7d40b6f..882bdbe 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -160,9 +160,9 @@ func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, if !flag.yamux && !flag.pmux { if flag.symmetricallyEncrypts { if opensslAesCtrParams != nil { - fmt.Println("[INFO] Hint: Client host (socat + curl + openssl)") + fmt.Println("[INFO] Hint: Client host. should be replaced (socat + curl + openssl)") fmt.Printf( - " curl -NsS %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | socat TCP-LISTEN:31376 - | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:mypass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -NsST - %s\n", + " read -p \"passphrase: \" -s pass && curl -NsS %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:$pass\" -bufsize 1 -pbkdf2 -iter %d -md %s | socat TCP-LISTEN:31376 - | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:$pass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -NsST - %s; unset pass\n", serverToClientUrl, opensslAesCtrParams.KeyBits, opensslAesCtrParams.Pbkdf2.Iter, From 1b69a94c20c579648406623024bd6435bab56460 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sun, 2 May 2021 12:06:00 +0900 Subject: [PATCH 17/21] rename --passphrase to --pass (breaking change) --- .github/workflows/ci.yml | 20 ++++++++++---------- cmd/shared.go | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cda9cd..f0f9a61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,8 +100,8 @@ jobs: - name: Encrypt with AES-CTR run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=aes-ctr --passphrase=mypass aesctraaa aesctrbbb & - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=aes-ctr --passphrase=mypass aesctraaa aesctrbbb & + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=aes-ctr --pass=mypass aesctraaa aesctrbbb & + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=aes-ctr --pass=mypass aesctraaa aesctrbbb & sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname @@ -109,8 +109,8 @@ jobs: - name: Encrypt with OpenSSL-compabile AES-CTR run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl1aaa openssl1bbb & echo $! > pid1 - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl1aaa openssl1bbb & echo $! > pid2 + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --pass=mypass openssl1aaa openssl1bbb & echo $! > pid1 + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --pass=mypass openssl1aaa openssl1bbb & echo $! > pid2 sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname @@ -119,7 +119,7 @@ jobs: run: | set -eux curl -sSN http://localhost:8080/openssl2aaa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc localhost 2022 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - http://localhost:8080/openssl2bbb & - ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl2aaa openssl2bbb & + ./piping-tunnel -s http://localhost:8080 client -p 3322 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --pass=mypass openssl2aaa openssl2bbb & sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) ssh -p 3322 -o 'StrictHostKeyChecking no' guest@localhost hostname @@ -127,7 +127,7 @@ jobs: - name: Encrypt with OpenSSL-compabile AES-CTR using real openssl in client host run: | set -eux - ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --passphrase=mypass openssl3aaa openssl3bbb & + ./piping-tunnel -s http://localhost:8080 server -p 2022 --symmetric --cipher-type=openssl-aes-256-ctr --pbkdf2='{"iter":100000,"hash":"sha256"}' --pass=mypass openssl3aaa openssl3bbb & curl -NsS http://localhost:8080/openssl3bbb | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | nc -l -p 3322 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -NsST - http://localhost:8080/openssl3aaa & sleep 1 # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) @@ -151,9 +151,9 @@ jobs: run: | set -eux # Run server-host with yamux (encrypt with AES-CTR) - ./piping-tunnel -s http://localhost:8080 server -p 2022 --yamux --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa-yamux bbb-yamux & echo $! > pid1 + ./piping-tunnel -s http://localhost:8080 server -p 2022 --yamux --symmetric --cipher-type=aes-ctr --pass=mypass aaa-yamux bbb-yamux & echo $! > pid1 # Run client-host with yamux (encrypt with AES-CTR) - ./piping-tunnel -s http://localhost:8080 client -p 4422 --yamux --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa-yamux bbb-yamux & echo $! > pid2 + ./piping-tunnel -s http://localhost:8080 client -p 4422 --yamux --symmetric --cipher-type=aes-ctr --pass=mypass aaa-yamux bbb-yamux & echo $! > pid2 sleep 1 # Check whether ssh multiple times # (base: -o option: https://www.cyberithub.com/ssh-host-key-verification-failed-error-in-linux/) @@ -177,9 +177,9 @@ jobs: run: | set -eux # Run socks with yamux (encrypt with AES-CTR) - ./piping-tunnel -s http://localhost:8080 socks --yamux --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa-socks bbb-socks & echo $! > pid1 + ./piping-tunnel -s http://localhost:8080 socks --yamux --symmetric --cipher-type=aes-ctr --pass=mypass aaa-socks bbb-socks & echo $! > pid1 # Run client-host with yamux (encrypt with AES-CTR) - ./piping-tunnel -s http://localhost:8080 client -p 1081 --yamux --symmetric --cipher-type=aes-ctr --passphrase=mypass aaa-socks bbb-socks & echo $! > pid2 + ./piping-tunnel -s http://localhost:8080 client -p 1081 --yamux --symmetric --cipher-type=aes-ctr --pass=mypass aaa-socks bbb-socks & echo $! > pid2 sleep 1 # NOTE: Depends on external resource: example.com curl -x socks5h://localhost:1081 https://example.com diff --git a/cmd/shared.go b/cmd/shared.go index a7926fc..e917251 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -29,7 +29,7 @@ const ( PmuxConfigFlagLongName = "pmux-config" SymmetricallyEncryptsFlagLongName = "symmetric" SymmetricallyEncryptsFlagShortName = "c" - SymmetricallyEncryptPassphraseFlagLongName = "passphrase" + SymmetricallyEncryptPassphraseFlagLongName = "pass" CipherTypeFlagLongName = "cipher-type" Pbkdf2FlagLongName = "pbkdf2" ) From 9ba3ae2d8cfadc46a8c858d897694b7208f2d671 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sun, 2 May 2021 13:43:59 +0900 Subject: [PATCH 18/21] docs: update Help --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6d48940..1956749 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,12 @@ Usage: piping-tunnel server [flags] Flags: - --cipher-type string Cipher type: aes-ctr, openpgp (default "aes-ctr") + --cipher-type string Cipher type: aes-ctr, openssl-aes-128-ctr, openssl-aes-256-ctr, openpgp (default "aes-ctr") --cs-buf-size uint Buffer size of client-to-server in bytes (default 16) -h, --help help for server --host string Target host (default "localhost") - --passphrase string Passphrase for encryption + --pass string Passphrase for encryption + --pbkdf2 string e.g. {"iter":100000,"hash":"sha256"} --pmux Multiplex connection by pmux (experimental) --pmux-config string pmux config in JSON (experimental) (default "{\"hb\": true}") -p, --port int TCP port of server host @@ -113,9 +114,10 @@ Usage: piping-tunnel client [flags] Flags: - --cipher-type string Cipher type: aes-ctr, openpgp (default "aes-ctr") + --cipher-type string Cipher type: aes-ctr, openssl-aes-128-ctr, openssl-aes-256-ctr, openpgp (default "aes-ctr") -h, --help help for client - --passphrase string Passphrase for encryption + --pass string Passphrase for encryption + --pbkdf2 string e.g. {"iter":100000,"hash":"sha256"} --pmux Multiplex connection by pmux (experimental) --pmux-config string pmux config in JSON (experimental) (default "{\"hb\": true}") -p, --port int TCP port of client host @@ -144,9 +146,10 @@ Usage: piping-tunnel socks [flags] Flags: - --cipher-type string Cipher type: aes-ctr, openpgp (default "aes-ctr") + --cipher-type string Cipher type: aes-ctr, openssl-aes-128-ctr, openssl-aes-256-ctr, openpgp (default "aes-ctr") -h, --help help for socks - --passphrase string Passphrase for encryption + --pass string Passphrase for encryption + --pbkdf2 string e.g. {"iter":100000,"hash":"sha256"} --pmux Multiplex connection by pmux (experimental) --pmux-config string pmux config in JSON (experimental) (default "{\"hb\": true}") -c, --symmetric Encrypt symmetrically From e49ea25f1e13ac852dc0f2e204917be44a909d4a Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Sun, 2 May 2021 16:45:38 +0900 Subject: [PATCH 19/21] go mod tidy --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index 913fece..ca83151 100644 --- a/go.sum +++ b/go.sum @@ -133,7 +133,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -164,7 +163,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -219,7 +217,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -247,7 +244,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From debb189a5a92b6b5168124ac3cad3e537a18ff5f Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Mon, 9 Aug 2021 10:03:05 +0900 Subject: [PATCH 20/21] improve message --- cmd/server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/server/server.go b/cmd/server/server.go index 882bdbe..5e87f10 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -160,7 +160,7 @@ func printHintForClientHost(clientToServerUrl string, serverToClientUrl string, if !flag.yamux && !flag.pmux { if flag.symmetricallyEncrypts { if opensslAesCtrParams != nil { - fmt.Println("[INFO] Hint: Client host. should be replaced (socat + curl + openssl)") + fmt.Println("[INFO] Hint: Client host. Port 31376 may be replaced (socat + curl + openssl)") fmt.Printf( " read -p \"passphrase: \" -s pass && curl -NsS %s | stdbuf -i0 -o0 openssl aes-%d-ctr -d -pass \"pass:$pass\" -bufsize 1 -pbkdf2 -iter %d -md %s | socat TCP-LISTEN:31376 - | stdbuf -i0 -o0 openssl aes-%d-ctr -pass \"pass:$pass\" -bufsize 1 -pbkdf2 -iter %d -md %s | curl -NsST - %s; unset pass\n", serverToClientUrl, From 76e6033bc8f668ea7ba983ca435af897b41eaf28 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Mon, 9 Aug 2021 10:10:20 +0900 Subject: [PATCH 21/21] bump: 0.10.0 --- CHANGELOG.md | 10 +++++++++- version/version.go | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c51fc..60acbec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) ## [Unreleased] +## [0.10.0] - 2021-08-09 +### Added +* Add OpenSSL-compatible AES-CTR encryption + +### Changed +* (breaking change) Rename --passphrase flag to --pass flag + ## [0.9.0] - 2021-04-23 ### Added * Create pmux, which is a multiplexer specialized in Piping Server @@ -90,7 +97,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) ### Added * Initial release -[Unreleased]: https://github.com/nwtgck/go-piping-tunnel/compare/v0.9.0...HEAD +[Unreleased]: https://github.com/nwtgck/go-piping-tunnel/compare/v0.10.0...HEAD +[0.10.0]: https://github.com/nwtgck/go-piping-tunnel/compare/v0.9.0...v0.10.0 [0.9.0]: https://github.com/nwtgck/go-piping-tunnel/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/nwtgck/go-piping-tunnel/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/nwtgck/go-piping-tunnel/compare/v0.6.0...v0.7.0 diff --git a/version/version.go b/version/version.go index 6e73a93..30e0f05 100644 --- a/version/version.go +++ b/version/version.go @@ -1,3 +1,3 @@ package version -const Version = "0.9.0" +const Version = "0.10.0"