Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -248,11 +248,11 @@ static OF_KINDOF(OFDNSResourceRecord *) createResourceRecord(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, size_t dataLength) { - Class class; + uint16_t preference; id data; if (recordClass == OF_DNS_RESOURCE_RECORD_CLASS_IN) { size_t j; @@ -260,53 +260,95 @@ case OF_DNS_RESOURCE_RECORD_TYPE_A: if (dataLength != 4) @throw [OFInvalidServerReplyException exception]; - class = [OFADNSResourceRecord class]; data = [OFString stringWithFormat: @"%u.%u.%u.%u", buffer[i], buffer[i + 1], buffer[i + 2], buffer[i + 3]]; - break; + + return [[[OFADNSResourceRecord alloc] + initWithName: name + recordClass: recordClass + recordType: recordType + data: data + TTL: TTL] autorelease]; case OF_DNS_RESOURCE_RECORD_TYPE_CNAME: j = i; - class = [OFCNAMEDNSResourceRecord class]; + data = parseName(buffer, length, &j, + ALLOWED_POINTER_LEVELS); + + if (j != i + dataLength) + @throw [OFInvalidServerReplyException + exception]; + + return [[[OFCNAMEDNSResourceRecord alloc] + initWithName: name + recordClass: recordClass + recordType: recordType + data: data + TTL: TTL] autorelease]; + case OF_DNS_RESOURCE_RECORD_TYPE_MX: + if (dataLength < 2) + @throw [OFInvalidServerReplyException + exception]; + + preference = (buffer[i] << 8) | buffer[i + 1]; + + j = i + 2; + data = parseName(buffer, length, &j, ALLOWED_POINTER_LEVELS); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; - break; + return [[[OFMXDNSResourceRecord alloc] + initWithName: name + recordClass: recordClass + recordType: recordType + preference: preference + data: data + TTL: TTL] autorelease]; case OF_DNS_RESOURCE_RECORD_TYPE_AAAA: if (dataLength != 16) @throw [OFInvalidServerReplyException exception]; - class = [OFAAAADNSResourceRecord class]; - data = parseAAAAData(&buffer[i]); - break; - default: - class = [OFDNSResourceRecord class]; - data = [OFData dataWithItems: &buffer[i] - count: dataLength]; - break; - } - } else { - class = [OFDNSResourceRecord class]; - data = [OFData dataWithItems: &buffer[i] - count: dataLength]; - } - - return [[[class alloc] initWithName: name - recordClass: recordClass - recordType: recordType - data: data - TTL: TTL] autorelease]; + data = parseAAAAData(&buffer[i]); + + return [[[OFAAAADNSResourceRecord alloc] + initWithName: name + recordClass: recordClass + recordType: recordType + data: data + TTL: TTL] autorelease]; + default: + data = [OFData dataWithItems: &buffer[i] + count: dataLength]; + + return [[[OFDNSResourceRecord alloc] + initWithName: name + recordClass: recordClass + recordType: recordType + data: data + TTL: TTL] autorelease]; + } + } else { + data = [OFData dataWithItems: &buffer[i] + count: dataLength]; + + return [[[OFDNSResourceRecord alloc] + initWithName: name + recordClass: recordClass + recordType: recordType + data: data + TTL: TTL] autorelease]; + } } @implementation OFDNSResolver_context @synthesize host = _host, nameServers = _nameServers; @synthesize searchDomains = _searchDomains; Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -76,11 +76,11 @@ * @brief The domain name to which the resource record belongs. */ @property (readonly, nonatomic) OFString *name; /*! - * @brief The class of the data. + * @brief The resource record class code. */ @property (readonly, nonatomic) of_dns_resource_record_class_t recordClass; /*! * @brief The resource record type code. @@ -96,10 +96,21 @@ * @brief The number of seconds after which the resource record should be * discarded from the cache. */ @property (readonly, nonatomic) uint32_t TTL; +/*! + * @brief Initializes an already allocated OFDNSResourceRecord with the + * specified name, resource record class, resource record type, resource + * record data and resource record time to live. + * + * @param name The name of the resource record + * @param recordClass The class code for the resource record + * @param recordType The type code for the resource record + * @param data The data for the resource record + * @param TTL The time to live for the resource record + */ - (instancetype)initWithName: (OFString *)name recordClass: (of_dns_resource_record_class_t)recordClass recordType: (of_dns_resource_record_type_t)recordType data: (id)data TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @@ -141,10 +152,58 @@ * A string with the alias. */ @property (readonly, nonatomic) OFString *data; @end +/*! + * @class OFMXDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an MX DNS resource record. + */ +@interface OFMXDNSResourceRecord: OFDNSResourceRecord +{ + uint16_t _preference; +} + +/*! + * The preference of the resource record. + */ +@property (readonly, nonatomic) uint16_t preference; + +/*! + * A string with the mail exchange. + */ +@property (readonly, nonatomic) OFString *data; + +- (instancetype)initWithName: (OFString *)name + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType + data: (id)data + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/*! + * @brief Initializes an already allocated OFMXDNSResourceRecord with the + * specified name, resource record class, resource record type, resource + * record preference, resource record data and resource record time to + * live. + * + * @param name The name of the resource record + * @param recordClass The class code for the resource record + * @param recordType The type code for the resource record + * @param preference The preference of the resource record + * @param data The data for the resource record + * @param TTL The time to live for the resource record + */ +- (instancetype)initWithName: (OFString *)name + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType + preference: (uint16_t)preference + data: (id)data + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + #ifdef __cplusplus extern "C" { #endif extern OFString *_Nonnull of_dns_resource_record_class_to_string( of_dns_resource_record_class_t recordClass); Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -147,37 +147,111 @@ } - (OFString *)description { return [OFString stringWithFormat: - @"", - _name, of_dns_resource_record_class_to_string(_recordClass), + [self className], _name, + of_dns_resource_record_class_to_string(_recordClass), of_dns_resource_record_type_to_string(_recordType), _data, _TTL]; } @end @implementation OFADNSResourceRecord -- (OFString *)data -{ - return _data; -} +@dynamic data; @end @implementation OFAAAADNSResourceRecord -- (OFString *)data -{ - return _data; -} +@dynamic data; @end @implementation OFCNAMEDNSResourceRecord -- (OFString *)data +@dynamic data; +@end + +@implementation OFMXDNSResourceRecord +@dynamic data; +@synthesize preference = _preference; + +- (instancetype)initWithName: (OFString *)name + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType + data: (id)data + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType + preference: (uint16_t)preference + data: (id)data + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + recordClass: recordClass + recordType: recordType + data: data + TTL: TTL]; + + _preference = preference; + + return self; +} + +- (bool)isEqual: (id)otherObject +{ + OFMXDNSResourceRecord *otherRecord; + + if (![otherObject isKindOfClass: [OFMXDNSResourceRecord class]]) + return false; + + otherRecord = otherObject; + + if (![super isEqual: otherRecord]) + return false; + + if (otherRecord->_preference != _preference) + return false; + + return true; +} + +- (uint32_t)hash +{ + uint32_t hash; + + OF_HASH_INIT(hash); + + OF_HASH_ADD_HASH(hash, [super hash]); + OF_HASH_ADD(hash, _preference >> 8); + OF_HASH_ADD(hash, _preference); + + OF_HASH_FINALIZE(hash); + + return hash; +} + +- (OFString *)description { - return _data; + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tType = %@\n" + @"\tPreference = %" PRIu16 "\n" + @"\tData = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + [self className], _name, + of_dns_resource_record_class_to_string(_recordClass), + of_dns_resource_record_type_to_string(_recordType), _preference, + _data, _TTL]; } @end