Skip to content

Commit

Permalink
Add --rm flag to "inletsctl create"
Browse files Browse the repository at this point in the history
Fix issue with the opening of TCP ports for inlets-pro on GCE

The --rm flag will enable to point to
an upstream or a remote-tcp and will delete the exit-node
on a SIGINT (control + c)
Updates the firewall rule when switching between inlets OSS
and inlets-pro and opens up ports from 1024 to 65535 when using
inlets-pro.

Fixes inlets#41
Fixes inlets#44

Signed-off-by: Utsav Anand <[email protected]>
  • Loading branch information
utsavanand2 committed Feb 3, 2020
1 parent 00d03e0 commit 16d7cf5
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 65 deletions.
208 changes: 168 additions & 40 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@ import (
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"

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

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

var delTunnel bool

func init() {
inletsCmd.AddCommand(createCmd)
createCmd.Flags().StringP("provider", "p", "digitalocean", "The cloud provider - digitalocean, gce, ec2, packet, scaleway, or civo")
Expand All @@ -36,8 +42,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", "http://127.0.0.1:3000", "The upstream server running locally")
createCmd.Flags().StringP("license", "l", "", "The license key for inlets-pro")
}

// clientCmd represents the client sub command.
Expand All @@ -60,7 +71,6 @@ along with what OS version and spec will be used is explained in the README.
}

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 @@ -139,15 +149,26 @@ func runCreate(cmd *cobra.Command, _ []string) error {
}

remoteTCP, _ := cmd.Flags().GetString("remote-tcp")
upstream, _ := cmd.Flags().GetString("upstream")

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")

}

name := strings.Replace(names.GetRandomName(10), "_", "-", -1)

inletsControlPort := 8080
// proPort := 8123
proPort := 8080
if pro {
inletsControlPort = proPort
}

userData := makeUserdata(inletsToken, inletsControlPort, remoteTCP)

Expand Down Expand Up @@ -180,46 +201,87 @@ 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)
return nil
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
}()

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

port := inletsControlPort
if pro {
port = proPort
}

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

<-done
hostDelReq := provision.HostDeleteRequest{
ID: hostStatus.ID,
IP: hostStatus.IP,
ProjectID: projectID,
Zone: zone,
}
fmt.Println("Deleting tunnel")
err = provisioner.Delete(hostDelReq)
if err != nil {
return fmt.Errorf("error deleting the exitnode: %v", err)
}
fmt.Println("exiting")

} else {
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)
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, proPort, inletsToken, provider, hostStatus.ID)
}

proPort := 8123
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, proPort, inletsToken, provider, hostStatus.ID)

return nil
}
}
Expand Down Expand Up @@ -300,6 +362,7 @@ func createHost(provider, name, region, zone, projectID, userData, inletsPort st
"zone": zone,
"firewall-name": "inlets",
"firewall-port": inletsPort,
"pro": fmt.Sprint(pro),
},
}, nil
} else if provider == "ec2" {
Expand All @@ -313,7 +376,7 @@ func createHost(provider, name, region, zone, projectID, userData, inletsPort st
UserData: base64.StdEncoding.EncodeToString([]byte(userData)),
Additional: map[string]string{
"inlets-port": inletsPort,
"pro": fmt.Sprint(pro),
"pro": fmt.Sprint(pro),
},
}, nil
}
Expand Down Expand Up @@ -381,3 +444,68 @@ func getFileOrString(flags *pflag.FlagSet, file, value string, required bool) (s

return val, nil
}

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
} else {
return false, nil
}

}

func runInletsClient(pro bool, exitNodeIP string, upstream string, inletsControlPort int, authToken string, tcpPorts string, license string) error {
installed, err := checkIfInletsIsInstalled(pro)
if err != nil {
return fmt.Errorf("could not check 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")
cmd := execute.ExecTask{
Command: fmt.Sprintf("inlets client --remote %s --token %s --upstream %s", fmt.Sprintf("ws://%s:%d", exitNodeIP, inletsControlPort), authToken, upstream),
}
res, err := cmd.Execute()
if err != nil {
return fmt.Errorf("Could not run inlets: %v", err)
}
if res.ExitCode != 0 {
fmt.Printf("stdout: %q, stderr: %q, exit-code: %d\n", res.Stdout, res.Stderr, res.ExitCode)
}

} else {
fmt.Printf("Starting 'inlets-pro client' now, hit control+c to delete the tunnel\n")
cmd := execute.ExecTask{
Command: fmt.Sprintf("inlets-pro client --connect %s --token %s --tcp-ports %s --license %s", fmt.Sprintf("wss://%s:%d/connect", exitNodeIP, inletsControlPort), authToken, tcpPorts, license),
}
res, err := cmd.Execute()
if err != nil {
return fmt.Errorf("Could not run inlets: %v", err)
}
if res.ExitCode != 0 {
fmt.Printf("stdout: %q, stderr: %q, exit-code: %d\n", res.Stdout, res.Stderr, res.ExitCode)
}
}

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

return nil
}
9 changes: 5 additions & 4 deletions pkg/provision/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package provision

