chiark / gitweb /
networkd: send hostname to dhcp server
[elogind.git] / src / shared / socket-label.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <arpa/inet.h>
28 #include <stdio.h>
29 #include <net/if.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stddef.h>
33 #include <sys/ioctl.h>
34
35 #include "macro.h"
36 #include "util.h"
37 #include "mkdir.h"
38 #include "socket-util.h"
39 #include "missing.h"
40 #include "label.h"
41
42 int socket_address_listen(
43                 const SocketAddress *a,
44                 int flags,
45                 int backlog,
46                 SocketAddressBindIPv6Only only,
47                 const char *bind_to_device,
48                 bool free_bind,
49                 bool transparent,
50                 mode_t directory_mode,
51                 mode_t socket_mode,
52                 const char *label) {
53
54         _cleanup_close_ int fd = -1;
55         int r, one;
56
57         assert(a);
58
59         r = socket_address_verify(a);
60         if (r < 0)
61                 return r;
62
63         if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
64                 return -EAFNOSUPPORT;
65
66         if (label) {
67                 r = label_socket_set(label);
68                 if (r < 0)
69                         return r;
70         }
71
72         fd = socket(socket_address_family(a), a->type | flags, a->protocol);
73         r = fd < 0 ? -errno : 0;
74
75         if (label)
76                 label_socket_clear();
77
78         if (r < 0)
79                 return r;
80
81         if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
82                 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
83
84                 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
85                         return -errno;
86         }
87
88         if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
89                 if (bind_to_device)
90                         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
91                                 return -errno;
92
93                 if (free_bind) {
94                         one = 1;
95                         if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
96                                 log_warning("IP_FREEBIND failed: %m");
97                 }
98
99                 if (transparent) {
100                         one = 1;
101                         if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
102                                 log_warning("IP_TRANSPARENT failed: %m");
103                 }
104         }
105
106         one = 1;
107         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
108                 return -errno;
109
110         if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
111                 mode_t old_mask;
112
113                 /* Create parents */
114                 mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
115
116                 /* Enforce the right access mode for the socket */
117                 old_mask = umask(~ socket_mode);
118
119                 /* Include the original umask in our mask */
120                 umask(~socket_mode | old_mask);
121
122                 r = label_bind(fd, &a->sockaddr.sa, a->size);
123
124                 if (r < 0 && errno == EADDRINUSE) {
125                         /* Unlink and try again */
126                         unlink(a->sockaddr.un.sun_path);
127                         r = bind(fd, &a->sockaddr.sa, a->size);
128                 }
129
130                 umask(old_mask);
131         } else
132                 r = bind(fd, &a->sockaddr.sa, a->size);
133
134         if (r < 0)
135                 return -errno;
136
137         if (socket_address_can_accept(a))
138                 if (listen(fd, backlog) < 0)
139                         return -errno;
140
141         r = fd;
142         fd = -1;
143
144         return r;
145 }
146
147 int make_socket_fd(int log_level, const char* address, int flags) {
148         SocketAddress a;
149         int fd, r;
150
151         r = socket_address_parse(&a, address);
152         if (r < 0) {
153                 log_error("Failed to parse socket: %s", strerror(-r));
154                 return r;
155         }
156
157         fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
158                                    NULL, false, false, 0755, 0644, NULL);
159         if (fd < 0 || log_get_max_level() >= log_level) {
160                 _cleanup_free_ char *p = NULL;
161
162                 r = socket_address_print(&a, &p);
163                 if (r < 0) {
164                         log_error("socket_address_print(): %s", strerror(-r));
165                         return r;
166                 }
167
168                 if (fd < 0)
169                         log_error("Failed to listen on %s: %s", p, strerror(-r));
170                 else
171                         log_full(log_level, "Listening on %s", p);
172         }
173
174         return fd;
175 }