syspy 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/bytes.rb ADDED
@@ -0,0 +1,98 @@
1
+ require "bindata"
2
+
3
+ module Syspy
4
+ class Bytes
5
+ def self.uint(io)
6
+ BinData::Uint8.read(io).to_i
7
+ end
8
+
9
+ def self.uintle(io,length)
10
+ case length
11
+ when 1:
12
+ BinData::Uint8.read(io).to_i
13
+ when 2:
14
+ BinData::Uint16le.read(io).to_i
15
+ when 4:
16
+ BinData::Uint32le.read(io).to_i
17
+ else
18
+ raise ArgumentError.new("Invalid length")
19
+ end
20
+ end
21
+
22
+ def self.uint16le(io)
23
+ BinData::Uint16le.read(io).to_i
24
+ end
25
+
26
+ def self.uint32le(io)
27
+ BinData::Uint32le.read(io) .to_i
28
+ end
29
+
30
+ def self.uintbe(io,length)
31
+ case length
32
+ when 1:
33
+ BinData::Uint8.read(io).to_i
34
+ when 2:
35
+ BinData::Uint16be.read(io).to_i
36
+ when 4:
37
+ BinData::Uint32be.read(io).to_i
38
+ else
39
+ raise ArgumentError.new("Invalid length")
40
+ end
41
+ end
42
+
43
+ def self.uint16be(io)
44
+ BinData::Uint16be.read(io).to_i
45
+ end
46
+
47
+ def self.uint32be(io)
48
+ BinData::Uint32be.read(io).to_i
49
+ end
50
+
51
+ def self.int(io)
52
+ BinData::Int8.read(io).to_i
53
+ end
54
+
55
+ def self.intle(io,length)
56
+ case length
57
+ when 1:
58
+ BinData::Int8.read(io).to_i
59
+ when 2:
60
+ BinData::Int16le.read(io).to_i
61
+ when 4:
62
+ BinData::Int32le.read(io).to_i
63
+ else
64
+ raise ArgumentError.new("Invalid length")
65
+ end
66
+ end
67
+
68
+ def self.int16le(io)
69
+ BinData::Int16le.read(io).to_i
70
+ end
71
+
72
+ def self.int32le(io)
73
+ BinData::Int32le.read(io).to_i
74
+ end
75
+
76
+ def self.intbe(io,length)
77
+ case length
78
+ when 1:
79
+ BinData::Int8.read(io).to_i
80
+ when 2:
81
+ BinData::Int16be.read(io).to_i
82
+ when 4:
83
+ BinData::Int32be.read(io).to_i
84
+ else
85
+ raise ArgumentError.new("Invalid length")
86
+ end
87
+ end
88
+
89
+ def self.int16be(io)
90
+ BinData::Int16be.read(io).to_i
91
+ end
92
+
93
+ def self.int32be(io)
94
+ BinData::Int32be.read(io).to_i
95
+ end
96
+
97
+ end
98
+ end
data/lib/log.rb ADDED
@@ -0,0 +1,45 @@
1
+ require "logger"
2
+
3
+ module Syspy
4
+ class Log
5
+
6
+ LOG_FILE = "syspy.log"
7
+ LOGGERS = []
8
+
9
+ STDOUT_LOG = Logger.new(STDOUT)
10
+ STDOUT_LOG.level = Logger::INFO
11
+
12
+ #FILE_LOG = Logger.new(LOG_FILE)
13
+ #FILE_LOG.level = Logger::INFO
14
+
15
+ LOGGERS << STDOUT_LOG
16
+ #LOGGERS << FILE_LOG
17
+
18
+ def self.fatal(message)
19
+ self.log(Logger::FATAL,message)
20
+ end
21
+
22
+ def self.error(message)
23
+ self.log(Logger::ERROR,message)
24
+ end
25
+
26
+ def self.warn(message)
27
+ self.log(Logger::WARN,message)
28
+ end
29
+
30
+ def self.info(message)
31
+ self.log(Logger::INFO,message)
32
+ end
33
+
34
+ def self.debug(message)
35
+ self.log(Logger::DEBUG,message)
36
+ end
37
+
38
+ def self.log(severity,message)
39
+ LOGGERS.each(){|logger|
40
+ logger.log(severity,message)
41
+ }
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ require "lib/bytes"
2
+
3
+ module Syspy
4
+
5
+ class ParseError < Exception
6
+ end
7
+
8
+ class TdsPackage
9
+
10
+ def read_uint(io)
11
+ Bytes.uint(io)
12
+ end
13
+
14
+ def read_uint32(io)
15
+ Bytes.uint32le(io)
16
+ end
17
+
18
+ def read_uint16(io)
19
+ Bytes.uint16le(io)
20
+ end
21
+
22
+ def read_int(io)
23
+ Bytes.int(io)
24
+ end
25
+
26
+ def read_int32(io)
27
+ Bytes.int32le(io)
28
+ end
29
+
30
+ def read_int16(io)
31
+ Bytes.int16le(io)
32
+ end
33
+
34
+ def read_text(io,length)
35
+ io.read(length)
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,121 @@
1
+ require "stringio"
2
+ require "thread"
3
+
4
+ require "lib/tds_types"
5
+ require "lib/tds_tokens"
6
+
7
+ module Syspy
8
+ class TdsPackageStream
9
+
10
+ def initialize(interface,dst,dst_port)
11
+ @interface = interface
12
+ @dst = dst
13
+ @dst_port = dst_port
14
+ @in,@out = IO.pipe()
15
+ end
16
+
17
+ def each_package()
18
+ Thread.abort_on_exception = true
19
+ @tcpdump_thread = Thread.new(){
20
+ IO.popen("tcpdump -q -y EN10MB -U -B #{1024 * 1024} -w - -i #{@interface} tcp and dst #{@dst} and dst port #{@dst_port} 2>/dev/null"){|io|
21
+ content = ""
22
+ loop(){
23
+ tcp_length = read_ip_header(io)
24
+ Log.debug "Got IP package: #{tcp_length}"
25
+ content_length = read_tcp_header(io,tcp_length)
26
+ Log.debug "Got TCP package: #{content_length}"
27
+
28
+ if(content_length > 0)
29
+ content = io.read(content_length)
30
+ @out.write(content)
31
+ @out.flush
32
+ end
33
+
34
+ Log.debug "Network package done"
35
+ }
36
+ }
37
+ }
38
+
39
+ content = ""
40
+ @in.each_byte(){|byte|
41
+ if(byte == 0x0F)
42
+ last_packet_indicator = Bytes.uint(@in)
43
+ length = Bytes.uint16be(@in)
44
+
45
+ # skip next 4 bytes of the header
46
+ if(Bytes.uint32be(@in) == 0x00)
47
+ content << @in.read(length - 8)
48
+
49
+ if(last_packet_indicator == 0x1)
50
+ begin
51
+ io = StringIO.new(content)
52
+ package = handle_package(io)
53
+ yield package if package
54
+ ensure
55
+ content = ""
56
+ end
57
+ end
58
+ end
59
+ end
60
+ }
61
+ end
62
+
63
+ def handle_package(io)
64
+ token = io.readchar()
65
+ token_class = TdsTokens.token_class(token)
66
+ if(token_class)
67
+ length = TdsTokens.fixed_length(token)
68
+ unless(length)
69
+ length_field_size = TdsTokens.length_field_size(token)
70
+ if(length_field_size)
71
+ length = Bytes.uintle(io,length_field_size)
72
+ end
73
+ end
74
+ Log.debug("Got #{TdsTokens.token_name(token)} of #{length} bytes")
75
+ package = token_class.new(io,length)
76
+ return package
77
+ end
78
+ nil
79
+ end
80
+
81
+ def read_ip_header(io)
82
+ count = 0
83
+ loop(){
84
+ network_type = Bytes.uint16be(io)
85
+ break if network_type == 0x800 and count >= 14
86
+ count += 1
87
+ }
88
+
89
+ # read IP version and header length
90
+ ver_len = io.readchar()
91
+ version = ver_len >> 4
92
+
93
+ raise "Invalid IP version: #{version}" unless version == 4 || version == 6
94
+
95
+ header_length = (ver_len & 0x0F) * 4
96
+
97
+ # skip TOS
98
+ io.readchar()
99
+
100
+ # get package length
101
+ content_length = Bytes.uint16be(io)
102
+
103
+ # consume remaining IP header
104
+ io.read(header_length - 4)
105
+ content_length - header_length
106
+ end
107
+
108
+ def read_tcp_header(io, ip_package_size)
109
+ # skip first 12
110
+ io.read(12)
111
+
112
+ # get header length
113
+ tcp_offset = (io.readchar() >> 4) * 4
114
+
115
+ # consume remaining tcp header
116
+ io.read(tcp_offset - 13)
117
+
118
+ ip_package_size - tcp_offset
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,32 @@
1
+ require "lib/tds_package"
2
+
3
+ module Syspy
4
+ class TdsLanguage < TdsPackage
5
+
6
+ attr_reader :status, :language_text, :tds_paramfmt, :tds_params
7
+
8
+ STATUS_PARAMETERIZED = 0x01
9
+
10
+ def initialize(io,length)
11
+ @status = read_uint(io)
12
+ @language_text = read_text(io,length - 1)
13
+ if(@status == 1 && !io.eof?)
14
+ token = read_uint(io)
15
+ if(token == TdsTokens::TDS_PARAMFMT || token == TdsTokens::TDS_PARAMFMT2)
16
+ paramfmt_length = Bytes.uintle(io,TdsTokens.length_field_size(token))
17
+ if(paramfmt_length < 1000000)
18
+ @tds_paramfmt = TdsTokens.token_class(token).new(io,paramfmt_length)
19
+ if(@tds_paramfmt.params_count > 0)
20
+ token = read_uint(io)
21
+ if(token == TdsTokens::TDS_PARAMS)
22
+ @tds_params = TdsParams.new(io,@tds_paramfmt)
23
+ end
24
+ end
25
+ else
26
+ Log.warn("Illegal paramfmt length: #{paramfmt_length}")
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Syspy
2
+ class TdsParamfmt < TdsPackage
3
+
4
+ attr_reader :params_count, :parameters
5
+
6
+ def initialize(io,length)
7
+ @params_count = read_uint16(io)
8
+ puts "TdsParamfmt2: #{@params_count}"
9
+ @parameters = []
10
+ 1.upto(@params_count){
11
+
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ module Syspy
2
+ class TdsParamfmt2 < TdsPackage
3
+
4
+ attr_reader :params_count, :parameters
5
+
6
+ def initialize(io,length)
7
+ @params_count = read_uint16(io)
8
+ @parameters = []
9
+
10
+ 1.upto(@params_count){
11
+ parameter = {}
12
+ name_length = read_uint(io)
13
+ parameter[:name_length] = name_length
14
+ if(name_length > 0)
15
+ parameter[:param_name] = read_text(io,name_length)
16
+ end
17
+ parameter[:status] = read_uint32(io)
18
+ parameter[:user_type] = read_int32(io)
19
+ data_type = read_uint(io)
20
+ parameter[:data_type] = data_type
21
+
22
+ data_length = TdsTypes.fixed_length(data_type)
23
+
24
+ if(data_length == -5)
25
+ data_length = Bytes.int32le(io)
26
+ elsif(data_length == -4)
27
+ data_length = Bytes.int32le(io)
28
+ elsif(data_length == -2)
29
+ data_length = Bytes.int32le(io)
30
+ elsif(data_length == -1)
31
+ data_length = Bytes.uint(io)
32
+ end
33
+
34
+ parameter[:length] = data_length
35
+
36
+ if(TdsTypes.numeric?(data_type))
37
+ parameter[:precision] = read_uint(io)
38
+ parameter[:scale] = read_uint(io)
39
+ end
40
+
41
+ locale_length = read_uint(io)
42
+ parameter[:locale_length] = locale_length
43
+ if(locale_length > 0)
44
+ parameter[:locale_info] = read_text(io,locale_length)
45
+ end
46
+ @parameters << parameter
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ module Syspy
2
+ class TdsParams < TdsPackage
3
+
4
+ attr_reader :params_count, :parameters
5
+
6
+ def initialize(io,paramfmt)
7
+ @parameters = []
8
+ paramfmt.parameters.each(){|format|
9
+ @parameters << read_data(io,format)
10
+ }
11
+ end
12
+
13
+ def read_data(io,format)
14
+ data_type = format[:data_type]
15
+ case data_type
16
+ when TdsTypes::SYBINTN
17
+ len = read_int(io)
18
+ return Bytes.intle(io,len)
19
+ when TdsTypes::SYBINT1
20
+ return Bytes.int(io)
21
+ when TdsTypes::SYBINT2
22
+ return Bytes::int16le(io)
23
+ when TdsTypes::SYBINT4
24
+ return Bytes::int32le(io)
25
+ when TdsTypes::SYBCHAR, TdsTypes::SYBVARCHAR
26
+ len = read_uint(io)
27
+ if (len > 0)
28
+ val = read_text(io,len)
29
+ # In TDS 4/5 zero length varchars are stored as a
30
+ # single space to distinguish them from nulls.
31
+ if(len == 1 && data_type == TdsTypes::SYBVARCHAR)
32
+ return " " == val ? "" : val
33
+ end
34
+ return val
35
+ end
36
+ when TdsTypes::SYBDATETIME4, TdsTypes::SYBDATETIMN, TdsTypes::SYBDATETIME
37
+ read_datetime(io,data_type)
38
+ else
39
+ raise "Unhandled data type: #{TdsTypes.name(data_type)} (0x#{data_type.to_s(16)})"
40
+ end
41
+ end
42
+
43
+ TIME_DIFF = Time.at(0) - Time.local(1900,1,1)
44
+
45
+ def read_datetime(io,data_type)
46
+ if (data_type == TdsTypes::SYBDATETIMN)
47
+ len = read_uint(io)
48
+ elsif (data_type == TdsTypes::SYBDATETIME4)
49
+ len = 4;
50
+ else
51
+ len = 8;
52
+ end
53
+
54
+ gmt_offset = Time.new().gmt_offset
55
+
56
+ case len
57
+ when 0
58
+ return nil
59
+ when 8
60
+ days = read_int32(io)
61
+ time = read_int32(io)
62
+ return Time.at(days * 24 * 3600 - TIME_DIFF + time / 300 - gmt_offset)
63
+ when 4
64
+ days = read_int16le(io)
65
+ time = read_int16le(io)
66
+ return Time.at(days * 24 * 3600 + time * 60 - gmt_offset)
67
+ end
68
+ end
69
+ end
70
+ end
data/lib/tds_tokens.rb ADDED
@@ -0,0 +1,104 @@
1
+ module Syspy
2
+ class TdsTokens
3
+ TOKENS = [
4
+ ["TDS_ALTFMT", 0xA8, 2],
5
+ ["TDS_ALTNAME", 0xA7, 2],
6
+ ["TDS_ALTROW", 0xD3, nil],
7
+ ["TDS_CAPABILITY", 0xE2, 2],
8
+ ["TDS_COLINFO", 0xA5, 2],
9
+ ["TDS_COLINFO2", 0x20, 4],
10
+ ["TDS_CONTROL", 0xAE, 2],
11
+ ["TDS_CURCLOSE", 0x80, 2],
12
+ ["TDS_CURDECLARE", 0x86, 2],
13
+ ["TDS_CURDECLARE2", 0x23, 4],
14
+ ["TDS_CURDECLARE3", 0x10, 4],
15
+ ["TDS_CURDELETE", 0x81, 2],
16
+ ["TDS_CURFETCH", 0x82, 2],
17
+ ["TDS_CURINFO", 0x83, 2],
18
+ ["TDS_CURINFO2", 0x87, 2],
19
+ ["TDS_CURINFO3", 0x88, 2],
20
+ ["TDS_CUROPEN", 0x84, 2],
21
+ ["TDS_CURUPDATE", 0x85, 2],
22
+ ["TDS_DBRPC", 0xE6, 2],
23
+ ["TDS_DBRPC2", 0xE8, 2],
24
+ ["TDS_DONE", 0xFD, [8]],
25
+ ["TDS_DONEINPROC", 0xFF, [8]],
26
+ ["TDS_DONEPROC", 0xFE, [8]],
27
+ ["TDS_DYNAMIC", 0xE7, 2],
28
+ ["TDS_DYNAMIC2", 0x62, 4],
29
+ ["TDS_EED", 0xE5, 2],
30
+ ["TDS_ENVCHANGE", 0xE3, 2],
31
+ ["TDS_ERROR", 0xAA, 2],
32
+ ["TDS_EVENTNOTICE", 0xA2, 2],
33
+ ["TDS_INFO", 0xAB, 2],
34
+ ["TDS_KEY", 0xCA, nil],
35
+ ["TDS_LANGUAGE", 0x21, 4],
36
+ ["TDS_LOGINACK", 0xAD, 2],
37
+ ["TDS_LOGOUT", 0x71, [1]],
38
+ ["TDS_MSG", 0x65, 1, 1],
39
+ ["TDS_OFFSET", 0x78, [4]],
40
+ ["TDS_OPTIONCMD", 0xA6, 2],
41
+ ["TDS_ORDERBY", 0xA9, 2],
42
+ ["TDS_ORDERBY2", 0x22, 4],
43
+ ["TDS_PARAMFMT", 0xEC, 2],
44
+ ["TDS_PARAMFMT2", 0x20, 4],
45
+ ["TDS_PARAMS", 0xD7, nil],
46
+ ["TDS_RETURNSTATUS", 0x79, [4]],
47
+ ["TDS_RETURNVALUE", 0xAC, 2],
48
+ ["TDS_ROW", 0xD1, nil],
49
+ ["TDS_ROWFMT", 0xEE, 2],
50
+ ["TDS_ROWFMT2", 0x61, 4],
51
+ ["TDS_TABNAME", 0xA4, 2]
52
+ ]
53
+
54
+ NAMES = {}
55
+ FIXED_LENGTHS = {}
56
+ LENGTH_FIELD_SIZES = {}
57
+ STREAM_CLASSES = {}
58
+
59
+ TOKENS.each(){|values|
60
+ name = values[0]
61
+ token = values[1]
62
+ length = values[2]
63
+
64
+ self.const_set(name,token)
65
+
66
+ NAMES[token] = name
67
+ if(length)
68
+ if(length.instance_of?(Array))
69
+ FIXED_LENGTHS[token] = length.first
70
+ else
71
+ LENGTH_FIELD_SIZES[token] = length
72
+ end
73
+ end
74
+
75
+ class_file_name = name.downcase
76
+ if(File.exist?("lib/tds_packages/#{class_file_name}.rb"))
77
+ require "lib/tds_packages/#{class_file_name}"
78
+ class_name = class_file_name.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
79
+ cl = eval(class_name)
80
+ STREAM_CLASSES[token] = cl
81
+ end
82
+ }
83
+
84
+ def self.token?(token)
85
+ NAMES.include?(token)
86
+ end
87
+
88
+ def self.token_name(token)
89
+ NAMES[token]
90
+ end
91
+
92
+ def self.token_class(token)
93
+ STREAM_CLASSES[token]
94
+ end
95
+
96
+ def self.fixed_length(token)
97
+ FIXED_LENGTHS[token]
98
+ end
99
+
100
+ def self.length_field_size(token)
101
+ LENGTH_FIELD_SIZES[token]
102
+ end
103
+ end
104
+ end
data/lib/tds_types.rb ADDED
@@ -0,0 +1,94 @@
1
+ module Syspy
2
+ class TdsTypes
3
+ TYPES = [
4
+ [0x2f, "SYBCHAR" , "char" , -1, -1, 1, false, false, String ],
5
+ [0x27, "SYBVARCHAR" , "varchar" , -1, -1, 1, false, false, String ],
6
+ [0x26, "SYBINTN" , "int" , -1, 10, 11, true , false, Integer ],
7
+ [0x30, "SYBINT1" , "tinyint" , 1, 3, 4, false, false, Integer ],
8
+ [0x34, "SYBINT2" , "smallint" , 2, 5, 6, true , false, Integer ],
9
+ [0x38, "SYBINT4" , "int" , 4, 10, 11, true , false, Integer ],
10
+ [0x7f, "SYBINT8" , "bigint" , 8, 19, 20, true , false, Integer ],
11
+ [0x3e, "SYBFLT8" , "float" , 8, 15, 24, true , false, Float ],
12
+ [0x3d, "SYBDATETIME" , "datetime" , 8, 23, 23, false, false, Time ],
13
+ [0x32, "SYBBIT" , "bit" , 1, 1, 1, false, false, Integer ],
14
+ [0x23, "SYBTEXT" , "text" , -4, -1, -1, false, true , String ],
15
+ [0x63, "SYBNTEXT" , "ntext" , -4, -1, -1, false, true , String ],
16
+ [0xae, "SYBUNITEXT" , "unitext" , -4, -1, -1, false, true , String ],
17
+ [0x22, "SYBIMAGE" , "image" , -4, -1, -1, false, false, String ],
18
+ [0x7a, "SYBMONEY4" , "smallmoney" , 4, 10, 12, true , false, Integer ],
19
+ [0x3c, "SYBMONEY" , "money" , 8, 19, 21, true , false, Integer ],
20
+ [0x31, "SYBDATETIME4" , "smalldatetime" , 4, 16, 19, false, false, Time ],
21
+ [0x3b, "SYBREAL" , "real" , 4, 7, 14, true , false, Integer ],
22
+ [0x2d, "SYBBINARY" , "binary" , -1, -1, 2, false, false, String ],
23
+ [0x1f, "SYBVOID" , "void" , -1, 1, 1, false, false, nil ],
24
+ [0x25, "SYBVARBINARY" , "varbinary" , -1, -1, -1, false, false, String ],
25
+ [0xa7, "SYBNVARCHAR" , "nvarchar" , -1, -1, -1, false, false, String ],
26
+ [0x68, "SYBBITN" , "bit" , -1, 1, 1, false, false, Integer ],
27
+ [0x6c, "SYBNUMERIC" , "numeric" , -1, -1, -1, true , false, Integer ],
28
+ [0x61, "SYBDECIMAL" , "decimal" , -1, -1, -1, true , false, Integer ],
29
+ [0x6d, "SYBFLTN" , "float" , -1, 15, 24, true , false, Float ],
30
+ [0x6e, "SYBMONEYN" , "money" , -1, 19, 21, true , false, Integer ],
31
+ [0x6f, "SYBDATETIMN" , "datetime" , -1, 23, 23, false, false, Time ],
32
+ [0x31, "SYBDATE" , "date" , 4, 10, 10, false, false, Time ],
33
+ [0x33, "SYBTIME" , "time" , 4, 8, 8, false, false, Time ],
34
+ [0x7b, "SYBDATEN" , "date" , -1, 10, 10, false, false, Time ],
35
+ [0x93, "SYBTIMEN" , "time" , -1, 8, 8, false, false, Time ],
36
+ [0xaf, "XSYBCHAR" , "char" , -2, -1, -1, false, true , String ],
37
+ [0xa7, "XSYBVARCHAR" , "varchar" , -2, -1, -1, false, true , String ],
38
+ [0xe7, "XSYBNVARCHAR" , "nvarchar" , -2, -1, -1, false, true , String ],
39
+ [0xef, "XSYBNCHAR" , "nchar" , -2, -1, -1, false, true , String ],
40
+ [0xa5, "XSYBVARBINARY" , "varbinary" , -2, -1, -1, false, false, String ],
41
+ [0xad, "XSYBBINARY" , "binary" , -2, -1, -1, false, false, String ],
42
+ [0xe1, "SYBLONGBINARY" , "varbinary" , -5, -1, 2, false, false, String ],
43
+ [0x40, "SYBSINT1" , "tinyint" , 1, 2, 3, false, false, Integer ],
44
+ [0x41, "SYBUINT2" , "unsigned smallint", 2, 5, 6, false, false, Integer ],
45
+ [0x42, "SYBUINT4" , "unsigned int" , 4, 10, 11, false, false, Integer ],
46
+ [0x43, "SYBUINT8" , "unsigned bigint" , 8, 20, 20, false, false, Integer ],
47
+ [0x44, "SYBUINTN" , "unsigned int" , -1, 10, 11, true , false, Integer ],
48
+ [0x24, "SYBUNIQUE" , "uniqueidentifier" , -1, 36, 36, false, false, String ],
49
+ [0x62, "SYBVARIANT" , "sql_variant" , -5, 0, 8000, false, false, String ],
50
+ [0xbf, "SYBSINT8" , "bigint" , 8, 19, 20, true , false, Integer ],
51
+ [0xf1, "XML" , "xml" , -4, -1, -1, false, true , String ]
52
+ ]
53
+
54
+ NAMES = {}
55
+ RUBY_TYPES = {}
56
+ FIXED_LENGTHS = {}
57
+ SIGNED = {}
58
+
59
+ TYPES.each(){|type|
60
+ code = type[0]
61
+ name = type[1]
62
+ length = type[3]
63
+ signed = type[6]
64
+ ruby_type = type[8]
65
+
66
+ const_set(name,code)
67
+
68
+ NAMES[code] = name
69
+ FIXED_LENGTHS[code] = length
70
+ SIGNED[code] = signed
71
+ RUBY_TYPES[code] = ruby_type
72
+ }
73
+
74
+ def self.name(code)
75
+ NAMES[code]
76
+ end
77
+
78
+ def self.numeric?(code)
79
+ code == SYBNUMERIC || code == SYBDECIMAL
80
+ end
81
+
82
+ def self.fixed_length(code)
83
+ FIXED_LENGTHS[code]
84
+ end
85
+
86
+ def self.signed?(code)
87
+ SIGNED[code]
88
+ end
89
+
90
+ def self.ruby_type(code)
91
+ RUBY_TYPES[code]
92
+ end
93
+ end
94
+ end
data/syspy.rb ADDED
@@ -0,0 +1,63 @@
1
+ require "rubygems"
2
+ require "lib/log"
3
+ require "lib/tds_package_stream"
4
+ require "time"
5
+
6
+
7
+ module Syspy
8
+ if(__FILE__ == $0)
9
+ if(ARGV.size != 3)
10
+ puts "Usage: sudo ruby syspy.rb <interface> <destination_ip> <destination_port>"
11
+ exit(1)
12
+ end
13
+
14
+ if(`id -u`.strip != "0")
15
+ puts "Has to be run as root"
16
+ exit(2)
17
+ end
18
+
19
+ INTERFACE = ARGV[0]
20
+ DST = ARGV[1]
21
+ DST_PORT = ARGV[2]
22
+
23
+ # INTERFACE = "eth0"
24
+ # DST = "192.168.1.6"
25
+ # DST_PORT = "2048"
26
+
27
+ stream = TdsPackageStream.new(INTERFACE,DST,DST_PORT)
28
+ stream.each_package(){|package|
29
+ if(package.instance_of?(TdsLanguage))
30
+ statement = package.language_text
31
+ replaced_statement = "#{statement}"
32
+
33
+ index = 0
34
+ if(package.tds_params)
35
+ params = package.tds_params.parameters
36
+ statement.scan(/@sql\d+[^ ]+/){|match|
37
+ param = params[index]
38
+ if(param.instance_of?(String))
39
+ replaced_statement.gsub!(match,"\"#{param}\"")
40
+ elsif(param.kind_of?(Numeric))
41
+ replaced_statement.gsub!(match,param.to_s)
42
+ elsif(param.instance_of?(Time))
43
+ replaced_statement.gsub!(match,"\"#{param.strftime("%Y%m%d %H:%M:%S")}\"")
44
+ end
45
+ index += 1
46
+ }
47
+ end
48
+ Log.info("Replaced parameters: #{index}\n\n#{replaced_statement.gsub("\n","\r\n")}\n------------------------------------------------------")
49
+ end
50
+ }
51
+ end
52
+ end
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syspy
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthias Balmer
@@ -40,6 +40,17 @@ extensions: []
40
40
  extra_rdoc_files: []
41
41
 
42
42
  files:
43
+ - syspy.rb
44
+ - lib/bytes.rb
45
+ - lib/tds_types.rb
46
+ - lib/tds_tokens.rb
47
+ - lib/tds_package_stream.rb
48
+ - lib/tds_packages/tds_paramfmt2.rb
49
+ - lib/tds_packages/tds_params.rb
50
+ - lib/tds_packages/tds_paramfmt.rb
51
+ - lib/tds_packages/tds_language.rb
52
+ - lib/log.rb
53
+ - lib/tds_package.rb
43
54
  - bin/syspy
44
55
  homepage:
45
56
  licenses: []