import (
"fmt"
"github.com/aws/aws-sdk-go/aws/credentials"
"strconv"
"strings"

"github.com/aws/aws-sdk-go/aws/credentials"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
Expand Down Expand Up @@ -40,7 +41,7 @@ func (p *EC2Provisioner) Provision(host BasicHost) (*ProvisionedHost, error) {
}
pro := host.Additional["pro"]

groupID, name, err := p.creteEC2SecurityGroup(port, pro)
groupID, name, err := p.createEC2SecurityGroup(port, pro)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -230,9 +231,9 @@ func (p *EC2Provisioner) lookupID(request HostDeleteRequest) (string, error) {
}

// creteEC2SecurityGroup creates a security group for the exit-node
func (p *EC2Provisioner) creteEC2SecurityGroup(controlPort int, pro string) (*string, *string, error) {
func (p *EC2Provisioner) createEC2SecurityGroup(controlPort int, pro string) (*string, *string, error) {
ports := []int{80, 443, controlPort}
proPorts := []int{1024,65535}
proPorts := []int{1024, 65535}
groupName := "inlets-" + uuid.New().String()
group, err := p.ec2Provisioner.CreateSecurityGroup(&ec2.CreateSecurityGroupInput{
Description: aws.String("inlets security group"),
Expand Down
43 changes: 22 additions & 21 deletions pkg/provision/gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,10 @@ func (p *GCEProvisioner) Provision(host BasicHost) (*ProvisionedHost, error) {
},
}

exists, _ := p.checkInletsFirewallRuleExists(host.Additional["projectid"], host.Additional["firewall-name"], host.Additional["firewall-port"])

if !exists {
err := p.createInletsFirewallRule(host.Additional["projectid"], host.Additional["firewall-name"], host.Additional["firewall-port"])
log.Println("inlets firewallRule does not exist")
if err != nil {
return nil, fmt.Errorf("could not create inlets firewall rule: %v", err)
}
log.Printf("Creating inlets firewallRule opening port: %s\n", host.Additional["firewall-port"])
} else {
log.Println("inlets firewallRule exists")
log.Printf("Creating inlets firewallRule opening port: %s\n", host.Additional["firewall-port"])
err := p.createInletsFirewallRule(host.Additional["projectid"], host.Additional["firewall-name"], host.Additional["firewall-port"], host.Additional["pro"])
if err != nil {
return nil, err
}

op, err := p.gceProvisioner.Instances.Insert(host.Additional["projectid"], host.Additional["zone"], instance).Do()
Expand All @@ -121,25 +114,23 @@ func (p *GCEProvisioner) Provision(host BasicHost) (*ProvisionedHost, error) {
}

// checkInletsFirewallRuleExists checks if the inlets firewall rule exists or not
func (p *GCEProvisioner) checkInletsFirewallRuleExists(projectID string, firewallRuleName string, inletsPort string) (bool, error) {
func (p *GCEProvisioner) checkInletsFirewallRuleExists(projectID string, firewallRuleName string) (bool, error) {
op, err := p.gceProvisioner.Firewalls.Get(projectID, firewallRuleName).Do()
if err != nil {
return false, fmt.Errorf("could not get inlets firewall rule: %v", err)
}
if op.Name == firewallRuleName {
for _, firewallRule := range op.Allowed {
for _, port := range firewallRule.Ports {
if port == inletsPort {
return true, nil
}
}
}
return true, nil
}
return false, nil
}

// createInletsFirewallRule creates a firewall rule opening up the control port for inlets
func (p *GCEProvisioner) createInletsFirewallRule(projectID string, firewallRuleName string, inletsPort string) error {
func (p *GCEProvisioner) createInletsFirewallRule(projectID string, firewallRuleName string, inletsPort string, pro string) error {
if pro == "true" {
inletsPort = "1024-65535"
}

firewallRule := &compute.Firewall{
Name: firewallRuleName,
Description: "Firewall rule created by inlets-operator",
Expand All @@ -155,9 +146,19 @@ func (p *GCEProvisioner) createInletsFirewallRule(projectID string, firewallRule
TargetTags: []string{"inlets"},
}

exists, _ := p.checkInletsFirewallRuleExists(projectID, firewallRuleName)
if exists {
log.Println("inlets firewallRule exists, updating firewall-rules")
_, err := p.gceProvisioner.Firewalls.Update(projectID, firewallRuleName, firewallRule).Do()
if err != nil {
return fmt.Errorf("could not update inlets firewall rule: %v", err)
}
return nil
}

_, err := p.gceProvisioner.Firewalls.Insert(projectID, firewallRule).Do()
if err != nil {
return fmt.Errorf("could not create firewall rule: %v", err)
return fmt.Errorf("could not create inlets firewall rule: %v", err)
}
return nil
}
Expand Down

0 comments on commit 16d7cf5

Please sign in to comment.