*/
#include "dnsdist.hh"
#include "sodcrypto.hh"
+#include "pwd.h"
#if defined (__OpenBSD__)
#include <readline/readline.h>
g_confDelta.push_back({now,line});
}
+string historyFile(const bool &ignoreHOME = false)
+{
+ string ret;
+
+ struct passwd pwd;
+ struct passwd *result;
+ char buf[16384];
+ getpwuid_r(geteuid(), &pwd, buf, sizeof(buf), &result);
+
+ const char *homedir = getenv("HOME");
+ if (result)
+ ret = string(pwd.pw_dir);
+ if (homedir && !ignoreHOME) // $HOME overrides what the OS tells us
+ ret = string(homedir);
+ if (ret.empty())
+ ret = "."; // CWD if nothing works..
+ ret.append("/.dnsdist_history");
+ return ret;
+}
+
void doClient(ComboAddress server, const std::string& command)
{
if(g_verbose)
}
SConnect(fd, server);
setTCPNoDelay(fd);
- SodiumNonce theirs, ours;
+ SodiumNonce theirs, ours, readingNonce, writingNonce;
ours.init();
writen2(fd, (const char*)ours.value, sizeof(ours.value));
readn2(fd, (char*)theirs.value, sizeof(theirs.value));
+ readingNonce.merge(ours, theirs);
+ writingNonce.merge(theirs, ours);
if(!command.empty()) {
- string msg=sodEncryptSym(command, g_key, ours);
+ string msg=sodEncryptSym(command, g_key, writingNonce);
putMsgLen32(fd, (uint32_t) msg.length());
if(!msg.empty())
writen2(fd, msg);
boost::scoped_array<char> resp(new char[len]);
readn2(fd, resp.get(), len);
msg.assign(resp.get(), len);
- msg=sodDecryptSym(msg, g_key, theirs);
+ msg=sodDecryptSym(msg, g_key, readingNonce);
cout<<msg;
cout.flush();
}
return;
}
+ string histfile = historyFile();
set<string> dupper;
{
- ifstream history(".dnsdist_history");
+ ifstream history(histfile);
string line;
while(getline(history, line))
add_history(line.c_str());
}
- ofstream history(".dnsdist_history", std::ios_base::app);
+ ofstream history(histfile, std::ios_base::app);
string lastline;
for(;;) {
char* sline = readline("> ");
if(line.empty())
continue;
- string msg=sodEncryptSym(line, g_key, ours);
+ string msg=sodEncryptSym(line, g_key, writingNonce);
putMsgLen32(fd, (uint32_t) msg.length());
writen2(fd, msg);
uint32_t len;
boost::scoped_array<char> resp(new char[len]);
readn2(fd, resp.get(), len);
msg.assign(resp.get(), len);
- msg=sodDecryptSym(msg, g_key, theirs);
+ msg=sodDecryptSym(msg, g_key, readingNonce);
cout<<msg;
cout.flush();
}
void doConsole()
{
+ string histfile = historyFile(true);
set<string> dupper;
{
- ifstream history(".dnsdist_history");
+ ifstream history(histfile);
string line;
while(getline(history, line))
add_history(line.c_str());
}
- ofstream history(".dnsdist_history", std::ios_base::app);
+ ofstream history(histfile, std::ios_base::app);
string lastline;
for(;;) {
char* sline = readline("> ");
{ "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" },
+ { "setMaxTCPConnectionDuration", true, "n", "set the maximum duration of an incoming TCP connection, in seconds. 0 means unlimited" },
+ { "setMaxTCPConnectionsPerClient", true, "n", "set the maximum number of TCP connections per client. 0 means unlimited" },
+ { "setMaxTCPQueriesPerConnection", true, "n", "set the maximum number of queries in an incoming TCP connection. 0 means unlimited" },
{ "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" },
{ "setQueryCount", true, "bool", "set whether queries should be counted" },
{ "setQueryCountFilter", true, "func", "filter queries that would be counted, where `func` is a function with parameter `dq` which decides whether a query should and how it should be counted" },
+ { "setRingBuffersSize", true, "n", "set the capacity of the ringbuffers used for live traffic inspection to `n`" },
{ "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'" },
try
{
setTCPNoDelay(fd);
- SodiumNonce theirs;
- readn2(fd, (char*)theirs.value, sizeof(theirs.value));
- SodiumNonce ours;
+ SodiumNonce theirs, ours, readingNonce, writingNonce;
ours.init();
+ readn2(fd, (char*)theirs.value, sizeof(theirs.value));
writen2(fd, (char*)ours.value, sizeof(ours.value));
+ readingNonce.merge(ours, theirs);
+ writingNonce.merge(theirs, ours);
for(;;) {
uint32_t len;
readn2(fd, msg.get(), len);
string line(msg.get(), len);
- line = sodDecryptSym(line, g_key, theirs);
+ line = sodDecryptSym(line, g_key, readingNonce);
// cerr<<"Have decrypted line: "<<line<<endl;
string response;
try {
catch(const LuaContext::SyntaxErrorException& e) {
response = "Error: " + string(e.what()) + ": ";
}
- response = sodEncryptSym(response, g_key, ours);
+ response = sodEncryptSym(response, g_key, writingNonce);
putMsgLen32(fd, response.length());
writen2(fd, response.c_str(), response.length());
}
return (receivedQuery, message)
@classmethod
- def sendTCPQuery(cls, query, response, useQueue=True, timeout=2.0, rawQuery=False):
- if useQueue:
- cls._toResponderQueue.put(response, True, timeout)
+ def openTCPConnection(cls, timeout=None):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if timeout:
sock.settimeout(timeout)
sock.connect(("127.0.0.1", cls._dnsDistPort))
+ return sock
- try:
- if not rawQuery:
- wire = query.to_wire()
- else:
- wire = query
+ @classmethod
+ def sendTCPQueryOverConnection(cls, sock, query, rawQuery=False):
+ if not rawQuery:
+ wire = query.to_wire()
+ else:
+ wire = query
- sock.send(struct.pack("!H", len(wire)))
- sock.send(wire)
- data = sock.recv(2)
+ sock.send(struct.pack("!H", len(wire)))
+ sock.send(wire)
+
+ @classmethod
+ def recvTCPResponseOverConnection(cls, sock):
+ message = None
+ data = sock.recv(2)
+ if data:
+ (datalen,) = struct.unpack("!H", data)
+ data = sock.recv(datalen)
if data:
- (datalen,) = struct.unpack("!H", data)
- data = sock.recv(datalen)
+ message = dns.message.from_wire(data)
+ return message
+
+ @classmethod
+ def sendTCPQuery(cls, query, response, useQueue=True, timeout=2.0, rawQuery=False):
+ message = None
+ if useQueue:
+ cls._toResponderQueue.put(response, True, timeout)
+
+ sock = cls.openTCPConnection(timeout)
+
+ try:
+ cls.sendTCPQueryOverConnection(sock, query, rawQuery)
+ message = cls.recvTCPResponseOverConnection(sock)
except socket.timeout as e:
print("Timeout: %s" % (str(e)))
- data = None
except socket.error as e:
print("Network error: %s" % (str(e)))
- data = None
finally:
sock.close()
receivedQuery = None
- message = None
if useQueue and not cls._fromResponderQueue.empty():
receivedQuery = cls._fromResponderQueue.get(True, timeout)
- if data:
- message = dns.message.from_wire(data)
+
return (receivedQuery, message)
@classmethod
sock.send(ourNonce)
theirNonce = sock.recv(len(ourNonce))
- msg = cls._encryptConsole(command, ourNonce)
+ halfNonceSize = len(ourNonce) / 2
+ readingNonce = ourNonce[0:halfNonceSize] + theirNonce[halfNonceSize:]
+ writingNonce = theirNonce[0:halfNonceSize] + ourNonce[halfNonceSize:]
+
+ msg = cls._encryptConsole(command, writingNonce)
sock.send(struct.pack("!I", len(msg)))
sock.send(msg)
data = sock.recv(4)
(responseLen,) = struct.unpack("!I", data)
data = sock.recv(responseLen)
- response = cls._decryptConsole(data, theirNonce)
+ response = cls._decryptConsole(data, readingNonce)
return response