Esempio n. 1
0
int socket_address_listen(
                const SocketAddress *a,
                int flags,
                int backlog,
                SocketAddressBindIPv6Only only,
                const char *bind_to_device,
                bool free_bind,
                bool transparent,
                mode_t directory_mode,
                mode_t socket_mode,
                const char *label) {

        _cleanup_close_ int fd = -1;
        int r, one;

        assert(a);

        r = socket_address_verify(a);
        if (r < 0)
                return r;

        if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
                return -EAFNOSUPPORT;

        if (label) {
                r = mac_selinux_create_socket_prepare(label);
                if (r < 0)
                        return r;
        }

        fd = socket(socket_address_family(a), a->type | flags, a->protocol);
        r = fd < 0 ? -errno : 0;

        if (label)
                mac_selinux_create_socket_clear();

        if (r < 0)
                return r;

        if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
                int flag = only == SOCKET_ADDRESS_IPV6_ONLY;

                if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
                        return -errno;
        }

        if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
                if (bind_to_device)
                        if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
                                return -errno;

                if (free_bind) {
                        one = 1;
                        if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
                                log_warning_errno(errno, "IP_FREEBIND failed: %m");
                }

                if (transparent) {
                        one = 1;
                        if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
                                log_warning_errno(errno, "IP_TRANSPARENT failed: %m");
                }
        }

        one = 1;
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
                return -errno;

        if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
                mode_t old_mask;

                /* Create parents */
                mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);

                /* Enforce the right access mode for the socket */
                old_mask = umask(~ socket_mode);

                /* Include the original umask in our mask */
                umask(~socket_mode | old_mask);

                r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);

                if (r < 0 && errno == EADDRINUSE) {
                        /* Unlink and try again */
                        unlink(a->sockaddr.un.sun_path);
                        r = bind(fd, &a->sockaddr.sa, a->size);
                }

                umask(old_mask);
        } else
                r = bind(fd, &a->sockaddr.sa, a->size);

        if (r < 0)
                return -errno;

        if (socket_address_can_accept(a))
                if (listen(fd, backlog) < 0)
                        return -errno;

        r = fd;
        fd = -1;

        return r;
}
Esempio n. 2
0
static int print_socket(const char* desc, int fd) {
        int r;
        SocketAddress addr = {
                .size = sizeof(union sockaddr_union),
                .type = SOCK_STREAM,
        };
        int family;

        r = getsockname(fd, &addr.sockaddr.sa, &addr.size);
        if (r < 0) {
                log_warning("Failed to query socket on fd:%d: %m", fd);
                return 0;
        }

        family = socket_address_family(&addr);
        switch(family) {
        case AF_INET:
        case AF_INET6: {
                char* _cleanup_free_ a = NULL;
                r = socket_address_print(&addr, &a);
                if (r < 0)
                        log_warning("socket_address_print(): %s", strerror(-r));
                else
                        log_info("%s %s address %s",
                                 desc,
                                 family == AF_INET ? "IP" : "IPv6",
                                 a);
                break;
        }
        default:
                log_warning("Connection with unknown family %d", family);
        }

        return 0;
}

static int open_sockets(int *epoll_fd, bool accept) {
        int n, fd;
        int count = 0;
        char **address;

        n = sd_listen_fds(true);
        if (n < 0) {
                log_error("Failed to read listening file descriptors from environment: %s",
                          strerror(-n));
                return n;
        }
        log_info("Received %d descriptors", n);

        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
                log_debug("Received descriptor fd:%d", fd);
                print_socket("Listening on", fd);

                if (!arg_accept) {
                        int r = set_nocloexec(fd);
                        if (r < 0)
                                return r;
                }

                count ++;
        }

        /** Note: we leak some fd's on error here. I doesn't matter
         *  much, since the program will exit immediately anyway, but
         *  would be a pain to fix.
         */

        STRV_FOREACH(address, arg_listen) {
                log_info("Opening address %s", *address);

                fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
                if (fd < 0) {
                        log_error("Failed to open '%s': %s", *address, strerror(-fd));
                        return fd;
                }

                count ++;
        }