Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/basic/socket-label.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include <errno.h>
4
#include <netinet/in.h>
5
#include <stdbool.h>
6
#include <stddef.h>
7
#include <string.h>
8
#include <sys/socket.h>
9
#include <sys/un.h>
10
#include <unistd.h>
11
12
#include "alloc-util.h"
13
#include "fd-util.h"
14
#include "fs-util.h"
15
#include "log.h"
16
#include "macro.h"
17
#include "missing.h"
18
#include "mkdir.h"
19
#include "selinux-util.h"
20
#include "socket-util.h"
21
#include "umask-util.h"
22
23
int socket_address_listen(
24
                const SocketAddress *a,
25
                int flags,
26
                int backlog,
27
                SocketAddressBindIPv6Only only,
28
                const char *bind_to_device,
29
                bool reuse_port,
30
                bool free_bind,
31
                bool transparent,
32
                mode_t directory_mode,
33
                mode_t socket_mode,
34
0
                const char *label) {
35
0
36
0
        _cleanup_close_ int fd = -1;
37
0
        const char *p;
38
0
        int r;
39
0
40
0
        assert(a);
41
0
42
0
        r = socket_address_verify(a, true);
43
0
        if (r < 0)
44
0
                return r;
45
0
46
0
        if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
47
0
                return -EAFNOSUPPORT;
48
0
49
0
        if (label) {
50
0
                r = mac_selinux_create_socket_prepare(label);
51
0
                if (r < 0)
52
0
                        return r;
53
0
        }
54
0
55
0
        fd = socket(socket_address_family(a), a->type | flags, a->protocol);
56
0
        r = fd < 0 ? -errno : 0;
57
0
58
0
        if (label)
59
0
                mac_selinux_create_socket_clear();
60
0
61
0
        if (r < 0)
62
0
                return r;
63
0
64
0
        if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
65
0
                r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY);
66
0
                if (r < 0)
67
0
                        return r;
68
0
        }
69
0
70
0
        if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
71
0
                if (bind_to_device) {
72
0
                        r = socket_bind_to_ifname(fd, bind_to_device);
73
0
                        if (r < 0)
74
0
                                return r;
75
0
                }
76
0
77
0
                if (reuse_port) {
78
0
                        r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true);
79
0
                        if (r < 0)
80
0
                                log_warning_errno(r, "SO_REUSEPORT failed: %m");
81
0
                }
82
0
83
0
                if (free_bind) {
84
0
                        r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
85
0
                        if (r < 0)
86
0
                                log_warning_errno(r, "IP_FREEBIND failed: %m");
87
0
                }
88
0
89
0
                if (transparent) {
90
0
                        r = setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, true);
91
0
                        if (r < 0)
92
0
                                log_warning_errno(r, "IP_TRANSPARENT failed: %m");
93
0
                }
94
0
        }
95
0
96
0
        r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
97
0
        if (r < 0)
98
0
                return r;
99
0
100
0
        p = socket_address_get_path(a);
101
0
        if (p) {
102
0
                /* Create parents */
103
0
                (void) mkdir_parents_label(p, directory_mode);
104
0
105
0
                /* Enforce the right access mode for the socket */
106
0
                RUN_WITH_UMASK(~socket_mode) {
107
0
                        r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
108
0
                        if (r == -EADDRINUSE) {
109
0
                                /* Unlink and try again */
110
0
111
0
                                if (unlink(p) < 0)
112
0
                                        return r; /* didn't work, return original error */
113
0
114
0
                                r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
115
0
                        }
116
0
                        if (r < 0)
117
0
                                return r;
118
0
                }
119
0
        } else {
120
0
                if (bind(fd, &a->sockaddr.sa, a->size) < 0)
121
0
                        return -errno;
122
0
        }
123
0
124
0
        if (socket_address_can_accept(a))
125
0
                if (listen(fd, backlog) < 0)
126
0
                        return -errno;
127
0
128
0
        /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable
129
0
         * gets notified */
130
0
        if (p)
131
0
                (void) touch(p);
132
0
133
0
        r = fd;
134
0
        fd = -1;
135
0
136
0
        return r;
137
0
}
138
139
0
int make_socket_fd(int log_level, const char* address, int type, int flags) {
140
0
        SocketAddress a;
141
0
        int fd, r;
142
0
143
0
        r = socket_address_parse(&a, address);
144
0
        if (r < 0)
145
0
                return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
146
0
147
0
        a.type = type;
148
0
149
0
        fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
150
0
                                   NULL, false, false, false, 0755, 0644, NULL);
151
0
        if (fd < 0 || log_get_max_level() >= log_level) {
152
0
                _cleanup_free_ char *p = NULL;
153
0
154
0
                r = socket_address_print(&a, &p);
155
0
                if (r < 0)
156
0
                        return log_error_errno(r, "socket_address_print(): %m");
157
0
158
0
                if (fd < 0)
159
0
                        log_error_errno(fd, "Failed to listen on %s: %m", p);
160
0
                else
161
0
                        log_full(log_level, "Listening on %s", p);
162
0
        }
163
0
164
0
        return fd;
165
0
}