LCOV - code coverage report
Current view: top level - nspawn - nspawn-expose-ports.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 8 117 6.8 %
Date: 2019-08-23 13:36:53 Functions: 2 6 33.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 3 114 2.6 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "sd-netlink.h"
       4                 :            : 
       5                 :            : #include "alloc-util.h"
       6                 :            : #include "fd-util.h"
       7                 :            : #include "firewall-util.h"
       8                 :            : #include "in-addr-util.h"
       9                 :            : #include "local-addresses.h"
      10                 :            : #include "netlink-util.h"
      11                 :            : #include "nspawn-expose-ports.h"
      12                 :            : #include "parse-util.h"
      13                 :            : #include "socket-util.h"
      14                 :            : #include "string-util.h"
      15                 :            : #include "util.h"
      16                 :            : 
      17                 :          0 : int expose_port_parse(ExposePort **l, const char *s) {
      18                 :            : 
      19                 :            :         const char *split, *e;
      20                 :            :         uint16_t container_port, host_port;
      21                 :            :         int protocol;
      22                 :            :         ExposePort *p;
      23                 :            :         int r;
      24                 :            : 
      25         [ #  # ]:          0 :         assert(l);
      26         [ #  # ]:          0 :         assert(s);
      27                 :            : 
      28         [ #  # ]:          0 :         if ((e = startswith(s, "tcp:")))
      29                 :          0 :                 protocol = IPPROTO_TCP;
      30         [ #  # ]:          0 :         else if ((e = startswith(s, "udp:")))
      31                 :          0 :                 protocol = IPPROTO_UDP;
      32                 :            :         else {
      33                 :          0 :                 e = s;
      34                 :          0 :                 protocol = IPPROTO_TCP;
      35                 :            :         }
      36                 :            : 
      37                 :          0 :         split = strchr(e, ':');
      38         [ #  # ]:          0 :         if (split) {
      39                 :          0 :                 char v[split - e + 1];
      40                 :            : 
      41                 :          0 :                 memcpy(v, e, split - e);
      42                 :          0 :                 v[split - e] = 0;
      43                 :            : 
      44                 :          0 :                 r = parse_ip_port(v, &host_port);
      45         [ #  # ]:          0 :                 if (r < 0)
      46                 :          0 :                         return -EINVAL;
      47                 :            : 
      48                 :          0 :                 r = parse_ip_port(split + 1, &container_port);
      49                 :            :         } else {
      50                 :          0 :                 r = parse_ip_port(e, &container_port);
      51                 :          0 :                 host_port = container_port;
      52                 :            :         }
      53                 :            : 
      54         [ #  # ]:          0 :         if (r < 0)
      55                 :          0 :                 return -EINVAL;
      56                 :            : 
      57         [ #  # ]:          0 :         LIST_FOREACH(ports, p, *l)
      58   [ #  #  #  # ]:          0 :                 if (p->protocol == protocol && p->host_port == host_port)
      59                 :          0 :                         return -EEXIST;
      60                 :            : 
      61                 :          0 :         p = new(ExposePort, 1);
      62         [ #  # ]:          0 :         if (!p)
      63                 :          0 :                 return -ENOMEM;
      64                 :            : 
      65                 :          0 :         p->protocol = protocol;
      66                 :          0 :         p->host_port = host_port;
      67                 :          0 :         p->container_port = container_port;
      68                 :            : 
      69   [ #  #  #  # ]:          0 :         LIST_PREPEND(ports, *l, p);
      70                 :            : 
      71                 :          0 :         return 0;
      72                 :            : }
      73                 :            : 
      74                 :         16 : void expose_port_free_all(ExposePort *p) {
      75                 :            : 
      76         [ -  + ]:         16 :         while (p) {
      77                 :          0 :                 ExposePort *q = p;
      78   [ #  #  #  #  :          0 :                 LIST_REMOVE(ports, p, q);
             #  #  #  # ]
      79                 :          0 :                 free(q);
      80                 :            :         }
      81                 :         16 : }
      82                 :            : 
      83                 :         16 : int expose_port_flush(ExposePort* l, union in_addr_union *exposed) {
      84                 :            :         ExposePort *p;
      85                 :         16 :         int r, af = AF_INET;
      86                 :            : 
      87         [ -  + ]:         16 :         assert(exposed);
      88                 :            : 
      89         [ +  - ]:         16 :         if (!l)
      90                 :         16 :                 return 0;
      91                 :            : 
      92         [ #  # ]:          0 :         if (in_addr_is_null(af, exposed))
      93                 :          0 :                 return 0;
      94                 :            : 
      95         [ #  # ]:          0 :         log_debug("Lost IP address.");
      96                 :            : 
      97         [ #  # ]:          0 :         LIST_FOREACH(ports, p, l) {
      98                 :          0 :                 r = fw_add_local_dnat(false,
      99                 :            :                                       af,
     100                 :            :                                       p->protocol,
     101                 :            :                                       NULL,
     102                 :            :                                       NULL, 0,
     103                 :            :                                       NULL, 0,
     104                 :          0 :                                       p->host_port,
     105                 :            :                                       exposed,
     106                 :          0 :                                       p->container_port,
     107                 :            :                                       NULL);
     108         [ #  # ]:          0 :                 if (r < 0)
     109         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to modify firewall: %m");
     110                 :            :         }
     111                 :            : 
     112                 :          0 :         *exposed = IN_ADDR_NULL;
     113                 :          0 :         return 0;
     114                 :            : }
     115                 :            : 
     116                 :          0 : int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *exposed) {
     117                 :          0 :         _cleanup_free_ struct local_address *addresses = NULL;
     118                 :          0 :         _cleanup_free_ char *pretty = NULL;
     119                 :            :         union in_addr_union new_exposed;
     120                 :            :         ExposePort *p;
     121                 :            :         bool add;
     122                 :          0 :         int af = AF_INET, r;
     123                 :            : 
     124         [ #  # ]:          0 :         assert(exposed);
     125                 :            : 
     126                 :            :         /* Invoked each time an address is added or removed inside the
     127                 :            :          * container */
     128                 :            : 
     129         [ #  # ]:          0 :         if (!l)
     130                 :          0 :                 return 0;
     131                 :            : 
     132                 :          0 :         r = local_addresses(rtnl, 0, af, &addresses);
     133         [ #  # ]:          0 :         if (r < 0)
     134         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to enumerate local addresses: %m");
     135                 :            : 
     136                 :          0 :         add = r > 0 &&
     137   [ #  #  #  # ]:          0 :                 addresses[0].family == af &&
     138         [ #  # ]:          0 :                 addresses[0].scope < RT_SCOPE_LINK;
     139                 :            : 
     140         [ #  # ]:          0 :         if (!add)
     141                 :          0 :                 return expose_port_flush(l, exposed);
     142                 :            : 
     143                 :          0 :         new_exposed = addresses[0].address;
     144         [ #  # ]:          0 :         if (in_addr_equal(af, exposed, &new_exposed))
     145                 :          0 :                 return 0;
     146                 :            : 
     147                 :          0 :         in_addr_to_string(af, &new_exposed, &pretty);
     148         [ #  # ]:          0 :         log_debug("New container IP is %s.", strna(pretty));
     149                 :            : 
     150         [ #  # ]:          0 :         LIST_FOREACH(ports, p, l) {
     151                 :            : 
     152         [ #  # ]:          0 :                 r = fw_add_local_dnat(true,
     153                 :            :                                       af,
     154                 :            :                                       p->protocol,
     155                 :            :                                       NULL,
     156                 :            :                                       NULL, 0,
     157                 :            :                                       NULL, 0,
     158                 :          0 :                                       p->host_port,
     159                 :            :                                       &new_exposed,
     160                 :          0 :                                       p->container_port,
     161                 :          0 :                                       in_addr_is_null(af, exposed) ? NULL : exposed);
     162         [ #  # ]:          0 :                 if (r < 0)
     163         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to modify firewall: %m");
     164                 :            :         }
     165                 :            : 
     166                 :          0 :         *exposed = new_exposed;
     167                 :          0 :         return 0;
     168                 :            : }
     169                 :            : 
     170                 :          0 : int expose_port_send_rtnl(int send_fd) {
     171                 :          0 :         _cleanup_close_ int fd = -1;
     172                 :            :         int r;
     173                 :            : 
     174         [ #  # ]:          0 :         assert(send_fd >= 0);
     175                 :            : 
     176                 :          0 :         fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
     177         [ #  # ]:          0 :         if (fd < 0)
     178         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to allocate container netlink: %m");
     179                 :            : 
     180                 :            :         /* Store away the fd in the socket, so that it stays open as
     181                 :            :          * long as we run the child */
     182                 :          0 :         r = send_one_fd(send_fd, fd, 0);
     183         [ #  # ]:          0 :         if (r < 0)
     184         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to send netlink fd: %m");
     185                 :            : 
     186                 :          0 :         return 0;
     187                 :            : }
     188                 :            : 
     189                 :          0 : int expose_port_watch_rtnl(
     190                 :            :                 sd_event *event,
     191                 :            :                 int recv_fd,
     192                 :            :                 sd_netlink_message_handler_t handler,
     193                 :            :                 union in_addr_union *exposed,
     194                 :            :                 sd_netlink **ret) {
     195                 :          0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
     196                 :            :         int fd, r;
     197                 :            : 
     198         [ #  # ]:          0 :         assert(event);
     199         [ #  # ]:          0 :         assert(recv_fd >= 0);
     200         [ #  # ]:          0 :         assert(ret);
     201                 :            : 
     202                 :          0 :         fd = receive_one_fd(recv_fd, 0);
     203         [ #  # ]:          0 :         if (fd < 0)
     204         [ #  # ]:          0 :                 return log_error_errno(fd, "Failed to recv netlink fd: %m");
     205                 :            : 
     206                 :          0 :         r = sd_netlink_open_fd(&rtnl, fd);
     207         [ #  # ]:          0 :         if (r < 0) {
     208                 :          0 :                 safe_close(fd);
     209         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create rtnl object: %m");
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         r = sd_netlink_add_match(rtnl, NULL, RTM_NEWADDR, handler, NULL, exposed, "nspawn-NEWADDR");
     213         [ #  # ]:          0 :         if (r < 0)
     214         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to subscribe to RTM_NEWADDR messages: %m");
     215                 :            : 
     216                 :          0 :         r = sd_netlink_add_match(rtnl, NULL, RTM_DELADDR, handler, NULL, exposed, "nspawn-DELADDR");
     217         [ #  # ]:          0 :         if (r < 0)
     218         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to subscribe to RTM_DELADDR messages: %m");
     219                 :            : 
     220                 :          0 :         r = sd_netlink_attach_event(rtnl, event, 0);
     221         [ #  # ]:          0 :         if (r < 0)
     222         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add to event loop: %m");
     223                 :            : 
     224                 :          0 :         *ret = TAKE_PTR(rtnl);
     225                 :            : 
     226                 :          0 :         return 0;
     227                 :            : }

Generated by: LCOV version 1.14