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