func (c *Config) FeatureFlags() uint32 {
	var flags uint32
	for _, h := range c.Hosts {
		if h.Key != "" {
			flags |= FeatureSshKey
		} else if h.Pass != "" {
			flags |= FeatureSshPassword
		}
	}
	if c.Vpnc != nil {
		flags |= FeatureVpnc
	}
	if c.OpenConnect != nil {
		flags |= FeatureOpenConnect
	}
	if c.General.Main != "" && c.Hosts[c.HostsMap[c.General.Main]].SOCKS != "" {
		flags |= FeatureSocks
	}
	if len(c.Hosts) == 0 {
		flags |= FeatureLocalOnly
	}
	return flags
}
FeatureFlags returns the set of features required to handle a tunnel
configuration.
package conf
import (
	"fmt"
	"io"
	"net"
	"sort"
	"github.com/calmh/mole/ini"
)
const (
	defaultSSHPort = 22
)
const (
	FeatureError uint32 = 1 << iota
	FeatureSshPassword
	FeatureSshKey
	FeatureVpnc
	FeatureOpenConnect
	FeatureLocalOnly
	FeatureSocks
)
type Config struct {
	Comments []string
	General struct {
		Description string
		Author      string
		Main        string
		Version     int
		Other       map[string]string
		Comments    []string
	}
	Hosts       []Host
	Forwards    []Forward
	HostsMap    map[string]int
	OpenConnect map[string]string
	Vpnc        map[string]string
	VpnRoutes   []string
}
type Host struct {
	Name     string
	Addr     string
	Port     int
	User     string
	Key      string
	Pass     string
	Via      string
	SOCKS    string
	Other    map[string]string
	Comments []string
}
type Forward struct {
	Name     string
	Lines    []ForwardLine
	Other    map[string]string
	Comments []string
}
type Addrports struct {
	Addr  net.IP
	Ports []int
}
type ForwardLine struct {
	Src Addrports
	Dst Addrports
}
func (line ForwardLine) SrcString(i int) string {
	if i >= len(line.Src.Ports) {
		panic("index > repeat")
	}
	if line.Src.Addr.To4() != nil {
		return fmt.Sprintf("%s:%d", line.Src.Addr.String(), line.Src.Ports[i])
	} else {
		return fmt.Sprintf("[%s]:%d", line.Src.Addr.String(), line.Src.Ports[i])
	}
}
func (line ForwardLine) DstString(i int) string {
	if i >= len(line.Dst.Ports) {
		panic("index > repeat")
	}
	if line.Dst.Addr.To4() != nil {
		return fmt.Sprintf("%s:%d", line.Dst.Addr.String(), line.Dst.Ports[i])
	} else {
		return fmt.Sprintf("[%s]:%d", line.Dst.Addr.String(), line.Dst.Ports[i])
	}
}
func (line ForwardLine) String() string {
	if len(line.Src.Ports) == 1 {
		src := fmt.Sprintf("%s:%d", line.Src.Addr.String(), line.Src.Ports[0])
		dst := fmt.Sprintf("%s:%d", line.Dst.Addr.String(), line.Dst.Ports[0])
		return fmt.Sprintf("%s -> %s", src, dst)
	}
	src := fmt.Sprintf("%s:%d-%d", line.Src.Addr.String(), line.Src.Ports[0], line.Src.Ports[len(line.Src.Ports)-1])
	dst := fmt.Sprintf("%s:%d-%d", line.Dst.Addr.String(), line.Dst.Ports[0], line.Dst.Ports[len(line.Src.Ports)-1])
	return fmt.Sprintf("%s -> %s", src, dst)
}
func Load(r io.Reader) (*Config, error) {
	return parse(ini.Parse(r))
}
func (c *Config) SourceAddresses() []string {
	addrMap := make(map[string]bool)
	for _, fwd := range c.Forwards {
		for _, line := range fwd.Lines {
			addrMap[line.Src.Addr.String()] = true
		}
	}
	addrs := make([]string, 0, len(addrMap))
	for ip := range addrMap {
		addrs = append(addrs, ip)
	}
	sort.Strings(addrs)
	return addrs
}
func (c *Config) Remap() {
	port := 10000
	for fi := range c.Forwards {
		for li := range c.Forwards[fi].Lines {
			if c.Forwards[fi].Lines[li].Src.Addr.String() != "127.0.0.1" && c.Forwards[fi].Lines[li].Src.Addr.String() != "[::1]" {
				c.Forwards[fi].Lines[li].Src.Addr = net.ParseIP("127.0.0.1")
				for sp := range c.Forwards[fi].Lines[li].Src.Ports {
					c.Forwards[fi].Lines[li].Src.Ports[sp] = port
					port += 1
				}
			}
		}
	}
}