Add support for systemd style socket activation.
[tinc] / src / net_setup.c
index bab50fe..d3940e7 100644 (file)
@@ -221,7 +221,6 @@ void load_all_subnets(void) {
        config_t *cfg;
        subnet_t *s, *s2;
        node_t *n;
-       bool result;
 
        xasprintf(&dname, "%s/hosts", confbase);
        dir = opendir(dname);
@@ -243,10 +242,9 @@ void load_all_subnets(void) {
 
                xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);
                init_configuration(&config_tree);
-               result = read_config_file(config_tree, fname);
+               read_config_options(config_tree, ent->d_name);
+               read_config_file(config_tree, fname);
                free(fname);
-               if(!result)
-                       continue;
 
                if(!n) {
                        n = new_node();
@@ -550,6 +548,8 @@ static bool setup_myself(void) {
                        devops = dummy_devops;
                else if(!strcasecmp(type, "raw_socket"))
                        devops = raw_socket_devops;
+               else if(!strcasecmp(type, "multicast"))
+                       devops = multicast_devops;
 #ifdef ENABLE_UML
                else if(!strcasecmp(type, "uml"))
                        devops = uml_devops;
@@ -581,58 +581,112 @@ static bool setup_myself(void) {
 
        /* Open sockets */
 
-       listen_sockets = 0;
-       cfg = lookup_config(config_tree, "BindToAddress");
-
-       do {
-               get_config_string(cfg, &address);
-               if(cfg)
-                       cfg = lookup_config_next(config_tree, cfg);
-
-               hint.ai_family = addressfamily;
-               hint.ai_socktype = SOCK_STREAM;
-               hint.ai_protocol = IPPROTO_TCP;
-               hint.ai_flags = AI_PASSIVE;
+       if(!do_detach && getenv("LISTEN_FDS")) {
+               sockaddr_t sa;
+               socklen_t salen;
 
-               err = getaddrinfo(address, myport, &hint, &ai);
-               free(address);
+               listen_sockets = atoi(getenv("LISTEN_FDS"));
+#ifdef HAVE_UNSETENV
+               unsetenv("LISTEN_FDS");
+#endif
 
-               if(err || !ai) {
-                       logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
-                                  gai_strerror(err));
+               if(listen_sockets > MAXSOCKETS) {
+                       logger(LOG_ERR, "Too many listening sockets");
                        return false;
                }
 
-               for(aip = ai; aip; aip = aip->ai_next) {
-                       if(listen_sockets >= MAXSOCKETS) {
-                               logger(LOG_ERR, "Too many listening sockets");
+               for(i = 0; i < listen_sockets; i++) {
+                       salen = sizeof sa;
+                       if(getsockname(i + 3, &sa.sa, &salen) < 0) {
+                               logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
                                return false;
                        }
 
-                       listen_socket[listen_sockets].tcp =
-                               setup_listen_socket((sockaddr_t *) aip->ai_addr);
-
-                       if(listen_socket[listen_sockets].tcp < 0)
-                               continue;
+                       listen_socket[i].tcp = i + 3;
 
-                       listen_socket[listen_sockets].udp =
-                               setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
+#ifdef FD_CLOEXEC
+                       fcntl(i + 3, F_SETFD, FD_CLOEXEC);
+#endif
 
-                       if(listen_socket[listen_sockets].udp < 0)
-                               continue;
+                       listen_socket[i].udp = setup_vpn_in_socket(&sa);
+                       if(listen_socket[i].udp < 0)
+                               return false;
 
                        ifdebug(CONNECTIONS) {
-                               hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
+                               hostname = sockaddr2hostname(&sa);
                                logger(LOG_NOTICE, "Listening on %s", hostname);
                                free(hostname);
                        }
 
-                       memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
-                       listen_sockets++;
+                       memcpy(&listen_socket[i].sa, &sa, salen);
                }
+       } else {
+               listen_sockets = 0;
+               cfg = lookup_config(config_tree, "BindToAddress");
+
+               do {
+                       get_config_string(cfg, &address);
+                       if(cfg)
+                               cfg = lookup_config_next(config_tree, cfg);
+
+                       char *port = myport;
+
+                       if(address) {
+                               char *space = strchr(address, ' ');
+                               if(space) {
+                                       *space++ = 0;
+                                       port = space;
+                               }
+
+                               if(!strcmp(address, "*"))
+                                       *address = 0;
+                       }
+
+                       hint.ai_family = addressfamily;
+                       hint.ai_socktype = SOCK_STREAM;
+                       hint.ai_protocol = IPPROTO_TCP;
+                       hint.ai_flags = AI_PASSIVE;
+
+                       err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
+                       free(address);
 
-               freeaddrinfo(ai);
-       } while(cfg);
+                       if(err || !ai) {
+                               logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
+                                          gai_strerror(err));
+                               return false;
+                       }
+
+                       for(aip = ai; aip; aip = aip->ai_next) {
+                               if(listen_sockets >= MAXSOCKETS) {
+                                       logger(LOG_ERR, "Too many listening sockets");
+                                       return false;
+                               }
+
+                               listen_socket[listen_sockets].tcp =
+                                       setup_listen_socket((sockaddr_t *) aip->ai_addr);
+
+                               if(listen_socket[listen_sockets].tcp < 0)
+                                       continue;
+
+                               listen_socket[listen_sockets].udp =
+                                       setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
+
+                               if(listen_socket[listen_sockets].udp < 0)
+                                       continue;
+
+                               ifdebug(CONNECTIONS) {
+                                       hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
+                                       logger(LOG_NOTICE, "Listening on %s", hostname);
+                                       free(hostname);
+                               }
+
+                               memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
+                               listen_sockets++;
+                       }
+
+                       freeaddrinfo(ai);
+               } while(cfg);
+       }
 
        if(listen_sockets)
                logger(LOG_NOTICE, "Ready");