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; }
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 ++; }