1 /***************************************************************************
2  * proxy_socks4.c -- SOCKS4 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 
64 #include <string.h>
65 
66 #define DEFAULT_PROXY_PORT_SOCKS4 1080
67 
68 
69 extern struct timeval nsock_tod;
70 extern const struct proxy_spec ProxySpecSocks4;
71 
72 
73 struct socks4_data {
74     uint8_t  version;
75     uint8_t  type;
76     uint16_t port;
77     uint32_t address;
78     uint8_t  null;
79 } __attribute__((packed));
80 
81 
proxy_socks4_node_new(struct proxy_node ** node,const struct uri * uri)82 static int proxy_socks4_node_new(struct proxy_node **node, const struct uri *uri) {
83   int rc;
84   struct proxy_node *proxy;
85 
86   proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node));
87   proxy->spec = &ProxySpecSocks4;
88 
89   rc = proxy_resolve(uri->host, (struct sockaddr *)&proxy->ss, &proxy->sslen);
90   if (rc < 0)
91     goto err_out;
92 
93   if (proxy->ss.ss_family != AF_INET) {
94     rc = -1;
95     goto err_out;
96   }
97 
98   if (uri->port == -1)
99     proxy->port = DEFAULT_PROXY_PORT_SOCKS4;
100   else
101     proxy->port = (unsigned short)uri->port;
102 
103   rc = asprintf(&proxy->nodestr, "socks4://%s:%d", uri->host, proxy->port);
104   if (rc < 0) {
105     /* asprintf() failed for some reason but this is not a disaster (yet).
106      * Set nodestr to NULL and try to keep on going. */
107     proxy->nodestr = NULL;
108   }
109 
110   rc = 1;
111 
112 err_out:
113   if (rc < 0) {
114     free(proxy);
115     proxy = NULL;
116   }
117   *node = proxy;
118   return rc;
119 }
120 
proxy_socks4_node_delete(struct proxy_node * node)121 static void proxy_socks4_node_delete(struct proxy_node *node) {
122   if (!node)
123     return;
124 
125   free(node->nodestr);
126 
127   free(node);
128 }
129 
socks4_data_init(struct socks4_data * socks4,struct sockaddr_storage * ss,size_t sslen,unsigned short port)130 static inline void socks4_data_init(struct socks4_data *socks4,
131                                     struct sockaddr_storage *ss, size_t sslen,
132                                     unsigned short port) {
133   struct sockaddr_in *sin = (struct sockaddr_in *)ss;
134 
135   memset(socks4, 0x00, sizeof(struct socks4_data));
136   socks4->version = 4;
137   socks4->type = 1;
138   socks4->port = htons(port);
139   assert(ss->ss_family == AF_INET);
140   socks4->address = sin->sin_addr.s_addr;
141 }
142 
handle_state_initial(struct npool * nsp,struct nevent * nse,void * udata)143 static int handle_state_initial(struct npool *nsp, struct nevent *nse, void *udata) {
144   struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
145   struct sockaddr_storage *ss;
146   size_t sslen;
147   unsigned short port;
148   struct proxy_node *next;
149   struct socks4_data socks4;
150   int timeout;
151 
152   px_ctx->px_state = PROXY_STATE_SOCKS4_TCP_CONNECTED;
153 
154   next = proxy_ctx_node_next(px_ctx);
155   if (next) {
156     ss    = &next->ss;
157     sslen = next->sslen;
158     port  = next->port;
159   } else {
160     ss    = &px_ctx->target_ss;
161     sslen = px_ctx->target_sslen;
162     port  = px_ctx->target_port;
163   }
164 
165   socks4_data_init(&socks4, ss, sslen, port);
166 
167   timeout = TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod);
168 
169   nsock_write(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, timeout, udata,
170               (char *)&socks4, sizeof(socks4));
171 
172   nsock_readbytes(nsp, (nsock_iod)nse->iod, nsock_proxy_ev_dispatch, timeout,
173                   udata, 8);
174   return 0;
175 }
176 
handle_state_tcp_connected(struct npool * nsp,struct nevent * nse,void * udata)177 static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) {
178   struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
179   char *res;
180   int reslen;
181 
182   res = nse_readbuf(nse, &reslen);
183 
184   if (!(reslen == 8 && res[1] == 90)) {
185     struct proxy_node *node = px_ctx->px_current;
186 
187     nsock_log_debug("Ignoring invalid socks4 reply from proxy %s",
188                     node->nodestr);
189     return -EINVAL;
190   }
191 
192   px_ctx->px_state = PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED;
193 
194   if (proxy_ctx_node_next(px_ctx) == NULL) {
195     forward_event(nsp, nse, udata);
196   } else {
197     px_ctx->px_current = proxy_ctx_node_next(px_ctx);
198     px_ctx->px_state   = PROXY_STATE_INITIAL;
199     nsock_proxy_ev_dispatch(nsp, nse, udata);
200   }
201   return 0;
202 }
203 
proxy_socks4_handler(nsock_pool nspool,nsock_event nsevent,void * udata)204 static void proxy_socks4_handler(nsock_pool nspool, nsock_event nsevent, void *udata) {
205   int rc = 0;
206   struct npool *nsp = (struct npool *)nspool;
207   struct nevent *nse = (struct nevent *)nsevent;
208 
209   switch (nse->iod->px_ctx->px_state) {
210     case PROXY_STATE_INITIAL:
211       rc = handle_state_initial(nsp, nse, udata);
212       break;
213 
214     case PROXY_STATE_SOCKS4_TCP_CONNECTED:
215       if (nse->type == NSE_TYPE_READ)
216         rc = handle_state_tcp_connected(nsp, nse, udata);
217       break;
218 
219     case PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED:
220       forward_event(nsp, nse, udata);
221       break;
222 
223     default:
224       fatal("Invalid proxy state!");
225   }
226 
227   if (rc) {
228     nse->status = NSE_STATUS_PROXYERROR;
229     forward_event(nsp, nse, udata);
230   }
231 }
232 
233 /* ---- PROXY DEFINITION ---- */
234 static const struct proxy_op ProxyOpsSocks4 = {
235   proxy_socks4_node_new,
236   proxy_socks4_node_delete,
237   proxy_socks4_handler,
238 };
239 
240 const struct proxy_spec ProxySpecSocks4 = {
241   "socks4://",
242   PROXY_TYPE_SOCKS4,
243   &ProxyOpsSocks4,
244 };
245 
246