Fix Proxy = exec.
[tinc] / src / proxy.c
1 /*
2     proxy.c -- Proxy handling functions.
3     Copyright (C) 2015-2016 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                 c->status.proxy_passed = true;
178                 send_id(c);
179                 return true;
180
181         default:
182                 logger(LOG_ERR, "Unknown proxy type");
183                 return false;
184         }
185 }
186
187 int receive_proxy_meta(connection_t *c, int start, int lenin) {
188         switch(proxytype) {
189         case PROXY_SOCKS4:
190         case PROXY_SOCKS4A:
191                 if(c->buflen < 8)
192                         return 0;
193                 if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
194                         if(c->address.sa.sa_family == AF_UNKNOWN)
195                                 update_address_ipv4(c, c->buffer + 4, c->buffer + 2);
196
197                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
198                         c->allow_request = ID;
199                         c->status.proxy_passed = true;
200                         send_id(c);
201                         return 8;
202                 } else {
203                         logger(LOG_ERR, "Proxy request rejected");
204                         return -1;
205                 }
206
207         case PROXY_SOCKS5:
208                 if(c->buflen < 2)
209                         return 0;
210                 if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
211                         logger(LOG_ERR, "Proxy authentication method rejected");
212                         return -1;
213                 }
214                 int offset = 2;
215                 if(c->buffer[1] == 0x02) {
216                         if(c->buflen < 4)
217                                 return 0;
218                         if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
219                                 logger(LOG_ERR, "Proxy username/password rejected");
220                                 return -1;
221                         }
222                         offset += 2;
223                 }
224                 if(c->buflen - offset < 7)
225                         return 0;
226                 if(c->buffer[offset] != 0x05  || c->buffer[offset + 1] != 0x00) {
227                         logger(LOG_ERR, "Proxy request rejected");
228                         return -1;
229                 }
230                 int replen = offset + 6;
231                 switch(c->buffer[offset + 3]) {
232                         case 0x01: // IPv4
233                                 if(c->address.sa.sa_family == AF_UNKNOWN)
234                                         update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
235                                 replen += 4;
236                                 break;
237                         case 0x03: // Hostname
238                                 if(c->address.sa.sa_family == AF_UNKNOWN)
239                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
240                                 replen += ((uint8_t *)c->buffer)[offset + 4];
241                                 break;
242                         case 0x04: // IPv6
243                                 if(c->address.sa.sa_family == AF_UNKNOWN)
244                                         update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
245                                 replen += 16;
246                                 break;
247                         default:
248                                 logger(LOG_ERR, "Proxy reply malformed");
249                                 return -1;
250                 }
251                 if(c->buflen < replen) {
252                         return 0;
253                 } else {
254                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
255                         c->allow_request = ID;
256                         c->status.proxy_passed = true;
257                         send_id(c);
258                         return replen;
259                 }
260
261         case PROXY_HTTP: {
262                 char *p = memchr(c->buffer, '\n', c->buflen);
263                 if(!p || p - c->buffer >= c->buflen)
264                         return 0;
265
266                 while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) {
267                         if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4))
268                                 break;
269                 }
270
271                 if(!p)
272                         return 0;
273
274                 if(c->buflen < 9)
275                         return 0;
276
277                 if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
278                         if(!strncmp(c->buffer + 9, "200", 3)) {
279                                 if(c->address.sa.sa_family == AF_UNKNOWN)
280                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
281                                 logger(LOG_DEBUG, "Proxy request granted");
282                                 replen = p  + 1 - c->buffer;
283                                 c->allow_request = ID;
284                                 c->status.proxy_passed = true;
285                                 send_id(c);
286                                 return replen;
287                         } else {
288                                 p = memchr(c->buffer, '\n', c->buflen);
289                                 p[-1] = 0;
290                                 logger(LOG_ERR, "Proxy request rejected: %s", c->buffer + 9);
291                                 return false;
292                         }
293                 } else {
294                         logger(LOG_ERR, "Proxy reply malformed");
295                         return -1;
296                 }
297         }
298
299         default:
300                 abort();
301         }
302 }