@@ -69,10 +69,12 @@ #ifndef SOCK_DNS # define SOCK_DNS 0 #endif +#define BUFFER_LENGTH OF_DNS_RESOLVER_BUFFER_LENGTH + /* * RFC 1035 doesn't specify if pointers to pointers are allowed, and if so how * many. Since it's unspecified, we have to assume that it might happen, but we * also want to limit it to avoid DoS. Limiting it to 16 levels of pointers and * immediately rejecting pointers to itself seems like a fair balance. @@ -226,11 +228,11 @@ socketAddresses: (OFData *)socketAddresses context: (id)context exception: (id)exception; @end -@interface OFDNSResolver () +@interface OFDNSResolver () - (void)of_setDefaults; - (void)of_obtainSystemConfig; #if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_3DS) - (void)of_parseHosts: (OFString *)path; # if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS4) @@ -259,22 +261,10 @@ selector: (SEL)selector context: (id)context; - (void)of_sendQuery: (OFDNSResolverQuery *)query runLoopMode: (of_run_loop_mode_t)runLoopMode; - (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query; -- (size_t)of_socket: (OFUDPSocket *)sock - didSendBuffer: (void **)buffer - bytesSent: (size_t)bytesSent - receiver: (of_socket_address_t *)receiver - context: (OFDNSResolverQuery *)query - exception: (id)exception; -- (bool)of_socket: (OFUDPSocket *)sock - didReceiveIntoBuffer: (unsigned char *)buffer - length: (size_t)length - sender: (of_socket_address_t)sender - context: (id)context - exception: (id)exception; @end #ifndef OF_WII static OFString * domainFromHostname(void) @@ -1289,12 +1279,14 @@ [_staticHosts release]; [_nameServers release]; [_localDomain release]; [_searchDomains release]; [_lastConfigReload release]; + [_IPv4Socket cancelAsyncRequests]; [_IPv4Socket release]; #ifdef OF_HAVE_IPV6 + [_IPv6Socket cancelAsyncRequests]; [_IPv6Socket release]; #endif [_queries release]; [super dealloc]; @@ -1790,10 +1782,13 @@ _IPv6Socket = [[OFUDPSocket alloc] init]; [_IPv6Socket of_bindToAddress: &address extraType: SOCK_DNS]; [_IPv6Socket setBlocking: false]; + [_IPv6Socket setDelegate: self]; + [_IPv6Socket asyncReceiveIntoBuffer: _buffer + length: BUFFER_LENGTH]; } sock = _IPv6Socket; break; #endif @@ -1804,10 +1799,13 @@ _IPv4Socket = [[OFUDPSocket alloc] init]; [_IPv4Socket of_bindToAddress: &address extraType: SOCK_DNS]; [_IPv4Socket setBlocking: false]; + [_IPv4Socket setDelegate: self]; + [_IPv4Socket asyncReceiveIntoBuffer: _buffer + length: BUFFER_LENGTH]; } sock = _IPv4Socket; break; default: @@ -1815,15 +1813,11 @@ } [sock asyncSendBuffer: [query->_queryData items] length: [query->_queryData count] receiver: query->_usedNameServer - runLoopMode: runLoopMode - target: self - selector: @selector(of_socket:didSendBuffer:bytesSent: - receiver:context:exception:) - context: query]; + runLoopMode: runLoopMode]; } - (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query { OFResolveHostFailedException *exception; @@ -1848,10 +1842,23 @@ } query = [[query retain] autorelease]; [_queries removeObjectForKey: query->_ID]; + /* + * Cancel any pending requests, to avoid a send being still pending and + * trying to access the query once it no longer exists. + */ + [_IPv4Socket cancelAsyncRequests]; + [_IPv4Socket asyncReceiveIntoBuffer: _buffer + length: BUFFER_LENGTH]; +#ifdef OF_HAVE_IPV6 + [_IPv6Socket cancelAsyncRequests]; + [_IPv6Socket asyncReceiveIntoBuffer: _buffer + length: BUFFER_LENGTH]; +#endif + exception = [OFResolveHostFailedException exceptionWithHost: query->_host recordClass: query->_recordClass recordType: query->_recordType error: OF_DNS_RESOLVER_ERROR_TIMEOUT]; @@ -1858,62 +1865,21 @@ callback(query->_target, query->_selector, self, query->_domainName, nil, nil, nil, query->_context, exception); } -- (size_t)of_socket: (OFUDPSocket *)sock - didSendBuffer: (void **)buffer - bytesSent: (size_t)bytesSent - receiver: (of_socket_address_t *)receiver - context: (OFDNSResolverQuery *)query - exception: (id)exception -{ - if (exception != nil) { - query = [[query retain] autorelease]; - [_queries removeObjectForKey: query->_ID]; - - callback(query->_target, query->_selector, self, - query->_domainName, nil, nil, nil, query->_context, - exception); - - return 0; - } - - /* - * Pass the query as context to make sure that its buffer stays around - * for as long as our receive is pending. - */ - [sock asyncReceiveIntoBuffer: [query allocMemoryWithSize: 512] - length: 512 - runLoopMode: [[OFRunLoop currentRunLoop] currentMode] - target: self - selector: @selector(of_socket:didReceiveIntoBuffer: - length:sender:context:exception:) - context: query]; - - return 0; -} - -- (bool)of_socket: (OFUDPSocket *)sock - didReceiveIntoBuffer: (unsigned char *)buffer +- (bool)socket: (OF_KINDOF(OFUDPSocket *))sock + didReceiveIntoBuffer: (void *)buffer_ length: (size_t)length sender: (of_socket_address_t)sender - context: (id)context - exception: (id)exception { + unsigned char *buffer = buffer_; OFDictionary *answerRecords = nil, *authorityRecords = nil; OFDictionary *additionalRecords = nil; OFNumber *ID; OFDNSResolverQuery *query; - if (exception != nil) { - if ([exception respondsToSelector: @selector(errNo)]) - return ([exception errNo] == EINTR); - - return false; - } - if (length < 2) /* We can't get the ID to get the query. Ignore packet. */ return true; ID = [OFNumber numberWithUInt16: (buffer[0] << 8) | buffer[1]]; @@ -1985,11 +1951,11 @@ runLoopMode: runLoopMode target: query->_target selector: query->_selector context: query->_context]; - return false; + return true; } error = OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR; break; case 4: @@ -2034,18 +2000,18 @@ additionalRecords = parseSection(buffer, length, &i, numAdditionalRecords); } @catch (id e) { callback(query->_target, query->_selector, self, query->_domainName, nil, nil, nil, query->_context, e); - return false; + return true; } callback(query->_target, query->_selector, self, query->_domainName, answerRecords, authorityRecords, additionalRecords, query->_context, nil); - return false; + return true; } - (void)asyncResolveSocketAddressesForHost: (OFString *)host target: (id)target selector: (SEL)selector