From 79c2ac5f3d80f2f303a7b9f774eeaf1eda719cb9 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Tue, 21 May 2019 18:54:02 -0600 Subject: [PATCH] update to be more go-ish --- README.md | 8 ++++++-- cmd/sclient/main.go | 21 ++++++++++----------- doc.go | 38 ++++++++++++++++++++++++++++++++++++++ go.mod | 4 +++- sclient.go | 38 ++++++++++++++++++-------------------- 5 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 doc.go diff --git a/README.md b/README.md index ea5cf74..052690d 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,18 @@ For the moment you'll have to install go and compile `sclient` yourself: * ```bash -git clone https://git.coolaj86.com/coolaj86/sclient.go.git +git clone https://git.rootprojects.org/root/sclient.go.git pushd sclient.go go build -o dist/sclient cmd/sclient/main.go rsync -av dist/sclient /usr/local/bin/sclient +sclient example.com:443 localhost:3000 ``` +Or + ```bash -go run cmd/sclient/main.go example.com:443 localhost:3000 +go get git.rootprojects.org/root/sclient.go/cmd/sclient +go run git.rootprojects.org/root/sclient.go/cmd/sclient example.com:443 localhost:3000 ``` Usage diff --git a/cmd/sclient/main.go b/cmd/sclient/main.go index 35421e0..5831575 100644 --- a/cmd/sclient/main.go +++ b/cmd/sclient/main.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - sclient "git.coolaj86.com/coolaj86/sclient.go" + sclient "git.rootprojects.org/root/sclient.go" ) func usage() { @@ -42,7 +42,7 @@ func main() { } } - opts := &sclient.PipeOpts{ + sclient := &sclient.Tunnel{ RemotePort: 443, LocalAddress: "localhost", InsecureSkipVerify: *insecure, @@ -57,17 +57,17 @@ func main() { usage() os.Exit(0) } - opts.RemotePort = rport + sclient.RemotePort = rport } else if 1 != len(remote) { usage() os.Exit(0) } - opts.RemoteAddress = remote[0] + sclient.RemoteAddress = remote[0] if "-" == localstr || "|" == localstr { // User may specify stdin/stdout instead of net - opts.LocalAddress = localstr - opts.LocalPort = -1 + sclient.LocalAddress = localstr + sclient.LocalPort = -1 } else { // Test that argument is a local address local := strings.Split(localstr, ":") @@ -78,20 +78,19 @@ func main() { usage() os.Exit(0) } - opts.LocalPort = lport + sclient.LocalPort = lport } else { lport, err := strconv.Atoi(local[1]) if nil != err { usage() os.Exit(0) } - opts.LocalAddress = local[0] - opts.LocalPort = lport + sclient.LocalAddress = local[0] + sclient.LocalPort = lport } } - sclient := &sclient.Tun{} - err := sclient.DialAndListen(opts) + err := sclient.DialAndListen() if nil != err { fmt.Fprintf(os.Stderr, "%s\n", err) //usage() diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..612d16f --- /dev/null +++ b/doc.go @@ -0,0 +1,38 @@ +/* +Package sclient unwraps SSL. + +It makes secure remote connections (such as HTTPS) available locally as plain-text connections - +similar to `stunnel` or `openssl s_client`. + +There are a variety of reasons that you might want to do that, +but we created it specifically to be able to upgrade applications with legacy +security protocols - like SSH, OpenVPN, and Postgres - to be able to take +advantage of the features modern TLS, such as ALPN and SNI +(which makes them routable through almost every type of firewall). + +See https://telebit.cloud/sclient for more info. + +Try the CLI + + go get git.rootprojects.org/root/sclient.go/cmd/sclient + go run git.rootprojects.org/root/sclient.go/cmd/sclient example.com:443 localhost:3000 + +Package Basics + + servername := "example.com" + + sclient := &sclient.Tunnel{ + ServerName: servername, + RemoteAddress: servername, + RemotePort: 443, + LocalAddress: "localhost", + LocalPort: 3000, + } + + err := sclient.DialAndListen() + +Pre-built versions for various platforms are also available at +https://telebit.cloud/sclient + +*/ +package sclient diff --git a/go.mod b/go.mod index 8d4f363..f1932f0 100644 --- a/go.mod +++ b/go.mod @@ -1 +1,3 @@ -module git.coolaj86.com/coolaj86/sclient.go +module git.rootprojects.org/root/sclient.go + +go 1.12 diff --git a/sclient.go b/sclient.go index 96303d1..a8bf17d 100644 --- a/sclient.go +++ b/sclient.go @@ -35,12 +35,12 @@ func (rw *stdnet) RemoteAddr() net.Addr { } // not all of net.Conn, just RWC and RemoteAddr() -type Rwc interface { +type netReadWriteCloser interface { io.ReadWriteCloser RemoteAddr() net.Addr } -type PipeOpts struct { +type Tunnel struct { RemoteAddress string RemotePort int LocalAddress string @@ -49,9 +49,7 @@ type PipeOpts struct { ServerName string } -type Tun struct{} - -func pipe(r Rwc, w Rwc, t string) { +func pipe(r netReadWriteCloser, w netReadWriteCloser, t string) { buffer := make([]byte, 2048) for { done := false @@ -87,11 +85,11 @@ func pipe(r Rwc, w Rwc, t string) { } } -func handleConnection(remote string, conn Rwc, opts *PipeOpts) { +func (t *Tunnel) handleConnection(remote string, conn netReadWriteCloser) { sclient, err := tls.Dial("tcp", remote, &tls.Config{ - ServerName: opts.ServerName, - InsecureSkipVerify: opts.InsecureSkipVerify, + ServerName: t.ServerName, + InsecureSkipVerify: t.InsecureSkipVerify, }) if err != nil { @@ -102,22 +100,22 @@ func handleConnection(remote string, conn Rwc, opts *PipeOpts) { if "stdio" == conn.RemoteAddr().Network() { fmt.Fprintf(os.Stdout, "(connected to %s:%d and reading from %s)\n", - opts.RemoteAddress, opts.RemotePort, conn.RemoteAddr().String()) + t.RemoteAddress, t.RemotePort, conn.RemoteAddr().String()) } else { fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n", - strings.Replace(conn.RemoteAddr().String(), "[::1]:", "localhost:", 1), opts.RemoteAddress, opts.RemotePort) + strings.Replace(conn.RemoteAddr().String(), "[::1]:", "localhost:", 1), t.RemoteAddress, t.RemotePort) } go pipe(conn, sclient, "local") pipe(sclient, conn, "remote") } -func (*Tun) DialAndListen(opts *PipeOpts) error { - remote := opts.RemoteAddress + ":" + strconv.Itoa(opts.RemotePort) +func (t *Tunnel) DialAndListen() error { + remote := t.RemoteAddress + ":" + strconv.Itoa(t.RemotePort) conn, err := tls.Dial("tcp", remote, &tls.Config{ - ServerName: opts.ServerName, - InsecureSkipVerify: opts.InsecureSkipVerify, + ServerName: t.ServerName, + InsecureSkipVerify: t.InsecureSkipVerify, }) if err != nil { @@ -127,28 +125,28 @@ func (*Tun) DialAndListen(opts *PipeOpts) error { } // use stdin/stdout - if "-" == opts.LocalAddress || "|" == opts.LocalAddress { + if "-" == t.LocalAddress || "|" == t.LocalAddress { var name string network := "stdio" - if "|" == opts.LocalAddress { + if "|" == t.LocalAddress { name = "pipe" } else { name = "stdin" } conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}} - handleConnection(remote, conn, opts) + t.handleConnection(remote, conn) return nil } // use net.Conn - local := opts.LocalAddress + ":" + strconv.Itoa(opts.LocalPort) + local := t.LocalAddress + ":" + strconv.Itoa(t.LocalPort) ln, err := net.Listen("tcp", local) if err != nil { return err } fmt.Fprintf(os.Stdout, "[listening] %s:%d <= %s:%d\n", - opts.RemoteAddress, opts.RemotePort, opts.LocalAddress, opts.LocalPort) + t.RemoteAddress, t.RemotePort, t.LocalAddress, t.LocalPort) for { conn, err := ln.Accept() @@ -156,6 +154,6 @@ func (*Tun) DialAndListen(opts *PipeOpts) error { fmt.Fprintf(os.Stderr, "[error] %s\n", err) continue } - go handleConnection(remote, conn, opts) + go t.handleConnection(remote, conn) } }