- updated to 1.9.1
[packages/proxytunnel.git] / proxytunnel-git.patch
CommitLineData
2a2b5a0b
AG
1diff --git a/.gitignore b/.gitignore
2new file mode 100644
3index 0000000..c15583a
4--- /dev/null
5+++ b/.gitignore
6@@ -0,0 +1,4 @@
7+*.o
8+*.exec
9+proxytunnel.exe
10+proxytunnel
11diff --git a/.travis.yml b/.travis.yml
12new file mode 100644
13index 0000000..1348562
14--- /dev/null
15+++ b/.travis.yml
16@@ -0,0 +1,14 @@
17+language: c
18+compiler:
19+ - clang
20+ - gcc
21+addons:
22+ apt:
23+ packages:
24+ - asciidoc
25+ - xmlto
26+install:
27+ - make clean
28+script:
29+ - make
30+ - make docs
31\ No newline at end of file
32diff --git a/Makefile b/Makefile
33index 006b5b1..57328e8 100644
34--- a/Makefile
35+++ b/Makefile
36@@ -5,17 +5,9 @@
37 name = proxytunnel
38 version = $(shell awk 'BEGIN { FS="\"" } /^\#define VERSION / { print $$2 }' config.h)
39
40-ifneq ($(wildcard .svn),)
41-revision = $(shell svnversion | awk 'BEGIN { RS=":" } { next } END { print $$1 }')
42-else
43-revision = $(shell echo '$$Revision$$' | sed -e 's/\$$Revision: \([0-9]\+\) \$$$$/\1/')
44-endif
45-
46 CC ?= cc
47 CFLAGS ?= -Wall -O2 -ggdb
48
49-OPTFLAGS = -DREVISION=\"$(revision)\"
50-
51 # Comment on non-gnu systems
52 OPTFLAGS += -DHAVE_GETOPT_LONG
53
54@@ -46,9 +38,9 @@ OPTFLAGS += -DSO_REUSEPORT
55
56 # END system dependant block
57
58-SSL_LIBS := $(shell pkg-config --libs libssl 2>/dev/null)
59-ifeq ($(SSL_LIBS),)
60 SSL_LIBS := $(shell pkg-config --libs openssl 2>/dev/null)
61+ifeq ($(SSL_LIBS),)
62+SSL_LIBS := $(shell pkg-config --libs libssl 2>/dev/null)
63 endif
64 ifeq ($(SSL_LIBS),)
65 SSL_LIBS := -lssl -lcrypto
66@@ -63,8 +55,6 @@ mandir = $(datadir)/man
67 # Remove strlcpy/strlcat on (open)bsd/darwin systems
68 OBJ = proxytunnel.o \
69 base64.o \
70- strlcpy.o \
71- strlcat.o \
72 strzcat.o \
73 setproctitle.o \
74 io.o \
75@@ -76,9 +66,15 @@ OBJ = proxytunnel.o \
76 ntlm.o \
77 ptstream.o
78
79+UNAME = $(shell uname)
80+ifneq ($(UNAME),Darwin)
81+OBJ += strlcpy.o \
82+ strlcat.o
83+endif
84+
85 .PHONY: all clean docs install
86
87-all: proxytunnel docs
88+all: proxytunnel
89
90 docs:
91 $(MAKE) -C docs
92@@ -91,7 +87,8 @@ clean:
93 $(MAKE) -C docs clean
94
95 install:
96- install -Dp -m0755 $(name) $(DESTDIR)$(bindir)/$(name)
97+ install -d $(DESTDIR)$(bindir)
98+ install -p -m555 $(name) $(DESTDIR)$(bindir)
99 $(MAKE) -C docs install
100
101 .c.o:
102diff --git a/README b/README
103index 1c30836..bdb7fe3 100644
104--- a/README
105+++ b/README
106@@ -3,8 +3,6 @@ proxytunnel
107 -----------
108
109 Author: Jos Visser <josv@osp.nl>, Mark Janssen <maniac@maniac.nl>
110-Date: Mon Mar 3 22:49:43 CET 2008
111-Version: 1.9.0
112
113 Hi all,
114
115@@ -22,27 +20,32 @@ Proxytunnel is very easy to use, when running proxytunnel with the help
116 option it specifies it's command-line options.
117
118 $ ./proxytunnel --help
119-proxytunnel 1.9.0 (rev 224) Copyright 2001-2008 Proxytunnel Project
120+proxytunnel 1.9.9 Copyright 2001-2018 Proxytunnel Project
121 Usage: proxytunnel [OPTIONS]...
122-Build generic tunnels trough HTTPS proxy's, supports HTTP authorization
123+Build generic tunnels through HTTPS proxies using HTTP authentication
124
125 Standard options:
126- -i, --inetd Run from inetd (default=off)
127+ -i, --inetd Run from inetd (default: off)
128 -a, --standalone=INT Run as standalone daemon on specified port
129 -p, --proxy=STRING Local proxy host:port combination
130 -r, --remproxy=STRING Remote proxy host:port combination (using 2 proxies)
131 -d, --dest=STRING Destination host:port combination
132 -e, --encrypt SSL encrypt data between local proxy and destination
133 -E, --encrypt-proxy SSL encrypt data between client and local proxy
134- -X, --encrypt-remproxy Encrypt between 1st and 2nd proxy using SSL
135+ -X, --encrypt-remproxy SSL encrypt data between local and remote proxy
136+ -L (legacy) enforce TLSv1 connection
137+ -T, --no-ssl3 Do not connect using SSLv3
138
139 Additional options for specific features:
140+ -z, --no-check-certficate Don't verify server SSL certificate
141+ -C, --cacert=STRING Path to trusted CA certificate or directory
142 -F, --passfile=STRING File with credentials for proxy authentication
143 -P, --proxyauth=STRING Proxy auth credentials user:pass combination
144- -R, --remproxyauth=STRING Remote proxy auth credentials user:pass combination
145+ -R, --remproxyauth=STRING Remote proxy auth credentials user:pass combination
146 -N, --ntlm Use NTLM based authentication
147 -t, --domain=STRING NTLM domain (default: autodetect)
148 -H, --header=STRING Add additional HTTP headers to send to proxy
149+ -o STRING send custom Host Header
150 -x, --proctitle=STRING Use a different process title
151
152 Miscellaneous options:
153@@ -51,7 +54,6 @@ Miscellaneous options:
154 -h, --help Print help and exit
155 -V, --version Print version and exit
156
157-
158 To use this program with OpenSSH to connect to a host somewhere, create
159 a $HOME/.ssh/config file with the following content:
160
161diff --git a/TODO b/TODO
162index 4339a0f..45c19e4 100644
163--- a/TODO
164+++ b/TODO
165@@ -8,14 +8,11 @@
166
167
168 ### SSL proxy support
169-- Lobby for the Apache project to allow CONNECT over SSL (much like GET,
170- PUT and HEAD is supported over SSL)
171- see: http://issues.apache.org/bugzilla/show_bug.cgi?id=29744
172+- Starting with Apache 2.4 using CONNECT over SSL is supported !!
173+ See: http://issues.apache.org/bugzilla/show_bug.cgi?id=29744
174
175
176 ### Code cleanup
177-- Fix permissions in subversion tree (some files are wrongly executable)
178-
179 - Find some hardcore C experts to help us improve the code quality
180
181 - Improve the error output, make it consistent throughout the program
182diff --git a/cmdline.c b/cmdline.c
183index 15ebe98..e1ee9b0 100644
184--- a/cmdline.c
185+++ b/cmdline.c
186@@ -38,14 +38,14 @@ extern char * optarg;
187 static char *getCredentialsFromFile( const char* filename, char **user, char **pass, char **rem_user, char **rem_pass);
188
189 void cmdline_parser_print_version (void) {
190- printf ("%s %s (rev %s) Copyright 2001-2008 Proxytunnel Project\n", PACKAGE, VERSION, REVISION);
191+ printf ("%s %s Copyright 2001-2018 Proxytunnel Project\n", PACKAGE, VERSION);
192 }
193
194 void cmdline_parser_print_help (void) {
195 cmdline_parser_print_version ();
196 printf(
197 "Usage: %s [OPTIONS]...\n"
198-"Build generic tunnels trough HTTPS proxies using HTTP authentication\n"
199+"Build generic tunnels through HTTPS proxies using HTTP authentication\n"
200 "\n"
201 "Standard options:\n"
202 // FIXME: " -c, --config=FILE Read config options from file\n"
203@@ -59,9 +59,15 @@ void cmdline_parser_print_help (void) {
204 " -e, --encrypt SSL encrypt data between local proxy and destination\n"
205 " -E, --encrypt-proxy SSL encrypt data between client and local proxy\n"
206 " -X, --encrypt-remproxy SSL encrypt data between local and remote proxy\n"
207+" -L (legacy) enforce TLSv1 connection\n"
208+" -T, --no-ssl3 Do not connect using SSLv3\n"
209 #endif
210 "\n"
211 "Additional options for specific features:\n"
212+#ifdef USE_SSL
213+" -z, --no-check-certficate Don't verify server SSL certificate\n"
214+" -C, --cacert=STRING Path to trusted CA certificate or directory\n"
215+#endif
216 " -F, --passfile=STRING File with credentials for proxy authentication\n"
217 " -P, --proxyauth=STRING Proxy auth credentials user:pass combination\n"
218 " -R, --remproxyauth=STRING Remote proxy auth credentials user:pass combination\n"
219@@ -72,6 +78,7 @@ void cmdline_parser_print_help (void) {
220 " -N, --ntlm Use NTLM based authentication\n"
221 " -t, --domain=STRING NTLM domain (default: autodetect)\n"
222 " -H, --header=STRING Add additional HTTP headers to send to proxy\n"
223+" -o STRING send custom Host Header\n"
224 #ifdef SETPROCTITLE
225 " -x, --proctitle=STRING Use a different process title\n"
226 #endif
227@@ -132,6 +139,9 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
228 args_info->encryptproxy_given = 0;
229 args_info->encryptremproxy_given = 0;
230 args_info->proctitle_given = 0;
231+ args_info->enforcetls1_given = 0;
232+ args_info->host_given = 0;
233+ args_info->cacert_given = 0;
234
235 /* No... we can't make this a function... -- Maniac */
236 #define clear_args() \
237@@ -156,8 +166,13 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
238 args_info->encrypt_flag = 0; \
239 args_info->encryptproxy_flag = 0; \
240 args_info->encryptremproxy_flag = 0; \
241+ args_info->no_ssl3_flag = 0; \
242 args_info->proctitle_arg = NULL; \
243-}
244+ args_info->enforcetls1_flag = 0; \
245+ args_info->host_arg = NULL; \
246+ args_info->no_check_cert_flag = 0; \
247+ args_info->cacert_arg = NULL; \
248+}
249
250 clear_args();
251
252@@ -189,6 +204,8 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
253 { "remproxy", 1, NULL, 'r' },
254 { "remproxyauth", 1, NULL, 'R' },
255 { "proctitle", 1, NULL, 'x' },
256+ { "host", 1, NULL, 'o' },
257+ { "tlsenforce", 1, NULL, 'L' },
258 { "header", 1, NULL, 'H' },
259 { "verbose", 0, NULL, 'v' },
260 { "ntlm", 0, NULL, 'N' },
261@@ -198,12 +215,15 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
262 { "encrypt", 0, NULL, 'e' },
263 { "encrypt-proxy", 0, NULL, 'E' },
264 { "encrypt-remproxy",0,NULL, 'X' },
265+ { "no-ssl3", 0, NULL, 'T' },
266+ { "no-check-certificate",0,NULL,'z' },
267+ { "cacert", 1, NULL, 'C' },
268 { NULL, 0, NULL, 0 }
269 };
270
271- c = getopt_long (argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXq", long_options, &option_index);
272+ c = getopt_long (argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo:TzC:", long_options, &option_index);
273 #else
274- c = getopt( argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXq" );
275+ c = getopt( argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo:TzC:" );
276 #endif
277
278 if (c == -1)
279@@ -262,6 +282,18 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
280 args_info->proctitle_arg = gengetopt_strdup (optarg);
281 break;
282
283+ case 'L':
284+ args_info->enforcetls1_given = 1;
285+ message("Enforcing TLSv1");
286+ args_info->enforcetls1_flag = 1;
287+ break;
288+
289+ case 'o':
290+ args_info->host_given = 1;
291+ message("Host-header override enabled\n");
292+ args_info->host_arg = gengetopt_strdup (optarg);
293+ break;
294+
295 case 'u': /* Username to send to HTTPS proxy for authentication. */
296 if (args_info->user_given) {
297 fprintf (stderr, "%s: `--user' (`-u'), `--proxyauth' (`-P') or `--passfile' (`-F') option given more than once\n", PACKAGE);
298@@ -370,6 +402,11 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
299 message("SSL local to remote proxy enabled\n");
300 break;
301
302+ case 'T': /* Turn off SSLv3 */
303+ args_info->no_ssl3_flag = !(args_info->no_ssl3_flag);
304+ if( args_info->verbose_flag )
305+ message("SSLv3 disabled\n");
306+ break;
307
308 case 'd': /* Destination host to built the tunnel to. */
309 if (args_info->dest_given) {
310@@ -403,6 +440,22 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
311 args_info->quiet_flag = !(args_info->quiet_flag);
312 break;
313
314+ case 'z': /* Don't verify server SSL certificate */
315+ args_info->no_check_cert_flag = 1;
316+ if( args_info->verbose_flag )
317+ message("Server SSL certificate verification disabled\n");
318+ break;
319+
320+ case 'C': /* Trusted CA certificate (or directory) for server SSL certificate verification */
321+ if (args_info->cacert_given) {
322+ fprintf (stderr, "%s: `--cacert' (`-C') option given more than once\n", PACKAGE);
323+ clear_args ();
324+ exit(1);
325+ }
326+ args_info->cacert_given = 1;
327+ args_info->cacert_arg = gengetopt_strdup (optarg);
328+ break;
329+
330 case 0: /* Long option with no short option */
331
332 case '?': /* Invalid option. */
333@@ -461,10 +514,11 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
334
335 if ( args_info->proxy_arg == NULL ) {
336 if ( ((tmp = getenv("http_proxy")) != NULL) || ((tmp = getenv("HTTP_PROXY")) != NULL) ) {
337- int r;
338+ //int r;
339 char * temp;
340 temp = malloc( 56+1 );
341- r = sscanf( tmp, "http://%56[^/]/", temp );
342+ sscanf( tmp, "http://%56[^/]/", temp );
343+ //r = sscanf( tmp, "http://%56[^/]/", temp );
344 // message( "r = '%d'\ntemp = '%s'\n", r, temp);
345
346 args_info->proxy_given = 1;
347@@ -474,7 +528,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
348 }
349 }
350
351- if (! args_info->proxy_given || ! args_info->dest_given ) {
352+ if (! args_info->proxy_given && ! args_info->dest_given ) {
353 clear_args ();
354 // cmdline_parser_print_help ();
355 message( "No proxy or destination given, exiting\nUse '--help' flag for usage info\n" );
356@@ -482,12 +536,23 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar
357 }
358
359 if (args_info->proxy_given ) {
360+ char proxy_arg_fmt[32];
361+ size_t proxy_arg_len;
362 char * phost;
363 int pport;
364
365- phost = malloc( 50+1 );
366-
367- r = sscanf( args_info->proxy_arg, "%50[^:]:%5u", phost, &pport );
368+ proxy_arg_len = strlen( args_info->proxy_arg );
369+ if ( (phost = malloc( proxy_arg_len + 1 )) == NULL ) {
370+ message( "Out of memory\n" );
371+ exit(1);
372+ }
373+ snprintf( proxy_arg_fmt, sizeof(proxy_arg_fmt), "%%%zu[^:]:%%5u", proxy_arg_len - 1 );
374+ r = sscanf( args_info->proxy_arg, proxy_arg_fmt, phost, &pport );
375+ if ( r != 2 ) {
376+ /* try bracket-enclosed IPv6 literal */
377+ snprintf( proxy_arg_fmt, sizeof(proxy_arg_fmt), "[%%%zu[^]]]:%%5u", proxy_arg_len - 1 );
378+ r = sscanf( args_info->proxy_arg, proxy_arg_fmt, phost, &pport );
379+ }
380 if ( r == 2 ) {
381 args_info->proxyhost_arg = phost;
382 args_info->proxyport_arg = pport;
383diff --git a/cmdline.h b/cmdline.h
384index 2eccab7..cd85191 100644
385--- a/cmdline.h
386+++ b/cmdline.h
387@@ -47,7 +47,12 @@ struct gengetopt_args_info {
388 int encrypt_flag; /* Turn on SSL encryption (default=off). */
389 int encryptproxy_flag; /* Turn on client to proxy SSL encryption (def=off).*/
390 int encryptremproxy_flag; /* Turn on local to remote proxy SSL encryption (def=off).*/
391+ int no_ssl3_flag; /* Turn off SSLv3 (default=on) */
392 char *proctitle_arg; /* Override process title (default=off). */
393+ int enforcetls1_flag; /* Override default and enforce TLSv1 */
394+ char *host_arg; /* Optional Host Header */
395+ int no_check_cert_flag; /* Turn off server SSL certificate verification (default=on) */
396+ char *cacert_arg; /* Trusted CA certificate (or directory) for server SSL certificate verification */
397 int help_given; /* Whether help was given. */
398 int version_given; /* Whether version was given. */
399 int user_given; /* Whether user was given. */
400@@ -71,6 +76,9 @@ struct gengetopt_args_info {
401 int encryptproxy_given; /* Whether encrypt was given */
402 int encryptremproxy_given; /* Whether encrypt was given */
403 int proctitle_given; /* Whether to override process title */
404+ int enforcetls1_given; /* Wheter to enforce TLSv1 */
405+ int host_given; /* Wheter we override the Host Header */
406+ int cacert_given; /* Whether cacert was given */
407 };
408
409 int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *args_info );
410diff --git a/config.h b/config.h
411index 4e73de1..204ded5 100644
412--- a/config.h
413+++ b/config.h
414@@ -17,7 +17,7 @@
415 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
416 */
417
418-#define VERSION "1.9.0"
419+#define VERSION "1.9.9"
420 #define PACKAGE "proxytunnel"
421 #define PURPOSE "Build generic tunnels through HTTPS proxies"
422 #define AUTHORS "Jos Visser (Muppet) <josv@osp.nl>, Mark Janssen (Maniac) <maniac@maniac.nl>"
423diff --git a/contrib/proxytunnel.spec b/contrib/proxytunnel.spec
424index 0c0493d..69cd62e 100644
425--- a/contrib/proxytunnel.spec
426+++ b/contrib/proxytunnel.spec
427@@ -47,7 +47,7 @@ proxy authentication.
428
429 %files
430 %defattr(-, root, root, 0755)
431-%doc CHANGES CREDITS INSTALL KNOWN_ISSUES LICENSE.txt README RELNOTES TODO docs/*.txt docs/*.html
432+%doc CHANGES CREDITS INSTALL KNOWN_ISSUES LICENSE.txt README RELNOTES TODO docs/*.adoc docs/*.html
433 %doc %{_mandir}/man1/proxytunnel.1*
434 %{_bindir}/proxytunnel
435
436diff --git a/docs/Makefile b/docs/Makefile
437index 09babbb..f313c38 100644
438--- a/docs/Makefile
439+++ b/docs/Makefile
440@@ -2,25 +2,26 @@ prefix = /usr/local
441 datadir = $(prefix)/share
442 mandir = $(datadir)/man
443
444-txttargets = $(shell echo *.txt)
445-htmltargets = $(patsubst %.txt, %.html, $(txttargets))
446+adoctargets = $(shell echo *.adoc)
447+htmltargets = $(patsubst %.adoc, %.html, $(adoctargets))
448
449 docs: proxytunnel.1 $(htmltargets)
450
451 install: proxytunnel.1
452- install -Dp -m0644 proxytunnel.1 $(DESTDIR)$(mandir)/man1/proxytunnel.1
453+ install -d $(DESTDIR)$(mandir)/man1
454+ install -p proxytunnel.1 $(DESTDIR)$(mandir)/man1
455
456 clean:
457 rm -f proxytunnel.1 *.html *.xml
458
459-%.1.html: %.1.txt
460+%.1.html: %.1.adoc
461 asciidoc -d manpage $<
462
463 %.1: %.1.xml
464 xmlto man $<
465
466-%.html: %.txt
467+%.html: %.adoc
468 asciidoc $<
469
470-%.1.xml: %.1.txt
471+%.1.xml: %.1.adoc
472 asciidoc -b docbook -d manpage $<
473diff --git a/docs/proxytunnel-paper.txt b/docs/proxytunnel-paper.adoc
474similarity index 100%
475rename from docs/proxytunnel-paper.txt
476rename to docs/proxytunnel-paper.adoc
477diff --git a/docs/proxytunnel.1.txt b/docs/proxytunnel.1.adoc
478similarity index 90%
479rename from docs/proxytunnel.1.txt
480rename to docs/proxytunnel.1.adoc
481index 03fa427..a884207 100644
482--- a/docs/proxytunnel.1.txt
483+++ b/docs/proxytunnel.1.adoc
484@@ -49,6 +49,20 @@ also be used for other proxy-traversing purposes like proxy bouncing.
485
486 == ADDITIONAL OPTIONS
487
488+*-T*, *--no-ssl3*::
489+ Prevent the use of SSLv3 in encrypted connections (default: enabled)
490+
491+*-z*, *--no-check-certificate*::
492+ Do not verify server SSL certificate when establishing an SSL connection.
493+ By default, the server SSL certficate is verified and the target host name
494+ is checked against the server certificate's subject alternative names if
495+ any are present, or common name if there are no subject alternative names.
496+
497+*-C*, *--cacert*=_filename/directory_::
498+ Specify a CA certificate file (or directory containing CA certificate(s))
499+ to trust when verifying a server SSL certificate. If a directory is provided,
500+ it must be prepared with OpenSSL's c_rehash tool. (default: /etc/ssl/certs)
501+
502 *-F*, *--passfile*=_filename_::
503 Use _filename_ for reading username and password for HTTPS proxy
504 authentication, the file uses the same format as .wgetrc and can be shared
505diff --git a/http.c b/http.c
506index 3b7f6b9..3b85418 100644
507--- a/http.c
508+++ b/http.c
509@@ -105,11 +105,11 @@ void proxy_protocol(PTSTREAM *pts) {
510 if (args_info.remproxy_given ) {
511 if( args_info.verbose_flag )
512 message( "\nTunneling to %s (remote proxy)\n", args_info.remproxy_arg );
513- sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.remproxy_arg, args_info.remproxy_arg );
514+ sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.remproxy_arg, args_info.host_arg ? args_info.host_arg : args_info.remproxy_arg );
515 } else {
516 if( args_info.verbose_flag )
517 message( "\nTunneling to %s (destination)\n", args_info.dest_arg );
518- sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.dest_arg );
519+ sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.host_arg ? args_info.host_arg : args_info.proxyhost_arg );
520 }
521
522 if ( args_info.user_given && args_info.pass_given ) {
523@@ -157,13 +157,13 @@ void proxy_protocol(PTSTREAM *pts) {
524 while ( strcmp( buf, "\r\n" ) != 0 )
525 readline(pts);
526
527-/* If --encrypt-remproxy is specified, connect to the remote proxy using SSL */
528- if ( args_info.encryptremproxy_flag )
529- stream_enable_ssl(stunnel);
530+ /* If --encrypt-remproxy is specified, connect to the remote proxy using SSL */
531+ if ( args_info.encryptremproxy_flag )
532+ stream_enable_ssl(stunnel, args_info.remproxy_arg);
533
534 if( args_info.verbose_flag )
535 message( "\nTunneling to %s (destination)\n", args_info.dest_arg );
536- sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.dest_arg);
537+ sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.host_arg ? args_info.host_arg : args_info.dest_arg);
538
539 if ( args_info.remuser_given && args_info.rempass_given )
540 strzcat( buf, "Proxy-Authorization: Basic %s\r\n", basicauth(args_info.remuser_arg, args_info.rempass_arg ));
541diff --git a/io.c b/io.c
542index acbcde7..e8df31a 100644
543--- a/io.c
544+++ b/io.c
545@@ -29,6 +29,8 @@
546 #include "proxytunnel.h"
547 #include "io.h"
548
549+#define ACTIVE 1
550+#define CLOSED 0
551
552 /*
553 * Read one line of data from the tunnel. Line is terminated by a
554@@ -41,7 +43,7 @@ int readline(PTSTREAM *pts) {
555
556 /* Read one character at a time into buf, until a newline is encountered. */
557 while ( c != 10 && ( i < SIZE - 1 ) ) {
558- if( stream_read( pts, &c ,1) < 0) {
559+ if( stream_read( pts, &c ,1) <= 0) {
560 my_perror( "Socket read error" );
561 exit( 1 );
562 }
563@@ -55,8 +57,8 @@ int readline(PTSTREAM *pts) {
564
565 if( args_info.verbose_flag ) {
566 /* Copy line of data into dstr without trailing newline */
567- char *dstr = malloc(sizeof(buf) + 1);
568- strlcpy( dstr, buf, strlen(buf) - 1);
569+ char *dstr = malloc(strlen(buf) + 1);
570+ strncpy( dstr, buf, strlen(buf));
571 if (strcmp(dstr, ""))
572 message( " <- %s\n", dstr );
573 }
574@@ -81,11 +83,17 @@ void cpio(PTSTREAM *stream1, PTSTREAM *stream2) {
575 /* We are never interested in sockets being available for write */
576 FD_ZERO( &writefds );
577
578+
579+ /* experimental timeout */
580+ struct timeval select_timeout;
581+ select_timeout.tv_sec = 30; /* should be fine */
582+ select_timeout.tv_usec = 0;
583+
584 if( args_info.verbose_flag )
585 message( "\nTunnel established.\n" );
586
587- /* Only diamonds are forever :-) */
588- while( 1==1 ) {
589+ int stream_status = ACTIVE;
590+ while( stream_status == ACTIVE ) {
591 /* Clear the interesting socket sets */
592 FD_ZERO( &readfds );
593 FD_ZERO( &exceptfds );
594@@ -99,32 +107,37 @@ void cpio(PTSTREAM *stream1, PTSTREAM *stream2) {
595 FD_SET( stream_get_outgoing_fd(stream1), &exceptfds );
596 FD_SET( stream_get_incoming_fd(stream2), &exceptfds );
597 FD_SET( stream_get_outgoing_fd(stream2), &exceptfds );
598-
599- /* Wait until something happens on the registered sockets/files */
600- if ( select( max_fd + 1, &readfds, &writefds, &exceptfds, 0 ) < 0 ) {
601+
602+ /* reset the timeout, since select() does modify this struct! */
603+ select_timeout.tv_sec = 30;
604+ select_timeout.tv_usec = 0;
605+
606+ /* Wait/timeout something happens on the registered sockets/files */
607+ int number_of_fds_ready;
608+ number_of_fds_ready = select( max_fd + 1, &readfds, &writefds, &exceptfds, &select_timeout );
609+ if ( number_of_fds_ready < 0 ) {
610 perror("select error");
611 exit(1);
612 }
613
614- /*
615- * Is stream1 ready for read? If so, copy a block of data
616- * from stream1 to stream2. Or else if stream2
617- * is ready for read, copy a block of data from the
618- * stream2 to stream1. Otherwise an exceptional condition
619- * is flagged and the program is terminated.
620- */
621- if ( FD_ISSET( stream_get_incoming_fd(stream1), &readfds ) ) {
622- if ( stream_copy(stream1, stream2 ) )
623- break;
624- } else if( FD_ISSET( stream_get_incoming_fd(stream2), &readfds ) ) {
625- if( stream_copy(stream2, stream1 ) )
626- break;
627- } else {
628- my_perror( "Exceptional condition" );
629- break;
630- }
631+ if (number_of_fds_ready > 0) {
632+ /* Is stream1 ready for read? If so, copy a block of data
633+ * from stream1 to stream2. Or else if stream2
634+ * is ready for read, copy a block of data from the
635+ * stream2 to stream1. Otherwise an exceptional condition
636+ * is flagged and the program is terminated.
637+ */
638+ if ( FD_ISSET( stream_get_incoming_fd(stream1), &readfds ) ) {
639+ if ( stream_copy(stream1, stream2 ) )
640+ stream_status = CLOSED;
641+ } else if( FD_ISSET( stream_get_incoming_fd(stream2), &readfds ) ) {
642+ if( stream_copy(stream2, stream1 ) )
643+ stream_status = CLOSED;
644+ } else {
645+ my_perror( "Exceptional condition" );
646+ stream_status = CLOSED;
647+ }
648+ }
649 }
650 closeall();
651 }
652-
653-// vim:noexpandtab:ts=4
654diff --git a/proxytunnel.c b/proxytunnel.c
655index 9844e3d..18aa414 100644
656--- a/proxytunnel.c
657+++ b/proxytunnel.c
658@@ -66,45 +66,44 @@ void signal_handler( int signal ) {
659 * the socket that is connected to the proxy
660 */
661 int tunnel_connect() {
662- struct sockaddr_in sa;
663- struct hostent *he;
664+ struct addrinfo hints = {
665+ .ai_family = AF_UNSPEC,
666+ .ai_socktype = SOCK_STREAM,
667+ .ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV,
668+ .ai_protocol = 0
669+ };
670+ struct addrinfo * result, * rp;
671+ int rc;
672+ char service[6];
673 int sd;
674
675- /* Create the socket */
676- if( ( sd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) {
677- my_perror("Can not create socket");
678+ rc = snprintf( service, sizeof(service), "%d", args_info.proxyport_arg );
679+ if( ( rc < 0 ) || ( rc >= sizeof(service) ) ) {
680+ /* this should never happen */
681+ message( "snprintf() failed" );
682 exit(1);
683 }
684-
685- /* Lookup the IP address of the proxy */
686- if( ! ( he = gethostbyname( args_info.proxyhost_arg ) ) ) {
687-// FIXME: my_perror("Local proxy %s could not be resolved", args_info.proxyhost_arg);
688- my_perror("Local proxy could not be resolved." );
689+ rc = getaddrinfo( args_info.proxyhost_arg, service, &hints, &result );
690+ if( rc != 0 ) {
691+ message( "getaddrinfo() failed to resolve local proxy: %s\n",
692+ gai_strerror( rc ) );
693 exit(1);
694 }
695-
696- char ip[16];
697- snprintf(ip, 16, "%d.%d.%d.%d", he->h_addr[0] & 255, he->h_addr[1] & 255, he->h_addr[2] & 255, he->h_addr[3] & 255);
698- if( args_info.verbose_flag && strcmp(args_info.proxyhost_arg, ip)) {
699- message( "Local proxy %s resolves to %d.%d.%d.%d\n",
700- args_info.proxyhost_arg,
701- he->h_addr[0] & 255,
702- he->h_addr[1] & 255,
703- he->h_addr[2] & 255,
704- he->h_addr[3] & 255 );
705+ for (rp = result; rp != NULL; rp = rp->ai_next) {
706+ sd = socket( rp->ai_family, rp->ai_socktype, rp->ai_protocol );
707+ if( sd < 0 ) {
708+ continue;
709+ }
710+ if( connect( sd, rp->ai_addr, rp->ai_addrlen ) == 0 ) {
711+ break;
712+ }
713+ close(sd);
714 }
715-
716- /* Set up the structure to connect to the proxy port of the proxy host */
717- memset( &sa, '\0', sizeof( sa ) );
718- sa.sin_family = AF_INET;
719- memcpy( &sa.sin_addr.s_addr, he->h_addr, 4);
720- sa.sin_port = htons( args_info.proxyport_arg );
721-
722- /* Connect the socket */
723- if( connect( sd, (struct sockaddr*) &sa, sizeof( sa ) ) < 0 ) {
724- my_perror("connect() failed");
725+ if( rp == NULL ) {
726+ my_perror( "failed to connect to local proxy" );
727 exit(1);
728 }
729+ freeaddrinfo(result);
730
731 /* Increase interactivity of tunnel, patch by Ingo Molnar */
732 int flag = 1;
733@@ -266,7 +265,7 @@ void do_daemon()
734 #ifdef USE_SSL
735 /* If --encrypt-proxy is specified, connect to the proxy using SSL */
736 if ( args_info.encryptproxy_flag )
737- stream_enable_ssl(stunnel);
738+ stream_enable_ssl(stunnel, args_info.proxy_arg);
739 #endif /* USE_SSL */
740
741 /* Open the tunnel */
742@@ -275,7 +274,7 @@ void do_daemon()
743 #ifdef USE_SSL
744 /* If --encrypt is specified, wrap all traffic after the proxy handoff in SSL */
745 if( args_info.encrypt_flag )
746- stream_enable_ssl(stunnel);
747+ stream_enable_ssl(stunnel, args_info.dest_arg);
748 #endif /* USE_SSL */
749
750 #ifdef SETPROCTITLE
751@@ -388,7 +387,7 @@ int main( int argc, char *argv[] ) {
752 /* If --encrypt-proxy is specified, connect to the proxy using SSL */
753 #ifdef USE_SSL
754 if ( args_info.encryptproxy_flag )
755- stream_enable_ssl(stunnel);
756+ stream_enable_ssl(stunnel, args_info.proxy_arg);
757 #endif /* USE_SSL */
758
759 /* Open the tunnel */
760@@ -397,7 +396,7 @@ int main( int argc, char *argv[] ) {
761 /* If --encrypt is specified, wrap all traffic after the proxy handoff in SSL */
762 #ifdef USE_SSL
763 if( args_info.encrypt_flag )
764- stream_enable_ssl(stunnel);
765+ stream_enable_ssl(stunnel, args_info.dest_arg);
766 #endif /* USE_SSL */
767
768 #ifdef SETPROCTITLE
769diff --git a/proxytunnel.h b/proxytunnel.h
770index b948be0..593cd7e 100644
771--- a/proxytunnel.h
772+++ b/proxytunnel.h
773@@ -26,14 +26,20 @@ void message( char *s, ... );
774 void my_perror( char *msg );
775 void signal_handler( int signal );
776 int tunnel_connect();
777-void analyze_HTTP();
778-void proxy_protocol();
779+void analyze_HTTP(PTSTREAM *pts);
780+void proxy_protocol(PTSTREAM *pts);
781 void closeall();
782 void do_daemon();
783 void initsetproctitle(int argc, char *argv[]);
784 void setproctitle(const char *fmt, ...);
785+
786+#if defined(__APPLE__) && defined(__MACH__)
787+/* Don't include strlcat and strlcpy since they are provided as macros on OSX */
788+#else
789 size_t strlcat(char *dst, const char *src, size_t siz);
790 size_t strlcpy(char *dst, const char *src, size_t siz);
791+#endif
792+
793 size_t strzcat(char *dst, char *format, ...);
794 int main( int argc, char *argv[] );
795 char * readpassphrase(const char *, char *, size_t, int);
796diff --git a/ptstream.c b/ptstream.c
797index 4c87c80..d1c5f44 100644
798--- a/ptstream.c
799+++ b/ptstream.c
800@@ -19,12 +19,15 @@
801
802 /* ptstream.c */
803
804+#include <arpa/inet.h>
805+#include <openssl/x509v3.h>
806 #include <stdio.h>
807 #include <stdlib.h>
808 #include <string.h>
809 #include <unistd.h>
810 #include <sys/types.h>
811 #include <sys/socket.h>
812+#include <sys/stat.h>
813
814 #include "proxytunnel.h"
815
816@@ -142,24 +145,199 @@ int stream_copy(PTSTREAM *pts_from, PTSTREAM *pts_to) {
817 }
818
819
820+/* Check the certificate host name against the expected host name */
821+/* Return 1 if peer hostname is valid, any other value indicates failure */
822+int check_cert_valid_host(const char *cert_host, const char *peer_host) {
823+ if (cert_host == NULL || peer_host == NULL) {
824+ return 0;
825+ }
826+ if (cert_host[0] == '*') {
827+ if (strncmp(cert_host, "*.", 2) != 0) {
828+ /* Invalid wildcard hostname */
829+ return 0;
830+ }
831+ /* Skip "*." */
832+ cert_host += 2;
833+ /* Wildcards can only match the first subdomain component */
834+ while (*peer_host++ != '.' && *peer_host != '\0')
835+ ;;
836+ }
837+ if (strlen(cert_host) == 0 || strlen(peer_host) == 0) {
838+ return 0;
839+ }
840+ return strcmp(cert_host, peer_host) == 0;
841+}
842+
843+
844+int check_cert_valid_ip6(const unsigned char *cert_ip_data, const int cert_ip_len, const struct in6_addr *addr6) {
845+ int i;
846+ for (i = 0; i < cert_ip_len; i++) {
847+ if (cert_ip_data[i] != addr6->s6_addr[i]) {
848+ return 0;
849+ }
850+ }
851+ return 1;
852+}
853+
854+
855+int check_cert_valid_ip(const unsigned char *cert_ip_data, const int cert_ip_len, const struct in_addr *addr) {
856+ int i;
857+ for (i = 0; i < cert_ip_len; i++) {
858+ if (cert_ip_data[i] != ((addr->s_addr >> (i * 8)) & 0xFF)) {
859+ return 0;
860+ }
861+ }
862+ return 1;
863+}
864+
865+
866+int check_cert_names(X509 *cert, char *peer_host) {
867+ char peer_cn[256];
868+ const GENERAL_NAME *gn;
869+ STACK_OF(GENERAL_NAME) *gen_names;
870+ struct in_addr addr;
871+ struct in6_addr addr6;
872+ int peer_host_is_ipv4 = 0, peer_host_is_ipv6 = 0;
873+ int i, san_count;
874+
875+ gen_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
876+ san_count = sk_GENERAL_NAME_num(gen_names);
877+ if (san_count > 0) {
878+ peer_host_is_ipv4 = (inet_pton(AF_INET, peer_host, &addr) == 1);
879+ peer_host_is_ipv6 = (peer_host_is_ipv4 ? 0 : inet_pton(AF_INET6, peer_host, &addr6) == 1);
880+ for (i = 0; i < san_count; i++) {
881+ gn = sk_GENERAL_NAME_value(gen_names, i);
882+ if (gn->type == GEN_DNS && !(peer_host_is_ipv4 || peer_host_is_ipv6)) {
883+ if (check_cert_valid_host((char*)ASN1_STRING_data(gn->d.ia5), peer_host)) {
884+ return 1;
885+ }
886+ } else if (gn->type == GEN_IPADD) {
887+ if (gn->d.ip->length == 4 && peer_host_is_ipv4) {
888+ if (check_cert_valid_ip(gn->d.ip->data, gn->d.ip->length, &addr)) {
889+ return 1;
890+ }
891+ } else if (gn->d.ip->length == 16 && peer_host_is_ipv6) {
892+ if (check_cert_valid_ip6(gn->d.ip->data, gn->d.ip->length, &addr6)) {
893+ return 1;
894+ }
895+ }
896+ }
897+ }
898+ message("Host name %s does not match certificate subject alternative names\n", peer_host);
899+ } else {
900+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, peer_cn, sizeof(peer_cn));
901+ message("Host name %s does not match certificate common name %s or any subject alternative names\n", peer_host, peer_cn);
902+ return check_cert_valid_host(peer_cn, peer_host);
903+ }
904+ return 0;
905+}
906+
907 /* Initiate an SSL handshake on this stream and encrypt all subsequent data */
908-int stream_enable_ssl(PTSTREAM *pts) {
909+int stream_enable_ssl(PTSTREAM *pts, const char *proxy_arg) {
910 #ifdef USE_SSL
911- SSL_METHOD *meth;
912+ const SSL_METHOD *meth;
913 SSL *ssl;
914 SSL_CTX *ctx;
915-
916+ long res = 1;
917+ long ssl_options = 0;
918+
919+ X509* cert = NULL;
920+ int status;
921+ struct stat st_buf;
922+ const char *ca_file = NULL;
923+ const char *ca_dir = "/etc/ssl/certs/"; /* Default cert directory if none given */
924+ long vresult;
925+ char *peer_host = NULL;
926+ char proxy_arg_fmt[32];
927+ size_t proxy_arg_len;
928+
929 /* Initialise the connection */
930 SSLeay_add_ssl_algorithms();
931- meth = SSLv3_client_method();
932+ if (args_info.enforcetls1_flag) {
933+ meth = TLSv1_client_method();
934+ } else {
935+ meth = SSLv23_client_method();
936+ }
937 SSL_load_error_strings();
938
939 ctx = SSL_CTX_new (meth);
940+ if (args_info.no_ssl3_flag) {
941+ ssl_options |= SSL_OP_NO_SSLv3;
942+ }
943+ SSL_CTX_set_options (ctx, ssl_options);
944+
945+ if ( !args_info.no_check_cert_flag ) {
946+ if ( args_info.cacert_given ) {
947+ if ((status = stat(args_info.cacert_arg, &st_buf)) != 0) {
948+ message("Error reading certificate path %s\n", args_info.cacert_arg);
949+ goto fail;
950+ }
951+ if (S_ISDIR(st_buf.st_mode)) {
952+ ca_dir = args_info.cacert_arg;
953+ } else {
954+ ca_dir = NULL;
955+ ca_file = args_info.cacert_arg;
956+ }
957+ }
958+ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_dir)) {
959+ message("Error loading certificate(s) from %s\n", args_info.cacert_arg);
960+ goto fail;
961+ }
962+ }
963+
964 ssl = SSL_new (ctx);
965+
966 SSL_set_rfd (ssl, stream_get_incoming_fd(pts));
967 SSL_set_wfd (ssl, stream_get_outgoing_fd(pts));
968+
969+ /* Determine the host name we are connecting to */
970+ proxy_arg_len = strlen(proxy_arg);
971+ if ((peer_host = malloc(proxy_arg_len + 1)) == NULL) {
972+ message("Out of memory\n");
973+ goto fail;
974+ }
975+ snprintf( proxy_arg_fmt, sizeof(proxy_arg_fmt), proxy_arg[0] == '[' ? "[%%%zu[^]]]" : "%%%zu[^:]", proxy_arg_len - 1 );
976+ if ( sscanf( proxy_arg, proxy_arg_fmt, peer_host ) != 1 ) {
977+ goto fail;
978+ }
979+
980+ /* SNI support */
981+ if ( args_info.verbose_flag ) {
982+ message( "Set SNI hostname to %s\n", peer_host);
983+ }
984+ res = SSL_set_tlsext_host_name(ssl, peer_host);
985+ if (res < 0) {
986+ message( "TLS SNI error, giving up: SSL_set_tlsext_host_name returned error message:\n %u\n", res );
987+ exit( 1 );
988+ }
989+
990 SSL_connect (ssl);
991
992+ if ( !args_info.no_check_cert_flag ) {
993+ /* Make sure peer presented a certificate */
994+ cert = SSL_get_peer_certificate(ssl);
995+ if (cert == NULL) {
996+ message("No certificate presented\n");
997+ goto fail;
998+ }
999+
1000+ /* Check that the certificate is valid */
1001+ vresult = SSL_get_verify_result(ssl);
1002+ if (vresult != X509_V_OK) {
1003+ message("Certificate verification failed (%s)\n",
1004+ X509_verify_cert_error_string(vresult));
1005+ goto fail;
1006+ }
1007+
1008+ /* Verify the certificate name matches the host we are connecting to */
1009+ if (!check_cert_names(cert, peer_host)) {
1010+ goto fail;
1011+ }
1012+
1013+ free(peer_host);
1014+ X509_free(cert);
1015+ }
1016+
1017 /* Store ssl and ctx parameters */
1018 pts->ssl = ssl;
1019 pts->ctx = ctx;
1020@@ -168,6 +346,17 @@ int stream_enable_ssl(PTSTREAM *pts) {
1021 #endif /* USE_SSL */
1022
1023 return 1;
1024+
1025+fail:
1026+#ifdef USE_SSL
1027+ if (cert != NULL) {
1028+ X509_free(cert);
1029+ }
1030+ if (peer_host != NULL) {
1031+ free(peer_host);
1032+ }
1033+#endif /* USE_SSL */
1034+ exit(1);
1035 }
1036
1037
1038diff --git a/ptstream.h b/ptstream.h
1039index e7efd43..ee36af2 100644
1040--- a/ptstream.h
1041+++ b/ptstream.h
1042@@ -44,7 +44,7 @@ int stream_close(PTSTREAM *pts);
1043 int stream_read(PTSTREAM *pts, void *buf, size_t len);
1044 int stream_write(PTSTREAM *pts, void *buf, size_t len);
1045 int stream_copy(PTSTREAM *pts_from, PTSTREAM *pts_to);
1046-int stream_enable_ssl(PTSTREAM *pts);
1047+int stream_enable_ssl(PTSTREAM *pts, const char *proxy_arg);
1048 int stream_get_incoming_fd(PTSTREAM *pts);
1049 int stream_get_outgoing_fd(PTSTREAM *pts);
1050
1051diff --git a/readpassphrase.c b/readpassphrase.c
1052index 1870700..b107624 100644
1053--- a/readpassphrase.c
1054+++ b/readpassphrase.c
1055@@ -135,8 +135,13 @@ restart:
1056 oterm.c_lflag |= ECHO;
1057 }
1058
1059- if (!(flags & RPP_STDIN))
1060- (void)write(output, prompt, strlen(prompt));
1061+ if (!(flags & RPP_STDIN)) {
1062+ ssize_t bytes_written = write(output, prompt, strlen(prompt));
1063+ if (bytes_written != strlen(prompt)) {
1064+ message("Error on writing bytes to prompt\n");
1065+ }
1066+ }
1067+
1068 end = buf + bufsiz - 1;
1069 for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
1070 if (p < end) {
1071@@ -153,8 +158,12 @@ restart:
1072 }
1073 *p = '\0';
1074 save_errno = errno;
1075- if (!(term.c_lflag & ECHO))
1076- (void)write(output, "\n", 1);
1077+ if (!(term.c_lflag & ECHO)) {
1078+ ssize_t bytes_written = write(output, "\n", 1);
1079+ if (bytes_written != 1) {
1080+ message("Error writing one byte to prompt\n");
1081+ }
1082+ }
1083
1084 /* Restore old terminal settings and signals. */
1085 if (memcmp(&term, &oterm, sizeof(term)) != 0) {
This page took 0.181763 seconds and 4 git commands to generate.