chiark / gitweb /
timedatectl: introduce new command line client for timedated
[elogind.git] / src / shared / socket-util.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 "path-util.h"
39 #include "socket-util.h"
40 #include "missing.h"
41
42 int socket_address_parse(SocketAddress *a, const char *s) {
43         int r;
44         char *e, *n;
45         unsigned u;
46
47         assert(a);
48         assert(s);
49
50         zero(*a);
51         a->type = SOCK_STREAM;
52
53         if (*s == '[') {
54                 /* IPv6 in [x:.....:z]:p notation */
55
56                 if (!socket_ipv6_is_supported()) {
57                         log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
58                         return -EAFNOSUPPORT;
59                 }
60
61                 if (!(e = strchr(s+1, ']')))
62                         return -EINVAL;
63
64                 if (!(n = strndup(s+1, e-s-1)))
65                         return -ENOMEM;
66
67                 errno = 0;
68                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
69                         free(n);
70                         return errno != 0 ? -errno : -EINVAL;
71                 }
72
73                 free(n);
74
75                 e++;
76                 if (*e != ':')
77                         return -EINVAL;
78
79                 e++;
80                 if ((r = safe_atou(e, &u)) < 0)
81                         return r;
82
83                 if (u <= 0 || u > 0xFFFF)
84                         return -EINVAL;
85
86                 a->sockaddr.in6.sin6_family = AF_INET6;
87                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
88                 a->size = sizeof(struct sockaddr_in6);
89
90         } else if (*s == '/') {
91                 /* AF_UNIX socket */
92
93                 size_t l;
94
95                 l = strlen(s);
96                 if (l >= sizeof(a->sockaddr.un.sun_path))
97                         return -EINVAL;
98
99                 a->sockaddr.un.sun_family = AF_UNIX;
100                 memcpy(a->sockaddr.un.sun_path, s, l);
101                 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
102
103         } else if (*s == '@') {
104                 /* Abstract AF_UNIX socket */
105                 size_t l;
106
107                 l = strlen(s+1);
108                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
109                         return -EINVAL;
110
111                 a->sockaddr.un.sun_family = AF_UNIX;
112                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
113                 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
114
115         } else {
116
117                 if ((e = strchr(s, ':'))) {
118
119                         if ((r = safe_atou(e+1, &u)) < 0)
120                                 return r;
121
122                         if (u <= 0 || u > 0xFFFF)
123                                 return -EINVAL;
124
125                         if (!(n = strndup(s, e-s)))
126                                 return -ENOMEM;
127
128                         /* IPv4 in w.x.y.z:p notation? */
129                         if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
130                                 free(n);
131                                 return -errno;
132                         }
133
134                         if (r > 0) {
135                                 /* Gotcha, it's a traditional IPv4 address */
136                                 free(n);
137
138                                 a->sockaddr.in4.sin_family = AF_INET;
139                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
140                                 a->size = sizeof(struct sockaddr_in);
141                         } else {
142                                 unsigned idx;
143
144                                 if (strlen(n) > IF_NAMESIZE-1) {
145                                         free(n);
146                                         return -EINVAL;
147                                 }
148
149                                 /* Uh, our last resort, an interface name */
150                                 idx = if_nametoindex(n);
151                                 free(n);
152
153                                 if (idx == 0)
154                                         return -EINVAL;
155
156                                 if (!socket_ipv6_is_supported()) {
157                                         log_warning("Binding to interface is not available since kernel does not support IPv6.");
158                                         return -EAFNOSUPPORT;
159                                 }
160
161                                 a->sockaddr.in6.sin6_family = AF_INET6;
162                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
163                                 a->sockaddr.in6.sin6_scope_id = idx;
164                                 a->sockaddr.in6.sin6_addr = in6addr_any;
165                                 a->size = sizeof(struct sockaddr_in6);
166                         }
167                 } else {
168
169                         /* Just a port */
170                         r = safe_atou(s, &u);
171                         if (r < 0)
172                                 return r;
173
174                         if (u <= 0 || u > 0xFFFF)
175                                 return -EINVAL;
176
177                         if (socket_ipv6_is_supported()) {
178                                 a->sockaddr.in6.sin6_family = AF_INET6;
179                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
180                                 a->sockaddr.in6.sin6_addr = in6addr_any;
181                                 a->size = sizeof(struct sockaddr_in6);
182                         } else {
183                                 a->sockaddr.in4.sin_family = AF_INET;
184                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
185                                 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
186                                 a->size = sizeof(struct sockaddr_in);
187                         }
188                 }
189         }
190
191         return 0;
192 }
193
194 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
195         int family;
196         unsigned group = 0;
197         char* sfamily = NULL;
198         assert(a);
199         assert(s);
200
201         zero(*a);
202         a->type = SOCK_RAW;
203
204         errno = 0;
205         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
206                 return errno ? -errno : -EINVAL;
207
208         if ((family = netlink_family_from_string(sfamily)) < 0)
209                 if (safe_atoi(sfamily, &family) < 0) {
210                         free(sfamily);
211                         return -EINVAL;
212                 }
213
214         free(sfamily);
215
216         a->sockaddr.nl.nl_family = AF_NETLINK;
217         a->sockaddr.nl.nl_groups = group;
218
219         a->type = SOCK_RAW;
220         a->size = sizeof(struct sockaddr_nl);
221         a->protocol = family;
222
223         return 0;
224 }
225
226 int socket_address_verify(const SocketAddress *a) {
227         assert(a);
228
229         switch (socket_address_family(a)) {
230
231         case AF_INET:
232                 if (a->size != sizeof(struct sockaddr_in))
233                         return -EINVAL;
234
235                 if (a->sockaddr.in4.sin_port == 0)
236                         return -EINVAL;
237
238                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
239                         return -EINVAL;
240
241                 return 0;
242
243         case AF_INET6:
244                 if (a->size != sizeof(struct sockaddr_in6))
245                         return -EINVAL;
246
247                 if (a->sockaddr.in6.sin6_port == 0)
248                         return -EINVAL;
249
250                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
251                         return -EINVAL;
252
253                 return 0;
254
255         case AF_UNIX:
256                 if (a->size < offsetof(struct sockaddr_un, sun_path))
257                         return -EINVAL;
258
259                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
260
261                         if (a->sockaddr.un.sun_path[0] != 0) {
262                                 char *e;
263
264                                 /* path */
265                                 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
266                                         return -EINVAL;
267
268                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
269                                         return -EINVAL;
270                         }
271                 }
272
273                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
274                         return -EINVAL;
275
276                 return 0;
277
278         case AF_NETLINK:
279
280                 if (a->size != sizeof(struct sockaddr_nl))
281                         return -EINVAL;
282
283                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
284                         return -EINVAL;
285
286                 return 0;
287
288         default:
289                 return -EAFNOSUPPORT;
290         }
291 }
292
293 int socket_address_print(const SocketAddress *a, char **p) {
294         int r;
295         assert(a);
296         assert(p);
297
298         if ((r = socket_address_verify(a)) < 0)
299                 return r;
300
301         switch (socket_address_family(a)) {
302
303         case AF_INET: {
304                 char *ret;
305
306                 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
307                         return -ENOMEM;
308
309                 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
310                         free(ret);
311                         return -errno;
312                 }
313
314                 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
315                 *p = ret;
316                 return 0;
317         }
318
319         case AF_INET6: {
320                 char *ret;
321
322                 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
323                         return -ENOMEM;
324
325                 ret[0] = '[';
326                 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
327                         free(ret);
328                         return -errno;
329                 }
330
331                 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
332                 *p = ret;
333                 return 0;
334         }
335
336         case AF_UNIX: {
337                 char *ret;
338
339                 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
340
341                         if (!(ret = strdup("<unnamed>")))
342                                 return -ENOMEM;
343
344                 } else if (a->sockaddr.un.sun_path[0] == 0) {
345                         /* abstract */
346
347                         /* FIXME: We assume we can print the
348                          * socket path here and that it hasn't
349                          * more than one NUL byte. That is
350                          * actually an invalid assumption */
351
352                         if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
353                                 return -ENOMEM;
354
355                         ret[0] = '@';
356                         memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
357                         ret[sizeof(a->sockaddr.un.sun_path)] = 0;
358
359                 } else {
360
361                         if (!(ret = strdup(a->sockaddr.un.sun_path)))
362                                 return -ENOMEM;
363                 }
364
365                 *p = ret;
366                 return 0;
367         }
368
369         case AF_NETLINK: {
370                 const char *sfamily;
371
372                 if ((sfamily = netlink_family_to_string(a->protocol)))
373                         r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
374                 else
375                         r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
376
377                 if (r < 0)
378                         return -ENOMEM;
379
380                 return 0;
381         }
382
383         default:
384                 return -EINVAL;
385         }
386 }
387
388 bool socket_address_can_accept(const SocketAddress *a) {
389         assert(a);
390
391         return
392                 a->type == SOCK_STREAM ||
393                 a->type == SOCK_SEQPACKET;
394 }
395
396 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
397         assert(a);
398         assert(b);
399
400         /* Invalid addresses are unequal to all */
401         if (socket_address_verify(a) < 0 ||
402             socket_address_verify(b) < 0)
403                 return false;
404
405         if (a->type != b->type)
406                 return false;
407
408         if (a->size != b->size)
409                 return false;
410
411         if (socket_address_family(a) != socket_address_family(b))
412                 return false;
413
414         switch (socket_address_family(a)) {
415
416         case AF_INET:
417                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
418                         return false;
419
420                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
421                         return false;
422
423                 break;
424
425         case AF_INET6:
426                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
427                         return false;
428
429                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
430                         return false;
431
432                 break;
433
434         case AF_UNIX:
435
436                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
437                         return false;
438
439                 if (a->sockaddr.un.sun_path[0]) {
440                         if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
441                                 return false;
442                 } else {
443                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
444                                 return false;
445                 }
446
447                 break;
448
449         case AF_NETLINK:
450
451                 if (a->protocol != b->protocol)
452                         return false;
453
454                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
455                         return false;
456
457                 break;
458
459         default:
460                 /* Cannot compare, so we assume the addresses are different */
461                 return false;
462         }
463
464         return true;
465 }
466
467 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
468         struct SocketAddress b;
469
470         assert(a);
471         assert(s);
472
473         if (socket_address_parse(&b, s) < 0)
474                 return false;
475
476         b.type = type;
477
478         return socket_address_equal(a, &b);
479 }
480
481 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
482         struct SocketAddress b;
483
484         assert(a);
485         assert(s);
486
487         if (socket_address_parse_netlink(&b, s) < 0)
488                 return false;
489
490         return socket_address_equal(a, &b);
491 }
492
493 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
494         assert(a);
495
496         if (socket_address_family(a) != AF_UNIX)
497                 return false;
498
499         if (a->sockaddr.un.sun_path[0] == 0)
500                 return false;
501
502         return path_startswith(a->sockaddr.un.sun_path, prefix);
503 }
504
505 bool socket_ipv6_is_supported(void) {
506         char *l = 0;
507         bool enabled;
508
509         if (access("/sys/module/ipv6", F_OK) != 0)
510                 return 0;
511
512         /* If we can't check "disable" parameter, assume enabled */
513         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
514                 return 1;
515
516         /* If module was loaded with disable=1 no IPv6 available */
517         enabled = l[0] == '0';
518         free(l);
519
520         return enabled;
521 }
522
523 static const char* const netlink_family_table[] = {
524         [NETLINK_ROUTE] = "route",
525         [NETLINK_FIREWALL] = "firewall",
526         [NETLINK_INET_DIAG] = "inet-diag",
527         [NETLINK_NFLOG] = "nflog",
528         [NETLINK_XFRM] = "xfrm",
529         [NETLINK_SELINUX] = "selinux",
530         [NETLINK_ISCSI] = "iscsi",
531         [NETLINK_AUDIT] = "audit",
532         [NETLINK_FIB_LOOKUP] = "fib-lookup",
533         [NETLINK_CONNECTOR] = "connector",
534         [NETLINK_NETFILTER] = "netfilter",
535         [NETLINK_IP6_FW] = "ip6-fw",
536         [NETLINK_DNRTMSG] = "dnrtmsg",
537         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
538         [NETLINK_GENERIC] = "generic",
539         [NETLINK_SCSITRANSPORT] = "scsitransport",
540         [NETLINK_ECRYPTFS] = "ecryptfs"
541 };
542
543 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
544
545 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
546         [SOCKET_ADDRESS_DEFAULT] = "default",
547         [SOCKET_ADDRESS_BOTH] = "both",
548         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
549 };
550
551 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);