File indexing completed on 2024-05-19 04:06:38
0001 /* 0002 * Copyright (C) 2005 Justin Karneges 0003 * 0004 * Permission is hereby granted, free of charge, to any person obtaining a 0005 * copy of this software and associated documentation files (the 0006 * "Software"), to deal in the Software without restriction, including 0007 * without limitation the rights to use, copy, modify, merge, publish, 0008 * distribute, sublicense, and/or sell copies of the Software, and to 0009 * permit persons to whom the Software is furnished to do so, subject to 0010 * the following conditions: 0011 * 0012 * The above copyright notice and this permission notice shall be included 0013 * in all copies or substantial portions of the Software. 0014 * 0015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 0016 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0017 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 0018 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 0019 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 0020 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 0021 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0022 */ 0023 0024 #include <QtCore> 0025 #include <QtNetwork> 0026 #include "qjdns.h" 0027 0028 QString dataToString(const QByteArray &buf) 0029 { 0030 QString out; 0031 for(int n = 0; n < buf.size(); ++n) 0032 { 0033 unsigned char c = (unsigned char)buf[n]; 0034 if(c == '\\') 0035 out += "\\\\"; 0036 else if(c >= 0x20 && c < 0x7f) 0037 out += c; 0038 else 0039 out += QString().sprintf("\\x%02x", (unsigned int)c); 0040 } 0041 return out; 0042 } 0043 0044 void print_record(const QJDns::Record &r) 0045 { 0046 switch(r.type) 0047 { 0048 case QJDns::A: 0049 printf(" A: [%s] (ttl=%d)\n", qPrintable(r.address.toString()), r.ttl); 0050 break; 0051 case QJDns::Aaaa: 0052 printf(" AAAA: [%s] (ttl=%d)\n", qPrintable(r.address.toString()), r.ttl); 0053 break; 0054 case QJDns::Mx: 0055 printf(" MX: [%s] priority=%d (ttl=%d)\n", r.name.data(), r.priority, r.ttl); 0056 break; 0057 case QJDns::Srv: 0058 printf(" SRV: [%s] port=%d priority=%d weight=%d (ttl=%d)\n", r.name.data(), r.port, r.priority, r.weight, r.ttl); 0059 break; 0060 case QJDns::Cname: 0061 printf(" CNAME: [%s] (ttl=%d)\n", r.name.data(), r.ttl); 0062 break; 0063 case QJDns::Ptr: 0064 printf(" PTR: [%s] (ttl=%d)\n", r.name.data(), r.ttl); 0065 break; 0066 case QJDns::Txt: 0067 { 0068 printf(" TXT: count=%d (ttl=%d)\n", r.texts.count(), r.ttl); 0069 for(int n = 0; n < r.texts.count(); ++n) 0070 printf(" len=%d [%s]\n", r.texts[n].size(), qPrintable(dataToString(r.texts[n]))); 0071 break; 0072 } 0073 case QJDns::Hinfo: 0074 printf(" HINFO: [%s] [%s] (ttl=%d)\n", r.cpu.data(), r.os.data(), r.ttl); 0075 break; 0076 case QJDns::Ns: 0077 printf(" NS: [%s] (ttl=%d)\n", r.name.data(), r.ttl); 0078 break; 0079 default: 0080 printf(" (Unknown): type=%d, size=%d (ttl=%d)\n", r.type, r.rdata.size(), r.ttl); 0081 break; 0082 } 0083 } 0084 0085 class App : public QObject 0086 { 0087 Q_OBJECT 0088 public: 0089 bool opt_debug, opt_ipv6, opt_quit; 0090 int quit_time; 0091 QString mode, type, name, ipaddr; 0092 QStringList nslist; 0093 QList<QJDns::Record> pubitems; 0094 QJDns jdns; 0095 int req_id; 0096 0097 App() 0098 { 0099 connect(&jdns, SIGNAL(resultsReady(int,QJDns::Response)), SLOT(jdns_resultsReady(int,QJDns::Response))); 0100 connect(&jdns, SIGNAL(published(int)), SLOT(jdns_published(int))); 0101 connect(&jdns, SIGNAL(error(int,QJDns::Error)), SLOT(jdns_error(int,QJDns::Error))); 0102 connect(&jdns, SIGNAL(shutdownFinished()), SLOT(jdns_shutdownFinished())); 0103 connect(&jdns, SIGNAL(debugLinesReady()), SLOT(jdns_debugLinesReady())); 0104 } 0105 0106 ~App() 0107 { 0108 } 0109 0110 public slots: 0111 void start() 0112 { 0113 if(mode == "uni") 0114 { 0115 if(!jdns.init(QJDns::Unicast, opt_ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any)) 0116 { 0117 jdns_debugLinesReady(); 0118 printf("unable to bind\n"); 0119 emit quit(); 0120 return; 0121 } 0122 0123 QList<QJDns::NameServer> addrs; 0124 for(int n = 0; n < nslist.count(); ++n) 0125 { 0126 QJDns::NameServer host; 0127 QString str = nslist[n]; 0128 if(str == "mul") 0129 { 0130 if(opt_ipv6) 0131 host.address = QHostAddress("FF02::FB"); 0132 else 0133 host.address = QHostAddress("224.0.0.251"); 0134 host.port = 5353; 0135 } 0136 else 0137 { 0138 int at = str.indexOf(';'); 0139 if(at != -1) 0140 { 0141 host.address = QHostAddress(str.mid(0, at)); 0142 host.port = str.mid(at + 1).toInt(); 0143 } 0144 else 0145 { 0146 host.address = QHostAddress(str); 0147 } 0148 } 0149 0150 if(host.address.isNull() || host.port <= 0) 0151 { 0152 printf("bad nameserver: [%s]\n", qPrintable(nslist[n])); 0153 emit quit(); 0154 return; 0155 } 0156 addrs += host; 0157 } 0158 0159 if(addrs.isEmpty()) 0160 addrs = QJDns::systemInfo().nameServers; 0161 0162 if(addrs.isEmpty()) 0163 { 0164 printf("no nameservers were detected or specified\n"); 0165 emit quit(); 0166 return; 0167 } 0168 0169 jdns.setNameServers(addrs); 0170 } 0171 else 0172 { 0173 if(!jdns.init(QJDns::Multicast, opt_ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any)) 0174 { 0175 jdns_debugLinesReady(); 0176 printf("unable to bind\n"); 0177 emit quit(); 0178 return; 0179 } 0180 } 0181 0182 if(mode == "uni" || mode == "mul") 0183 { 0184 int x = QJDns::A; 0185 if(type == "ptr") 0186 x = QJDns::Ptr; 0187 else if(type == "srv") 0188 x = QJDns::Srv; 0189 else if(type == "a") 0190 x = QJDns::A; 0191 else if(type == "aaaa") 0192 x = QJDns::Aaaa; 0193 else if(type == "mx") 0194 x = QJDns::Mx; 0195 else if(type == "txt") 0196 x = QJDns::Txt; 0197 else if(type == "hinfo") 0198 x = QJDns::Hinfo; 0199 else if(type == "cname") 0200 x = QJDns::Cname; 0201 else if(type == "any") 0202 x = QJDns::Any; 0203 else 0204 { 0205 bool ok; 0206 int y = type.toInt(&ok); 0207 if(ok) 0208 x = y; 0209 } 0210 0211 req_id = jdns.queryStart(name.toLatin1(), x); 0212 printf("[%d] Querying for [%s] type=%d ...\n", req_id, qPrintable(name), x); 0213 } 0214 else // publish 0215 { 0216 for(int n = 0; n < pubitems.count(); ++n) 0217 { 0218 const QJDns::Record &rr = pubitems[n]; 0219 QJDns::PublishMode m = QJDns::Unique; 0220 if(rr.type == QJDns::Ptr) 0221 m = QJDns::Shared; 0222 int id = jdns.publishStart(m, rr); 0223 printf("[%d] Publishing [%s] type=%d ...\n", id, rr.owner.data(), rr.type); 0224 } 0225 } 0226 0227 if(opt_quit) 0228 QTimer::singleShot(quit_time * 1000, this, SLOT(doShutdown())); 0229 } 0230 0231 signals: 0232 void quit(); 0233 0234 private slots: 0235 void jdns_resultsReady(int id, const QJDns::Response &results) 0236 { 0237 printf("[%d] Results\n", id); 0238 for(int n = 0; n < results.answerRecords.count(); ++n) 0239 print_record(results.answerRecords[n]); 0240 0241 if(mode == "uni") 0242 jdns.shutdown(); 0243 } 0244 0245 void jdns_published(int id) 0246 { 0247 printf("[%d] Published\n", id); 0248 } 0249 0250 void jdns_error(int id, QJDns::Error e) 0251 { 0252 QString str; 0253 if(e == QJDns::ErrorGeneric) 0254 str = "Generic"; 0255 else if(e == QJDns::ErrorNXDomain) 0256 str = "NXDomain"; 0257 else if(e == QJDns::ErrorTimeout) 0258 str = "Timeout"; 0259 else if(e == QJDns::ErrorConflict) 0260 str = "Conflict"; 0261 printf("[%d] Error: %s\n", id, qPrintable(str)); 0262 jdns.shutdown(); 0263 } 0264 0265 void jdns_shutdownFinished() 0266 { 0267 emit quit(); 0268 } 0269 0270 void jdns_debugLinesReady() 0271 { 0272 QStringList lines = jdns.debugLines(); 0273 if(opt_debug) 0274 { 0275 for(int n = 0; n < lines.count(); ++n) 0276 printf("jdns: %s\n", qPrintable(lines[n])); 0277 } 0278 } 0279 0280 void doShutdown() 0281 { 0282 jdns.shutdown(); 0283 } 0284 }; 0285 0286 #include "main.moc" 0287 0288 void usage() 0289 { 0290 printf("usage: jdns (options) uni [type] [name] (nameserver(;port)|mul ...)\n"); 0291 printf(" jdns (options) mul [type] [name]\n"); 0292 printf(" jdns (options) pub [items ...]\n"); 0293 printf(" jdns sys\n"); 0294 printf("\n"); 0295 printf("options:\n"); 0296 printf(" -d show debug output\n"); 0297 printf(" -6 use ipv6\n"); 0298 printf(" -q x quit x seconds after starting\n"); 0299 printf("\n"); 0300 printf("uni/mul types: a aaaa ptr srv mx txt hinfo cname any\n"); 0301 printf("pub items: ptr:name,answer srv:name,answer,port a:name,ipaddr\n"); 0302 printf(" txt:name,str0,...,strn aaaa:name,ipaddr\n"); 0303 printf("\n"); 0304 printf("examples:\n"); 0305 printf(" jdns uni a jabber.org 192.168.0.1\n"); 0306 printf(" jdns uni srv _xmpp-client._tcp.jabber.org 192.168.0.1;53\n"); 0307 printf(" jdns uni 10 user@host._presence._tcp.local mul\n"); 0308 printf(" jdns mul a foobar.local\n"); 0309 printf(" jdns mul ptr _services._dns-sd._udp.local\n"); 0310 printf(" jdns pub a:mybox.local.,192.168.0.55\n"); 0311 printf("\n"); 0312 } 0313 0314 int main(int argc, char **argv) 0315 { 0316 QCoreApplication app(argc, argv); 0317 0318 if(argc < 2) 0319 { 0320 usage(); 0321 return 1; 0322 } 0323 0324 // get args 0325 QStringList args; 0326 for(int n = 1; n < argc; ++n) 0327 args += QString(argv[n]); 0328 0329 bool opt_debug = false; 0330 bool opt_ipv6 = false; 0331 bool opt_quit = false; 0332 int quit_time = 0; 0333 QString mode, type, name, ipaddr; 0334 QStringList nslist; 0335 QList<QJDns::Record> pubitems; 0336 0337 // options 0338 for(int n = 0; n < args.count(); ++n) 0339 { 0340 if(args[n].left(1) == "-") 0341 { 0342 if(args[n] == "-d") 0343 opt_debug = true; 0344 else if(args[n] == "-6") 0345 opt_ipv6 = true; 0346 else if(args[n] == "-q") 0347 { 0348 if(n + 1 >= args.count()) 0349 { 0350 printf("need to specify number of seconds\n"); 0351 usage(); 0352 return 1; 0353 } 0354 0355 int x = args[n + 1].toInt(); 0356 if(x < 1) 0357 x = 30; 0358 0359 opt_quit = true; 0360 quit_time = x; 0361 0362 args.removeAt(n + 1); 0363 } 0364 else 0365 { 0366 printf("bad option\n"); 0367 usage(); 0368 return 1; 0369 } 0370 args.removeAt(n); 0371 --n; // adjust position 0372 } 0373 } 0374 0375 mode = args[0]; 0376 if(mode == "uni" || mode == "mul") 0377 { 0378 if(args.count() < 3) 0379 { 0380 printf("not enough args\n"); 0381 usage(); 0382 return 1; 0383 } 0384 type = args[1]; 0385 name = args[2]; 0386 if(mode == "uni") 0387 { 0388 for(int n = 3; n < args.count(); ++n) 0389 nslist += QString(args[n]); 0390 } 0391 } 0392 else if(mode == "pub") 0393 { 0394 if(args.count() < 2) 0395 { 0396 printf("not enough args\n"); 0397 usage(); 0398 return 1; 0399 } 0400 for(int n = 1; n < args.count(); ++n) 0401 { 0402 QString arg = args[n]; 0403 int at = arg.indexOf(':'); 0404 if(at == -1) 0405 { 0406 printf("missing colon\n"); 0407 usage(); 0408 return 1; 0409 } 0410 QString type = arg.mid(0, at).toLower(); 0411 QString val = arg.mid(at + 1); 0412 if(type == "a") 0413 { 0414 QStringList list = val.split(','); 0415 if(list.count() != 2) 0416 { 0417 printf("bad format for A type\n"); 0418 usage(); 0419 return 1; 0420 } 0421 QHostAddress host(list[1]); 0422 if(host.isNull() || host.protocol() != QAbstractSocket::IPv4Protocol) 0423 { 0424 printf("bad format for A type IP address\n"); 0425 usage(); 0426 return 1; 0427 } 0428 0429 QJDns::Record rec; 0430 rec.owner = list[0].toLatin1(); 0431 rec.type = QJDns::A; 0432 rec.ttl = 120; 0433 rec.haveKnown = true; 0434 rec.address = host; 0435 pubitems += rec; 0436 } 0437 else if(type == "aaaa") 0438 { 0439 QStringList list = val.split(','); 0440 if(list.count() != 2) 0441 { 0442 printf("bad format for AAAA type\n"); 0443 usage(); 0444 return 1; 0445 } 0446 QHostAddress host(list[1]); 0447 if(host.isNull() || host.protocol() != QAbstractSocket::IPv6Protocol) 0448 { 0449 printf("bad format for AAAA type IP address\n"); 0450 usage(); 0451 return 1; 0452 } 0453 0454 QJDns::Record rec; 0455 rec.owner = list[0].toLatin1(); 0456 rec.type = QJDns::Aaaa; 0457 rec.ttl = 120; 0458 rec.haveKnown = true; 0459 rec.address = host; 0460 pubitems += rec; 0461 } 0462 else if(type == "srv") 0463 { 0464 QStringList list = val.split(','); 0465 if(list.count() != 3) 0466 { 0467 printf("bad format for SRV type\n"); 0468 usage(); 0469 return 1; 0470 } 0471 0472 QJDns::Record rec; 0473 rec.owner = list[0].toLatin1(); 0474 rec.type = QJDns::Srv; 0475 rec.ttl = 120; 0476 rec.haveKnown = true; 0477 rec.name = list[1].toLatin1(); 0478 rec.priority = 0; 0479 rec.weight = 0; 0480 rec.port = list[2].toInt(); 0481 pubitems += rec; 0482 } 0483 else if(type == "ptr") 0484 { 0485 QStringList list = val.split(','); 0486 if(list.count() != 2) 0487 { 0488 printf("bad format for PTR type\n"); 0489 usage(); 0490 return 1; 0491 } 0492 0493 QJDns::Record rec; 0494 rec.owner = list[0].toLatin1(); 0495 rec.type = QJDns::Ptr; 0496 rec.ttl = 120; 0497 rec.haveKnown = true; 0498 rec.name = list[1].toLatin1(); 0499 pubitems += rec; 0500 } 0501 else if(type == "txt") 0502 { 0503 QStringList list = val.split(','); 0504 QList<QByteArray> texts; 0505 for(int n = 1; n < list.count(); ++n) 0506 texts += list[n].toLatin1(); 0507 0508 QJDns::Record rec; 0509 rec.owner = list[0].toLatin1(); 0510 rec.type = QJDns::Txt; 0511 rec.ttl = 120; 0512 rec.haveKnown = true; 0513 rec.texts = texts; 0514 pubitems += rec; 0515 } 0516 else 0517 { 0518 printf("bad record type [%s]\n", qPrintable(type)); 0519 usage(); 0520 return 1; 0521 } 0522 } 0523 } 0524 else if(mode == "sys") 0525 { 0526 QJDns::SystemInfo info = QJDns::systemInfo(); 0527 0528 printf("DNS System Information\n"); 0529 printf(" Name Servers:\n"); 0530 if(!info.nameServers.isEmpty()) 0531 { 0532 for(int n = 0; n < info.nameServers.count(); ++n) 0533 printf(" %s\n", qPrintable(info.nameServers[n].address.toString())); 0534 } 0535 else 0536 printf(" (None)\n"); 0537 0538 printf(" Domains:\n"); 0539 if(!info.domains.isEmpty()) 0540 { 0541 for(int n = 0; n < info.domains.count(); ++n) 0542 printf(" [%s]\n", info.domains[n].data()); 0543 } 0544 else 0545 printf(" (None)\n"); 0546 0547 printf(" Hosts:\n"); 0548 if(!info.hosts.isEmpty()) 0549 { 0550 for(int n = 0; n < info.hosts.count(); ++n) 0551 { 0552 const QJDns::DnsHost &h = info.hosts[n]; 0553 printf(" [%s] -> %s\n", h.name.data(), qPrintable(h.address.toString())); 0554 } 0555 } 0556 else 0557 printf(" (None)\n"); 0558 0559 QHostAddress addr; 0560 printf("Primary IPv4 Multicast Address: "); 0561 addr = QJDns::detectPrimaryMulticast(QHostAddress::Any); 0562 if(!addr.isNull()) 0563 printf("%s\n", qPrintable(addr.toString())); 0564 else 0565 printf("(None)\n"); 0566 printf("Primary IPv6 Multicast Address: "); 0567 addr = QJDns::detectPrimaryMulticast(QHostAddress::AnyIPv6); 0568 if(!addr.isNull()) 0569 printf("%s\n", qPrintable(addr.toString())); 0570 else 0571 printf("(None)\n"); 0572 0573 return 0; 0574 } 0575 else 0576 { 0577 usage(); 0578 return 1; 0579 } 0580 0581 App a; 0582 a.opt_debug = opt_debug; 0583 a.opt_ipv6 = opt_ipv6; 0584 a.opt_quit = opt_quit; 0585 a.quit_time = quit_time; 0586 a.mode = mode; 0587 a.type = type.toLower(); 0588 a.name = name; 0589 a.ipaddr = ipaddr; 0590 a.nslist = nslist; 0591 a.pubitems = pubitems; 0592 QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit())); 0593 QTimer::singleShot(0, &a, SLOT(start())); 0594 app.exec(); 0595 return 0; 0596 }