From bc4aeb3124ef3b1806a34fb39f7cbbf9ec999e35 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 27 Oct 2023 15:16:29 -0600 Subject: [PATCH] feat: add --alpn (for h2, ssh, etc) --- .goreleaser.yml | 2 +- README.md | 18 +++++++++++++++--- cmd/sclient/main.go | 44 +++++++++++++++++++++++++++++++++++--------- sclient.go | 2 ++ 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 99b9c56..36e7e61 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,7 +3,7 @@ before: - go mod download - go generate ./... builds: - - main: ./cmd/sclient/main.go + - main: ./cmd/sclient/ env: - CGO_ENABLED=0 goos: diff --git a/README.md b/README.md index 28ff475..f4f8a11 100644 --- a/README.md +++ b/README.md @@ -70,10 +70,11 @@ sclient [flags] ``` - flags - - -s, --silent less verbose logging - - -k, --insecure ignore invalid TLS (SSL/HTTPS) certificates - - --servername spoof SNI (to disable use IP as <remote> and do + - `-s`, `--silent` less verbose logging + - `-k`, `--insecure` ignore invalid TLS (SSL/HTTPS) certificates + - `--servername ` spoof SNI (to disable use IP as <remote> and do not use this option) + - `--alpn ` - remote - must have servername (i.e. example.com) - port is optional (default is 443) @@ -81,6 +82,17 @@ sclient [flags] - address is optional (default is localhost) - must have port (i.e. 3000) + -alpn string + acceptable protocols, ex: 'h2,http/1.1' 'http/1.1' (default) 'ssh' (default "http/1.1") + -insecure + ignore bad TLS/SSL/HTTPS certificates + -k alias for --insecure + -s alias of --silent + -servername string + specify a servername different from (to disable SNI use an IP as and do use this option) + -silent + less verbose output + # Examples Bridge between `telebit.cloud` and local port `3000`. diff --git a/cmd/sclient/main.go b/cmd/sclient/main.go index bd9bbed..9916079 100644 --- a/cmd/sclient/main.go +++ b/cmd/sclient/main.go @@ -40,20 +40,30 @@ func usage() { func main() { if len(os.Args) >= 2 { - if "version" == strings.TrimLeft(os.Args[1], "-") { + if os.Args[1] == "-V" || strings.TrimLeft(os.Args[1], "-") == "version" { fmt.Printf("%s\n", ver()) os.Exit(0) return } } + var alpnList string + var insecure bool + var servername string + var silent bool + flag.Usage = usage - insecure := flag.Bool("k", false, "alias for --insecure") - silent := flag.Bool("s", false, "alias of --silent") - servername := flag.String("servername", "", "specify a servername different from (to disable SNI use an IP as and do not use this option)") - flag.BoolVar(insecure, "insecure", false, "ignore bad TLS/SSL/HTTPS certificates") - flag.BoolVar(silent, "silent", false, "less verbose output") + + flag.StringVar(&alpnList, "alpn", "", "acceptable protocols, ex: 'h2,http/1.1' 'http/1.1' 'ssh'") + flag.BoolVar(&insecure, "k", false, "alias for --insecure") + flag.BoolVar(&silent, "s", false, "alias of --silent") + flag.StringVar(&servername, "servername", "", "specify a servername different from (to disable SNI use an IP as and do not use this option)") + flag.BoolVar(&insecure, "insecure", false, "ignore bad TLS/SSL/HTTPS certificates") + flag.BoolVar(&silent, "silent", false, "less verbose output") + flag.Parse() + + alpns := parseOptionList(alpnList) remotestr := flag.Arg(0) localstr := flag.Arg(1) @@ -71,9 +81,10 @@ func main() { sclient := &sclient.Tunnel{ RemotePort: 443, LocalAddress: "localhost", - InsecureSkipVerify: *insecure, - ServerName: *servername, - Silent: *silent, + InsecureSkipVerify: insecure, + ServerName: servername, + Silent: silent, + NextProtos: alpns, } remote := strings.Split(remotestr, ":") @@ -124,3 +135,18 @@ func main() { //os.Exit(6) } } + +// parsers "a,b,c" "a b c" and "a, b, c" all the same +func parseOptionList(optionList string) []string { + optionList = strings.TrimSpace(optionList) + + if len(optionList) == 0 { + return nil + } + + options := []string{} + optionList = strings.ReplaceAll(optionList, ",", " ") + options = strings.Fields(optionList) + + return options +} diff --git a/sclient.go b/sclient.go index b8f82c9..4a54f24 100644 --- a/sclient.go +++ b/sclient.go @@ -17,6 +17,7 @@ type Tunnel struct { LocalAddress string LocalPort int InsecureSkipVerify bool + NextProtos []string ServerName string Silent bool } @@ -29,6 +30,7 @@ func (t *Tunnel) DialAndListen() error { &tls.Config{ ServerName: t.ServerName, InsecureSkipVerify: t.InsecureSkipVerify, + NextProtos: t.NextProtos, }) if err != nil {