Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -130,12 +130,15 @@ * @brief Asynchronously resolves the specified host. * * @param host The host to resolve * @param target The target to call with the result once resolving is done * @param selector The selector to call on the target. The signature must be - * `void (OFArray *response, id context, - * id exception)`. + * `void (OFDNSResolver *resolver, + * nullable OFArray *answerRecords, + * nullable OFArray *authorityRecords, + * nullable OFArray *additionalRecords, + * nullable id context, nullable id exception)`. * @param context A context object to pass along to the target */ - (void)asyncResolveHost: (OFString *)host target: (id)target selector: (SEL)selector Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -150,64 +150,59 @@ return [OFString stringWithCString: domain + 1 encoding: [OFLocale encoding]]; } static OFString * -parseString(const unsigned char *buffer, size_t length, size_t *idx) +parseString(const unsigned char *buffer, size_t length, size_t *i) { - size_t i = *idx; uint8_t stringLength; OFString *string; - if (i >= length) + if (*i >= length) @throw [OFTruncatedDataException exception]; - stringLength = buffer[i++]; + stringLength = buffer[(*i)++]; - if (i + stringLength > length) + if (*i + stringLength > length) @throw [OFTruncatedDataException exception]; - string = [OFString stringWithUTF8String: (char *)&buffer[i] + string = [OFString stringWithUTF8String: (char *)&buffer[*i] length: stringLength]; - i += stringLength; - - *idx = i; + *i += stringLength; return string; } static OFString * -parseName(const unsigned char *buffer, size_t length, size_t *idx, +parseName(const unsigned char *buffer, size_t length, size_t *i, uint_fast8_t pointerLevel) { - size_t i = *idx; OFMutableArray *components = [OFMutableArray array]; uint8_t componentLength; do { OFString *component; - if (i >= length) + if (*i >= length) @throw [OFTruncatedDataException exception]; - componentLength = buffer[i++]; + componentLength = buffer[(*i)++]; if (componentLength & 0xC0) { size_t j; OFString *suffix; if (pointerLevel == 0) @throw [OFInvalidServerReplyException exception]; - if (i >= length) + if (*i >= length) @throw [OFTruncatedDataException exception]; - j = ((componentLength & 0x3F) << 8) | buffer[i++]; - *idx = i; + j = ((componentLength & 0x3F) << 8) | buffer[(*i)++]; - if (j == i - 2) + if (j == *i - 2) /* Pointing to itself?! */ @throw [OFInvalidServerReplyException exception]; suffix = parseName(buffer, length, &j, @@ -220,27 +215,25 @@ return [components componentsJoinedByString: @"."]; } } - if (i + componentLength > length) + if (*i + componentLength > length) @throw [OFTruncatedDataException exception]; - component = [OFString stringWithUTF8String: (char *)&buffer[i] + component = [OFString stringWithUTF8String: (char *)&buffer[*i] length: componentLength]; - i += componentLength; + *i += componentLength; [components addObject: component]; } while (componentLength > 0); - *idx = i; - return [components componentsJoinedByString: @"."]; } static OF_KINDOF(OFDNSResourceRecord *) -createResourceRecord(OFString *name, of_dns_resource_record_class_t recordClass, +parseResourceRecord(OFString *name, of_dns_resource_record_class_t recordClass, of_dns_resource_record_type_t recordType, uint32_t TTL, const unsigned char *buffer, size_t length, size_t i, uint16_t dataLength) { if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_A && recordClass == OF_DNS_RESOURCE_RECORD_CLASS_IN) { @@ -465,10 +458,64 @@ initWithName: name recordClass: recordClass recordType: recordType TTL: TTL] autorelease]; } + +static OFArray * +parseSection(const unsigned char *buffer, size_t length, size_t *i, + uint_fast16_t count) +{ + OFMutableArray *ret = [OFMutableArray array]; + + for (uint_fast16_t j = 0; j < count; j++) { + OFString *name = parseName(buffer, length, i, + MAX_ALLOWED_POINTERS); + of_dns_resource_record_class_t recordClass; + of_dns_resource_record_type_t recordType; + uint32_t TTL; + uint16_t dataLength; + OFDNSResourceRecord *record; + + if (*i + 10 > length) + @throw [OFTruncatedDataException exception]; + + recordType = (buffer[*i] << 16) | buffer[*i + 1]; + recordClass = (buffer[*i + 2] << 16) | buffer[*i + 3]; + TTL = (buffer[*i + 4] << 24) | (buffer[*i + 5] << 16) | + (buffer[*i + 6] << 8) | buffer[*i + 7]; + dataLength = (buffer[*i + 8] << 16) | buffer[*i + 9]; + + *i += 10; + + if (*i + dataLength > length) + @throw [OFTruncatedDataException exception]; + + record = parseResourceRecord(name, recordClass, recordType, TTL, + buffer, length, *i, dataLength); + *i += dataLength; + + [ret addObject: record]; + } + + [ret makeImmutable]; + + return ret; +} + +static void callback(id target, SEL selector, OFDNSResolver *resolver, + OFArray *answerRecords, OFArray *authorityRecords, + OFArray *additionalRecords, id context, id exception) +{ + void (*method)(id, SEL, OFDNSResolver *, OFArray *, OFArray *, + OFArray *, id, id) = (void (*)(id, SEL, OFDNSResolver *, OFArray *, + OFArray *, OFArray *, id, id)) + [target methodForSelector: selector]; + + method(target, selector, resolver, answerRecords, authorityRecords, + additionalRecords, context, exception); +} @implementation OFDNSResolverQuery @synthesize host = _host, recordClass = _recordClass, recordType = _recordType; @synthesize ID = _ID, nameServers = _nameServers; @synthesize searchDomains = _searchDomains; @@ -1014,13 +1061,12 @@ context: query]; } - (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query { - id target; + id target, context; SEL selector; - void (*callback)(id, SEL, OFArray *, id, id); OFResolveHostFailedException *exception; if (query == nil) return; @@ -1037,22 +1083,21 @@ return; } target = [[[query target] retain] autorelease]; selector = [query selector]; - callback = (void (*)(id, SEL, OFArray *, id, id)) - [target methodForSelector: selector]; + context = [[[query context] retain] autorelease]; exception = [OFResolveHostFailedException exceptionWithHost: [query host] recordClass: [query recordClass] recordType: [query recordType] error: OF_DNS_RESOLVER_ERROR_TIMEOUT]; [_queries removeObjectForKey: [query ID]]; - callback(target, selector, nil, [query context], exception); + callback(target, selector, self, nil, nil, nil, context, exception); } - (size_t)of_socket: (OFUDPSocket *)sock didSendBuffer: (void **)buffer bytesSent: (size_t)bytesSent @@ -1061,17 +1106,16 @@ exception: (id)exception { if (exception != nil) { id target = [[[query target] retain] autorelease]; SEL selector = [query selector]; - void (*callback)(id, SEL, OFArray *, id, id) = - (void (*)(id, SEL, OFArray *, id, id)) - [target methodForSelector: selector]; + id context = [[[query context] retain] autorelease]; [_queries removeObjectForKey: [query ID]]; - callback(target, selector, nil, [query context], exception); + callback(target, selector, self, nil, nil, nil, context, + exception); return 0; } [sock asyncReceiveIntoBuffer: [self allocMemoryWithSize: 512] @@ -1089,23 +1133,21 @@ length: (size_t)length sender: (of_socket_address_t)sender context: (id)context exception: (id)exception { - OFMutableArray *answers = nil; + OFArray *answerRecords = nil, *authorityRecords = nil; + OFArray *additionalRecords = nil; OFNumber *ID; OFDNSResolverQuery *query; - id target; - SEL selector; - void (*callback)(id, SEL, OFArray *, id, id); OFData *queryData; if (exception != nil) return false; if (length < 2) - /* We can't get the ID to get the context. Give up. */ + /* We can't get the ID to get the query. Give up. */ return false; ID = [OFNumber numberWithUInt16: (buffer[0] << 8) | buffer[1]]; query = [[[_queries objectForKey: ID] retain] autorelease]; @@ -1113,21 +1155,18 @@ return false; [[query cancelTimer] invalidate]; [_queries removeObjectForKey: ID]; - target = [query target]; - selector = [query selector]; - callback = (void (*)(id, SEL, OFArray *, id, id)) - [target methodForSelector: selector]; queryData = [query queryData]; @try { const unsigned char *queryDataBuffer; size_t i; of_dns_resolver_error_t error; - uint16_t numQuestions, numAnswers; + uint16_t numQuestions, numAnswers, numAuthorityRecords; + uint16_t numAdditionalRecords; if (length < 12) @throw [OFTruncatedDataException exception]; if ([queryData itemSize] != 1 || [queryData count] < 12) @@ -1177,13 +1216,13 @@ recordClass: [query recordClass] recordType: [query recordType] error: error]; numQuestions = (buffer[4] << 8) | buffer[5]; - numAnswers = (buffer[6] << 8) | buffer[7]; - answers = [OFMutableArray arrayWithCapacity: numAnswers]; + numAuthorityRecords = (buffer[8] << 8) | buffer[9]; + numAdditionalRecords = (buffer[10] << 8) | buffer[11]; i = 12; /* * Skip over the questions - we use the ID to identify the @@ -1194,45 +1233,23 @@ for (uint_fast16_t j = 0; j < numQuestions; j++) { parseName(buffer, length, &i, MAX_ALLOWED_POINTERS); i += 4; } - for (uint_fast16_t j = 0; j < numAnswers; j++) { - OFString *name = parseName(buffer, length, &i, - MAX_ALLOWED_POINTERS); - of_dns_resource_record_class_t recordClass; - of_dns_resource_record_type_t recordType; - uint32_t TTL; - uint16_t dataLength; - OFDNSResourceRecord *record; - - if (i + 10 > length) - @throw [OFTruncatedDataException exception]; - - recordType = (buffer[i] << 16) | buffer[i + 1]; - recordClass = (buffer[i + 2] << 16) | buffer[i + 3]; - TTL = (buffer[i + 4] << 24) | (buffer[i + 5] << 16) | - (buffer[i + 6] << 8) | buffer[i + 7]; - dataLength = (buffer[i + 8] << 16) | buffer[i + 9]; - - i += 10; - - if (i + dataLength > length) - @throw [OFTruncatedDataException exception]; - - record = createResourceRecord(name, recordClass, - recordType, TTL, buffer, length, i, dataLength); - i += dataLength; - - [answers addObject: record]; - } + answerRecords = parseSection(buffer, length, &i, numAnswers); + authorityRecords = parseSection(buffer, length, &i, + numAuthorityRecords); + additionalRecords = parseSection(buffer, length, &i, + numAdditionalRecords); } @catch (id e) { - callback(target, selector, nil, [query context], e); + callback([query target], [query selector], self, nil, nil, nil, + [query context], e); return false; } - callback(target, selector, answers, [query context], nil); + callback([query target], [query selector], self, answerRecords, + authorityRecords, additionalRecords, [query context], nil); return false; } - (void)close @@ -1251,26 +1268,22 @@ _IPv6Socket = nil; #endif enumerator = [_queries objectEnumerator]; while ((query = [enumerator nextObject]) != nil) { - id target = [[[query target] retain] autorelease]; - SEL selector = [query selector]; - void (*callback)(id, SEL, OFArray *, id, id) = - (void (*)(id, SEL, OFArray *, id, id)) - [target methodForSelector: selector]; OFResolveHostFailedException *exception; exception = [OFResolveHostFailedException exceptionWithHost: [query host] recordClass: [query recordClass] recordType: [query recordType] error: OF_DNS_RESOLVER_ERROR_CANCELED]; - callback(target, selector, nil, [query context], exception); + callback([query target], [query selector], self, nil, nil, nil, + [query context], exception); } [_queries removeAllObjects]; objc_autoreleasePoolPop(pool); } @end Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -26,20 +26,27 @@ @end OF_APPLICATION_DELEGATE(OFDNS) @implementation OFDNS -- (void)handleDNSResponse: (OFArray OF_GENERIC(OFDNSResourceRecord *) *)response +- (void)DNSResolver: (OFDNSResolver *)resolver + didReceiveAnswerRecords: (OFArray *)answerRecords + authorityRecords: (OFArray *)authorityRecords + additionalRecords: (OFArray *)additionalRecords context: (id)context exception: (id)exception { if (exception != nil) { [of_stderr writeFormat: @"Failed to resolve: %@\n", exception]; [OFApplication terminateWithStatus: 1]; } - [of_stdout writeLine: [response description]]; + [of_stdout writeFormat: @"Answer records: %@\n" + @"Authority records: %@\n" + @"Additional records: %@\n", + answerRecords, authorityRecords, + additionalRecords]; [OFApplication terminate]; } - (void)applicationDidFinishLaunching @@ -74,10 +81,12 @@ [resolver asyncResolveHost: [arguments objectAtIndex: 0] recordClass: recordClass recordType: recordType target: self - selector: @selector(handleDNSResponse:context: - exception:) + selector: @selector(DNSResolver: + didReceiveAnswerRecords: + authorityRecords:additionalRecords: + context:exception:) context: nil]; } @end