adrienverge / openfortivpn

Client for PPP+TLS VPN tunnel services
GNU General Public License v3.0
2.7k stars 320 forks source link

[Feature request] support proxy #150

Closed ymartineau closed 7 years ago

ymartineau commented 7 years ago

hi,

do you already support corporate proxy (standard, no SOCKS, without authentication) or do you plan to add that kind of feature?

thank you

mrbaseman commented 7 years ago

currently, there is no built-in proxy support. The simple approach without authentication should not be too hard to implement. Something like described here needs to be implemented in the tcp_connect function in tunnel.c (just linking this here as a reminder for myself or anyone else who likes to create a pull request)

mrbaseman commented 7 years ago

could you test this implementation please? When connecting to the vpn server it first looks at the environment variable PROXY which should contain proxy_host:proxy_port. If this variable is set, openfortivpn tries to connect to this proxy and tell it to forward the traffic to the vpn_host and vpn_port specified on the command line or in the config file of openfortivpn. Documentation is still to be done.

mrbaseman commented 7 years ago

@ymartineau did you have a chance to test the proposed implementation for proxy support?

ymartineau commented 7 years ago

hi, I didn't had the time yet. I work from home today and vpn over vpn is not supported in our network, I'll try next week. Thank you

ymartineau commented 7 years ago

I would say it doesn't work:

I exported the PROXY environment variable. I checked it before with http_proxy, https_proxy and a wget.

Then, I ran openfortivpn and had a connection timeout.

[root@localhost bin]# ./openfortivpn -v --insecure-ssl DEBUG: Loaded config file "/home/centos/programs/openfortivpn-local/etc/openfortivpn/config". DEBUG: Config host = "1.2.3.4" DEBUG: Config realm = "" DEBUG: Config port = "5678" DEBUG: Config username = "johndoe" DEBUG: Config password = "****" ERROR: connect: Connection timed out INFO: Closed connection to gateway. ERROR: connect: Network is unreachable INFO: Could not log out. [root@localhost bin]#

I ran a tcpdump and saw that connection was still done directly to the vpn, not through the proxy. I did not check your code.

mrbaseman commented 7 years ago

thanks for testing. Obviously I have to correct my code. I thought the socket to the proxy was already open and the connect to the gateway is forwarded through the proxy, but it seems not to be the case. I didn't notice this because I'm not forced to use a proxy ;-) I'll let you know when I believe that I have a new version to test.

mrbaseman commented 7 years ago

@ymartineau could you test my proxy_support branch once more? The connection should be made to the proxy, now, which should then establish the connection to the vpn host and forward the traffic on the level of a tcp socket.

Note that following the proposal by @DimitriPapadopoulos I have changed the environment variable to a behavior which is some kind of standard. the variable https_proxy is supposed to contain http://ip:port where ip is the ip of the proxy and port is the port on which the proxy is listening. If this variable is not set, HTTPS_PROXY, all_proxy, and ALL_PROXY are checked.

The proxy is supposed to support the http connect command. If your proxy doesn't support it, a different approach with get and put might work, but I have found quite a number of different descriptions how things would work, and all of them leave out important parts of the http communication. A tcpdump of the communication in a successful connection through the proxy (e.g. using a browser) would be helpful.

ymartineau commented 7 years ago

Program received signal SIGSEGV, Segmentation fault. 0x00007ffff70d7514 in strchr_sse42 () from /lib64/libc.so.6 Missing separate debuginfos, use: debuginfo-install glibc-2.17-157.el7_3.4.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.14.1-27.el7_3.x86_64 libcom_err-1.42.9-9.el7.x86_64 libselinux-2.5-6.el7.x86_64 openssl-libs-1.0.1e-60.el7_3.1.x86_64 pcre-8.32-15.el7_2.1.x86_64 zlib-1.2.7-17.el7.x86_64 (gdb) bt #0 0x00007ffff70d7514 in strchr_sse42 () from /lib64/libc.so.6 #1 0x000000000040a50e in tcp_connect (tunnel=0x7fffffffc660) at src/tunnel.c:264 #2 ssl_connect (tunnel=0x7fffffffc660) at src/tunnel.c:423 #3 0x000000000040b156 in run_tunnel (config=config@entry=0x7fffffffcc90) at src/tunnel.c:566 #4 0x0000000000403e27 in main (argc=, argv=) at src/main.c:381 (gdb)

