From 959268bf31b390ffa7a74ba209c9a7f796fa2a10 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Tue, 21 May 2019 19:15:43 -0600 Subject: [PATCH] doc updates --- doc.go | 16 +++++--- sclient.go | 117 +++++++++++++++++++++++++++-------------------------- 2 files changed, 71 insertions(+), 62 deletions(-) diff --git a/doc.go b/doc.go index 612d16f..fdbb06b 100644 --- a/doc.go +++ b/doc.go @@ -1,24 +1,32 @@ /* -Package sclient unwraps SSL. +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 +security protocols - like SSH, OpenVPN, and Postgres - to take +advantage of the features of 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 +If you'd like to better understand what sclient does, you can try it out with `go run`: + 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 + curl http://localhost:3000 -H "Host: example.com" + +Pre-built versions for various platforms are also available at +https://telebit.cloud/sclient Package Basics +The general use of + servername := "example.com" sclient := &sclient.Tunnel{ @@ -31,8 +39,6 @@ Package Basics err := sclient.DialAndListen() -Pre-built versions for various platforms are also available at -https://telebit.cloud/sclient */ package sclient diff --git a/sclient.go b/sclient.go index a8bf17d..7cb3296 100644 --- a/sclient.go +++ b/sclient.go @@ -10,6 +10,66 @@ import ( "strings" ) +// Tunnel specifies which remote encrypted connection to make available as a plain connection locally. +type Tunnel struct { + RemoteAddress string + RemotePort int + LocalAddress string + LocalPort int + InsecureSkipVerify bool + ServerName string +} + +// DialAndListen will create a test TLS connection to the remote address and then +// begin listening locally. Each local connection will result in a separate remote connection. +func (t *Tunnel) DialAndListen() error { + remote := t.RemoteAddress + ":" + strconv.Itoa(t.RemotePort) + conn, err := tls.Dial("tcp", remote, + &tls.Config{ + ServerName: t.ServerName, + InsecureSkipVerify: t.InsecureSkipVerify, + }) + + if err != nil { + fmt.Fprintf(os.Stderr, "[warn] '%s' may not be accepting connections: %s\n", remote, err) + } else { + conn.Close() + } + + // use stdin/stdout + if "-" == t.LocalAddress || "|" == t.LocalAddress { + var name string + network := "stdio" + if "|" == t.LocalAddress { + name = "pipe" + } else { + name = "stdin" + } + conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}} + t.handleConnection(remote, conn) + return nil + } + + // use net.Conn + 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", + t.RemoteAddress, t.RemotePort, t.LocalAddress, t.LocalPort) + + for { + conn, err := ln.Accept() + if nil != err { + fmt.Fprintf(os.Stderr, "[error] %s\n", err) + continue + } + go t.handleConnection(remote, conn) + } +} + // I wonder if I can get this to exactly mirror UnixAddr without passing it in type stdaddr struct { net.UnixAddr @@ -40,15 +100,6 @@ type netReadWriteCloser interface { RemoteAddr() net.Addr } -type Tunnel struct { - RemoteAddress string - RemotePort int - LocalAddress string - LocalPort int - InsecureSkipVerify bool - ServerName string -} - func pipe(r netReadWriteCloser, w netReadWriteCloser, t string) { buffer := make([]byte, 2048) for { @@ -109,51 +160,3 @@ func (t *Tunnel) handleConnection(remote string, conn netReadWriteCloser) { go pipe(conn, sclient, "local") pipe(sclient, conn, "remote") } - -func (t *Tunnel) DialAndListen() error { - remote := t.RemoteAddress + ":" + strconv.Itoa(t.RemotePort) - conn, err := tls.Dial("tcp", remote, - &tls.Config{ - ServerName: t.ServerName, - InsecureSkipVerify: t.InsecureSkipVerify, - }) - - if err != nil { - fmt.Fprintf(os.Stderr, "[warn] '%s' may not be accepting connections: %s\n", remote, err) - } else { - conn.Close() - } - - // use stdin/stdout - if "-" == t.LocalAddress || "|" == t.LocalAddress { - var name string - network := "stdio" - if "|" == t.LocalAddress { - name = "pipe" - } else { - name = "stdin" - } - conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}} - t.handleConnection(remote, conn) - return nil - } - - // use net.Conn - 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", - t.RemoteAddress, t.RemotePort, t.LocalAddress, t.LocalPort) - - for { - conn, err := ln.Accept() - if nil != err { - fmt.Fprintf(os.Stderr, "[error] %s\n", err) - continue - } - go t.handleConnection(remote, conn) - } -}