示例#1
0
文件: parse.go 项目: reth-/mole
func parse(ic ini.Config) (cp *Config, err error) {
	c := Config{}
	c.General.Other = make(map[string]string)
	c.HostsMap = make(map[string]int)

	c.Comments = ic.Comments("")

	for _, section := range ic.Sections() {
		options := ic.OptionMap(section)

		if section == "general" {
			err := parseGeneral(&c, options)
			if err != nil {
				return nil, err
			}
			c.General.Comments = ic.Comments(section)
		} else if strings.HasPrefix(section, "hosts.") {
			host, err := parseHost(ic, section)
			if err != nil {
				return nil, err
			}
			if c.General.Version < 400 {
				for k := range host.Other {
					return nil, fmt.Errorf("unrecognized field %q on host %q not permitted by config version %d", k, host.Name, c.General.Version)
				}
			}

			c.Hosts = append(c.Hosts, host)
			c.HostsMap[host.Name] = len(c.Hosts) - 1
		} else if strings.HasPrefix(section, "forwards.") {
			forw, err := parseForward(ic, section)
			if err != nil {
				return nil, err
			}
			if cmt := ic.Get(section, "comment"); cmt != "" && c.General.Version < 320 {
				return nil, fmt.Errorf("forward comments are supported in config version 3.2 and above")
			}
			c.Forwards = append(c.Forwards, forw)
		} else if section == "openconnect" {
			c.OpenConnect = options
		} else if section == "vpnc" {
			c.Vpnc = options
		} else if section == "vpn routes" {
			for net, mask := range options {
				c.VpnRoutes = append(c.VpnRoutes, net+"/"+mask)
			}
			sort.Strings(c.VpnRoutes)
		}
	}

	// Check for existence of either hosts or forwards
	if len(c.Hosts) == 0 && len(c.Forwards) == 0 {
		err = fmt.Errorf(`must exist either "hosts" or "forwards" section`)
		return
	}

	// Check for nonexistant "main"
	if c.General.Main != "" {
		if _, ok := c.HostsMap[c.General.Main]; !ok {
			err = fmt.Errorf(`"main" refers to nonexistent host %q`, c.General.Main)
			return
		}
	}

	for _, host := range c.Hosts {
		// Check for errors in "via" links
		if host.Via != "" {
			if _, ok := c.HostsMap[host.Via]; !ok {
				err = fmt.Errorf(`host %q "via" refers to nonexistent host %q`, host.Name, host.Via)
				return
			}
		}
	}

	seenSources := map[string]bool{}
	for _, fwd := range c.Forwards {
		for _, line := range fwd.Lines {
			// Check for duplicate forwards
			for i := 0; i <= line.Repeat; i++ {
				src := line.SrcString(i)
				if seenSources[src] {
					err = fmt.Errorf("duplicate forward source %q", src)
					return
				}
				seenSources[src] = true
			}

			// Check for privileged ports
			if line.SrcPort < 1024 {
				err = fmt.Errorf("privileged source port %d in forward source %q", line.SrcPort, line.SrcString(0))
				return
			}
		}
	}

	cp = &c
	return
}