Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -47,9 +47,11 @@ tests/tests.exe tests/tests.nds utils/objfw-config utils/ofarc/ofarc utils/ofarc/ofarc.exe +utils/ofdns/ofdns +utils/ofdns/ofdns.exe utils/ofhash/ofhash utils/ofhash/ofhash.exe utils/ofhttp/ofhttp utils/ofhttp/ofhttp.exe Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1389,10 +1389,11 @@ AS_IF([test x"$enable_sockets" != x"no" -a x"$enable_threads" != x"no"], [ AC_SUBST(OFHTTPCLIENT_M, "OFHTTPClient.m") AC_SUBST(OFHTTPCLIENTTESTS_M, "OFHTTPClientTests.m") AC_SUBST(OFURLHANDLER_HTTP_M, "OFURLHandler_HTTP.m") + AC_SUBST(OFDNS, "ofdns") AS_IF([test x"$enable_files" != x"no"], [ AC_SUBST(OFHTTP, "ofhttp") ]) ]) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -51,10 +51,11 @@ LOOKUP_ASM_LOOKUP_ASM_A = @LOOKUP_ASM_LOOKUP_ASM_A@ LOOKUP_ASM_LOOKUP_ASM_LIB_A = @LOOKUP_ASM_LOOKUP_ASM_LIB_A@ MAP_LDFLAGS = @MAP_LDFLAGS@ OFARC = @OFARC@ OFBLOCKTESTS_M = @OFBLOCKTESTS_M@ +OFDNS = @OFDNS@ OFHASH = @OFHASH@ OFHTTP = @OFHTTP@ OFHTTPCLIENTTESTS_M = @OFHTTPCLIENTTESTS_M@ OFHTTPCLIENT_M = @OFHTTPCLIENT_M@ OFKERNELEVENTOBSERVER_EPOLL_M = @OFKERNELEVENTOBSERVER_EPOLL_M@ Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -448,10 +448,14 @@ #endif extern OFString *_Nonnull of_dns_resource_record_class_to_string( of_dns_resource_record_class_t recordClass); extern OFString *_Nonnull of_dns_resource_record_type_to_string( of_dns_resource_record_type_t recordType); +extern of_dns_resource_record_class_t of_dns_resource_record_class_parse( + OFString *_Nonnull string); +extern of_dns_resource_record_type_t of_dns_resource_record_type_parse( + OFString *_Nonnull string); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -18,10 +18,11 @@ #include "config.h" #import "OFDNSResourceRecord.h" #import "OFData.h" +#import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" OFString * of_dns_resource_record_class_to_string( of_dns_resource_record_class_t recordClass) @@ -62,10 +63,62 @@ return @"all"; default: return [OFString stringWithFormat: @"%u", recordType]; } } + +of_dns_resource_record_class_t of_dns_resource_record_class_parse( + OFString *string) +{ + void *pool = objc_autoreleasePoolPush(); + of_dns_resource_record_class_t recordClass; + + string = [string uppercaseString]; + + if ([string isEqual: @"IN"]) + recordClass = OF_DNS_RESOURCE_RECORD_CLASS_IN; + else + @throw [OFInvalidArgumentException exception]; + + objc_autoreleasePoolPop(pool); + + return recordClass; +} + +of_dns_resource_record_type_t of_dns_resource_record_type_parse( + OFString *string) +{ + void *pool = objc_autoreleasePoolPush(); + of_dns_resource_record_type_t recordType; + + string = [string uppercaseString]; + + if ([string isEqual: @"A"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_A; + else if ([string isEqual: @"NS"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_NS; + else if ([string isEqual: @"CNAME"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_CNAME; + else if ([string isEqual: @"SOA"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_SOA; + else if ([string isEqual: @"PTR"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_PTR; + else if ([string isEqual: @"HINFO"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_HINFO; + else if ([string isEqual: @"MX"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_MX; + else if ([string isEqual: @"TXT"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_TXT; + else if ([string isEqual: @"AAAA"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_AAAA; + else + @throw [OFInvalidArgumentException exception]; + + objc_autoreleasePoolPop(pool); + + return recordType; +} @implementation OFDNSResourceRecord @synthesize name = _name, recordClass = _recordClass, recordType = _recordType; @synthesize TTL = _TTL; Index: utils/Makefile ================================================================== --- utils/Makefile +++ utils/Makefile @@ -1,8 +1,9 @@ include ../extra.mk SUBDIRS += ${OFARC} \ + ${OFDNS} \ ${OFHASH} \ ${OFHTTP} include ../buildsys.mk ADDED utils/ofdns/Makefile Index: utils/ofdns/Makefile ================================================================== --- utils/ofdns/Makefile +++ utils/ofdns/Makefile @@ -0,0 +1,20 @@ +include ../../extra.mk + +PROG = ofdns${PROG_SUFFIX} +SRCS = OFDNS.m + +include ../../buildsys.mk + +PACKAGE_NAME = ofdns + +${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFW_RT_DEP_LVL2} + +CPPFLAGS += -I../../src \ + -I../../src/runtime \ + -I../../src/exceptions \ + -I../.. +LIBS := -L../../src -lobjfw \ + -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ + ${LIBS} +LD = ${OBJC} +LDFLAGS += ${LDFLAGS_RPATH} ADDED utils/ofdns/OFDNS.m Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFApplication.h" +#import "OFArray.h" +#import "OFDNSResolver.h" +#import "OFStdIOStream.h" + +@interface OFDNS: OFObject +@end + +OF_APPLICATION_DELEGATE(OFDNS) + +@implementation OFDNS +- (void)handleDNSResponse: (OFArray OF_GENERIC(OFDNSResourceRecord *) *)response + 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]]; + + [OFApplication terminate]; +} + +- (void)applicationDidFinishLaunching +{ + OFArray OF_GENERIC(OFString *) *arguments = [OFApplication arguments]; + of_dns_resource_record_class_t recordClass = + OF_DNS_RESOURCE_RECORD_CLASS_ANY; + of_dns_resource_record_type_t recordType = + OF_DNS_RESOURCE_RECORD_TYPE_ALL; + OFDNSResolver *resolver; + + if ([arguments count] < 1 || [arguments count] > 4) { + [of_stderr writeFormat: + @"Usage: %@ host [type [class [server]]]\n", + [OFApplication programName]]; + [OFApplication terminateWithStatus: 1]; + } + + resolver = [OFDNSResolver resolver]; + + if ([arguments count] >= 2) + recordType = of_dns_resource_record_type_parse( + [arguments objectAtIndex: 1]); + + if ([arguments count] >= 3) + recordClass = of_dns_resource_record_class_parse( + [arguments objectAtIndex: 2]); + + if ([arguments count] >= 4) + [resolver setNameServers: + [OFArray arrayWithObject: [arguments objectAtIndex: 3]]]; + + [resolver asyncResolveHost: [arguments objectAtIndex: 0] + recordClass: recordClass + recordType: recordType + target: self + selector: @selector(handleDNSResponse:context: + exception:) + context: nil]; +} +@end