1 /***************************************************************************
2  * proxy_http.c -- HTTP Connect proxying.                                  *
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 #define _GNU_SOURCE
58 #include <stdio.h>
59 
60 #include "nsock.h"
61 #include "nsock_internal.h"
62 #include "nsock_log.h"
63 #include <string.h>
64 
65 #define DEFAULT_PROXY_PORT_HTTP 8080
66 
67 
68 extern struct timeval nsock_tod;
69 extern const struct proxy_spec ProxySpecHttp;
70 
71 
proxy_http_node_new(struct proxy_node ** node,const struct uri * uri)72 static int proxy_http_node_new(struct proxy_node **node, const struct uri *uri) {
73   int rc;
74   struct proxy_node *proxy;
75 
76   proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node));
77   proxy->spec = &ProxySpecHttp;
78 
79   rc = proxy_resolve(uri->host, (struct sockaddr *)&proxy->ss, &proxy->sslen);
80   if (rc < 0) {
81     free(proxy);
82     *node = NULL;
83     return -1;
84   }
85 
86   if (uri->port == -1)
87     proxy->port = DEFAULT_PROXY_PORT_HTTP;
88   else
89     proxy->port = (unsigned short)uri->port;
90 
91   rc = asprintf(&proxy->nodestr, "http://%s:%d", uri->host, proxy->port);
92   if (rc < 0) {
93     /* asprintf() failed for some reason but this is not a disaster (yet).
94      * Set nodestr to NULL and try to keep on going. */
95     proxy->nodestr = NULL;
96   }
97 
98   *node = proxy;
99 
100   return 1;
101 }
102 
proxy_http_node_delete(struct proxy_node * node)103 static void proxy_http_node_delete(struct proxy_node *node) {
104   if (!node)
105     return;
106 
107   free(node->nodestr);
108 
109   free(node);
110 }
111 
handle_state_initial(struct npool * nsp,struct nevent * nse,void * udata)112 static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) {
113   struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
114   struct sockaddr_storage *ss;
115   size_t sslen;
116   unsigned short port;
117   struct proxy_node *next;
118   int timeout;
119 
120   px_ctx->px_state = PROXY_STATE_HTTP_TCP_CONNECTED;
121 
122   next = proxy_ctx_node_next(px_ctx);
123   if (next) {
124     ss    = &next->ss;
125     sslen = next->sslen;
126     port  = next->port;
127   } else {
128     ss    = &px_ctx->target_ss;
129     sslen = px_ctx->target_sslen;
130     port  = px_ctx->target_port;
131   }
132 
133   timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod);
134 
135   nsock_printf(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch,
136                timeout, udata, "CONNECT %s:%d HTTP/1.1\r\n\r\n",
137                inet_ntop_ez(ss, sslen), (int)port);
138 
139   nsock_readlines(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch,
140                   timeout, udata, 1);
141 
142   return 0;
143 }
144 
handle_state_tcp_connected(struct npool * nsp,struct nevent * nse,void * udata)145 static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) {
146   struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
147   char *res;
148   int reslen;
149 
150   res = nse_readbuf(nse, &reslen);
151 
152   /* TODO string check!! */
153   if (!((reslen >= 15) && strstr(res, "200 OK"))) {
154     struct proxy_node *node = px_ctx->px_current;
155 
156     nsock_log_debug("Connection refused from proxy %s", node->nodestr);
157     return -EINVAL;
158   }
159 
160   px_ctx->px_state = PROXY_STATE_HTTP_TUNNEL_ESTABLISHED;
161 
162   if (proxy_ctx_node_next(px_ctx) == NULL) {
163     forward_event(nsp, nse, udata);
164   } else {
165     px_ctx->px_current = proxy_ctx_node_next(px_ctx);
166     px_ctx->px_state   = PROXY_STATE_INITIAL;
167     nsock_proxy_ev_dispatch(nsp, nse, udata);
168   }
169   return 0;
170 }
171 
proxy_http_handler(nsock_pool nspool,nsock_event nsevent,void * udata)172 static void proxy_http_handler(nsock_pool nspool, nsock_event nsevent, void *udata) {
173   int rc = 0;
174   struct npool *nsp = (struct npool *)nspool;
175   struct nevent *nse = (struct nevent *)nsevent;
176 
177   switch (nse->iod->px_ctx->px_state) {
178     case PROXY_STATE_INITIAL:
179       rc = handle_state_initial(nsp, nse, udata);
180       break;
181 
182     case PROXY_STATE_HTTP_TCP_CONNECTED:
183       if (nse->type == NSE_TYPE_READ)
184         rc = handle_state_tcp_connected(nsp, nse, udata);
185       break;
186 
187     case PROXY_STATE_HTTP_TUNNEL_ESTABLISHED:
188       forward_event(nsp, nse, udata);
189       break;
190 
191     default:
192       fatal("Invalid proxy state!");
193   }
194 
195   if (rc) {
196     nse->status = NSE_STATUS_PROXYERROR;
197     forward_event(nsp, nse, udata);
198   }
199 }
200 
201 
202 /* ---- PROXY DEFINITION ---- */
203 static const struct proxy_op ProxyOpsHttp = {
204   proxy_http_node_new,
205   proxy_http_node_delete,
206   proxy_http_handler,
207 };
208 
209 const struct proxy_spec ProxySpecHttp = {
210   "http://",
211   PROXY_TYPE_HTTP,
212   &ProxyOpsHttp,
213 };
214 
215