]> git.pld-linux.org Git - packages/connect.git/blob - connect.c
Since OpenSSH 5.4 ssh -W can do the basic TCP tunnel
[packages/connect.git] / connect.c
1 /***********************************************************************
2  * connect.c -- Make socket connection using SOCKS4/5 and HTTP tunnel.
3  *
4  * Copyright (c) 2000-2004 Shun-ichi Goto
5  * Copyright (c) 2002, J. Grant (English Corrections)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * ---------------------------------------------------------
22  * PROJECT:  My Test Program
23  * AUTHOR:   Shun-ichi GOTO <gotoh@taiyo.co.jp>
24  * CREATE:   Wed Jun 21, 2000
25  * REVISION: $Revision$
26  * ---------------------------------------------------------
27  *
28  * Getting Source
29  * ==============
30  *
31  *   Recent version of 'connect.c' is available from
32  *     http://www.taiyo.co.jp/~gotoh/ssh/connect.c
33  *
34  *   Related tool, ssh-askpass.exe (alternative ssh-askpass on UNIX)
35  *   is available:
36  *     http://www.taiyo.co.jp/~gotoh/ssh/ssh-askpass.exe.gz
37  *
38  *   See more detail:
39  *     http://www.taiyo.co.jp/~gotoh/ssh/connect.html
40  *
41  * How To Compile
42  * ==============
43  *
44  *  On UNIX environment:
45  *      $ gcc connect.c -o connect
46  *
47  *  On SOLARIS:
48  *      $ gcc -o connect -lresolv -lsocket -lnsl connect.c
49  *
50  *  on Win32 environment:
51  *      $ cl connect.c wsock32.lib advapi32.lib
52  *    or
53  *      $ bcc32 connect.c wsock32.lib advapi32.lib
54  *    or
55  *      $ gcc connect.c -o connect
56  *
57  *  on Mac OS X environment:
58  *      $ gcc connect.c -o connect -lresolv
59  *    or
60  *      $ gcc connect.c -o connect -DBIND_8_COMPAT=1
61  *
62  * How To Use
63  * ==========
64  *
65  *   You can specify proxy method in an environment variable or in a
66  *   command line option.
67  *
68  *   usage:  connect [-dnhst45] [-R resolve] [-p local-port] [-w sec]
69  *                   [-H [user@]proxy-server[:port]]
70  *                   [-S [user@]socks-server[:port]]
71  *                   [-T proxy-server[:port]]
72  *                   [-c telnet proxy command]
73  *                   host port
74  *
75  *   "host" and "port" is for the target hostname and port-number to
76  *   connect to.
77  *
78  *   The -H option specifys a hostname and port number of the http proxy
79  *   server to relay. If port is omitted, 80 is used. You can specify this
80  *   value in the environment variable HTTP_PROXY and pass the -h option
81  *   to use it.
82  *
83  *   The -S option specifys the hostname and port number of the SOCKS
84  *   server to relay.  Like -H, port number can be omitted and the default
85  *   is 1080. You can also specify this value pair in the environment
86  *   variable SOCKS5_SERVER and give the -s option to use it.
87  *
88  *   The '-4' and the '-5' options are for specifying SOCKS relaying and
89  *   indicates protocol version to use. It is valid only when used with
90  *   '-s' or '-S'. Default is '-5' (protocol version 5)
91  *
92  *   The '-R' option is for specifying method to resolve the
93  *   hostname. Three keywords ("local", "remote", "both") or dot-notation
94  *   IP address are acceptable.  The keyword "both" means, "Try local
95  *   first, then remote". If a dot-notation IP address is specified, use
96  *   this host as nameserver. The default is "remote" for SOCKS5 or
97  *   "local" for others. On SOCKS4 protocol, remote resolving method
98  *   ("remote" and "both") requires protocol 4a supported server.
99  *
100  *   The '-p' option will forward a local TCP port instead of using the
101  *   standard input and output.
102  *
103  *   The '-P' option is same to '-p' except keep remote session. The
104  *   program repeats waiting the port with holding remote session without
105  *   disconnecting. To disconnect the remote session, send EOF to stdin or
106  *   kill the program.
107  *
108  *   The '-w' option specifys timeout seconds for making connection with
109  *   TARGET host.
110  *
111  *   The '-d' option is used for debug. If you fail to connect, use this
112  *   and check request to and response from server.
113  *
114  *   You can omit the "port" argument when program name is special format
115  *   containing port number itself. For example,
116  *     $ ln -s connect connect-25
117  *   means this connect-25 command is spcifying port number 25 already
118  *   so you need not 2nd argument (and ignored if specified).
119  *
120  *   To use proxy, this example is for SOCKS5 connection to connect to
121  *   'host' at port 25 via SOCKS5 server on 'firewall' host.
122  *     $ connect -S firewall  host 25
123  *   or
124  *     $ SOCKS5_SERVER=firewall; export SOCKS5_SERVER
125  *     $ connect -s host 25
126  *
127  *   For a HTTP-PROXY connection:
128  *     $ connect -H proxy-server:8080  host 25
129  *   or
130  *     $ HTTP_PROXY=proxy-server:8080; export HTTP_PROXY
131  *     $ connect -h host 25
132  *   To forward a local port, for example to use ssh:
133  *     $ connect -p 5550 -H proxy-server:8080  host 22
134  *    ($ ssh -l user -p 5550 localhost )
135  *
136  * TIPS
137  * ====
138  *
139  *   Connect.c doesn't have any configuration to specify the SOCKS server.
140  *   If you are a mobile user, this limitation might bother you.  However,
141  *   You can compile connect.c and link with other standard SOCKS library
142  *   like the NEC SOCKS5 library or Dante. This means connect.c is
143  *   socksified and uses a configration file like to other SOCKSified
144  *   network commands and you can switch configuration file any time
145  *   (ex. when ppp startup) that brings you switching of SOCKS server for
146  *   connect.c in same way with other commands. For this case, you can
147  *   write ~/.ssh/config like this:
148  *
149  *     ProxyCommand connect -n %h %p
150  *
151  * SOCKS5 authentication
152  * =====================
153  *
154  *   Only USER/PASS authentication is supported.
155  *
156  * Proxy authentication
157  * ====================
158  *
159  *   Only BASIC scheme is supported.
160  *
161  * Authentication informations
162  * ===========================
163  *
164  *   User name for authentication is specifed by an environment variable
165  *   or system login name.  And password is specified from environment
166  *   variable or external program (specified in $SSH_ASKPASS) or tty.
167  *
168  *   Following environment variable is used for specifying user name.
169  *     SOCKS: $SOCKS5_USER, $LOGNAME, $USER
170  *     HTTP Proxy: $HTTP_PROXY_USER, $LOGNAME, $USER
171  *
172  * ssh-askpass support
173  * ===================
174   *
175  *   You can use ssh-askpass (came from OpenSSH or else) to specify
176  *   password on graphical environment (X-Window or MS Windows). To use
177  *   this, set program name to environment variable SSH_ASKPASS. On UNIX,
178  *   X-Window must be required, so $DISPLAY environment variable is also
179  *   needed.  On Win32 environment, $DISPLAY is not mentioned.
180  *
181  * Related Informations
182  * ====================
183  *
184  *   SOCKS5 -- RFC 1928, RFC 1929, RFC 1961
185  *             NEC SOCKS Reference Implementation is available from:
186  *               http://www.socks.nec.com
187  *             DeleGate version 5 or earlier can be SOCKS4 server,
188  *             and version 6 can be SOCKS5 and SOCKS4 server.
189  *             and version 7.7.0 or later can be SOCKS5 and SOCKS4a server.
190  *               http://www.delegate.org/delegate/
191  *
192  *   HTTP-Proxy --
193  *             Many http proxy servers supports this, but https should
194  *             be allowed as configuration on your host.
195  *             For example on DeleGate, you should add "https" to the
196  *             "REMITTABLE" parameter to allow HTTP-Proxy like this:
197  *               delegated -Pxxxx ...... REMITTABLE="+,https" ...
198  *
199  *  Hypertext Transfer Protocol -- HTTP/1.1  -- RFC 2616
200  *  HTTP Authentication: Basic and Digest Access Authentication -- RFC 2617
201  *             For proxy authentication, refer these documents.
202  *
203  ***********************************************************************/
204
205 #include <stdio.h>
206 #include <stdlib.h>
207 #include <string.h>
208 #include <ctype.h>
209 #include <memory.h>
210 #include <errno.h>
211 #include <assert.h>
212 #include <sys/types.h>
213 #include <stdarg.h>
214 #include <fcntl.h>
215 #include <signal.h>
216
217 #ifdef __CYGWIN32__
218 #undef _WIN32
219 #endif
220
221 #ifdef _WIN32
222 #include <windows.h>
223 #include <winsock.h>
224 #include <sys/stat.h>
225 #include <io.h>
226 #include <conio.h>
227 #else /* !_WIN32 */
228 #include <unistd.h>
229 #include <pwd.h>
230 #include <termios.h>
231 #include <sys/time.h>
232 #ifndef __hpux
233 #include <sys/select.h>
234 #endif /* __hpux */
235 #include <sys/socket.h>
236 #include <netinet/in.h>
237 #include <arpa/inet.h>
238 #include <netdb.h>
239 #if !defined(_WIN32) && !defined(__CYGWIN32__)
240 #define WITH_RESOLVER 1
241 #include <arpa/nameser.h>
242 #include <resolv.h>
243 #else  /* not ( not _WIN32 && not __CYGWIN32__) */
244 #undef WITH_RESOLVER
245 #endif /* not ( not _WIN32 && not __CYGWIN32__) */
246 #endif /* !_WIN32 */
247
248 #ifdef _WIN32
249 #define ECONNRESET WSAECONNRESET
250 #endif /* _WI32 */
251
252
253
254 #ifndef LINT
255 static char *vcid = "$Id$";
256 #endif
257
258 /* Microsoft Visual C/C++ has _snprintf() and _vsnprintf() */
259 #ifdef _MSC_VER
260 #define snprintf _snprintf
261 #define vsnprintf _vsnprintf
262 #endif
263
264 /* consider Borland C */
265 #ifdef __BORLANDC__
266 #define _kbhit kbhit
267 #define _setmode setmode
268 #endif
269
270 /* help message.
271    Win32 environment does not support -R option (vc and cygwin)
272    Win32 native compilers does not support -w option, yet (vc)
273 */
274 static char *usage = "usage: %s [-dnhst45] [-p local-port]"
275 #ifdef _WIN32
276 #ifdef __CYGWIN32__
277 "[-w timeout] \n"                               /* cygwin cannot -R */
278 #else  /* not __CYGWIN32__ */
279 " \n"                                           /* VC cannot -w nor -R  */
280 #endif /* not __CYGWIN32__ */
281 #else  /* not _WIN32 */
282 /* help message for UNIX */
283 "[-R resolve] [-w timeout] \n"
284 #endif /* not _WIN32 */
285 "          [-H proxy-server[:port]] [-S [user@]socks-server[:port]] \n"
286 "          [-T proxy-server[:port]]\n"
287 "          [-c telnet-proxy-command]\n"
288 "          host port\n";
289
290 /* name of this program */
291 char *progname = NULL;
292 char *progdesc = "connect --- simple relaying command via proxy.";
293 char *rcs_revstr = "$Revision$";
294 char *revstr = NULL;
295
296 /* set of character for strspn() */
297 const char *digits    = "0123456789";
298 const char *dotdigits = "0123456789.";
299
300 /* options */
301 int f_debug = 0;
302
303 /* report flag to hide secure information */
304 int f_report = 1;
305
306 int connect_timeout = 0;
307
308 /* local input type */
309 #define LOCAL_STDIO     0
310 #define LOCAL_SOCKET    1
311 char *local_type_names[] = { "stdio", "socket" };
312 int   local_type = LOCAL_STDIO;
313 u_short local_port = 0;                         /* option 'p' */
314 int f_hold_session = 0;                         /* option 'P' */
315
316 char *telnet_command = "telnet %h %p";
317
318 /* utiity types, pair holder of number and string */
319 typedef struct {
320     int num;
321     const char *str;
322 } LOOKUP_ITEM;
323
324 /* relay method, server and port */
325 #define METHOD_UNDECIDED 0
326 #define METHOD_DIRECT    1
327 #define METHOD_SOCKS     2
328 #define METHOD_HTTP      3
329 #define METHOD_TELNET    4
330 char *method_names[] = { "UNDECIDED", "DIRECT", "SOCKS", "HTTP", "TELNET" };
331
332 int   relay_method = METHOD_UNDECIDED;          /* relaying method */
333 char *relay_host = NULL;                        /* hostname of relay server */
334 u_short relay_port = 0;                         /* port of relay server */
335 char *relay_user = NULL;                        /* user name for auth */
336
337 /* destination target host and port */
338 char *dest_host = NULL;
339 struct sockaddr_in dest_addr;
340 u_short dest_port = 0;
341
342 /* informations for SOCKS */
343 #define SOCKS5_REP_SUCCEEDED    0x00    /* succeeded */
344 #define SOCKS5_REP_FAIL         0x01    /* general SOCKS serer failure */
345 #define SOCKS5_REP_NALLOWED     0x02    /* connection not allowed by ruleset */
346 #define SOCKS5_REP_NUNREACH     0x03    /* Network unreachable */
347 #define SOCKS5_REP_HUNREACH     0x04    /* Host unreachable */
348 #define SOCKS5_REP_REFUSED      0x05    /* connection refused */
349 #define SOCKS5_REP_EXPIRED      0x06    /* TTL expired */
350 #define SOCKS5_REP_CNOTSUP      0x07    /* Command not supported */
351 #define SOCKS5_REP_ANOTSUP      0x08    /* Address not supported */
352 #define SOCKS5_REP_INVADDR      0x09    /* Inalid address */
353
354 LOOKUP_ITEM socks5_rep_names[] = {
355     { SOCKS5_REP_SUCCEEDED, "succeeded"},
356     { SOCKS5_REP_FAIL,      "general SOCKS server failure"},
357     { SOCKS5_REP_NALLOWED,  "connection not allowed by ruleset"},
358     { SOCKS5_REP_NUNREACH,  "Network unreachable"},
359     { SOCKS5_REP_HUNREACH,  "Host unreachable"},
360     { SOCKS5_REP_REFUSED,   "connection refused"},
361     { SOCKS5_REP_EXPIRED,   "TTL expired"},
362     { SOCKS5_REP_CNOTSUP,   "Command not supported"},
363     { SOCKS5_REP_ANOTSUP,   "Address not supported"},
364     { SOCKS5_REP_INVADDR,   "Invalid address"},
365     { -1, NULL }
366 };
367
368 /* SOCKS5 authentication methods */
369 #define SOCKS5_AUTH_REJECT      0xFF    /* No acceptable auth method */
370 #define SOCKS5_AUTH_NOAUTH      0x00    /* without authentication */
371 #define SOCKS5_AUTH_GSSAPI      0x01    /* GSSAPI */
372 #define SOCKS5_AUTH_USERPASS    0x02    /* User/Password */
373 #define SOCKS5_AUTH_CHAP        0x03    /* Challenge-Handshake Auth Proto. */
374 #define SOCKS5_AUTH_EAP         0x05    /* Extensible Authentication Proto. */
375 #define SOCKS5_AUTH_MAF         0x08    /* Multi-Authentication Framework */
376
377 #define SOCKS4_REP_SUCCEEDED    90      /* rquest granted (succeeded) */
378 #define SOCKS4_REP_REJECTED     91      /* request rejected or failed */
379 #define SOCKS4_REP_IDENT_FAIL   92      /* cannot connect identd */
380 #define SOCKS4_REP_USERID       93      /* user id not matched */
381
382 LOOKUP_ITEM socks4_rep_names[] = {
383     { SOCKS4_REP_SUCCEEDED,  "request granted (succeeded)"},
384     { SOCKS4_REP_REJECTED,   "request rejected or failed"},
385     { SOCKS4_REP_IDENT_FAIL, "cannot connect identd"},
386     { SOCKS4_REP_USERID,     "user id not matched"},
387     { -1, NULL }
388 };
389
390 #define RESOLVE_UNKNOWN 0
391 #define RESOLVE_LOCAL   1
392 #define RESOLVE_REMOTE  2
393 #define RESOLVE_BOTH    3
394 char *resolve_names[] = { "UNKNOWN", "LOCAL", "REMOTE", "BOTH" };
395
396 int socks_version = 5;                          /* SOCKS protocol version */
397 int socks_resolve = RESOLVE_UNKNOWN;
398 struct sockaddr_in socks_ns;
399 char *socks5_auth = NULL;
400
401 /* Environment variable names */
402 #define ENV_SOCKS_SERVER  "SOCKS_SERVER"        /* SOCKS server */
403 #define ENV_SOCKS5_SERVER "SOCKS5_SERVER"
404 #define ENV_SOCKS4_SERVER "SOCKS4_SERVER"
405
406 #define ENV_SOCKS_RESOLVE  "SOCKS_RESOLVE"      /* resolve method */
407 #define ENV_SOCKS5_RESOLVE "SOCKS5_RESOLVE"
408 #define ENV_SOCKS4_RESOLVE "SOCKS4_RESOLVE"
409
410 #define ENV_SOCKS5_USER     "SOCKS5_USER"       /* auth user for SOCKS5 */
411 #define ENV_SOCKS4_USER     "SOCKS4_USER"       /* auth user for SOCKS4 */
412 #define ENV_SOCKS_USER      "SOCKS_USER"        /* auth user for SOCKS */
413 #define ENV_SOCKS5_PASSWD   "SOCKS5_PASSWD"     /* auth password for SOCKS5 */
414 #define ENV_SOCKS5_PASSWORD "SOCKS5_PASSWORD"   /* old style */
415
416 #define ENV_HTTP_PROXY          "HTTP_PROXY"    /* common env var */
417 #define ENV_HTTP_PROXY_USER     "HTTP_PROXY_USER" /* auth user */
418 #define ENV_HTTP_PROXY_PASSWORD "HTTP_PROXY_PASSWORD" /* auth password */
419
420 #define ENV_TELNET_PROXY          "TELNET_PROXY"    /* common env var */
421
422 #define ENV_CONNECT_USER     "CONNECT_USER"     /* default auth user name */
423 #define ENV_CONNECT_PASSWORD "CONNECT_PASSWORD" /* default auth password */
424
425 #define ENV_SOCKS_DIRECT   "SOCKS_DIRECT"       /* addr-list for non-proxy */
426 #define ENV_SOCKS5_DIRECT  "SOCKS5_DIRECT"
427 #define ENV_SOCKS4_DIRECT  "SOCKS4_DIRECT"
428 #define ENV_HTTP_DIRECT    "HTTP_DIRECT"
429 #define ENV_CONNECT_DIRECT "CONNECT_DIRECT"
430
431 #define ENV_SOCKS5_AUTH "SOCKS5_AUTH"
432 #define ENV_SSH_ASKPASS "SSH_ASKPASS"           /* askpass program */
433
434 /* Prefix string of HTTP_PROXY */
435 #define HTTP_PROXY_PREFIX "http://"
436 #define PROXY_AUTH_NONE 0
437 #define PROXY_AUTH_BASIC 1
438 #define PROXY_AUTH_DIGEST 2
439 int proxy_auth_type = PROXY_AUTH_NONE;
440
441 /* reason of end repeating */
442 #define REASON_UNK              -2
443 #define REASON_ERROR            -1
444 #define REASON_CLOSED_BY_LOCAL  0
445 #define REASON_CLOSED_BY_REMOTE 1
446
447 /* return value of relay start function. */
448 #define START_ERROR -1
449 #define START_OK     0
450 #define START_RETRY  1
451
452 /* socket related definitions */
453 #ifndef _WIN32
454 #define SOCKET int
455 #endif
456 #ifndef SOCKET_ERROR
457 #define SOCKET_ERROR -1
458 #endif
459
460 #ifdef _WIN32
461 #define socket_errno() WSAGetLastError()
462 #else /* !_WIN32 */
463 #define closesocket close
464 #define socket_errno() (errno)
465 #endif /* !_WIN32 */
466
467 #ifdef _WIN32
468 #define popen _popen
469 #endif /* WIN32 */
470
471 /* packet operation macro */
472 #define PUT_BYTE(ptr,data) (*(unsigned char*)ptr = data)
473
474 /* debug message output */
475 void
476 debug( const char *fmt, ... )
477 {
478     va_list args;
479     if ( f_debug ) {
480         va_start( args, fmt );
481         fprintf(stderr, "DEBUG: ");
482         vfprintf( stderr, fmt, args );
483         va_end( args );
484     }
485 }
486
487 void
488 debug_( const char *fmt, ... )                  /* without prefix */
489 {
490     va_list args;
491     if ( f_debug ) {
492         va_start( args, fmt );
493         vfprintf( stderr, fmt, args );
494         va_end( args );
495     }
496 }
497
498 /* error message output */
499 void
500 error( const char *fmt, ... )
501 {
502     va_list args;
503     va_start( args, fmt );
504     fprintf(stderr, "ERROR: ");
505     vfprintf( stderr, fmt, args );
506     va_end( args );
507 }
508
509 void
510 fatal( const char *fmt, ... )
511 {
512     va_list args;
513     va_start( args, fmt );
514     fprintf(stderr, "FATAL: ");
515     vfprintf( stderr, fmt, args );
516     va_end( args );
517     exit (EXIT_FAILURE);
518 }
519
520
521 void *
522 xmalloc (size_t size)
523 {
524     void *ret = malloc(size);
525     if (ret == NULL)
526         fatal("Cannot allocate memory: %d bytes.\n", size);
527     return ret;
528 }
529
530 void
531 downcase( char *buf )
532 {
533     while ( *buf ) {
534         if ( isupper(*buf) )
535             *buf += 'a'-'A';
536         buf++;
537     }
538 }
539
540 char *
541 expand_host_and_port (const char *fmt, const char *host, int port)
542 {
543     const char *src;
544     char *buf, *dst, *ptr;
545     size_t len = strlen(fmt) + strlen(host) + 20;
546     buf = xmalloc (len);
547     dst = buf;
548     src = fmt;
549     
550     while (*src) {
551         if (*src == '%') {
552             switch (src[1]) {
553             case 'h':
554                 strcpy (dst, host);
555                 src += 2;
556                 break;
557             case 'p':
558                 snprintf (dst, len, "%d", port);
559                 src += 2;
560                 break;
561             default:
562                 src ++;
563                 break;
564             }
565             dst = buf + strlen (buf);
566         } else if (*src == '\\') {
567             switch (src[1]) {
568             case 'r':                           /* CR */
569                 *dst++ = '\r';
570                 src += 2;
571                 break;
572             case 'n':                           /* LF */
573                 *dst++ = '\n';
574                 src += 2;
575                 break;
576             case 't':                           /* TAB */
577                 *dst++ = '\t';
578                 src += 2;
579                 break;
580             default:
581                 src ++;
582                 break;
583             }
584         } else {
585             /* usual */
586             *dst++ = *src++;
587         }
588         *dst = '\0';
589     }
590     assert (strlen(buf) < len);
591     return buf;
592 }
593
594
595 int
596 lookup_resolve( const char *str )
597 {
598     char *buf = strdup( str );
599     int ret;
600
601     downcase( buf );
602     if ( strcmp( buf, "both" ) == 0 )
603         ret = RESOLVE_BOTH;
604     else if ( strcmp( buf, "remote" ) == 0 )
605         ret = RESOLVE_REMOTE;
606     else if ( strcmp( buf, "local" ) == 0 )
607         ret = RESOLVE_LOCAL;
608     else if ( strspn(buf, dotdigits) == strlen(buf) ) {
609 #ifndef WITH_RESOLVER
610         fatal("Sorry, you can't specify to resolve the hostname with the -R option on Win32 environment.");
611 #endif /* not WITH_RESOLVER */
612         ret = RESOLVE_LOCAL;                    /* this case is also 'local' */
613         socks_ns.sin_addr.s_addr = inet_addr(buf);
614         socks_ns.sin_family = AF_INET;
615     }
616     else
617         ret = RESOLVE_UNKNOWN;
618     free(buf);
619     return ret;
620 }
621
622 char *
623 getusername(void)
624 {
625 #ifdef _WIN32
626     static char buf[1024];
627     DWORD size = sizeof(buf);
628     buf[0] = '\0';
629     GetUserName( buf, &size);
630     return buf;
631 #else  /* not _WIN32 */
632     struct passwd *pw = getpwuid(getuid());
633     if ( pw == NULL )
634         fatal("getpwuid() failed for uid: %d\n", getuid());
635     return pw->pw_name;
636 #endif /* not _WIN32 */
637 }
638
639 /* expect
640    check STR is begin with substr with case-ignored comparison.
641    Return 1 if matched, otherwise 0.
642 */
643 int
644 expect( char *str, char *substr)
645 {
646     int len = strlen(substr);
647     while ( 0 < len-- ) {
648         if ( toupper(*str) != toupper(*substr) )
649             return 0;                           /* not matched */
650         str++, substr++;
651     }
652     return 1;                   /* good, matched */
653 }
654
655
656 /** PARAMETER operation **/
657 #define PARAMETER_FILE "/etc/connectrc"
658 #define PARAMETER_DOTFILE ".connectrc"
659 typedef struct {
660     char* name;
661     char* value;
662 } PARAMETER_ITEM;
663 PARAMETER_ITEM parameter_table[] = {
664     { ENV_SOCKS_SERVER, NULL },
665     { ENV_SOCKS5_SERVER, NULL },
666     { ENV_SOCKS4_SERVER, NULL },
667     { ENV_SOCKS_RESOLVE, NULL },
668     { ENV_SOCKS5_RESOLVE, NULL },
669     { ENV_SOCKS4_RESOLVE, NULL },
670     { ENV_SOCKS5_USER, NULL },
671     { ENV_SOCKS5_PASSWD, NULL },
672     { ENV_SOCKS5_PASSWORD, NULL },
673     { ENV_HTTP_PROXY, NULL },
674     { ENV_HTTP_PROXY_USER, NULL },
675     { ENV_HTTP_PROXY_PASSWORD, NULL },
676     { ENV_CONNECT_USER, NULL },
677     { ENV_CONNECT_PASSWORD, NULL },
678     { ENV_SSH_ASKPASS, NULL },
679     { ENV_SOCKS5_DIRECT, NULL },
680     { ENV_SOCKS4_DIRECT, NULL },
681     { ENV_SOCKS_DIRECT, NULL },
682     { ENV_HTTP_DIRECT, NULL },
683     { ENV_CONNECT_DIRECT, NULL },
684     { ENV_SOCKS5_AUTH, NULL },
685     { NULL, NULL }
686 };
687
688 PARAMETER_ITEM*
689 find_parameter_item(const char* name)
690 {
691     int i;
692     for( i = 0; parameter_table[i].name != NULL; i++ ){
693         if ( strcmp(name, parameter_table[i].name) == 0 )
694             return &parameter_table[i];
695     }
696     return NULL;
697 }
698
699 void
700 read_parameter_file_1(const char* name)
701 {
702     FILE* f;
703     int line;
704     char lbuf[1025];
705     f = fopen(name, "r");
706     if( f ){
707         debug("Reading parameter file(%s)\n", name);
708         for ( line = 1; fgets(lbuf, 1024, f); line++ ) {
709             char *p, *q, *param, *value;
710             p = strchr(lbuf, '\n');
711             if ( p == NULL )
712                 fatal("%s:%d: buffer overflow\n", name, line);
713             *p = '\0';
714             p = strchr(lbuf, '#');
715             if ( p )
716                 *p = '\0';
717             for ( p = lbuf; *p; p++ )
718                 if( *p != ' ' && *p != '\t' ) break;
719             if ( *p == '\0' ) continue;
720             param = p;
721             p = strchr(p, '=');
722             if ( p == NULL ) {
723                 error("%s:%d: missing equal sign\n", name, line);
724                 continue;
725             }
726             for ( q = p - 1; q >= lbuf; q-- )
727                 if ( *q != ' ' && *q != '\t' ) break;
728             *++q = '\0';
729             for ( ++p; *p; p++ )
730                 if ( *p != ' ' && *p != '\t' ) break;
731             value = p;
732             for ( ; *p; p++ );
733             for ( p--; p >= lbuf; p-- )
734                 if ( *p != ' ' && *p != '\t' ) break;
735             *++p = '\0';
736             if ( param && value ) {
737                 PARAMETER_ITEM *item;
738                 item = find_parameter_item(param);
739                 if ( item == NULL ) {
740                     error("%s:%d: unknown parameter `%s'\n", name, line, param);
741                     continue;
742                 }
743                 item->value = strdup(value);
744                 debug("Parameter `%s' is set to `%s'\n", param, value);
745             }
746         }
747     }
748 }
749
750 void
751 read_parameter_file(void)
752 {
753 #if !defined(_WIN32) || defined(cygwin)
754     char *name;
755     struct passwd *pw;
756 #endif
757
758     read_parameter_file_1(PARAMETER_FILE);
759 #if !defined(_WIN32) || defined(cygwin)
760     pw = getpwuid(getuid());
761     if ( pw == NULL )
762         fatal("getpwuid() failed for uid: %d\n", getuid());
763     name = xmalloc(strlen(pw->pw_dir) + strlen(PARAMETER_DOTFILE) + 2);
764     strcpy(name, pw->pw_dir);
765     strcat(name, "/" PARAMETER_DOTFILE);
766     read_parameter_file_1(name);
767     free(name);
768 #endif /* _WIN32 */
769 }
770
771 char*
772 getparam(const char* name)
773 {
774     char *value = getenv(name);
775     if ( value == NULL ){
776         PARAMETER_ITEM *item = find_parameter_item(name);
777         if ( item != NULL )
778             value = item->value;
779     }
780     return value;
781 }
782
783
784 /** DIRECT connection **/
785 #define MAX_DIRECT_ADDR_LIST 256
786
787 struct ADDRPAIR {
788     struct in_addr addr;
789     struct in_addr mask;
790     int negative;
791 };
792
793 struct ADDRPAIR direct_addr_list[MAX_DIRECT_ADDR_LIST];
794 int n_direct_addr_list = 0;
795
796 void
797 mask_addr (void *addr, void *mask, int addrlen)
798 {
799     char *a, *m;
800     a = addr;
801     m = mask;
802     while ( 0 < addrlen-- )
803         *a++ &= *m++;
804 }
805
806 int
807 add_direct_addr (struct in_addr *addr, struct in_addr *mask, int negative)
808 {
809     struct in_addr iaddr;
810     char *s;
811     if ( MAX_DIRECT_ADDR_LIST <= n_direct_addr_list ) {
812         error("direct address table is full!\n");
813         return -1;
814     }
815     iaddr = *addr;
816     mask_addr(&iaddr, mask, sizeof(iaddr));
817     s = strdup(inet_ntoa(iaddr));
818     debug("adding direct address entry: %s/%s\n", s, inet_ntoa(*mask));
819     free(s);
820     memcpy( &direct_addr_list[n_direct_addr_list].addr,
821             &iaddr, sizeof(iaddr));
822     memcpy( &direct_addr_list[n_direct_addr_list].mask,
823             mask, sizeof(*mask));
824     direct_addr_list[n_direct_addr_list].negative = negative;
825     n_direct_addr_list++;
826     return 0;
827 }
828
829 int
830 parse_addr_pair (const char *str, struct in_addr *addr, struct in_addr *mask)
831 {
832     /* NOTE: */
833     /* Assume already be splitted by separator
834        and formatted as folowing:
835        1)  12.34.56.789/255.255.255.0
836        2)  12.34.56.789/24
837        3)  12.34.56.
838        All above generates same addr/mask pair 12.34.56.0 and 255.255.255.0
839     */
840     const char *ptr;
841     u_char *dsta, *dstm;
842     int i, n;
843
844     assert( str != NULL );
845     debug("parsing address pair: '%s'\n", str);
846     addr->s_addr = 0;
847     mask->s_addr = 0;
848     ptr = str;
849     dsta = (u_char*)&addr->s_addr;
850     dstm = (u_char*)&mask->s_addr;
851     for (i=0; i<4; i++ ) {
852         if ( *ptr == '\0' )
853             break;              /* case of format #3 */
854         if ( !isdigit(*ptr) )
855             return -1;          /* format error: */
856         *dsta++ = atoi( ptr );
857         *dstm++ = 255;          /* automatic mask for format #3 */
858         while ( isdigit(*ptr) ) /* skip digits */
859             ptr++;
860         if ( *ptr == '.' )
861             ptr++;
862         else
863             break;
864     }
865     /* At this point, *ptr points '/' or EOS ('\0') */
866     if ( *ptr == '\0' )
867         return 0;                       /* complete as format #3 */
868     if ( *ptr != '/' )
869         return -1;                      /* format error */
870     /* Now parse mask for format #1 or #2 */
871     ptr++;
872     mask->s_addr = 0;                   /* clear automatic mask */
873
874     if ( strchr( ptr, '.') ) {
875         /* case of format #1 */
876         dstm = (u_char*)&mask->s_addr;
877         for (i=0; i<4; i++) {
878             if ( !isdigit(*ptr) )
879                 return -1;              /* format error: */
880             *dstm++ = atoi(ptr);
881             while ( isdigit(*ptr) )     /* skip digits */
882                 ptr++;
883             if ( *ptr == '.' )
884                 ptr++;
885             else
886                 break;                  /* from for loop */
887         }
888         /* complete as format #1 */
889     } else {
890         /* case of format #2 */
891         if ( !isdigit(*ptr) )
892             return -1;                  /* format error: */
893         n = atoi(ptr);
894         if ( n<0 || 32<n)
895             return -1;                  /* format error */
896         mask->s_addr = (n==0)? 0: htonl(((u_long)0xFFFFFFFF)<<(32-n));
897         /* complete as format #1 */
898     }
899     return 0;
900 }
901
902 void
903 initialize_direct_addr (void)
904 {
905     int negative;
906     int n_entries;
907     char *env = NULL, *beg, *next, *envkey = NULL;
908     struct in_addr addr, mask;
909
910     if ( relay_method == METHOD_SOCKS ){
911         if ( socks_version == 5 )
912             envkey = ENV_SOCKS5_DIRECT;
913         else
914             envkey = ENV_SOCKS4_DIRECT;
915         env = getparam(envkey);
916         if ( env == NULL )
917             env = getparam(ENV_SOCKS_DIRECT);
918     } else if ( relay_method == METHOD_HTTP ){
919         env = getparam(ENV_HTTP_DIRECT);
920     }
921
922     if ( env == NULL )
923         env = getparam(ENV_CONNECT_DIRECT);
924
925     if ( env == NULL )
926         return;                 /* no entry */
927     debug("making direct addr list from: '%s'\n", env);
928     env = strdup( env );        /* reallocate to modify */
929     beg = next = env;
930     n_entries = 0;
931     do {
932         if ( MAX_DIRECT_ADDR_LIST <= n_entries ) {
933             error("too many entries in %s", envkey);
934             break;              /* from do loop */
935         }
936         next = strchr( beg, ',');
937         if ( next != NULL )
938             *next++ = '\0';
939         addr.s_addr = 0;
940         mask.s_addr = 0;
941         if (*beg == '!') {
942             negative = 1;
943             beg++;
944         } else
945             negative = 0;
946         if ( !parse_addr_pair( beg, &addr, &mask ) ) {
947             add_direct_addr( &addr, &mask, negative );
948         } else {
949             error("invalid addr format in %s: %s\n", envkey, beg);
950         }
951         if ( next != NULL )
952             beg = next;
953     } while ( next != NULL );
954
955     free( env );
956     return;
957 }
958
959 int
960 cmp_addr (void *addr1, void *addr2, int addrlen)
961 {
962     return memcmp( addr1, addr2, addrlen );
963 }
964
965 int
966 is_direct_address (const struct sockaddr_in *addr)
967 {
968     int i;
969     struct in_addr saddr, iaddr;
970
971     saddr = addr->sin_addr;
972
973     /* Note: assume IPV4 address !! */
974     for (i=0; i<n_direct_addr_list; i++ ) {
975         iaddr = saddr;
976         mask_addr( &iaddr, &direct_addr_list[i].mask,
977                    sizeof(struct in_addr));
978         if (cmp_addr(&iaddr, &direct_addr_list[i].addr,
979                      sizeof(struct in_addr)) == 0) {
980             if (direct_addr_list[i].negative) {
981                 debug("negative match, addr to be SOCKSify: %s\n",
982                       inet_ntoa(saddr));
983                 return 0;       /* not direct */
984             }
985             if (!direct_addr_list[i].negative) {
986                 debug("positive match, addr to be direct: %s\n",
987                       inet_ntoa(saddr));
988                 return 1;       /* direct*/
989             }
990         }
991     }
992     debug("not matched, addr to be SOCKSified: %s\n", inet_ntoa(saddr));
993     return 0;                   /* not direct */
994 }
995
996
997 /** TTY operation **/
998
999 int intr_flag = 0;
1000
1001 #ifndef _WIN32
1002 void
1003 intr_handler(int sig)
1004 {
1005     intr_flag = 1;
1006 }
1007
1008 void
1009 tty_change_echo(int fd, int enable)
1010 {
1011     static struct termios ntio, otio;           /* new/old termios */
1012     static sigset_t nset, oset;                 /* new/old sigset */
1013     static struct sigaction nsa, osa;           /* new/old sigaction */
1014     static int disabled = 0;
1015
1016     if ( disabled && enable ) {
1017         /* enable echo */
1018         tcsetattr(fd, TCSANOW, &otio);
1019         disabled = 0;
1020         /* resotore sigaction */
1021         sigprocmask(SIG_SETMASK, &oset, NULL);
1022         sigaction(SIGINT, &osa, NULL);
1023         if ( intr_flag != 0 ) {
1024             /* re-generate signal  */
1025             kill(getpid(), SIGINT);
1026             sigemptyset(&nset);
1027             sigsuspend(&nset);
1028             intr_flag = 0;
1029         }
1030     } else if (!disabled && !enable) {
1031         /* set SIGINTR handler and break syscall on singal */
1032         sigemptyset(&nset);
1033         sigaddset(&nset, SIGTSTP);
1034         sigprocmask(SIG_BLOCK, &nset, &oset);
1035         intr_flag = 0;
1036         memset(&nsa, 0, sizeof(nsa));
1037         nsa.sa_handler = intr_handler;
1038         sigaction(SIGINT, &nsa, &osa);
1039         /* disable echo */
1040         if (tcgetattr(fd, &otio) == 0 && (otio.c_lflag & ECHO)) {
1041             disabled = 1;
1042             ntio = otio;
1043             ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
1044             (void) tcsetattr(fd, TCSANOW, &ntio);
1045         }
1046     }
1047
1048     return;
1049 }
1050
1051 #define TTY_NAME "/dev/tty"
1052 int
1053 tty_readpass( const char *prompt, char *buf, size_t size )
1054 {
1055     int tty, ret = 0;
1056
1057     tty = open(TTY_NAME, O_RDWR);
1058     if ( tty < 0 ) {
1059         error("Unable to open %s\n", TTY_NAME);
1060         return -1;                              /* can't open tty */
1061     }
1062     if ( size <= 0 )
1063         return -1;                              /* no room */
1064     write(tty, prompt, strlen(prompt));
1065     buf[0] = '\0';
1066     tty_change_echo(tty, 0);                    /* disable echo */
1067     ret = read(tty,buf, size-1);
1068     tty_change_echo(tty, 1);                    /* restore */
1069     write(tty, "\n", 1);                        /* new line */
1070     close(tty);
1071     if ( strchr(buf,'\n') == NULL  )
1072         return -1;
1073     if ( 0 < ret )
1074         buf[ret] = '\0';
1075     return ret;
1076 }
1077
1078 #else  /* _WIN32 */
1079
1080 BOOL __stdcall
1081 w32_intr_handler(DWORD dwCtrlType)
1082 {
1083     if ( dwCtrlType == CTRL_C_EVENT ) {
1084         intr_flag = 1;
1085         return TRUE;
1086     } else {
1087         return FALSE;
1088     }
1089 }
1090
1091 #define tty_readpass w32_tty_readpass
1092 int
1093 w32_tty_readpass( const char *prompt, char *buf, size_t size )
1094 {
1095     HANDLE in = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE,
1096                            0, NULL, OPEN_EXISTING, 0, NULL);
1097     HANDLE out = CreateFile("CONOUT$", GENERIC_WRITE,
1098                             0, NULL, OPEN_EXISTING, 0, NULL);
1099     DWORD mode;
1100     DWORD ret, bytes;
1101
1102     if (in == INVALID_HANDLE_VALUE || out == INVALID_HANDLE_VALUE)
1103         fatal("Cannot open console. (errno=%d)", GetLastError());
1104
1105     WriteFile(out, prompt, strlen(prompt), &bytes, 0);
1106     SetConsoleCtrlHandler(w32_intr_handler, TRUE ); /* add handler */
1107     GetConsoleMode(in, &mode);
1108     SetConsoleMode(in, mode&~ENABLE_ECHO_INPUT); /* disable echo */
1109     ret = ReadFile(in, buf, size, &bytes, 0);
1110     SetConsoleMode(in, mode);                   /* enable echo */
1111     SetConsoleCtrlHandler( w32_intr_handler, FALSE ); /* remove handler */
1112     if ( intr_flag )
1113         GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); /* re-signal */
1114     WriteFile(out,"\n", 1, &bytes, 0);
1115     CloseHandle(in);
1116     CloseHandle(out);
1117     return ret;
1118 }
1119
1120 #endif /* _WIN32 */
1121
1122 /*** User / Password ***/
1123
1124 /* SOCKS5 and HTTP Proxy authentication may requires username and
1125    password. We ll give it via environment variable or tty.
1126    Username and password for authentication are decided by
1127    following rules:
1128
1129    Username is taken from
1130      1) server location spec (i.e. user@host:port)
1131      2) environment variables (see tables.1)
1132      3) system account name currently logged in.
1133
1134      Table.1 Order of environment variables for username
1135
1136         |  SOCKS v5   |  SOCKS v4   |   HTTP proxy    |
1137       --+-------------+-------------+-----------------+
1138       1 | SOCKS45_USER | SOCKS4_USER | HTTP_PROXY_USER |
1139       --+-------------+-------------+                 |
1140       2 |        SOCKS_USER         |                 |
1141       --+---------------------------+-----------------+
1142       3 |              CONNECT_USER                   |
1143       --+---------------------------------------------+
1144
1145    Password is taken from
1146      1) by environment variables (see table.2)
1147      2) by entering from tty.
1148
1149      Table.2 Order of environment variables for password
1150
1151         |    SOCKS v5     |     HTTP proxy      |
1152       --+-----------------+---------------------+
1153       1 | SOCKS5_PASSWD   |                     |
1154       --+-----------------+ HTTP_PROXY_PASSWORD |
1155       2 | SOCKS5_PASSWORD |                     |
1156       --+-----------------+---------------------+
1157       3 |           CONNECT_PASSWORD            |
1158       --+---------------------------------------+
1159
1160       Note: SOCKS5_PASSWD which is added in rev. 1.79
1161             to share value with NEC SOCKS implementation.
1162  */
1163
1164 char *
1165 determine_relay_user ()
1166 {
1167     char *user = NULL;
1168     /* get username from environment variable, or system. */
1169     if (relay_method == METHOD_SOCKS) {
1170         if (user == NULL && socks_version == 5)
1171             user = getparam (ENV_SOCKS5_USER);
1172         if (user == NULL && socks_version == 4)
1173             user = getparam (ENV_SOCKS4_USER);
1174         if (user == NULL)
1175             user = getparam (ENV_SOCKS_USER);
1176     } else if (relay_method == METHOD_HTTP) {
1177         if (user == NULL)
1178             user = getparam (ENV_HTTP_PROXY_USER);
1179     }
1180     if (user == NULL)
1181         user = getparam (ENV_CONNECT_USER);
1182     /* determine relay user by system call if not yet. */
1183     if (user == NULL)
1184         user = getusername();
1185     return user;
1186 }
1187
1188 char *
1189 determine_relay_password ()
1190 {
1191     char *pass = NULL;
1192     if (pass == NULL && relay_method == METHOD_HTTP)
1193         pass = getparam(ENV_HTTP_PROXY_PASSWORD);
1194     if (pass == NULL && relay_method == METHOD_SOCKS)
1195         pass = getparam(ENV_SOCKS5_PASSWD);
1196     if (pass == NULL && relay_method == METHOD_SOCKS)
1197         pass = getparam(ENV_SOCKS5_PASSWORD);
1198     if (pass == NULL)
1199         pass = getparam(ENV_CONNECT_PASSWORD);
1200     return pass;
1201 }
1202
1203
1204 /*** network operations ***/
1205
1206
1207 /* set_relay()
1208    Determine relay informations:
1209    method, host, port, and username.
1210    1st arg, METHOD should be METHOD_xxx.
1211    2nd arg, SPEC is hostname or hostname:port or user@hostame:port.
1212    hostname is domain name or dot notation.
1213    If port is omitted, use 80 for METHOD_HTTP method,
1214    use 1080 for METHOD_SOCKS method.
1215    Username is also able to given by 3rd. format.
1216    2nd argument SPEC can be NULL. if NULL, use environment variable.
1217  */
1218 int
1219 set_relay( int method, char *spec )
1220 {
1221     char *buf, *sep, *resolve;
1222
1223     relay_method = method;
1224
1225     read_parameter_file();
1226     initialize_direct_addr();
1227     if (n_direct_addr_list == 0) {
1228         debug ("No direct address are specified.\n");
1229     } else {
1230         int i;
1231         for ( i=0; i<n_direct_addr_list; i++ ) {
1232             char *s1, *s2;
1233             s1 = strdup(inet_ntoa(direct_addr_list[i].addr));
1234             s2 = strdup(inet_ntoa(direct_addr_list[i].mask));
1235             debug(" #%d: %c%s/%s\n", i,
1236                   (direct_addr_list[i].negative)? '!': ' ',
1237                   s1, s2);
1238             free(s1);
1239             free(s2);
1240         }
1241     }
1242
1243     switch ( method ) {
1244     case METHOD_DIRECT:
1245         return -1;                              /* nothing to do */
1246
1247     case METHOD_SOCKS:
1248         if ( spec == NULL ) {
1249             switch ( socks_version ) {
1250             case 5:
1251                 spec = getparam(ENV_SOCKS5_SERVER);
1252                 break;
1253             case 4:
1254                 spec = getparam(ENV_SOCKS4_SERVER);
1255                 break;
1256             }
1257         }
1258         if ( spec == NULL )
1259             spec = getparam(ENV_SOCKS_SERVER);
1260
1261         if ( spec == NULL )
1262             fatal("Failed to determine SOCKS server.\n");
1263         relay_port = 1080;                      /* set default first */
1264
1265         /* determine resolve method */
1266         if ( socks_resolve == RESOLVE_UNKNOWN ) {
1267             if ( ((socks_version == 5) &&
1268                   ((resolve = getparam(ENV_SOCKS5_RESOLVE)) != NULL)) ||
1269                  ((socks_version == 4) &&
1270                   ((resolve = getparam(ENV_SOCKS4_RESOLVE)) != NULL)) ||
1271                  ((resolve = getparam(ENV_SOCKS_RESOLVE)) != NULL) ) {
1272                 socks_resolve = lookup_resolve( resolve );
1273                 if ( socks_resolve == RESOLVE_UNKNOWN )
1274                     fatal("Invalid resolve method: %s\n", resolve);
1275             } else {
1276                 /* default */
1277                 if ( socks_version == 5 )
1278                     socks_resolve = RESOLVE_REMOTE;
1279                 else
1280                     socks_resolve = RESOLVE_LOCAL;
1281             }
1282         }
1283         break;
1284
1285     case METHOD_HTTP:
1286         if ( spec == NULL )
1287             spec = getparam(ENV_HTTP_PROXY);
1288         if ( spec == NULL )
1289             fatal("You must specify http proxy server\n");
1290         relay_port = 80;                        /* set default first */
1291         break;
1292     case METHOD_TELNET:
1293         if ( spec == NULL )
1294             spec = getparam(ENV_TELNET_PROXY);
1295         if ( spec == NULL )
1296             fatal("You must specify telnet proxy server\n");
1297         relay_port = 23;                        /* set default first */
1298     }
1299
1300     if (expect( spec, HTTP_PROXY_PREFIX)) {
1301         /* URL format like: "http://server:port/" */
1302         /* extract server:port part */
1303         buf = strdup( spec + strlen(HTTP_PROXY_PREFIX));
1304         buf[strcspn(buf, "/")] = '\0';
1305     } else {
1306         /* assume spec is aready "server:port" format */
1307         buf = strdup( spec );
1308     }
1309     spec = buf;
1310
1311     /* check username in spec */
1312     sep = strchr( spec, '@' );
1313     if ( sep != NULL ) {
1314         *sep = '\0';
1315         relay_user = strdup( spec );
1316         spec = sep +1;
1317     }
1318     if (relay_user == NULL)
1319         relay_user = determine_relay_user();
1320
1321     /* split out hostname and port number from spec */
1322     sep = strchr(spec,':');
1323     if ( sep == NULL ) {
1324         /* hostname only, port is already set as default */
1325         relay_host = strdup( spec );
1326     } else {
1327         /* hostname and port */
1328         relay_port = atoi(sep+1);
1329         *sep = '\0';
1330         relay_host = strdup( spec );
1331     }
1332     free(buf);
1333     return 0;
1334 }
1335
1336
1337 u_short
1338 resolve_port( const char *service )
1339 {
1340     int port;
1341     if ( service[strspn (service, digits)] == '\0'  ) {
1342         /* all digits, port number */
1343         port = atoi(service);
1344     } else {
1345         /* treat as service name */
1346         struct servent *ent;
1347         ent = getservbyname( service, NULL );
1348         if ( ent == NULL ) {
1349             debug("Unknown service, '%s'\n", service);
1350             port = 0;
1351         } else {
1352             port = ntohs(ent->s_port);
1353             debug("service: %s => %d\n", service, port);
1354         }
1355     }
1356     return (u_short)port;
1357 }
1358
1359 void
1360 make_revstr(void)
1361 {
1362     char *ptr;
1363     size_t len;
1364     ptr = strstr(rcs_revstr, ": ");
1365     if (!ptr) {
1366         revstr = strdup("unknown");
1367         return;
1368     }
1369     ptr += 2;
1370     len = strspn(ptr, dotdigits);
1371     if (0 < len) {
1372         revstr = xmalloc(len+1);
1373         memcpy(revstr, ptr, len);
1374         revstr[len] = '\0';
1375     }
1376 }
1377
1378 int
1379 getarg( int argc, char **argv )
1380 {
1381     int err = 0;
1382     char *ptr, *server = (char*)NULL;
1383     int method = METHOD_DIRECT;
1384
1385     progname = *argv;
1386     argc--, argv++;
1387
1388     /* check optinos */
1389     while ( (0 < argc) && (**argv == '-') ) {
1390         ptr = *argv + 1;
1391         while ( *ptr ) {
1392             switch ( *ptr ) {
1393             case 's':                           /* use SOCKS */
1394                 method = METHOD_SOCKS;
1395                 break;
1396
1397             case 'n':                           /* no proxy */
1398                 method = METHOD_DIRECT;
1399                 break;
1400
1401             case 'h':                           /* use http-proxy */
1402                 method = METHOD_HTTP;
1403                 break;
1404             case 't':
1405                 method = METHOD_TELNET;
1406                 break;
1407
1408             case 'S':                           /* specify SOCKS server */
1409                 if ( 1 < argc ) {
1410                     argv++, argc--;
1411                     method = METHOD_SOCKS;
1412                     server = *argv;
1413                 } else {
1414                     error("option '-%c' needs argument.\n", *ptr);
1415                     err++;
1416                 }
1417                 break;
1418
1419             case 'H':                           /* specify http-proxy server */
1420                 if ( 1 < argc ) {
1421                     argv++, argc--;
1422                     method = METHOD_HTTP;
1423                     server = *argv;
1424                 } else {
1425                     error("option '-%c' needs argument.\n", *ptr);
1426                     err++;
1427                 }
1428                 break;
1429             case 'T':                           /* specify telnet proxy server */
1430                 if ( 1 < argc ) {
1431                     argv++, argc--;
1432                     method = METHOD_TELNET;
1433                     server = *argv;
1434                 } else {
1435                     error("option '-%c' needs argument.\n", *ptr);
1436                     err++;
1437                 }
1438                 break;
1439
1440             case 'c':
1441                  if (1 < argc) {
1442                       argv++, argc--;
1443                       telnet_command = *argv;
1444                  } else {
1445                       error("option '%c' needs argument.\n", *ptr);
1446                       err++;
1447                  }
1448                  break;
1449
1450             case 'P':
1451                 f_hold_session = 1;
1452                 /* without break */
1453             case 'p':                          /* specify port to forward */
1454                 if ( 1 < argc ) {
1455                     argv++, argc--;
1456                     local_type = LOCAL_SOCKET;
1457                     local_port = resolve_port(*argv);
1458                 } else {
1459                     error("option '-%c' needs argument.\n", *ptr);
1460                     err++;
1461                 }
1462                 break;
1463
1464 #ifndef _WIN32
1465             case 'w':
1466                 if ( 1 < argc ) {
1467                     argv++, argc--;
1468                     connect_timeout = atoi(*argv);
1469                 } else {
1470                     error("option '-%c' needs argument.\n", *ptr);
1471                     err++;
1472                 }
1473                 break;
1474 #endif /* not _WIN32 */
1475
1476             case '4':
1477                 socks_version = 4;
1478                 break;
1479
1480             case '5':
1481                 socks_version = 5;
1482                 break;
1483
1484             case 'a':
1485                 if ( 1 < argc ) {
1486                     argv++, argc--;
1487                     socks5_auth = *argv;
1488                 } else {
1489                     error("option '-%c' needs argument.\n", *ptr);
1490                     err++;
1491                 }
1492                 break;
1493
1494             case 'R':                           /* specify resolve method */
1495                 if ( 1 < argc ) {
1496                     argv++, argc--;
1497                     socks_resolve = lookup_resolve( *argv );
1498                 } else {
1499                     error("option '-%c' needs argument.\n", *ptr);
1500                     err++;
1501                 }
1502                 break;
1503
1504             case 'V':                           /* print version */
1505                 fprintf(stderr, "%s\nVersion %s\n", progdesc, revstr);
1506                 exit(0);
1507
1508             case 'd':                           /* debug mode */
1509                 f_debug++;
1510                 break;
1511
1512             default:
1513                 error("unknown option '-%c'\n", *ptr);
1514                 err++;
1515             }
1516             ptr++;
1517         }
1518         argc--, argv++;
1519     }
1520
1521     /* check error */
1522     if ( 0 < err )
1523         goto quit;
1524
1525     set_relay( method, server );
1526
1527     /* check destination HOST (MUST) */
1528     if ( argc == 0  ) {
1529         fprintf(stderr, "%s\nVersion %s\n", progdesc, revstr);
1530         fprintf(stderr, usage, progname);
1531         exit(0);
1532     }
1533     dest_host = argv[0];
1534     /* decide port or service name from programname or argument */
1535     if ( ((ptr=strrchr( progname, '/' )) != NULL) ||
1536          ((ptr=strchr( progname, '\\')) != NULL) )
1537         ptr++;
1538     else
1539         ptr = progname;
1540     if ( dest_port == 0 ) {
1541         /* accept only if -P is not specified. */
1542         if ( 1 < argc ) {
1543             /* get port number from argument (prior to progname) */
1544             /* NOTE: This way is for cvs ext method. */
1545             dest_port = resolve_port(argv[1]);
1546         } else if ( strncmp( ptr, "connect-", 8) == 0 ) {
1547             /* decide port number from program name */
1548             char *str = strdup( ptr+8 );
1549             str[strcspn( str, "." )] = '\0';
1550             dest_port = resolve_port(str);
1551             free(str);
1552         }
1553     }
1554     /* check port number */
1555     if ( dest_port <= 0 ) {
1556         error( "You must specify the destination port correctly.\n");
1557         err++;
1558         goto quit;
1559     }
1560     if ( (relay_method != METHOD_DIRECT) && (relay_port <= 0) ) {
1561         error("Invalid relay port: %d\n", dest_port);
1562         err++;
1563         goto quit;
1564     }
1565
1566 quit:
1567     /* report for debugging */
1568     debug("relay_method = %s (%d)\n",
1569           method_names[relay_method], relay_method);
1570     if ( relay_method != METHOD_DIRECT ) {
1571         debug("relay_host=%s\n", relay_host);
1572         debug("relay_port=%d\n", relay_port);
1573         debug("relay_user=%s\n", relay_user);
1574     }
1575     if ( relay_method == METHOD_SOCKS ) {
1576         debug("socks_version=%d\n", socks_version);
1577         debug("socks_resolve=%s (%d)\n",
1578               resolve_names[socks_resolve], socks_resolve);
1579     }
1580     debug("local_type=%s\n", local_type_names[local_type]);
1581     if ( local_type == LOCAL_SOCKET ) {
1582         debug("local_port=%d\n", local_port);
1583         if (f_hold_session)
1584             debug ("  with holding remote session.\n");
1585     }
1586     debug("dest_host=%s\n", dest_host);
1587     debug("dest_port=%d\n", dest_port);
1588     if ( 0 < err ) {
1589         fprintf(stderr, usage, progname);
1590         exit(1);
1591     }
1592     return 0;
1593 }
1594
1595 #ifndef _WIN32
1596 /* Time-out feature is not allowed for Win32 native compilers. */
1597 /* MSVC and Borland C cannot but Cygwin and UNIXes can. */
1598
1599 /* timeout signal hander */
1600 void
1601 sig_timeout(void)
1602 {
1603     debug( "timed out\n" );
1604     signal( SIGALRM, SIG_IGN );
1605     alarm( 0 );
1606 }
1607
1608 /* set timeout param = seconds, 0 clears */
1609 void
1610 set_timeout(int timeout)
1611 {
1612     /* This feature is allowed for UNIX or cygwin environments, currently */
1613     if ( timeout == 0 ) {
1614         debug( "clearing timeout\n" );
1615         signal( SIGALRM, SIG_IGN );
1616         alarm( 0 );
1617     } else {
1618         debug( "setting timeout: %d seconds\n", timeout );
1619         signal(SIGALRM, (void *)sig_timeout);
1620         alarm( timeout );
1621     }
1622 }
1623 #endif
1624
1625 #if !defined(_WIN32) && !defined(__CYGWIN32__)
1626 void
1627 switch_ns (struct sockaddr_in *ns)
1628 {
1629     res_init();
1630     memcpy (&_res.nsaddr_list[0], ns, sizeof(*ns));
1631     _res.nscount = 1;
1632     debug("Using nameserver at %s\n", inet_ntoa(ns->sin_addr));
1633 }
1634 #endif /* !_WIN32 && !__CYGWIN32__ */
1635
1636 /* TODO: IPv6
1637    TODO: fallback if askpass execution failed.
1638  */
1639
1640 int
1641 local_resolve (const char *host, struct sockaddr_in *addr)
1642 {
1643     struct hostent *ent;
1644     if ( strspn(host, dotdigits) == strlen(host) ) {
1645         /* given by IPv4 address */
1646         addr->sin_family = AF_INET;
1647         addr->sin_addr.s_addr = inet_addr(host);
1648     } else {
1649         debug("resolving host by name: %s\n", host);
1650         ent = gethostbyname (host);
1651         if ( ent ) {
1652             memcpy (&addr->sin_addr, ent->h_addr, ent->h_length);
1653             addr->sin_family = ent->h_addrtype;
1654             debug("resolved: %s (%s)\n",
1655                   host, inet_ntoa(addr->sin_addr));
1656         } else {
1657             debug("failed to resolve locally.\n");
1658             return -1;                          /* failed */
1659         }
1660     }
1661     return 0;                                   /* good */
1662 }
1663
1664 int
1665 open_connection( const char *host, u_short port )
1666 {
1667     SOCKET s;
1668     struct sockaddr_in saddr;
1669
1670     if ( relay_method == METHOD_DIRECT ) {
1671         host = dest_host;
1672         port = dest_port;
1673     } else if ((local_resolve (dest_host, &saddr) >= 0)&&
1674                (is_direct_address(&saddr))) {
1675         debug("%s is connected directly\n", dest_host);
1676         relay_method = METHOD_DIRECT;
1677         host = dest_host;
1678         port = dest_port;
1679     } else {
1680         host = relay_host;
1681         port = relay_port;
1682     }
1683
1684     if (local_resolve (host, &saddr) < 0) {
1685         error("can't resolve hostname: %s\n", host);
1686         return SOCKET_ERROR;
1687     }
1688     saddr.sin_port = htons(port);
1689
1690     debug("connecting to %s:%u\n", inet_ntoa(saddr.sin_addr), port);
1691     s = socket( AF_INET, SOCK_STREAM, 0 );
1692     if ( connect( s, (struct sockaddr *)&saddr, sizeof(saddr))
1693          == SOCKET_ERROR) {
1694         debug( "connect() failed.\n");
1695         return SOCKET_ERROR;
1696     }
1697     return s;
1698 }
1699
1700 void
1701 report_text( char *prefix, char *buf )
1702 {
1703     static char work[1024];
1704     char *tmp;
1705
1706     if ( !f_debug )
1707         return;
1708     if ( !f_report )
1709         return;                                 /* don't report */
1710     debug("%s \"", prefix);
1711     while ( *buf ) {
1712         memset( work, 0, sizeof(work));
1713         tmp = work;
1714         while ( *buf && ((tmp-work) < (int)sizeof(work)-5) ) {
1715             switch ( *buf ) {
1716             case '\t': *tmp++ = '\\'; *tmp++ = 't'; break;
1717             case '\r': *tmp++ = '\\'; *tmp++ = 'r'; break;
1718             case '\n': *tmp++ = '\\'; *tmp++ = 'n'; break;
1719             case '\\': *tmp++ = '\\'; *tmp++ = '\\'; break;
1720             default:
1721                 if ( isprint(*buf) ) {
1722                     *tmp++ = *buf;
1723                 } else {
1724                     int consumed = tmp - work;
1725                     snprintf( tmp, sizeof(work)-consumed,
1726                               "\\x%02X", (unsigned char)*buf);
1727                     tmp += strlen(tmp);
1728                 }
1729             }
1730             buf++;
1731             *tmp = '\0';
1732         }
1733         debug_("%s", work);
1734     }
1735
1736     debug_("\"\n");
1737 }
1738
1739
1740 void
1741 report_bytes( char *prefix, char *buf, int len )
1742 {
1743     if ( ! f_debug )
1744         return;
1745     debug( "%s", prefix );
1746     while ( 0 < len ) {
1747         fprintf( stderr, " %02x", *(unsigned char *)buf);
1748         buf++;
1749         len--;
1750     }
1751     fprintf(stderr, "\n");
1752     return;
1753 }
1754
1755 int
1756 atomic_out( SOCKET s, char *buf, int size )
1757 {
1758     int ret, len;
1759
1760     assert( buf != NULL );
1761     assert( 0<=size );
1762     /* do atomic out */
1763     ret = 0;
1764     while ( 0 < size ) {
1765         len = send( s, buf+ret, size, 0 );
1766         if ( len == -1 )
1767             fatal("atomic_out() failed to send(), %d\n", socket_errno());
1768         ret += len;
1769         size -= len;
1770     }
1771     if (!f_report) {
1772         debug("atomic_out()  [some bytes]\n");
1773         debug(">>> xx xx xx xx ...\n");
1774     } else {
1775         debug("atomic_out()  [%d bytes]\n", ret);
1776         report_bytes(">>>", buf, ret);
1777     }
1778     return ret;
1779 }
1780
1781 int
1782 atomic_in( SOCKET s, char *buf, int size )
1783 {
1784     int ret, len;
1785
1786     assert( buf != NULL );
1787     assert( 0<=size );
1788
1789     /* do atomic in */
1790     ret = 0;
1791     while ( 0 < size ) {
1792         len = recv( s, buf+ret, size, 0 );
1793         if ( len == -1 ) {
1794             fatal("atomic_in() failed to recv(), %d\n", socket_errno());
1795         } else if ( len == 0 ) {
1796             fatal( "Connection closed by peer.\n");
1797         }
1798         ret += len;
1799         size -= len;
1800     }
1801     if (!f_report) {
1802         debug("atomic_in()  [some bytes]\n");
1803         debug("<<< xx xx xx xx ...\n");
1804     } else {
1805         debug("atomic_in() [%d bytes]\n", ret);
1806         report_bytes("<<<", buf, ret);
1807     }
1808     return ret;
1809 }
1810
1811 int
1812 line_input( SOCKET s, char *buf, int size )
1813 {
1814     char *dst = buf;
1815     if ( size == 0 )
1816         return 0;                               /* no error */
1817     size--;
1818     while ( 0 < size ) {
1819         switch ( recv( s, dst, 1, 0) ) {        /* recv one-by-one */
1820         case SOCKET_ERROR:
1821             error("recv() error\n");
1822             return -1;                          /* error */
1823         case 0:
1824             size = 0;                           /* end of stream */
1825             break;
1826         default:
1827             /* continue reading until last 1 char is EOL? */
1828             if ( *dst == '\n' ) {
1829                 /* finished */
1830                 size = 0;
1831             } else {
1832                 /* more... */
1833                 size--;
1834             }
1835             dst++;
1836         }
1837     }
1838     *dst = '\0';
1839     report_text( "<<<", buf);
1840     return 0;
1841 }
1842
1843 /* cut_token()
1844    Span token in given string STR until char in DELIM is appeared.
1845    Then replace contiguous DELIMS with '\0' for string termination
1846    and returns next pointer.
1847    If no next token, return NULL.
1848 */
1849 char *
1850 cut_token( char *str, char *delim)
1851 {
1852     char *ptr = str + strcspn(str, delim);
1853     char *end = ptr + strspn(ptr, delim);
1854     if ( ptr == str )
1855         return NULL;
1856     while ( ptr < end )
1857         *ptr++ = '\0';
1858     return ptr;
1859 }
1860
1861 const char *
1862 lookup(int num, LOOKUP_ITEM *items)
1863 {
1864     int i = 0;
1865     while (0 <= items[i].num) {
1866         if (items[i].num == num)
1867             return items[i].str;
1868         i++;
1869     }
1870     return "(unknown)";
1871 }
1872
1873 /* readpass()
1874    password input routine
1875    Use ssh-askpass (same mechanism to OpenSSH)
1876 */
1877 char *
1878 readpass( const char* prompt, ...)
1879 {
1880     static char buf[1000];                      /* XXX, don't be fix length */
1881     va_list args;
1882     va_start(args, prompt);
1883     vsnprintf(buf, sizeof(buf), prompt, args);
1884     va_end(args);
1885
1886     if ( getparam(ENV_SSH_ASKPASS)
1887 #if !defined(_WIN32) && !defined(__CYGWIN32__)
1888          && getenv("DISPLAY")
1889 #endif /* not _WIN32 && not __CYGWIN32__ */
1890         ) {
1891         /* use ssh-askpass to get password */
1892         FILE *fp;
1893         char *askpass = getparam(ENV_SSH_ASKPASS), *cmd;
1894         int cmd_size = strlen(askpass) +1 +1 +strlen(buf) +1 +1;
1895         cmd = xmalloc(cmd_size);
1896         snprintf(cmd, cmd_size, "%s \"%s\"", askpass, buf);
1897         fp = popen(cmd, "r");
1898         free(cmd);
1899         if ( fp == NULL )
1900             return NULL;                        /* fail */
1901         buf[0] = '\0';
1902         if (fgets(buf, sizeof(buf), fp) == NULL)
1903             return NULL;                        /* fail */
1904         fclose(fp);
1905     } else {
1906         tty_readpass( buf, buf, sizeof(buf));
1907     }
1908     buf[strcspn(buf, "\r\n")] = '\0';
1909     return buf;
1910 }
1911
1912 static int
1913 socks5_do_auth_userpass( int s )
1914 {
1915     unsigned char buf[1024], *ptr;
1916     char *pass = NULL;
1917     int len;
1918
1919     /* do User/Password authentication. */
1920     /* This feature requires username and password from
1921        command line argument or environment variable,
1922        or terminal. */
1923     if (relay_user == NULL)
1924         fatal("cannot determine user name.\n");
1925
1926     /* get password from environment variable if exists. */
1927     if ((pass=determine_relay_password()) == NULL &&
1928         (pass=readpass("Enter SOCKS5 password for %s@%s: ",
1929                        relay_user, relay_host)) == NULL)
1930         fatal("Cannot get password for user: %s\n", relay_user);
1931
1932     /* make authentication packet */
1933     ptr = buf;
1934     PUT_BYTE( ptr++, 1 );                       /* subnegotiation ver.: 1 */
1935     len = strlen( relay_user );                 /* ULEN and UNAME */
1936     PUT_BYTE( ptr++, len );
1937     strcpy( ptr, relay_user );
1938     ptr += len;
1939     len = strlen( pass );                       /* PLEN and PASSWD */
1940     PUT_BYTE( ptr++, strlen(pass));
1941     strcpy( ptr, pass );
1942     ptr += len;
1943     memset (pass, 0, strlen(pass));             /* erase password */
1944
1945     /* send it and get answer */
1946     f_report = 0;
1947     atomic_out( s, buf, ptr-buf );
1948     f_report = 1;
1949     atomic_in( s, buf, 2 );
1950
1951     /* check status */
1952     if ( buf[1] == 0 )
1953         return 0;                               /* success */
1954     else
1955         return -1;                              /* fail */
1956 }
1957
1958 static const char *
1959 socks5_getauthname( int auth )
1960 {
1961     switch ( auth ) {
1962     case SOCKS5_AUTH_REJECT: return "REJECTED";
1963     case SOCKS5_AUTH_NOAUTH: return "NO-AUTH";
1964     case SOCKS5_AUTH_GSSAPI: return "GSSAPI";
1965     case SOCKS5_AUTH_USERPASS: return "USERPASS";
1966     case SOCKS5_AUTH_CHAP: return "CHAP";
1967     case SOCKS5_AUTH_EAP: return "EAP";
1968     case SOCKS5_AUTH_MAF: return "MAF";
1969     default: return "(unknown)";
1970     }
1971 }
1972
1973 typedef struct {
1974     char* name;
1975     unsigned char auth;
1976 } AUTH_METHOD_ITEM;
1977
1978 AUTH_METHOD_ITEM socks5_auth_table[] = {
1979     { "none", SOCKS5_AUTH_NOAUTH },
1980     { "gssapi", SOCKS5_AUTH_GSSAPI },
1981     { "userpass", SOCKS5_AUTH_USERPASS },
1982     { "chap", SOCKS5_AUTH_CHAP },
1983     { NULL, -1 },
1984 };
1985
1986 int
1987 socks5_auth_parse_1(char *start, char *end){
1988     int i, len;
1989     for ( ; *start; start++ )
1990         if ( *start != ' ' && *start != '\t') break;
1991     for ( end--; end >= start; end-- ) {
1992         if ( *end != ' ' && *end != '\t'){
1993             end++;
1994             break;
1995         }
1996     }
1997     len = end - start;
1998     for ( i = 0; socks5_auth_table[i].name != NULL; i++ ){
1999         if ( strncmp(start, socks5_auth_table[i].name, len) == 0) {
2000             return socks5_auth_table[i].auth;
2001         }
2002     }
2003     fatal("Unknown auth method: %s\n", start);
2004     return -1;
2005 }
2006
2007 int
2008 socks5_auth_parse(char *start, unsigned char *auth_list, int max_auth){
2009     char *end;
2010     int i = 0;
2011     while ( i < max_auth ) {
2012         end = strchr(start, ',');
2013         if (*start && end) {
2014             auth_list[i++] = socks5_auth_parse_1(start, end);
2015             start = ++end;
2016         } else {
2017             break;
2018         }
2019     }
2020     if ( *start && ( i < max_auth ) ){
2021         for( end = start; *end; end++ );
2022         auth_list[i++] = socks5_auth_parse_1(start, end);
2023     } else {
2024         fatal("Too much auth method.\n");
2025     }
2026     return i;
2027 }
2028
2029 /* begin SOCKS5 relaying
2030    And no authentication is supported.
2031  */
2032 int
2033 begin_socks5_relay( SOCKET s )
2034 {
2035     unsigned char buf[256], *ptr, *env = socks5_auth;
2036     unsigned char n_auth = 0; unsigned char auth_list[10], auth_method;
2037     int len, auth_result, i;
2038
2039     debug( "begin_socks_relay()\n");
2040
2041     /* request authentication */
2042     ptr = buf;
2043     PUT_BYTE( ptr++, 5);                        /* SOCKS version (5) */
2044
2045     if ( env == NULL )
2046         env = getparam(ENV_SOCKS5_AUTH);
2047     if ( env == NULL ) {
2048         /* add no-auth authentication */
2049         auth_list[n_auth++] = SOCKS5_AUTH_NOAUTH;
2050         /* add user/pass authentication */
2051         auth_list[n_auth++] = SOCKS5_AUTH_USERPASS;
2052     } else {
2053         n_auth = socks5_auth_parse(env, auth_list, 10);
2054     }
2055     PUT_BYTE( ptr++, n_auth);                   /* num auth */
2056     for (i=0; i<n_auth; i++) {
2057         debug("available auth method[%d] = %s (0x%02x)\n",
2058               i, socks5_getauthname(auth_list[i]), auth_list[i]);
2059         PUT_BYTE( ptr++, auth_list[i]);         /* authentications */
2060     }
2061     atomic_out( s, buf, ptr-buf );              /* send requst */
2062     atomic_in( s, buf, 2 );                     /* recv response */
2063     if ( (buf[0] != 5) ||                       /* ver5 response */
2064          (buf[1] == 0xFF) ) {                   /* check auth method */
2065         error("No auth method accepted.\n");
2066         return -1;
2067     }
2068     auth_method = buf[1];
2069
2070     debug("auth method: %s\n", socks5_getauthname(auth_method));
2071
2072     switch ( auth_method ) {
2073     case SOCKS5_AUTH_REJECT:
2074         error("No acceptable authentication method\n");
2075         return -1;                              /* fail */
2076
2077     case SOCKS5_AUTH_NOAUTH:
2078         /* nothing to do */
2079         auth_result = 0;
2080         break;
2081
2082     case SOCKS5_AUTH_USERPASS:
2083         auth_result = socks5_do_auth_userpass(s);
2084         break;
2085
2086     default:
2087         error("Unsupported authentication method: %s\n",
2088               socks5_getauthname( auth_method ));
2089         return -1;                              /* fail */
2090     }
2091     if ( auth_result != 0 ) {
2092         error("Authentication failed.\n");
2093         return -1;
2094     }
2095     /* request to connect */
2096     ptr = buf;
2097     PUT_BYTE( ptr++, 5);                        /* SOCKS version (5) */
2098     PUT_BYTE( ptr++, 1);                        /* CMD: CONNECT */
2099     PUT_BYTE( ptr++, 0);                        /* FLG: 0 */
2100     if ( dest_addr.sin_addr.s_addr == 0 ) {
2101         /* resolved by SOCKS server */
2102         PUT_BYTE( ptr++, 3);                    /* ATYP: DOMAINNAME */
2103         len = strlen(dest_host);
2104         PUT_BYTE( ptr++, len);                  /* DST.ADDR (len) */
2105         memcpy( ptr, dest_host, len );          /* (hostname) */
2106         ptr += len;
2107     } else {
2108         /* resolved localy */
2109         PUT_BYTE( ptr++, 1 );                   /* ATYP: IPv4 */
2110         memcpy( ptr, &dest_addr.sin_addr.s_addr, sizeof(dest_addr.sin_addr));
2111         ptr += sizeof(dest_addr.sin_addr);
2112     }
2113     PUT_BYTE( ptr++, dest_port>>8);     /* DST.PORT */
2114     PUT_BYTE( ptr++, dest_port&0xFF);
2115     atomic_out( s, buf, ptr-buf);               /* send request */
2116     atomic_in( s, buf, 4 );                     /* recv response */
2117     if ( (buf[1] != SOCKS5_REP_SUCCEEDED) ) {   /* check reply code */
2118         error("Got error response from SOCKS server: %d (%s).\n",
2119               buf[1], lookup(buf[1], socks5_rep_names));
2120         return -1;
2121     }
2122     ptr = buf + 4;
2123     switch ( buf[3] ) {                         /* case by ATYP */
2124     case 1:                                     /* IP v4 ADDR*/
2125         atomic_in( s, ptr, 4+2 );               /* recv IPv4 addr and port */
2126         break;
2127     case 3:                                     /* DOMAINNAME */
2128         atomic_in( s, ptr, 1 );                 /* recv name and port */
2129         atomic_in( s, ptr+1, *(unsigned char*)ptr + 2);
2130         break;
2131     case 4:                                     /* IP v6 ADDR */
2132         atomic_in( s, ptr, 16+2 );              /* recv IPv6 addr and port */
2133         break;
2134     }
2135
2136     /* Conguraturation, connected via SOCKS5 server! */
2137     return 0;
2138 }
2139
2140 /* begin SOCKS protocol 4 relaying
2141    And no authentication is supported.
2142
2143    There's SOCKS protocol version 4 and 4a. Protocol version
2144    4a has capability to resolve hostname by SOCKS server, so
2145    we don't need resolving IP address of destination host on
2146    local machine.
2147
2148    Environment variable SOCKS_RESOLVE directs how to resolve
2149    IP addess. There's 3 keywords allowed; "local", "remote"
2150    and "both" (case insensitive). Keyword "local" means taht
2151    target host name is resolved by localhost resolver
2152    (usualy with gethostbyname()), "remote" means by remote
2153    SOCKS server, "both" means to try resolving by localhost
2154    then remote.
2155
2156    SOCKS4 protocol and authentication of SOCKS5 protocol
2157    requires user name on connect request.
2158    User name is determined by following method.
2159
2160    1. If server spec has user@hostname:port format then
2161       user part is used for this SOCKS server.
2162
2163    2. Get user name from environment variable LOGNAME, USER
2164       (in this order).
2165
2166 */
2167 int
2168 begin_socks4_relay( SOCKET s )
2169 {
2170     unsigned char buf[256], *ptr;
2171
2172     debug( "begin_socks_relay()\n");
2173
2174     /* make connect request packet
2175        protocol v4:
2176          VN:1, CD:1, PORT:2, ADDR:4, USER:n, NULL:1
2177        protocol v4a:
2178          VN:1, CD:1, PORT:2, DUMMY:4, USER:n, NULL:1, HOSTNAME:n, NULL:1
2179     */
2180     ptr = buf;
2181     PUT_BYTE( ptr++, 4);                        /* protocol version (4) */
2182     PUT_BYTE( ptr++, 1);                        /* CONNECT command */
2183     PUT_BYTE( ptr++, dest_port>>8);     /* destination Port */
2184     PUT_BYTE( ptr++, dest_port&0xFF);
2185     /* destination IP */
2186     memcpy(ptr, &dest_addr.sin_addr, sizeof(dest_addr.sin_addr));
2187     ptr += sizeof(dest_addr.sin_addr);
2188     if ( dest_addr.sin_addr.s_addr == 0 )
2189         *(ptr-1) = 1;                           /* fake, protocol 4a */
2190     /* username */
2191     if (relay_user == NULL)
2192         fatal( "Cannot determine user name.\n");
2193     strcpy( ptr, relay_user );
2194     ptr += strlen( relay_user ) +1;
2195     /* destination host name (for protocol 4a) */
2196     if ( (socks_version == 4) && (dest_addr.sin_addr.s_addr == 0)) {
2197         strcpy( ptr, dest_host );
2198         ptr += strlen( dest_host ) +1;
2199     }
2200     /* send command and get response
2201        response is: VN:1, CD:1, PORT:2, ADDR:4 */
2202     atomic_out( s, buf, ptr-buf);               /* send request */
2203     atomic_in( s, buf, 8 );                     /* recv response */
2204     if ( (buf[1] != SOCKS4_REP_SUCCEEDED) ) {   /* check reply code */
2205         error("Got error response: %d: '%s'.\n",
2206               buf[1], lookup(buf[1], socks4_rep_names));
2207         return -1;                              /* failed */
2208     }
2209
2210     /* Conguraturation, connected via SOCKS4 server! */
2211     return 0;
2212 }
2213
2214 int
2215 sendf(SOCKET s, const char *fmt,...)
2216 {
2217     static char buf[10240];                     /* xxx, enough? */
2218
2219     va_list args;
2220     va_start( args, fmt );
2221     vsnprintf( buf, sizeof(buf), fmt, args );
2222     va_end( args );
2223
2224     report_text(">>>", buf);
2225     if ( send(s, buf, strlen(buf), 0) == SOCKET_ERROR ) {
2226         debug("failed to send http request. errno=%d\n", socket_errno());
2227         return -1;
2228     }
2229     return 0;
2230 }
2231
2232 const char *base64_table =
2233 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2234
2235 char *
2236 make_base64_string(const char *str)
2237 {
2238     static char *buf;
2239     unsigned char *src;
2240     char *dst;
2241     int bits, data, src_len, dst_len;
2242     /* make base64 string */
2243     src_len = strlen(str);
2244     dst_len = (src_len+2)/3*4;
2245     buf = xmalloc(dst_len+1);
2246     bits = data = 0;
2247     src = (unsigned char *)str;
2248     dst = (unsigned char *)buf;
2249     while ( dst_len-- ) {
2250         if ( bits < 6 ) {
2251             data = (data << 8) | *src;
2252             bits += 8;
2253             if ( *src != 0 )
2254                 src++;
2255         }
2256         *dst++ = base64_table[0x3F & (data >> (bits-6))];
2257         bits -= 6;
2258     }
2259     *dst = '\0';
2260     /* fix-up tail padding */
2261     switch ( src_len%3 ) {
2262     case 1:
2263         *--dst = '=';
2264     case 2:
2265         *--dst = '=';
2266     }
2267     return buf;
2268 }
2269
2270
2271 int
2272 basic_auth (SOCKET s)
2273 {
2274     char *userpass;
2275     char *cred;
2276     const char *user = relay_user;
2277     char *pass = NULL;
2278     int len, ret;
2279
2280     /* Get username/password for authentication */
2281     if (user == NULL)
2282         fatal("Cannot decide username for proxy authentication.");
2283     if ((pass = determine_relay_password ()) == NULL &&
2284         (pass = readpass("Enter proxy authentication password for %s@%s: ",
2285                          relay_user, relay_host)) == NULL)
2286         fatal("Cannot decide password for proxy authentication.");
2287
2288     len = strlen(user)+strlen(pass)+1;
2289     userpass = xmalloc(len+1);
2290     snprintf(userpass, len+1, "%s:%s", user, pass);
2291     memset (pass, 0, strlen(pass));
2292     cred = make_base64_string(userpass);
2293     memset (userpass, 0, len);
2294
2295     f_report = 0;                               /* don't report for security */
2296     ret = sendf(s, "Proxy-Authorization: Basic %s\r\n", cred);
2297     f_report = 1;
2298     report_text(">>>", "Proxy-Authorization: Basic xxxxx\r\n");
2299
2300     memset(cred, 0, strlen(cred));
2301     free(cred);
2302
2303     return ret;
2304 }
2305
2306 /* begin relaying via HTTP proxy
2307    Directs CONNECT method to proxy server to connect to
2308    destination host (and port). It may not be allowed on your
2309    proxy server.
2310  */
2311 int
2312 begin_http_relay( SOCKET s )
2313 {
2314     char buf[1024];
2315     int result;
2316     char *auth_what;
2317
2318     debug("begin_http_relay()\n");
2319
2320     if (sendf(s,"CONNECT %s:%d HTTP/1.0\r\n", dest_host, dest_port) < 0)
2321         return START_ERROR;
2322     if (proxy_auth_type == PROXY_AUTH_BASIC && basic_auth (s) < 0)
2323         return START_ERROR;
2324     if (sendf(s,"\r\n") < 0)
2325         return START_ERROR;
2326
2327     /* get response */
2328     if ( line_input(s, buf, sizeof(buf)) < 0 ) {
2329         debug("failed to read http response.\n");
2330         return START_ERROR;
2331     }
2332
2333     /* check status */
2334     if (!strchr(buf, ' ')) {
2335         error ("Unexpected http response: '%s'.\n", buf);
2336         return START_ERROR;
2337     }
2338     result = atoi(strchr(buf,' '));
2339
2340     switch ( result ) {
2341     case 200:
2342         /* Conguraturation, connected via http proxy server! */
2343         debug("connected, start user session.\n");
2344         break;
2345     case 302:                                   /* redirect */
2346         do {
2347             if (line_input(s, buf, sizeof(buf)))
2348                 break;
2349             downcase(buf);
2350             if (expect(buf, "Location: ")) {
2351                 relay_host = cut_token(buf, "//");
2352                 cut_token(buf, "/");
2353                 relay_port = atoi(cut_token(buf, ":"));
2354             }
2355         } while (strcmp(buf,"\r\n") != 0);
2356         return START_RETRY;
2357
2358     /* We handle both 401 and 407 codes here: 401 is WWW-Authenticate, which
2359      * not strictly the correct response, but some proxies do send this (e.g.
2360      * Symantec's Raptor firewall) */
2361     case 401:                                   /* WWW-Auth required */
2362     case 407:                                   /* Proxy-Auth required */
2363         /** NOTE: As easy implementation, we support only BASIC scheme
2364             and ignore realm. */
2365         /* If proxy_auth_type is PROXY_AUTH_BASIC and get
2366          this result code, authentication was failed. */
2367         if (proxy_auth_type != PROXY_AUTH_NONE) {
2368             error("Authentication failed.\n");
2369             return START_ERROR;
2370         }
2371         auth_what = (result == 401) ? "WWW-Authenticate:" : "Proxy-Authenticate:";
2372         do {
2373             if ( line_input(s, buf, sizeof(buf)) ) {
2374                 break;
2375             }
2376             downcase(buf);
2377             if (expect(buf, auth_what)) {
2378                 /* parse type and realm */
2379                 char *scheme, *realm;
2380                 scheme = cut_token(buf, " ");
2381                 realm = cut_token(scheme, " ");
2382                 if ( scheme == NULL || realm == NULL ) {
2383                     debug("Invalid format of %s field.", auth_what);
2384                     return START_ERROR;         /* fail */
2385                 }
2386                 /* check supported auth type */
2387                 if (expect(scheme, "basic")) {
2388                     proxy_auth_type = PROXY_AUTH_BASIC;
2389                 } else {
2390                     debug("Unsupported authentication type: %s", scheme);
2391                 }
2392             }
2393         } while (strcmp(buf,"\r\n") != 0);
2394         if ( proxy_auth_type == PROXY_AUTH_NONE ) {
2395             debug("Can't find %s in response header.", auth_what);
2396             return START_ERROR;
2397         } else {
2398             return START_RETRY;
2399         }
2400
2401     default:
2402         /* Not allowed */
2403         debug("http proxy is not allowed.\n");
2404         return START_ERROR;
2405     }
2406     /* skip to end of response header */
2407     do {
2408         if ( line_input(s, buf, sizeof(buf) ) ) {
2409             debug("Can't skip response headers\n");
2410             return START_ERROR;
2411         }
2412     } while ( strcmp(buf,"\r\n") != 0 );
2413
2414     return START_OK;
2415 }
2416
2417 /* begin relaying via TELNET proxy.
2418    Sends string specified by telnet_command (-c option) with
2419    replacing host name and port number to the socket.  */
2420 int
2421 begin_telnet_relay( SOCKET s )
2422 {
2423     char buf[1024];
2424     char *cmd;
2425     char *good_phrase = "connected to";
2426     char *bad_phrase_list[] = {
2427         " failed", " refused", " rejected", " closed"
2428     };
2429     char sep = ' ';
2430     int i;
2431
2432     debug("begin_telnet_relay()\n");
2433
2434     /* report phrase */
2435     debug("good phrase: '%s'\n", good_phrase);
2436     debug("bad phrases");
2437     sep = ':';
2438     for (i=0; i< (sizeof(bad_phrase_list) / sizeof(char*)); i++) {
2439         debug_("%c '%s'", sep, bad_phrase_list[i]);
2440         sep = ',';
2441     }
2442     debug_("\n");
2443
2444     /* make request string with replacing %h by destination hostname
2445        and %p by port number, etc. */
2446     cmd = expand_host_and_port(telnet_command, dest_host, dest_port);
2447     
2448     /* Sorry, we send request string now without waiting a prompt. */
2449     if (sendf(s, "%s\r\n", cmd) < 0) {
2450         free(cmd);
2451         return START_ERROR;
2452     }
2453     free(cmd);
2454
2455     /* Process answer from proxy until good or bad phrase is detected.  We
2456        assume that the good phrase should be appeared only in the final
2457        line of proxy responses. Bad keywods in the line causes operation
2458        fail. First checks a good phrase, then checks bad phrases.
2459        If no match, continue reading line from proxy. */
2460     while (!line_input(s, buf, sizeof(buf)) && buf[0] != '\0') {
2461         downcase(buf);
2462         /* first, check good phrase */
2463         if (strstr(buf, good_phrase)) {
2464             debug("good phrase is detected: '%s'\n", good_phrase);
2465             return START_OK;
2466         }
2467         /* then, check bad phrase */
2468         for (i=0; i<(sizeof(bad_phrase_list)/sizeof(char*)); i++) {
2469             if (strstr(buf, bad_phrase_list[i]) != NULL) {
2470                 debug("bad phrase is detected: '%s'\n", bad_phrase_list[i]);
2471                 return START_ERROR;
2472             }
2473         }
2474     }
2475     debug("error reading from telnet proxy\n");
2476
2477     return START_ERROR;
2478 }
2479
2480
2481 #ifdef _WIN32
2482 /* ddatalen()
2483    Returns 1 if data is available, otherwise return 0
2484  */
2485 int
2486 stdindatalen (void)
2487 {
2488     DWORD len = 0;
2489     struct stat st;
2490     fstat( 0, &st );
2491     if ( st.st_mode & _S_IFIFO ) {
2492         /* in case of PIPE */
2493         if ( !PeekNamedPipe( GetStdHandle(STD_INPUT_HANDLE),
2494                              NULL, 0, NULL, &len, NULL) ) {
2495             if ( GetLastError() == ERROR_BROKEN_PIPE ) {
2496                 /* PIPE source is closed */
2497                 /* read() will detects EOF */
2498                 len = 1;
2499             } else {
2500                 fatal("PeekNamedPipe() failed, errno=%d\n",
2501                       GetLastError());
2502             }
2503         }
2504     } else if ( st.st_mode & _S_IFREG ) {
2505         /* in case of regular file (redirected) */
2506         len = 1;                        /* always data ready */
2507     } else if ( _kbhit() ) {
2508         /* in case of console */
2509         len = 1;
2510     }
2511     return len;
2512 }
2513 #endif /* _WIN32 */
2514
2515 /* relay byte from stdin to socket and fro socket to stdout.
2516    returns reason of termination */
2517 int
2518 do_repeater( SOCKET local_in, SOCKET local_out, SOCKET remote )
2519 {
2520     /** vars for local input data **/
2521     char lbuf[1024];                            /* local input buffer */
2522     int lbuf_len;                               /* available data in lbuf */
2523     int f_local;                                /* read local input more? */
2524     /** vars for remote input data **/
2525     char rbuf[1024];                            /* remote input buffer */
2526     int rbuf_len;                               /* available data in rbuf */
2527     int f_remote;                               /* read remote input more? */
2528     int close_reason = REASON_UNK;              /* reason of end repeating */
2529     /** other variables **/
2530     int nfds, len;
2531     fd_set ifds, ofds;
2532     struct timeval *tmo;
2533 #ifdef _WIN32
2534     struct timeval win32_tmo;
2535 #endif /* _WIN32 */
2536
2537     /* repeater between stdin/out and socket  */
2538     nfds = ((local_in<remote)? remote: local_in) +1;
2539     f_local = 1;                                /* yes, read from local */
2540     f_remote = 1;                               /* yes, read from remote */
2541     lbuf_len = 0;
2542     rbuf_len = 0;
2543
2544     while ( f_local || f_remote ) {
2545         FD_ZERO(&ifds );
2546         FD_ZERO(&ofds );
2547         tmo = NULL;
2548
2549         /** prepare for reading local input **/
2550         if ( f_local && (lbuf_len < (int)sizeof(lbuf)) ) {
2551 #ifdef _WIN32
2552             if ( local_type != LOCAL_SOCKET ) {
2553                 /* select() on Winsock is not accept standard handle.
2554                    So use select() with short timeout and checking data
2555                    in stdin by another method. */
2556                 win32_tmo.tv_sec = 0;
2557                 win32_tmo.tv_usec = 10*1000;    /* 10 ms */
2558                 tmo = &win32_tmo;
2559             } else
2560 #endif /* !_WIN32 */
2561             FD_SET( local_in, &ifds );
2562         }
2563
2564         /** prepare for reading remote input **/
2565         if ( f_remote && (rbuf_len < (int)sizeof(rbuf)) ) {
2566             FD_SET( remote, &ifds );
2567         }
2568
2569         /* FD_SET( local_out, ofds ); */
2570         /* FD_SET( remote, ofds ); */
2571
2572         if ( select( nfds, &ifds, &ofds, (fd_set*)NULL, tmo ) == -1 ) {
2573             /* some error */
2574             error( "select() failed, %d\n", socket_errno());
2575             return REASON_ERROR;
2576         }
2577 #ifdef _WIN32
2578         /* fake ifds if local is stdio handle because
2579            select() of Winsock does not accept stdio
2580            handle. */
2581         if (f_local && (local_type!=LOCAL_SOCKET) && (0<stdindatalen()))
2582             FD_SET(0,&ifds);            /* data ready */
2583 #endif
2584
2585         /* remote => local */
2586         if ( FD_ISSET(remote, &ifds) && (rbuf_len < (int)sizeof(rbuf)) ) {
2587             len = recv( remote, rbuf + rbuf_len, sizeof(rbuf)-rbuf_len, 0);
2588             if ( len == 0 ) {
2589                 debug("connection closed by peer\n");
2590                 close_reason = REASON_CLOSED_BY_REMOTE;
2591                 f_remote = 0;                   /* no more read from socket */
2592                 f_local = 0;
2593             } else if ( len == -1 ) {
2594                 if (socket_errno() != ECONNRESET) {
2595                     /* error */
2596                     fatal("recv() faield, %d\n", socket_errno());
2597                 } else {
2598                     debug("ECONNRESET detected\n");
2599                 }
2600             } else {
2601                 debug("recv %d bytes\n", len);
2602                 if ( 1 < f_debug )              /* more verbose */
2603                     report_bytes( "<<<", rbuf, rbuf_len);
2604                 rbuf_len += len;
2605             }
2606         }
2607
2608         /* local => remote */
2609         if ( FD_ISSET(local_in, &ifds) && (lbuf_len < (int)sizeof(lbuf)) ) {
2610             if (local_type == LOCAL_SOCKET)
2611                 len = recv(local_in, lbuf + lbuf_len,
2612                            sizeof(lbuf)-lbuf_len, 0);
2613             else
2614                 len = read(local_in, lbuf + lbuf_len, sizeof(lbuf)-lbuf_len);
2615             if ( len == 0 ) {
2616                 /* stdin is EOF */
2617                 debug("local input is EOF\n");
2618                 if (!f_hold_session)
2619                     shutdown(remote, 1);        /* no-more writing */
2620                 f_local = 0;
2621                 close_reason = REASON_CLOSED_BY_LOCAL;
2622             } else if ( len == -1 ) {
2623                 /* error on reading from stdin */
2624                 if (f_hold_session) {
2625                     debug ("failed to read from local\n");
2626                     f_local = 0;
2627                     close_reason = REASON_CLOSED_BY_LOCAL;
2628                 } else
2629                     fatal("recv() failed, errno = %d\n", errno);
2630             } else {
2631                 /* repeat */
2632                 lbuf_len += len;
2633             }
2634         }
2635
2636         /* flush data in buffer to socket */
2637         if ( 0 < lbuf_len ) {
2638             len = send(remote, lbuf, lbuf_len, 0);
2639             if ( 1 < f_debug )          /* more verbose */
2640                 report_bytes( ">>>", lbuf, lbuf_len);
2641             if ( len == -1 ) {
2642                 fatal("send() failed, %d\n", socket_errno());
2643             } else if ( 0 < len ) {
2644                 /* move data on to top of buffer */
2645                 debug("send %d bytes\n", len);
2646                 lbuf_len -= len;
2647                 if ( 0 < lbuf_len )
2648                     memcpy( lbuf, lbuf+len, lbuf_len );
2649                 assert( 0 <= lbuf_len );
2650             }
2651         }
2652
2653         /* flush data in buffer to local output */
2654         if ( 0 < rbuf_len ) {
2655             if (local_type == LOCAL_SOCKET)
2656                 len = send( local_out, rbuf, rbuf_len, 0);
2657             else
2658                 len = write( local_out, rbuf, rbuf_len);
2659             if ( len == -1 ) {
2660                 fatal("output (local) failed, errno=%d\n", errno);
2661             }
2662             rbuf_len -= len;
2663             if ( len < rbuf_len )
2664                 memcpy( rbuf, rbuf+len, rbuf_len );
2665             assert( 0 <= rbuf_len );
2666         }
2667         if (f_local == 0 && f_hold_session) {
2668             debug ("closing local port without disconnecting from remote\n");
2669             f_remote = 0;
2670             shutdown (local_out, 2);
2671             close (local_out);
2672             break;
2673         }
2674     }
2675
2676     return close_reason;
2677 }
2678
2679 int
2680 accept_connection (u_short port)
2681 {
2682     static int sock = -1;
2683     int connection;
2684     struct sockaddr_in name;
2685     struct sockaddr client;
2686     int socklen;
2687     fd_set ifds;
2688     int nfds;
2689     int sockopt;
2690
2691     /* Create the socket. */
2692     debug("Creating source port to forward.\n");
2693     sock = socket (PF_INET, SOCK_STREAM, 0);
2694     if (sock < 0)
2695         fatal("socket() failed, errno=%d\n", socket_errno());
2696     sockopt = 1;
2697     setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
2698                 (void*)&sockopt, sizeof(sockopt));
2699
2700     /* Give the socket a name. */
2701     name.sin_family = AF_INET;
2702     name.sin_port = htons (port);
2703     name.sin_addr.s_addr = htonl (INADDR_ANY);
2704     if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
2705         fatal ("bind() failed, errno=%d\n", socket_errno());
2706
2707     if (listen( sock, 1) < 0)
2708         fatal ("listen() failed, errno=%d\n", socket_errno());
2709
2710     /* wait for new connection with watching EOF of stdin. */
2711     debug ("waiting new connection at port %d (socket=%d)\n", port, sock);
2712     nfds = sock + 1;
2713     do {
2714         int n;
2715         struct timeval *ptmo = NULL;
2716 #ifdef _WIN32
2717         struct timeval tmo;
2718         tmo.tv_sec = 0;
2719         tmo.tv_usec = 100*1000;                 /* On Windows, 100ms timeout */
2720         ptmo = &tmo;
2721 #endif /* _WIN32 */
2722         FD_ZERO (&ifds);
2723         FD_SET ((SOCKET)sock, &ifds);
2724 #ifndef _WIN32
2725         FD_SET (0, &ifds);                      /* watch stdin */
2726 #endif
2727         n = select (nfds, &ifds, NULL, NULL, ptmo);
2728         if (n == -1) {
2729             fatal ("select() failed, %d\n", socket_errno());
2730             exit (1);
2731         }
2732 #ifdef _WIN32
2733         if (0 < stdindatalen()) {
2734             FD_SET (0, &ifds);          /* fake */
2735             n++;
2736         }
2737 #endif
2738         if (0 < n) {
2739             if (FD_ISSET(0, &ifds) && (getchar() <= 0)) {
2740                 /* EOF */
2741                 debug ("Give-up waiting port because stdin is closed.");
2742                 exit(0);
2743             }
2744             if (FD_ISSET(sock, &ifds))
2745                 break;                          /* socket is stimulated */
2746         }
2747     } while (1);
2748     socklen = sizeof(client);
2749     connection = accept( sock, &client, &socklen);
2750     if ( connection < 0 )
2751         fatal ("accept() failed, errno=%d\n", socket_errno());
2752     return connection;
2753 }
2754
2755
2756
2757 /** Main of program **/
2758 int
2759 main( int argc, char **argv )
2760 {
2761     int ret;
2762     int remote;                                 /* socket */
2763     int local_in;                               /* Local input */
2764     int local_out;                              /* Local output */
2765     int reason;
2766 #ifdef _WIN32
2767     WSADATA wsadata;
2768     WSAStartup( 0x101, &wsadata);
2769 #endif /* _WIN32 */
2770
2771     /* initialization */
2772     make_revstr();
2773     getarg( argc, argv );
2774     debug("Program is $Revision$\n");
2775
2776     /* Open local_in and local_out if forwarding a port */
2777     if ( local_type == LOCAL_SOCKET ) {
2778         /* Relay between local port and destination */
2779         local_in = local_out = accept_connection( local_port );
2780     } else {
2781         /* Relay between stdin/stdout and desteination */
2782         local_in = 0;
2783         local_out = 1;
2784 #ifdef _WIN32
2785         _setmode(local_in, O_BINARY);
2786         _setmode(local_out, O_BINARY);
2787 #endif
2788     }
2789
2790 retry:
2791 #ifndef _WIN32
2792     if (0 < connect_timeout)
2793         set_timeout (connect_timeout);
2794 #endif /* not _WIN32 */
2795
2796     /* make connection */
2797     if ( relay_method == METHOD_DIRECT ) {
2798         remote = open_connection (dest_host, dest_port);
2799         if ( remote == SOCKET_ERROR )
2800             fatal( "Unable to connect to destination host, errno=%d\n",
2801                    socket_errno());
2802     } else {
2803         remote = open_connection (relay_host, relay_port);
2804         if ( remote == SOCKET_ERROR )
2805             fatal( "Unable to connect to relay host, errno=%d\n",
2806                    socket_errno());
2807     }
2808
2809     /** resolve destination host (SOCKS) **/
2810 #if !defined(_WIN32) && !defined(__CYGWIN32__)
2811     if (socks_ns.sin_addr.s_addr != 0)
2812         switch_ns (&socks_ns);
2813 #endif /* not _WIN32 && not __CYGWIN32__ */
2814     if (relay_method == METHOD_SOCKS &&
2815         socks_resolve == RESOLVE_LOCAL &&
2816         local_resolve (dest_host, &dest_addr) < 0) {
2817         fatal("Unknown host: %s", dest_host);
2818     }
2819
2820     /** relay negociation **/
2821     switch ( relay_method ) {
2822     case METHOD_SOCKS:
2823         if ( ((socks_version == 5) && (begin_socks5_relay(remote) < 0)) ||
2824              ((socks_version == 4) && (begin_socks4_relay(remote) < 0)) )
2825             fatal( "failed to begin relaying via SOCKS.\n");
2826         break;
2827
2828     case METHOD_HTTP:
2829         ret = begin_http_relay(remote);
2830         switch (ret) {
2831         case START_ERROR:
2832             close (remote);
2833             fatal("failed to begin relaying via HTTP.\n");
2834         case START_OK:
2835             break;
2836         case START_RETRY:
2837             /* retry with authentication */
2838             close (remote);
2839             goto retry;
2840         }
2841         break;
2842     case METHOD_TELNET:
2843         if (begin_telnet_relay(remote) < 0)
2844              fatal("failed to begin relaying via telnet.\n");
2845         break;
2846     }
2847     debug("connected\n");
2848
2849 #ifndef _WIN32
2850     if (0 < connect_timeout)
2851         set_timeout (0);
2852 #endif /* not _WIN32 */
2853
2854     /* main loop */
2855     debug ("start relaying.\n");
2856 do_repeater:
2857     reason = do_repeater(local_in, local_out, remote);
2858     debug ("relaying done.\n");
2859     if (local_type == LOCAL_SOCKET &&
2860         reason == REASON_CLOSED_BY_LOCAL &&
2861         f_hold_session) {
2862         /* re-wait at local port without closing remote session */
2863         debug ("re-waiting at local port %d\n", local_port);
2864         local_in = local_out = accept_connection( local_port );
2865         debug ("re-start relaying\n");
2866         goto do_repeater;
2867     }
2868     closesocket(remote);
2869     if ( local_type == LOCAL_SOCKET)
2870         closesocket(local_in);
2871 #ifdef _WIN32
2872     WSACleanup();
2873 #endif /* _WIN32 */
2874     debug ("that's all, bye.\n");
2875
2876     return 0;
2877 }
2878
2879 /* ------------------------------------------------------------
2880    Local Variables:
2881    compile-command: "cc connect.c -o connect"
2882    tab-width: 8
2883    fill-column: 74
2884    comment-column: 48
2885    End:
2886    ------------------------------------------------------------ */
2887
2888 /*** end of connect.c ***/
This page took 0.41568 seconds and 3 git commands to generate.