update to be more go-ish
This commit is contained in:
parent
1e9f579043
commit
79c2ac5f3d
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
4
go.mod
|
@ -1 +1,3 @@
|
||||||
module git.coolaj86.com/coolaj86/sclient.go
|
module git.rootprojects.org/root/sclient.go
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
38
sclient.go
38
sclient.go
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue