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