package files import ( "errors" "fmt" "os" "path/filepath" "regexp" "strings" "gopkg.in/ini.v1" ) func (s *Source) lazyLoadWireguardConf() WireguardConfig { if s.cached.wireguardLoaded { return s.cached.wireguardConf } s.cached.wireguardLoaded = true var err error s.cached.wireguardConf, err = ParseWireguardConf(filepath.Join(s.rootDirectory, "wireguard", "wg0.conf")) if err != nil { s.warner.Warnf("skipping Wireguard config: %s", err) } return s.cached.wireguardConf } type WireguardConfig struct { PrivateKey *string PreSharedKey *string Addresses *string PublicKey *string EndpointIP *string EndpointPort *string } var ( regexINISectionNotExist = regexp.MustCompile(`^section ".+" does not exist$`) ) func ParseWireguardConf(path string) (config WireguardConfig, err error) { iniFile, err := ini.Load(path) if err != nil { if errors.Is(err, os.ErrNotExist) { return WireguardConfig{}, nil } return WireguardConfig{}, fmt.Errorf("loading ini from reader: %w", err) } interfaceSection, err := iniFile.GetSection("Interface") if err == nil { config.PrivateKey, config.Addresses = parseWireguardInterfaceSection(interfaceSection) } else if !regexINISectionNotExist.MatchString(err.Error()) { // can never happen return WireguardConfig{}, fmt.Errorf("getting interface section: %w", err) } peerSection, err := iniFile.GetSection("Peer") if err == nil { config.PreSharedKey, config.PublicKey, config.EndpointIP, config.EndpointPort = parseWireguardPeerSection(peerSection) } else if !regexINISectionNotExist.MatchString(err.Error()) { // can never happen return WireguardConfig{}, fmt.Errorf("getting peer section: %w", err) } return config, nil } func parseWireguardInterfaceSection(interfaceSection *ini.Section) ( privateKey, addresses *string) { privateKey = getINIKeyFromSection(interfaceSection, "PrivateKey") addresses = getINIKeyFromSection(interfaceSection, "Address") return privateKey, addresses } var ( ErrEndpointHostNotIP = errors.New("endpoint host is not an IP") ) func parseWireguardPeerSection(peerSection *ini.Section) ( preSharedKey, publicKey, endpointIP, endpointPort *string) { preSharedKey = getINIKeyFromSection(peerSection, "PresharedKey") publicKey = getINIKeyFromSection(peerSection, "PublicKey") endpoint := getINIKeyFromSection(peerSection, "Endpoint") if endpoint != nil { parts := strings.Split(*endpoint, ":") endpointIP = &parts[0] const partsWithPort = 2 if len(parts) >= partsWithPort { endpointPort = new(string) *endpointPort = strings.Join(parts[1:], ":") } } return preSharedKey, publicKey, endpointIP, endpointPort } var ( regexINIKeyNotExist = regexp.MustCompile(`key ".*" not exists$`) ) func getINIKeyFromSection(section *ini.Section, key string) (value *string) { iniKey, err := section.GetKey(key) if err != nil { if regexINIKeyNotExist.MatchString(err.Error()) { return nil } // can never happen panic(fmt.Sprintf("getting key %q: %s", key, err)) } value = new(string) *value = iniKey.String() return value }