Пример #1
0
func usageFor(fs *flag.FlagSet, usage string) func() {
	return func() {
		var b bytes.Buffer
		b.WriteString(ansi.Bold("Usage:") + "\n  " + usage + "\n")

		var options [][]string
		fs.VisitAll(func(f *flag.Flag) {
			var opt = "  -" + f.Name

			if f.DefValue != "false" {
				opt += "=" + f.DefValue
			}

			options = append(options, []string{opt, f.Usage})
		})

		if len(options) > 0 {
			b.WriteString("\n" + ansi.Bold("Options:") + "\n")
			optionTable(&b, options)
		}

		fmt.Println(b.String())

	}
}
Пример #2
0
func lazySetupPrefixes() {
	if prefix == nil {
		if !loggingEnabled {
			panic("attempting setup before logging enabled")
		}
		prefix = map[string]string{
			"debug": ansi.Magenta("debug "),
			// info has no prefix
			"ok":      ansi.Bold(ansi.Green("ok ")),
			"warning": ansi.Bold(ansi.Yellow("warning ")),
			"fatal":   ansi.Bold(ansi.Red("fatal ")),
		}
	}
}
Пример #3
0
func tableFormatter(cell string, row, col, flags int) string {
	if row == 0 {
		return ansi.Underline(cell)
	} else if col == 0 {
		return ansi.Bold(ansi.Cyan(cell))
	} else if col == 1 && (strings.HasSuffix(cell, "U") || strings.HasSuffix(cell, "E")) {
		return ansi.Red(cell)
	} else if flags&table.Truncated != 0 {
		return cell[:len(cell)-1] + ansi.Red(">")
	}
	return cell
}
Пример #4
0
func mainUsage(w io.Writer) {
	tw := tabwriter.NewWriter(w, 2, 4, 2, ' ', 0)

	fmt.Fprintln(w, ansi.Bold("Commands:"))
	var cmds []string
	for _, cmd := range commandList {
		cmds = append(cmds, cmd.name)
	}
	sort.Strings(cmds)
	for _, name := range cmds {
		cmd := commandMap[name]
		if sn := cmd.descr; sn != "" {
			alias := ""
			// Ignore undocumented commands
			if len(cmd.aliases) > 0 {
				alias = " (" + strings.Join(cmd.aliases, ", ") + ")"
			}
			tw.Write([]byte(fmt.Sprintf("  %s%s\t%s\n", ansi.Bold(ansi.Cyan(name)), ansi.Cyan(alias), sn)))
		}
	}
	tw.Flush()
	fmt.Fprintln(w, "\n  Commands can be abbreviated to their unique prefix.\n")

	fmt.Fprintln(w, ansi.Bold("Examples:"))
	examples := [][]string{
		{"  mole ls", "# show all available tunnels"},
		{"  mole l foo", "# show all available tunnels matching the regexp \"foo\""},
		{"  mole show foo", "# show the hosts and forwards in the tunnel \"foo\""},
		{"  sudo mole dig foo", "# dig the tunnel \"foo\""},
		{"  sudo mole -d d foo", "# dig the tunnel \"foo\", while showing debug output"},
		{"  mole push foo.ini", "# create or update the \"foo\" tunnel from a local file"},
		{"  mole install", "# list packages available for installation"},
		{"  mole ins vpnc", "# install a package named vpnc"},
		{"  mole up -force", "# perform a forced up/downgrade to the server version"},
	}
	optionTable(w, examples)
	w.Write([]byte("\n"))
}
Пример #5
0
func commandLs(args []string) {
	fs := flag.NewFlagSet("ls", flag.ContinueOnError)
	short := fs.Bool("s", false, "Short listing")
	long := fs.Bool("l", false, "Long listing")
	fs.Usage = usageFor(fs, msgLsUsage)
	err := fs.Parse(args)
	if err != nil {
		fmt.Println(ansi.Bold("Feature Flags:"))
		fmt.Println(msgLsFlags)
		exit(3)
	}
	args = fs.Args()

	var re *regexp.Regexp
	if len(args) == 1 {
		re, err = regexp.Compile("(?i)" + args[0])
		fatalErr(err)
	}

	cl := NewClient(serverAddress(), moleIni.Get("server", "fingerprint"))
	res, err := authenticated(cl, func() (interface{}, error) { return cl.List() })
	fatalErr(err)
	l := res.([]ListItem)

	var rows [][]string
	var header []string
	var format string
	var hasFeatureFlags bool

	for _, i := range l {
		if i.Features != 0 {
			hasFeatureFlags = true
			break
		}
	}

	if hasFeatureFlags {
		header = []string{"TUNNEL", "FLAGS", "DESCRIPTION"}
		format = "lll"
	} else {
		header = []string{"TUNNEL", "DESCRIPTION"}
		format = "ll"
	}
	if *long {
		header = append(header, "HOSTS", "VER")
		format += "lr"
	}

	rows = [][]string{header}

	tunnelCache, _ := os.Create(path.Join(homeDir, "tunnels.cache"))

	var matched int
	for _, i := range l {
		hosts := strings.Join(i.Hosts, ", ")
		if re == nil || re.MatchString(i.Name) || re.MatchString(i.Description) || re.MatchString(hosts) {
			if tunnelCache != nil {
				fmt.Fprintln(tunnelCache, i.Name)
			}

			if *short {
				fmt.Println(i.Name)
			} else {
				matched++

				row := []string{i.Name}

				if hasFeatureFlags {
					flags := ""
					spacer := "·"
					unsupported := i.Features & ^(conf.FeatureError|conf.FeatureSshKey|conf.FeatureSshPassword|conf.FeatureLocalOnly|conf.FeatureVpnc|conf.FeatureOpenConnect|conf.FeatureSocks) != 0

					if i.Features&conf.FeatureError != 0 {
						flags = strings.Repeat(spacer, 4) + "E"
					} else {
						if i.Features&conf.FeatureVpnc != 0 {
							flags += "v"
							unsupported = unsupported || !supportsVpn("vpnc")
						} else if i.Features&conf.FeatureOpenConnect != 0 {
							flags += "o"
							unsupported = unsupported || !supportsVpn("openconnect")
						} else {
							flags += spacer
						}

						if i.Features&conf.FeatureSshKey != 0 {
							flags += "k"
						} else {
							flags += spacer
						}

						if i.Features&conf.FeatureSshPassword != 0 {
							flags += "p"
						} else {
							flags += spacer
						}

						if i.Features&conf.FeatureSocks != 0 {
							flags += "s"
						} else if i.Features&conf.FeatureLocalOnly != 0 {
							flags += "l"
						} else {
							flags += spacer
						}

						if unsupported {
							flags += "U"
						} else {
							flags += spacer
						}
					}
					row = append(row, flags)
				}

				row = append(row, i.Description)

				if *long {
					ver := fmt.Sprintf("%.01f", i.Version)
					if hosts == "" {
						hosts = "-"
					}
					row = append(row, hosts, ver)
				}

				rows = append(rows, row)
			}
		}
	}

	if tunnelCache != nil {
		_ = tunnelCache.Close()
	}

	if !*short {
		// Never prefix table with log stuff
		fmt.Printf(table.FmtFunc(format, rows, tableFormatter))
		if matched != len(l) {
			fmt.Printf(ansi.Faint(" - Matched %d out of %d records\n"), matched, len(l))
		}
	}
}
Пример #6
0
func shell(fwdChan chan<- conf.ForwardLine, cfg *conf.Config, dialer Dialer) {
	help := func() {
		infoln("Available commands:")
		infoln("  help, ?                          - show help")
		infoln("  quit, ^D                         - stop forwarding and exit")
		infoln("  test                             - test each forward for connection")
		infoln("  stat                             - show forwarding statistics")
		infoln("  debug                            - enable debugging")
		infoln("  fwd srcip:srcport dstip:dstport  - add forward")
	}

	term := liner.NewLiner()
	atExit(func() {
		term.Close()
	})

	// Receive commands

	commands := make(chan string)
	next := make(chan bool)
	go func() {
		for {
			prompt := "mole> "
			if debugEnabled {
				prompt = "(debug) mole> "
			}
			cmd, err := term.Prompt(prompt)
			if err == io.EOF {
				fmt.Println("quit")
				commands <- "quit"
				return
			}

			if cmd != "" {
				commands <- cmd
				term.AppendHistory(cmd)
				_, ok := <-next
				if !ok {
					return
				}
			}
		}
	}()

	// Catch ^C and treat as "quit" command

	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	go func() {
		<-sigchan
		fmt.Println("quit")
		commands <- "quit"
	}()

	// Handle commands

	for {
		cmd := <-commands

		parts := strings.SplitN(cmd, " ", -1)

		switch parts[0] {
		case "quit":
			close(next)
			return
		case "help", "?":
			help()
		case "stat":
			printStats()
		case "test":
			results := testForwards(dialer, cfg)
			for res := range results {
				infof(ansi.Bold(ansi.Cyan(res.name)))
				for _, line := range res.results {
					if line.err == nil {
						infof("%22s %s in %.02f ms", line.dst, ansi.Bold(ansi.Green("-ok-")), line.ms)
					} else {
						infof("%22s %s in %.02f ms (%s)", line.dst, ansi.Bold(ansi.Red("fail")), line.ms, line.err)
					}
				}
			}
		case "debug":
			infoln(msgDebugEnabled)
			debugEnabled = true
		case "fwd":
			if len(parts) != 3 {
				warnf(msgErrIncorrectFwd, cmd)
				break
			}

			src := strings.SplitN(parts[1], ":", 2)
			if len(src) != 2 {
				warnf(msgErrIncorrectFwdSrc, parts[1])
				break
			}

			var ipExists bool
			for _, ip := range currentAddresses() {
				if ip == src[0] {
					ipExists = true
					break
				}
			}
			if !ipExists {
				warnf(msgErrIncorrectFwdIP, src[0])
				break
			}

			dst := strings.SplitN(parts[2], ":", 2)
			if len(dst) != 2 {
				warnf(msgErrIncorrectFwdDst, parts[2])
				break
			}

			srcp, err := strconv.Atoi(src[1])
			if err != nil {
				warnln(err)
				break
			}
			if srcp < 1024 {
				warnf(msgErrIncorrectFwdPriv, srcp)
				break
			}

			dstp, err := strconv.Atoi(dst[1])
			if err != nil {
				warnln(err)
				break
			}
			fwd := conf.ForwardLine{
				SrcIP:   src[0],
				SrcPort: srcp,
				DstIP:   dst[0],
				DstPort: dstp,
			}
			okln("add", fwd)
			fwdChan <- fwd
		default:
			warnf(msgErrNoSuchCommand, parts[0])
		}

		next <- true
	}
}