1 /***************************************************************************
2  * nsock_proxy.c -- This contains the functions relating to proxies.       *
3  *                                                                         *
4  ***********************IMPORTANT NSOCK LICENSE TERMS***********************
5  *                                                                         *
6  * The nsock parallel socket event library is (C) 1999-2020 Insecure.Com   *
7  * LLC This library is free software; you may redistribute and/or          *
8  * modify it under the terms of the GNU General Public License as          *
9  * published by the Free Software Foundation; Version 2.  This guarantees  *
10  * your right to use, modify, and redistribute this software under certain *
11  * conditions.  If this license is unacceptable to you, Insecure.Com LLC   *
12  * may be willing to sell alternative licenses (contact                    *
13  * sales@insecure.com ).                                                   *
14  *                                                                         *
15  * As a special exception to the GPL terms, Insecure.Com LLC grants        *
16  * permission to link the code of this program with any version of the     *
17  * OpenSSL library which is distributed under a license identical to that  *
18  * listed in the included docs/licenses/OpenSSL.txt file, and distribute   *
19  * linked combinations including the two. You must obey the GNU GPL in all *
20  * respects for all of the code used other than OpenSSL.  If you modify    *
21  * this file, you may extend this exception to your version of the file,   *
22  * but you are not obligated to do so.                                     *
23  *                                                                         *
24  * If you received these files with a written license agreement stating    *
25  * terms other than the (GPL) terms above, then that alternative license   *
26  * agreement takes precedence over this comment.                           *
27  *                                                                         *
28  * Source is provided to this software because we believe users have a     *
29  * right to know exactly what a program is going to do before they run it. *
30  * This also allows you to audit the software for security holes.          *
31  *                                                                         *
32  * Source code also allows you to port Nmap to new platforms, fix bugs,    *
33  * and add new features.  You are highly encouraged to send your changes   *
34  * to the dev@nmap.org mailing list for possible incorporation into the    *
35  * main distribution.  By sending these changes to Fyodor or one of the    *
36  * Insecure.Org development mailing lists, or checking them into the Nmap  *
37  * source code repository, it is understood (unless you specify otherwise) *
38  * that you are offering the Nmap Project (Insecure.Com LLC) the           *
39  * unlimited, non-exclusive right to reuse, modify, and relicense the      *
40  * code.  Nmap will always be available Open Source, but this is important *
41  * because the inability to relicense code has caused devastating problems *
42  * for other Free Software projects (such as KDE and NASM).  We also       *
43  * occasionally relicense the code to third parties as discussed above.    *
44  * If you wish to specify special license conditions of your               *
45  * contributions, just say so when you send them.                          *
46  *                                                                         *
47  * This program is distributed in the hope that it will be useful, but     *
48  * WITHOUT ANY WARRANTY; without even the implied warranty of              *
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
50  * General Public License v2.0 for more details                            *
51  * (http://www.gnu.org/licenses/gpl-2.0.html).                             *
52  *                                                                         *
53  ***************************************************************************/
54 
55 /* $Id$ */
56 
57 #include "nsock.h"
58 #include "nsock_internal.h"
59 #include "nsock_log.h"
60 #include <string.h>
61 
62 #define IN_RANGE(x, min, max) ((x) >= (min) && (x) <= (max))
63 
64 
65 struct proxy_parser {
66   int done;
67   struct proxy_node *value;
68   char *str;
69   char *tokens;
70 };
71 
72 static struct proxy_parser *proxy_parser_new(const char *proxychainstr);
73 static void proxy_parser_next(struct proxy_parser *parser);
74 static void proxy_parser_delete(struct proxy_parser *parser);
75 
76 
77 /* --- Implemented proxy backends --- */
78 extern const struct proxy_spec ProxySpecHttp;
79 extern const struct proxy_spec ProxySpecSocks4;
80 
81 
82 static const struct proxy_spec *ProxyBackends[] = {
83   &ProxySpecHttp,
84   &ProxySpecSocks4,
85   NULL
86 };
87 
88 
89 /* A proxy chain is a comma-separated list of proxy specification strings:
90  * proto://[user:pass@]host[:port] */
nsock_proxychain_new(const char * proxystr,nsock_proxychain * chain,nsock_pool nspool)91 int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_pool nspool) {
92   struct npool *nsp = (struct npool *)nspool;
93   struct proxy_chain *pxc, **pchain = (struct proxy_chain **)chain;
94 
95   *pchain = NULL;
96 
97   pxc = (struct proxy_chain *)safe_malloc(sizeof(struct proxy_chain));
98   gh_list_init(&pxc->nodes);
99 
100   if (proxystr) {
101     struct proxy_parser *parser;
102 
103     parser = proxy_parser_new(proxystr);
104     while (!parser->done) {
105       gh_list_append(&pxc->nodes, &parser->value->nodeq);
106       proxy_parser_next(parser);
107     }
108     proxy_parser_delete(parser);
109   }
110 
111   if (nsp) {
112     if (nsock_pool_set_proxychain(nspool, pxc) < 0) {
113       nsock_proxychain_delete(pxc);
114       return -1;
115     }
116   }
117 
118   *pchain = pxc;
119   return 1;
120 }
121 
nsock_proxychain_delete(nsock_proxychain chain)122 void nsock_proxychain_delete(nsock_proxychain chain) {
123   struct proxy_chain *pchain = (struct proxy_chain *)chain;
124   gh_lnode_t *lnode;
125 
126   if (!pchain)
127     return;
128 
129   while ((lnode = gh_list_pop(&pchain->nodes)) != NULL) {
130     struct proxy_node *node;
131 
132     node = container_of(lnode, struct proxy_node, nodeq);
133     node->spec->ops->node_delete(node);
134   }
135 
136   gh_list_free(&pchain->nodes);
137   free(pchain);
138 }
139 
nsock_pool_set_proxychain(nsock_pool nspool,nsock_proxychain chain)140 int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain) {
141   struct npool *nsp = (struct npool *)nspool;
142   assert(nsp != NULL);
143 
144   if (nsp && nsp->px_chain) {
145     nsock_log_error("Invalid call. Existing proxychain on this nsock_pool");
146     return -1;
147   }
148 
149   nsp->px_chain = (struct proxy_chain *)chain;
150   return 1;
151 }
152 
proxy_chain_context_new(nsock_pool nspool)153 struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) {
154   struct npool *nsp = (struct npool *)nspool;
155   struct proxy_chain_context *ctx;
156 
157   ctx = (struct proxy_chain_context *)safe_malloc(sizeof(struct proxy_chain_context));
158   ctx->px_chain = nsp->px_chain;
159   ctx->px_state = PROXY_STATE_INITIAL;
160   ctx->px_current = container_of(gh_list_first_elem(&nsp->px_chain->nodes),
161                                  struct proxy_node,
162                                  nodeq);
163   return ctx;
164 }
165 
proxy_chain_context_delete(struct proxy_chain_context * ctx)166 void proxy_chain_context_delete(struct proxy_chain_context *ctx) {
167   free(ctx);
168 }
169 
uri_free(struct uri * uri)170 static void uri_free(struct uri *uri) {
171   free(uri->scheme);
172   free(uri->user);
173   free(uri->pass);
174   free(uri->host);
175   free(uri->path);
176 }
177 
lowercase(char * s)178 static int lowercase(char *s) {
179   char *p;
180 
181   for (p = s; *p != '\0'; p++)
182     *p = tolower((int) (unsigned char) *p);
183 
184   return p - s;
185 }
186 
hex_digit_value(char digit)187 static int hex_digit_value(char digit) {
188   static const char DIGITS[] = "0123456789abcdef";
189   const char *p;
190 
191   if ((unsigned char)digit == '\0')
192     return -1;
193 
194   p = strchr(DIGITS, tolower((int)(unsigned char)digit));
195   if (p == NULL)
196     return -1;
197 
198   return p - DIGITS;
199 }
200 
percent_decode(char * s)201 static int percent_decode(char *s) {
202   char *p, *q;
203 
204   /* Skip to the first '%'. If there are no percent escapes, this lets us
205    * return without doing any copying. */
206   q = s;
207   while (*q != '\0' && *q != '%')
208     q++;
209 
210   p = q;
211   while (*q != '\0') {
212     if (*q == '%') {
213       int c, d;
214 
215       q++;
216       c = hex_digit_value(*q);
217       if (c == -1)
218         return -1;
219       q++;
220       d = hex_digit_value(*q);
221       if (d == -1)
222         return -1;
223 
224       *p++ = c * 16 + d;
225       q++;
226       } else {
227         *p++ = *q++;
228       }
229   }
230   *p = '\0';
231 
232   return p - s;
233 }
234 
uri_parse_authority(const char * authority,struct uri * uri)235 static int uri_parse_authority(const char *authority, struct uri *uri) {
236   const char *portsep;
237   const char *host_start, *host_end;
238   char *tail;
239 
240   /* We do not support "user:pass@" userinfo. The proxy has no use for it. */
241   if (strchr(authority, '@') != NULL)
242     return -1;
243 
244   /* Find the beginning and end of the host. */
245   host_start = authority;
246 
247   if (*host_start == '[') {
248     /* IPv6 address in brackets. */
249     host_start++;
250     host_end = strchr(host_start, ']');
251 
252     if (host_end == NULL)
253       return -1;
254 
255     portsep = host_end + 1;
256 
257     if (!(*portsep == ':' || *portsep == '\0'))
258       return -1;
259 
260   } else {
261     portsep = strrchr(authority, ':');
262 
263     if (portsep == NULL)
264       portsep = strchr(authority, '\0');
265     host_end = portsep;
266   }
267 
268   /* Get the port number. */
269   if (*portsep == ':' && *(portsep + 1) != '\0') {
270     long n;
271 
272     errno = 0;
273     n = parse_long(portsep + 1, &tail);
274     if (errno || *tail || (tail == (portsep + 1)) || !IN_RANGE(n, 1, 65535))
275       return -1;
276     uri->port = n;
277   } else {
278     uri->port = -1;
279   }
280 
281   /* Get the host. */
282   uri->host = mkstr(host_start, host_end);
283   if (percent_decode(uri->host) < 0) {
284     free(uri->host);
285     uri->host = NULL;
286     return -1;
287   }
288 
289   return 1;
290 }
291 
parse_uri(const char * proxystr,struct uri * uri)292 static int parse_uri(const char *proxystr, struct uri *uri) {
293   const char *p, *q;
294 
295   /* Scheme, section 3.1. */
296   p = proxystr;
297   if (!isalpha(*p))
298     goto fail;
299 
300   q = p;
301   while (isalpha(*q) || isdigit(*q) || *q == '+' || *q == '-' || *q == '.')
302     q++;
303 
304   if (*q != ':')
305       goto fail;
306 
307   uri->scheme = mkstr(p, q);
308 
309   /* "An implementation should accept uppercase letters as equivalent to
310    * lowercase in scheme names (e.g., allow "HTTP" as well as "http") for the
311    * sake of robustness..." */
312   lowercase(uri->scheme);
313 
314   /* Authority, section 3.2. */
315   p = q + 1;
316   if (*p == '/' && *(p + 1) == '/') {
317     char *authority = NULL;
318 
319     p += 2;
320     q = p;
321     while (!(*q == '/' || *q == '?' || *q == '#' || *q == '\0'))
322       q++;
323           ;
324     authority = mkstr(p, q);
325     if (uri_parse_authority(authority, uri) < 0) {
326       free(authority);
327       goto fail;
328     }
329     free(authority);
330 
331     p = q;
332   }
333 
334   /* Path, section 3.3. We include the query and fragment in the path. The
335    * path is also not percent-decoded because we just pass it on to the origin
336    * server. */
337 
338   q = strchr(p, '\0');
339   uri->path = mkstr(p, q);
340 
341   return 1;
342 
343 fail:
344   uri_free(uri);
345   return -1;
346 }
347 
proxy_node_new(char * proxystr)348 static struct proxy_node *proxy_node_new(char *proxystr) {
349   int i;
350 
351   for (i = 0; ProxyBackends[i] != NULL; i++) {
352     const struct proxy_spec *pspec;
353 
354     pspec = ProxyBackends[i];
355     if (strncasecmp(proxystr, pspec->prefix, strlen(pspec->prefix)) == 0) {
356       struct proxy_node *proxy = NULL;
357       struct uri uri;
358 
359       memset(&uri, 0x00, sizeof(struct uri));
360 
361       if (parse_uri(proxystr, &uri) < 0)
362         break;
363 
364       if (pspec->ops->node_new(&proxy, &uri) < 0)
365         fatal("Cannot initialize proxy node %s", proxystr);
366 
367       uri_free(&uri);
368 
369       return proxy;
370     }
371   }
372   fatal("Invalid protocol in proxy specification string: %s", proxystr);
373   return NULL;
374 }
375 
proxy_parser_new(const char * proxychainstr)376 struct proxy_parser *proxy_parser_new(const char *proxychainstr) {
377   struct proxy_parser *parser;
378 
379   parser = (struct proxy_parser *)safe_malloc(sizeof(struct proxy_parser));
380   parser->done = 0;
381   parser->value = NULL;
382 
383   parser->str = strdup(proxychainstr);
384 
385   parser->tokens = strtok(parser->str, ",");
386   if (parser->tokens)
387     parser->value = proxy_node_new(parser->tokens);
388   else
389     parser->done = 1;
390 
391   return parser;
392 }
393 
proxy_parser_next(struct proxy_parser * parser)394 void proxy_parser_next(struct proxy_parser *parser) {
395 
396   parser->tokens = strtok(NULL, ",");
397   if (parser->tokens)
398     parser->value = proxy_node_new(parser->tokens);
399   else
400     parser->done = 1;
401 }
402 
proxy_parser_delete(struct proxy_parser * parser)403 void proxy_parser_delete(struct proxy_parser *parser) {
404   if (parser) {
405     free(parser->str);
406     free(parser);
407   }
408 }
409 
forward_event(nsock_pool nspool,nsock_event nsevent,void * udata)410 void forward_event(nsock_pool nspool, nsock_event nsevent, void *udata) {
411   struct npool *nsp = (struct npool *)nspool;
412   struct nevent *nse = (struct nevent *)nsevent;
413   enum nse_type cached_type;
414   enum nse_status cached_status;
415 
416   cached_type = nse->type;
417   cached_status = nse->status;
418 
419   nse->type = nse->iod->px_ctx->target_ev_type;
420 
421   if (nse->status != NSE_STATUS_SUCCESS)
422     nse->status = NSE_STATUS_PROXYERROR;
423 
424   nsock_log_info("Forwarding event upstream: TCP connect %s (IOD #%li) EID %li",
425                  nse_status2str(nse->status), nse->iod->id, nse->id);
426 
427   nse->iod->px_ctx->target_handler(nsp, nse, udata);
428 
429   nse->type = cached_type;
430   nse->status = cached_status;
431 }
432 
nsock_proxy_ev_dispatch(nsock_pool nspool,nsock_event nsevent,void * udata)433 void nsock_proxy_ev_dispatch(nsock_pool nspool, nsock_event nsevent, void *udata) {
434   struct nevent *nse = (struct nevent *)nsevent;
435 
436   if (nse->status == NSE_STATUS_SUCCESS) {
437     struct proxy_node *current;
438 
439     current = nse->iod->px_ctx->px_current;
440     assert(current);
441     current->spec->ops->handler(nspool, nsevent, udata);
442   } else {
443     forward_event(nspool, nsevent, udata);
444   }
445 }
446 
proxy_resolve(const char * host,struct sockaddr * addr,size_t * addrlen)447 int proxy_resolve(const char *host, struct sockaddr *addr, size_t *addrlen) {
448   struct addrinfo *res;
449   int rc;
450 
451   rc = getaddrinfo(host, NULL, NULL, &res);
452   if (rc)
453     return -abs(rc);
454 
455   *addr = *res->ai_addr;
456   *addrlen = res->ai_addrlen;
457   freeaddrinfo(res);
458   return 1;
459 }
460 
461