net: add support for max_conns
authorPhilip Papurt <ginkoid@gmail.com>
Tue, 9 Feb 2021 22:13:35 +0000 (17:13 -0500)
committerPhilip Papurt <ginkoid@gmail.com>
Tue, 9 Feb 2021 22:13:35 +0000 (17:13 -0500)
README.md
cmdline.cc
config.cc
config.proto
net.cc
nsjail.1
nsjail.h

index 5901cb27e47f5b82603521f0ad3e0bc91c8549be..78fb8be254a609a13dcc02ce742373f6a1914b89 100644 (file)
--- a/README.md
+++ b/README.md
@@ -368,6 +368,8 @@ Options:
        TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)
  --bindhost VALUE
        IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::')
+ --max_conns VALUE
+       Maximum number of connections across all IPs (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))
  --max_conns_per_ip|-i VALUE
        Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))
  --log|-l VALUE
index 88723aef10502458b6b3b7aee989e0d81e88be2c..9a5b8f8bdf26b2c50be015137aa1b1e041fa949d 100644 (file)
@@ -83,6 +83,7 @@ struct custom_option custom_opts[] = {
     { { "cwd", required_argument, NULL, 'D' }, "Directory in the namespace the process will run (default: '/')" },
     { { "port", required_argument, NULL, 'p' }, "TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)" },
     { { "bindhost", required_argument, NULL, 0x604 }, "IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::')" },
+    { { "max_conns", required_argument, NULL, 0x608 }, "Maximum number of connections across all IPs (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))" },
     { { "max_conns_per_ip", required_argument, NULL, 'i' }, "Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))" },
     { { "log", required_argument, NULL, 'l' }, "Log file (default: use log_fd)" },
     { { "log_fd", required_argument, NULL, 'L' }, "Log FD (default: 2)" },
@@ -226,19 +227,19 @@ void logParams(nsjconf_t* nsjconf) {
 
        LOG_I(
            "Jail parameters: hostname:'%s', chroot:'%s', process:'%s', bind:[%s]:%d, "
-           "max_conns_per_ip:%u, time_limit:%" PRId64
+           "max_conns:%u, max_conns_per_ip:%u, time_limit:%" PRId64
            ", personality:%#lx, daemonize:%s, clone_newnet:%s, "
            "clone_newuser:%s, clone_newns:%s, clone_newpid:%s, clone_newipc:%s, clone_newuts:%s, "
            "clone_newcgroup:%s, keep_caps:%s, disable_no_new_privs:%s, max_cpus:%zu",
            nsjconf->hostname.c_str(), nsjconf->chroot.c_str(),
            nsjconf->exec_file.empty() ? nsjconf->argv[0].c_str() : nsjconf->exec_file.c_str(),
-           nsjconf->bindhost.c_str(), nsjconf->port, nsjconf->max_conns_per_ip, nsjconf->tlimit,
-           nsjconf->personality, logYesNo(nsjconf->daemonize), logYesNo(nsjconf->clone_newnet),
-           logYesNo(nsjconf->clone_newuser), logYesNo(nsjconf->clone_newns),
-           logYesNo(nsjconf->clone_newpid), logYesNo(nsjconf->clone_newipc),
-           logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newcgroup),
-           logYesNo(nsjconf->keep_caps), logYesNo(nsjconf->disable_no_new_privs),
-           nsjconf->max_cpus);
+           nsjconf->bindhost.c_str(), nsjconf->port, nsjconf->max_conns, nsjconf->max_conns_per_ip,
+           nsjconf->tlimit, nsjconf->personality, logYesNo(nsjconf->daemonize),
+           logYesNo(nsjconf->clone_newnet), logYesNo(nsjconf->clone_newuser),
+           logYesNo(nsjconf->clone_newns), logYesNo(nsjconf->clone_newpid),
+           logYesNo(nsjconf->clone_newipc), logYesNo(nsjconf->clone_newuts),
+           logYesNo(nsjconf->clone_newcgroup), logYesNo(nsjconf->keep_caps),
+           logYesNo(nsjconf->disable_no_new_privs), nsjconf->max_cpus);
 
        for (const auto& p : nsjconf->mountpts) {
                LOG_I(
@@ -423,6 +424,7 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
        nsjconf->is_silent = false;
        nsjconf->stderr_to_null = false;
        nsjconf->skip_setsid = false;
+       nsjconf->max_conns = 0;
        nsjconf->max_conns_per_ip = 0;
        nsjconf->proc_path = "/proc";
        nsjconf->is_proc_rw = false;
@@ -503,6 +505,9 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
                case 0x604:
                        nsjconf->bindhost = optarg;
                        break;
+               case 0x608:
+                       nsjconf->max_conns = strtoul(optarg, NULL, 0);
+                       break;
                case 'i':
                        nsjconf->max_conns_per_ip = strtoul(optarg, NULL, 0);
                        break;
index f9ca8670093aa2f77b35509830cd34af707bdec8..bf8cee603c4cd9a8d990fdedcf16fd652509f7d2 100644 (file)
--- a/config.cc
+++ b/config.cc
@@ -86,6 +86,7 @@ static bool configParseInternal(nsjconf_t* nsjconf, const nsjail::NsJailConfig&
        nsjconf->cwd = njc.cwd();
        nsjconf->port = njc.port();
        nsjconf->bindhost = njc.bindhost();
+       nsjconf->max_conns = njc.max_conns();
        nsjconf->max_conns_per_ip = njc.max_conns_per_ip();
        nsjconf->tlimit = njc.time_limit();
        nsjconf->max_cpus = njc.max_cpus();
index db1e6c7e6447f5ba045b33297066f8cb63eff229..6b03dcf1550227c886e425060b56dbe24b28dac7 100644 (file)
@@ -90,6 +90,8 @@ message NsJailConfig {
     optional uint32 port = 10 [default = 0];
     /* Host to bind to for mode=LISTEN. Must be in IPv6 format */
     optional string bindhost = 11 [default = "::"];
+    /* For mode=LISTEN, maximum number of connections across all IPs */
+    optional uint32 max_conns = 85 [default = 0];
     /* For mode=LISTEN, maximum number of connections from a single IP */
     optional uint32 max_conns_per_ip = 12 [default = 0];
 
diff --git a/net.cc b/net.cc
index c17a24c076d981c7c271b592a580bbac60c8056d..5259f9cc0c24f203a30c32d2830952ca95ef88ca 100644 (file)
--- a/net.cc
+++ b/net.cc
@@ -181,6 +181,12 @@ static bool isSocket(int fd) {
 }
 
 bool limitConns(nsjconf_t* nsjconf, int connsock) {
+       /* 0 means 'unlimited' */
+       if (nsjconf->max_conns != 0 && nsjconf->pids.size() >= nsjconf->max_conns) {
+               LOG_W("Rejecting connection, max_conns limit reached: %u", nsjconf->max_conns);
+               return false;
+       }
+
        /* 0 means 'unlimited' */
        if (nsjconf->max_conns_per_ip == 0) {
                return true;
index 7714de75976e4a0ea36156a460f026bd224f4c7f..439f8e1f0639ab9a7589e4113dbb12b9604becac 100644 (file)
--- a/nsjail.1
+++ b/nsjail.1
@@ -61,6 +61,9 @@ TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)
 \fB\-\-bindhost\fR VALUE
 IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::')
 .TP
+\fB\-\-max_conns\fR VALUE
+Maximum number of connections across all IPs (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))
+.TP
 \fB\-\-max_conns_per_ip\fR|\fB\-i\fR VALUE
 Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))
 .TP
index fda3392bc3249a3b5f55f50becef1171a4a1c72b..038a62eea623589b13c36e5960cfab6655e6fd63 100644 (file)
--- a/nsjail.h
+++ b/nsjail.h
@@ -129,6 +129,7 @@ struct nsjconf_t {
        bool is_silent;
        bool stderr_to_null;
        bool skip_setsid;
+       unsigned int max_conns;
        unsigned int max_conns_per_ip;
        std::string proc_path;
        bool is_proc_rw;