Throttle the rate of MTU_INFO messages.
[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-2013 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 "conf.h"
24 #include "connection.h"
25 #include "logger.h"
26 #include "meta.h"
27 #include "net.h"
28 #include "netutl.h"
29 #include "protocol.h"
30 #include "utils.h"
31 #include "xalloc.h"
32
33 int maxoutbufsize = 0;
34 int mtu_info_interval = 5;
35 int udp_info_interval = 5;
36
37 /* Status and error notification routines */
38
39 bool send_status(connection_t *c, int statusno, const char *statusstring) {
40         if(!statusstring)
41                 statusstring = "Status";
42
43         return send_request(c, "%d %d %s", STATUS, statusno, statusstring);
44 }
45
46 bool status_h(connection_t *c, const char *request) {
47         int statusno;
48         char statusstring[MAX_STRING_SIZE];
49
50         if(sscanf(request, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
51                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "STATUS",
52                            c->name, c->hostname);
53                 return false;
54         }
55
56         logger(DEBUG_STATUS, LOG_NOTICE, "Status message from %s (%s): %d: %s",
57                            c->name, c->hostname, statusno, statusstring);
58
59         return true;
60 }
61
62 bool send_error(connection_t *c, int err, const char *errstring) {
63         if(!errstring)
64                 errstring = "Error";
65
66         return send_request(c, "%d %d %s", ERROR, err, errstring);
67 }
68
69 bool error_h(connection_t *c, const char *request) {
70         int err;
71         char errorstring[MAX_STRING_SIZE];
72
73         if(sscanf(request, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
74                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ERROR",
75                            c->name, c->hostname);
76                 return false;
77         }
78
79         logger(DEBUG_ERROR, LOG_NOTICE, "Error message from %s (%s): %d: %s",
80                            c->name, c->hostname, err, errorstring);
81
82         return false;
83 }
84
85 bool send_termreq(connection_t *c) {
86         return send_request(c, "%d", TERMREQ);
87 }
88
89 bool termreq_h(connection_t *c, const char *request) {
90         return false;
91 }
92
93 bool send_ping(connection_t *c) {
94         c->status.pinged = true;
95         c->last_ping_time = now.tv_sec;
96
97         return send_request(c, "%d", PING);
98 }
99
100 bool ping_h(connection_t *c, const char *request) {
101         return send_pong(c);
102 }
103
104 bool send_pong(connection_t *c) {
105         return send_request(c, "%d", PONG);
106 }
107
108 bool pong_h(connection_t *c, const char *request) {
109         c->status.pinged = false;
110
111         /* Succesful connection, reset timeout if this is an outgoing connection. */
112
113         if(c->outgoing) {
114                 c->outgoing->timeout = 0;
115                 c->outgoing->cfg = NULL;
116                 if(c->outgoing->ai)
117                         freeaddrinfo(c->outgoing->ai);
118                 c->outgoing->ai = NULL;
119                 c->outgoing->aip = NULL;
120         }
121
122         return true;
123 }
124
125 /* Sending and receiving packets via TCP */
126
127 bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) {
128         /* If there already is a lot of data in the outbuf buffer, discard this packet.
129            We use a very simple Random Early Drop algorithm. */
130
131         if(2.0 * c->outbuf.len / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
132                 return true;
133
134         if(!send_request(c, "%d %hd", PACKET, packet->len))
135                 return false;
136
137         return send_meta(c, (char *)DATA(packet), packet->len);
138 }
139
140 bool tcppacket_h(connection_t *c, const char *request) {
141         short int len;
142
143         if(sscanf(request, "%*d %hd", &len) != 1) {
144                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name,
145                            c->hostname);
146                 return false;
147         }
148
149         /* Set reqlen to len, this will tell receive_meta() that a tcppacket is coming. */
150
151         c->tcplen = len;
152
153         return true;
154 }
155
156 /* Transmitting UDP information */
157
158 bool send_udp_info(node_t *from, node_t *to) {
159         /* If there's a static relay in the path, there's no point in sending the message
160            farther than the static relay. */
161         to = (to->via == myself) ? to->nexthop : to->via;
162
163         /* Skip cases where sending UDP info messages doesn't make sense.
164            This is done here in order to avoid repeating the same logic in multiple callsites. */
165
166         if(to == myself)
167                 return true;
168
169         if(!to->status.reachable)
170                 return true;
171
172         if(from == myself) {
173                 if(to->connection)
174                         return true;
175
176                 struct timeval elapsed;
177                 timersub(&now, &to->udp_info_sent, &elapsed);
178                 if(elapsed.tv_sec < udp_info_interval)
179                         return true;
180         }
181
182         if((myself->options | from->options | to->options) & OPTION_TCPONLY)
183                 return true;
184
185         if((to->nexthop->options >> 24) < 5)
186                 return true;
187
188         char *from_address, *from_port;
189         /* If we're the originator, the address we use is irrelevant
190            because the first intermediate node will ignore it.
191            We use our local address as it somewhat makes sense
192            and it's simpler than introducing an encoding for "null" addresses anyway. */
193         sockaddr2str((from != myself) ? &from->address : &to->nexthop->connection->edge->local_address, &from_address, &from_port);
194
195         bool x = send_request(to->nexthop->connection, "%d %s %s %s %s", UDP_INFO, from->name, to->name, from_address, from_port);
196
197         free(from_address);
198         free(from_port);
199
200         if(from == myself)
201                 to->udp_info_sent = now;
202
203         return x;
204 }
205
206 bool udp_info_h(connection_t *c, const char* request) {
207         char from_name[MAX_STRING_SIZE];
208         char to_name[MAX_STRING_SIZE];
209         char from_address[MAX_STRING_SIZE];
210         char from_port[MAX_STRING_SIZE];
211
212         if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, from_address, from_port) != 4) {
213                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "UDP_INFO", c->name, c->hostname);
214                 return false;
215         }
216
217         if(!check_id(from_name) || !check_id(to_name)) {
218                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "UDP_INFO", c->name, c->hostname, "invalid name");
219                 return false;
220         }
221
222         node_t *from = lookup_node(from_name);
223         if(!from) {
224                 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);
225                 return true;
226         }
227
228         if(from != from->via) {
229                 /* Not supposed to happen, as it means the message wandered past a static relay */
230                 logger(DEBUG_PROTOCOL, LOG_WARNING, "Got UDP info message from %s (%s) which we can't reach directly", from->name, from->hostname);
231                 return true;
232         }
233
234         /* If we have a direct edge to "from", we are in a better position
235            to guess its address than it is itself. */
236         if(!from->connection && !from->status.udp_confirmed) {
237                 sockaddr_t from_addr = str2sockaddr(from_address, from_port);
238                 if(sockaddrcmp(&from_addr, &from->address))
239                         update_node_udp(from, &from_addr);
240         }
241
242         node_t *to = lookup_node(to_name);
243         if(!to) {
244                 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);
245                 return true;
246         }
247
248         /* Send our own data (which could be what we just received) up the chain. */
249
250         return send_udp_info(from, to);
251 }
252
253 /* Transmitting MTU information */
254
255 bool send_mtu_info(node_t *from, node_t *to, int mtu) {
256         /* Skip cases where sending MTU info messages doesn't make sense.
257            This is done here in order to avoid repeating the same logic in multiple callsites. */
258
259         if(to == myself)
260                 return true;
261
262         if(!to->status.reachable)
263                 return true;
264
265         if(from == myself) {
266                 if(to->connection)
267                         return true;
268
269                 struct timeval elapsed;
270                 timersub(&now, &to->mtu_info_sent, &elapsed);
271                 if(elapsed.tv_sec < mtu_info_interval)
272                         return true;
273         }
274
275         if((to->nexthop->options >> 24) < 6)
276                 return true;
277
278         /* We will send the passed-in MTU value, unless we believe ours is better. */
279
280         node_t *via = (from->via == myself) ? from->nexthop : from->via;
281         if(from->minmtu == from->maxmtu && from->via == myself) {
282                 /* We have a direct measurement. Override the value entirely.
283                    Note that we only do that if we are sitting as a static relay in the path;
284                    otherwise, we can't guarantee packets will flow through us, and increasing
285                    MTU could therefore end up being too optimistic. */
286                 mtu = from->minmtu;
287         } else if(via->minmtu == via->maxmtu) {
288                 /* Static relay. Ensure packets will make it through the entire relay path. */
289                 mtu = MIN(mtu, via->minmtu);
290         } else if(via->nexthop->minmtu == via->nexthop->maxmtu) {
291                 /* Dynamic relay. Ensure packets will make it through the entire relay path. */
292                 mtu = MIN(mtu, via->nexthop->minmtu);
293         }
294
295         if(from == myself)
296                 to->mtu_info_sent = now;
297
298         /* If none of the conditions above match in the steady state, it means we're using TCP,
299            so the MTU is irrelevant. That said, it is still important to honor the MTU that was passed in,
300            because other parts of the relay path might be able to use UDP, which means they care about the MTU. */
301
302         return send_request(to->nexthop->connection, "%d %s %s %d", MTU_INFO, from->name, to->name, mtu);
303 }
304
305 bool mtu_info_h(connection_t *c, const char* request) {
306         char from_name[MAX_STRING_SIZE];
307         char to_name[MAX_STRING_SIZE];
308         int mtu;
309
310         if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" %d", from_name, to_name, &mtu) != 3) {
311                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "MTU_INFO", c->name, c->hostname);
312                 return false;
313         }
314
315         if(mtu < 512) {
316                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid MTU");
317                 return false;
318         }
319
320         mtu = MIN(mtu, MTU);
321
322         if(!check_id(from_name) || !check_id(to_name)) {
323                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid name");
324                 return false;
325         }
326
327         node_t *from = lookup_node(from_name);
328         if(!from) {
329                 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);
330                 return true;
331         }
332
333         /* If we don't know the current MTU for that node, use the one we received.
334            Even if we're about to make our own measurements, the value we got from downstream nodes should be pretty close
335            so it's a good idea to use it in the mean time. */
336         if(from->mtu != mtu && from->minmtu != from->maxmtu) {
337                 logger(DEBUG_TRAFFIC, LOG_INFO, "Using provisional MTU %d for node %s (%s)", mtu, from->name, from->hostname);
338                 from->mtu = mtu;
339         }
340
341         node_t *to = lookup_node(to_name);
342         if(!to) {
343                 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);
344                 return true;
345         }
346
347         /* Continue passing the MTU value (or a better one if we have it) up the chain. */
348
349         return send_mtu_info(from, to, mtu);
350 }