could you perform at least one test on e.g. squid? thanks.

mrbaseman commented 7 years ago

@ymartineau sorry. I had tried it with a few public proxies and had to realize that they don't allow connections to non-standard ports. Thanks for the hint with a local squid installation. With my latest commits it works in my environment with a squid that I have installed on localhost now

mrbaseman commented 7 years ago

I have squashed all the commits now and created the pull request. I have split the description of the other environment variables in the man page into a separate commit.

ymartineau commented 7 years ago

[root@localhost bin]# ./openfortivpn -v --insecure-ssl DEBUG: Loaded config file "/home/centos/programs/openfortivpn-local/etc/openfortivpn/config". DEBUG: Config host = "1.2.3.4" DEBUG: Config realm = "" DEBUG: Config port = "4567" DEBUG: Config username = "johndoe" DEBUG: Config password = "****" DEBUG: proxy_host: proxy.example.com DEBUG: proxy_port: 8000 DEBUG: server_addr: 255.255.255.255 DEBUG: server_port: 8000 DEBUG: gateway_addr: 1.2.3.4 DEBUG: gateway_port: 4567 ERROR: connect: Network is unreachable ...

mrbaseman commented 7 years ago

It seems you have specified the proxy with its hostname. It should be the IP address, like this: export https_proxy=http://127.0.0.1:3128 That IP should appear also as server_addr in the debug output, and the gateway_addr should be the ip of your vpn gateway to which the proxy shall connect.

ymartineau commented 7 years ago

sorry,

[root@localhost bin]# ./openfortivpn -v --insecure-ssl DEBUG: Loaded config file "/home/centos/programs/openfortivpn-local/etc/openfortivpn/config". DEBUG: Config host = "1.2.3.4" DEBUG: Config realm = "" DEBUG: Config port = "4567" DEBUG: Config username = "johndoe" DEBUG: Config password = "****" DEBUG: proxy_host: 2.3.4.5 DEBUG: proxy_port: 8000 DEBUG: server_addr: 2.3.4.5 DEBUG: server_port: 8000 DEBUG: gateway_addr: 1.2.3.4 DEBUG: gateway_port: 4567 ERROR: SSL_connect: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol You might want to try --insecure-ssl or specify a different --cipher-list ...

mrbaseman commented 7 years ago

ok, now we are at the point where the proxy switches to the forwarded connection. That's a bit tricky here, because the server sends a response from which we don't a prori know how it looks like. It must be a http success code (hopefully 200) and some text along with it (I have seen a simple string "OK" but also more verbose srings like "OK connecting now"), followed by a blank line, and it should use cr+lf line endings. We may not read a single byte too much, otherwise the ssl handshake gets confused, and we can not easily push back characters into the stream (socket streams are not like regular files). So we have to put in some intelligence that reads the exact number of bytes before going into the ssl handshake. Can you check with tcpdump how the response of the proxy looks like? Maybe it uses unix newlines only, or it sends some more lines before switching to the forwarded connection.

mrbaseman commented 7 years ago

I have just added another commit which might help here. It seems the line endings are not always CR+LF, but also LF+CR sometimes. Unless authentication at the proxy is required or for other reasons there are more lines, it should at least recognize the line end and the first empty line now, even if the proxy sends non-standard line endings.

ymartineau commented 7 years ago

seems better but I cannot ssh my remote host yet. I'll retry tommorrow. thank you

On Mon, Oct 16, 2017 at 2:59 PM, Martin Hecht notifications@github.com wrote:

I have just added another commit which might help here. It seems the line endings are not always CR+LF, but also LF+CR sometimes. Unless authentication at the proxy is required or for other reasons there are more lines, it should at least recognize the line end and the first empty line now, even if the proxy sends non-standard line endings.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adrienverge/openfortivpn/issues/150#issuecomment-336878913, or mute the thread https://github.com/notifications/unsubscribe-auth/ABX47_2nccXqo9GgfZWgEfXM95NnJ0bCks5ss1MlgaJpZM4ONtXJ .

