Allow compilation from a build directory
[oweals/tinc.git] / 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         if(address)
41                 memcpy(&c->address.in.sin_addr, address, sizeof(ipv4_t));
42         if(port)
43                 memcpy(&c->address.in.sin_port, port, sizeof(uint16_t));
44         // OpenSSH -D returns all zero address, set it to 0.0.0.1 to prevent spamming ourselves.
45         if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4))
46                 memcpy(&c->address.in.sin_addr, "\0\0\0\01", 4);
47 }
48
49 static void update_address_ipv6(connection_t *c, void *address, void *port) {
50         sockaddrfree(&c->address);
51         memset(&c->address, 0, sizeof c->address);
52         c->address.sa.sa_family = AF_INET6;
53         if(address)
54                 memcpy(&c->address.in6.sin6_addr, address, sizeof(ipv6_t));
55         if(port)
56                 memcpy(&c->address.in6.sin6_port, port, sizeof(uint16_t));
57         // OpenSSH -D returns all zero address, set it to 0100:: to prevent spamming ourselves.
58         if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
59                 memcpy(&c->address.in6.sin6_addr, "\01\0\0\0\0\0\0\0", 8);
60 }
61
62 bool send_proxyrequest(connection_t *c) {
63         switch(proxytype) {
64         case PROXY_SOCKS4:
65                 if(c->address.sa.sa_family != AF_INET) {
66                         logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!");
67                         return false;
68                 }
69         case PROXY_SOCKS4A: {
70                 if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) {
71                         logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!");
72                         return false;
73                 }
74                 int len = 9;
75                 if(proxyuser)
76                         len += strlen(proxyuser);
77                 if(c->address.sa.sa_family == AF_UNKNOWN)
78                         len += 1 + strlen(c->address.unknown.address);
79                 char s4req[len];
80                 s4req[0] = 4;
81                 s4req[1] = 1;
82                 if(c->address.sa.sa_family == AF_INET) {
83                         memcpy(s4req + 2, &c->address.in.sin_port, 2);
84                         memcpy(s4req + 4, &c->address.in.sin_addr, 4);
85                 } else {
86                         uint16_t port = htons(atoi(c->address.unknown.port));
87                         memcpy(s4req + 2, &port, 2);
88                         memcpy(s4req + 4, "\0\0\0\1", 4);
89                         strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address);
90                 }
91                 if(proxyuser)
92                         strcpy(s4req + 8, proxyuser);
93                 else
94                         s4req[8] = 0;
95                 s4req[sizeof s4req - 1] = 0;
96                 c->allow_request = PROXY;
97                 return send_meta(c, s4req, sizeof s4req);
98         }
99
100         case PROXY_SOCKS5: {
101                 int len = 3 + 6;
102                 if(c->address.sa.sa_family == AF_INET) {
103                         len += 4;
104                 } else if(c->address.sa.sa_family == AF_INET6) {
105                         len += 16;
106                 } else if(c->address.sa.sa_family == AF_UNKNOWN) {
107                         len += 1 + strlen(c->address.unknown.address);
108                 } else {
109                         logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
110                         return false;
111                 }
112                 if(proxypass)
113                         len += 3 + strlen(proxyuser) + strlen(proxypass);
114                 char s5req[len];
115                 int i = 0;
116                 s5req[i++] = 5;
117                 s5req[i++] = 1;
118                 if(proxypass) {
119                         s5req[i++] = 2;
120                         s5req[i++] = 1;
121                         s5req[i++] = strlen(proxyuser);
122                         strcpy(s5req + i, proxyuser);
123                         i += strlen(proxyuser);
124                         s5req[i++] = strlen(proxypass);
125                         strcpy(s5req + i, proxypass);
126                         i += strlen(proxypass);
127                 } else {
128                         s5req[i++] = 0;
129                 }
130                 s5req[i++] = 5;
131                 s5req[i++] = 1;
132                 s5req[i++] = 0;
133                 if(c->address.sa.sa_family == AF_INET) {
134                         s5req[i++] = 1;
135                         memcpy(s5req + i, &c->address.in.sin_addr, 4);
136                         i += 4;
137                         memcpy(s5req + i, &c->address.in.sin_port, 2);
138                         i += 2;
139                 } else if(c->address.sa.sa_family == AF_INET6) {
140                         s5req[i++] = 4;
141                         memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
142                         i += 16;
143                         memcpy(s5req + i, &c->address.in6.sin6_port, 2);
144                         i += 2;
145                 } else if(c->address.sa.sa_family == AF_UNKNOWN) {
146                         s5req[i++] = 3;
147                         int len = strlen(c->address.unknown.address);
148                         s5req[i++] = len;
149                         memcpy(s5req + i, c->address.unknown.address, len);
150                         i += len;
151                         uint16_t port = htons(atoi(c->address.unknown.port));
152                         memcpy(s5req + i, &port, 2);
153                         i += 2;
154                 } else {
155                         logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy");
156                         return false;
157                 }
158                 if(i > len)
159                         abort();
160                 c->allow_request = PROXY;
161                 return send_meta(c, s5req, sizeof s5req);
162         }
163
164         case PROXY_HTTP: {
165                 char *host;
166                 char *port;
167
168                 sockaddr2str(&c->address, &host, &port);
169                 send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
170                 free(host);
171                 free(port);
172                 c->allow_request = PROXY;
173                 return true;
174         }
175
176         case PROXY_EXEC:
177                 abort();
178
179         default:
180                 logger(LOG_ERR, "Unknown proxy type");
181                 return false;
182         }
183 }
184
185 int receive_proxy_meta(connection_t *c, int start, int lenin) {
186         switch(proxytype) {
187         case PROXY_SOCKS4:
188         case PROXY_SOCKS4A:
189                 if(c->buflen < 8)
190                         return 0;
191                 if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
192                         if(c->address.sa.sa_family == AF_UNKNOWN)
193                                 update_address_ipv4(c, c->buffer + 4, c->buffer + 2);
194
195                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
196                         c->allow_request = ID;
197                         c->status.proxy_passed = true;
198                         send_id(c);
199                         return 8;
200                 } else {
201                         logger(LOG_ERR, "Proxy request rejected");
202                         return -1;
203                 }
204
205         case PROXY_SOCKS5:
206                 if(c->buflen < 2)
207                         return 0;
208                 if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
209                         logger(LOG_ERR, "Proxy authentication method rejected");
210                         return -1;
211                 }
212                 int offset = 2;
213                 if(c->buffer[1] == 0x02) {
214                         if(c->buflen < 4)
215                                 return 0;
216                         if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
217                                 logger(LOG_ERR, "Proxy username/password rejected");
218                                 return -1;
219                         }
220                         offset += 2;
221                 }
222                 if(c->buflen - offset < 7)
223                         return 0;
224                 if(c->buffer[offset] != 0x05  || c->buffer[offset + 1] != 0x00) {
225                         logger(LOG_ERR, "Proxy request rejected");
226                         return -1;
227                 }
228                 int replen = offset + 6;
229                 switch(c->buffer[offset + 3]) {
230                         case 0x01: // IPv4
231                                 if(c->address.sa.sa_family == AF_UNKNOWN)
232                                         update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
233                                 replen += 4;
234                                 break;
235                         case 0x03: // Hostname
236                                 if(c->address.sa.sa_family == AF_UNKNOWN)
237                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
238                                 replen += ((uint8_t *)c->buffer)[offset + 4];
239                                 break;
240                         case 0x04: // IPv6
241                                 if(c->address.sa.sa_family == AF_UNKNOWN)
242                                         update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
243                                 replen += 16;
244                                 break;
245                         default:
246                                 logger(LOG_ERR, "Proxy reply malformed");
247                                 return -1;
248                 }
249                 if(c->buflen < replen) {
250                         return 0;
251                 } else {
252                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
253                         c->allow_request = ID;
254                         c->status.proxy_passed = true;
255                         send_id(c);
256                         return replen;
257                 }
258
259         case PROXY_HTTP: {
260                 char *p = memchr(c->buffer, '\n', c->buflen);
261                 if(!p || p - c->buffer >= c->buflen)
262                         return 0;
263
264                 while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) {
265                         if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4))
266                                 break;
267                 }
268
269                 if(!p)
270                         return 0;
271
272                 if(c->buflen < 9)
273                         return 0;
274
275                 if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
276                         if(!strncmp(c->buffer + 9, "200", 3)) {
277                                 if(c->address.sa.sa_family == AF_UNKNOWN)
278                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
279                                 logger(LOG_DEBUG, "Proxy request granted");
280                                 replen = p  + 1 - c->buffer;
281                                 c->allow_request = ID;
282                                 c->status.proxy_passed = true;
283                                 send_id(c);
284                                 return replen;
285                         } else {
286                                 p = memchr(c->buffer, '\n', c->buflen);
287                                 p[-1] = 0;
288                                 logger(LOG_ERR, "Proxy request rejected: %s", c->buffer + 9);
289                                 return false;
290                         }
291                 } else {
292                         logger(LOG_ERR, "Proxy reply malformed");
293                         return -1;
294                 }
295         }
296
297         default:
298                 abort();
299         }
300 }