Improve recently seen address cache
[tinc] / src / protocol_misc.c
1 /*
2     protocol_misc.c -- handle the meta-protocol, miscellaneous functions
3     Copyright (C) 1999-2005 Ivo Timmermans,
4                   2000-2022 Guus Sliepen <guus@tinc-vpn.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "system.h"
22
23 #include "address_cache.h"
24 #include "connection.h"
25 #include "crypto.h"
26 #include "logger.h"
27 #include "meta.h"
28 #include "net.h"
29 #include "netutl.h"
30 #include "protocol.h"
31 #include "utils.h"
32
33 int maxoutbufsize = 0;
34 int mtu_info_interval = 5;
35 int udp_info_interval = 5;
36
37 bool send_termreq(connection_t *c) {
38         return send_request(c, "%d", TERMREQ);
39 }
40
41 bool termreq_h(connection_t *c, const char *request) {
42         (void)c;
43         (void)request;
44         return false;
45 }
46
47 bool send_ping(connection_t *c) {
48         c->status.pinged = true;
49         c->last_ping_time = now.tv_sec;
50
51         return send_request(c, "%d", PING);
52 }
53
54 bool ping_h(connection_t *c, const char *request) {
55         (void)request;
56         return send_pong(c);
57 }
58
59 bool send_pong(connection_t *c) {
60         return send_request(c, "%d", PONG);
61 }
62
63 bool pong_h(connection_t *c, const char *request) {
64         (void)request;
65         c->status.pinged = false;
66
67         /* Successful connection, reset timeout if this is an outgoing connection. */
68
69         if(c->outgoing && c->outgoing->timeout) {
70                 c->outgoing->timeout = 0;
71                 reset_address_cache(c->node->address_cache);
72                 add_recent_address(c->node->address_cache, &c->address);
73         }
74
75         return true;
76 }
77
78 static bool random_early_drop(connection_t *c) {
79         if(c->outbuf.len > (size_t)maxoutbufsize / 2) {
80                 if((c->outbuf.len - (size_t)maxoutbufsize / 2) > prng((size_t)maxoutbufsize / 2)) {
81                         return true;
82                 }
83         }
84
85         return false;
86 }
87
88 /* Sending and receiving packets via TCP */
89
90 bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) {
91         /* If there already is a lot of data in the outbuf buffer, discard this packet.
92            We use a very simple Random Early Drop algorithm. */
93
94         if(random_early_drop(c)) {
95                 return true;
96         }
97
98         if(!send_request(c, "%d %d", PACKET, packet->len)) {
99                 return false;
100         }
101
102         return send_meta(c, DATA(packet), packet->len);
103 }
104
105 bool tcppacket_h(connection_t *c, const char *request) {
106         short int len;
107
108         if(sscanf(request, "%*d %hd", &len) != 1 || len < 0) {
109                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name,
110                        c->hostname);
111                 return false;
112         }
113
114         /* Set reqlen to len, this will tell receive_meta() that a tcppacket is coming. */
115
116         c->tcplen = len;
117
118         return true;
119 }
120
121 bool send_sptps_tcppacket(connection_t *c, const void *packet, size_t len) {
122         /* If there already is a lot of data in the outbuf buffer, discard this packet.
123            We use a very simple Random Early Drop algorithm. */
124
125         if(random_early_drop(c)) {
126                 return true;
127         }
128
129         if(!send_request(c, "%d %lu", SPTPS_PACKET, (unsigned long)len)) {
130                 return false;
131         }
132
133         send_meta_raw(c, packet, len);
134         return true;
135 }
136
137 bool sptps_tcppacket_h(connection_t *c, const char *request) {
138         short int len;
139
140         if(sscanf(request, "%*d %hd", &len) != 1 || len < 0) {
141                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "SPTPS_PACKET", c->name,
142                        c->hostname);
143                 return false;
144         }
145
146         /* Set sptpslen to len, this will tell receive_meta() that a SPTPS packet is coming. */
147
148         c->sptpslen = len;
149
150         return true;
151 }
152
153 /* Transmitting UDP information */
154
155 bool send_udp_info(node_t *from, node_t *to) {
156         /* If there's a static relay in the path, there's no point in sending the message
157            farther than the static relay. */
158         to = (to->via == myself) ? to->nexthop : to->via;
159
160         if(to == NULL) {
161                 logger(DEBUG_ALWAYS, LOG_ERR, "Something went wrong when selecting relay - possible fake UDP_INFO");
162                 return false;
163         }
164
165         /* Skip cases where sending UDP info messages doesn't make sense.
166            This is done here in order to avoid repeating the same logic in multiple callsites. */
167
168         if(to == myself) {
169                 return true;
170         }
171
172         if(!to->status.reachable) {
173                 return true;
174         }
175
176         if(from == myself) {
177                 if(to->connection) {
178                         return true;
179                 }
180
181                 struct timeval elapsed;
182
183                 timersub(&now, &to->udp_info_sent, &elapsed);
184
185                 if(elapsed.tv_sec < udp_info_interval) {
186                         return true;
187                 }
188         }
189
190         if((myself->options | from->options | to->options) & OPTION_TCPONLY) {
191                 return true;
192         }
193
194         if((to->nexthop->options >> 24) < 5) {
195                 return true;
196         }
197
198         char *from_address, *from_port;
199         /* If we're the originator, the address we use is irrelevant
200            because the first intermediate node will ignore it.
201            We use our local address as it somewhat makes sense
202            and it's simpler than introducing an encoding for "null" addresses anyway. */
203         sockaddr2str((from != myself) ? &from->address : &to->nexthop->connection->edge->local_address, &from_address, &from_port);
204
205         bool x = send_request(to->nexthop->connection, "%d %s %s %s %s", UDP_INFO, from->name, to->name, from_address, from_port);
206
207         free(from_address);
208         free(from_port);
209
210         if(from == myself) {
211                 to->udp_info_sent = now;
212         }
213
214         return x;
215 }
216
217 bool udp_info_h(connection_t *c, const char *request) {
218         char from_name[MAX_STRING_SIZE];
219         char to_name[MAX_STRING_SIZE];
220         char from_address[MAX_STRING_SIZE];
221         char from_port[MAX_STRING_SIZE];
222
223         if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, from_address, from_port) != 4) {
224                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "UDP_INFO", c->name, c->hostname);
225                 return false;
226         }
227
228         if(!check_id(from_name) || !check_id(to_name)) {
229                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "UDP_INFO", c->name, c->hostname, "invalid name");
230                 return false;
231         }
232
233         node_t *from = lookup_node(from_name);
234
235         if(!from) {
236                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, from_name);
237                 return true;
238         }
239
240         if(from != from->via) {
241                 /* Not supposed to happen, as it means the message wandered past a static relay */
242                 logger(DEBUG_PROTOCOL, LOG_WARNING, "Got UDP info message from %s (%s) which we can't reach directly", from->name, from->hostname);
243                 return true;
244         }
245
246         /* If we have a direct edge to "from", we are in a better position
247            to guess its address than it is itself. */
248         if(!from->connection && !from->status.udp_confirmed) {
249                 sockaddr_t from_addr = str2sockaddr(from_address, from_port);
250
251                 if(sockaddrcmp(&from_addr, &from->address)) {
252                         update_node_udp(from, &from_addr);
253                 }
254         }
255
256         node_t *to = lookup_node(to_name);
257
258         if(!to) {
259                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, to_name);
260                 return true;
261         }
262
263         /* Send our own data (which could be what we just received) up the chain. */
264
265         return send_udp_info(from, to);
266 }
267
268 /* Transmitting MTU information */
269
270 bool send_mtu_info(node_t *from, node_t *to, int mtu) {
271         /* Skip cases where sending MTU info messages doesn't make sense.
272            This is done here in order to avoid repeating the same logic in multiple callsites. */
273
274         if(to == myself) {
275                 return true;
276         }
277
278         if(!to->status.reachable) {
279                 return true;
280         }
281
282         if(from == myself) {
283                 if(to->connection) {
284                         return true;
285                 }
286
287                 struct timeval elapsed;
288
289                 timersub(&now, &to->mtu_info_sent, &elapsed);
290
291                 if(elapsed.tv_sec < mtu_info_interval) {
292                         return true;
293                 }
294         }
295
296         if((to->nexthop->options >> 24) < 6) {
297                 return true;
298         }
299
300         /* We will send the passed-in MTU value, unless we believe ours is better. */
301
302         node_t *via = (from->via == myself) ? from->nexthop : from->via;
303
304         if(from->minmtu == from->maxmtu && from->via == myself) {
305                 /* We have a direct measurement. Override the value entirely.
306                    Note that we only do that if we are sitting as a static relay in the path;
307                    otherwise, we can't guarantee packets will flow through us, and increasing
308                    MTU could therefore end up being too optimistic. */
309                 mtu = from->minmtu;
310         } else if(via->minmtu == via->maxmtu) {
311                 /* Static relay. Ensure packets will make it through the entire relay path. */
312                 mtu = MIN(mtu, via->minmtu);
313         } else if(via->nexthop->minmtu == via->nexthop->maxmtu) {
314                 /* Dynamic relay. Ensure packets will make it through the entire relay path. */
315                 mtu = MIN(mtu, via->nexthop->minmtu);
316         }
317
318         if(from == myself) {
319                 to->mtu_info_sent = now;
320         }
321
322         /* If none of the conditions above match in the steady state, it means we're using TCP,
323            so the MTU is irrelevant. That said, it is still important to honor the MTU that was passed in,
324            because other parts of the relay path might be able to use UDP, which means they care about the MTU. */
325
326         return send_request(to->nexthop->connection, "%d %s %s %d", MTU_INFO, from->name, to->name, mtu);
327 }
328
329 bool mtu_info_h(connection_t *c, const char *request) {
330         char from_name[MAX_STRING_SIZE];
331         char to_name[MAX_STRING_SIZE];
332         int mtu;
333
334         if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" %d", from_name, to_name, &mtu) != 3) {
335                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "MTU_INFO", c->name, c->hostname);
336                 return false;
337         }
338
339         if(mtu < 512) {
340                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid MTU");
341                 return false;
342         }
343
344         mtu = MIN(mtu, MTU);
345
346         if(!check_id(from_name) || !check_id(to_name)) {
347                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid name");
348                 return false;
349         }
350
351         node_t *from = lookup_node(from_name);
352
353         if(!from) {
354                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, from_name);
355                 return true;
356         }
357
358         /* If we don't know the current MTU for that node, use the one we received.
359            Even if we're about to make our own measurements, the value we got from downstream nodes should be pretty close
360            so it's a good idea to use it in the mean time. */
361         if(from->mtu != mtu && from->minmtu != from->maxmtu) {
362                 logger(DEBUG_TRAFFIC, LOG_INFO, "Using provisional MTU %d for node %s (%s)", mtu, from->name, from->hostname);
363                 from->mtu = mtu;
364         }
365
366         node_t *to = lookup_node(to_name);
367
368         if(!to) {
369                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, to_name);
370                 return true;
371         }
372
373         /* Continue passing the MTU value (or a better one if we have it) up the chain. */
374
375         return send_mtu_info(from, to, mtu);
376 }