Enable silent builds by default.
[tinc] / src / proxy.c
1 /*
2     proxy.c -- Proxy handling functions.
3     Copyright (C) 2015 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                 return true;
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                         return 8;
198                 } else {
199                         logger(LOG_ERR, "Proxy request rejected");
200                         return -1;
201                 }
202
203         case PROXY_SOCKS5:
204                 if(c->buflen < 2)
205                         return 0;
206                 if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
207                         logger(LOG_ERR, "Proxy authentication method rejected");
208                         return -1;
209                 }
210                 int offset = 2;
211                 if(c->buffer[1] == 0x02) {
212                         if(c->buflen < 4)
213                                 return 0;
214                         if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
215                                 logger(LOG_ERR, "Proxy username/password rejected");
216                                 return -1;
217                         }
218                         offset += 2;
219                 }
220                 if(c->buflen - offset < 7)
221                         return 0;
222                 if(c->buffer[offset] != 0x05  || c->buffer[offset + 1] != 0x00) {
223                         logger(LOG_ERR, "Proxy request rejected");
224                         return -1;
225                 }
226                 int replen = offset + 6;
227                 switch(c->buffer[offset + 3]) {
228                         case 0x01: // IPv4
229                                 if(c->address.sa.sa_family == AF_UNKNOWN)
230                                         update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
231                                 replen += 4;
232                                 break;
233                         case 0x03: // Hostname
234                                 if(c->address.sa.sa_family == AF_UNKNOWN)
235                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
236                                 replen += ((uint8_t *)c->buffer)[offset + 4];
237                                 break;
238                         case 0x04: // IPv6
239                                 if(c->address.sa.sa_family == AF_UNKNOWN)
240                                         update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
241                                 replen += 16;
242                                 break;
243                         default:
244                                 logger(LOG_ERR, "Proxy reply malformed");
245                                 return -1;
246                 }
247                 if(c->buflen < replen) {
248                         return 0;
249                 } else {
250                         ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
251                         c->allow_request = ID;
252                         return replen;
253                 }
254
255         case PROXY_HTTP: {
256                 char *p = memchr(c->buffer, '\n', c->buflen);
257                 if(!p || p - c->buffer >= c->buflen)
258                         return 0;
259                 p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer));
260                 if(!p)
261                         return 0;
262
263                 if(c->buflen < 9)
264                         return 0;
265
266                 if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
267                         if(!strncmp(c->buffer + 9, "200", 3)) {
268                                 if(c->address.sa.sa_family == AF_UNKNOWN)
269                                         update_address_ipv4(c, "\0\0\0\1", "\0\0");
270                                 logger(LOG_DEBUG, "Proxy request granted");
271                                 replen = p  + 1 - c->buffer;
272                                 c->allow_request = ID;
273                                 return replen;
274                         } else {
275                                 logger(LOG_ERR, "Proxy request rejected: %s", c->buffer + 9);
276                                 return false;
277                         }
278                 } else {
279                         logger(LOG_ERR, "Proxy reply malformed");
280                         return -1;
281                 }
282         }
283
284         default:
285                 abort();
286         }
287 }