Skip to content

Commit

Permalink
Merge pull request #72 from davrodpin/multiple-remotes
Browse files Browse the repository at this point in the history
Add support for multiple ssh channels through one connection.
  • Loading branch information
davrodpin authored Jun 24, 2019
2 parents b590417 + 737a597 commit f5bb373
Show file tree
Hide file tree
Showing 17 changed files with 775 additions and 353 deletions.
74 changes: 54 additions & 20 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import (

var re = regexp.MustCompile(`(?P<user>.+@)?(?P<host>[[:alpha:][:digit:]\_\-\.]+)?(?P<port>:[0-9]+)?`)

// App contains main settings of application.
// App contains all supported CLI arguments given by the user.
type App struct {
args []string
flag *flag.FlagSet

Command string
Local HostInput
Remote HostInput
Server HostInput
Local AddressInputList
Remote AddressInputList
Server AddressInput
Key string
Verbose bool
Help bool
Expand Down Expand Up @@ -47,8 +47,8 @@ func (c *App) Parse() error {
f.BoolVar(&c.AliasDelete, "delete", false, "delete a tunnel alias (must be used with -alias)")
f.BoolVar(&c.AliasList, "aliases", false, "list all aliases")
f.StringVar(&c.Start, "start", "", "Start a tunnel using a given alias")
f.Var(&c.Local, "local", "(optional) Set local endpoint address: [<host>]:<port>")
f.Var(&c.Remote, "remote", "set remote endpoint address: [<host>]:<port>")
f.Var(&c.Local, "local", "(optional) Set local endpoint address: [<host>]:<port>. Multiple -local args can be provided.")
f.Var(&c.Remote, "remote", "(optional) Set remote endpoint address: [<host>]:<port>. Multiple -remote args can be provided.")
f.Var(&c.Server, "server", "set server address: [<user>@]<host>[:<port>]")
f.StringVar(&c.Key, "key", "", "(optional) Set server authentication key file path")
f.BoolVar(&c.Verbose, "v", false, "(optional) Increase log verbosity")
Expand Down Expand Up @@ -95,26 +95,24 @@ func (c App) Validate() error {

switch c.Command {
case "new-alias":
if c.Remote.String() == "" {
return fmt.Errorf("required flag is missing: -remote")
} else if c.Server.String() == "" {
if c.Server.String() == "" {
return fmt.Errorf("required flag is missing: -server")
}
case "start":
if c.Server.String() == "" {
return fmt.Errorf("required flag is missing: -server")
}

}

return nil
}

// PrintUsage prints, to the standard output, the informational text on how to
// use the tool.
func (c *App) PrintUsage() {
fmt.Fprintf(os.Stderr, "%s\n\n", `usage:
mole [-v] [-insecure] [-detach] [-local [<host>]:<port>] -remote [<host>]:<port> -server [<user>@]<host>[:<port>] [-key <key_path>]
mole -alias <alias_name> [-v] [-local [<host>]:<port>] -remote [<host>]:<port> -server [<user>@]<host>[:<port>] [-key <key_path>]
mole [-v] [-insecure] [-detach] (-local [<host>]:<port>)... (-remote [<host>]:<port>)... -server [<user>@]<host>[:<port>] [-key <key_path>]
mole -alias <alias_name> [-v] (-local [<host>]:<port>)... (-remote [<host>]:<port>)... -server [<user>@]<host>[:<port>] [-key <key_path>]
mole -alias <alias_name> -delete
mole -start <alias_name>
mole -help
Expand All @@ -128,15 +126,15 @@ func (c App) String() string {
c.Local, c.Remote, c.Server, c.Key, c.Verbose, c.Help, c.Version, c.Detach)
}

// HostInput holds information about a host
type HostInput struct {
// AddressInput holds information about a host
type AddressInput struct {
User string
Host string
Port string
}

// String returns a string representation of a HostInput
func (h HostInput) String() string {
// String returns a string representation of a AddressInput
func (h AddressInput) String() string {
var s string
if h.User == "" {
s = h.Address()
Expand All @@ -147,8 +145,8 @@ func (h HostInput) String() string {
return s
}

// Set parses a string representation of HostInput into its proper attributes.
func (h *HostInput) Set(value string) error {
// Set parses a string representation of AddressInput into its proper attributes.
func (h *AddressInput) Set(value string) error {
result := parseServerInput(value)
h.User = strings.Trim(result["user"], "@")
h.Host = result["host"]
Expand All @@ -157,9 +155,9 @@ func (h *HostInput) Set(value string) error {
return nil
}

// Address returns a string representation of HostInput to be used to perform
// Address returns a string representation of AddressInput to be used to perform
// network connections.
func (h HostInput) Address() string {
func (h AddressInput) Address() string {
if h.Port == "" {
return fmt.Sprintf("%s", h.Host)
}
Expand All @@ -180,3 +178,39 @@ func parseServerInput(input string) map[string]string {

return result
}

type AddressInputList []AddressInput

func (il AddressInputList) String() string {
ils := []string{}

for _, i := range il {
ils = append(ils, i.String())
}

return strings.Join(ils, ",")
}

func (il *AddressInputList) Set(value string) error {
i := AddressInput{}

err := i.Set(value)
if err != nil {
return err
}

*il = append(*il, i)

return nil
}

func (il AddressInputList) List() []string {
sl := []string{}

for _, i := range il {
sl = append(sl, i.String())
}

return sl

}
44 changes: 26 additions & 18 deletions cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,52 @@ import (
"github.com/davrodpin/mole/cli"
)

func TestHostInput(t *testing.T) {
func TestAddressInput(t *testing.T) {
tests := []struct {
input string
expected cli.HostInput
expected cli.AddressInput
}{
{
"test",
cli.HostInput{User: "", Host: "test", Port: ""},
cli.AddressInput{User: "", Host: "test", Port: ""},
},
{
"user@test",
cli.HostInput{User: "user", Host: "test", Port: ""},
cli.AddressInput{User: "user", Host: "test", Port: ""},
},
{
"user@test:2222",
cli.HostInput{User: "user", Host: "test", Port: "2222"},
cli.AddressInput{User: "user", Host: "test", Port: "2222"},
},
{
"test-1",
cli.HostInput{User: "", Host: "test-1", Port: ""},
cli.AddressInput{User: "", Host: "test-1", Port: ""},
},
{
"test-1-2-xy",
cli.HostInput{User: "", Host: "test-1-2-xy", Port: ""},
cli.AddressInput{User: "", Host: "test-1-2-xy", Port: ""},
},
{
"test.com",
cli.HostInput{User: "", Host: "test.com", Port: ""},
cli.AddressInput{User: "", Host: "test.com", Port: ""},
},
{
"test_1",
cli.HostInput{User: "", Host: "test_1", Port: ""},
cli.AddressInput{User: "", Host: "test_1", Port: ""},
},
{
"user@test_1",
cli.HostInput{User: "user", Host: "test_1", Port: ""},
cli.AddressInput{User: "user", Host: "test_1", Port: ""},
},
{
"user@test_1:2222",
cli.HostInput{User: "user", Host: "test_1", Port: "2222"},
cli.AddressInput{User: "user", Host: "test_1", Port: "2222"},
},
}

var h cli.HostInput
var h cli.AddressInput
for _, test := range tests {
h = cli.HostInput{}
h = cli.AddressInput{}
h.Set(test.input)

if !reflect.DeepEqual(test.expected, h) {
Expand Down Expand Up @@ -128,11 +128,7 @@ func TestValidate(t *testing.T) {
},
{
[]string{"./mole", "-alias", "xyz", "-server", "example1"},
false,
},
{
[]string{"./mole", "-alias", "xyz", "-server", "example1"},
false,
true,
},
{
[]string{"./mole", "-alias", "xyz", "-remote", ":443"},
Expand All @@ -142,6 +138,18 @@ func TestValidate(t *testing.T) {
[]string{"./mole", "-alias", "xyz"},
false,
},
{
[]string{"./mole", "-local", ":8080", "-remote", ":80", "-server", "example1"},
true,
},
{
[]string{"./mole", "-remote", ":3366", "-remote", ":443", "-server", "example1"},
true,
},
{
[]string{"./mole", "-local", ":1234", "-remote", ":3366", "-remote", ":443", "-server", "example1"},
true,
},
}

var c *cli.App
Expand Down
75 changes: 75 additions & 0 deletions cmd/mole/alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"fmt"
"strings"

"github.com/davrodpin/mole/cli"
"github.com/davrodpin/mole/storage"
)

func lsAliases() error {
aliases, err := storage.FindAll()
if err != nil {
return err
}

as := []string{}
for a := range aliases {
as = append(as, a)
}

fmt.Printf("alias list: %s\n", strings.Join(as, ", "))

return nil
}

func app2alias(app cli.App) *storage.Alias {
return &storage.Alias{
Local: app.Local.List(),
Remote: app.Remote.List(),
Server: app.Server.String(),
Key: app.Key,
Verbose: app.Verbose,
Help: app.Help,
Version: app.Version,
Detach: app.Detach,
}
}

func alias2app(t *storage.Alias) (*cli.App, error) {
sla, err := t.ReadLocal()
if err != nil {
return nil, err
}

lal := cli.AddressInputList{}
for _, la := range sla {
lal.Set(la)
}

sra, err := t.ReadRemote()
if err != nil {
return nil, err
}

ral := cli.AddressInputList{}
for _, ra := range sra {
ral.Set(ra)
}

server := cli.AddressInput{}
server.Set(t.Server)

return &cli.App{
Command: "start",
Local: lal,
Remote: ral,
Server: server,
Key: t.Key,
Verbose: t.Verbose,
Help: t.Help,
Version: t.Version,
Detach: t.Detach,
}, nil
}
Loading

0 comments on commit f5bb373

Please sign in to comment.