mirror of
				https://github.com/therootcompany/sclient
				synced 2024-11-16 17:09:00 +00:00 
			
		
		
		
	Compare commits
	
		
			14 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8ba42a09a4 | |||
| 66f2d41c6b | |||
|  | ca84ed48de | ||
| 455db50928 | |||
| 5b0374f2e9 | |||
| af639f0b2e | |||
| 828344802b | |||
| 5334a377a4 | |||
| 959268bf31 | |||
| 79c2ac5f3d | |||
| 1e9f579043 | |||
| 8042bcf41c | |||
| 312a5de977 | |||
| d4eb17ea44 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1,4 @@ | |||||||
|  | /sclient | ||||||
|  | /cmd/sclient/sclient | ||||||
|  | 
 | ||||||
| dist | dist | ||||||
|  | |||||||
							
								
								
									
										37
									
								
								.goreleaser.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.goreleaser.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | before: | ||||||
|  |   hooks: | ||||||
|  |     - go mod download | ||||||
|  |     - go generate ./... | ||||||
|  | builds: | ||||||
|  |   - main: ./cmd/sclient/main.go | ||||||
|  |     env: | ||||||
|  |       - CGO_ENABLED=0 | ||||||
|  |     goos: | ||||||
|  |       - linux | ||||||
|  |       - windows | ||||||
|  |       - darwin | ||||||
|  |     goarch: | ||||||
|  |       - 386 | ||||||
|  |       - amd64 | ||||||
|  |       - arm | ||||||
|  |       - arm64 | ||||||
|  |     goarm: | ||||||
|  |       - 6 | ||||||
|  |       - 7 | ||||||
|  | archives: | ||||||
|  |   - replacements: | ||||||
|  |       386: i386 | ||||||
|  |       amd64: x86_64 | ||||||
|  |     format_overrides: | ||||||
|  |       - goos: windows | ||||||
|  |         format: zip | ||||||
|  | checksum: | ||||||
|  |   name_template: 'checksums.txt' | ||||||
|  | snapshot: | ||||||
|  |   name_template: "{{ .Tag }}-next" | ||||||
|  | changelog: | ||||||
|  |   sort: asc | ||||||
|  |   filters: | ||||||
|  |     exclude: | ||||||
|  |       - '^docs:' | ||||||
|  |       - '^test:' | ||||||
							
								
								
									
										119
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								README.md
									
									
									
									
									
								
							| @ -1,5 +1,4 @@ | |||||||
| sclient.go | # sclient | ||||||
| ========== |  | ||||||
| 
 | 
 | ||||||
| Secure Client for exposing TLS (aka SSL) secured services as plain-text connections locally. | Secure Client for exposing TLS (aka SSL) secured services as plain-text connections locally. | ||||||
| 
 | 
 | ||||||
| @ -8,76 +7,75 @@ Also ideal for multiplexing a single port with multiple protocols using SNI. | |||||||
| Unwrap a TLS connection: | Unwrap a TLS connection: | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| $ sclient whatever.com:443 localhost:3000 | sclient whatever.com:443 localhost:3000 | ||||||
|  | 
 | ||||||
| > [listening] whatever.com:443 <= localhost:3000 | > [listening] whatever.com:443 <= localhost:3000 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Connect via Telnet | Connect via Telnet | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| $ telnet localhost 3000 | telnet localhost 3000 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Connect via netcat (nc) | Connect via netcat (nc) | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| $ nc localhost 3000 | nc localhost 3000 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| cURL | cURL | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| $ curl http://localhost:3000 -H 'Host: whatever.com' | curl http://localhost:3000 -H 'Host: whatever.com' | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| A poor man's (or Windows user's) makeshift replacement for `openssl s_client`, `stunnel`, or `socat`. | A poor man's (or Windows user's) makeshift replacement for `openssl s_client`, `stunnel`, or `socat`. | ||||||
| 
 | 
 | ||||||
| Install | # Table of Contents | ||||||
| ======= | 
 | ||||||
