1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 Jeremy Lainé <jeremy.laine@m4x.org> |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the examples of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include "dnslookup.h" |
52 | |
53 | #include <QCoreApplication> |
54 | #include <QDnsLookup> |
55 | #include <QHostAddress> |
56 | #include <QStringList> |
57 | #include <QTimer> |
58 | #include <QCommandLineParser> |
59 | #include <QCommandLineOption> |
60 | |
61 | #include <stdio.h> |
62 | |
63 | static int typeFromParameter(const QString &type) |
64 | { |
65 | if (type == "a" ) |
66 | return QDnsLookup::A; |
67 | if (type == "aaaa" ) |
68 | return QDnsLookup::AAAA; |
69 | if (type == "any" ) |
70 | return QDnsLookup::ANY; |
71 | if (type == "cname" ) |
72 | return QDnsLookup::CNAME; |
73 | if (type == "mx" ) |
74 | return QDnsLookup::MX; |
75 | if (type == "ns" ) |
76 | return QDnsLookup::NS; |
77 | if (type == "ptr" ) |
78 | return QDnsLookup::PTR; |
79 | if (type == "srv" ) |
80 | return QDnsLookup::SRV; |
81 | if (type == "txt" ) |
82 | return QDnsLookup::TXT; |
83 | return -1; |
84 | } |
85 | |
86 | //! [0] |
87 | |
88 | enum CommandLineParseResult |
89 | { |
90 | CommandLineOk, |
91 | CommandLineError, |
92 | CommandLineVersionRequested, |
93 | CommandLineHelpRequested |
94 | }; |
95 | |
96 | CommandLineParseResult parseCommandLine(QCommandLineParser &parser, DnsQuery *query, QString *errorMessage) |
97 | { |
98 | parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); |
99 | const QCommandLineOption nameServerOption("n" , "The name server to use." , "nameserver" ); |
100 | parser.addOption(commandLineOption: nameServerOption); |
101 | const QCommandLineOption typeOption("t" , "The lookup type." , "type" ); |
102 | parser.addOption(commandLineOption: typeOption); |
103 | parser.addPositionalArgument(name: "name" , description: "The name to look up." ); |
104 | const QCommandLineOption helpOption = parser.addHelpOption(); |
105 | const QCommandLineOption versionOption = parser.addVersionOption(); |
106 | |
107 | if (!parser.parse(arguments: QCoreApplication::arguments())) { |
108 | *errorMessage = parser.errorText(); |
109 | return CommandLineError; |
110 | } |
111 | |
112 | if (parser.isSet(option: versionOption)) |
113 | return CommandLineVersionRequested; |
114 | |
115 | if (parser.isSet(option: helpOption)) |
116 | return CommandLineHelpRequested; |
117 | |
118 | if (parser.isSet(option: nameServerOption)) { |
119 | const QString nameserver = parser.value(option: nameServerOption); |
120 | query->nameServer = QHostAddress(nameserver); |
121 | if (query->nameServer.isNull() || query->nameServer.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { |
122 | *errorMessage = "Bad nameserver address: " + nameserver; |
123 | return CommandLineError; |
124 | } |
125 | } |
126 | |
127 | if (parser.isSet(option: typeOption)) { |
128 | const QString typeParameter = parser.value(option: typeOption); |
129 | const int type = typeFromParameter(type: typeParameter.toLower()); |
130 | if (type < 0) { |
131 | *errorMessage = "Bad record type: " + typeParameter; |
132 | return CommandLineError; |
133 | } |
134 | query->type = static_cast<QDnsLookup::Type>(type); |
135 | } |
136 | |
137 | const QStringList positionalArguments = parser.positionalArguments(); |
138 | if (positionalArguments.isEmpty()) { |
139 | *errorMessage = "Argument 'name' missing." ; |
140 | return CommandLineError; |
141 | } |
142 | if (positionalArguments.size() > 1) { |
143 | *errorMessage = "Several 'name' arguments specified." ; |
144 | return CommandLineError; |
145 | } |
146 | query->name = positionalArguments.first(); |
147 | |
148 | return CommandLineOk; |
149 | } |
150 | |
151 | //! [0] |
152 | |
153 | DnsManager::DnsManager() |
154 | : dns(new QDnsLookup(this)) |
155 | { |
156 | connect(sender: dns, signal: &QDnsLookup::finished, receiver: this, slot: &DnsManager::showResults); |
157 | } |
158 | |
159 | void DnsManager::execute() |
160 | { |
161 | // lookup type |
162 | dns->setType(query.type); |
163 | if (!query.nameServer.isNull()) |
164 | dns->setNameserver(query.nameServer); |
165 | dns->setName(query.name); |
166 | dns->lookup(); |
167 | } |
168 | |
169 | void DnsManager::showResults() |
170 | { |
171 | if (dns->error() != QDnsLookup::NoError) |
172 | printf(format: "Error: %i (%s)\n" , dns->error(), qPrintable(dns->errorString())); |
173 | |
174 | // CNAME records |
175 | const QList<QDnsDomainNameRecord> cnameRecords = dns->canonicalNameRecords(); |
176 | for (const QDnsDomainNameRecord &record : cnameRecords) |
177 | printf(format: "%s\t%i\tIN\tCNAME\t%s\n" , qPrintable(record.name()), record.timeToLive(), qPrintable(record.value())); |
178 | |
179 | // A and AAAA records |
180 | const QList<QDnsHostAddressRecord> aRecords = dns->hostAddressRecords(); |
181 | for (const QDnsHostAddressRecord &record : aRecords) { |
182 | const char *type = (record.value().protocol() == QAbstractSocket::IPv6Protocol) ? "AAAA" : "A" ; |
183 | printf(format: "%s\t%i\tIN\t%s\t%s\n" , qPrintable(record.name()), record.timeToLive(), type, qPrintable(record.value().toString())); |
184 | } |
185 | |
186 | // MX records |
187 | const QList<QDnsMailExchangeRecord> mxRecords = dns->mailExchangeRecords(); |
188 | for (const QDnsMailExchangeRecord &record : mxRecords) |
189 | printf(format: "%s\t%i\tIN\tMX\t%u %s\n" , qPrintable(record.name()), record.timeToLive(), record.preference(), qPrintable(record.exchange())); |
190 | |
191 | // NS records |
192 | const QList<QDnsDomainNameRecord> nsRecords = dns->nameServerRecords(); |
193 | for (const QDnsDomainNameRecord &record : nsRecords) |
194 | printf(format: "%s\t%i\tIN\tNS\t%s\n" , qPrintable(record.name()), record.timeToLive(), qPrintable(record.value())); |
195 | |
196 | // PTR records |
197 | const QList<QDnsDomainNameRecord> ptrRecords = dns->pointerRecords(); |
198 | for (const QDnsDomainNameRecord &record : ptrRecords) |
199 | printf(format: "%s\t%i\tIN\tPTR\t%s\n" , qPrintable(record.name()), record.timeToLive(), qPrintable(record.value())); |
200 | |
201 | // SRV records |
202 | const QList<QDnsServiceRecord> srvRecords = dns->serviceRecords(); |
203 | for (const QDnsServiceRecord &record : srvRecords) |
204 | printf(format: "%s\t%i\tIN\tSRV\t%u %u %u %s\n" , qPrintable(record.name()), record.timeToLive(), record.priority(), record.weight(), record.port(), qPrintable(record.target())); |
205 | |
206 | // TXT records |
207 | const QList<QDnsTextRecord> txtRecords = dns->textRecords(); |
208 | for (const QDnsTextRecord &record : txtRecords) { |
209 | QStringList values; |
210 | const QList<QByteArray> dnsRecords = record.values(); |
211 | for (const QByteArray &ba : dnsRecords) |
212 | values << "\"" + QString::fromLatin1(str: ba) + "\"" ; |
213 | printf(format: "%s\t%i\tIN\tTXT\t%s\n" , qPrintable(record.name()), record.timeToLive(), qPrintable(values.join(' '))); |
214 | } |
215 | |
216 | QCoreApplication::instance()->quit(); |
217 | } |
218 | |
219 | int main(int argc, char *argv[]) |
220 | { |
221 | QCoreApplication app(argc, argv); |
222 | |
223 | //! [1] |
224 | QCoreApplication::setApplicationVersion(QT_VERSION_STR); |
225 | QCoreApplication::setApplicationName(QCoreApplication::translate(context: "QDnsLookupExample" , key: "DNS Lookup Example" )); |
226 | QCommandLineParser parser; |
227 | parser.setApplicationDescription(QCoreApplication::translate(context: "QDnsLookupExample" , key: "An example demonstrating the class QDnsLookup." )); |
228 | DnsQuery query; |
229 | QString errorMessage; |
230 | switch (parseCommandLine(parser, query: &query, errorMessage: &errorMessage)) { |
231 | case CommandLineOk: |
232 | break; |
233 | case CommandLineError: |
234 | fputs(qPrintable(errorMessage), stderr); |
235 | fputs(s: "\n\n" , stderr); |
236 | fputs(qPrintable(parser.helpText()), stderr); |
237 | return 1; |
238 | case CommandLineVersionRequested: |
239 | printf(format: "%s %s\n" , qPrintable(QCoreApplication::applicationName()), |
240 | qPrintable(QCoreApplication::applicationVersion())); |
241 | return 0; |
242 | case CommandLineHelpRequested: |
243 | parser.showHelp(); |
244 | Q_UNREACHABLE(); |
245 | } |
246 | //! [1] |
247 | |
248 | DnsManager manager; |
249 | manager.setQuery(query); |
250 | QTimer::singleShot(msec: 0, receiver: &manager, SLOT(execute())); |
251 | |
252 | return app.exec(); |
253 | } |
254 | |