socket-label.c revision 1af719edc5958c01c19204fb68d6fc45c9eea85c
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2010 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
8bdbb8d9cbe1d35708385573d70984ab4533812dLennart Poettering#include <assert.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <string.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <unistd.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <errno.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdlib.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <arpa/inet.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdio.h>
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include <net/if.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/types.h>
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include <sys/stat.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stddef.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/ioctl.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "macro.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include "util.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include "mkdir.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "socket-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "missing.h"
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering#include "label.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poetteringint socket_address_listen(
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering const SocketAddress *a,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int flags,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int backlog,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SocketAddressBindIPv6Only only,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *bind_to_device,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool free_bind,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool transparent,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering mode_t directory_mode,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering mode_t socket_mode,
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering const char *label) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_close_ int fd = -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r, one;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(a);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = socket_address_verify(a);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EAFNOSUPPORT;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (label) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = label_socket_set(label);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = socket(socket_address_family(a), a->type | flags, a->protocol);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = fd < 0 ? -errno : 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (label)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen label_socket_clear();
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
74c7b1ed052fc42d9841a5d83d310fa96124c47cLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (bind_to_device)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (free_bind) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering one = 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_warning("IP_FREEBIND failed: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering if (transparent) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen one = 1;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_warning("IP_TRANSPARENT failed: %m");
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
74c7b1ed052fc42d9841a5d83d310fa96124c47cLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering one = 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen mode_t old_mask;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* Create parents */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* Enforce the right access mode for the socket */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering old_mask = umask(~ socket_mode);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* Include the original umask in our mask */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering umask(~socket_mode | old_mask);
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = label_bind(fd, &a->sockaddr.sa, a->size);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0 && errno == EADDRINUSE) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* Unlink and try again */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering unlink(a->sockaddr.un.sun_path);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = bind(fd, &a->sockaddr.sa, a->size);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering umask(old_mask);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering } else
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = bind(fd, &a->sockaddr.sa, a->size);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -errno;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (socket_address_can_accept(a))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (listen(fd, backlog) < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -errno;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = fd;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering fd = -1;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering return r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering}
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poetteringint make_socket_fd(int log_level, const char* address, int flags) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering SocketAddress a;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering int fd, r;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering r = socket_address_parse(&a, address);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_error("Failed to parse socket address \"%s\": %s",
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering address, strerror(-r));
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering NULL, false, false, 0755, 0644, NULL);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (fd < 0 || log_get_max_level() >= log_level) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering _cleanup_free_ char *p = NULL;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = socket_address_print(&a, &p);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_error("socket_address_print(): %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (fd < 0)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers log_error("Failed to listen on %s: %s", p, strerror(-fd));
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering else
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers log_full(log_level, "Listening on %s", p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen