LCOV - code coverage report
Current view: top level - basic - socket-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 215 387 55.6 %
Date: 2015-07-29 18:47:03 Functions: 16 25 64.0 %

          Line data    Source code
       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 <string.h>
      23             : #include <unistd.h>
      24             : #include <errno.h>
      25             : #include <arpa/inet.h>
      26             : #include <stdio.h>
      27             : #include <net/if.h>
      28             : #include <sys/types.h>
      29             : #include <stddef.h>
      30             : #include <netdb.h>
      31             : 
      32             : #include "macro.h"
      33             : #include "path-util.h"
      34             : #include "util.h"
      35             : #include "socket-util.h"
      36             : #include "missing.h"
      37             : #include "fileio.h"
      38             : #include "formats-util.h"
      39             : 
      40          45 : int socket_address_parse(SocketAddress *a, const char *s) {
      41             :         char *e, *n;
      42             :         unsigned u;
      43             :         int r;
      44             : 
      45          45 :         assert(a);
      46          45 :         assert(s);
      47             : 
      48          45 :         zero(*a);
      49          45 :         a->type = SOCK_STREAM;
      50             : 
      51          45 :         if (*s == '[') {
      52             :                 /* IPv6 in [x:.....:z]:p notation */
      53             : 
      54          10 :                 e = strchr(s+1, ']');
      55          10 :                 if (!e)
      56           0 :                         return -EINVAL;
      57             : 
      58          10 :                 n = strndupa(s+1, e-s-1);
      59             : 
      60          10 :                 errno = 0;
      61          10 :                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
      62           1 :                         return errno > 0 ? -errno : -EINVAL;
      63             : 
      64           9 :                 e++;
      65           9 :                 if (*e != ':')
      66           2 :                         return -EINVAL;
      67             : 
      68           7 :                 e++;
      69           7 :                 r = safe_atou(e, &u);
      70           7 :                 if (r < 0)
      71           0 :                         return r;
      72             : 
      73           7 :                 if (u <= 0 || u > 0xFFFF)
      74           2 :                         return -EINVAL;
      75             : 
      76           5 :                 a->sockaddr.in6.sin6_family = AF_INET6;
      77           5 :                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
      78           5 :                 a->size = sizeof(struct sockaddr_in6);
      79             : 
      80          35 :         } else if (*s == '/') {
      81             :                 /* AF_UNIX socket */
      82             : 
      83             :                 size_t l;
      84             : 
      85           5 :                 l = strlen(s);
      86           5 :                 if (l >= sizeof(a->sockaddr.un.sun_path))
      87           0 :                         return -EINVAL;
      88             : 
      89           5 :                 a->sockaddr.un.sun_family = AF_UNIX;
      90           5 :                 memcpy(a->sockaddr.un.sun_path, s, l);
      91           5 :                 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
      92             : 
      93          30 :         } else if (*s == '@') {
      94             :                 /* Abstract AF_UNIX socket */
      95             :                 size_t l;
      96             : 
      97           4 :                 l = strlen(s+1);
      98           4 :                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
      99           0 :                         return -EINVAL;
     100             : 
     101           4 :                 a->sockaddr.un.sun_family = AF_UNIX;
     102           4 :                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
     103           4 :                 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
     104             : 
     105             :         } else {
     106          26 :                 e = strchr(s, ':');
     107          26 :                 if (e) {
     108          16 :                         r = safe_atou(e+1, &u);
     109          16 :                         if (r < 0)
     110           1 :                                 return r;
     111             : 
     112          15 :                         if (u <= 0 || u > 0xFFFF)
     113           2 :                                 return -EINVAL;
     114             : 
     115          13 :                         n = strndupa(s, e-s);
     116             : 
     117             :                         /* IPv4 in w.x.y.z:p notation? */
     118          13 :                         r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
     119          13 :                         if (r < 0)
     120           0 :                                 return -errno;
     121             : 
     122          13 :                         if (r > 0) {
     123             :                                 /* Gotcha, it's a traditional IPv4 address */
     124          13 :                                 a->sockaddr.in.sin_family = AF_INET;
     125          13 :                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
     126          13 :                                 a->size = sizeof(struct sockaddr_in);
     127             :                         } else {
     128             :                                 unsigned idx;
     129             : 
     130           0 :                                 if (strlen(n) > IF_NAMESIZE-1)
     131           0 :                                         return -EINVAL;
     132             : 
     133             :                                 /* Uh, our last resort, an interface name */
     134           0 :                                 idx = if_nametoindex(n);
     135           0 :                                 if (idx == 0)
     136           0 :                                         return -EINVAL;
     137             : 
     138           0 :                                 a->sockaddr.in6.sin6_family = AF_INET6;
     139           0 :                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
     140           0 :                                 a->sockaddr.in6.sin6_scope_id = idx;
     141           0 :                                 a->sockaddr.in6.sin6_addr = in6addr_any;
     142           0 :                                 a->size = sizeof(struct sockaddr_in6);
     143             :                         }
     144             :                 } else {
     145             : 
     146             :                         /* Just a port */
     147          10 :                         r = safe_atou(s, &u);
     148          10 :                         if (r < 0)
     149           5 :                                 return r;
     150             : 
     151           5 :                         if (u <= 0 || u > 0xFFFF)
     152           2 :                                 return -EINVAL;
     153             : 
     154           3 :                         if (socket_ipv6_is_supported()) {
     155           3 :                                 a->sockaddr.in6.sin6_family = AF_INET6;
     156           3 :                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
     157           3 :                                 a->sockaddr.in6.sin6_addr = in6addr_any;
     158           3 :                                 a->size = sizeof(struct sockaddr_in6);
     159             :                         } else {
     160           0 :                                 a->sockaddr.in.sin_family = AF_INET;
     161           0 :                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
     162           0 :                                 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
     163           0 :                                 a->size = sizeof(struct sockaddr_in);
     164             :                         }
     165             :                 }
     166             :         }
     167             : 
     168          30 :         return 0;
     169             : }
     170             : 
     171           0 : int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
     172             :         SocketAddress b;
     173             :         int r;
     174             : 
     175             :         /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
     176             : 
     177           0 :         r = socket_address_parse(&b, s);
     178           0 :         if (r < 0)
     179           0 :                 return r;
     180             : 
     181           0 :         if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
     182           0 :                 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
     183           0 :                 return -EAFNOSUPPORT;
     184             :         }
     185             : 
     186           0 :         *a = b;
     187           0 :         return 0;
     188             : }
     189             : 
     190          10 : int socket_address_parse_netlink(SocketAddress *a, const char *s) {
     191             :         int family;
     192          10 :         unsigned group = 0;
     193          20 :         _cleanup_free_ char *sfamily = NULL;
     194          10 :         assert(a);
     195          10 :         assert(s);
     196             : 
     197          10 :         zero(*a);
     198          10 :         a->type = SOCK_RAW;
     199             : 
     200          10 :         errno = 0;
     201          10 :         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
     202           1 :                 return errno > 0 ? -errno : -EINVAL;
     203             : 
     204           9 :         family = netlink_family_from_string(sfamily);
     205           9 :         if (family < 0)
     206           2 :                 return -EINVAL;
     207             : 
     208           7 :         a->sockaddr.nl.nl_family = AF_NETLINK;
     209           7 :         a->sockaddr.nl.nl_groups = group;
     210             : 
     211           7 :         a->type = SOCK_RAW;
     212           7 :         a->size = sizeof(struct sockaddr_nl);
     213           7 :         a->protocol = family;
     214             : 
     215           7 :         return 0;
     216             : }
     217             : 
     218          26 : int socket_address_verify(const SocketAddress *a) {
     219          26 :         assert(a);
     220             : 
     221          26 :         switch (socket_address_family(a)) {
     222             : 
     223             :         case AF_INET:
     224          12 :                 if (a->size != sizeof(struct sockaddr_in))
     225           0 :                         return -EINVAL;
     226             : 
     227          12 :                 if (a->sockaddr.in.sin_port == 0)
     228           0 :                         return -EINVAL;
     229             : 
     230          12 :                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
     231           1 :                         return -EINVAL;
     232             : 
     233          11 :                 return 0;
     234             : 
     235             :         case AF_INET6:
     236           3 :                 if (a->size != sizeof(struct sockaddr_in6))
     237           0 :                         return -EINVAL;
     238             : 
     239           3 :                 if (a->sockaddr.in6.sin6_port == 0)
     240           0 :                         return -EINVAL;
     241             : 
     242           3 :                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
     243           0 :                         return -EINVAL;
     244             : 
     245           3 :                 return 0;
     246             : 
     247             :         case AF_UNIX:
     248           5 :                 if (a->size < offsetof(struct sockaddr_un, sun_path))
     249           0 :                         return -EINVAL;
     250             : 
     251           5 :                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
     252             : 
     253           5 :                         if (a->sockaddr.un.sun_path[0] != 0) {
     254             :                                 char *e;
     255             : 
     256             :                                 /* path */
     257           3 :                                 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
     258           3 :                                 if (!e)
     259           0 :                                         return -EINVAL;
     260             : 
     261           3 :                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
     262           0 :                                         return -EINVAL;
     263             :                         }
     264             :                 }
     265             : 
     266           5 :                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
     267           0 :                         return -EINVAL;
     268             : 
     269           5 :                 return 0;
     270             : 
     271             :         case AF_NETLINK:
     272             : 
     273           6 :                 if (a->size != sizeof(struct sockaddr_nl))
     274           0 :                         return -EINVAL;
     275             : 
     276           6 :                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
     277           0 :                         return -EINVAL;
     278             : 
     279           6 :                 return 0;
     280             : 
     281             :         default:
     282           0 :                 return -EAFNOSUPPORT;
     283             :         }
     284             : }
     285             : 
     286           0 : int socket_address_print(const SocketAddress *a, char **ret) {
     287             :         int r;
     288             : 
     289           0 :         assert(a);
     290           0 :         assert(ret);
     291             : 
     292           0 :         r = socket_address_verify(a);
     293           0 :         if (r < 0)
     294           0 :                 return r;
     295             : 
     296           0 :         if (socket_address_family(a) == AF_NETLINK) {
     297           0 :                 _cleanup_free_ char *sfamily = NULL;
     298             : 
     299           0 :                 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
     300           0 :                 if (r < 0)
     301           0 :                         return r;
     302             : 
     303           0 :                 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
     304           0 :                 if (r < 0)
     305           0 :                         return -ENOMEM;
     306             : 
     307           0 :                 return 0;
     308             :         }
     309             : 
     310           0 :         return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
     311             : }
     312             : 
     313           0 : bool socket_address_can_accept(const SocketAddress *a) {
     314           0 :         assert(a);
     315             : 
     316             :         return
     317           0 :                 a->type == SOCK_STREAM ||
     318           0 :                 a->type == SOCK_SEQPACKET;
     319             : }
     320             : 
     321          13 : bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
     322          13 :         assert(a);
     323          13 :         assert(b);
     324             : 
     325             :         /* Invalid addresses are unequal to all */
     326          26 :         if (socket_address_verify(a) < 0 ||
     327          13 :             socket_address_verify(b) < 0)
     328           1 :                 return false;
     329             : 
     330          12 :         if (a->type != b->type)
     331           0 :                 return false;
     332             : 
     333          12 :         if (socket_address_family(a) != socket_address_family(b))
     334           2 :                 return false;
     335             : 
     336          10 :         switch (socket_address_family(a)) {
     337             : 
     338             :         case AF_INET:
     339           4 :                 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
     340           1 :                         return false;
     341             : 
     342           3 :                 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
     343           1 :                         return false;
     344             : 
     345           2 :                 break;
     346             : 
     347             :         case AF_INET6:
     348           1 :                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
     349           0 :                         return false;
     350             : 
     351           1 :                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
     352           0 :                         return false;
     353             : 
     354           1 :                 break;
     355             : 
     356             :         case AF_UNIX:
     357           4 :                 if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
     358           2 :                     b->size <= offsetof(struct sockaddr_un, sun_path))
     359           0 :                         return false;
     360             : 
     361           2 :                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
     362           0 :                         return false;
     363             : 
     364           2 :                 if (a->sockaddr.un.sun_path[0]) {
     365           1 :                         if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
     366           0 :                                 return false;
     367             :                 } else {
     368           1 :                         if (a->size != b->size)
     369           0 :                                 return false;
     370             : 
     371           1 :                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
     372           0 :                                 return false;
     373             :                 }
     374             : 
     375           2 :                 break;
     376             : 
     377             :         case AF_NETLINK:
     378           3 :                 if (a->protocol != b->protocol)
     379           0 :                         return false;
     380             : 
     381           3 :                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
     382           1 :                         return false;
     383             : 
     384           2 :                 break;
     385             : 
     386             :         default:
     387             :                 /* Cannot compare, so we assume the addresses are different */
     388           0 :                 return false;
     389             :         }
     390             : 
     391           7 :         return true;
     392             : }
     393             : 
     394           3 : bool socket_address_is(const SocketAddress *a, const char *s, int type) {
     395             :         struct SocketAddress b;
     396             : 
     397           3 :         assert(a);
     398           3 :         assert(s);
     399             : 
     400           3 :         if (socket_address_parse(&b, s) < 0)
     401           1 :                 return false;
     402             : 
     403           2 :         b.type = type;
     404             : 
     405           2 :         return socket_address_equal(a, &b);
     406             : }
     407             : 
     408           3 : bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
     409             :         struct SocketAddress b;
     410             : 
     411           3 :         assert(a);
     412           3 :         assert(s);
     413             : 
     414           3 :         if (socket_address_parse_netlink(&b, s) < 0)
     415           1 :                 return false;
     416             : 
     417           2 :         return socket_address_equal(a, &b);
     418             : }
     419             : 
     420           4 : const char* socket_address_get_path(const SocketAddress *a) {
     421           4 :         assert(a);
     422             : 
     423           4 :         if (socket_address_family(a) != AF_UNIX)
     424           2 :                 return NULL;
     425             : 
     426           2 :         if (a->sockaddr.un.sun_path[0] == 0)
     427           1 :                 return NULL;
     428             : 
     429           1 :         return a->sockaddr.un.sun_path;
     430             : }
     431             : 
     432           4 : bool socket_ipv6_is_supported(void) {
     433           8 :         _cleanup_free_ char *l = NULL;
     434             : 
     435           4 :         if (access("/sys/module/ipv6", F_OK) != 0)
     436           0 :                 return false;
     437             : 
     438             :         /* If we can't check "disable" parameter, assume enabled */
     439           4 :         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
     440           0 :                 return true;
     441             : 
     442             :         /* If module was loaded with disable=1 no IPv6 available */
     443           4 :         return l[0] == '0';
     444             : }
     445             : 
     446           0 : bool socket_address_matches_fd(const SocketAddress *a, int fd) {
     447             :         SocketAddress b;
     448             :         socklen_t solen;
     449             : 
     450           0 :         assert(a);
     451           0 :         assert(fd >= 0);
     452             : 
     453           0 :         b.size = sizeof(b.sockaddr);
     454           0 :         if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
     455           0 :                 return false;
     456             : 
     457           0 :         if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
     458           0 :                 return false;
     459             : 
     460           0 :         solen = sizeof(b.type);
     461           0 :         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
     462           0 :                 return false;
     463             : 
     464           0 :         if (b.type != a->type)
     465           0 :                 return false;
     466             : 
     467           0 :         if (a->protocol != 0)  {
     468           0 :                 solen = sizeof(b.protocol);
     469           0 :                 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
     470           0 :                         return false;
     471             : 
     472           0 :                 if (b.protocol != a->protocol)
     473           0 :                         return false;
     474             :         }
     475             : 
     476           0 :         return socket_address_equal(a, &b);
     477             : }
     478             : 
     479           0 : int sockaddr_port(const struct sockaddr *_sa) {
     480           0 :         union sockaddr_union *sa = (union sockaddr_union*) _sa;
     481             : 
     482           0 :         assert(sa);
     483             : 
     484           0 :         if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
     485           0 :                 return -EAFNOSUPPORT;
     486             : 
     487           0 :         return ntohs(sa->sa.sa_family == AF_INET6 ?
     488           0 :                        sa->in6.sin6_port :
     489           0 :                        sa->in.sin_port);
     490             : }
     491             : 
     492           2 : int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
     493           2 :         union sockaddr_union *sa = (union sockaddr_union*) _sa;
     494             :         char *p;
     495             :         int r;
     496             : 
     497           2 :         assert(sa);
     498           2 :         assert(salen >= sizeof(sa->sa.sa_family));
     499             : 
     500           2 :         switch (sa->sa.sa_family) {
     501             : 
     502             :         case AF_INET: {
     503             :                 uint32_t a;
     504             : 
     505           1 :                 a = ntohl(sa->in.sin_addr.s_addr);
     506             : 
     507           1 :                 if (include_port)
     508           3 :                         r = asprintf(&p,
     509             :                                      "%u.%u.%u.%u:%u",
     510           2 :                                      a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
     511           1 :                                      ntohs(sa->in.sin_port));
     512             :                 else
     513           0 :                         r = asprintf(&p,
     514             :                                      "%u.%u.%u.%u",
     515           0 :                                      a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
     516           1 :                 if (r < 0)
     517           0 :                         return -ENOMEM;
     518           1 :                 break;
     519             :         }
     520             : 
     521             :         case AF_INET6: {
     522             :                 static const unsigned char ipv4_prefix[] = {
     523             :                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
     524             :                 };
     525             : 
     526           1 :                 if (translate_ipv6 &&
     527           0 :                     memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
     528           0 :                         const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
     529           0 :                         if (include_port)
     530           0 :                                 r = asprintf(&p,
     531             :                                              "%u.%u.%u.%u:%u",
     532           0 :                                              a[0], a[1], a[2], a[3],
     533           0 :                                              ntohs(sa->in6.sin6_port));
     534             :                         else
     535           0 :                                 r = asprintf(&p,
     536             :                                              "%u.%u.%u.%u",
     537           0 :                                              a[0], a[1], a[2], a[3]);
     538           0 :                         if (r < 0)
     539           0 :                                 return -ENOMEM;
     540             :                 } else {
     541             :                         char a[INET6_ADDRSTRLEN];
     542             : 
     543           1 :                         inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
     544             : 
     545           1 :                         if (include_port) {
     546           1 :                                 r = asprintf(&p,
     547             :                                              "[%s]:%u",
     548             :                                              a,
     549           1 :                                              ntohs(sa->in6.sin6_port));
     550           1 :                                 if (r < 0)
     551           0 :                                         return -ENOMEM;
     552             :                         } else {
     553           0 :                                 p = strdup(a);
     554           0 :                                 if (!p)
     555           0 :                                         return -ENOMEM;
     556             :                         }
     557             :                 }
     558             : 
     559           1 :                 break;
     560             :         }
     561             : 
     562             :         case AF_UNIX:
     563           0 :                 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
     564           0 :                         p = strdup("<unnamed>");
     565           0 :                         if (!p)
     566           0 :                                 return -ENOMEM;
     567             : 
     568           0 :                 } else if (sa->un.sun_path[0] == 0) {
     569             :                         /* abstract */
     570             : 
     571             :                         /* FIXME: We assume we can print the
     572             :                          * socket path here and that it hasn't
     573             :                          * more than one NUL byte. That is
     574             :                          * actually an invalid assumption */
     575             : 
     576           0 :                         p = new(char, sizeof(sa->un.sun_path)+1);
     577           0 :                         if (!p)
     578           0 :                                 return -ENOMEM;
     579             : 
     580           0 :                         p[0] = '@';
     581           0 :                         memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
     582           0 :                         p[sizeof(sa->un.sun_path)] = 0;
     583             : 
     584             :                 } else {
     585           0 :                         p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
     586           0 :                         if (!ret)
     587           0 :                                 return -ENOMEM;
     588             :                 }
     589             : 
     590           0 :                 break;
     591             : 
     592             :         default:
     593           0 :                 return -EOPNOTSUPP;
     594             :         }
     595             : 
     596             : 
     597           2 :         *ret = p;
     598           2 :         return 0;
     599             : }
     600             : 
     601           0 : int getpeername_pretty(int fd, char **ret) {
     602             :         union sockaddr_union sa;
     603           0 :         socklen_t salen = sizeof(sa);
     604             :         int r;
     605             : 
     606           0 :         assert(fd >= 0);
     607           0 :         assert(ret);
     608             : 
     609           0 :         if (getpeername(fd, &sa.sa, &salen) < 0)
     610           0 :                 return -errno;
     611             : 
     612           0 :         if (sa.sa.sa_family == AF_UNIX) {
     613           0 :                 struct ucred ucred = {};
     614             : 
     615             :                 /* UNIX connection sockets are anonymous, so let's use
     616             :                  * PID/UID as pretty credentials instead */
     617             : 
     618           0 :                 r = getpeercred(fd, &ucred);
     619           0 :                 if (r < 0)
     620           0 :                         return r;
     621             : 
     622           0 :                 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
     623           0 :                         return -ENOMEM;
     624             : 
     625           0 :                 return 0;
     626             :         }
     627             : 
     628             :         /* For remote sockets we translate IPv6 addresses back to IPv4
     629             :          * if applicable, since that's nicer. */
     630             : 
     631           0 :         return sockaddr_pretty(&sa.sa, salen, true, true, ret);
     632             : }
     633             : 
     634           0 : int getsockname_pretty(int fd, char **ret) {
     635             :         union sockaddr_union sa;
     636           0 :         socklen_t salen = sizeof(sa);
     637             : 
     638           0 :         assert(fd >= 0);
     639           0 :         assert(ret);
     640             : 
     641           0 :         if (getsockname(fd, &sa.sa, &salen) < 0)
     642           0 :                 return -errno;
     643             : 
     644             :         /* For local sockets we do not translate IPv6 addresses back
     645             :          * to IPv6 if applicable, since this is usually used for
     646             :          * listening sockets where the difference between IPv4 and
     647             :          * IPv6 matters. */
     648             : 
     649           0 :         return sockaddr_pretty(&sa.sa, salen, false, true, ret);
     650             : }
     651             : 
     652           1 : int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
     653             :         int r;
     654             :         char host[NI_MAXHOST], *ret;
     655             : 
     656           1 :         assert(_ret);
     657             : 
     658           1 :         r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
     659             :                         NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
     660           1 :         if (r != 0) {
     661           0 :                 int saved_errno = errno;
     662             : 
     663           0 :                 r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
     664           0 :                 if (r < 0)
     665           0 :                         return log_error_errno(r, "sockadd_pretty() failed: %m");
     666             : 
     667           0 :                 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
     668             :         } else {
     669           1 :                 ret = strdup(host);
     670           1 :                 if (!ret)
     671           0 :                         return log_oom();
     672             :         }
     673             : 
     674           1 :         *_ret = ret;
     675           1 :         return 0;
     676             : }
     677             : 
     678           2 : int getnameinfo_pretty(int fd, char **ret) {
     679             :         union sockaddr_union sa;
     680           2 :         socklen_t salen = sizeof(sa);
     681             : 
     682           2 :         assert(fd >= 0);
     683           2 :         assert(ret);
     684             : 
     685           2 :         if (getsockname(fd, &sa.sa, &salen) < 0)
     686           1 :                 return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
     687             : 
     688           1 :         return socknameinfo_pretty(&sa, salen, ret);
     689             : }
     690             : 
     691           0 : int socket_address_unlink(SocketAddress *a) {
     692           0 :         assert(a);
     693             : 
     694           0 :         if (socket_address_family(a) != AF_UNIX)
     695           0 :                 return 0;
     696             : 
     697           0 :         if (a->sockaddr.un.sun_path[0] == 0)
     698           0 :                 return 0;
     699             : 
     700           0 :         if (unlink(a->sockaddr.un.sun_path) < 0)
     701           0 :                 return -errno;
     702             : 
     703           0 :         return 1;
     704             : }
     705             : 
     706             : static const char* const netlink_family_table[] = {
     707             :         [NETLINK_ROUTE] = "route",
     708             :         [NETLINK_FIREWALL] = "firewall",
     709             :         [NETLINK_INET_DIAG] = "inet-diag",
     710             :         [NETLINK_NFLOG] = "nflog",
     711             :         [NETLINK_XFRM] = "xfrm",
     712             :         [NETLINK_SELINUX] = "selinux",
     713             :         [NETLINK_ISCSI] = "iscsi",
     714             :         [NETLINK_AUDIT] = "audit",
     715             :         [NETLINK_FIB_LOOKUP] = "fib-lookup",
     716             :         [NETLINK_CONNECTOR] = "connector",
     717             :         [NETLINK_NETFILTER] = "netfilter",
     718             :         [NETLINK_IP6_FW] = "ip6-fw",
     719             :         [NETLINK_DNRTMSG] = "dnrtmsg",
     720             :         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
     721             :         [NETLINK_GENERIC] = "generic",
     722             :         [NETLINK_SCSITRANSPORT] = "scsitransport",
     723             :         [NETLINK_ECRYPTFS] = "ecryptfs"
     724             : };
     725             : 
     726           9 : DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
     727             : 
     728             : static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
     729             :         [SOCKET_ADDRESS_DEFAULT] = "default",
     730             :         [SOCKET_ADDRESS_BOTH] = "both",
     731             :         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
     732             : };
     733             : 
     734          10 : DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
     735             : 
     736           5 : bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
     737           5 :         assert(a);
     738           5 :         assert(b);
     739             : 
     740           5 :         if (a->sa.sa_family != b->sa.sa_family)
     741           0 :                 return false;
     742             : 
     743           5 :         if (a->sa.sa_family == AF_INET)
     744           4 :                 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
     745             : 
     746           1 :         if (a->sa.sa_family == AF_INET6)
     747           1 :                 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
     748             : 
     749           0 :         return false;
     750             : }
     751             : 
     752           1 : char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
     753           1 :         assert(addr);
     754           1 :         assert(buffer);
     755             : 
     756             :         /* Like ether_ntoa() but uses %02x instead of %x to print
     757             :          * ethernet addresses, which makes them look less funny. Also,
     758             :          * doesn't use a static buffer. */
     759             : 
     760           6 :         sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
     761           1 :                 addr->ether_addr_octet[0],
     762           1 :                 addr->ether_addr_octet[1],
     763           1 :                 addr->ether_addr_octet[2],
     764           1 :                 addr->ether_addr_octet[3],
     765           1 :                 addr->ether_addr_octet[4],
     766           1 :                 addr->ether_addr_octet[5]);
     767             : 
     768           1 :         return buffer;
     769             : }

Generated by: LCOV version 1.11