Fix building documentation when using OpenBSD's make.
[tinc] / src / proxy.c
1 /*
2     proxy.c -- Proxy handling functions.
3     Copyright (C) 2015-2017 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "connection.h"
23 #include "logger.h"
24 #include "meta.h"
25 #include "netutl.h"
26 #include "protocol.h"
27 #include "proxy.h"
28 #include "utils.h" //
29
30 proxytype_t proxytype;
31 char *proxyhost;
32 char *proxyport;
33 char *proxyuser;
34 char *proxypass;
35
36 static void update_address_ipv4(connection_t *c, void *address, void *port) {
37         sockaddrfree(&c->address);
38         memset(&c->address, 0, sizeof(c->address));
39         c->address.sa.sa_family = AF_INET;
40
41         if(address) {
42                 memcpy(&c->address.in.sin_addr, address, sizeof(ipv4_t));
43         }
44
45         if(port) {
46                 memcpy(&c->address.in.sin_port, port, sizeof(uint16_t));
47         }
48
49         // OpenSSH -D returns all zero address, set it to 0.0.0.1 to prevent spamming ourselves.
50         if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4)) {
51                 memcpy(&c->address.in.sin_addr, "\0\0\0\01", 4);
52         }
53 }
54
55 static void update_address_ipv6(connection_t *c, void *address, void *port) {
56         sockaddrfree(&c->address);
57         memset(&c->address, 0, sizeof(c->address));
58         c->address.sa.sa_family = AF_INET6;
59
60         if(address) {
61                 memcpy(&c->address.in6.sin6_addr, address, sizeof(ipv6_t));
62         }
63
64         if(port) {
65                 memcpy(&c->address.in6.sin6_port, port, sizeof(uint16_t));
66         }
67
68         // OpenSSH -D returns all zero address, set it to 0100:: to prevent spamming ourselves.
69         if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) {
70                 memcpy(&c->address.in6.sin6_addr, "\01\0\0\0\0\0\0\0", 8);
71         }
72 }
73
74 bool send_proxyrequest(connection_t *c) {
75         switch(proxytype) {
76         case PROXY_SOCKS4:
77                 if(c->address.sa.sa_family != AF_INET) {
78                         logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!");
79                         return false;
80                 }
81
82         // fallthrough
83         case PROXY_SOCKS4A: {
84                 if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) {
85                         logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!");
86                         return false;
87                 }
88
89                 int len = 9;
90
91                 if(proxyuser) {
92                         len += strlen(proxyuser);
93                 }
94
95                 if(c->address.sa.sa_family == AF_UNKNOWN) {
96                         len += 1 + strlen(c->address.unknown.address);
97                 }
98
99                 char s4req[len];
100                 s4req[0] = 4;
101                 s4req[1] = 1;
102
103                 if(c->address.sa.sa_family == AF_INET) {
104                         memcpy(s4req + 2, &c->address.in.sin_port, 2);
105                         memcpy(s4req + 4, &c->address.in.sin_addr, 4);
106                 } else {
107                         uint16_t port = htons(atoi(c->address.unknown.port));
108                         memcpy(s4req + 2, &port, 2);
109                         memcpy(s4req + 4, "\0\0\0\1", 4);
110                         strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address);
111                 }
112
113                 if(proxyuser) {
114                         strcpy(s4req + 8, proxyuser);
115                 } else {
116                         s4req[8] = 0;
117                 }
118
119                 s4req[sizeof(s4req) - 1] = 0;
120                 c->allow_request = PROXY;
121                 return send_meta(c, s4req, sizeof(s4req));
122         }
123
124         case PROXY_SOCKS5: {
125                 int len = 3 + 6;
126
127                 if(c->address.sa.sa_family == AF_INET) {
128                         len += 4;
129                 } else if(c->address.sa.sa_family == AF_INET6) {
130                         len += 16;
131                 } else if(c->address.sa.sa_family == AF_UNKNOWN) {
132                         len += 1 + strlen(c->address.unknown.address);
133                 } else {
134                         logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
135                         return false;
136                 }
137
138                 if(proxypass) {
139                         len += 3 + strlen(proxyuser) + strlen(proxypass);
140                 }
141
142                 char s5req[len];
143                 int i = 0;
144                 s5req[i++] = 5;
145                 s5req[i++] = 1;
146
147                 if(proxypass) {
148                         s5req[i++] = 2;
149                         s5req[i++] = 1;
150                         s5req[i++] = strlen(proxyuser);
151                         strcpy(s5req + i, proxyuser);
152                         i += strlen(proxyuser);
153                         s5req[i++] = strlen(proxypass);
154                         strcpy(s5req + i, proxypass);
155                         i += strlen(proxypass);
156                 } else {
157                         s5req[i++] = 0;
158                 }
159
160                 s5req[i++] = 5;
161                 s5req[i++] = 1;
162                 s5req[i++] = 0;
163
164                 if(c->address.sa.sa_family == AF_INET) {
165                         s5req[i++] = 1;
166                         memcpy(s5req + i, &c->address.in.sin_addr, 4);
167                         i += 4;
168                         memcpy(s5req + i, &c->address.in.sin_port, 2);
169                         i += 2;
170                 } else if(c->address.sa.sa_family == AF_INET6) {
171                         s5req[i++] = 4;
172                         memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
173                         i += 16;
174                         memcpy(s5req + i, &c->address.in6.sin6_port, 2);
175                         i += 2;
176                 } else if(c->address.sa.sa_family == AF_UNKNOWN) {
177                         s5req[i++] = 3;
178                         int len = strlen(c->address.unknown.address);
179                         s5req[i++] = len;
180                         memcpy(s5req + i, c->address.unknown.address, len);
181                         i += len;
182                         uint16_t port = htons(atoi(c->address.unknown.port));
183                         memcpy(s5req + i, &port, 2);
184                         i += 2;
185                 } else {
186                         logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy");
187                         return false;
188                 }
189
190                 if(i > len) {
191                         abort();
192                 }
193
194                 c->allow_request = PROXY;
195                 return send_meta(c, s5req, sizeof(s5req));
196         }
197
198         case PROXY_HTTP: {
199                 char *host;
200                 char *port;
201
202                 sockaddr2str(&c->address, &host, &port);
203                 send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
204                 free(host);
205                 free(port);
206                 c->allow_request = PROXY;
207                 return true;
208         }
209
210         case PROXY_EXEC:
211                 abort();
212
213         default:
214                 logger(LOG_ERR, "Unknown proxy type");
215                 return false;
216         }
217 }
218
219 int receive_proxy_meta(connection_t *c) {
220         switch(proxytype) {
221         case PROXY_SOCKS4:
222         case PROXY_SOCKS4A:
223                 if(c->buflen < 8) {
224                         return 0;
225                 }
226
227                 if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
228                         if(c->address.sa.sa_family == AF_UNKNOWN) {
229                                 update_address_ipv4(c, c->buffer + 4, c->buffer + 2);
230                         }
231
232                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
233                         c->allow_request = ID;
234                         c->status.proxy_passed = true;
235                         send_id(c);
236                         return 8;
237                 } else {
238                         logger(LOG_ERR, "Proxy request rejected");
239                         return -1;
240                 }
241
242         case PROXY_SOCKS5:
243                 if(c->buflen < 2) {
244                         return 0;
245                 }
246
247                 if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
248                         logger(LOG_ERR, "Proxy authentication method rejected");
249                         return -1;
250                 }
251
252                 int offset = 2;
253
254                 if(c->buffer[1] == 0x02) {
255                         if(c->buflen < 4) {
256                                 return 0;
257                         }
258
259                         if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
260                                 logger(LOG_ERR, "Proxy username/password rejected");
261                                 return -1;
262                         }
263
264                         offset += 2;
265                 }
266
267                 if(c->buflen - offset < 7) {
268                         return 0;
269                 }
270
271                 if(c->buffer[offset] != 0x05  || c->buffer[offset + 1] != 0x00) {
272                         logger(LOG_ERR, "Proxy request rejected");
273                         return -1;
274                 }
275
276                 int replen = offset + 6;
277
278                 switch(c->buffer[offset + 3]) {
279                 case 0x01: // IPv4
280                         if(c->address.sa.sa_family == AF_UNKNOWN) {
281                                 update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
282                         }
283
284                         replen += 4;
285                         break;
286
287                 case 0x03: // Hostname
288                         if(c->address.sa.sa_family == AF_UNKNOWN) {
289                                 update_address_ipv4(c, "\0\0\0\1", "\0\0");
290                         }
291
292                         replen += ((uint8_t *)c->buffer)[offset + 4];
293                         break;
294
295                 case 0x04: // IPv6
296                         if(c->address.sa.sa_family == AF_UNKNOWN) {
297                                 update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
298                         }
299
300                         replen += 16;
301                         break;
302
303                 default:
304                         logger(LOG_ERR, "Proxy reply malformed");
305                         return -1;
306                 }
307
308                 if(c->buflen < replen) {
309                         return 0;
310                 } else {
311                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
312                         c->allow_request = ID;
313                         c->status.proxy_passed = true;
314                         send_id(c);
315                         return replen;
316                 }
317
318         case PROXY_HTTP: {
319                 char *p = memchr(c->buffer, '\n', c->buflen);
320
321                 if(!p || p - c->buffer >= c->buflen) {
322                         return 0;
323                 }
324
325                 while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) {
326                         if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4)) {
327                                 break;
328                         }
329                 }
330
331                 if(!p) {
332                         return 0;
333                 }
334
335                 if(c->buflen < 9) {
336                         return 0;
337                 }
338
339                 if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
340                         if(!strncmp(c->buffer + 9, "200", 3)) {
341                                 if(c->address.sa.sa_family == AF_UNKNOWN) {
342                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
343                                 }
344
345                                 logger(LOG_DEBUG, "Proxy request granted");
346                                 replen = p  + 1 - c->buffer;
347                                 c->allow_request = ID;
348                                 c->status.proxy_passed = true;
349                                 send_id(c);
350                                 return replen;
351                         } else {
352                                 p = memchr(c->buffer, '\n', c->buflen);
353                                 p[-1] = 0;
354                                 logger(LOG_ERR, "Proxy request rejected: %s", c->buffer + 9);
355                                 return false;
356                         }
357                 } else {
358                         logger(LOG_ERR, "Proxy reply malformed");
359                         return -1;
360                 }
361         }
362
363         default:
364                 abort();
365         }
366 }