ymartineau commented 7 years ago

sorry, actually, yesterday I forgot the http_proxy & https_proxy env variables I tried again today and got the same error as before. I made a network capture and found:

<CONNECT 1.2.3.4:4567 HTTP/1.1\r\n <Host: 1.2.3.4:4567\r\n <\r\n

>HTTP/1.1 200 Connection established\r\n >Date: Tue, 17 Oct 2017 07:35:59 GMT\r\n >Via: 1.1 host.company.com\r\n >\r\n

There, there is a ssl client hello followed by a tcp reset from remote. I made another capture with a wget https://... and compared the ssl client hello: For wget, I have tls "server_name" extension and it is not provided in the openforti connection attempt, but I don't think it matters. I made another comparison with windows forticlient: image (left is windows forticlient right is linux openforticlient)

there are three extensions on windows that are not in linux: status_request, extended_master_secret and renegociation_info. The supported_groups are the same but in different order. SessionTicketTLS and heartbeat are on linus but not on windows. ec_point_format uncompressed (used on windows) is included in ec_point_format supported on linux.

I'm not 100% the comparisons I performed are relevant.

mrbaseman commented 7 years ago

the main difference is TLS 1.2 in the left picture versus TLS 1.0 in the right one, but that's not so relevant here, because that happens later. The main point is that your proxy returns more header lines which the client must consume before opening the tls connection. I think we are slowly converging now. can you try out my latest commit? I can connect to my squid and establish an ssh connection over the proxified vpn connection

ymartineau commented 7 years ago

It works, thanks a lot!

Here is my memo:

1) run: nslookup proxy.company.com to get the ip address of your proxy

2) setup environment variables using proxy ip address: export http_proxy=http://1.2.3.4:8000 export https_proxy=$http_proxy take care, there should be no final / in url and there must be http:// prefix, http_proxy might not be needed but https_proxy is mandatory.

3) run (as root) first time with: ./openfortivpn -v --insecure-ssl ... DEBUG: Gateway certificate validation failed. ERROR: Gateway certificate validation failed, and the certificate digest in not in the local whitelist. If you trust it, rerun with: ERROR: --trusted-cert 1234567890abcdef... ERROR: or add this line to your config file: ERROR: trusted-cert = 1234567890abcdef... ...

4) add this "trusted-cert" option to your etc/openfortivpn/config and rerun with same command line (still as root): ./openfortivpn -v --insecure-ssl ... INFO: Adding VPN nameservers... INFO: Tunnel is up and running.

It would be nice to:

but at least it works, thank you very much, nice job!

marfcg commented 7 years ago

Dears, sorry to interrupt the flow. I'm writing just to check whether @mrbaseman 's branch is ready for use by "moderately-adventurous" users. I've seen that the pull request has not been accepted yet, hence my question.

I'm currently under a proxy myself, trying to connect to the vpn of my home institution using openfortiGUI 0.3.3. It works fine when I'm not behind a proxy, but now that I'm under one, things went down. You can't imagine how thankful I was when I found that you are working on a way to connect on this situation. BIG THANKS!

DimitriPapadopoulos commented 7 years ago

@marfcg I believe it's now worth testing if you are able to build from source. It's always good to have feedback from multiple users. Just follow suggestions from @ymartineau.

mrbaseman commented 7 years ago

I have just added the feature that trailing slashes in the proxy environment variables are ignored and host names are resolved when the proxy host is not specified by its IP address. From my point of view the changes become ready to merge. I would squash them again before everything goes into master branch. It would be good to have another confirmation that the latest commit indeed works.

marfcg commented 7 years ago

Yep, worked like a charm! I have installed the version from proxy_support branch and followed the steps described here.

ymartineau commented 7 years ago

Hi, I confirm that your latest changes work, I exported my https_proxy environment without any prefix and using fqdn and it worked. I also tested with prefix and with or without trailing slash and it works. Thank you!

mrbaseman commented 7 years ago

I have just merged my proxy_support branch into the official master branch