update to be more go-ish

This commit is contained in:
AJ ONeal 2019-05-21 18:54:02 -06:00
parent 1e9f579043
commit 79c2ac5f3d
5 changed files with 75 additions and 34 deletions

View File

@ -50,14 +50,18 @@ For the moment you'll have to install go and compile `sclient` yourself:
* <https://golang.org/doc/install#install> * <https://golang.org/doc/install#install>
```bash ```bash
git clone https://git.coolaj86.com/coolaj86/sclient.go.git git clone https://git.rootprojects.org/root/sclient.go.git
pushd sclient.go pushd sclient.go
go build -o dist/sclient cmd/sclient/main.go go build -o dist/sclient cmd/sclient/main.go
rsync -av dist/sclient /usr/local/bin/sclient rsync -av dist/sclient /usr/local/bin/sclient
sclient example.com:443 localhost:3000
``` ```
Or
```bash ```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 Usage

View File

@ -7,7 +7,7 @@ import (
"strconv" "strconv"
"strings" "strings"
sclient "git.coolaj86.com/coolaj86/sclient.go" sclient "git.rootprojects.org/root/sclient.go"
) )
func usage() { func usage() {
@ -42,7 +42,7 @@ func main() {
} }
} }
opts := &sclient.PipeOpts{ sclient := &sclient.Tunnel{
RemotePort: 443, RemotePort: 443,
LocalAddress: "localhost", LocalAddress: "localhost",
InsecureSkipVerify: *insecure, InsecureSkipVerify: *insecure,
@ -57,17 +57,17 @@ func main() {
usage() usage()
os.Exit(0) os.Exit(0)
} }
opts.RemotePort = rport sclient.RemotePort = rport
} else if 1 != len(remote) { } else if 1 != len(remote) {
usage() usage()
os.Exit(0) os.Exit(0)
} }
opts.RemoteAddress = remote[0] sclient.RemoteAddress = remote[0]
if "-" == localstr || "|" == localstr { if "-" == localstr || "|" == localstr {
// User may specify stdin/stdout instead of net // User may specify stdin/stdout instead of net
opts.LocalAddress = localstr sclient.LocalAddress = localstr
opts.LocalPort = -1 sclient.LocalPort = -1
} else { } else {
// Test that argument is a local address // Test that argument is a local address
local := strings.Split(localstr, ":") local := strings.Split(localstr, ":")
@ -78,20 +78,19 @@ func main() {
usage() usage()
os.Exit(0) os.Exit(0)
} }
opts.LocalPort = lport sclient.LocalPort = lport
} else { } else {
lport, err := strconv.Atoi(local[1]) lport, err := strconv.Atoi(local[1])
if nil != err { if nil != err {
usage() usage()
os.Exit(0) os.Exit(0)
} }
opts.LocalAddress = local[0] sclient.LocalAddress = local[0]
opts.LocalPort = lport sclient.LocalPort = lport
} }
} }
sclient := &sclient.Tun{} err := sclient.DialAndListen()
err := sclient.DialAndListen(opts)
if nil != err { if nil != err {
fmt.Fprintf(os.Stderr, "%s\n", err) fmt.Fprintf(os.Stderr, "%s\n", err)
//usage() //usage()

38
doc.go Normal file
View File

@ -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

4
go.mod
View File

@ -1 +1,3 @@
module git.coolaj86.com/coolaj86/sclient.go module git.rootprojects.org/root/sclient.go
go 1.12

View File

@ -35,12 +35,12 @@ func (rw *stdnet) RemoteAddr() net.Addr {
} }
// not all of net.Conn, just RWC and RemoteAddr() // not all of net.Conn, just RWC and RemoteAddr()
type Rwc interface { type netReadWriteCloser interface {
io.ReadWriteCloser io.ReadWriteCloser
RemoteAddr() net.Addr RemoteAddr() net.Addr
} }
type PipeOpts struct { type Tunnel struct {
RemoteAddress string RemoteAddress string
RemotePort int RemotePort int
LocalAddress string LocalAddress string
@ -49,9 +49,7 @@ type PipeOpts struct {
ServerName string ServerName string
} }
type Tun struct{} func pipe(r netReadWriteCloser, w netReadWriteCloser, t string) {
func pipe(r Rwc, w Rwc, t string) {
buffer := make([]byte, 2048) buffer := make([]byte, 2048)
for { for {
done := false 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, sclient, err := tls.Dial("tcp", remote,
&tls.Config{ &tls.Config{
ServerName: opts.ServerName, ServerName: t.ServerName,
InsecureSkipVerify: opts.InsecureSkipVerify, InsecureSkipVerify: t.InsecureSkipVerify,
}) })
if err != nil { if err != nil {
@ -102,22 +100,22 @@ func handleConnection(remote string, conn Rwc, opts *PipeOpts) {
if "stdio" == conn.RemoteAddr().Network() { if "stdio" == conn.RemoteAddr().Network() {
fmt.Fprintf(os.Stdout, "(connected to %s:%d and reading from %s)\n", 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 { } else {
fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n", 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") go pipe(conn, sclient, "local")
pipe(sclient, conn, "remote") pipe(sclient, conn, "remote")
} }
func (*Tun) DialAndListen(opts *PipeOpts) error { func (t *Tunnel) DialAndListen() error {
remote := opts.RemoteAddress + ":" + strconv.Itoa(opts.RemotePort) remote := t.RemoteAddress + ":" + strconv.Itoa(t.RemotePort)
conn, err := tls.Dial("tcp", remote, conn, err := tls.Dial("tcp", remote,
&tls.Config{ &tls.Config{
ServerName: opts.ServerName, ServerName: t.ServerName,
InsecureSkipVerify: opts.InsecureSkipVerify, InsecureSkipVerify: t.InsecureSkipVerify,
}) })
if err != nil { if err != nil {
@ -127,28 +125,28 @@ func (*Tun) DialAndListen(opts *PipeOpts) error {
} }
// use stdin/stdout // use stdin/stdout
if "-" == opts.LocalAddress || "|" == opts.LocalAddress { if "-" == t.LocalAddress || "|" == t.LocalAddress {
var name string var name string
network := "stdio" network := "stdio"
if "|" == opts.LocalAddress { if "|" == t.LocalAddress {
name = "pipe" name = "pipe"
} else { } else {
name = "stdin" name = "stdin"
} }
conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}} conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}}
handleConnection(remote, conn, opts) t.handleConnection(remote, conn)
return nil return nil
} }
// use net.Conn // use net.Conn
local := opts.LocalAddress + ":" + strconv.Itoa(opts.LocalPort) local := t.LocalAddress + ":" + strconv.Itoa(t.LocalPort)
ln, err := net.Listen("tcp", local) ln, err := net.Listen("tcp", local)
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintf(os.Stdout, "[listening] %s:%d <= %s:%d\n", 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 { for {
conn, err := ln.Accept() conn, err := ln.Accept()
@ -156,6 +154,6 @@ func (*Tun) DialAndListen(opts *PipeOpts) error {
fmt.Fprintf(os.Stderr, "[error] %s\n", err) fmt.Fprintf(os.Stderr, "[error] %s\n", err)
continue continue
} }
go handleConnection(remote, conn, opts) go t.handleConnection(remote, conn)
} }
} }