#include <unistd.h>
#include "sodcrypto.hh"
#include "dnsrulactions.hh"
-
+#include <grp.h>
+#include <pwd.h>
#include <getopt.h>
/* Known sins:
}
};
-DelayPipe<DelayedPacket> g_delay;
+DelayPipe<DelayedPacket> * g_delay = 0;
// listens on a dedicated socket, lobs answers from downstream servers to original requestors
void* responderThread(std::shared_ptr<DownstreamState> state)
dh->id = ids->origID;
g_stats.responses++;
- if(ids->delayMsec) {
+ if(ids->delayMsec && g_delay) {
DelayedPacket dp{ids->origFD, string(packet,len), ids->origRemote, ids->origDest};
- g_delay.submit(dp, ids->delayMsec);
+ g_delay->submit(dp, ids->delayMsec);
}
else {
if(ids->origDest.sin4.sin_family == 0)
#endif
}
+static void dropGroupPrivs(gid_t gid)
+{
+ if (gid) {
+ if (setgid(gid) == 0) {
+ if (setgroups(0, NULL) < 0) {
+ warnlog("Warning: Unable to drop supplementary gids: %s", strerror(errno));
+ }
+ }
+ else {
+ warnlog("Warning: Unable to set group ID to %d: %s", gid, strerror(errno));
+ }
+ }
+}
+
+static void dropUserPrivs(uid_t uid)
+{
+ if(uid) {
+ if(setuid(uid) < 0) {
+ warnlog("Warning: Unable to set user ID to %d: %s", uid, strerror(errno));
+ }
+ }
+}
+
+static uid_t strToUID(const string &str)
+{
+ uid_t result = 0;
+ const char * cstr = str.c_str();
+ struct passwd * pwd = getpwnam(cstr);
+
+ if (pwd == NULL) {
+ char * endptr = 0;
+ long int val = strtol(cstr, &endptr, 10);
+
+ if (((val == LONG_MAX || val == LLONG_MIN) && errno == ERANGE) || endptr == cstr || val <= 0) {
+ warnlog("Warning: Unable to parse user ID %s", cstr);
+ }
+ else {
+ result = val;
+ }
+ }
+ else {
+ result = pwd->pw_uid;
+ }
+
+ return result;
+}
+
+static gid_t strToGID(const string &str)
+{
+ gid_t result = 0;
+ const char * cstr = str.c_str();
+ struct group * grp = getgrnam(cstr);
+
+ if (grp == NULL) {
+ char * endptr = 0;
+ long int val = strtol(cstr, &endptr, 10);
+
+ if (((val == LONG_MAX || val == LLONG_MIN) && errno == ERANGE) || endptr == cstr || val <= 0) {
+ warnlog("Warning: Unable to parse group ID %s", cstr);
+ }
+ else {
+ result = val;
+ }
+ }
+ else {
+ result = grp->gr_gid;
+ }
+
+ return result;
+}
+
/**** CARGO CULT CODE AHEAD ****/
extern "C" {
char* my_generator(const char* text, int state)
string pidfile;
string command;
string config;
+ string uid;
+ string gid;
} g_cmdLine;
{"config", required_argument, 0, 'C'},
{"execute", required_argument, 0, 'e'},
{"client", 0, 0, 'c'},
+ {"gid", required_argument, 0, 'g'},
{"local", required_argument, 0, 'l'},
{"daemon", 0, 0, 'd'},
{"pidfile", required_argument, 0, 'p'},
{"supervised", 0, 0, 's'},
+ {"uid", required_argument, 0, 'u'},
{"help", 0, 0, 'h'},
{0,0,0,0}
};
int longindex=0;
for(;;) {
- int c=getopt_long(argc, argv, "hcde:C:l:vp:", longopts, &longindex);
+ int c=getopt_long(argc, argv, "hcde:C:l:vp:g:u:", longopts, &longindex);
if(c==-1)
break;
switch(c) {
case 'e':
g_cmdLine.command=optarg;
break;
+ case 'g':
+ g_cmdLine.gid=optarg;
+ break;
case 'h':
cout<<"Syntax: dnsdist [-C,--config file] [-c,--client] [-d,--daemon]\n";
cout<<"[-p,--pidfile file] [-e,--execute cmd] [-h,--help] [-l,--local addr]\n";
cout<<"-c,--client Operate as a client, connect to dnsdist\n";
cout<<"-d,--daemon Operate as a daemon\n";
cout<<"-e,--execute cmd Connect to dnsdist and execute 'cmd'\n";
+ cout<<"-g,--gid gid Change the process group ID after binding sockets\n";
cout<<"-h,--help Display this helpful message\n";
cout<<"-l,--local address Listen on this local address\n";
cout<<"--supervised Don't open a console, I'm supervised\n";
cout<<" (use with e.g. systemd and daemontools)\n";
cout<<"-p,--pidfile file Write a pidfile, works only with --daemon\n";
+ cout<<"-u,--uid uid Change the process user ID after binding sockets\n";
cout<<"\n";
exit(EXIT_SUCCESS);
break;
case 's':
g_cmdLine.beSupervised=true;
break;
+ case 'u':
+ g_cmdLine.uid=optarg;
+ break;
case 'v':
g_verbose=true;
break;
toLaunch.push_back(cs);
}
+ for(const auto& local : g_locals) {
+ ClientState* cs = new ClientState;
+ if(!local.second) { // no TCP/IP
+ warnlog("Not providing TCP/IP service on local address '%s'", local.first.toStringWithPort());
+ continue;
+ }
+ cs->local= local.first;
+
+ cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
+
+ SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1);
+#ifdef TCP_DEFER_ACCEPT
+ SSetsockopt(cs->tcpFD, SOL_TCP,TCP_DEFER_ACCEPT, 1);
+#endif
+ if(cs->local.sin4.sin_family == AF_INET6) {
+ SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+ }
+ // if(g_vm.count("bind-non-local"))
+ bindAny(cs->local.sin4.sin_family, cs->tcpFD);
+ SBind(cs->tcpFD, cs->local);
+ SListen(cs->tcpFD, 64);
+ warnlog("Listening on %s",cs->local.toStringWithPort());
+
+ toLaunch.push_back(cs);
+ }
+
+ uid_t newgid=0;
+ gid_t newuid=0;
+
+ if(!g_cmdLine.gid.empty())
+ newgid = strToGID(g_cmdLine.gid.c_str());
+
+ if(!g_cmdLine.uid.empty())
+ newuid = strToUID(g_cmdLine.uid.c_str());
+
+ dropGroupPrivs(newgid);
+ dropUserPrivs(newuid);
+
if(g_cmdLine.beDaemon) {
g_console=false;
daemonize();
vinfolog("Running in the foreground");
}
+ /* this need to be done _after_ dropping privileges */
+ g_delay = new DelayPipe<DelayedPacket>();
+
for(auto& t : todo)
t();
for(auto& cs : toLaunch) {
- thread t1(udpClientThread, cs);
- t1.detach();
- }
-
- for(const auto& local : g_locals) {
- ClientState* cs = new ClientState;
- if(!local.second) { // no TCP/IP
- warnlog("Not providing TCP/IP service on local address '%s'", local.first.toStringWithPort());
- continue;
+ if (cs->udpFD >= 0) {
+ thread t1(udpClientThread, cs);
+ t1.detach();
}
- cs->local= local.first;
-
- cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
-
- SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1);
-#ifdef TCP_DEFER_ACCEPT
- SSetsockopt(cs->tcpFD, SOL_TCP,TCP_DEFER_ACCEPT, 1);
-#endif
- if(cs->local.sin4.sin_family == AF_INET6) {
- SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+ else if (cs->tcpFD >= 0) {
+ thread t1(tcpAcceptorThread, cs);
+ t1.detach();
}
- // if(g_vm.count("bind-non-local"))
- bindAny(cs->local.sin4.sin_family, cs->tcpFD);
- SBind(cs->tcpFD, cs->local);
- SListen(cs->tcpFD, 64);
- warnlog("Listening on %s",cs->local.toStringWithPort());
-
- thread t1(tcpAcceptorThread, cs);
- t1.detach();
}
+
thread carbonthread(carbonDumpThread);
carbonthread.detach();