Friday, May 20, 2011

Moving On… to Node SPDY

‹prev | My Chain | next›

With zlib decompression of multiple SPDY packets working in both Python and Node.js, I am ready to punt on Ruby support. But first some specs enticing others to solve this for me.

I add the compressed and uncompressed values to the spec helper in the SPDY gem:
COMPRESSED_HEADER_1 = "8\xEA\xDF\xA2Q\xB2b\xE0b`\x83\xA4\x17\x06{\xB8\vu0,\xD6\xAE@\x17\xCD\xCD\xB1.\xB45\xD0\xB3\xD4\xD1\xD2\xD7\x02\xB3,\x18\xF8Ps,\x83\x9Cg\xB0?\xD4=:`\a\x81\xD5\x99\xEB@\xD4\e3\xF0\xA3\xE5i\x06A\x90\x8Bu\xA0N\xD6)NI\xCE\x80\xAB\x81%\x03\x06\xBE\xD4<\xDD\xD0`\x9D\xD4<\xA8\xA5,\xA0<\xCE\xC0\x0FJ\b9 \xA6\x150\xE3\x19\x180\xB0\xE5\x02\v\x97\xFC\x14\x06fw\xD7\x10\x06\xB6b`z\xCCMe`\xCD())(f`\x06y\x9CQ\x9F\x81\v\x91[\x19\xD2}\xF3\xAB2sr\x12\xF5M\xF5\f\x144\x00\x8A04\xB4V\xF0\xC9\xCC+\xADP\xA8\xB00\x8B73\xD1Tp\x04z>5<5\xC9;\xB3D\xDF\xD4\xD8D\xCF\x18\xA8\xCC\xDB#\xC4\xD7GG!'3;U\xC1=59;_S\xC19\x03X\xEC\xA4\xEA\e\x1A\xE9\x01}jb\x04R\x16\x9C\x98\x96X\x94\t\xD5\xC4\xC0\x0E\r|\x06\x0EX\x9C\x00\x00\x00\x00\xFF\xFF"

COMPRESSED_HEADER_2 = "B\x8A\x02f``\x0E\xAD`\xE4\xD1OK,\xCB\x04f3= 1XB\x14\x00\x00\x00\xFF\xFF"

UNCOMPRESSED_HEADER_1 = "\x00\n\x00\x06accept\x00?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\x00\x0eaccept-charset\x00\x1eISO-8859-1,utf-8;q=0.7,*;q=0.3\x00\x0faccept-encoding\x00\x11gzip,deflate,sdch\x00\x0faccept-language\x00\x0een-US,en;q=0.8\x00\x04host\x00\x0flocalhost:10000\x00\x06method\x00\x03GET\x00\x06scheme\x00\x05https\x00\x03url\x00\x01/\x00\nuser-agent\x00gMozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.30 Safari/534.30\x00\x07version\x00\x08HTTP/1.1"

UNCOMPRESSED_HEADER_2 = "\x00\n\x00\x06accept\x00\x03*/*\x00\x0eaccept-charset\x00\x1eISO-8859-1,utf-8;q=0.7,*;q=0.3\x00\x0faccept-encoding\x00\x11gzip,deflate,sdch\x00\x0faccept-language\x00\x0een-US,en;q=0.8\x00\x04host\x00\x0flocalhost:10000\x00\x06method\x00\x03GET\x00\x06scheme\x00\x05https\x00\x03url\x00\x0c/favicon.ico\x00\nuser-agent\x00gMozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.30 Safari/534.30\x00\x07version\x00\x08HTTP/1.1"
I can then write a simple spec detailing my woes:
  it "can deflate multiple packets" do
# see also https://gist.github.com/982287
SPDY::Zlib.inflate(COMPRESSED_HEADER_1)

SPDY::Zlib.inflate(COMPRESSED_HEADER_2).
should == UNCOMPRESSED_HEADER_2
end
Running that spec results in my nemesis, the "invalid stream" exception:
➜  spdy git:(master) ✗ rspec ./spec/compressor_spec.rb
..F

Failures:

1) SPDY::Zlib can deflate multiple packets
Failure/Error: SPDY::Zlib.inflate(COMPRESSED_HEADER_2).
RuntimeError:
invalid stream
# ./lib/spdy/compressor.rb:35:in `inflate'
# ./spec/compressor_spec.rb:18:in `block (2 levels) in <top (required)>'

Finished in 0.00194 seconds
3 examples, 1 failure
I mark that pending, commit to SPDY gem and open an issue. Someone please help!

I will continue to investigate this in my spare time, but, for now I turn back to node-spdy. Digging through edge-node.js some, I find the following SSL cipher suite being employed:
    creds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
Hrm... that does not seem to imclude my beloved DES-CBC3-SHA. Any chance Wireshark is able to decrypt (if supplied with the server keys) those cipher suites?

Ain't but one way to find out. I fire up the node-spdy example server:
➜  node-spdy git:(master) ✗ node test/spdy-server.js
TLS NPN Server is running on port : 8081
Then I need to start Wireshark, adding the example server's private key to the list of keys known to Wireshark:
127.0.0.1,10443,http,/home/cstrom/key.pem;127.0.0.1,10000,http,/home/cstrom/key.pem;127.0.0.1,8081,http,/home/cstrom/repos/node-spdy/keys/spdy-key.pem
With that I can start capture for packets on the loopback interface for port 8081. After making a request in Chrome, I see in Wireshark:



That is a whole lotta green. As is usual, green is good. In this case, the green packets indicate packets that have been decrypted. Nice!

But why so much green? Well, it turns out you need to send lots of data when rendering an awesome page:



For good measure, I inspect the first packet sent:



The destination port is 8081, so this is from the client to the server. The packet itself starts with 80 02 00 01 octets. The first octet (80) is just the control bit at the beginning of the control frame. The next (02) indicates the SPDY version being used here: 2. Lastly the remaining octets indicate the type of control frame being used: a SYN_STREAM which starts the SPDY session.

(More info can be found in the control frames section of the SPDY draft specification)

It is nice to have so much data at my disposal. I will pick back up tomorrow running through the various packets watching the nitty gritty SPDY packets in detail. Should be fun :)

Day #27

No comments:

Post a Comment