Skip to content

Commit

Permalink
The --rm flag will enable to point to
Browse files Browse the repository at this point in the history
an upstream or a remote-tcp and will delete the exit-node
on a SIGINT (control + c)

Fixes inlets#41

Signed-off-by: Utsav Anand <[email protected]>
  • Loading branch information
utsavanand2 committed Feb 24, 2020
1 parent 0699f70 commit 8c5ffe0
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 119 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,6 @@ inletsctl create --provider scaleway \
The region is hard-coded to France / Paris 1.
## Example for GCE
Follow the steps here to [configure your service account](https://github.com/inlets/inlets-operator#running-in-cluster-using-google-compute-engine-for-the-exit-node-using-helm)
## Examples for `inletsctl kfwd`
The `inletsctl kfwd` command can port-forward services from within your local Kubernetes cluster to your local network or computer.
Expand Down
305 changes: 244 additions & 61 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,32 @@ package cmd
import (
"encoding/base64"
"fmt"
"net/http"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"

"github.com/inlets/inletsctl/pkg/env"

"github.com/inlets/inletsctl/pkg/names"
"github.com/inlets/inletsctl/pkg/provision"

execute "github.com/alexellis/go-execute/pkg/v1"
"github.com/hashicorp/go-retryablehttp"
"github.com/pkg/errors"
"github.com/sethvargo/go-password/password"
"github.com/spf13/cobra"
)

const inletsControlPort = 8080
var inletsControlPort = 8080

const inletsProControlPort = 8123

var delTunnel bool

func init() {

inletsCmd.AddCommand(createCmd)
Expand All @@ -41,8 +50,13 @@ func init() {
createCmd.Flags().String("project-id", "", "Project ID (Packet.com, Google Compute Engine)")

createCmd.Flags().StringP("remote-tcp", "c", "", `Remote host for inlets-pro to use for forwarding TCP connections`)
createCmd.Flags().String("tcp-ports", "80,443", "Comma-separated list of TCP ports to proxy (default '80,443')")

createCmd.Flags().DurationP("poll", "n", time.Second*2, "poll every N seconds, use a higher value if you encounter rate-limiting")

createCmd.Flags().BoolVar(&delTunnel, "rm", false, "Delete the exit node on pressing control + c")
createCmd.Flags().StringP("upstream", "u", "", "The upstream server running locally")
createCmd.Flags().StringP("license", "l", "", "The license key for inlets-pro")
}

// clientCmd represents the client sub command.
Expand All @@ -52,20 +66,41 @@ var createCmd = &cobra.Command{
Long: `Create an exit node on cloud infrastructure. The estimated cost of each VM
along with what OS version and spec will be used is explained in the README.
`,
Example: ` inletsctl create \
Example: ` # To use inlets-OSS run
inletsctl create \
--provider [digitalocean|packet|ec2|scaleway|civo|gce] \
--access-token-file $HOME/access-token \
--region lon1
--access-token-file $HOME/access-token
# To create a temporary tunnel with inlets-OSS run
inletsctl create --rm \
--provider [digitalocean|packet|ec2|scaleway|civo|gce] \
--access-token-file $HOME/access-token \
--upstream http://127.0.0.1:3000
# For inlets-pro, give the --remote-tcp flag
inletsctl create \
--proider [digitalocean|packet|ec2|scaleway|civo|gce] \
--access-token-file $HOME/access-token \
--remote-tcp 192.168.0.100 \
--tcp-ports=80,443,8080
# To create a temporary tunnel with inlets-pro run
inletsctl create --rm \
--provider [digitalocean|packet|ec2|scaleway|civo|gce] \
--access-token-file $HOME/access-token \
--remote-tcp 127.0.0.1:3000
--tcp-ports=80,443,8080
--license=$INLETS_LICENSE`,

# For inlets-pro, give the --remote-tcp flag
inletsctl create --remote-tcp 192.168.0.100`,
RunE: runCreate,
SilenceUsage: true,
SilenceErrors: true,
}

func runCreate(cmd *cobra.Command, _ []string) error {

provider, err := cmd.Flags().GetString("provider")
if err != nil {
return errors.Wrap(err, "failed to get 'provider' value.")
Expand Down Expand Up @@ -129,7 +164,6 @@ func runCreate(cmd *cobra.Command, _ []string) error {
var organisationID string
var projectID string
if provider == "scaleway" || provider == "ec2" {

var secretKeyErr error
secretKey, secretKeyErr = getFileOrString(cmd.Flags(), "secret-key-file", "secret-key", true)
if secretKeyErr != nil {
Expand All @@ -156,9 +190,24 @@ func runCreate(cmd *cobra.Command, _ []string) error {
}

remoteTCP, _ := cmd.Flags().GetString("remote-tcp")
upstream, _ := cmd.Flags().GetString("upstream")
if delTunnel == true {
if len(remoteTCP) == 0 && len(upstream) == 0 {
return fmt.Errorf("either of --remote-tcp or --upstream must be specified")
}
}

var pro bool
var tcpPorts string
var inletsProLicenseKey string
if len(remoteTCP) > 0 {
pro = true
tcpPorts, _ = cmd.Flags().GetString("tcp-ports")
inletsProLicenseKey, _ = cmd.Flags().GetString("license")
}

if pro {
inletsControlPort = inletsProControlPort
}

name := strings.Replace(names.GetRandomName(10), "_", "-", -1)
Expand Down Expand Up @@ -192,49 +241,53 @@ func runCreate(cmd *cobra.Command, _ []string) error {
return err
}

fmt.Printf("[%d/%d] Host: %s, status: %s\n",
i+1, max, hostStatus.ID, hostStatus.Status)

if hostStatus.Status == "active" {
if !pro {
fmt.Printf(`Inlets OSS exit-node summary:
IP: %s
Auth-token: %s
Command:
export UPSTREAM=http://127.0.0.1:8000
inlets client --remote "ws://%s:%d" \
--token "%s" \
--upstream $UPSTREAM
To Delete:
inletsctl delete --provider %s --id "%s"
`,
hostStatus.IP, inletsToken, hostStatus.IP, inletsControlPort, inletsToken, provider, hostStatus.ID)
if delTunnel == true {
sig := make(chan os.Signal, 1)
done := make(chan bool, 1)

signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

go func() {
sigval := <-sig
fmt.Printf("\n%v\n", sigval)
done <- true
close(sig)
}()

fmt.Printf("Your IP is: %s\n", hostStatus.IP)

var err error = nil
if pro {
err = runInletsClient(pro, hostStatus.IP, inletsControlPort, remoteTCP, inletsToken, tcpPorts, inletsProLicenseKey)
} else {
err = runInletsClient(pro, hostStatus.IP, inletsControlPort, upstream, inletsToken, tcpPorts, "")
}
if err != nil {
return fmt.Errorf("Error running inlets: %v", err)
}

<-done
close(done)
hostDelReq := provision.HostDeleteRequest{
ID: hostStatus.ID,
IP: hostStatus.IP,
ProjectID: projectID,
Zone: zone,
}
fmt.Printf("Deleting host: %s with IP: %s from %s\n", hostStatus.ID, hostStatus.IP, provider)
err = provisioner.Delete(hostDelReq)
if err != nil {
return fmt.Errorf("error deleting the exitnode: %v", err)
}
fmt.Println("exiting")
return nil
} else {
printExample(pro, hostStatus, inletsToken, provider, inletsControlPort)
return nil
}

fmt.Printf(`inlets-pro exit-node summary:
IP: %s
Auth-token: %s
Command:
export TCP_PORTS="8000"
export LICENSE=""
inlets-pro client --connect "wss://%s:%d/connect" \
--token "%s" \
--license "$LICENSE" \
--tcp-ports $TCP_PORTS
To Delete:
inletsctl delete --provider %s --id "%s"
`,
hostStatus.IP, inletsToken, hostStatus.IP, inletsProControlPort, inletsToken, provider, hostStatus.ID)

return nil
}
}

return err
}

Expand Down Expand Up @@ -352,19 +405,149 @@ curl -sLO https://raw.githubusercontent.com/inlets/inlets/master/hack/inlets-ope
}

return `#!/bin/bash
export AUTHTOKEN="` + authToken + `"
export REMOTETCP="` + remoteTCP + `"
export IP=$(curl -sfSL https://ifconfig.co)
curl -SLsf https://github.com/inlets/inlets-pro/releases/download/0.4.3/inlets-pro > /tmp/inlets-pro && \
chmod +x /tmp/inlets-pro && \
mv /tmp/inlets-pro /usr/local/bin/inlets-pro
curl -sLO https://raw.githubusercontent.com/inlets/inlets/master/hack/inlets-pro.service && \
mv inlets-pro.service /etc/systemd/system/inlets-pro.service && \
echo "AUTHTOKEN=$AUTHTOKEN" >> /etc/default/inlets-pro && \
echo "REMOTETCP=$REMOTETCP" >> /etc/default/inlets-pro && \
echo "IP=$IP" >> /etc/default/inlets-pro && \
systemctl start inlets-pro && \
systemctl enable inlets-pro`
export AUTHTOKEN="` + authToken + `"
export REMOTETCP="` + remoteTCP + `"
export IP=$(curl -sfSL https://ifconfig.co)
curl -SLsf https://github.com/inlets/inlets-pro/releases/download/0.4.3/inlets-pro > /tmp/inlets-pro && \
chmod +x /tmp/inlets-pro && \
mv /tmp/inlets-pro /usr/local/bin/inlets-pro
curl -sLO https://raw.githubusercontent.com/inlets/inlets/master/hack/inlets-pro.service && \
mv inlets-pro.service /etc/systemd/system/inlets-pro.service && \
echo "AUTHTOKEN=$AUTHTOKEN" >> /etc/default/inlets-pro && \
echo "REMOTETCP=$REMOTETCP" >> /etc/default/inlets-pro && \
echo "IP=$IP" >> /etc/default/inlets-pro && \
systemctl start inlets-pro && \
systemctl enable inlets-pro`
}

func printExample(pro bool, hostStatus *provision.ProvisionedHost, inletsToken string, provider string, inletsControlPort int) {
if !pro {
fmt.Printf(`Inlets OSS exit-node summary:
IP: %s
Auth-token: %s
Command:
export UPSTREAM=http://127.0.0.1:3000
inlets client --remote "ws://%s:%d" \
--token "%s" \
--upstream $UPSTREAM
To Delete:
inletsctl delete --provider %s --id "%s"
`,
hostStatus.IP, inletsToken, hostStatus.IP, inletsControlPort, inletsToken, provider, hostStatus.ID)
} else {
fmt.Printf(`inlets-pro exit-node summary:
IP: %s
Auth-token: %s
Command:
export TCP_PORTS="8000"
export LICENSE=""
inlets-pro client --connect "wss://%s:%d/connect" \
--token "%s" \
--license "$LICENSE" \
--tcp-ports $TCP_PORTS
To Delete:
inletsctl delete --provider %s --id "%s"
`,
hostStatus.IP, inletsToken, hostStatus.IP, inletsControlPort, inletsToken, provider, hostStatus.ID)
}
}

func checkIfInletsIsInstalled(usingPro bool) (bool, error) {
basePath := "/usr/local/bin/%s"
if usingPro {
basePath = fmt.Sprintf(basePath, "inlets-pro")
} else {
basePath = fmt.Sprintf(basePath, "inlets")
}

fileInfo, err := os.Stat(basePath)
if err != nil {
return false, fmt.Errorf("Error finding file: %v", err)
}

if strings.SplitAfter(basePath, "/usr/local/bin/")[1] == fileInfo.Name() {
return true, nil
}
return false, nil
}

func runInletsClient(pro bool, exitNodeIP string, inletsControlPort int, upstream string, authToken string, tcpPorts string, license string) error {
installed, err := checkIfInletsIsInstalled(pro)
if err != nil {
return fmt.Errorf("error checking if inlets is installed: %v", err)
}

if !installed {
return fmt.Errorf("inlets/inlets-pro not installed")
}

if !pro {
fmt.Printf("Starting 'inlets client' now, hit control+c to delete the tunnel\n\n")
cmd := execute.ExecTask{
Command: "inlets",
Args: []string{"client", "--remote",
fmt.Sprintf("ws://%s:%d", exitNodeIP, inletsControlPort),
"--token", authToken, "--upstream", upstream},
StreamStdio: true,
}
_, err := cmd.Execute()
if err != nil {
return fmt.Errorf("Error running inlets: %v", err)
}

} else {
timeout := 600
retries := 10
url := fmt.Sprintf("https://%s:%d/.well-known/ca.crt", exitNodeIP, inletsControlPort)
up, err := checkServiceUp(url, timeout, retries)
fmt.Printf("Starting 'inlets-pro client', hit control+c to delete the tunnel\n\n")
if err != nil {
return fmt.Errorf("%v", err)
}
if up {
cmd := execute.ExecTask{
Command: "inlets-pro",
Args: []string{"client", "--connect",
fmt.Sprintf("wss://%s:%d/connect", exitNodeIP, inletsControlPort),
"--token", authToken, "--tcp-ports", tcpPorts, "--license", license},
StreamStdio: true,
}
_, err := cmd.Execute()
if err != nil {
return fmt.Errorf("Error running inlets-pro: %v", err)
}
}
}

if err != nil && fmt.Sprintf("%s", err) != "signal: interrupt" {
return fmt.Errorf("%v", err)
}

return nil
}

func checkServiceUp(url string, timeout int, retries int) (bool, error) {
for i := 0; i < retries; i++ {
fmt.Println("checking if the inlets server is up!")
client := retryablehttp.Client{
RetryWaitMin: time.Second * time.Duration(timeout),
RetryMax: retries,
}
res, err := client.Get(url)
if err != nil {
fmt.Printf("error with GET request: %v\n", err)
}
if err == nil && res.StatusCode == http.StatusOK {
return true, nil
}
// fmt.Println("retrying")
// time.Sleep(time.Second * time.Duration((i+1)*10))
}
return false, fmt.Errorf("used maximum number of retries, failed to resolve if the service is up")
}
Loading

0 comments on commit 8c5ffe0

Please sign in to comment.