Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -21,10 +21,11 @@ OF_ASSUME_NONNULL_BEGIN @class OFArray OF_GENERIC(ObjectType); @class OFDNSResolverQuery; +@class OFDate; @class OFDictionary OF_GENERIC(KeyType, ObjectType); @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); @class OFNumber; @class OFUDPSocket; @@ -61,10 +62,15 @@ /*! * @class OFDNSResolver OFDNSResolver.h ObjFW/OFDNSResolver.h * * @brief A class for resolving DNS names. + * + * @note If you change any of the properties, make sure to set + * @ref configReloadInterval to 0, as otherwise your changes will be + * reverted back to the system configuration on the next periodic config + * reload. */ @interface OFDNSResolver: OFObject { OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC(OFString *) *) *_staticHosts; @@ -71,10 +77,12 @@ OFArray OF_GENERIC(OFString *) *_nameServers; OFString *_Nullable _localDomain; OFArray OF_GENERIC(OFString *) *_searchDomains; size_t _minNumberOfDotsInAbsoluteName; bool _usesTCP; + of_time_interval_t _configReloadInterval; + OFDate *_lastConfigReload; OFUDPSocket *_IPv4Socket; #ifdef OF_HAVE_IPV6 OFUDPSocket *_IPv6Socket; #endif OFMutableDictionary OF_GENERIC(OFNumber *, OFDNSResolverQuery *) @@ -114,10 +122,17 @@ /*! * @brief Whether the resolver uses TCP to talk to a name server. */ @property (nonatomic) bool usesTCP; +/*! + * @brief The interval in seconds in which the config should be reloaded. + * + * Setting this to 0 disables config reloading. + */ +@property (nonatomic) of_time_interval_t configReloadInterval; + /*! * @brief Creates a new, autoreleased OFDNSResolver. */ + (instancetype)resolver; Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -22,10 +22,11 @@ #import "OFDNSResolver.h" #import "OFArray.h" #import "OFCharacterSet.h" #import "OFData.h" +#import "OFDate.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFString.h" @@ -56,10 +57,27 @@ */ #define MAX_ALLOWED_POINTERS 16 #define TIMEOUT 2 #define ATTEMPTS 3 + +#if defined(OF_HAIKU) +# define HOSTS_PATH @"/system/settings/network/hosts" +# define RESOLV_CONF_PATH @"/system/settings/network/resolv.conf" +#elif defined(OF_MORPHOS) +# define HOSTS_PATH @"ENV:sys/net/hosts" +# define RESOLV_CONF_PATH @"ENV:sys/net/resolv.conf" +#elif defined(OF_AMIGAOS4) +# define HOSTS_PATH @"DEVS:Internet/hosts" +# define RESOLV_CONF_PATH @"DEVS:Internet/resolv.conf" +#elif defined(OF_AMIGAOS) +# define HOSTS_PATH @"AmiTCP:db/hosts" +# define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" +#else +# define HOSTS_PATH @"/etc/hosts" +# define RESOLV_CONF_PATH @"/etc/resolv.conf" +#endif /* * TODO: * * - Resolve with each search domain @@ -108,10 +126,11 @@ selector: (SEL)selector context: (id)context; @end @interface OFDNSResolver () +- (void)of_parseConfig; #ifdef OF_HAVE_FILES - (void)of_parseHosts: (OFString *)path; # ifndef OF_WINDOWS - (void)of_parseResolvConf: (OFString *)path; - (void)of_parseResolvConfOption: (OFString *)option; @@ -118,10 +137,11 @@ # endif #endif #ifdef OF_WINDOWS - (void)of_parseNetworkParams; #endif +- (void)of_reloadConfig; - (void)of_sendQuery: (OFDNSResolverQuery *)query; - (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query; - (size_t)of_socket: (OFUDPSocket *)sock didSendBuffer: (void **)buffer bytesSent: (size_t)bytesSent @@ -633,11 +653,11 @@ @implementation OFDNSResolver @synthesize staticHosts = _staticHosts, nameServers = _nameServers; @synthesize localDomain = _localDomain, searchDomains = _searchDomains; @synthesize minNumberOfDotsInAbsoluteName = _minNumberOfDotsInAbsoluteName; -@synthesize usesTCP = _usesTCP; +@synthesize usesTCP = _usesTCP, configReloadInterval = _configReloadInterval; + (instancetype)resolver { return [[[self alloc] init] autorelease]; } @@ -645,109 +665,105 @@ - (instancetype)init { self = [super init]; @try { - void *pool = objc_autoreleasePoolPush(); -#ifdef OF_WINDOWS - OFString *path; -#endif - - _minNumberOfDotsInAbsoluteName = 1; - -#ifdef OF_HAVE_FILES -# if defined(OF_WINDOWS) - path = [[OFWindowsRegistryKey localMachineKey] - stringForValue: @"DataBasePath" - subKeyPath: @"SYSTEM\\CurrentControlSet\\Services\\" - @"Tcpip\\Parameters"]; - path = [path stringByAppendingPathComponent: @"hosts"]; - - if (path != nil) - [self of_parseHosts: path]; -# elif defined(OF_HAIKU) - [self of_parseHosts: @"/boot/common/settings/network/hosts"]; -# elif defined(OF_MORPHOS) - [self of_parseHosts: @"ENVARC:sys/net/hosts"]; -# elif defined(OF_AMIGAOS4) - [self of_parseHosts: @"DEVS:Internet/hosts"]; -# elif defined(OF_AMIGAOS) - [self of_parseHosts: @"AmiTCP:db/hosts"]; -# else - [self of_parseHosts: @"/etc/hosts"]; -# endif - -# if defined(OF_MORPHOS) - [self of_parseResolvConf: @"ENV:sys/net/resolv.conf"]; -# elif !defined(OF_WINDOWS) - [self of_parseResolvConf: @"/etc/resolv.conf"]; - [self of_parseResolvConf: @"/etc/resolv.conf.tail"]; -# endif -#endif -#ifdef OF_WINDOWS - [self of_parseNetworkParams]; -#endif - - if (_staticHosts == nil) { - OFArray *localhost = - -#ifdef OF_HAVE_IPV6 - localhost = [OFArray arrayWithObjects: - @"::1", @"127.0.0.1", nil]; -#else - localhost = [OFArray arrayWithObject: @"127.0.0.1"]; -#endif - - _staticHosts = [[OFDictionary alloc] - initWithObject: localhost - forKey: @"localhost"]; - } - - if (_nameServers == nil) -#ifdef OF_HAVE_IPV6 - _nameServers = [[OFArray alloc] - initWithObjects: @"127.0.0.1", @"::1", nil]; -#else - _nameServers = [[OFArray alloc] - initWithObject: @"127.0.0.1"]; -#endif - - if (_localDomain == nil) - _localDomain = [domainFromHostname() copy]; - - if (_searchDomains == nil) { - if (_localDomain != nil) - _searchDomains = [[OFArray alloc] - initWithObject: _localDomain]; - else - _searchDomains = [[OFArray alloc] init]; - } - _queries = [[OFMutableDictionary alloc] init]; - objc_autoreleasePoolPop(pool); + [self of_parseConfig]; } @catch (id e) { [self release]; @throw e; } return self; } + +- (void)of_parseConfig +{ + void *pool = objc_autoreleasePoolPush(); +#ifdef OF_WINDOWS + OFString *path; +#endif + + _minNumberOfDotsInAbsoluteName = 1; + _usesTCP = false; + _configReloadInterval = 2; + +#if defined(OF_WINDOWS) +# ifdef OF_HAVE_FILES + path = [[OFWindowsRegistryKey localMachineKey] + stringForValue: @"DataBasePath" + subKeyPath: @"SYSTEM\\CurrentControlSet\\Services\\" + @"Tcpip\\Parameters"]; + path = [path stringByAppendingPathComponent: @"hosts"]; + + if (path != nil) + [self of_parseHosts: path]; +# endif + + [self of_parseNetworkParams]; +#elif defined(OF_HAVE_FILES) + [self of_parseHosts: HOSTS_PATH]; +# ifdef OF_OPENBSD + [self of_parseHosts: @"/etc/resolv.conf.tail"]; +# endif + + [self of_parseResolvConf: RESOLV_CONF_PATH]; +#endif + + if (_staticHosts == nil) { + OFArray *localhost = +#ifdef OF_HAVE_IPV6 + [OFArray arrayWithObjects: @"::1", @"127.0.0.1", nil]; +#else + [OFArray arrayWithObject: @"127.0.0.1"]; +#endif + + _staticHosts = [[OFDictionary alloc] + initWithObject: localhost + forKey: @"localhost"]; + } + + if (_nameServers == nil) +#ifdef OF_HAVE_IPV6 + _nameServers = [[OFArray alloc] + initWithObjects: @"127.0.0.1", @"::1", nil]; +#else + _nameServers = [[OFArray alloc] initWithObject: @"127.0.0.1"]; +#endif + + if (_localDomain == nil) + _localDomain = [domainFromHostname() copy]; + + if (_searchDomains == nil) { + if (_localDomain != nil) + _searchDomains = [[OFArray alloc] + initWithObject: _localDomain]; + else + _searchDomains = [[OFArray alloc] init]; + } + + _lastConfigReload = [[OFDate alloc] init]; + + objc_autoreleasePoolPop(pool); +} - (void)dealloc { [self close]; [_staticHosts release]; [_nameServers release]; [_localDomain release]; [_searchDomains release]; - [_queries release]; + [_lastConfigReload release]; [_IPv4Socket release]; #ifdef OF_HAVE_IPV6 [_IPv6Socket release]; #endif + [_queries release]; [super dealloc]; } #ifdef OF_HAVE_FILES @@ -956,10 +972,43 @@ _localDomain = [localDomain copy]; objc_autoreleasePoolPop(pool); } #endif + +- (void)of_reloadConfig +{ + /* + * TODO: Rather than reparsing every, check what actually changed + * (mtime) and only reset those. + */ + + if (_lastConfigReload != nil && _configReloadInterval > 0 && + [_lastConfigReload timeIntervalSinceNow] < _configReloadInterval) + return; + + [_staticHosts release]; + _staticHosts = nil; + + [_nameServers release]; + _nameServers = nil; + + [_localDomain release]; + _localDomain = nil; + + [_searchDomains release]; + _searchDomains = nil; + + _minNumberOfDotsInAbsoluteName = 1; + _usesTCP = false; + _configReloadInterval = 2; + + [_lastConfigReload release]; + _lastConfigReload = nil; + + [self of_parseConfig]; +} - (void)asyncResolveHost: (OFString *)host target: (id)target selector: (SEL)selector context: (id)context @@ -981,10 +1030,12 @@ { void *pool = objc_autoreleasePoolPush(); OFNumber *ID; OFString *domainName; OFDNSResolverQuery *query; + + [self of_reloadConfig]; /* Random, unused ID */ do { ID = [OFNumber numberWithUInt16: (uint16_t)of_random()]; } while ([_queries objectForKey: ID] != nil); Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -75,13 +75,15 @@ if ([arguments count] >= 3) recordClass = of_dns_resource_record_class_parse( [arguments objectAtIndex: 2]); - if ([arguments count] >= 4) + if ([arguments count] >= 4) { + [resolver setConfigReloadInterval: 0]; [resolver setNameServers: [OFArray arrayWithObject: [arguments objectAtIndex: 3]]]; + } [resolver asyncResolveHost: [arguments objectAtIndex: 0] recordClass: recordClass recordType: recordType target: self