--- -- A library implementing SPDY3 protocol. For more information, check -- the protocol specification, at -- http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1 -- -- @author "Claudiu Perta " local bin = require "bin" local bit = require "bit" local os = require "os" local stdnse = require "stdnse" local table = require "table" local zlib = stdnse.silent_require "zlib" _ENV = stdnse.module("spdy", stdnse.seeall) -- zlib compression/decompression required by SPDY local Z_DEFAULT_COMPRESSION_LEVEL = 9 local Z_DEFAULT_WINDOW_BITS = 15 -- Dictionary used by SPDY3 for headers compression/decompression SPDY3_DICTIONARY = table.concat({ "\x00", "\x00", "\x00", "\x07", "\x6f", "\x70", "\x74", "\x69", -- - - - - o p t i "\x6f", "\x6e", "\x73", "\x00", "\x00", "\x00", "\x04", "\x68", -- o n s - - - - h "\x65", "\x61", "\x64", "\x00", "\x00", "\x00", "\x04", "\x70", -- e a d - - - - p "\x6f", "\x73", "\x74", "\x00", "\x00", "\x00", "\x03", "\x70", -- o s t - - - - p "\x75", "\x74", "\x00", "\x00", "\x00", "\x06", "\x64", "\x65", -- u t - - - - d e "\x6c", "\x65", "\x74", "\x65", "\x00", "\x00", "\x00", "\x05", -- l e t e - - - - "\x74", "\x72", "\x61", "\x63", "\x65", "\x00", "\x00", "\x00", -- t r a c e - - - "\x06", "\x61", "\x63", "\x63", "\x65", "\x70", "\x74", "\x00", -- - a c c e p t - "\x00", "\x00", "\x0e", "\x61", "\x63", "\x63", "\x65", "\x70", -- - - - a c c e p "\x74", "\x2d", "\x63", "\x68", "\x61", "\x72", "\x73", "\x65", -- t - c h a r s e "\x74", "\x00", "\x00", "\x00", "\x0f", "\x61", "\x63", "\x63", -- t - - - - a c c "\x65", "\x70", "\x74", "\x2d", "\x65", "\x6e", "\x63", "\x6f", -- e p t - e n c o "\x64", "\x69", "\x6e", "\x67", "\x00", "\x00", "\x00", "\x0f", -- d i n g - - - - "\x61", "\x63", "\x63", "\x65", "\x70", "\x74", "\x2d", "\x6c", -- a c c e p t - l "\x61", "\x6e", "\x67", "\x75", "\x61", "\x67", "\x65", "\x00", -- a n g u a g e - "\x00", "\x00", "\x0d", "\x61", "\x63", "\x63", "\x65", "\x70", -- - - - a c c e p "\x74", "\x2d", "\x72", "\x61", "\x6e", "\x67", "\x65", "\x73", -- t - r a n g e s "\x00", "\x00", "\x00", "\x03", "\x61", "\x67", "\x65", "\x00", -- - - - - a g e - "\x00", "\x00", "\x05", "\x61", "\x6c", "\x6c", "\x6f", "\x77", -- - - - a l l o w "\x00", "\x00", "\x00", "\x0d", "\x61", "\x75", "\x74", "\x68", -- - - - - a u t h "\x6f", "\x72", "\x69", "\x7a", "\x61", "\x74", "\x69", "\x6f", -- o r i z a t i o "\x6e", "\x00", "\x00", "\x00", "\x0d", "\x63", "\x61", "\x63", -- n - - - - c a c "\x68", "\x65", "\x2d", "\x63", "\x6f", "\x6e", "\x74", "\x72", -- h e - c o n t r "\x6f", "\x6c", "\x00", "\x00", "\x00", "\x0a", "\x63", "\x6f", -- o l - - - - c o "\x6e", "\x6e", "\x65", "\x63", "\x74", "\x69", "\x6f", "\x6e", -- n n e c t i o n "\x00", "\x00", "\x00", "\x0c", "\x63", "\x6f", "\x6e", "\x74", -- - - - - c o n t "\x65", "\x6e", "\x74", "\x2d", "\x62", "\x61", "\x73", "\x65", -- e n t - b a s e "\x00", "\x00", "\x00", "\x10", "\x63", "\x6f", "\x6e", "\x74", -- - - - - c o n t "\x65", "\x6e", "\x74", "\x2d", "\x65", "\x6e", "\x63", "\x6f", -- e n t - e n c o "\x64", "\x69", "\x6e", "\x67", "\x00", "\x00", "\x00", "\x10", -- d i n g - - - - "\x63", "\x6f", "\x6e", "\x74", "\x65", "\x6e", "\x74", "\x2d", -- c o n t e n t - "\x6c", "\x61", "\x6e", "\x67", "\x75", "\x61", "\x67", "\x65", -- l a n g u a g e "\x00", "\x00", "\x00", "\x0e", "\x63", "\x6f", "\x6e", "\x74", -- - - - - c o n t "\x65", "\x6e", "\x74", "\x2d", "\x6c", "\x65", "\x6e", "\x67", -- e n t - l e n g "\x74", "\x68", "\x00", "\x00", "\x00", "\x10", "\x63", "\x6f", -- t h - - - - c o "\x6e", "\x74", "\x65", "\x6e", "\x74", "\x2d", "\x6c", "\x6f", -- n t e n t - l o "\x63", "\x61", "\x74", "\x69", "\x6f", "\x6e", "\x00", "\x00", -- c a t i o n - - "\x00", "\x0b", "\x63", "\x6f", "\x6e", "\x74", "\x65", "\x6e", -- - - c o n t e n "\x74", "\x2d", "\x6d", "\x64", "\x35", "\x00", "\x00", "\x00", -- t - m d 5 - - - "\x0d", "\x63", "\x6f", "\x6e", "\x74", "\x65", "\x6e", "\x74", -- - c o n t e n t "\x2d", "\x72", "\x61", "\x6e", "\x67", "\x65", "\x00", "\x00", -- - r a n g e - - "\x00", "\x0c", "\x63", "\x6f", "\x6e", "\x74", "\x65", "\x6e", -- - - c o n t e n "\x74", "\x2d", "\x74", "\x79", "\x70", "\x65", "\x00", "\x00", -- t - t y p e - - "\x00", "\x04", "\x64", "\x61", "\x74", "\x65", "\x00", "\x00", -- - - d a t e - - "\x00", "\x04", "\x65", "\x74", "\x61", "\x67", "\x00", "\x00", -- - - e t a g - - "\x00", "\x06", "\x65", "\x78", "\x70", "\x65", "\x63", "\x74", -- - - e x p e c t "\x00", "\x00", "\x00", "\x07", "\x65", "\x78", "\x70", "\x69", -- - - - - e x p i "\x72", "\x65", "\x73", "\x00", "\x00", "\x00", "\x04", "\x66", -- r e s - - - - f "\x72", "\x6f", "\x6d", "\x00", "\x00", "\x00", "\x04", "\x68", -- r o m - - - - h "\x6f", "\x73", "\x74", "\x00", "\x00", "\x00", "\x08", "\x69", -- o s t - - - - i "\x66", "\x2d", "\x6d", "\x61", "\x74", "\x63", "\x68", "\x00", -- f - m a t c h - "\x00", "\x00", "\x11", "\x69", "\x66", "\x2d", "\x6d", "\x6f", -- - - - i f - m o "\x64", "\x69", "\x66", "\x69", "\x65", "\x64", "\x2d", "\x73", -- d i f i e d - s "\x69", "\x6e", "\x63", "\x65", "\x00", "\x00", "\x00", "\x0d", -- i n c e - - - - "\x69", "\x66", "\x2d", "\x6e", "\x6f", "\x6e", "\x65", "\x2d", -- i f - n o n e - "\x6d", "\x61", "\x74", "\x63", "\x68", "\x00", "\x00", "\x00", -- m a t c h - - - "\x08", "\x69", "\x66", "\x2d", "\x72", "\x61", "\x6e", "\x67", -- - i f - r a n g "\x65", "\x00", "\x00", "\x00", "\x13", "\x69", "\x66", "\x2d", -- e - - - - i f - "\x75", "\x6e", "\x6d", "\x6f", "\x64", "\x69", "\x66", "\x69", -- u n m o d i f i "\x65", "\x64", "\x2d", "\x73", "\x69", "\x6e", "\x63", "\x65", -- e d - s i n c e "\x00", "\x00", "\x00", "\x0d", "\x6c", "\x61", "\x73", "\x74", -- - - - - l a s t "\x2d", "\x6d", "\x6f", "\x64", "\x69", "\x66", "\x69", "\x65", -- - m o d i f i e "\x64", "\x00", "\x00", "\x00", "\x08", "\x6c", "\x6f", "\x63", -- d - - - - l o c "\x61", "\x74", "\x69", "\x6f", "\x6e", "\x00", "\x00", "\x00", -- a t i o n - - - "\x0c", "\x6d", "\x61", "\x78", "\x2d", "\x66", "\x6f", "\x72", -- - m a x - f o r "\x77", "\x61", "\x72", "\x64", "\x73", "\x00", "\x00", "\x00", -- w a r d s - - - "\x06", "\x70", "\x72", "\x61", "\x67", "\x6d", "\x61", "\x00", -- - p r a g m a - "\x00", "\x00", "\x12", "\x70", "\x72", "\x6f", "\x78", "\x79", -- - - - p r o x y "\x2d", "\x61", "\x75", "\x74", "\x68", "\x65", "\x6e", "\x74", -- - a u t h e n t "\x69", "\x63", "\x61", "\x74", "\x65", "\x00", "\x00", "\x00", -- i c a t e - - - "\x13", "\x70", "\x72", "\x6f", "\x78", "\x79", "\x2d", "\x61", -- - p r o x y - a "\x75", "\x74", "\x68", "\x6f", "\x72", "\x69", "\x7a", "\x61", -- u t h o r i z a "\x74", "\x69", "\x6f", "\x6e", "\x00", "\x00", "\x00", "\x05", -- t i o n - - - - "\x72", "\x61", "\x6e", "\x67", "\x65", "\x00", "\x00", "\x00", -- r a n g e - - - "\x07", "\x72", "\x65", "\x66", "\x65", "\x72", "\x65", "\x72", -- - r e f e r e r "\x00", "\x00", "\x00", "\x0b", "\x72", "\x65", "\x74", "\x72", -- - - - - r e t r "\x79", "\x2d", "\x61", "\x66", "\x74", "\x65", "\x72", "\x00", -- y - a f t e r - "\x00", "\x00", "\x06", "\x73", "\x65", "\x72", "\x76", "\x65", -- - - - s e r v e "\x72", "\x00", "\x00", "\x00", "\x02", "\x74", "\x65", "\x00", -- r - - - - t e - "\x00", "\x00", "\x07", "\x74", "\x72", "\x61", "\x69", "\x6c", -- - - - t r a i l "\x65", "\x72", "\x00", "\x00", "\x00", "\x11", "\x74", "\x72", -- e r - - - - t r "\x61", "\x6e", "\x73", "\x66", "\x65", "\x72", "\x2d", "\x65", -- a n s f e r - e "\x6e", "\x63", "\x6f", "\x64", "\x69", "\x6e", "\x67", "\x00", -- n c o d i n g - "\x00", "\x00", "\x07", "\x75", "\x70", "\x67", "\x72", "\x61", -- - - - u p g r a "\x64", "\x65", "\x00", "\x00", "\x00", "\x0a", "\x75", "\x73", -- d e - - - - u s "\x65", "\x72", "\x2d", "\x61", "\x67", "\x65", "\x6e", "\x74", -- e r - a g e n t "\x00", "\x00", "\x00", "\x04", "\x76", "\x61", "\x72", "\x79", -- - - - - v a r y "\x00", "\x00", "\x00", "\x03", "\x76", "\x69", "\x61", "\x00", -- - - - - v i a - "\x00", "\x00", "\x07", "\x77", "\x61", "\x72", "\x6e", "\x69", -- - - - w a r n i "\x6e", "\x67", "\x00", "\x00", "\x00", "\x10", "\x77", "\x77", -- n g - - - - w w "\x77", "\x2d", "\x61", "\x75", "\x74", "\x68", "\x65", "\x6e", -- w - a u t h e n "\x74", "\x69", "\x63", "\x61", "\x74", "\x65", "\x00", "\x00", -- t i c a t e - - "\x00", "\x06", "\x6d", "\x65", "\x74", "\x68", "\x6f", "\x64", -- - - m e t h o d "\x00", "\x00", "\x00", "\x03", "\x67", "\x65", "\x74", "\x00", -- - - - - g e t - "\x00", "\x00", "\x06", "\x73", "\x74", "\x61", "\x74", "\x75", -- - - - s t a t u "\x73", "\x00", "\x00", "\x00", "\x06", "\x32", "\x30", "\x30", -- s - - - - 2 0 0 "\x20", "\x4f", "\x4b", "\x00", "\x00", "\x00", "\x07", "\x76", -- - O K - - - - v "\x65", "\x72", "\x73", "\x69", "\x6f", "\x6e", "\x00", "\x00", -- e r s i o n - - "\x00", "\x08", "\x48", "\x54", "\x54", "\x50", "\x2f", "\x31", -- - - H T T P - 1 "\x2e", "\x31", "\x00", "\x00", "\x00", "\x03", "\x75", "\x72", -- - 1 - - - - u r "\x6c", "\x00", "\x00", "\x00", "\x06", "\x70", "\x75", "\x62", -- l - - - - p u b "\x6c", "\x69", "\x63", "\x00", "\x00", "\x00", "\x0a", "\x73", -- l i c - - - - s "\x65", "\x74", "\x2d", "\x63", "\x6f", "\x6f", "\x6b", "\x69", -- e t - c o o k i "\x65", "\x00", "\x00", "\x00", "\x0a", "\x6b", "\x65", "\x65", -- e - - - - k e e "\x70", "\x2d", "\x61", "\x6c", "\x69", "\x76", "\x65", "\x00", -- p - a l i v e - "\x00", "\x00", "\x06", "\x6f", "\x72", "\x69", "\x67", "\x69", -- - - - o r i g i "\x6e", "\x31", "\x30", "\x30", "\x31", "\x30", "\x31", "\x32", -- n 1 0 0 1 0 1 2 "\x30", "\x31", "\x32", "\x30", "\x32", "\x32", "\x30", "\x35", -- 0 1 2 0 2 2 0 5 "\x32", "\x30", "\x36", "\x33", "\x30", "\x30", "\x33", "\x30", -- 2 0 6 3 0 0 3 0 "\x32", "\x33", "\x30", "\x33", "\x33", "\x30", "\x34", "\x33", -- 2 3 0 3 3 0 4 3 "\x30", "\x35", "\x33", "\x30", "\x36", "\x33", "\x30", "\x37", -- 0 5 3 0 6 3 0 7 "\x34", "\x30", "\x32", "\x34", "\x30", "\x35", "\x34", "\x30", -- 4 0 2 4 0 5 4 0 "\x36", "\x34", "\x30", "\x37", "\x34", "\x30", "\x38", "\x34", -- 6 4 0 7 4 0 8 4 "\x30", "\x39", "\x34", "\x31", "\x30", "\x34", "\x31", "\x31", -- 0 9 4 1 0 4 1 1 "\x34", "\x31", "\x32", "\x34", "\x31", "\x33", "\x34", "\x31", -- 4 1 2 4 1 3 4 1 "\x34", "\x34", "\x31", "\x35", "\x34", "\x31", "\x36", "\x34", -- 4 4 1 5 4 1 6 4 "\x31", "\x37", "\x35", "\x30", "\x32", "\x35", "\x30", "\x34", -- 1 7 5 0 2 5 0 4 "\x35", "\x30", "\x35", "\x32", "\x30", "\x33", "\x20", "\x4e", -- 5 0 5 2 0 3 - N "\x6f", "\x6e", "\x2d", "\x41", "\x75", "\x74", "\x68", "\x6f", -- o n - A u t h o "\x72", "\x69", "\x74", "\x61", "\x74", "\x69", "\x76", "\x65", -- r i t a t i v e "\x20", "\x49", "\x6e", "\x66", "\x6f", "\x72", "\x6d", "\x61", -- - I n f o r m a "\x74", "\x69", "\x6f", "\x6e", "\x32", "\x30", "\x34", "\x20", -- t i o n 2 0 4 - "\x4e", "\x6f", "\x20", "\x43", "\x6f", "\x6e", "\x74", "\x65", -- N o - C o n t e "\x6e", "\x74", "\x33", "\x30", "\x31", "\x20", "\x4d", "\x6f", -- n t 3 0 1 - M o "\x76", "\x65", "\x64", "\x20", "\x50", "\x65", "\x72", "\x6d", -- v e d - P e r m "\x61", "\x6e", "\x65", "\x6e", "\x74", "\x6c", "\x79", "\x34", -- a n e n t l y 4 "\x30", "\x30", "\x20", "\x42", "\x61", "\x64", "\x20", "\x52", -- 0 0 - B a d - R "\x65", "\x71", "\x75", "\x65", "\x73", "\x74", "\x34", "\x30", -- e q u e s t 4 0 "\x31", "\x20", "\x55", "\x6e", "\x61", "\x75", "\x74", "\x68", -- 1 - U n a u t h "\x6f", "\x72", "\x69", "\x7a", "\x65", "\x64", "\x34", "\x30", -- o r i z e d 4 0 "\x33", "\x20", "\x46", "\x6f", "\x72", "\x62", "\x69", "\x64", -- 3 - F o r b i d "\x64", "\x65", "\x6e", "\x34", "\x30", "\x34", "\x20", "\x4e", -- d e n 4 0 4 - N "\x6f", "\x74", "\x20", "\x46", "\x6f", "\x75", "\x6e", "\x64", -- o t - F o u n d "\x35", "\x30", "\x30", "\x20", "\x49", "\x6e", "\x74", "\x65", -- 5 0 0 - I n t e "\x72", "\x6e", "\x61", "\x6c", "\x20", "\x53", "\x65", "\x72", -- r n a l - S e r "\x76", "\x65", "\x72", "\x20", "\x45", "\x72", "\x72", "\x6f", -- v e r - E r r o "\x72", "\x35", "\x30", "\x31", "\x20", "\x4e", "\x6f", "\x74", -- r 5 0 1 - N o t "\x20", "\x49", "\x6d", "\x70", "\x6c", "\x65", "\x6d", "\x65", -- - I m p l e m e "\x6e", "\x74", "\x65", "\x64", "\x35", "\x30", "\x33", "\x20", -- n t e d 5 0 3 - "\x53", "\x65", "\x72", "\x76", "\x69", "\x63", "\x65", "\x20", -- S e r v i c e - "\x55", "\x6e", "\x61", "\x76", "\x61", "\x69", "\x6c", "\x61", -- U n a v a i l a "\x62", "\x6c", "\x65", "\x4a", "\x61", "\x6e", "\x20", "\x46", -- b l e J a n - F "\x65", "\x62", "\x20", "\x4d", "\x61", "\x72", "\x20", "\x41", -- e b - M a r - A "\x70", "\x72", "\x20", "\x4d", "\x61", "\x79", "\x20", "\x4a", -- p r - M a y - J "\x75", "\x6e", "\x20", "\x4a", "\x75", "\x6c", "\x20", "\x41", -- u n - J u l - A "\x75", "\x67", "\x20", "\x53", "\x65", "\x70", "\x74", "\x20", -- u g - S e p t - "\x4f", "\x63", "\x74", "\x20", "\x4e", "\x6f", "\x76", "\x20", -- O c t - N o v - "\x44", "\x65", "\x63", "\x20", "\x30", "\x30", "\x3a", "\x30", -- D e c - 0 0 - 0 "\x30", "\x3a", "\x30", "\x30", "\x20", "\x4d", "\x6f", "\x6e", -- 0 - 0 0 - M o n "\x2c", "\x20", "\x54", "\x75", "\x65", "\x2c", "\x20", "\x57", -- - - T u e - - W "\x65", "\x64", "\x2c", "\x20", "\x54", "\x68", "\x75", "\x2c", -- e d - - T h u - "\x20", "\x46", "\x72", "\x69", "\x2c", "\x20", "\x53", "\x61", -- - F r i - - S a "\x74", "\x2c", "\x20", "\x53", "\x75", "\x6e", "\x2c", "\x20", -- t - - S u n - - "\x47", "\x4d", "\x54", "\x63", "\x68", "\x75", "\x6e", "\x6b", -- G M T c h u n k "\x65", "\x64", "\x2c", "\x74", "\x65", "\x78", "\x74", "\x2f", -- e d - t e x t - "\x68", "\x74", "\x6d", "\x6c", "\x2c", "\x69", "\x6d", "\x61", -- h t m l - i m a "\x67", "\x65", "\x2f", "\x70", "\x6e", "\x67", "\x2c", "\x69", -- g e - p n g - i "\x6d", "\x61", "\x67", "\x65", "\x2f", "\x6a", "\x70", "\x67", -- m a g e - j p g "\x2c", "\x69", "\x6d", "\x61", "\x67", "\x65", "\x2f", "\x67", -- - i m a g e - g "\x69", "\x66", "\x2c", "\x61", "\x70", "\x70", "\x6c", "\x69", -- i f - a p p l i "\x63", "\x61", "\x74", "\x69", "\x6f", "\x6e", "\x2f", "\x78", -- c a t i o n - x "\x6d", "\x6c", "\x2c", "\x61", "\x70", "\x70", "\x6c", "\x69", -- m l - a p p l i "\x63", "\x61", "\x74", "\x69", "\x6f", "\x6e", "\x2f", "\x78", -- c a t i o n - x "\x68", "\x74", "\x6d", "\x6c", "\x2b", "\x78", "\x6d", "\x6c", -- h t m l - x m l "\x2c", "\x74", "\x65", "\x78", "\x74", "\x2f", "\x70", "\x6c", -- - t e x t - p l "\x61", "\x69", "\x6e", "\x2c", "\x74", "\x65", "\x78", "\x74", -- a i n - t e x t "\x2f", "\x6a", "\x61", "\x76", "\x61", "\x73", "\x63", "\x72", -- - j a v a s c r "\x69", "\x70", "\x74", "\x2c", "\x70", "\x75", "\x62", "\x6c", -- i p t - p u b l "\x69", "\x63", "\x70", "\x72", "\x69", "\x76", "\x61", "\x74", -- i c p r i v a t "\x65", "\x6d", "\x61", "\x78", "\x2d", "\x61", "\x67", "\x65", -- e m a x - a g e "\x3d", "\x67", "\x7a", "\x69", "\x70", "\x2c", "\x64", "\x65", -- - g z i p - d e "\x66", "\x6c", "\x61", "\x74", "\x65", "\x2c", "\x73", "\x64", -- f l a t e - s d "\x63", "\x68", "\x63", "\x68", "\x61", "\x72", "\x73", "\x65", -- c h c h a r s e "\x74", "\x3d", "\x75", "\x74", "\x66", "\x2d", "\x38", "\x63", -- t - u t f - 8 c "\x68", "\x61", "\x72", "\x73", "\x65", "\x74", "\x3d", "\x69", -- h a r s e t - i "\x73", "\x6f", "\x2d", "\x38", "\x38", "\x35", "\x39", "\x2d", -- s o - 8 8 5 9 - "\x31", "\x2c", "\x75", "\x74", "\x66", "\x2d", "\x2c", "\x2a", -- 1 - u t f - - - "\x2c", "\x65", "\x6e", "\x71", "\x3d", "\x30", "\x2e" -- - e n q - 0 - }) local spdy_deflate = function(data, dictionary, compression_level) local buffer = {} local f = function(d) table.insert(buffer, d) end local stream = zlib.deflate( f, compression_level, nil, Z_DEFAULT_WINDOW_BITS, 1, nil, dictionary) stream:write(data) stream:flush() return table.concat(buffer) end local spdy_inflate = function(data, dictionary) local stream = zlib.inflate(data, Z_DEFAULT_WINDOW_BITS, dictionary) return stream:read("*a") end spdy_compress = function(data, dictionary, compression_level) return pcall(spdy_deflate, data, dictionary, compression_level) end spdy_decompress = function(data, dictionary) return pcall(spdy_inflate, data, dictionary) end -- Errors Error = { ERROR_TLS_NEXTPROTONEG_NOT_SUPPORTED = "TLS NEXTPROTONEG NOT SUPPORTED", ERROR_TLS_NEXTPROTONEG_NO_OVERLAP = "TLS NEXTPROTONEG NO OVERLAP", ERROR_CONNECT = "CONNECT", ERROR_TIMEOUT = "TIMEOUT", ERROR_INVALID_FRAME = "INVALID FRAME", ERROR_INVALID_STREAM = "INVALID STREAM", ERROR_SPDY_VERSION_UNSUPPORTED = "UNSUPPORTED SPDY VERSION", ERROR_INFLATE = "INFLATE", ERROR_DEFLATE = "DEFLATE ", ERROR_UNKNOWN = "UNKNOWN" } -- Flags on data packets. local SPDY_DATA_FLAGS = { ["DATA_FLAG_NONE"] = 0x00, ["DATA_FLAG_FIN"] = 0x01, ["DATA_FLAG_END_SEGMENT"] = 0x02, ["DATA_FLAG_PADDED"] = 0x08, ["DATA_FLAG_COMPRESSED"] = 0x20 } -- Flags on control packets SPDY_CONTROL_FLAGS = { ["CONTROL_FLAG_NONE"] = 0x00, ["CONTROL_FLAG_FIN"] = 0x01, ["CONTROL_FLAG_UNIDIRECTIONAL"] = 0x02 } SPDY_PING_FLAGS = { ["PING_FLAG_ACK"] = 0x01 } -- Used by HEADERS, PUSH_PROMISE, and CONTINUATION. SPDY_HEADERS_FLAGS = { ["HEADERS_FLAG_END_SEGMENT"] = 0x02, ["HEADERS_FLAG_END_HEADERS"] = 0x04, ["HEADERS_FLAG_PADDED"] = 0x08, ["HEADERS_FLAG_PRIORITY"] = 0x20 } SPDY_PUSH_PROMISE_FLAGS = { ["PUSH_PROMISE_FLAG_END_PUSH_PROMISE"] = 0x04, ["PUSH_PROMISE_FLAG_PADDED"] = 0x08 } -- Flags on the SETTINGS control frame. SPDY_SETTINGS_CONTROL_FLAGS = { ["SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS"] = 0x01 } HTTP2_SETTIMGS_CONTROL_FLAGS = { ["SETTINGS_FLAG_ACK"] = 0x01 } -- Flags for settings within a SETTINGS frame. SPDY_SETTINGS_FLAGS = { ["SETTINGS_FLAG_NONE"] = 0x00, ["SETTINGS_FLAG_PLEASE_PERSIST"] = 0x01, ["SETTINGS_FLAG_PERSISTED"] = 0x02 } -- List of known settings SPDY_SETTINGS_IDS = { ["SETTINGS_UPLOAD_BANDWIDTH"] = 0x1, ["SETTINGS_DOWNLOAD_BANDWIDTH"] = 0x2, -- Network round trip time in milliseconds. ["SETTINGS_ROUND_TRIP_TIME"] = 0x3, -- The maximum number of simultaneous live streams in each direction. ["SETTINGS_MAX_CONCURRENT_STREAMS"] = 0x4, -- TCP congestion window in packets. ["SETTINGS_CURRENT_CWND"] = 0x5, -- Downstream byte retransmission rate in percentage. ["SETTINGS_DOWNLOAD_RETRANS_RATE"] = 0x6, -- Initial window size in bytes ["SETTINGS_INITIAL_WINDOW_SIZE"] = 0x7, -- HPACK header table maximum size. ["SETTINGS_HEADER_TABLE_SIZE"] = 0x8, -- Whether or not server push (PUSH_PROMISE) is enabled. ["SETTINGS_ENABLE_PUSH"] = 0x9 } -- Status codes for RST_STREAM frames. SPDY_RST_STREAM_STATUS = { ["RST_STREAM_INVALID"] = 0, ["RST_STREAM_PROTOCOL_ERROR"] = 1, ["RST_STREAM_INVALID_STREAM"] = 2, ["RST_STREAM_STREAM_CLOSED"] = 2, -- Equivalent to INVALID_STREAM ["RST_STREAM_REFUSED_STREAM"] = 3, ["RST_STREAM_UNSUPPORTED_VERSION"] = 4, ["RST_STREAM_CANCEL"] = 5, ["RST_STREAM_INTERNAL_ERROR"] = 6, ["RST_STREAM_FLOW_CONTROL_ERROR"] = 7, ["RST_STREAM_STREAM_IN_USE"] = 8, ["RST_STREAM_STREAM_ALREADY_CLOSED"] = 9, ["RST_STREAM_INVALID_CREDENTIALS"] = 10, -- FRAME_TOO_LARGE (defined by SPDY versions 3.1 and below), and -- FRAME_SIZE_ERROR (defined by HTTP/2) are mapped to the same internal -- reset status. ["RST_STREAM_FRAME_TOO_LARGE"] = 11, ["RST_STREAM_FRAME_SIZE_ERROR"] = 11, ["RST_STREAM_SETTINGS_TIMEOUT"] = 12, ["RST_STREAM_CONNECT_ERROR"] = 13, ["RST_STREAM_ENHANCE_YOUR_CALM"] = 14, ["RST_STREAM_NUM_STATUS_CODES"] = 15 } -- Status codes for GOAWAY frames. SPDY_GOAWAY_STATUS = { ["GOAWAY_OK"] = 0, ["GOAWAY_NO_ERROR"] = 0, ["GOAWAY_PROTOCOL_ERROR"] = 1, ["GOAWAY_INTERNAL_ERROR"] = 2, ["GOAWAY_FLOW_CONTROL_ERROR"] = 3, ["GOAWAY_SETTINGS_TIMEOUT"] = 4, ["GOAWAY_STREAM_CLOSED"] = 5, ["GOAWAY_FRAME_SIZE_ERROR"] = 6, ["GOAWAY_REFUSED_STREAM"] = 7, ["GOAWAY_CANCEL"] = 8, ["GOAWAY_COMPRESSION_ERROR"] = 9, ["GOAWAY_CONNECT_ERROR"] = 10, ["GOAWAY_ENHANCE_YOUR_CALM"] = 11, ["GOAWAY_INADEQUATE_SECURITY"] = 12 } -- SPDY3 frames types. Each frame provides a 'pack' and 'unpack' function. -- To help understand the code, the format of each frame is illustrated, as -- specified in the protocol draft. SPDY3_FRAMES = { --+------------------------------------+ --|1| version | 1 | --+------------------------------------+ --| Flags (8) | Length (24 bits) | --+------------------------------------+ ["CONTROL_FRAME_HEADER"] = { value = nil, pack = function(header) flags = 0x00 for _,v in pairs(header["flags"]) do flags = bit.bor(flags, v) end return bin.pack( ">CCSCCS", 0x80, tonumber(header["version"]), SPDY3_FRAMES[header["type"]].value, flags, 0x00, header["length"] ) end, unpack = function(data, start, header) local pos, frame_type pos, header["version"], header["type"] = bin.unpack( ">SS", data, start) header["version"] = bit.band(header["version"], 0x7FFF) pos, header["flags"] = bin.unpack("C", data, pos) pos = pos-1 pos, header["length"] = bin.unpack(">I", data, pos) header["length"] = bit.band(header["length"], 0x00FFFFFF) return pos end }, --+----------------------------------+ --|C| Stream-ID (31bits) | --+----------------------------------+ --| Flags (8) | Length (24 bits) | --+----------------------------------+ --| Data | --+----------------------------------+ ["DATA_FRAME_HEADER"] = { value = nil, pack = function(header) return bin.pack( ">ICCS", header["stream_id"], header["flags"], 0x00, header["length"] ) end, unpack = function(data, start, header) local pos pos, header["stream_id"], header["flags"] = bin.unpack( ">IC", data, start) pos = pos -1 pos, header["length"] = bin.unpack(">I", data, pos) header["length"] = bit.band(header["length"], 0x00FFFFFF) header["type"] = 0 return pos end }, ["DATA"] = { value = 0, pack = function(data) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["DATA_FRAME_HEADER"].unpack( data, start, frame["header"]) frame["payload"] = string.sub( data, pos, pos + frame["header"]["length"]) return pos + frame["header"]["length"] end, }, --+------------------------------------+ --|1| version | 1 | --+------------------------------------+ --| Flags (8) | Length (24 bits) | --+------------------------------------+ --|X| Stream-ID (31bits) | --+------------------------------------+ --|X| Associated-To-Stream-ID (31bits) | --+------------------------------------+ --| Pri|Unused | Slot | | --+-------------------+ | --| Number of Name/Value pairs (int32) | <+ --+------------------------------------+ | --| Length of name (int32) | | This section is the "Name/Value --+------------------------------------+ | Header Block", compressed. --| Name (string) | | --+------------------------------------+ | --| Length of value (int32) | | --+------------------------------------+ | --| Value (string) | | --+------------------------------------+ | --| (repeats) | <+ ["SYN_STREAM"] = { value = 1, pack = function(frame) local name_value_pairs = {} table.insert(name_value_pairs, bin.pack( ">I", frame["num_name_value_pairs"])) for name,value in pairs(frame["name_value_pairs"]) do table.insert(name_value_pairs, bin.pack(">aa", name, value)) end local uncompressed_headers = table.concat(name_value_pairs) local status, compressed_headers = spdy_compress( uncompressed_headers, SPDY3_DICTIONARY, 9) frame["header"]["length"] = 10 + #compressed_headers return bin.pack( ">AIICCA", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["stream_id"], frame["associated_stream_id"], 0x00, 0x00, compressed_headers ) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) local stream_id pos, stream_id = bin.unpack(">I", data, pos) stream_id = bit.band(value, 0x7FFFFFFF) frame["stream_id"] = stream_id local associated_stream_id pos, associated_stream_id = bin.unpack(">I", data, pos) associated_stream_id = bit.band(value, 0x7FFFFFFF) frame["associated_stream_id"] = associated_stream_id -- First 3 bits local priority pos, priority = bin.unpack("C", data, pos) priority = bit.rshift(priority, 5) priority = bin.band(priority, 0x07) frame["priority"] = priority -- Unused local slot pos, slot = bin.unpack("C", data, pos) -- Name/Value header block local status, name_value_block = spdy_decompress( string.sub(data, pos), SPDY3_DICTIONARY) if not status then return -1, Error.ERROR_INFLATE end pos, frame["num_name_value_pairs"] = bin.unpack( ">I", name_value_block, 0) frame["name_value_pairs"] = {} local name, value for i=1,frame["num_name_value_pairs"] do pos, name = bin.unpack(">a", name_value_block, pos) pos, value = bin.unpack(">a", name_value_block, pos) frame["name_value_pairs"][name] = value end frame["header"]["type"] = "SYN_STREAM" return pos end }, --+------------------------------------+ --|1| version | 2 | --+------------------------------------+ --| Flags (8) | Length (24 bits) | --+------------------------------------+ --|X| Stream-ID (31bits) | --+------------------------------------+ --| Number of Name/Value pairs (int32) | <+ --+------------------------------------+ | --| Length of name (int32) | | This section is the "Name/Value --+------------------------------------+ | Header Block", compressed. --| Name (string) | | --+------------------------------------+ | --| Length of value (int32) | | --+------------------------------------+ | --| Value (string) | | --+------------------------------------+ | --| (repeats) | <+ ["SYN_REPLY"] = { value = 2, pack = function(frame) local name_value_pairs = {} table.insert(name_value_pairs, bin.pack( ">I", frame["num_name_value_pairs"])) for name,value in pairs(frame["name_value_pairs"]) do table.insert(name_value_pairs, bin.pack(">aa", name, value)) end local status, compressed_headers = spdy_compress( table.concat(name_value_pairs), SPDY3_DICTIONARY, 9) frame["header"]["length"] = 4 + #compressed_headers return bin.pack( ">AIA", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["stream_id"], compressed_headers ) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) local stream_id pos, stream_id = bin.unpack(">I", data, pos) stream_id = bit.band(stream_id, 0x7FFFFFFF) frame["stream_id"] = stream_id local name_value_block_length = frame["header"]["length"] - 4 local status, name_value_block = spdy_decompress( string.sub(data, pos, name_value_block_length + 8), SPDY3_DICTIONARY) if not status then return pos, nil end -- Get compression level info local CMF, FLG pos, CMF, FLG = bin.unpack("CC", data, pos) frame.extra["compression_method"] = bit.band(CMF, 0x0F) frame.extra["compression_window"] = 8 + bit.rshift( bit.band(CMF,0xF0), 4) frame.extra["compression_level"] = bit.band(bit.rshift(FLG, 6), 0x03) pos, frame["num_name_value_pairs"] = bin.unpack(">I", name_value_block, 0) frame["name_value_pairs"] = {} local name, length, value, format for i=1,frame["num_name_value_pairs"] do pos, name = bin.unpack(">a", name_value_block, pos) pos, value = bin.unpack(">a", name_value_block, pos) frame["name_value_pairs"][name] = value end frame["header"]["type"] = "SYN_REPLY" return start + 12 + name_value_block_length + 1 end }, --+----------------------------------+ --|1| version | 3 | --+----------------------------------+ --| Flags (8) | 8 | --+----------------------------------+ --|X| Stream-ID (31bits) | --+----------------------------------+ --| Status code | --+----------------------------------+ ["RST_STREAM"] = { value = 3, pack = function(frame) frame["header"]["length"] = 8 return bin.pack( ">AII", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["stream_id"], frame["status_code"] ) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) pos, frame["stream_id"] = bin.unpack(">I", data, pos) frame["stream_id"] = bit.band(frame["stream_id"], 0x7FFFFFFF) pos, frame["status_code"] = bin.unpack(">I", data, pos) frame["header"]["type"] = "RST_STREAM" return pos end }, --+----------------------------------+ --|1| version | 4 | --+----------------------------------+ --| Flags (8) | Length (24 bits) | --+----------------------------------+ --| Number of entries | --+----------------------------------+ --| ID/Value Pairs | --| ... | --+----------------------------------+ --Each ID/value pair is as follows: -- -- +----------------------------------+ -- | Flags(8) | ID (24 bits) | -- +----------------------------------+ -- | Value (32 bits) | -- +----------------------------------+ ["SETTINGS"] = { value = 4, pack = function(frame) frame["header"]["length"] = 8 + frame["num_settings"] * 4 id_value_pairs = {} for _,id_value in ipairs(frame["settings"]) do table.insert(id_value_pairs, bin.pack(">CCSI", id_value["flags"], 0x00, id_value["id"], id_value["value"] ) ) end return bin.pack( ">AIA", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["num_settings"], table.concat(id_value_pairs) ) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) pos, frame["num_settings"] = bin.unpack(">I", data, pos) frame["settings"] = {} local flags, id, value for i=1,frame["num_settings"] do pos, value = bin.unpack("C", data, pos) for k,v in pairs(SPDY_SETTINGS_FLAGS) do if v == value then flags = k end end pos = pos -1 pos, value = bin.unpack(">I", data, pos) value = bit.band(value, 0x00FFFFFF) for k,v in pairs(SPDY_SETTINGS_IDS) do if v == value then id = k end end pos, value = bin.unpack(">I", data, pos) table.insert(frame["settings"], { ["flags"] = flags, ["id"] = id, ["value"] = value }) end frame["header"]["type"] = "SETTINGS" return pos end, }, --+----------------------------------+ --|1| version | 6 | --+----------------------------------+ --| 0 (flags) | 4 (length) | --+----------------------------------| --| 32-bit ID | --+----------------------------------+ ["PING"] = { value = 6, pack = function(frame) frame["header"]["length"] = 4 return bin.pack( ">AI", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["ping_id"] ) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) pos, frame["ping_id"] = bin.unpack(">I", data, pos) frame["header"]["type"] = "PING" return pos end }, --+----------------------------------+ --|1| version | 7 | --+----------------------------------+ --| 0 (flags) | 8 (length) | --+----------------------------------| --|X| Last-good-stream-ID (31 bits) | --+----------------------------------+ --| Status code | --+----------------------------------+ ["GOAWAY"] = { value = 7, pack = function(frame) data["header"]["length"] = 8 return bin.pack( ">AII", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["last_good_stream_id"], frame["status_code"] ) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) pos, frame["last_good_stream_id"] = bin.unpack(">I", data, pos) pos, frame["status_code"] = bin.unpack(">I", data, pos) frame["header"]["type"] = "GOAWAY" return pos end }, --+------------------------------------+ --|1| version | 8 | --+------------------------------------+ --| Flags (8) | Length (24 bits) | --+------------------------------------+ --|X| Stream-ID (31bits) | --+------------------------------------+ --| Number of Name/Value pairs (int32) | <+ --+------------------------------------+ | --| Length of name (int32) | | This section is the "Name/Value --+------------------------------------+ | Header Block", compressed. --| Name (string) | | --+------------------------------------+ | --| Length of value (int32) | | --+------------------------------------+ | --| Value (string) | | --+------------------------------------+ | --| (repeats) | <+ ["HEADERS"] = { value = 8, pack = function(frame) local name_value_pairs = {} table.insert(name_value_pairs, bin.pack( ">I", frame["num_name_value_pairs"])) for name,value in pairs(frame["name_value_pairs"]) do table.insert(name_value_pairs, bin.pack(">aa", name, value)) end local status, compressed_headers = spdy_compress( table.concat(name_value_pairs), SPDY3_DICTIONARY, 9) frame["header"]["length"] = 4 + #compressed_headers return bin.pack( ">AIA", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["stream_id"], compressed_headers ) end, -- Just unpack this as a SYN_REPLY frame and change the type unpack = function(data, start, frame) local pos = SPDY3_FRAMES["SYN_REPLY"].unpack(data, start, frame) frame["header"]["type"] = "HEADERS" return pos end, }, --+----------------------------------+ --|1| version | 9 | --+----------------------------------+ --| 0 (flags) | 8 (length) | --+----------------------------------+ --|X| Stream-ID (31-bits) | --+----------------------------------+ --|X| Delta-Window-Size (31-bits) | --+----------------------------------+ ["WINDOW_UPDATE"] = { value = 9, pack = function(frame) frame["header"]["length"] = 8 return bin.pack( ">AII", SPDY3_FRAMES["CONTROL_FRAME_HEADER"].pack(frame["header"]), frame["stream_id"], frame["delta_window_size"]) end, unpack = function(data, start, frame) local pos = SPDY3_FRAMES["CONTROL_FRAME_HEADER"].unpack( data, start, frame["header"]) pos, frame["stream_id"] = bin.unpack(">I", data, pos) pos, frame["delta_window_size"] = bin.unpack(">I", data, pos) frame["header"]["type"] = "WINDOW_UPDATE" return pos end }, ["INVALID"] = { value = -1, pack = function(frame) return nil end, unpack = function(data, start, frame) frame["header"]["type"] = "INVALID" return -1 end } } SPDY_FRAMES = { ["spdy/3"] = SPDY3_FRAMES, ["spdy/3.1"] = SPDY3_FRAMES, ["spdy/4"] = {}, ["spdy/5"] = {}, ["spdy/5a1"] = {} } SPDY_DICTIONARY = { ["spdy/3"] = SPDY3_DICTIONARY, ["spdy/3.1"] = SPDY3_DICTIONARY, ["spdy/4"] = "", ["spdy/5a1"] = "" } SPDY_PROTOCOLS = {"spdy/3", "spdy/3.1"} Frame = { DATA = "DATA", SYN_STREAM = "SYN_STREAM", SYN_REPLY = "SYN_REPLY", RST_STREAM = "RST_STREAM", SETTINGS = "SETTINGS", PING = "PING", GOAWAY = "GOAWAY", HEADERS = "HEADERS", WINDOW_UPDATE = "WINDOW_UPDATE", CREDENTIAL = "CREDENTIAL", BLOCKED = "BLOCKED", PUSH_PROMISE = "PUSH_PROMISE", CONTINUATION = "CONTINUATION", ALTSVC = "ALTSVC", PRIORITY = "PRIORITY", INVALID = "INVALID", new = function(self, spdy_version) local o = {} setmetatable(o, self) self.__index = self o.spdy_version = spdy_version or "3.1" o.spdy_protocol = "spdy/" .. o.spdy_version o.data = {} o.data["header"] = {} o.data["header"]["flags"] = {} o.data["header"]["type"] = Frame.INVALID o.data["header"]["version"] = tonumber(spdy_version) o.data["header"]["length"] = 0 o.data["header"]["stream_id"] = 0 o.data["stream_id"] = 0 o.data["associated_stream_id"] = 0 o.data["num_name_value_pairs"] = nil o.data["name_value_pairs"] = {} o.data["priority"] = 0 o.data["status_code"] = 0 o.data["delta_window_size"] = 0 o.data["last_good_stream_id"] = 0 o.data["ping_id"] = 0 o.data["num_settings"] = 0 o.data["settings"] = {} o.extra = {} return o end, set_type = function(self, frame_type) self.data["header"]["type"] = frame_type end, get_type = function(self) if not self.data then return Frame.INVALID elseif not self.data["header"] then return Frame.INVALID elseif not self.data["header"]["type"] then return Frame.INVALID end return self.data["header"]["type"] end, set_stream_id = function(self, stream_id) self.data["stream_id"] = stream_id end, get_stream_id = function(self) return self.data["stream_id"] end, set_associated_stream_id = function(self, stream_id) self.data["associated_stream_id"] = stream_id end, get_associated_stream_id = function(self) return self.data["associated_stream_id"] end, set_priority = function(self, priority) self.data["priority"] = priority end, get_priority = function(self) return self.data["priority"] end, set_num_settings = function(self, num_settings) self.data["num_settings"] = num_settings end, get_num_settings = function(self) return self.data["num_settings"] end, set_settings = function(self, settings) self.data["settings"] = settings if not self.data["num_settings"] then self.data["num_settings"] = #settings end end, set_flag = function(self, flag) table.insert(self.data["header"]["flags"], flag) end, set_num_name_value_pairs = function(self, num_pairs) self.data["num_name_value_pairs"] = num_pairs end, get_num_name_value_pairs = function(self) local num_pairs = #self.data["name_value_pairs"] if self.data["num_name_value_pairs"] then num_pairs = self.data["num_name_value_pairs"] end return num_pairs end, set_name_value_pairs = function(self, name_value_pairs) self.data["name_value_pairs"] = name_value_pairs if not self.data["num_name_value_pairs"] then local num_pairs = 0 local k, v for k,v in pairs(name_value_pairs) do num_pairs = num_pairs + 1 end self.data["num_name_value_pairs"] = num_pairs end end, get_name_value_pairs = function(self) return self.data["name_value_pairs"] end, pack = function(self) return SPDY3_FRAMES[self.data["header"]["type"]].pack( self.data) end, unpack = function(self, data, pos) -- Check the first bit, to see if it's a data frame or -- a control frame local unused, value = bin.unpack("C", data, pos) local control_bit = bit.band(value, 0x80) if control_bit == 0 then return self:unpack_data_frame(data, pos) else return self:unpack_control_frame(data, pos) end end, unpack_data_frame = function(self, data, start) return SPDY3_FRAMES["DATA"].unpack(data, start, self.data) end, unpack_control_frame = function(self, data, start) local pos, version, frame_type = bin.unpack(">SS", data, start) self:set_type(self:decode_frame_type(frame_type)) if self.data["header"]["type"] == Frame.INVALID then stdnse.debug("Invalid frame type", version) return -1, Error.INVALID_FRAME end return SPDY3_FRAMES[self.data["header"]["type"]].unpack( data, start, self.data) end, decode_frame_type = function(self, value) local spdy_version = "spdy/" .. self.spdy_version for k,v in pairs(SPDY_FRAMES[spdy_version]) do if value == v.value then return k end end return Frame.INVALID end } Session = { new = function(self, spdy_version, host, port) local o = {} setmetatable(o, self) self.__index = self o.spdy_version = spdy_version or "3" o.host = host o.port = port o.timeout = 10000 return o end, open = function(self) local protocol = "spdy/" .. self.spdy_version local status, err self.socket = nmap.new_socket() self.socket:set_timeout(self.timeout) status = self.socket:connect(self.host, self.port) if not status then return false, Error.ERROR_CONNECT end return self.socket:reconnect_ssl(protocol) end, send_frame = function(self, frame) return self.socket:send(frame:pack()) end, receive_frames = function(self) local status, response = self.socket:receive() if not status then return nil, response end -- Unpack the frames received local frames = {} local err local done = false local start = 0 repeat local frame = Frame:new(self.spdy_version) local pos = frame:unpack(response, start) if pos == -1 then stdnse.debug("Error while unpacking frame") done = true else table.insert(frames, frame) start = pos end until done or (start >= #response) return frames end, close = function(self) self.socket:close() end } Helper = { new = function(self, config) local o = {} setmetatable(o, self) self.__index = self o.spdy_version = config.version or "3" o.spdy_protocol = "spdy/" .. o.spdy_version return o end, new_frame = function(self) return Frame:new(self.spdy_version) end, new_session = function(self, host, port) return Session:new(self.spdy_version, host, port) end } return _ENV;