From 47a2cd2f8830372f2ec3a326a106581773442c5d Mon Sep 17 00:00:00 2001 From: Antonio Mika Date: Sat, 23 Nov 2019 22:41:20 -0500 Subject: [PATCH 1/2] Added port overrides --- README.md | 37 ++++++++++++++++++++++++++++--------- main.go | 10 ++++++++++ utils.go | 4 ++-- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b33d72d..5806f50 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ sish An open source serveo/ngrok alternative. -## Deploy +Deploy +------ + Builds are made automatically on Google Cloud Build and Dockerhub. Feel free to either use the automated binaries or to build your own. If you submit a PR and would like access to Google Cloud Build's output (including pre-made PR binaries), feel free to let me know. 1. Pull the Docker image @@ -29,7 +31,9 @@ Builds are made automatically on Google Cloud Build and Dockerhub. Feel free to 3. SSH to your host to communicate with sish - `ssh -p 2222 -R 80:localhost:8080 ssi.sh` -### Docker Compose +Docker Compose +-------------- + You can also use Docker Compose to setup your sish instance. This includes taking care of SSL via Let's Encrypt for you. This uses the [adferrand/docker-letsencrypt-dns](https://github.com/adferrand/docker-letsencrypt-dns) container to handle issuing wildcard certifications over DNS. For more information on how to use this, head to that link above. Generally, you can deploy your service like so: ```bash @@ -40,7 +44,9 @@ LEXICON_PROVIDER_OPTIONS="--auth-username=you@yourdomain.com --auth-token=your-a docker-compose -f deploy/docker-compose.yml up -d ``` -## How it works +How it works +------------ + SSH can normally forward local and remote ports. This service implements an SSH server that only does that and nothing else. The service supports multiplexing connections over HTTP/HTTPS with WebSocket support. Just assign a remote port as port `80` to proxy HTTP traffic and `443` to proxy HTTPS traffic. If you use any other remote port, the server will listen to the port for connections, but only if that port is available. You can choose your own subdomain instead of relying on a randomly assigned one @@ -51,7 +57,9 @@ subdomain by prepending it to the remote port specifier: If the selected subdomain is not taken, it will be assigned to your connection. -## Authentication +Authentication +-------------- + If you want to use this service privately, it supports both public key and password authentication. To enable authentication, set `-sish.auth=true` as one of your CLI options and be sure to configure `-sish.password` or `-sish.keysdir` to your liking. The directory provided by `-sish.keysdir` is watched for changes and will reload the authorized keys automatically. The authorized cert index is regenerated on directory modification, so removed public keys will also automatically be removed. Files in this directory can either be single key per file, or multiple keys per file separated by newlines, similar to `authorized_keys`. Password auth can be disabled by setting `-sish.password=""` as a CLI option. One of my favorite ways of using this for authentication is like so: @@ -62,7 +70,8 @@ sish@sish0:~/sish/pubkeys# curl https://github.com/antoniomika.keys > antoniomik This will load my public keys from GitHub, place them in the directory that sish is watching, and then load the pubkey. As soon as this command is run, I can SSH normally and it will authorize me. -## Whitelisting IPs +Whitelisting IPs +---------------- Whitelisting IP ranges or countries is also possible. Whole CIDR ranges can be specified with the `-sish.whitelistedips` option that accepts a comma-separated string like "192.30.252.0/22,185.199.108.0/22". If you want to whitelist a single @@ -72,17 +81,23 @@ To whitelist countries, use `sish.whitelistedcountries` with a comma-separated string of countries in ISO format (for example, "pt" for Portugal). You'll also need to set `-sish.usegeodb` to `true`. -## Demo +Demo - At this time, the demo instance has been set to require auth due to abuse +---- + There is a demo service (and my private instance) currently running on `ssi.sh` that doesn't require any authentication. This service provides default logging (errors, connection IP/username, and pubkey fingerprint). I do not log any of the password authentication data or the data sent within the service/tunnels. My deploy uses the exact deploy steps that are listed above. This instance is for testing and educational purposes only. You can deploy this extremely easily on any host (Google Cloud Platform provides an always-free instance that this should run perfectly on). If the service begins to accrue a lot of traffic, I will enable authentication and then you can reach out to me to get your SSH key whitelisted (make sure it's on GitHub and you provide me with your GitHub username). -## Notes +Notes +----- + 1. This is by no means production ready in any way. This was hacked together and solves a fairly specific use case. - You can help it get production ready by submitting PRs/reviewing code/writing tests/etc 2. This is a fairly simple implementation, I've intentionally cut corners in some places to make it easier to write. 3. If you have any questions or comments, feel free to reach out via email [me@antoniomika.me](mailto:me@antoniomika.me) or on [freenode IRC #sish](https://kiwiirc.com/client/chat.freenode.net:6697/#sish) -## CLI Flags -``` +CLI Flags +--------- + +```text sh-3.2# ./sish -h Usage of ./sish: -sish.addr string @@ -109,12 +124,16 @@ Usage of ./sish: Whether or not to force a random subdomain (default true) -sish.http string The address to listen for HTTP connections (default "localhost:80") + -sish.httpport int + The port to use for http command output -sish.https string The address to listen for HTTPS connections (default "localhost:443") -sish.httpsenabled Whether or not to listen for HTTPS connections -sish.httpspems string The location of pem files for HTTPS (fullchain.pem and privkey.pem) (default "ssl/") + -sish.httpsport int + The port to use for https command output -sish.keysdir string Directory for public keys for pubkey auth (default "pubkeys/") -sish.logtoclient diff --git a/main.go b/main.go index 88a7e9e..6c0a041 100644 --- a/main.go +++ b/main.go @@ -45,7 +45,9 @@ var ( httpsPort int serverAddr = flag.String("sish.addr", "localhost:2222", "The address to listen for SSH connections") httpAddr = flag.String("sish.http", "localhost:80", "The address to listen for HTTP connections") + httpPortOverride = flag.Int("sish.httpport", 0, "The port to use for http command output") httpsAddr = flag.String("sish.https", "localhost:443", "The address to listen for HTTPS connections") + httpsPortOverride = flag.Int("sish.httpsport", 0, "The port to use for https command output") verifyOrigin = flag.Bool("sish.verifyorigin", true, "Whether or not to verify origin on websocket connection") verifySSL = flag.Bool("sish.verifyssl", true, "Whether or not to verify SSL on proxy connection") httpsEnabled = flag.Bool("sish.httpsenabled", false, "Whether or not to listen for HTTPS connections") @@ -102,6 +104,14 @@ func main() { log.Fatalln("Error parsing address:", err) } + if *httpPortOverride != 0 { + httpPort = *httpPortOverride + } + + if *httpsPortOverride != 0 { + httpsPort = *httpsPortOverride + } + if *versionCheck { log.Printf("\nVersion: %v\nCommit: %v\nDate: %v\n", version, commit, date) os.Exit(0) diff --git a/utils.go b/utils.go index c6558ba..124cfe0 100644 --- a/utils.go +++ b/utils.go @@ -398,14 +398,14 @@ func sendMessage(sshConn *SSHConnection, message string, block bool) { return } - for i := 0; i < 2; { + for i := 0; i < 5; { select { case <-sshConn.Close: return case sshConn.Messages <- message: return default: - time.Sleep(20 * time.Millisecond) + time.Sleep(100 * time.Millisecond) i++ } } From b22eee973469774927faf39e6caa48e94da3bcc1 Mon Sep 17 00:00:00 2001 From: Antonio Mika Date: Sat, 23 Nov 2019 22:57:19 -0500 Subject: [PATCH 2/2] Force console colors for Gin --- http.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/http.go b/http.go index 43fd4f1..fe65fa8 100644 --- a/http.go +++ b/http.go @@ -32,6 +32,8 @@ func startHTTPHandler(state *State) { } gin.SetMode(releaseMode) + gin.ForceConsoleColor() + r := gin.New() r.Use(func(c *gin.Context) { clientIPAddr, _, err := net.SplitHostPort(c.Request.RemoteAddr)