// NewTrafficRulesSet initializes a TrafficRulesSet with // the rules data in the specified config file. func NewTrafficRulesSet(filename string) (*TrafficRulesSet, error) { set := &TrafficRulesSet{} set.ReloadableFile = common.NewReloadableFile( filename, func(filename string) error { configJSON, err := ioutil.ReadFile(filename) if err != nil { // On error, state remains the same return common.ContextError(err) } var newSet TrafficRulesSet err = json.Unmarshal(configJSON, &newSet) if err != nil { return common.ContextError(err) } err = newSet.Validate() if err != nil { return common.ContextError(err) } // Modify actual traffic rules only after validation set.DefaultRules = newSet.DefaultRules set.FilteredRules = newSet.FilteredRules return nil }) _, err := set.Reload() if err != nil { return nil, common.ContextError(err) } return set, nil }
// NewDatabase initializes a Database, calling Reload on the specified // filename. func NewDatabase(filename string) (*Database, error) { database := &Database{} database.ReloadableFile = common.NewReloadableFile( filename, func(filename string) error { psinetJSON, err := ioutil.ReadFile(filename) if err != nil { // On error, state remains the same return common.ContextError(err) } err = json.Unmarshal(psinetJSON, &database) if err != nil { // On error, state remains the same // (Unmarshal first validates the provided // JOSN and then populates the interface) return common.ContextError(err) } return nil }) _, err := database.Reload() if err != nil { return nil, common.ContextError(err) } return database, nil }
// NewDNSResolver initializes a new DNSResolver, loading it with // a fresh resolver value. The load must succeed, so either // "/etc/resolv.conf" must contain a valid "nameserver" line with // a DNS server IP address, or a valid "defaultResolver" default // value must be provided. // On systems without "/etc/resolv.conf", "defaultResolver" is // required. // // The resolver is considered stale and reloaded if last checked // more than 5 seconds before the last Get(), which is similar to // frequencies in other implementations: // // - https://golang.org/src/net/dnsclient_unix.go, // resolverConfig.tryUpdate: 5 seconds // // - https://github.com/ambrop72/badvpn/blob/master/udpgw/udpgw.c, // maybe_update_dns: 2 seconds // func NewDNSResolver(defaultResolver string) (*DNSResolver, error) { dns := &DNSResolver{ lastReloadTime: int64(monotime.Now()), } dns.ReloadableFile = common.NewReloadableFile( DNS_SYSTEM_CONFIG_FILENAME, func(fileContent []byte) error { resolver, err := parseResolveConf(fileContent) if err != nil { // On error, state remains the same return common.ContextError(err) } dns.resolver = resolver log.WithContextFields( LogFields{ "resolver": resolver.String(), }).Debug("loaded system DNS resolver") return nil }) _, err := dns.Reload() if err != nil { if defaultResolver == "" { return nil, common.ContextError(err) } log.WithContextFields( LogFields{"err": err}).Info( "failed to load system DNS resolver; using default") resolver, err := parseResolver(defaultResolver) if err != nil { return nil, common.ContextError(err) } dns.resolver = resolver } return dns, nil }
// NewGeoIPService initializes a new GeoIPService. func NewGeoIPService( databaseFilenames []string, discoveryValueHMACKey string) (*GeoIPService, error) { geoIP := &GeoIPService{ databases: make([]*geoIPDatabase, len(databaseFilenames)), sessionCache: cache.New(GEOIP_SESSION_CACHE_TTL, 1*time.Minute), discoveryValueHMACKey: discoveryValueHMACKey, } for i, filename := range databaseFilenames { database := &geoIPDatabase{} database.ReloadableFile = common.NewReloadableFile( filename, func(filename string) error { maxMindReader, err := maxminddb.Open(filename) if err != nil { // On error, database state remains the same return common.ContextError(err) } if database.maxMindReader != nil { database.maxMindReader.Close() } database.maxMindReader = maxMindReader return nil }) _, err := database.Reload() if err != nil { return nil, common.ContextError(err) } geoIP.databases[i] = database } return geoIP, nil }
// NewConfig initializes a Config with the settings in the specified // file. func NewConfig(filename string) (*Config, error) { config := &Config{} config.ReloadableFile = common.NewReloadableFile( filename, func(fileContent []byte) error { newConfig, err := LoadConfig(fileContent) if err != nil { return common.ContextError(err) } // Modify actual traffic rules only after validation config.Schemes = newConfig.Schemes return nil }) _, err := config.Reload() if err != nil { return nil, common.ContextError(err) } return config, nil }