Improve proxy server support
[tinc] / src / meta.c
1 /*
2     meta.c -- handle the meta communication
3     Copyright (C) 2000-2018 Guus Sliepen <guus@tinc-vpn.org>,
4                   2000-2005 Ivo Timmermans
5                   2006      Scott Lamb <slamb@slamb.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License along
18     with this program; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include "system.h"
23
24 #include <assert.h>
25
26 #include "cipher.h"
27 #include "connection.h"
28 #include "logger.h"
29 #include "meta.h"
30 #include "net.h"
31 #include "protocol.h"
32 #include "utils.h"
33 #include "proxy.h"
34
35 #ifndef MIN
36 static ssize_t MIN(ssize_t x, ssize_t y) {
37         return x < y ? x : y;
38 }
39 #endif
40
41 bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t length) {
42         (void)type;
43         connection_t *c = handle;
44
45         if(!c) {
46                 logger(DEBUG_ALWAYS, LOG_ERR, "send_meta_sptps() called with NULL pointer!");
47                 abort();
48         }
49
50         buffer_add(&c->outbuf, buffer, length);
51         io_set(&c->io, IO_READ | IO_WRITE);
52
53         return true;
54 }
55
56 bool send_meta(connection_t *c, const void *buffer, size_t length) {
57         if(!c) {
58                 logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
59                 abort();
60         }
61
62         logger(DEBUG_META, LOG_DEBUG, "Sending %lu bytes of metadata to %s (%s)",
63                (unsigned long)length, c->name, c->hostname);
64
65         if(c->protocol_minor >= 2) {
66                 return sptps_send_record(&c->sptps, 0, buffer, length);
67         }
68
69         /* Add our data to buffer */
70         if(c->status.encryptout) {
71 #ifdef DISABLE_LEGACY
72                 return false;
73 #else
74                 assert(c->legacy);
75
76                 if(!decrease_budget(&c->legacy->out, length)) {
77                         logger(DEBUG_META, LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname);
78                         return false;
79                 }
80
81                 size_t outlen = length;
82
83                 if(!cipher_encrypt(&c->legacy->out.cipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
84                         logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting metadata to %s (%s)",
85                                c->name, c->hostname);
86                         return false;
87                 }
88
89 #endif
90         } else {
91                 buffer_add(&c->outbuf, buffer, length);
92         }
93
94         io_set(&c->io, IO_READ | IO_WRITE);
95
96         return true;
97 }
98
99 void send_meta_raw(connection_t *c, const void *buffer, size_t length) {
100         if(!c) {
101                 logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
102                 abort();
103         }
104
105         logger(DEBUG_META, LOG_DEBUG, "Sending %lu bytes of raw metadata to %s (%s)",
106                (unsigned long)length, c->name, c->hostname);
107
108         buffer_add(&c->outbuf, buffer, length);
109
110         io_set(&c->io, IO_READ | IO_WRITE);
111 }
112
113 void broadcast_meta(connection_t *from, const char *buffer, size_t length) {
114         for list_each(connection_t, c, &connection_list)
115                 if(c != from && c->edge) {
116                         send_meta(c, buffer, length);
117                 }
118 }
119
120 bool receive_meta_sptps(void *handle, uint8_t type, const void *vdata, uint16_t length) {
121         const char *data = vdata;
122         connection_t *c = handle;
123
124         if(!c) {
125                 logger(DEBUG_ALWAYS, LOG_ERR, "receive_meta_sptps() called with NULL pointer!");
126                 abort();
127         }
128
129         if(type == SPTPS_HANDSHAKE) {
130                 if(c->allow_request == ACK) {
131                         return send_ack(c);
132                 } else {
133                         return true;
134                 }
135         }
136
137         if(!data) {
138                 return true;
139         }
140
141         /* Are we receiving a TCPpacket? */
142
143         if(c->tcplen) {
144                 if(length != c->tcplen) {
145                         return false;
146                 }
147
148                 receive_tcppacket(c, data, length);
149                 c->tcplen = 0;
150                 return true;
151         }
152
153         /* Change newline to null byte, just like non-SPTPS requests */
154
155         if(data[length - 1] == '\n') {
156                 ((char *)data)[length - 1] = 0;
157         }
158
159         /* Otherwise we are waiting for a request */
160
161         return receive_request(c, data);
162 }
163
164 bool receive_meta(connection_t *c) {
165         ssize_t inlen;
166         char inbuf[MAXBUFSIZE];
167         char *bufp = inbuf, *endp;
168
169         /* Strategy:
170            - Read as much as possible from the TCP socket in one go.
171            - Decrypt it.
172            - Check if a full request is in the input buffer.
173            - If yes, process request and remove it from the buffer,
174            then check again.
175            - If not, keep stuff in buffer and exit.
176          */
177
178         buffer_compact(&c->inbuf, MAXBUFSIZE);
179
180         if(sizeof(inbuf) <= c->inbuf.len) {
181                 logger(DEBUG_ALWAYS, LOG_ERR, "Input buffer full for %s (%s)", c->name, c->hostname);
182                 return false;
183         }
184
185         inlen = recv(c->socket, inbuf, sizeof(inbuf) - c->inbuf.len, 0);
186
187         if(inlen <= 0) {
188                 if(!inlen || !sockerrno) {
189                         logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)",
190                                c->name, c->hostname);
191                 } else if(sockwouldblock(sockerrno)) {
192                         return true;
193                 } else
194                         logger(DEBUG_ALWAYS, LOG_ERR, "Metadata socket read error for %s (%s): %s",
195                                c->name, c->hostname, sockstrerror(sockerrno));
196
197                 return false;
198         }
199
200         do {
201                 /* Are we receiving a SPTPS packet? */
202
203                 if(c->sptpslen) {
204                         ssize_t len = MIN(inlen, c->sptpslen - c->inbuf.len);
205                         buffer_add(&c->inbuf, bufp, len);
206
207                         char *sptpspacket = buffer_read(&c->inbuf, c->sptpslen);
208
209                         if(!sptpspacket) {
210                                 return true;
211                         }
212
213                         if(!receive_tcppacket_sptps(c, sptpspacket, c->sptpslen)) {
214                                 return false;
215                         }
216
217                         c->sptpslen = 0;
218
219                         bufp += len;
220                         inlen -= len;
221                         continue;
222                 }
223
224                 if(c->protocol_minor >= 2) {
225                         size_t len = sptps_receive_data(&c->sptps, bufp, inlen);
226
227                         if(!len) {
228                                 return false;
229                         }
230
231                         bufp += len;
232                         inlen -= (ssize_t)len;
233                         continue;
234                 }
235
236                 if(!c->status.decryptin) {
237                         endp = memchr(bufp, '\n', inlen);
238
239                         if(endp) {
240                                 endp++;
241                         } else {
242                                 endp = bufp + inlen;
243                         }
244
245                         buffer_add(&c->inbuf, bufp, endp - bufp);
246
247                         inlen -= endp - bufp;
248                         bufp = endp;
249                 } else {
250 #ifdef DISABLE_LEGACY
251                         return false;
252 #else
253                         assert(c->legacy);
254
255                         if(!decrease_budget(&c->legacy->in, (size_t) inlen)) {
256                                 logger(DEBUG_META, LOG_ERR, "Byte limit exceeded for decryption from %s (%s)", c->name, c->hostname);
257                                 return false;
258                         }
259
260                         size_t outlen = inlen;
261
262                         if(!cipher_decrypt(&c->legacy->in.cipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || (size_t)inlen != outlen) {
263                                 logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)",
264                                        c->name, c->hostname);
265                                 return false;
266                         }
267
268                         inlen = 0;
269 #endif
270                 }
271
272                 while(c->inbuf.len) {
273                         /* Are we receiving a TCPpacket? */
274
275                         if(c->tcplen) {
276                                 char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
277
278                                 if(!tcpbuffer) {
279                                         break;
280                                 }
281
282                                 if(!c->node) {
283                                         if(c->outgoing && c->allow_request == ID && (proxytype == PROXY_SOCKS4 || proxytype == PROXY_SOCKS5)) {
284                                                 if(!check_socks_resp(proxytype, tcpbuffer, c->tcplen)) {
285                                                         return false;
286                                                 }
287                                         } else {
288                                                 logger(DEBUG_CONNECTIONS, LOG_ERR, "c->tcplen set but c->node is NULL!");
289                                                 abort();
290                                         }
291                                 } else {
292                                         if(c->allow_request == ALL) {
293                                                 receive_tcppacket(c, tcpbuffer, c->tcplen);
294                                         } else {
295                                                 logger(DEBUG_CONNECTIONS, LOG_ERR, "Got unauthorized TCP packet from %s (%s)", c->name, c->hostname);
296                                                 return false;
297                                         }
298                                 }
299
300                                 c->tcplen = 0;
301                         }
302
303                         /* Otherwise we are waiting for a request */
304
305                         char *request = buffer_readline(&c->inbuf);
306
307                         if(request) {
308                                 bool result = receive_request(c, request);
309
310                                 if(!result) {
311                                         return false;
312                                 }
313
314                                 continue;
315                         } else {
316                                 break;
317                         }
318                 }
319         } while(inlen);
320
321         return true;
322 }