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