pex-msg: fix memory leak on fread fail in pex_msg_update_request_init
[project/unetd.git] / pex-stun.c
1 #include <arpa/inet.h>
2 #include <netinet/in.h>
3 #include <netinet/ip.h>
4 #include <netinet/udp.h>
5 #include <string.h>
6 #include <errno.h>
7
8 #include <libubox/usock.h>
9
10 #include "unetd.h"
11
12 static inline int avl_stun_cmp(const void *k1, const void *k2, void *priv)
13 {
14 return memcmp(k1, k2, 12);
15 }
16
17 static bool has_connected_peer(struct network *net, bool pex)
18 {
19 struct network_peer *peer;
20
21 vlist_for_each_element(&net->peers, peer, node) {
22 if (pex && !peer->pex_port)
23 continue;
24
25 if (peer->state.connected)
26 return true;
27 }
28
29 return false;
30 }
31
32 void network_stun_server_add(struct network *net, const char *host)
33 {
34 struct network_stun *stun = &net->stun;
35 struct network_stun_server *s;
36 char *name_buf;
37
38 s = calloc_a(sizeof(*s), &name_buf, strlen(host) + 1);
39 s->pending_node.key = s->req.transaction;
40 s->host = strcpy(name_buf, host);
41
42 list_add_tail(&s->list, &stun->servers);
43 }
44
45 static void
46 network_stun_close_socket(struct network *net)
47 {
48 struct network_host *local = net->net_config.local_host;
49 struct network_stun *stun = &net->stun;
50
51 if (!stun->wgport_disabled)
52 return;
53
54 D_NET(net, "close STUN socket");
55 uloop_fd_delete(&stun->socket);
56 close(stun->socket.fd);
57 wg_init_local(net, &local->peer);
58 stun->wgport_disabled = false;
59 }
60
61 static void
62 network_stun_socket_cb(struct uloop_fd *fd, unsigned int events)
63 {
64 struct network_stun *stun = container_of(fd, struct network_stun, socket);
65 struct network *net = container_of(stun, struct network, stun);
66 char buf[1024];
67 ssize_t len;
68
69 while (1) {
70 len = recv(fd->fd, buf, sizeof(buf), 0);
71 if (len < 0) {
72 if (errno == EAGAIN)
73 break;
74 if (errno == EINTR)
75 continue;
76
77 perror("recv");
78 network_stun_close_socket(net);
79 return;
80 }
81
82 if (!stun_msg_is_valid(buf, len))
83 continue;
84
85 network_stun_rx_packet(net, buf, len);
86 }
87 }
88
89 static void
90 network_stun_open_socket(struct network *net)
91 {
92 struct network_host *local = net->net_config.local_host;
93 struct network_stun *stun = &net->stun;
94 int fd;
95
96 if (stun->wgport_disabled)
97 return;
98
99 D_NET(net, "open STUN socket");
100 wg_init_local(net, NULL);
101
102 fd = usock(USOCK_SERVER | USOCK_UDP | USOCK_IPV4ONLY | USOCK_NONBLOCK,
103 NULL, usock_port(stun->port_local));
104 if (fd < 0) {
105 wg_init_local(net, &local->peer);
106 return;
107 }
108
109 stun->socket.fd = fd;
110 uloop_fd_add(&stun->socket, ULOOP_READ);
111 stun->wgport_disabled = true;
112 }
113
114 static bool
115 network_stun_query_next(struct network *net)
116 {
117 struct network_stun *stun = &net->stun;
118 struct network_stun_server *s;
119 char addrstr[INET6_ADDRSTRLEN];
120 union network_endpoint ep;
121 uint16_t res_port = 0;
122 const void *msg;
123 ssize_t ret;
124 size_t len;
125
126 s = list_first_entry(&stun->servers, struct network_stun_server, list);
127 if (s->pending)
128 return false;
129
130 /* send next query */
131 if (network_get_endpoint(&ep, AF_INET, s->host, 0, s->seq++) < 0) {
132 D_NET(net, "lookup failed for STUN host %s", s->host);
133 goto out;
134 }
135
136 if (ep.sa.sa_family != AF_INET || !ep.in.sin_port)
137 goto out;
138
139 if (!stun->wgport_disabled && stun->auth_port_ext)
140 res_port = stun->auth_port_ext;
141
142 D_NET(net, "Send STUN query to %s, res_port=%d, wg_disabled=%d",
143 inet_ntop(ep.sa.sa_family, network_endpoint_addr(&ep, NULL),
144 addrstr, sizeof(addrstr)), res_port, stun->wgport_disabled);
145 msg = stun_msg_request_prepare(&s->req, &len, res_port);
146 if (!msg)
147 goto out;
148
149 retry:
150 s->req_auth_port = false;
151 if (stun->wgport_disabled) {
152 ret = sendto(stun->socket.fd, msg, len, 0, &ep.sa, sizeof(ep.in));
153 } else if (!stun->auth_port_ext) {
154 s->req_auth_port = true;
155 ret = sendto(pex_socket(), msg, len, 0, &ep.sa, sizeof(ep.in));
156 } else {
157 struct {
158 struct ip ip;
159 struct udphdr udp;
160 } packet_hdr = {};
161 union network_addr local_addr = {};
162
163 network_get_local_addr(&local_addr, &ep);
164 packet_hdr.ip = (struct ip){
165 .ip_hl = 5,
166 .ip_v = 4,
167 .ip_ttl = 64,
168 .ip_p = IPPROTO_UDP,
169 .ip_src = local_addr.in,
170 .ip_dst = ep.in.sin_addr,
171 };
172 packet_hdr.udp = (struct udphdr){
173 .uh_sport = htons(stun->port_local),
174 .uh_dport = ep.in.sin_port,
175 };
176 ep.in.sin_port = 0;
177
178 ret = sendto_rawudp(pex_raw_socket(AF_INET), &ep,
179 &packet_hdr, sizeof(packet_hdr),
180 msg, len);
181 }
182
183 if (ret < 0 && errno == EINTR)
184 goto retry;
185
186 out:
187 avl_insert(&stun->pending, &s->pending_node);
188 s->pending = true;
189
190 if (!list_is_last(&s->list, &stun->servers))
191 list_move_tail(&s->list, &stun->servers);
192
193 return true;
194 }
195
196 static void
197 network_stun_query_clear_pending(struct network *net)
198 {
199 struct network_stun *stun = &net->stun;
200 struct network_stun_server *s;
201
202 list_for_each_entry(s, &stun->servers, list) {
203 if (!s->pending)
204 continue;
205
206 avl_delete(&stun->pending, &s->pending_node);
207 s->pending = false;
208 }
209 }
210
211 void network_stun_rx_packet(struct network *net, const void *data, size_t len)
212 {
213 struct network_stun *stun = &net->stun;
214 const struct stun_msg_hdr *hdr = data;
215 struct network_stun_server *s;
216
217 s = avl_find_element(&stun->pending, hdr->transaction, s, pending_node);
218 if (!s)
219 return;
220
221 if (!stun_msg_request_complete(&s->req, data, len))
222 return;
223
224 if (!s->req.port)
225 return;
226
227 network_stun_update_port(net, s->req_auth_port, s->req.port);
228 if (s->req_auth_port)
229 stun->state = STUN_STATE_STUN_QUERY_SEND;
230 else
231 stun->state = STUN_STATE_IDLE;
232
233 network_stun_query_clear_pending(net);
234
235 uloop_timeout_set(&stun->timer, 1);
236 }
237
238 static void
239 network_stun_timer_cb(struct uloop_timeout *t)
240 {
241 struct network_stun *stun = container_of(t, struct network_stun, timer);
242 struct network *net = container_of(stun, struct network, stun);
243 unsigned int next = 0;
244
245 restart:
246 switch (stun->state) {
247 case STUN_STATE_IDLE:
248 network_stun_close_socket(net);
249 next = 15 * 60 * 1000;
250 stun->state = STUN_STATE_STUN_QUERY_SEND;
251 D_NET(net, "STUN idle");
252 break;
253 case STUN_STATE_PEX_QUERY_WAIT:
254 stun->state = STUN_STATE_STUN_QUERY_SEND;
255 fallthrough;
256 case STUN_STATE_STUN_QUERY_SEND:
257 if (network_stun_query_next(net)) {
258 next = 50;
259 break;
260 }
261
262 stun->state = STUN_STATE_STUN_QUERY_WAIT;
263 D_NET(net, "wait for STUN server responses");
264 next = 1000;
265 break;
266 case STUN_STATE_STUN_QUERY_WAIT:
267 D_NET(net, "timeout waiting for STUN server responses, retry=%d", stun->retry);
268 network_stun_query_clear_pending(net);
269 if (stun->retry > 0) {
270 stun->retry--;
271 stun->state = STUN_STATE_STUN_QUERY_SEND;
272 goto restart;
273 }
274
275 if (!stun->port_ext && !stun->wgport_disabled) {
276 network_stun_open_socket(net);
277 stun->state = STUN_STATE_STUN_QUERY_SEND;
278 stun->retry = 2;
279 } else {
280 stun->state = STUN_STATE_IDLE;
281 }
282 goto restart;
283 }
284
285 if (next)
286 uloop_timeout_set(t, next);
287 }
288
289 void network_stun_update_port(struct network *net, bool auth, uint16_t val)
290 {
291 struct network_stun *stun = &net->stun;
292 uint16_t *port = auth ? &stun->auth_port_ext : &stun->port_ext;
293
294 D_NET(net, "Update external %s port: %d", auth ? "auth" : "data", val);
295 *port = val;
296 }
297
298 void network_stun_start(struct network *net)
299 {
300 struct network_host *local = net->net_config.local_host;
301 struct network_stun *stun = &net->stun;
302 unsigned int next = 1;
303
304 if (!local || list_empty(&stun->servers))
305 return;
306
307 if (local->peer.port != stun->port_local) {
308 stun->port_ext = 0;
309 stun->port_local = local->peer.port;
310 }
311
312 if (!stun->port_ext && has_connected_peer(net, true)) {
313 D_NET(net, "wait for port information from PEX");
314 stun->state = STUN_STATE_PEX_QUERY_WAIT;
315 next = 60 * 1000;
316 } else {
317 if (!stun->port_ext && !has_connected_peer(net, false))
318 network_stun_open_socket(net);
319
320 stun->state = STUN_STATE_STUN_QUERY_SEND;
321 stun->retry = 2;
322 }
323
324 uloop_timeout_set(&stun->timer, next);
325 }
326
327 void network_stun_init(struct network *net)
328 {
329 struct network_stun *stun = &net->stun;
330
331 stun->socket.cb = network_stun_socket_cb;
332 stun->timer.cb = network_stun_timer_cb;
333 INIT_LIST_HEAD(&stun->servers);
334 avl_init(&stun->pending, avl_stun_cmp, true, NULL);
335 }
336
337 void network_stun_free(struct network *net)
338 {
339 struct network_stun *stun = &net->stun;
340 struct network_stun_server *s, *tmp;
341
342 uloop_timeout_cancel(&stun->timer);
343 network_stun_close_socket(net);
344
345 avl_remove_all_elements(&stun->pending, s, pending_node, tmp)
346 s->pending = false;
347
348 list_for_each_entry_safe(s, tmp, &stun->servers, list) {
349 list_del(&s->list);
350 free(s);
351 }
352 }