From: Remi Gacogne Date: Tue, 9 Aug 2016 14:07:26 +0000 (+0200) Subject: dnsdist: Add `help()` and `showVersion()` X-Git-Tag: rec-4.0.2~43^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ca4252e0d56677f0de831ed037579168a87fb96a;p=pdns dnsdist: Add `help()` and `showVersion()` --- diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index 88d74d060..bd91fa390 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -1170,7 +1170,7 @@ Here are all functions: * `carbonServer(serverIP, [ourname], [interval])`: report statistics to serverIP using our hostname, or 'ourname' if provided, every 'interval' seconds * Control socket related: * `makeKey()`: generate a new server access key, emit configuration line ready for pasting - * `setKey(key)`: set access key to that key. + * `setKey(key)`: set access key to that key. * `testCrypto()`: test of the crypto all works * `controlSocket(addr)`: open a control socket on this address / connect to this address in client mode * Diagnostics and statistics @@ -1179,10 +1179,11 @@ Here are all functions: * `grepq({"::1", "powerdns.com", "100ms"} [, n])`: shows the last n queries and responses matching the specified client address AND range (Netmask) AND the specified DNS Name AND slower than 100ms * `topQueries(n[, labels])`: show top 'n' queries, as grouped when optionally cut down to 'labels' labels * `topResponses(n, kind[, labels])`: show top 'n' responses with RCODE=kind (0=NO Error, 2=ServFail, 3=ServFail), as grouped when optionally cut down to 'labels' labels - * `topSlow([top][, limit][, labels])`: show `top` queries slower than `limit` milliseconds, grouped by last `labels` labels + * `topSlow([top][, limit][, labels])`: show `top` queries slower than `limit` milliseconds, grouped by last `labels` labels * `topBandwidth(top)`: show top-`top` clients that consume the most bandwidth over length of ringbuffer * `topClients(n)`: show top-`n` clients sending the most queries over length of ringbuffer * `showResponseLatency()`: show a plot of the response time latency distribution + * `showVersion()`: show the current version of dnsdist * Logging related * `infolog(string)`: log at level info * `warnlog(string)`: log at level warning @@ -1245,7 +1246,8 @@ instantiate a server with additional parameters * `rmResponseRule(n)`: remove response rule n * `rmRule(n)`: remove rule n * `setRules(list)`: replace the current rules with the supplied list of pairs of DNS Rules and DNS Actions (see `newRuleAction()`) - * `showRules()`: show all defined rules (Pool, Block, QPS, addAnyTCRule) + * `showResponseRules()`: show all defined response rules + * `showRules()`: show all defined rules * `topResponseRule()`: move the last response rule to the first position * `topRule()`: move the last rule to the first position * Built-in Actions for Rules: @@ -1272,7 +1274,7 @@ instantiate a server with additional parameters * `addDomainCNAMESpoof(domain, cname)`: generate CNAME answers for queries using the specified value * `addDisableValidationRule(domain)`: set the CD flags to 1 for all queries matching the specified domain * `addNoRecurseRule(domain)`: clear the RD flag for all queries matching the specified domain - * `setDNSSECPool()`: move queries requesting DNSSEC processing to this pool + * `setDNSSECPool(pool)`: move queries requesting DNSSEC processing to this pool * Policy member data: * `name`: the policy name * `policy`: the policy function diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 1b37daac1..4a7f05412 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -219,56 +219,143 @@ void doConsole() } } /**** CARGO CULT CODE AHEAD ****/ +const std::vector g_consoleKeywords{ + /* keyword, function, parameters, description */ + { "addACL", true, "netmask", "add to the ACL set who can use this server" }, + { "addAction", true, "DNS rule, DNS action", "add a rule" }, + { "addAnyTCRule", true, "", "generate TC=1 answers to ANY queries received over UDP, moving them to TCP" }, + { "addDelay", true, "domain, n", "delay answers within that domain by n milliseconds" }, + { "addDisableValidationRule", true, "DNS rule", "set the CD flags to 1 for all queries matching the specified domain" }, + { "addDNSCryptBind", true, "\"127.0.0.1:8443\", \"provider name\", \"/path/to/resolver.cert\", \"/path/to/resolver.key\", [false], [TCP Fast Open queue size]", "listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of `provider name`, using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The fifth optional parameter sets SO_REUSEPORT when available. The last parameter sets the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0" }, + { "addDomainBlock", true, "domain", "block queries within this domain" }, + { "addDomainSpoof", true, "domain, ip[, ip6]", "generate answers for A/AAAA/ANY queries using the ip parameters" }, + { "addDynBlocks", true, "addresses, message[, seconds]", "block the set of addresses with message `msg`, for `seconds` seconds (10 by default)" }, + { "addLocal", true, "netmask, [true], [false], [TCP Fast Open queue size]", "add to addresses we listen on. Second optional parameter sets TCP or not. Third optional parameter sets SO_REUSEPORT when available. Last parameter sets the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0" }, + { "addLuaAction", true, "x, func", "where 'x' is all the combinations from `addPoolRule`, and func is a function with the parameter `dq`, which returns an action to be taken on this packet. Good for rare packets but where you want to do a lot of processing" }, + { "addNoRecurseRule", true, "domain", "clear the RD flag for all queries matching the specified domain" }, + { "addPoolRule", true, "domain, pool", "send queries to this domain to that pool" }, + { "addQPSLimit", true, "domain, n", "limit queries within that domain to n per second" }, + { "addQPSPoolRule", true, "x, limit, pool", "like `addPoolRule`, but only select at most 'limit' queries/s for this pool, letting the subsequent rules apply otherwise" }, + { "addResponseAction", true, "DNS rule, DNS response action", "add a response rule" }, + { "AllowAction", true, "", "let these packets go through" }, + { "AllRule", true, "", "matches all traffic" }, + { "AndRule", true, "list of DNS rules", "matches if all sub-rules matches" }, + { "benchRule", true, "DNS Rule [, iterations [, suffix]]", "bench the specified DNS rule" }, + { "carbonServer", true, "serverIP, [ourname], [interval]", "report statistics to serverIP using our hostname, or 'ourname' if provided, every 'interval' seconds" }, + { "controlSocket", true, "addr", "open a control socket on this address / connect to this address in client mode" }, + { "clearDynBlocks", true, "", "clear all dynamic blocks" }, + { "clearRules", true, "", "remove all current rules" }, + { "DelayAction", true, "milliseconds", "delay the response by the specified amount of milliseconds (UDP-only)" }, + { "delta", true, "", "shows all commands entered that changed the configuration" }, + { "DisableValidationAction", true, "", "set the CD bit in the question, let it go through" }, + { "DropAction", true, "", "drop these packets" }, + { "dumpStats", true, "", "print all statistics we gather" }, + { "exceedNXDOMAINs", true, "rate, seconds", "get set of addresses that exceed `rate` NXDOMAIN/s over `seconds` seconds" }, + { "exceedQRate", true, "rate, seconds", "get set of address that exceed `rate` queries/s over `seconds` seconds" }, + { "exceedQTypeRate", true, "type, rate, seconds", "get set of address that exceed `rate` queries/s for queries of type `type` over `seconds` seconds" }, + { "exceedRespByterate", true, "rate, seconds", "get set of addresses that exeeded `rate` bytes/s answers over `seconds` seconds" }, + { "exceedServFails", true, "rate, seconds", "get set of addresses that exceed `rate` servails/s over `seconds` seconds" }, + { "firstAvailable", false, "", "picks the server with the lowest `order` that has not exceeded its QPS limit" }, + { "fixupCase", true, "bool", "if set (default to no), rewrite the first qname of the question part of the answer to match the one from the query. It is only useful when you have a downstream server that messes up the case of the question qname in the answer" }, + { "generateDNSCryptCertificate", true, "\"/path/to/providerPrivate.key\", \"/path/to/resolver.cert\", \"/path/to/resolver.key\", serial, validFrom, validUntil", "generate a new resolver private key and related certificate, valid from the `validFrom` timestamp until the `validUntil` one, signed with the provider private key" }, + { "generateDNSCryptProviderKeys", true, "\"/path/to/providerPublic.key\", \"/path/to/providerPrivate.key\"", "generate a new provider keypair"}, + { "getPoolServers", true, "pool", "return servers part of this pool" }, + { "getResponseRing", true, "", "return the current content of the response ring" }, + { "getServer", true, "n", "returns server with index n" }, + { "getServers", true, "", "returns a table with all defined servers" }, + { "grepq", true, "Netmask|DNS Name|100ms|{\"::1\", \"powerdns.com\", \"100ms\"} [, n]", "shows the last n queries and responses matching the specified client address or range (Netmask), or the specified DNS Name, or slower than 100ms" }, + { "leastOutstanding", false, "", "Send traffic to downstream server with least outstanding queries, with the lowest 'order', and within that the lowest recent latency"}, + { "LogAction", true, "[filename], [binary]", "Log a line for each query, to the specified file if any, to the console (require verbose) otherwise. When logging to a file, the `binary` optional parameter specifies whether we log in binary form (default) or in textual form" }, + { "makeKey", true, "", "generate a new server access key, emit configuration line ready for pasting" }, + { "MaxQPSIPRule", true, "qps, v4Mask=32, v6Mask=64", "matches traffic exceeding the qps limit per subnet" }, + { "MaxQPSRule", true, "qps", "matches traffic **not** exceeding this qps limit" }, + { "mvResponseRule", true, "from, to", "move response rule 'from' to a position where it is in front of 'to'. 'to' can be one larger than the largest rule" }, + { "mvRule", true, "from, to", "move rule 'from' to a position where it is in front of 'to'. 'to' can be one larger than the largest rule, in which case the rule will be moved to the last position" }, + { "newDNSName", true, "name", "make a DNSName based on this .-terminated name" }, + { "newQPSLimiter", true, "rate, burst", "configure a QPS limiter with that rate and that burst capacity" }, + { "newRemoteLogger", true, "address:port [, timeout=2, maxQueuedEntries=100, reconnectWaitTime=1]", "create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()`" }, + { "newRuleAction", true, "DNS rule, DNS action", "return a pair of DNS Rule and DNS Action, to be used with `setRules()`" }, + { "newServer", true, "{address=\"ip:port\", qps=1000, order=1, weight=10, pool=\"abuse\", retries=5, tcpSendTimeout=30, tcpRecvTimeout=30, checkName=\"a.root-servers.net.\", checkType=\"A\", maxCheckFailures=1, mustResolve=false, useClientSubnet=true, source=\"address|interface name|address@interface\"", "instantiate a server" }, + { "newServerPolicy", true, "name, function", "create a policy object from a Lua function" }, + { "newSuffixMatchNode", true, "", "returns a new SuffixMatchNode" }, + { "NoRecurseAction", true, "", "strip RD bit from the question, let it go through" }, + { "PoolAction", true, "poolname", "set the packet into the specified pool" }, + { "printDNSCryptProviderFingerprint", true, "\"/path/to/providerPublic.key\"", "display the fingerprint of the provided resolver public key" }, + { "RegexRule", true, "regex", "matches the query name against the supplied regex" }, + { "RemoteLogAction", true, "RemoteLogger", "send the content of this query to a remote logger via Protocol Buffer" }, + { "RemoteLogResponseAction", true, "RemoteLogger", "send the content of this response to a remote logger via Protocol Buffer" }, + { "rmResponseRule", true, "n", "remove response rule n" }, + { "rmRule", true, "n", "remove rule n" }, + { "rmServer", true, "n", "remove server with index n" }, + { "roundrobin", false, "", "Simple round robin over available servers" }, + { "QNameLabelsCountRule", true, "min, max", "matches if the qname has less than `min` or more than `max` labels" }, + { "QNameWireLengthRule", true, "min, max", "matches if the qname's length on the wire is less than `min` or more than `max` bytes" }, + { "QTypeRule", true, "qtype", "matches queries with the specified qtype" }, + { "setACL", true, "{netmask, netmask}", "replace the ACL set with these netmasks. Use `setACL({})` to reset the list, meaning no one can use us" }, + { "setDNSSECPool", true, "pool name", "move queries requesting DNSSEC processing to this pool" }, + { "setECSOverride", true, "bool", "whether to override an existing EDNS Client Subnet value in the query" }, + { "setECSSourcePrefixV4", true, "prefix-length", "the EDNS Client Subnet prefix-length used for IPv4 queries" }, + { "setECSSourcePrefixV6", true, "prefix-length", "the EDNS Client Subnet prefix-length used for IPv6 queries" }, + { "setKey", true, "key", "set access key to that key" }, + { "setLocal", true, "netmask, [true], [false], [TCP Fast Open queue size]", "reset list of addresses we listen on to this address. Second optional parameter sets TCP or not. Third optional parameter sets SO_REUSEPORT when available. Last parameter sets the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0." }, + { "setMaxTCPClientThreads", true, "n", "set the maximum of TCP client threads, handling TCP connections" }, + { "setMaxTCPQueuedConnections", true, "n", "set the maximum number of TCP connections queued (waiting to be picked up by a client thread)" }, + { "setMaxUDPOutstanding", true, "n", "set the maximum number of outstanding UDP queries to a given backend server. This can only be set at configuration time and defaults to 10240" }, + { "setRules", true, "list of rules", "replace the current rules with the supplied list of pairs of DNS Rules and DNS Actions (see `newRuleAction()`)" }, + { "setServerPolicy", true, "policy", "set server selection policy to that policy" }, + { "setServerPolicyLua", true, "name, function", "set server selection policy to one named 'name' and provided by 'function'" }, + { "setTCPRecvTimeout", true, "n", "set the read timeout on TCP connections from the client, in seconds" }, + { "setTCPSendTimeout", true, "n", "set the write timeout on TCP connections from the client, in seconds" }, + { "setVerboseHealthChecks", true, "bool", "set whether health check errors will be logged" }, + { "show", true, "string", "outputs `string`" }, + { "showACL", true, "", "show our ACL set" }, + { "showDNSCryptBinds", true, "", "display the currently configured DNSCrypt binds" }, + { "showDynBlocks", true, "", "show dynamic blocks in force" }, + { "showResponseLatency", true, "", "show a plot of the response time latency distribution" }, + { "showResponseRules", true, "", "show all defined response rules" }, + { "showRules", true, "", "show all defined rules" }, + { "showServerPolicy", true, "", "show name of currently operational server selection policy" }, + { "showServers", true, "", "output all servers" }, + { "showVersion", true, "", "show the current version" }, + { "shutdown", true, "", "shut down `dnsdist`" }, + { "SpoofAction", true, "{ip, ...} ", "forge a response with the specified IPv4 (for an A query) or IPv6 (for an AAAA). If you specify multiple addresses, all that match the query type (A, AAAA or ANY) will get spoofed in" }, + { "TCAction", true, "", "create answer to query with TC and RD bits set, to move to TCP" }, + { "testCrypto", true, "", "test of the crypto all works" }, + { "topBandwidth", true, "top", "show top-`top` clients that consume the most bandwidth over length of ringbuffer" }, + { "topClients", true, "n", "show top-`n` clients sending the most queries over length of ringbuffer" }, + { "topQueries", true, "n[, labels]", "show top 'n' queries, as grouped when optionally cut down to 'labels' labels" }, + { "topResponses", true, "n, kind[, labels]", "show top 'n' responses with RCODE=kind (0=NO Error, 2=ServFail, 3=ServFail), as grouped when optionally cut down to 'labels' labels" }, + { "topResponseRule", true, "", "move the last response rule to the first position" }, + { "topRule", true, "", "move the last rule to the first position" }, + { "topSlow", true, "[top][, limit][, labels]", "show `top` queries slower than `limit` milliseconds, grouped by last `labels` labels" }, + { "truncateTC", true, "bool", "if set (default) truncate TC=1 answers so they are actually empty. Fixes an issue for PowerDNS Authoritative Server 2.9.22" }, + { "webserver", true, "address:port, password [, apiKey [, customHeaders ]])", "launch a webserver with stats on that address with that password" }, + { "whashed", false, "", "Weighted hashed ('sticky') distribution over available servers, based on the server 'weight' parameter" }, + { "wrandom", false, "", "Weighted random over available servers, based on the server 'weight' parameter" }, +}; + extern "C" { char* my_generator(const char* text, int state) { string t(text); /* to keep it readable, we try to keep only 4 keywords per line and to start a new line when the first letter changes */ - vector words{"addACL(", "addAction(", "addAnyTCRule()", "addDelay(", - "addDisableValidationRule(", "addDNSCryptBind(", "addDomainBlock(", - "addDomainSpoof(", "addDynBlocks(", "addLocal(", "addLuaAction(", - "addNoRecurseRule(", "addPoolRule(", "addQPSLimit(", "addQPSPoolRule(", - "addResponseAction(", - "AllowAction(", "AllRule(", "AndRule(", - "benchRule(", - "carbonServer(", "controlSocket(", "clearDynBlocks()", "clearRules(", - "DelayAction(", "delta()", "DisableValidationAction(", "DropAction(", - "dumpStats()", - "exceedNXDOMAINs(", "exceedQRate(", "exceedQTypeRate(", "exceedRespByterate(", - "exceedServFails(", - "firstAvailable", "fixupCase(", - "generateDNSCryptCertificate(", "generateDNSCryptProviderKeys(", "getPoolServers(", "getResponseRing(", - "getServer(", "getServers()", "grepq(", - "leastOutstanding", "LogAction(", - "makeKey()", "MaxQPSIPRule(", "MaxQPSRule(", "mvResponseRule(", - "mvRule(", - "newDNSName(", "newQPSLimiter(", "newRemoteLogger(", "newRuleAction(", "newServer(", - "newServerPolicy(", "newSuffixMatchNode(", "NoRecurseAction(", - "PoolAction(", "printDNSCryptProviderFingerprint(", - "RegexRule(", "RemoteLogAction(", "RemoteLogResponseAction(", "rmResponseRule(", - "rmRule(", "rmServer(", "roundrobin", - "QNameLabelsCountRule(", "QNameWireLengthRule(", "QTypeRule(", - "setACL(", "setDNSSECPool(", "setECSOverride(", - "setECSSourcePrefixV4(", "setECSSourcePrefixV6(", "setKey(", "setLocal(", - "setMaxTCPClientThreads(", "setMaxTCPQueuedConnections(", "setMaxUDPOutstanding(", "setRules(", - "setServerPolicy(", "setServerPolicyLua(", - "setTCPRecvTimeout(", "setTCPSendTimeout(", "setVerboseHealthChecks(", "show(", "showACL()", - "showDNSCryptBinds()", "showDynBlocks()", "showResponseLatency()", "showResponseRules()", - "showRules()", "showServerPolicy()", "showServers()", "shutdown()", "SpoofAction(", - "TCAction(", "testCrypto()", "topBandwidth(", "topClients(", - "topQueries(", "topResponses(", "topResponseRule()", "topRule()", "topSlow(", - "truncateTC(", - "webserver(", "whashed", "wrandom" }; static int s_counter=0; int counter=0; if(!state) s_counter=0; - for(auto w : words) { - if(boost::starts_with(w, t) && counter++ == s_counter) { + for(const auto& keyword : g_consoleKeywords) { + if(boost::starts_with(keyword.name, t) && counter++ == s_counter) { + std::string value(keyword.name); s_counter++; - return strdup(w.c_str()); + if (keyword.function) { + value += "("; + if (keyword.parameters.empty()) { + value += ")"; + } + } + return strdup(value.c_str()); } } return 0; diff --git a/pdns/dnsdist-lua2.cc b/pdns/dnsdist-lua2.cc index 08ef7c952..12066df03 100644 --- a/pdns/dnsdist-lua2.cc +++ b/pdns/dnsdist-lua2.cc @@ -796,6 +796,28 @@ void moreLua(bool client) return fe.local.toStringWithPort(); }); + g_lua.writeFunction("help", [](boost::optional command) { + setLuaNoSideEffect(); + g_outputBuffer = ""; + for (const auto& keyword : g_consoleKeywords) { + if (!command) { + g_outputBuffer += keyword.toString() + "\n"; + } + else if (keyword.name == command) { + g_outputBuffer = keyword.toString() + "\n"; + return; + } + } + if (command) { + g_outputBuffer = "Nothing found for " + *command + "\n"; + } + }); + + g_lua.writeFunction("showVersion", []() { + setLuaNoSideEffect(); + g_outputBuffer = "dnsdist " + std::string(VERSION) + "\n"; + }); + #ifdef HAVE_EBPF g_lua.writeFunction("newBPFFilter", [](uint32_t maxV4, uint32_t maxV6, uint32_t maxQNames) { return std::make_shared(maxV4, maxV6, maxQNames); diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index ee9d2e971..a91fd16e6 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -609,6 +609,24 @@ extern bool g_ECSOverride; extern bool g_verboseHealthChecks; extern uint32_t g_staleCacheEntriesTTL; +struct ConsoleKeyword { + std::string name; + bool function; + std::string parameters; + std::string description; + std::string toString() const + { + std::string res(name); + if (function) { + res += "(" + parameters + ")"; + } + res += ": "; + res += description; + return res; + } +}; +extern const std::vector g_consoleKeywords; + #ifdef HAVE_EBPF extern shared_ptr g_defaultBPFFilter; #endif /* HAVE_EBPF */