|  | - [Install](#install) | ||||||
|  | - [Usage](#usage) | ||||||
|  | - [Examples](#examples) | ||||||
|  | - [Build from Source](#build-from-source) | ||||||
|  | 
 | ||||||
|  | # Install | ||||||
|  | 
 | ||||||
|  | ### Mac, Linux | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | curl -sS https://webinstall.dev/sclient | bash | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | curl.exe -A MS https://webinstall.dev/sclient | powershell | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| ### Downloads | ### Downloads | ||||||
| 
 | 
 | ||||||
| * [Windows 10](https://telebit.cloud/sclient/dist/windows/amd64/sclient.exe) | Check the [Github Releases](https://github.com/therootcompany/sclient/releases) for | ||||||
| * [Mac OS X](https://telebit.cloud/sclient/dist/darwin/amd64/sclient) |  | ||||||
| * [Linux (x64)](https://telebit.cloud/sclient/dist/linux/amd64/sclient) |  | ||||||
| * [Raspberry Pi (armv7)](https://telebit.cloud/sclient/dist/linux/armv7/sclient) |  | ||||||
| * more downloads <https://telebit.cloud/sclient/> |  | ||||||
| 
 | 
 | ||||||
| ### Build from source | - macOS (x64) Apple Silicon [coming soon](https://github.com/golang/go/issues/39782) | ||||||
|  | - Linux (x64, i386, arm64, arm6, arm7) | ||||||
|  | - Windows 10 (x64, i386) | ||||||
| 
 | 
 | ||||||
| For the moment you'll have to install go and compile `sclient` yourself: | # Usage | ||||||
| 
 |  | ||||||
| * <https://golang.org/doc/install#install> |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| git clone https://git.coolaj86.com/coolaj86/sclient.go.git |  | ||||||
| pushd sclient.go |  | ||||||
| go build -o dist/sclient sclient*.go |  | ||||||
| rsync -av dist/sclient /usr/local/bin/sclient |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| go run sclient*.go example.com:443 localhost:3000 |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Usage |  | ||||||
| ===== |  | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| sclient [flags] <remote> <local> | sclient [flags] <remote> <local> | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| * flags | - flags | ||||||
|   * -k, --insecure ignore invalid TLS (SSL/HTTPS) certificates |   - -k, --insecure ignore invalid TLS (SSL/HTTPS) certificates | ||||||
| * remote |   - --servername <string> spoof SNI (to disable use IP as <remote> and do not use this option) | ||||||
|   * must have servername (i.e. example.com) | - remote | ||||||
|   * port is optional (default is 443) |   - must have servername (i.e. example.com) | ||||||
| * local |   - port is optional (default is 443) | ||||||
|   * address is optional (default is localhost) | - local | ||||||
|   * must have port (i.e. 3000) |   - address is optional (default is localhost) | ||||||
|  |   - must have port (i.e. 3000) | ||||||
| 
 | 
 | ||||||
| Examples | # Examples | ||||||
| ======== |  | ||||||
| 
 | 
 | ||||||
| Bridge between `telebit.cloud` and local port `3000`. | Bridge between `telebit.cloud` and local port `3000`. | ||||||
| 
 | 
 | ||||||
| @ -112,3 +110,42 @@ Piping | |||||||
| ```bash | ```bash | ||||||
| printf "GET / HTTP/1.1\r\nHost: telebit.cloud\r\n\r\n" | sclient telebit.cloud:443 | printf "GET / HTTP/1.1\r\nHost: telebit.cloud\r\n\r\n" | sclient telebit.cloud:443 | ||||||
| ``` | ``` | ||||||
|  | 
 | ||||||
|  | Testing for security vulnerabilities on the remote: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | sclient --servername "Robert'); DROP TABLE Students;" -k example.com localhost:3000 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | sclient --servername "../../../.hidden/private.txt" -k example.com localhost:3000 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Build from source | ||||||
|  | 
 | ||||||
|  | You'll need to install [Go](https://golang.org). | ||||||
|  | See [webinstall.dev/golang](https://webinstall.dev/golang) for install instructions. | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | curl -sS https://webinstall.dev/golang | bash | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Then you can install and run as per usual. | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | git clone https://git.rootprojects.org/root/sclient.go.git | ||||||
|  | 
 | ||||||
|  | pushd sclient.go | ||||||
|  |   go build -o dist/sclient cmd/sclient/main.go | ||||||
|  |   sudo rsync -av dist/sclient /usr/local/bin/sclient | ||||||
|  | popd | ||||||
|  | 
 | ||||||
|  | sclient example.com:443 localhost:3000 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Install or Run with Go | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | 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 | ||||||
|  | ``` | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								build-all.sh
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								build-all.sh
									
									
									
									
									
								
							| @ -1,31 +0,0 @@ | |||||||
| #GOOS=windows GOARCH=amd64 go install |  | ||||||
| go tool dist list |  | ||||||
| 
 |  | ||||||
| echo "" |  | ||||||
| 
 |  | ||||||
| echo "" |  | ||||||
| echo "Windows amd64" |  | ||||||
| GOOS=windows GOARCH=amd64 go build -o dist/windows/amd64/sclient.exe sclient*.go |  | ||||||
| echo "Windows 386" |  | ||||||
| GOOS=windows GOARCH=386 go build -o dist/windows/386/sclient.exe sclient*.go |  | ||||||
| 
 |  | ||||||
| echo "" |  | ||||||
| echo "Darwin (macOS) amd64" |  | ||||||
| GOOS=darwin GOARCH=amd64 go build -o dist/darwin/amd64/sclient sclient*.go |  | ||||||
| 
 |  | ||||||
| echo "" |  | ||||||
| echo "Linux amd64" |  | ||||||
| GOOS=linux GOARCH=amd64 go build -o dist/linux/amd64/sclient sclient*.go |  | ||||||
| echo "Linux 386" |  | ||||||
| 
 |  | ||||||
| echo "" |  | ||||||
| GOOS=linux GOARCH=386 go build -o dist/linux/386/sclient sclient*.go |  | ||||||
| echo "RPi 3 B+ ARMv7" |  | ||||||
| GOOS=linux GOARCH=arm GOARM=7 go build -o dist/linux/armv7/sclient sclient*.go |  | ||||||
| echo "RPi Zero ARMv5" |  | ||||||
| GOOS=linux GOARCH=arm GOARM=5 go build -o dist/linux/armv5/sclient sclient*.go |  | ||||||
| 
 |  | ||||||
| echo "" |  | ||||||
| echo "" |  | ||||||
| 
 |  | ||||||
| rsync -av ./dist/ root@telebit.cloud:/opt/telebit-relay/lib/extensions/admin/sclient/dist/ |  | ||||||
| @ -6,24 +6,53 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	sclient "git.rootprojects.org/root/sclient.go" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | var ( | ||||||
|  | 	// commit refers to the abbreviated commit hash | ||||||
|  | 	commit = "0000000" | ||||||
|  | 	// version refers to the most recent tag, plus any commits made since then | ||||||
|  | 	version = "v0.0.0-pre0+0000000" | ||||||
|  | 	// GitTimestamp refers to the timestamp of the most recent commit | ||||||
|  | 	date = "0000-00-00T00:00:00+0000" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func ver() string { | ||||||
|  | 	return fmt.Sprintf("sclient %s (%s) %s", version, commit[:7], date) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func usage() { | func usage() { | ||||||
| 	fmt.Fprintf(os.Stderr, "\nusage: go run sclient*.go <remote> <local>\n"+ | 	fmt.Fprintf(os.Stderr, "\n%s\n"+ | ||||||
|  | 		"\nusage: sclient <remote> <local>\n"+ | ||||||
| 		"\n"+ | 		"\n"+ | ||||||
| 		"   ex: sclient example.com 3000\n"+ | 		"   ex: sclient example.com 3000\n"+ | ||||||
| 		"      (sclient example.com:443 localhost:3000)\n"+ | 		"      (sclient example.com:443 localhost:3000)\n"+ | ||||||
| 		"\n"+ | 		"\n"+ | ||||||
| 		"   ex: sclient example.com:8443 0.0.0.0:4080\n"+ | 		"   ex: sclient example.com:8443 0.0.0.0:4080\n"+ | ||||||
| 		"\n") | 		"\n"+ | ||||||
|  | 		"   ex: sclient example.com:443 -\n"+ | ||||||
|  | 		"\n", ver()) | ||||||
| 	flag.PrintDefaults() | 	flag.PrintDefaults() | ||||||
| 	fmt.Println() | 	fmt.Println() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
|  | 	if len(os.Args) >= 2 { | ||||||
|  | 		if "version" == strings.TrimLeft(os.Args[1], "-") { | ||||||
|  | 			fmt.Printf("%s\n", ver()) | ||||||
|  | 			os.Exit(0) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	flag.Usage = usage | 	flag.Usage = usage | ||||||
| 	insecure := flag.Bool("k", false, "ignore bad TLS/SSL/HTTPS certificates") | 	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 <remote> (to disable SNI use an IP as <remote> and do use this option)") | ||||||
| 	flag.BoolVar(insecure, "insecure", false, "ignore bad TLS/SSL/HTTPS certificates") | 	flag.BoolVar(insecure, "insecure", false, "ignore bad TLS/SSL/HTTPS certificates") | ||||||
|  | 	flag.BoolVar(silent, "silent", false, "less verbose output") | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
| 	remotestr := flag.Arg(0) | 	remotestr := flag.Arg(0) | ||||||
| 	localstr := flag.Arg(1) | 	localstr := flag.Arg(1) | ||||||
| @ -39,10 +68,13 @@ func main() { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	opts := &SclientOpts{} | 	sclient := &sclient.Tunnel{ | ||||||
| 	opts.RemotePort = 443 | 		RemotePort:         443, | ||||||
| 	opts.LocalAddress = "localhost" | 		LocalAddress:       "localhost", | ||||||
| 	opts.InsecureSkipVerify = *insecure | 		InsecureSkipVerify: *insecure, | ||||||
|  | 		ServerName:         *servername, | ||||||
|  | 		Silent:             *silent, | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	remote := strings.Split(remotestr, ":") | 	remote := strings.Split(remotestr, ":") | ||||||
| 	//remoteAddr, remotePort, err := net.SplitHostPort(remotestr) | 	//remoteAddr, remotePort, err := net.SplitHostPort(remotestr) | ||||||
| @ -52,17 +84,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, ":") | ||||||
| @ -73,20 +105,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{} | 	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() | ||||||
							
								
								
									
										43
									
								
								doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								doc.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  | 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 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. | ||||||
|  | 
 | ||||||
|  | Package Basics | ||||||
|  | 
 | ||||||
|  | In the simplest case you'll just be setting a ServerName and connection info: | ||||||
|  | 
 | ||||||
|  | 	servername := "example.com" | ||||||
|  | 
 | ||||||
|  | 	sclient := &sclient.Tunnel{ | ||||||
|  | 		ServerName:         servername, | ||||||
|  | 		RemoteAddress:      servername, | ||||||
|  | 		RemotePort:         443, | ||||||
|  | 		LocalAddress:       "localhost", | ||||||
|  | 		LocalPort:          3000, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err := sclient.DialAndListen() | ||||||
|  | 
 | ||||||
|  | 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 sclient | ||||||
							
								
								
									
										147
									
								
								sclient.go
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								sclient.go
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| package main | package sclient | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
| @ -10,6 +10,69 @@ import ( | |||||||
| 	"strings" | 	"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 | ||||||
|  | 	Silent             bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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: name, Net: 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 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !t.Silent { | ||||||
|  | 		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 | // I wonder if I can get this to exactly mirror UnixAddr without passing it in | ||||||
| type stdaddr struct { | type stdaddr struct { | ||||||
| 	net.UnixAddr | 	net.UnixAddr | ||||||
| @ -35,22 +98,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 SclientOpts struct { | func pipe(r netReadWriteCloser, w netReadWriteCloser, t string) { | ||||||
| 	RemoteAddress      string |  | ||||||
| 	RemotePort         int |  | ||||||
| 	LocalAddress       string |  | ||||||
| 	LocalPort          int |  | ||||||
| 	InsecureSkipVerify bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Sclient struct{} |  | ||||||
| 
 |  | ||||||
| func pipe(r Rwc, w Rwc, t string) { |  | ||||||
| 	buffer := make([]byte, 2048) | 	buffer := make([]byte, 2048) | ||||||
| 	for { | 	for { | ||||||
| 		done := false | 		done := false | ||||||
| @ -60,7 +113,7 @@ func pipe(r Rwc, w Rwc, t string) { | |||||||
| 		if nil != err { | 		if nil != err { | ||||||
| 			//fmt.Fprintf(os.Stdout, "[debug] (%s:%d) error reading %s\n", t, count, err) | 			//fmt.Fprintf(os.Stdout, "[debug] (%s:%d) error reading %s\n", t, count, err) | ||||||
| 			if io.EOF != err { | 			if io.EOF != err { | ||||||
| 				fmt.Fprintf(os.Stderr, "[read error] (%s:%s) %s\n", t, count, err) | 				fmt.Fprintf(os.Stderr, "[read error] (%s:%d) %s\n", t, count, err) | ||||||
| 			} | 			} | ||||||
| 			r.Close() | 			r.Close() | ||||||
| 			//w.Close() | 			//w.Close() | ||||||
| @ -86,9 +139,12 @@ func pipe(r Rwc, w Rwc, t string) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func handleConnection(remote string, conn Rwc, opts *SclientOpts) { | func (t *Tunnel) handleConnection(remote string, conn netReadWriteCloser) { | ||||||
| 	sclient, err := tls.Dial("tcp", remote, | 	sclient, err := tls.Dial("tcp", remote, | ||||||
| 		&tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify}) | 		&tls.Config{ | ||||||
|  | 			ServerName:         t.ServerName, | ||||||
|  | 			InsecureSkipVerify: t.InsecureSkipVerify, | ||||||
|  | 		}) | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		fmt.Fprintf(os.Stderr, "[error] (remote) %s\n", err) | 		fmt.Fprintf(os.Stderr, "[error] (remote) %s\n", err) | ||||||
| @ -96,59 +152,16 @@ func handleConnection(remote string, conn Rwc, opts *SclientOpts) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if "stdio" == conn.RemoteAddr().Network() { | 	if !t.Silent { | ||||||
| 		fmt.Fprintf(os.Stdout, "(connected to %s:%d and reading from %s)\n", | 		if "stdio" == conn.RemoteAddr().Network() { | ||||||
| 			opts.RemoteAddress, opts.RemotePort, conn.RemoteAddr().String()) | 			fmt.Fprintf(os.Stdout, "(connected to %s:%d and reading from %s)\n", | ||||||
| 	} else { | 				t.RemoteAddress, t.RemotePort, conn.RemoteAddr().String()) | ||||||
| 		fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n", | 		} else { | ||||||
| 			strings.Replace(conn.RemoteAddr().String(), "[::1]:", "localhost:", 1), opts.RemoteAddress, opts.RemotePort) | 			fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n", | ||||||
|  | 				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 (*Sclient) DialAndListen(opts *SclientOpts) error { |  | ||||||
| 	remote := opts.RemoteAddress + ":" + strconv.Itoa(opts.RemotePort) |  | ||||||
| 	conn, err := tls.Dial("tcp", remote, |  | ||||||
| 		&tls.Config{InsecureSkipVerify: opts.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 "-" == opts.LocalAddress || "|" == opts.LocalAddress { |  | ||||||
| 		var name string |  | ||||||
| 		network := "stdio" |  | ||||||
| 		if "|" == opts.LocalAddress { |  | ||||||
| 			name = "pipe" |  | ||||||
| 		} else { |  | ||||||
| 			name = "stdin" |  | ||||||
| 		} |  | ||||||
| 		conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}} |  | ||||||
| 		handleConnection(remote, conn, opts) |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// use net.Conn |  | ||||||
| 	local := opts.LocalAddress + ":" + strconv.Itoa(opts.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) |  | ||||||
| 
 |  | ||||||
| 	for { |  | ||||||
| 		conn, err := ln.Accept() |  | ||||||
| 		if nil != err { |  | ||||||
| 			fmt.Fprintf(os.Stderr, "[error] %s\n", err) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		go handleConnection(remote, conn, opts) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								staticcheck.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								staticcheck.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | # I like my yoda conditions ST1017 | ||||||
|  | checks = ["all", "-ST1017", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022", "-ST1023"] | ||||||
|  | initialisms = ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", | ||||||
|  | 	"EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", | ||||||
|  | 	"IP", "JSON", "QPS", "RAM", "RPC", "SLA", | ||||||
|  | 	"SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", | ||||||
|  | 	"UDP", "UI", "GID", "UID", "UUID", "URI", | ||||||
|  | 	"URL", "UTF8", "VM", "XML", "XMPP", "XSRF", | ||||||
|  | 	"XSS", "SIP", "RTP", "AMQP", "DB", "TS"] | ||||||
|  | dot_import_whitelist = [] | ||||||
|  | http_status_code_whitelist = ["200", "400", "404", "500"] | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user