janimo / textsecure

TextSecure client package for Go
GNU General Public License v3.0
129 stars 26 forks source link

Allow textsecure to be easily used with an HTTP proxy #11

Closed ioerror closed 9 years ago

ioerror commented 9 years ago

This patch adds support for HTTP proxies to client.Transport and it may be used like this:

http_proxy=127.0.0.1:8118 ./textsecure
ioerror commented 9 years ago

( This allows a user to register with TextSecure through an HTTP/HTTPS proxy (eg: privoxy + Tor) but it does not allow for further usage that requires websockets. )

janimo commented 9 years ago

Thanks for the patch. The rest of proxy support can be added later.

janimo commented 9 years ago

The latest commit adds proxy support for the websocket stream. I've tested using a http-only localhost privoxy install and it seems to work but real-world usage reports would be appreciated.

ioerror commented 9 years ago

I tested the current git tip ( 6bc446d7b33e9f5714f06bda8551263c14ead098 ) and found the following:

go build && http_proxy=127.0.0.1:8118 ./textsecure 
PUT /v1/directory/tokens/ 401
Could not get contacts: Status code 401

Could not establish websocket connection: unexpected EOF

My firewall (which blocks everything except connections to my local http and socks proxy: I'm using Tails + privoxy) says nothing. As we can see it fails completely otherwise:

 ./textsecure 
PUT /v1/directory/tokens/ 0
Could not get contacts: Put https://textsecure-service.whispersystems.org:443/v1/directory/tokens/: dial tcp 52.1.136.37:443: connection refused
Could not establish websocket connection: websocket.Dial wss://textsecure-service.whispersystems.org:443/v1/websocket/?login=%2B1771111001&password=XXXXXXXREDACTED: dial tcp 52.1.136.37:443: connection refused

So - something seems to not be working properly - I'm not sure what is happening though. Probably time to bust out tcpdump.

janimo commented 9 years ago

I'll do some tests with the official whisper server, I only did local tests recently.

janimo commented 9 years ago

it's related to https, but I am not sure yet what, I thought passing https_proxy fixed it but it does not, it just skips the proxy.

ioerror commented 9 years ago

I haven't looked in detail but I think the trick you used for the CONNECT proxy doesn't do a proper wss:// setup.

ioerror commented 9 years ago

OK - I've looked at the output on the wire and indeed it is the case that the websocket is just treating the socket as if it's http. That's bad news as it sends data without TLS - it assumes the socket is already setup with TLS (!) and so sends bare HTTP requests:

11:09:15.632263 IP (tos 0x0, ttl 64, id 49741, offset 0, flags [DF], proto TCP (6), length 358)
    localhost.60092 > localhost.8118: Flags [P.], cksum 0xff5a (incorrect -> 0x3fb7), seq 145:463, ack 69, win 342, length 318
E..f.M@.@.yB.............T..M...P..V.Z..GET /v1/websocket/?login=%2B177XXX1&password=XXXXREDACTED HTTP/1.1
Host: textsecure-service.whispersystems.org:443
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: fVztNoE9uZhxQ4MYWBj4jw==
Origin: https://textsecure-service.whispersystems.org:443/v1/websocket/
Sec-WebSocket-Version: 13

In a quick one minute look at this:

It should be doing a TLS setup after the CONNECT request - since it doesn't do so, it just treats it as a normal HTTP request. This data is then sent to port 443 of the text secure servers. Anyone snooping on them will see a bare HTTP request (see above) send to the TLS port. The TLS server isn't happy and barfs. But the data is still sent over the HTTP proxy, over Tor, out of an exit node and to the text secure server. Whoops.

We need a way to tell the WebSocket code to do TLS after that CONNECT proxy setup - the current rwc object assumes you've done it all. That's bad news and means that the proxy support is totally broken.

ioerror commented 9 years ago

It would probably make more sense to implement a proper Dial object with SOCKS5 support over the hacky HTTP CONNECT trick. Either that or we'd need a core websockets function to setup TLS on a rwc object. I guess either trick should work. In any case - registration works with the first patch but the second changeset is broken.

janimo commented 9 years ago

I've made some progress on the wss front, but the app now crashes in an unrelated place when sending messages. I've seen this with plain http/ws before.

janimo commented 9 years ago

Thanks for your testing and suggestions btw. It's my first time dealing with http tunneling and I am not that familiar with websockets either besides what's in this codebase.

ioerror commented 9 years ago

Can you link to the changes as you go?

janimo commented 9 years ago

It was a single commit since my previous comment, the latest in the repo.

ioerror commented 9 years ago

OK - I've since rebuilt from git tip and it is failing in a new way:

http_proxy=127.0.0.1:8118 ./textsecure 
PUT /v1/directory/tokens/ 401
Could not get contacts: Status code 401

It hangs for quite some time and then it says:

Could not establish websocket connection: tls: oversized record received with length 20527

Each subsequent run says the same thing:

Could not establish websocket connection: tls: oversized record received with length 20527

TextSecure then exits with 0.

ioerror commented 9 years ago

Good news is that it worked to do the following:

http_proxy=127.0.0.1:8118 ./textsecure -message="hello world" -to="Sally"

I can't seem to receive any messages though - it just hangs out and replying to that "hello world" - the replies don't ever show up.

janimo commented 9 years ago

Sending messages is done via the http(s) API, websockets are only used for receiving, and for seding keepalive pings. So ws is broken if receiving does not work, and I see something similar in my local tests.

ioerror commented 9 years ago

So - just to recap - I registered freshly (sms verification with another phone) and it worked. Basic sending of messages seems to function. Receiving doesn't seem to function.

The receiving seems to properly create a connection to textsecure-service.whispersystems.org - it hangs out in an open (as an attached Tor stream) state for a while.

janimo commented 9 years ago

So ws is still broken when proxied. Sending messages should work even if we don't attempt to set up the websocket connection. I'll be looking into it some more.

janimo commented 9 years ago

The tunneling code was broken, I had tried upgrading the wrong connection to TLS. With the latest commit, I have wss working using local privoxy and local https whisper server. SHA: cd139bd8729f6b8e52c18337c228223e00a3f20f

janimo commented 9 years ago

the proxy url can now be set in the configuration file with something like proxy: http://192.168.1.10:8118 the environment variable is used as a fallback.