LCOV - code coverage report
Current view: top level - nspawn - nspawn-expose-ports.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 8 117 6.8 %
Date: 2019-08-22 15:41:25 Functions: 2 6 33.3 %

          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           4 : void expose_port_free_all(ExposePort *p) {
      75             : 
      76           4 :         while (p) {
      77           0 :                 ExposePort *q = p;
      78           0 :                 LIST_REMOVE(ports, p, q);
      79           0 :                 free(q);
      80             :         }
      81           4 : }
      82             : 
      83           4 : int expose_port_flush(ExposePort* l, union in_addr_union *exposed) {
      84             :         ExposePort *p;
      85           4 :         int r, af = AF_INET;
      86             : 
      87           4 :         assert(exposed);
      88             : 
      89           4 :         if (!l)
      90           4 :                 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