]> git.meshlink.io Git - catta/commitdiff
* add resource limit enforcement to the daemon
authorLennart Poettering <lennart@poettering.net>
Sun, 14 Aug 2005 00:47:37 +0000 (00:47 +0000)
committerLennart Poettering <lennart@poettering.net>
Sun, 14 Aug 2005 00:47:37 +0000 (00:47 +0000)
* add ne options --no-rlimits, --no-drop-root, --syslog and --debug

git-svn-id: file:///home/lennart/svn/public/avahi/trunk@311 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-core/iface.c
avahi-daemon/avahi-daemon.conf
avahi-daemon/main.c
docs/TODO
man/avahi-daemon.8.xml.in
man/avahi-daemon.conf.5.xml.in

index 81b8375576fd7682b04209a788288c9f8fa21a09..3d90657950679d5f6dab86cc6a26f730ece901d4 100644 (file)
@@ -344,7 +344,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat
         AvahiHwInterface *hw;
         struct rtattr *a = NULL;
         size_t l;
-
+        
         if (ifinfomsg->ifi_family != AF_UNSPEC)
             return;
 
@@ -507,7 +507,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdat
                 m->list = LIST_ADDR;
         } else {
             m->list = LIST_DONE;
-            avahi_log_debug("Enumeration complete");
+            avahi_log_debug("Networ interface enumeration completed");
         }
         
     } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) {
index eb485d638c8efd873897da1644d475d6b4630909..f3f81f73d526be4acd62966389b898febd4c3029 100644 (file)
@@ -18,3 +18,12 @@ publish-domain=yes
 [reflector]
 enable-reflector=no
 reflect-ipv=no
+
+[rlimits]
+#rlimit-as=
+rlimit-core=0
+rlimit-data=4194304
+rlimit-fsize=0
+rlimit-nofile=15
+rlimit-stack=4194304
+rlimit-nproc=1
index a29ad9fd599aaebbcfb5a92c3f582601fbeecb01..843ee2b899f58870565f8c377aeee965de05ffe9 100644 (file)
@@ -36,6 +36,8 @@
 #include <fcntl.h>
 #include <time.h>
 #include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include <libdaemon/dfork.h>
 #include <libdaemon/dsignal.h>
@@ -67,11 +69,22 @@ typedef struct {
     AvahiServerConfig server_config;
     DaemonCommand command;
     gboolean daemonize;
+    gboolean use_syslog;
     gchar *config_file;
     gboolean enable_dbus;
     gboolean drop_root;
     gboolean publish_resolv_conf;
     gchar ** publish_dns_servers;
+    gboolean no_rlimits;
+    gboolean debug;
+
+    gboolean rlimit_as_set, rlimit_core_set, rlimit_data_set, rlimit_fsize_set, rlimit_nofile_set, rlimit_stack_set;
+    rlim_t rlimit_as, rlimit_core, rlimit_data, rlimit_fsize, rlimit_nofile, rlimit_stack;
+
+#ifdef RLIMIT_NPROC
+    gboolean rlimit_nproc_set;
+    rlim_t rlimit_nproc;
+#endif
 } DaemonConfig;
 
 #define RESOLV_CONF "/etc/resolv.conf"
@@ -216,36 +229,55 @@ static void server_callback(AvahiServer *s, AvahiServerState state, void *userda
 static void help(FILE *f, const gchar *argv0) {
     fprintf(f,
             "%s [options]\n"
-            "    -h --help        Show this help\n"
-            "    -D --daemonize   Daemonize after startup\n"
-            "    -k --kill        Kill a running daemon\n"
-            "    -r --reload      Request a running daemon to reload static services\n"
-            "    -c --check       Return 0 if a daemon is already running\n"
-            "    -V --version     Show version\n"
-            "    -f --file=FILE   Load the specified configuration file instead of\n"
-            "                     "AVAHI_CONFIG_FILE"\n",
+            "    -h --help          Show this help\n"
+            "    -D --daemonize     Daemonize after startup (implies -s)\n"
+            "    -s --syslog        Write log messages to syslog(3) instead of STDERR\n"
+            "    -k --kill          Kill a running daemon\n"
+            "    -r --reload        Request a running daemon to reload static services\n"
+            "    -c --check         Return 0 if a daemon is already running\n"
+            "    -V --version       Show version\n"
+            "    -f --file=FILE     Load the specified configuration file instead of\n"
+            "                       "AVAHI_CONFIG_FILE"\n"
+            "       --no-rlimits    Don't enforce resource limits\n"
+            "       --no-drop-root  Don't drop priviliges\n"
+            "       --debug         Increase verbosity\n",
             argv0);
 }
 
+
 static gint parse_command_line(DaemonConfig *c, int argc, char *argv[]) {
     gint o;
+
+    enum {
+        OPTION_NO_RLIMITS = 256,
+        OPTION_NO_DROP_ROOT,
+        OPTION_DEBUG
+    };
     
     static const struct option const long_options[] = {
-        { "help",      no_argument,       NULL, 'h' },
-        { "daemonize", no_argument,       NULL, 'D' },
-        { "kill",      no_argument,       NULL, 'k' },
-        { "version",   no_argument,       NULL, 'V' },
-        { "file",      required_argument, NULL, 'f' },
-        { "reload",    no_argument,       NULL, 'r' },
-        { "check",     no_argument,       NULL, 'c' },
+        { "help",         no_argument,       NULL, 'h' },
+        { "daemonize",    no_argument,       NULL, 'D' },
+        { "kill",         no_argument,       NULL, 'k' },
+        { "version",      no_argument,       NULL, 'V' },
+        { "file",         required_argument, NULL, 'f' },
+        { "reload",       no_argument,       NULL, 'r' },
+        { "check",        no_argument,       NULL, 'c' },
+        { "syslog",       no_argument,       NULL, 's' },
+        { "no-rlimits",   no_argument,       NULL, OPTION_NO_RLIMITS },
+        { "no-drop-root", no_argument,       NULL, OPTION_NO_DROP_ROOT },
+        { "debug",        no_argument,       NULL, OPTION_DEBUG },
+        { NULL, 0, NULL, 0 }
     };
 
     g_assert(c);
 
     opterr = 0;
-    while ((o = getopt_long(argc, argv, "hDkVf:rc", long_options, NULL)) >= 0) {
+    while ((o = getopt_long(argc, argv, "hDkVf:rcs", long_options, NULL)) >= 0) {
 
         switch(o) {
+            case 's':
+                c->use_syslog = TRUE;
+                break;
             case 'h':
                 c->command = DAEMON_HELP;
                 break;
@@ -268,6 +300,15 @@ static gint parse_command_line(DaemonConfig *c, int argc, char *argv[]) {
             case 'c':
                 c->command = DAEMON_CHECK;
                 break;
+            case OPTION_NO_RLIMITS:
+                c->no_rlimits = TRUE;
+                break;
+            case OPTION_NO_DROP_ROOT:
+                c->drop_root = FALSE;
+                break;
+            case OPTION_DEBUG:
+                c->debug = TRUE;
+                break;
             default:
                 fprintf(stderr, "Invalid command line argument: %c\n", o);
                 return -1;
@@ -407,6 +448,50 @@ static gint load_config_file(DaemonConfig *c) {
             g_strfreev(keys);
             keys = NULL;
             
+        } else if (g_strcasecmp(*g, "rlimits") == 0) {
+            gchar **k;
+            
+            keys = g_key_file_get_keys(f, *g, NULL, NULL);
+
+            for (k = keys; *k; k++) {
+
+                v = g_key_file_get_string(f, *g, *k, NULL);
+                
+                if (g_strcasecmp(*k, "rlimit-as") == 0) {
+                    c->rlimit_as_set = TRUE;
+                    c->rlimit_as = atoi(v);
+                } else if (g_strcasecmp(*k, "rlimit-core") == 0) {
+                    c->rlimit_core_set = TRUE;
+                    c->rlimit_core = atoi(v);
+                } else if (g_strcasecmp(*k, "rlimit-data") == 0) {
+                    c->rlimit_data_set = TRUE;
+                    c->rlimit_data = atoi(v);
+                } else if (g_strcasecmp(*k, "rlimit-fsize") == 0) {
+                    c->rlimit_fsize_set = TRUE;
+                    c->rlimit_fsize = atoi(v);
+                } else if (g_strcasecmp(*k, "rlimit-nofile") == 0) {
+                    c->rlimit_nofile_set = TRUE;
+                    c->rlimit_nofile = atoi(v);
+                } else if (g_strcasecmp(*k, "rlimit-stack") == 0) {
+                    c->rlimit_stack_set = TRUE;
+                    c->rlimit_stack = atoi(v);
+#ifdef RLIMIT_NPROC
+                } else if (g_strcasecmp(*k, "rlimit-nproc") == 0) {
+                    c->rlimit_nproc_set = TRUE;
+                    c->rlimit_nproc = atoi(v);
+#endif
+                } else {
+                    fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+                    goto finish;
+                }
+
+                g_free(v);
+                v = NULL;
+            }
+    
+            g_strfreev(keys);
+            keys = NULL;
+            
         } else {
             fprintf(stderr, "Invalid configuration file group \"%s\".\n", *g);
             goto finish;
@@ -443,6 +528,9 @@ static void log_function(AvahiLogLevel level, const gchar *txt) {
     g_assert(level < AVAHI_LOG_LEVEL_MAX);
     g_assert(txt);
 
+    if (!config.debug && level == AVAHI_LOG_DEBUG)
+        return;
+
     daemon_log(log_level_map[level], "%s", txt);
 }
 
@@ -695,7 +783,39 @@ fail:
     if (reset_umask)
         umask(u);
     return r;
+}
+
+static void set_one_rlimit(int resource, rlim_t limit, const gchar *name) {
+    struct rlimit rl;
+    rl.rlim_cur = rl.rlim_max = limit;
 
+    if (setrlimit(resource, &rl) < 0)
+        avahi_log_warn("setrlimit(%s, {%u, %u}) failed: %s", name, (unsigned) limit, (unsigned) limit, strerror(errno));
+}
+
+static void enforce_rlimits(void) {
+
+    if (config.rlimit_as_set)
+        set_one_rlimit(RLIMIT_AS, config.rlimit_as, "RLIMIT_AS");
+    if (config.rlimit_core_set)
+        set_one_rlimit(RLIMIT_CORE, config.rlimit_core, "RLIMIT_CORE");
+    if (config.rlimit_data_set)
+        set_one_rlimit(RLIMIT_DATA, config.rlimit_data, "RLIMIT_DATA");
+    if (config.rlimit_fsize_set)
+        set_one_rlimit(RLIMIT_FSIZE, config.rlimit_fsize, "RLIMIT_FSIZE");
+    if (config.rlimit_nofile_set)
+        set_one_rlimit(RLIMIT_NOFILE, config.rlimit_nofile, "RLIMIT_NOFILE");
+    if (config.rlimit_stack_set)
+        set_one_rlimit(RLIMIT_STACK, config.rlimit_stack, "RLIMIT_STACK");
+#ifdef RLIMIT_NPROC
+    if (config.rlimit_nproc_set)
+        set_one_rlimit(RLIMIT_NPROC, config.rlimit_nproc, "RLIMIT_NPROC");
+#endif
+
+#ifdef RLIMIT_MEMLOCK
+    /* We don't need locked memory */
+    set_one_rlimit(RLIMIT_MEMLOCK, 0, "RLIMIT_MEMLOCK");
+#endif
 }
 
 #define RANDOM_DEVICE "/dev/urandom"
@@ -736,7 +856,20 @@ int main(int argc, char *argv[]) {
     config.drop_root = TRUE;
     config.publish_dns_servers = NULL;
     config.publish_resolv_conf = FALSE;
-
+    config.use_syslog = FALSE;
+    config.no_rlimits = FALSE;
+    config.debug = FALSE;
+    
+    config.rlimit_as_set = FALSE;
+    config.rlimit_core_set = FALSE;
+    config.rlimit_data_set = FALSE;
+    config.rlimit_fsize_set = FALSE;
+    config.rlimit_nofile_set = FALSE;
+    config.rlimit_stack_set = FALSE;
+#ifdef RLIMIT_NPROC
+    config.rlimit_nproc_set = FALSE;
+#endif
+    
     if ((argv0 = strrchr(argv[0], '/')))
         argv0++;
     else
@@ -776,7 +909,7 @@ int main(int argc, char *argv[]) {
     else if (config.command == DAEMON_RUN) {
         pid_t pid;
 
-        if (getuid() != 0) {
+        if (getuid() != 0 && config.drop_root) {
             avahi_log_error("This program is intended to be run as root.");
             goto finish;
         }
@@ -810,10 +943,8 @@ int main(int argc, char *argv[]) {
             /* Child */
         }
 
-
-        printf("%s "PACKAGE_VERSION" starting up.\n", argv0);
-        
-        chdir("/");
+        if (config.use_syslog || config.daemonize)
+            daemon_log_use = DAEMON_LOG_SYSLOG;
 
         if (make_runtime_dir() < 0)
             goto finish;
@@ -832,6 +963,13 @@ int main(int argc, char *argv[]) {
         } else
             wrote_pid_file = TRUE;
 
+        if (!config.no_rlimits)
+            enforce_rlimits();
+
+        chdir("/");
+        
+        avahi_log_info("%s "PACKAGE_VERSION" starting up.\n", argv0);
+        
         if (run_server(&config) == 0)
             r = 0;
     }
index 6f7446a1f71ee3b7982414b77fd659f1457f529b..aeca215b6fe23fb41c456cdabc3ba07cf67e2084 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
@@ -1,7 +1,7 @@
 todo:
-* drop glib
+* drop glib from avahi-daemon
 * allow srv port == 0
-* deal with no local interface
+* deal with no local interface ?
 * release!
 
 later:
index 93002ec827f75d33d0fe983aa505901544941a6f..ce8ab81e60c2274c1e796beeb0d0205263176ae5 100644 (file)
 
          <option>
                <p><opt>-D | --daemonize</opt></p>
-               <optdesc><p>Daemonize after startup and redirect log messages to syslog.</p></optdesc>
+               <optdesc><p>Daemonize after startup. Implies <opt>--syslog</opt></p></optdesc>
          </option>
 
+      <option>
+        <p><opt>-s | --syslog</opt></p>
+        <optdesc><p>Log to syslog instead of STDERR. Implied by <opt>--daemonize</opt></p></optdesc>
+      </option>
+
+      <option>
+        <p><opt>--debug</opt></p>
+        <optdesc><p>Increase verbosity to debug level</p></optdesc>
+      </option>
+
+      <option>
+        <p><opt>--no-rlimits</opt></p>
+        <optdesc><p>Don't enforce resource limits as specified in the configuration file. (See <manref section="2" name="setrlimit"/> for more information)</p></optdesc>
+      </option>
+
+      <option>
+        <p><opt>--no-drop-root</opt></p>
+        <optdesc><p>Don't drop root priviliges after startup and don't require daemon to be started as root. We recommend not to use this option.</p></optdesc>
+      </option>
+
          <option>
                <p><opt>-k | --kill</opt></p>
                <optdesc><p>Kill an already running avahi-daemon. (equivalent to sending a SIGTERM)</p></optdesc>
                <optdesc><p>Show version information </p></optdesc>
          </option>
 
+
        </options>
 
 
index 45fdf9f09b5ac5fc9e964d25c72c301f8b6eba5e..cac071711f5f210f775686271cd2f4de0ec87cfb 100644 (file)
       </option>
     </section>
 
+    <section name="Section [rlimits]">
+      <p>This section is used to define system resource limits for the
+      daemon. See <manref section="2" name="setrlimit"/> for more
+      information. If any of the options is not specified in the configuration
+      file, avahi-daemon does not change it from the system
+      defaults.</p>
+
+
+      <option>
+        <p><opt>rlimit-as=</opt> Value in bytes for RLIMIT_AS (maximum size of the process's virtual memory). Sensible values are heavily system dependent.</p>
+      </option>
+
+      <option>
+        <p><opt>rlimit-core=</opt> Value in bytes for RLIMIT_CORE (maximum core file size). Unless you want to debug avahi-daemon, it is safe to set this to 0.</p>
+      </option>
+
+      <option>
+        <p><opt>rlimit-data=</opt> Value in bytes for RLIMIT_DATA (maximum size of the process's data segment). Sensible values are heavily system dependent.</p>
+      </option>
+
+      <option>
+        <p><opt>rlimit-fsize=</opt> Value for RLIMIT_FSIZE (maximum size of files the process may create). Since avahi-daemon shouldn't write any files to disk, it is safe to set this to 0.</p>
+      </option>
+
+      <option>
+        <p><opt>rlimit-nofile=</opt> Value for RLIMIT_NOFILE (open file descriptors). avahi-daemon shouldn't need more than 15 to 20 open file descriptors concurrently.</p>
+      </option>
+
+      <option>
+        <p><opt>rlimit-stack=</opt> Value in bytes for RLIMIT_STACK (maximum size of the process stack). Sensible values are heavily system dependent.</p>
+      </option>
+
+      <option>
+        <p><opt>rlimit-nproc=</opt> Value for RLIMIT_NPROC (number of process of user). Since only a single avahi-daemon process is usually running you can set this safely to 1.</p>
+      </option>
+
+    </section>
+
        <section name="Authors">
          <p>The avahi developers &lt;@PACKAGE_BUGREPORT@&gt;; avahi is
          available from <url href="@PACKAGE_URL@"/></p>