1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
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.
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.
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/>.
22 #include "sd-netlink.h"
24 #include "alloc-util.h"
26 #include "firewall-util.h"
27 #include "in-addr-util.h"
28 #include "local-addresses.h"
29 #include "netlink-util.h"
30 #include "nspawn-expose-ports.h"
31 #include "parse-util.h"
32 #include "socket-util.h"
33 #include "string-util.h"
36 int expose_port_parse(ExposePort
**l
, const char *s
) {
38 const char *split
, *e
;
39 uint16_t container_port
, host_port
;
47 if ((e
= startswith(s
, "tcp:")))
48 protocol
= IPPROTO_TCP
;
49 else if ((e
= startswith(s
, "udp:")))
50 protocol
= IPPROTO_UDP
;
53 protocol
= IPPROTO_TCP
;
56 split
= strchr(e
, ':');
58 char v
[split
- e
+ 1];
60 memcpy(v
, e
, split
- e
);
63 r
= safe_atou16(v
, &host_port
);
64 if (r
< 0 || host_port
<= 0)
67 r
= safe_atou16(split
+ 1, &container_port
);
69 r
= safe_atou16(e
, &container_port
);
70 host_port
= container_port
;
73 if (r
< 0 || container_port
<= 0)
76 LIST_FOREACH(ports
, p
, *l
)
77 if (p
->protocol
== protocol
&& p
->host_port
== host_port
)
80 p
= new(ExposePort
, 1);
84 p
->protocol
= protocol
;
85 p
->host_port
= host_port
;
86 p
->container_port
= container_port
;
88 LIST_PREPEND(ports
, *l
, p
);
93 void expose_port_free_all(ExposePort
*p
) {
97 LIST_REMOVE(ports
, p
, q
);
102 int expose_port_flush(ExposePort
* l
, union in_addr_union
*exposed
) {
111 if (in_addr_is_null(af
, exposed
))
114 log_debug("Lost IP address.");
116 LIST_FOREACH(ports
, p
, l
) {
117 r
= fw_add_local_dnat(false,
128 log_warning_errno(r
, "Failed to modify firewall: %m");
131 *exposed
= IN_ADDR_NULL
;
135 int expose_port_execute(sd_netlink
*rtnl
, ExposePort
*l
, union in_addr_union
*exposed
) {
136 _cleanup_free_
struct local_address
*addresses
= NULL
;
137 _cleanup_free_
char *pretty
= NULL
;
138 union in_addr_union new_exposed
;
145 /* Invoked each time an address is added or removed inside the
151 r
= local_addresses(rtnl
, 0, af
, &addresses
);
153 return log_error_errno(r
, "Failed to enumerate local addresses: %m");
156 addresses
[0].family
== af
&&
157 addresses
[0].scope
< RT_SCOPE_LINK
;
160 return expose_port_flush(l
, exposed
);
162 new_exposed
= addresses
[0].address
;
163 if (in_addr_equal(af
, exposed
, &new_exposed
))
166 in_addr_to_string(af
, &new_exposed
, &pretty
);
167 log_debug("New container IP is %s.", strna(pretty
));
169 LIST_FOREACH(ports
, p
, l
) {
171 r
= fw_add_local_dnat(true,
180 in_addr_is_null(af
, exposed
) ? NULL
: exposed
);
182 log_warning_errno(r
, "Failed to modify firewall: %m");
185 *exposed
= new_exposed
;
189 int expose_port_send_rtnl(int send_fd
) {
190 _cleanup_close_
int fd
= -1;
193 assert(send_fd
>= 0);
195 fd
= socket(PF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, NETLINK_ROUTE
);
197 return log_error_errno(errno
, "Failed to allocate container netlink: %m");
199 /* Store away the fd in the socket, so that it stays open as
200 * long as we run the child */
201 r
= send_one_fd(send_fd
, fd
, 0);
203 return log_error_errno(r
, "Failed to send netlink fd: %m");
208 int expose_port_watch_rtnl(
211 sd_netlink_message_handler_t handler
,
212 union in_addr_union
*exposed
,
214 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
218 assert(recv_fd
>= 0);
221 fd
= receive_one_fd(recv_fd
, 0);
223 return log_error_errno(fd
, "Failed to recv netlink fd: %m");
225 r
= sd_netlink_open_fd(&rtnl
, fd
);
228 return log_error_errno(r
, "Failed to create rtnl object: %m");
231 r
= sd_netlink_add_match(rtnl
, RTM_NEWADDR
, handler
, exposed
);
233 return log_error_errno(r
, "Failed to subscribe to RTM_NEWADDR messages: %m");
235 r
= sd_netlink_add_match(rtnl
, RTM_DELADDR
, handler
, exposed
);
237 return log_error_errno(r
, "Failed to subscribe to RTM_DELADDR messages: %m");
239 r
= sd_netlink_attach_event(rtnl
, event
, 0);
241 return log_error_errno(r
, "Failed to add to even loop: %m");