/*************************************************************************** posask.cpp - posask query tool ------------------- begin : vr mei 23 2003 copyright : (C) 2003 by Meilof email : meilof@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* * This file has been taken, with some modifications, from the Poslib sources. * The Poslib version, in turn, was just an ugly hack of the Posadis 0.50.x * Posask. As such, you'll find some old Posadis artifacts. The code does * "just work"(r) though. */ #include #include #ifdef HAVE_RESOLV_H #ifdef HAVE_NAMESER_H #include #endif #include #include #include #include #include #endif #include #include #include /*_addr server;*/ stl_slist(_addr) servers; domainname dname = "."; int dname_given = 0; int qtype = 0; int serial = 0; int rd = 1; int use_tcp = -1; /* default */ int timeout = 5; int tries = 3; int cmd_server(char *line); int cmd_dname(char *line); int cmd_qtype(char *line); int cmd_serial(char *line); int cmd_rd(char *line); int cmd_tcp(char *line); int cmd_timeout(char *line); int cmd_tries(char *line); int cmd_query(char *line); int cmd_set(char *line); int cmd_help(char *line); int cmd_exit(char *line); typedef int(*commandfn)(char *); typedef char*(*completefn)(const char *, int); typedef struct { char *command; char *help; commandfn fn; } _command; _command commands[] = { { "server", "Sets the server at run-time", cmd_server }, { "dname", "Sets domain name to query", cmd_dname }, { "qtype", "Sets the default QTYPE", cmd_qtype }, { "serial", "Sets the previous serial for IXFR requests", cmd_serial }, { "rd", "Sets whether we demand recursion", cmd_rd }, { "use_tcp", "Sets whether we use TCP/IP (default only xfr)", cmd_tcp }, { "timeout", "Sets the time in seconds to wait for an answer", cmd_timeout }, { "tries", "Sets the number of tries for the query", cmd_tries }, { "query", "Sends a query to the nameserver", cmd_query }, { "q", "Synonym for 'query'", cmd_query }, { "set", "Show current settings", cmd_set }, { "help", "Print this message", cmd_help }, { "exit", "Quits the program", cmd_exit }, }; int n_commands = sizeof(commands) / sizeof(_command); char* settings[] = { "server", "dname", "qtype", "rd", "use_tcp", "timeout" }; int n_settings = sizeof(settings) / sizeof(char *); int issue_command(char *name, char *arg) { int t; for (t = 0; t < n_commands; t++) { if (strcasecmp(name, commands[t].command) == 0) { return commands[t].fn(arg); } } printf("*** Command unknown: %s\n", name); return -1; } int cmd_server(char *line) { _addr server; try { txt_to_addr(&server, line); servers.push_front(server); return 1; } catch (PException p) { if (!address_lookup(&server, line, DNS_PORT)) { printf("*** Server %s: incorrect identifier: %s\n", line, p.message); return -1; } servers.push_front(server); } return 1; } int cmd_dname(char *line) { dname_given = 1; try { dname = line; return 1; } catch (PException p) { printf("*** Incorrect dname %s: %s!\n", line, p.message); return -1; } } int cmd_qtype(char *line) { int ret; try { if (strncasecmp(line, "ixfr", 4) == 0) { if (line[4] == '/') { ret = cmd_serial(&line[5]); if (ret > 0) qtype = QTYPE_IXFR; return ret; } else { qtype = QTYPE_IXFR; return 1; } } else { qtype = qtype_getcode(line); } return 1; } catch (PException p) { printf("*** Error in qtype %s: %s\n", line, p.message); return -1; } } int cmd_serial(char *line) { try { serial = txt_to_int(line); return 1; } catch (PException p) { printf("*** Error in serial %s: %s\n", line, p.message); return -1; } } int cmd_rd(char *line) { try { rd = (txt_to_bool(line)) ? 1 : 0; return 1; } catch (PException p) { printf("*** Error in RD value %s: %s\n", line, p.message); return -1; } } int cmd_tcp(char *line) { try { use_tcp = (txt_to_bool(line)) ? 1 : 0; return 1; } catch (PException p) { printf("*** Error in use_tcp value %s: %s\n", line, p.message); return -1; } } int cmd_timeout(char *line) { try { timeout = txt_to_int(line); if (timeout < 0) { timeout = 5; throw PException(true, "%s: cannot be negative!", line); } } catch (PException p) { printf("**** Error in timeout: %s\n", p.message); return -1; } return 1; } int cmd_tries(char *line) { try { tries = txt_to_int(line); if (tries < 0) { tries = 3; throw PException(true, "#tries %s: cannot be negative!", line); } } catch (PException p) { printf("**** Error in #tries: %s\n", p.message); return -1; } return 1; } int cmd_query(char *line) { DnsMessage *q = NULL, *a = NULL; int prevtype = qtype; char *tmp; char *ptr; postime_t endtime, begintime; bool do_tcp; pos_cliresolver resolver; try { if (line[0]) { ptr = &line[strlen(line) - 1]; while (ptr > line && *ptr != ' ') ptr--; if (*ptr == ' ') { *ptr = '\0'; if (cmd_qtype(ptr + 1) < 0) return -1; } if (cmd_dname(line) < 0) { qtype = prevtype; return -1; } } begintime = getcurtime(); q = new DnsMessage(); q->questions.push_front(DnsQuestion(dname, qtype, CLASS_IN)); qtype = prevtype; q->ID = 3000; if (qtype == QTYPE_IXFR) { /* add a SOA record */ tmp = (char *)malloc(22); memset(tmp, 0, 22); memcpy(tmp + 2, uint32_buff(serial), 4); q->authority.push_front(DnsRR(dname, DNS_TYPE_SOA, CLASS_IN, 0)); q->authority.begin()->RDLENGTH = 22; q->authority.begin()->RDATA = tmp; } if (rd) q->RD = true; if (qtype == QTYPE_AXFR) q->RD = false; if (use_tcp == 1 || (use_tcp == -1 && (qtype == QTYPE_AXFR || qtype == QTYPE_IXFR))) { /* do a tcp query */ do_tcp = true; int sockid = resolver.tcpconnect(&*servers.begin()); resolver.tcp_timeout = timeout * 1000; resolver.tcpquery(q, a, sockid); resolver.tcpdisconnect(sockid); } else { /* do an udp query */ free(resolver.udp_tries); if (tries < 1) tries = 1; if (tries > 10) tries = 10; if (timeout < 1) timeout = 1; resolver.udp_tries = (int *)malloc(tries * sizeof(int)); resolver.n_udp_tries = tries; for (int tr = 0; tr < tries; tr++) { resolver.udp_tries[tr] = timeout * 1000 * (tr + 1) * 2 / tries / (tries + 1); } do_tcp = false; servers.reverse(); resolver.query(q, a, servers, Q_NOTCP); } endtime = getcurtime(); stl_list(stl_string) answer = answer_to_advanced_string(a, addrs_to_string(servers).c_str(), do_tcp, endtime.after(begintime), true); stl_list(stl_string)::iterator it = answer.begin(); while (it != answer.end()) { printf("%s\n", it->c_str()); it++; } if (q) delete q; if (a) delete a; } catch (PException p) { printf("*** Query failed: %s!\n", p.message); if (q) delete q; if (a) delete a; } return 1; } int cmd_set(char *line) { if (!line[0] || strcasecmp(line, "server") == 0) { printf("Server: %s\n", addrs_to_string(servers).c_str()); } if (!line[0] || strcasecmp(line, "dname") == 0) { printf("Domain name: %s\n", dname.tostring().c_str()); } if (!line[0] || strcasecmp(line, "qtype") == 0) printf("QTYPE: %s\n", str_qtype(qtype).c_str()); if (!line[0] || strcasecmp(line, "serial") == 0) printf("IXFR serial: %d\n", serial); if (!line[0] || strcasecmp(line, "rd") == 0) printf("Recursion: %s\n", (rd == 1) ? "true" : "false"); if (!line[0] || strcasecmp(line, "use_tcp") == 0) printf("Use TCP: %s\n", (use_tcp == 1) ? "true" : "false"); if (!line[0] || strcasecmp(line, "timeout") == 0) printf("Timeout: %d\n", timeout); if (!line[0] || strcasecmp(line, "tries") == 0) printf("Tries: %d\n", tries); return 1; } int cmd_help(char *line) { int x, p = 0; for (x = 0; x < n_commands; x++) { if (!line[0] || strcasecmp(line, commands[x].command) == 0) { printf("%-16s %s\n", commands[x].command, commands[x].help); p = 1; } } if (p == 0) { printf("*** %s is not a known command!\n", line); return -1; } return 1; } int cmd_exit(char *line) { return 0; } int main(int argc, char **argv) { int x, ret = 0; char *ptr; /* at first, read the command line */ for (x = 1; x < argc; x++) { if (strcasecmp(argv[x], "--help") == 0 || strcasecmp(argv[x], "-h") == 0) { printf( "Posask - Command-line DNS querier\n" "Usage:\n" " posask [--help|-h]\n" " posask [--version|-v]\n" " posask [@[server][:port]] [option=value] [qname] [qtype]\n" "If no server is given, the system resolver is assumed. If no qtype is given, A\n" "is assumed. If no qname is given, a query for {. ns} is assumed.\n" "\n" "Possible options:\n" " rd=[yes|no] Specifies whether to demand recursion. Default: yes\n" " serial=n Default serial number for IXFR requests\n" " use_tcp=[yes|no] Specifies whether or not to use TCP. Default: only xfr\n" " timeout=n Number of seconds to wait for an answer. Default: 5\n" " tries=n Number of times to retry query (in timeout). Default: 3\n" "\n" "Posask is part of the Posadis DNS Server package. It is distributed under the\n" "terms and conditions of the GNU General Public License. More info:\n" " http://posadis.sourceforge.net/\n"); return 1; } if (strcasecmp(argv[x], "--version") == 0 || strcasecmp(argv[x], "-v") == 0) { printf( "Posask - Command-line DNS querier\n" "Version ID: $Revision: 1.14 $\n" #ifdef __DATE "Compiled on: " __DATE__ #endif /*"Posadis version: " VERSION "\n"*/); return 1; } // if (stricmp(argv[x], "--resolve") == 0 || stricmp(argv[x], "-r") == 0) { //#ifdef HAVE_RESOLV_H // res_init(); // memcpy(&server, &_res.nsaddr, sizeof(sockaddr_in)); // continue; //#else // printf("*** Posadis not built with system resolver support!\n"); // return 1; //#endif // } if (argv[x][0] == '-') { printf("*** Command-line option not supported: %s\n", argv[x]); return 1; } if (argv[x][0] == '@') { /* server */ if (cmd_server(&argv[x][1]) < 0) return 2; continue; } ptr = strchr(argv[x], '='); if (ptr) { *ptr = '\0'; ret = issue_command(argv[x], ptr + 1); *ptr = '='; if (ret < 0) return 2; } else { if (dname_given != 0) { /* qtype */ if (qtype) { printf("*** Didn't expect another command-line argument: %s\n", argv[x]); return 2; } else { if (cmd_qtype(argv[x]) < 0) return 2; } } else { /* dname */ if (cmd_dname(argv[x]) < 0) return 2; } } } /* set default */ if (servers.size() == 0) { try { servers = get_os_dns_servers(); } catch(PException p) { _addr tmp; txt_to_addr(&tmp, "127.0.0.1", DNS_PORT); servers.clear(); servers.push_front(tmp); printf("*** Error: %s. Falling back to 127.0.0.1.\n", p.message); } } else servers.reverse(); if (!dname_given) { cmd_dname("."); qtype = DNS_TYPE_NS; } if (qtype == 0) { if (dname >= "in-addr.arpa" || dname >= "ip6.int" || dname >= "ip6.arpa") { qtype = DNS_TYPE_PTR; } else { qtype = DNS_TYPE_A; } } cmd_query(""); if (ret < 0) return 3; else return 0; }