Line data Source code
1 : /* socks5.c - Check the SOCKS5 client feature
2 : * Copyright (C) 2015 g10 Code GmbH
3 : *
4 : * This file is part of Assuan.
5 : *
6 : * Assuan is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Assuan is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #ifdef HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif
23 :
24 : #include <stdio.h>
25 : #include <stdlib.h>
26 : #include <string.h>
27 : #include <assert.h>
28 : #ifdef HAVE_W32_SYSTEM
29 : # ifdef HAVE_WINSOCK2_H
30 : # include <winsock2.h>
31 : # endif
32 : # include <windows.h>
33 : #else /*!HAVE_W32_SYSTEM*/
34 : # include <sys/types.h>
35 : # include <sys/socket.h>
36 : # include <netdb.h>
37 : #endif /*!HAVE_W32_SYSTEM*/
38 :
39 : #include "../src/assuan.h"
40 : #include "common.h"
41 :
42 : #ifndef HAVE_GETADDRINFO
43 : int
44 : main (void)
45 : {
46 : fputs ("socks5: getaddrinfo not supported\n", stderr);
47 : return 77; /* Skip test. */
48 : }
49 : #else /* HAVE_GETADDRINFO */
50 :
51 :
52 : /*
53 :
54 : M A I N
55 :
56 : */
57 : int
58 0 : main (int argc, char **argv)
59 : {
60 0 : int last_argc = -1;
61 : gpg_error_t err;
62 0 : int only_v6 = 0;
63 0 : int only_v4 = 0;
64 0 : int use_tor = 0;
65 0 : int disable_socks = 0;
66 0 : int opt_byname = 0;
67 0 : const char *user = NULL;
68 0 : const char *pass = NULL;
69 0 : assuan_fd_t sock = ASSUAN_INVALID_FD;
70 : estream_t infp, outfp;
71 : int c;
72 : int lf_seen;
73 :
74 0 : if (argc)
75 : {
76 0 : log_set_prefix (*argv);
77 0 : argc--; argv++;
78 : }
79 0 : while (argc && last_argc != argc )
80 : {
81 0 : last_argc = argc;
82 0 : if (!strcmp (*argv, "--"))
83 : {
84 0 : argc--; argv++;
85 0 : break;
86 : }
87 0 : else if (!strcmp (*argv, "--help"))
88 : {
89 0 : puts (
90 : "usage: ./socks5 [options] HOST PORT\n"
91 : "\n"
92 : "Options:\n"
93 : " --verbose Show what is going on\n"
94 : " --use-tor Use port 9050 instead of 1080\n"
95 : " --inet6-only Use only IPv6\n"
96 : " --inet4-only Use only IPv4\n"
97 : " --disable-socks Connect w/o SOCKS\n"
98 : " --byname Use assuan_sock_connect_byname\n"
99 : " --user STRING Use STRING as user for authentication\n"
100 : " --pass STRING Use STRING as password for authentication\n"
101 : );
102 0 : exit (0);
103 : }
104 0 : if (!strcmp (*argv, "--verbose"))
105 : {
106 0 : verbose = 1;
107 0 : argc--; argv++;
108 : }
109 0 : else if (!strcmp (*argv, "--debug"))
110 : {
111 0 : verbose = debug = 1;
112 0 : argc--; argv++;
113 : }
114 0 : else if (!strcmp (*argv, "-6") || !strcmp (*argv, "--inet6-only"))
115 : {
116 0 : only_v6 = 1;
117 0 : argc--; argv++;
118 : }
119 0 : else if (!strcmp (*argv, "-4") || !strcmp (*argv, "--inet4-only"))
120 : {
121 0 : only_v4 = 1;
122 0 : argc--; argv++;
123 : }
124 0 : else if (!strcmp (*argv, "--use-tor"))
125 : {
126 0 : use_tor = 1;
127 0 : argc--; argv++;
128 : }
129 0 : else if (!strcmp (*argv, "--disable-socks"))
130 : {
131 0 : disable_socks = 1;
132 0 : argc--; argv++;
133 : }
134 0 : else if (!strcmp (*argv, "--byname"))
135 : {
136 0 : opt_byname = 1;
137 0 : argc--; argv++;
138 : }
139 0 : else if (!strcmp (*argv, "--user"))
140 : {
141 0 : argc--; argv++;
142 0 : if (argc)
143 : {
144 0 : user = *argv;
145 0 : argc--; argv++;
146 : }
147 : }
148 0 : else if (!strcmp (*argv, "--pass"))
149 : {
150 0 : argc--; argv++;
151 0 : if (argc)
152 : {
153 0 : pass = *argv;
154 0 : argc--; argv++;
155 : }
156 : }
157 0 : else if (!strncmp (*argv, "--", 2))
158 : {
159 0 : log_error ("unknown option '%s'\n", *argv);
160 0 : exit (1);
161 : }
162 : }
163 :
164 0 : if (argc != 2)
165 : {
166 0 : fputs ("usage: socks5 HOST PORT\n", stderr);
167 0 : exit (1);
168 : }
169 :
170 0 : assuan_set_assuan_log_prefix (log_prefix);
171 :
172 0 : if (!assuan_check_version (ASSUAN_VERSION))
173 0 : log_error ("assuan_check_version returned an error\n");
174 :
175 0 : assuan_sock_init ();
176 :
177 0 : if (!disable_socks
178 0 : && assuan_sock_set_flag (ASSUAN_INVALID_FD,
179 : use_tor? "tor-mode":"socks", 1))
180 : {
181 0 : err = gpg_error_from_syserror ();
182 0 : log_fatal ("setting %s mode failed: %s\n",
183 : use_tor? "TOR": "SOCKS", gpg_strerror (err));
184 : }
185 :
186 0 : if (opt_byname)
187 : {
188 : unsigned short port;
189 : char *cred;
190 :
191 0 : if (user || pass)
192 0 : cred = xstrconcat (user?user:"", ":", pass, NULL);
193 : else
194 0 : cred = NULL;
195 :
196 0 : port = strtoul (argv[1], NULL, 10);
197 : if (port < 0 || port > 65535)
198 : log_fatal ("port number out of range\n");
199 :
200 0 : sock = assuan_sock_connect_byname (argv[0], port, 0, cred,
201 : ASSUAN_SOCK_TOR);
202 0 : if (sock == ASSUAN_INVALID_FD)
203 : {
204 0 : err = gpg_error_from_syserror ();
205 0 : log_error ("assuan_sock_connect_byname (%s) failed: %s\n",
206 : argv[0], gpg_strerror (err));
207 0 : exit (1);
208 : }
209 0 : xfree (cred);
210 : }
211 : else
212 : {
213 : struct addrinfo hints, *res, *ai;
214 : int ret;
215 0 : int anyok = 0;
216 :
217 0 : memset (&hints, 0, sizeof (hints));
218 0 : hints.ai_socktype = SOCK_STREAM;
219 0 : ret = getaddrinfo (argv[0], argv[1], &hints, &res);
220 0 : if (ret)
221 : {
222 0 : log_error ("error resolving '%s': %s\n", argv[0], gai_strerror (ret));
223 0 : exit (1);
224 : }
225 :
226 0 : for (ai = res; ai; ai = ai->ai_next)
227 : {
228 0 : if (ai->ai_family == AF_INET && only_v6)
229 0 : continue;
230 0 : if (ai->ai_family == AF_INET6 && only_v4)
231 0 : continue;
232 :
233 0 : if (sock != ASSUAN_INVALID_FD)
234 0 : assuan_sock_close (sock);
235 0 : sock = assuan_sock_new (ai->ai_family, ai->ai_socktype,
236 : ai->ai_protocol);
237 0 : if (sock == ASSUAN_INVALID_FD)
238 : {
239 0 : err = gpg_error_from_syserror ();
240 0 : log_error ("error creating socket: %s\n", gpg_strerror (err));
241 0 : freeaddrinfo (res);
242 0 : exit (1);
243 : }
244 :
245 0 : if (assuan_sock_connect (sock, ai->ai_addr, ai->ai_addrlen))
246 : {
247 0 : err = gpg_error_from_syserror ();
248 0 : log_error ("assuan_sock_connect (%s) failed: %s\n",
249 0 : ai->ai_family == AF_INET6? "v6" :
250 0 : ai->ai_family == AF_INET ? "v4" : "?",
251 : gpg_strerror (err));
252 : }
253 : else
254 : {
255 0 : log_info ("assuan_sock_connect succeeded (%s)\n",
256 0 : ai->ai_family == AF_INET6? "v6" :
257 0 : ai->ai_family == AF_INET ? "v4" : "?");
258 0 : anyok = 1;
259 0 : break;
260 : }
261 : }
262 0 : freeaddrinfo (res);
263 0 : if (!anyok)
264 0 : exit (1);
265 : }
266 :
267 0 : infp = es_fdopen_nc (sock, "rb");
268 0 : if (!infp)
269 : {
270 0 : err = gpg_error_from_syserror ();
271 0 : assuan_sock_close (sock);
272 0 : log_fatal ("opening inbound stream failed: %s\n", gpg_strerror (err));
273 : }
274 0 : outfp = es_fdopen (sock, "wb");
275 0 : if (!outfp)
276 : {
277 0 : err = gpg_error_from_syserror ();
278 0 : es_fclose (infp);
279 0 : assuan_sock_close (sock);
280 0 : log_fatal ("opening outbound stream failed: %s\n", gpg_strerror (err));
281 : }
282 :
283 0 : es_fputs ("GET / HTTP/1.0\r\n\r\n", outfp);
284 0 : es_fflush (outfp);
285 0 : lf_seen = 0;
286 0 : while ((c = es_fgetc (infp)) != EOF)
287 : {
288 0 : if (c == '\r')
289 0 : continue;
290 0 : putchar (c);
291 0 : if (c == '\n')
292 : {
293 0 : if (lf_seen)
294 0 : break;
295 0 : lf_seen = 1;
296 : }
297 : else
298 0 : lf_seen = 0;
299 : }
300 0 : es_fclose (infp);
301 0 : es_fclose (outfp);
302 :
303 0 : return errorcount ? 1 : 0;
304 : }
305 : #endif /*HAVE_GETADDRINFO*/
|