"Fossies" - the Fresh Open Source Software Archive 
Member "scanssh-2.1/socks.c" (5 Nov 2004, 11426 Bytes) of package /linux/privat/old/scanssh-2.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * Copyright 2000-2004 (c) Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/types.h>
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <sys/tree.h>
35 #include <sys/queue.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <netinet/in.h>
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <signal.h>
45 #include <err.h>
46
47 #include <event.h>
48 #include <dnet.h>
49
50 #include "scanssh.h"
51 #include "socks.h"
52
53 #ifdef DEBUG
54 extern int debug;
55 #define DFPRINTF(x) if (debug) fprintf x
56 #else
57 #define DFPRINTF(x)
58 #endif
59
60 extern rand_t *ss_rand;
61
62 void socks_init(struct bufferevent *bev, struct argument *arg);
63 void socks_finalize(struct bufferevent *bev, struct argument *arg);
64
65 void socks5_readcb(struct bufferevent *bev, void *parameter);
66 void socks5_writecb(struct bufferevent *bev, void *parameter);
67 void socks5_errorcb(struct bufferevent *bev, short what, void *parameter);
68
69 void socks4_readcb(struct bufferevent *bev, void *parameter);
70 void socks4_writecb(struct bufferevent *bev, void *parameter);
71 void socks4_errorcb(struct bufferevent *bev, short what, void *parameter);
72
73 char *words[] = {
74 "eerily",
75 "bloodthirster",
76 "negligence",
77 "uncooping",
78 "outsubtle",
79 "saturnize",
80 "unconclusiveness",
81 "optological",
82 "malabathrum",
83 "leiomyosarcoma",
84 "gristmill",
85 "offendible",
86 "pretyphoid",
87 "banjo",
88 "cossaean",
89 "panhuman",
90 "relive",
91 "unquakerlike",
92 "stupefier",
93 "unkilled"
94 };
95
96 struct addr *socks_dst_addr = NULL;
97
98 void
99 socks_resolveaddress(char *name, ip_addr_t *address)
100 {
101 struct addrinfo ai, *aitop;
102
103 if (socks_dst_addr != NULL) {
104 memcpy(address, &socks_dst_addr->addr_ip, sizeof(ip_addr_t));
105 return;
106 }
107
108 memset(&ai, 0, sizeof (ai));
109 ai.ai_family = AF_INET;
110 ai.ai_socktype = 0;
111 ai.ai_flags = 0;
112
113 if (getaddrinfo(name, NULL, &ai, &aitop) != 0)
114 err(1, "%s: getaddrinfo failed: %s", __func__, name);
115
116 if ((socks_dst_addr = calloc(1, sizeof(struct addr))) == NULL)
117 err(1, "%s: calloc", __func__);
118
119 addr_ston(aitop->ai_addr, socks_dst_addr);
120 freeaddrinfo(aitop);
121
122 memcpy(address, &socks_dst_addr->addr_ip, sizeof(ip_addr_t));
123 }
124
125 char *
126 socks_getword(void)
127 {
128 int off = rand_uint16(ss_rand) % (sizeof(words)/sizeof(char *));
129
130 return words[off];
131 }
132
133 void
134 socks_makeurl(struct socks_state *socks)
135 {
136 char *word = socks_getword();
137
138 socks->port = 80;
139 socks->word = word;
140 snprintf(socks->domain, sizeof(socks->domain), "www.google.com");
141 }
142
143 int
144 socks_getaddress(struct bufferevent *bev, uint8_t type)
145 {
146 uint8_t length;
147 char *name;
148
149 switch (type) {
150 case SOCKS_ADDR_IPV4:
151 if (EVBUFFER_LENGTH(bev->input) < 4)
152 return (-1);
153 evbuffer_drain(bev->input, 4);
154 break;
155
156 case SOCKS_ADDR_NAME:
157 bufferevent_read(bev, &length, sizeof(length));
158 if (EVBUFFER_LENGTH(bev->input) < length)
159 return (-1);
160 if ((name = malloc(length + 1)) == NULL)
161 err(1, "%s: malloc", __func__);
162 bufferevent_read(bev, name, length);
163 name[length] = '\0';
164 DFPRINTF((stderr, "Got: %s\n", name));
165 free(name);
166 break;
167
168 default:
169 return (-1);
170 }
171
172 /* Now get the port number */
173 if (EVBUFFER_LENGTH(bev->input) < 2)
174 return (-1);
175
176 evbuffer_drain(bev->input, 2);
177 return (0);
178 }
179
180 void
181 socks_bufferanalyse(struct bufferevent *bev, struct argument *arg)
182 {
183 struct evbuffer *input = EVBUFFER_INPUT(bev);
184 struct socks_state *socks = arg->a_state;
185 size_t off;
186 char response[32];
187 char *p;
188
189 if (!socks->gotheaders) {
190 while ((p = evbuffer_find(input, "\n", 1)) != NULL) {
191 off = (size_t)p - (size_t)EVBUFFER_DATA(input) + 1;
192 if (off > 0 && *(p-1) == '\r')
193 *(p-1) = '\0';
194 *p = '\0';
195
196 if (strlen(EVBUFFER_DATA(input)) == 0) {
197 socks->gotheaders = 1;
198 evbuffer_drain(input, off);
199 break;
200 } else {
201 DFPRINTF((stderr, "Header: %s\n",
202 EVBUFFER_DATA(input)));
203 }
204 evbuffer_drain(input, off);
205 }
206 }
207
208 if (!socks->gotheaders)
209 return;
210
211 if (evbuffer_find(input, "\r\n", 2) == NULL)
212 return;
213
214 if (evbuffer_find(input, socks->word, strlen(socks->word)) != NULL) {
215 snprintf(response, sizeof(response),
216 "SOCKS v%d", socks->version);
217 socks->success = 1;
218
219 } else {
220 snprintf(response, sizeof(response),
221 "bad SOCKS v%d", socks->version);
222 }
223 postres(arg, response);
224 scanhost_return(bev, arg, 1);
225 }
226
227 /* Scanner related functions */
228
229 void
230 socks_init(struct bufferevent *bev, struct argument *arg)
231 {
232 arg->a_flags = 0;
233 if ((arg->a_state = calloc(1, sizeof(struct socks_state))) == NULL)
234 err(1, "%s: calloc", __func__);
235 }
236
237 void
238 socks_finalize(struct bufferevent *bev, struct argument *arg)
239 {
240 free(arg->a_state);
241 arg->a_state = NULL;
242 arg->a_flags = 0;
243 }
244
245 void
246 socks5_readcb(struct bufferevent *bev, void *parameter)
247 {
248 struct argument *arg = parameter;
249 struct socks_state *socks = arg->a_state;
250 uint8_t version[2];
251 struct socks5_cmd cmd;
252 uint8_t reply[4];
253
254 DFPRINTF((stderr, "%s: called\n", __func__));
255
256 switch (arg->a_flags) {
257 case SOCKS_WAITING_RESPONSE:
258 if (EVBUFFER_LENGTH(bev->input) != 2)
259 goto error;
260
261 bufferevent_read(bev, version, sizeof(version));
262 DFPRINTF((stderr, "version: %d, response: %d\n",
263 version[0], version[1]));
264
265 socks->version = version[0];
266 socks->method = version[1];
267 if (socks->version != 4 && socks->version != 5)
268 goto error;
269 if (socks->method != 0)
270 goto error;
271
272 socks_makeurl(socks);
273
274 /* Now write our request */
275 cmd.version = SOCKS_VERSION5;
276 cmd.command = SOCKS_CMD_CONNECT;
277 cmd.reserved = 0;
278 cmd.addrtype = SOCKS_ADDR_IPV4;
279 socks_resolveaddress(socks->domain, &cmd.address.s_addr);
280 cmd.dstport = htons(socks->port);
281 bufferevent_write(bev, &cmd, 4 + 4 + 2);
282
283 bufferevent_disable(bev, EV_READ);
284 arg->a_flags = SOCKS_SENDING_COMMAND;
285 break;
286
287 case SOCKS_WAITING_COMMANDRESPONSE:
288 if (EVBUFFER_LENGTH(bev->input) < sizeof(reply))
289 goto error;
290 bufferevent_read(bev, reply, sizeof(reply));
291 DFPRINTF((stderr, "Version: %d, Reply: %d\n",
292 reply[0], reply[1]));
293
294 if (socks->version != reply[0])
295 goto error;
296
297 switch (reply[1]) {
298 case SOCKS5_RESP_SUCCESS:
299 break;
300 case SOCKS5_RESP_FAILURE:
301 postres(arg, "<error: server failure>");
302 goto done;
303 case SOCKS5_RESP_FORBIDDEN:
304 postres(arg, "<error: forbidden>");
305 goto done;
306 case SOCKS5_RESP_NETUNREACH:
307 case SOCKS5_RESP_HOSTUNREACH:
308 postres(arg, "<error: unreachable>");
309 goto done;
310 default:
311 postres(arg, "<error: response>");
312 goto done;
313 }
314
315 /* Success, now look at address type */
316 if (socks_getaddress(bev, reply[3]) == -1)
317 goto error;
318
319 arg->a_flags = SOCKS_SENDING_WEBREQUEST;
320 bufferevent_disable(bev, EV_READ);
321
322 http_makerequest(bev, arg, socks->word, 0);
323 break;
324
325 case SOCKS_READING_RESPONSE:
326 socks_bufferanalyse(bev, arg);
327 break;
328
329 default:
330 break;
331 }
332
333 return;
334
335 error:
336 postres(arg, "<socks5 proxy read error>");
337 done:
338 scanhost_return(bev, arg, 0);
339 }
340
341 void
342 socks5_writecb(struct bufferevent *bev, void *parameter)
343 {
344 struct argument *arg = parameter;
345 uint8_t version[3] = { 0x05, 0x01, 0x00 };
346
347 DFPRINTF((stderr, "%s: called\n", __func__));
348
349 switch (arg->a_flags) {
350 case 0:
351 arg->a_flags = SOCKS_WAITING_RESPONSE;
352 bufferevent_write(bev, version, sizeof(version));
353 break;
354 case SOCKS_SENDING_COMMAND:
355 arg->a_flags = SOCKS_WAITING_COMMANDRESPONSE;
356 bufferevent_enable(bev, EV_READ);
357 break;
358 case SOCKS_SENDING_WEBREQUEST:
359 arg->a_flags = SOCKS_READING_RESPONSE;
360 bufferevent_enable(bev, EV_READ);
361 break;
362 default:
363 break;
364 }
365 }
366
367 void
368 socks5_errorcb(struct bufferevent *bev, short what, void *parameter)
369 {
370 struct argument *arg = parameter;
371
372 DFPRINTF((stderr, "%s: called\n", __func__));
373
374 postres(arg, "<socks5 proxy error>");
375 scanhost_return(bev, arg, 0);
376 }
377
378 void
379 socks4_readcb(struct bufferevent *bev, void *parameter)
380 {
381 struct argument *arg = parameter;
382 struct socks_state *socks = arg->a_state;
383 struct socks4_cmd reply;
384
385 DFPRINTF((stderr, "%s: called\n", __func__));
386
387 switch (arg->a_flags) {
388 case SOCKS_WAITING_COMMANDRESPONSE:
389 if (EVBUFFER_LENGTH(bev->input) < sizeof(reply))
390 goto error;
391 bufferevent_read(bev, &reply, sizeof(reply));
392 DFPRINTF((stderr, "Version: %d, Reply: %d\n",
393 reply.version, reply.command));
394
395 if (0 != reply.version)
396 goto error;
397
398 switch (reply.command) {
399 case SOCKS4_RESP_SUCCESS:
400 break;
401 case SOCKS4_RESP_FAILURE:
402 postres(arg, "<socks4 proxy error: server failure>");
403 goto done;
404 case SOCKS4_RESP_NOIDENT:
405 postres(arg, "<socks4 proxy error: no ident>");
406 goto done;
407 case SOCKS4_RESP_BADIDENT:
408 postres(arg, "<socks4 proxy error: bad ident>");
409 goto done;
410 default:
411 postres(arg, "<socks4 proxy error: response>");
412 goto done;
413 }
414
415 arg->a_flags = SOCKS_SENDING_WEBREQUEST;
416 bufferevent_disable(bev, EV_READ);
417
418 http_makerequest(bev, arg, socks->word, 0);
419 break;
420
421 case SOCKS_READING_RESPONSE:
422 socks_bufferanalyse(bev, arg);
423 break;
424
425 default:
426 break;
427 }
428
429 return;
430
431 error:
432 postres(arg, "<socks4 proxy error>");
433 done:
434 scanhost_return(bev, arg, 0);
435 }
436
437 void
438 socks4_writecb(struct bufferevent *bev, void *parameter)
439 {
440 struct argument *arg = parameter;
441 struct socks_state *socks = arg->a_state;
442 struct socks4_cmd cmd;
443
444 socks->version = 4;
445 socks->method = 0;
446
447 DFPRINTF((stderr, "%s: called\n", __func__));
448
449 switch (arg->a_flags) {
450 case 0:
451 /* Request the connection to be made */
452 socks_makeurl(socks);
453
454 cmd.version = SOCKS_VERSION4;
455 cmd.command = SOCKS_CMD_CONNECT;
456 cmd.dstport = htons(socks->port);
457 socks_resolveaddress(socks->domain, &cmd.address.s_addr);
458
459 bufferevent_write(bev, &cmd, sizeof(cmd));
460 bufferevent_write(bev, socks->word, strlen(socks->word) + 1);
461
462 arg->a_flags = SOCKS_WAITING_COMMANDRESPONSE;
463 bufferevent_enable(bev, EV_READ);
464 break;
465 case SOCKS_SENDING_WEBREQUEST:
466 arg->a_flags = SOCKS_READING_RESPONSE;
467 bufferevent_enable(bev, EV_READ);
468 break;
469 default:
470 break;
471 }
472 }
473
474 void
475 socks4_errorcb(struct bufferevent *bev, short what, void *parameter)
476 {
477 struct argument *arg = parameter;
478
479 DFPRINTF((stderr, "%s: called\n", __func__));
480
481 postres(arg, "<socks4 proxy error>");
482 scanhost_return(bev, arg, 0);
483 }