882871ccd11dca4204a0679f0a7bced5706794d3
[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         case PROXY_SOCKS4A: {
83                 if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) {
84                         logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!");
85                         return false;
86                 }
87
88                 int len = 9;
89
90                 if(proxyuser) {
91                         len += strlen(proxyuser);
92                 }
93
94                 if(c->address.sa.sa_family == AF_UNKNOWN) {
95                         len += 1 + strlen(c->address.unknown.address);
96                 }
97
98                 char s4req[len];
99                 s4req[0] = 4;
100                 s4req[1] = 1;
101
102                 if(c->address.sa.sa_family == AF_INET) {
103                         memcpy(s4req + 2, &c->address.in.sin_port, 2);
104                         memcpy(s4req + 4, &c->address.in.sin_addr, 4);
105                 } else {
106                         uint16_t port = htons(atoi(c->address.unknown.port));
107                         memcpy(s4req + 2, &port, 2);
108                         memcpy(s4req + 4, "\0\0\0\1", 4);
109                         strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address);
110                 }
111
112                 if(proxyuser) {
113                         strcpy(s4req + 8, proxyuser);
114                 } else {
115                         s4req[8] = 0;
116                 }
117
118                 s4req[sizeof(s4req) - 1] = 0;
119                 c->allow_request = PROXY;
120                 return send_meta(c, s4req, sizeof(s4req));
121         }
122
123         case PROXY_SOCKS5: {
124                 int len = 3 + 6;
125
126                 if(c->address.sa.sa_family == AF_INET) {
127                         len += 4;
128                 } else if(c->address.sa.sa_family == AF_INET6) {
129                         len += 16;
130                 } else if(c->address.sa.sa_family == AF_UNKNOWN) {
131                         len += 1 + strlen(c->address.unknown.address);
132                 } else {
133                         logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
134                         return false;
135                 }
136
137                 if(proxypass) {
138                         len += 3 + strlen(proxyuser) + strlen(proxypass);
139                 }
140
141                 char s5req[len];
142                 int i = 0;
143                 s5req[i++] = 5;
144                 s5req[i++] = 1;
145
146                 if(proxypass) {
147                         s5req[i++] = 2;
148                         s5req[i++] = 1;
149                         s5req[i++] = strlen(proxyuser);
150                         strcpy(s5req + i, proxyuser);
151                         i += strlen(proxyuser);
152                         s5req[i++] = strlen(proxypass);
153                         strcpy(s5req + i, proxypass);
154                         i += strlen(proxypass);
155                 } else {
156                         s5req[i++] = 0;
157                 }
158
159                 s5req[i++] = 5;
160                 s5req[i++] = 1;
161                 s5req[i++] = 0;
162
163                 if(c->address.sa.sa_family == AF_INET) {
164                         s5req[i++] = 1;
165                         memcpy(s5req + i, &c->address.in.sin_addr, 4);
166                         i += 4;
167                         memcpy(s5req + i, &c->address.in.sin_port, 2);
168                         i += 2;
169                 } else if(c->address.sa.sa_family == AF_INET6) {
170                         s5req[i++] = 4;
171                         memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
172                         i += 16;
173                         memcpy(s5req + i, &c->address.in6.sin6_port, 2);
174                         i += 2;
175                 } else if(c->address.sa.sa_family == AF_UNKNOWN) {
176                         s5req[i++] = 3;
177                         int len = strlen(c->address.unknown.address);
178                         s5req[i++] = len;
179                         memcpy(s5req + i, c->address.unknown.address, len);
180                         i += len;
181                         uint16_t port = htons(atoi(c->address.unknown.port));
182                         memcpy(s5req + i, &port, 2);
183                         i += 2;
184                 } else {
185                         logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy");
186                         return false;
187                 }
188
189                 if(i > len) {
190                         abort();
191                 }
192
193                 c->allow_request = PROXY;
194                 return send_meta(c, s5req, sizeof(s5req));
195         }
196
197         case PROXY_HTTP: {
198                 char *host;
199                 char *port;
200
201                 sockaddr2str(&c->address, &host, &port);
202                 send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
203                 free(host);
204                 free(port);
205                 c->allow_request = PROXY;
206                 return true;
207         }
208
209         case PROXY_EXEC:
210                 abort();
211
212         default:
213                 logger(LOG_ERR, "Unknown proxy type");
214                 return false;
215         }
216 }
217
218 int receive_proxy_meta(connection_t *c, int start, int lenin) {
219         switch(proxytype) {
220         case PROXY_SOCKS4:
221         case PROXY_SOCKS4A:
222                 if(c->buflen < 8) {
223                         return 0;
224                 }
225
226                 if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
227                         if(c->address.sa.sa_family == AF_UNKNOWN) {
228                                 update_address_ipv4(c, c->buffer + 4, c->buffer + 2);
229                         }
230
231                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
232                         c->allow_request = ID;
233                         c->status.proxy_passed = true;
234                         send_id(c);
235                         return 8;
236                 } else {
237                         logger(LOG_ERR, "Proxy request rejected");
238                         return -1;
239                 }
240
241         case PROXY_SOCKS5:
242                 if(c->buflen < 2) {
243                         return 0;
244                 }
245
246                 if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
247                         logger(LOG_ERR, "Proxy authentication method rejected");
248                         return -1;
249                 }
250
251                 int offset = 2;
252
253                 if(c->buffer[1] == 0x02) {
254                         if(c->buflen < 4) {
255                                 return 0;
256                         }
257
258                         if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
259                                 logger(LOG_ERR, "Proxy username/password rejected");
260                                 return -1;
261                         }
262
263                         offset += 2;
264                 }
265
266                 if(c->buflen - offset < 7) {
267                         return 0;
268                 }
269
270                 if(c->buffer[offset] != 0x05  || c->buffer[offset + 1] != 0x00) {
271                         logger(LOG_ERR, "Proxy request rejected");
272                         return -1;
273                 }
274
275                 int replen = offset + 6;
276
277                 switch(c->buffer[offset + 3]) {
278                 case 0x01: // IPv4
279                         if(c->address.sa.sa_family == AF_UNKNOWN) {
280                                 update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
281                         }
282
283                         replen += 4;
284                         break;
285
286                 case 0x03: // Hostname
287                         if(c->address.sa.sa_family == AF_UNKNOWN) {
288                                 update_address_ipv4(c, "\0\0\0\1", "\0\0");
289                         }
290
291                         replen += ((uint8_t *)c->buffer)[offset + 4];
292                         break;
293
294                 case 0x04: // IPv6
295                         if(c->address.sa.sa_family == AF_UNKNOWN) {
296                                 update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
297                         }
298
299                         replen += 16;
300                         break;
301
302                 default:
303                         logger(LOG_ERR, "Proxy reply malformed");
304                         return -1;
305                 }
306
307                 if(c->buflen < replen) {
308                         return 0;
309                 } else {
310                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
311                         c->allow_request = ID;
312                         c->status.proxy_passed = true;
313                         send_id(c);
314                         return replen;
315                 }
316
317         case PROXY_HTTP: {
318                 char *p = memchr(c->buffer, '\n', c->buflen);
319
320                 if(!p || p - c->buffer >= c->buflen) {
321                         return 0;
322                 }
323
324                 while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) {
325                         if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4)) {
326                                 break;
327                         }
328                 }
329
330                 if(!p) {
331                         return 0;
332                 }
333
334                 if(c->buflen < 9) {
335                         return 0;
336                 }
337
338                 if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
339                         if(!strncmp(c->buffer + 9, "200", 3)) {
340                                 if(c->address.sa.sa_family == AF_UNKNOWN) {
341                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
342                                 }
343
344                                 logger(LOG_DEBUG, "Proxy request granted");
345                                 replen = p  + 1 - c->buffer;
346                                 c->allow_request = ID;
347                                 c->status.proxy_passed = true;
348                                 send_id(c);
349                                 return replen;
350                         } else {
351                                 p = memchr(c->buffer, '\n', c->buflen);
352                                 p[-1] = 0;
353                                 logger(LOG_ERR, "Proxy request rejected: %s", c->buffer + 9);
354                                 return false;
355                         }
356                 } else {
357                         logger(LOG_ERR, "Proxy reply malformed");
358                         return -1;
359                 }
360         }
361
362         default:
363                 abort();
364         }
365 }