rbkb 0.6.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/History.txt +74 -0
  2. data/README.rdoc +149 -0
  3. data/Rakefile +47 -0
  4. data/bin/b64 +5 -0
  5. data/bin/bgrep +5 -0
  6. data/bin/blit +5 -0
  7. data/bin/c +5 -0
  8. data/bin/crc32 +5 -0
  9. data/bin/d64 +5 -0
  10. data/bin/dedump +5 -0
  11. data/bin/feed +5 -0
  12. data/bin/hexify +5 -0
  13. data/bin/len +5 -0
  14. data/bin/plugsrv +271 -0
  15. data/bin/rex +10 -0
  16. data/bin/rstrings +5 -0
  17. data/bin/slice +5 -0
  18. data/bin/telson +5 -0
  19. data/bin/unhexify +5 -0
  20. data/bin/urldec +5 -0
  21. data/bin/urlenc +5 -0
  22. data/bin/xor +5 -0
  23. data/cli_usage.rdoc +285 -0
  24. data/doctor-bag.jpg +0 -0
  25. data/lib/rbkb.rb +51 -0
  26. data/lib/rbkb/cli.rb +219 -0
  27. data/lib/rbkb/cli/b64.rb +35 -0
  28. data/lib/rbkb/cli/bgrep.rb +86 -0
  29. data/lib/rbkb/cli/blit.rb +89 -0
  30. data/lib/rbkb/cli/chars.rb +24 -0
  31. data/lib/rbkb/cli/crc32.rb +35 -0
  32. data/lib/rbkb/cli/d64.rb +28 -0
  33. data/lib/rbkb/cli/dedump.rb +52 -0
  34. data/lib/rbkb/cli/feed.rb +229 -0
  35. data/lib/rbkb/cli/hexify.rb +65 -0
  36. data/lib/rbkb/cli/len.rb +76 -0
  37. data/lib/rbkb/cli/rstrings.rb +108 -0
  38. data/lib/rbkb/cli/slice.rb +47 -0
  39. data/lib/rbkb/cli/telson.rb +87 -0
  40. data/lib/rbkb/cli/unhexify.rb +50 -0
  41. data/lib/rbkb/cli/urldec.rb +35 -0
  42. data/lib/rbkb/cli/urlenc.rb +35 -0
  43. data/lib/rbkb/cli/xor.rb +43 -0
  44. data/lib/rbkb/extends.rb +725 -0
  45. data/lib/rbkb/http.rb +21 -0
  46. data/lib/rbkb/http/base.rb +172 -0
  47. data/lib/rbkb/http/body.rb +214 -0
  48. data/lib/rbkb/http/common.rb +74 -0
  49. data/lib/rbkb/http/headers.rb +370 -0
  50. data/lib/rbkb/http/parameters.rb +104 -0
  51. data/lib/rbkb/http/request.rb +58 -0
  52. data/lib/rbkb/http/response.rb +86 -0
  53. data/lib/rbkb/plug.rb +9 -0
  54. data/lib/rbkb/plug/blit.rb +222 -0
  55. data/lib/rbkb/plug/cli.rb +83 -0
  56. data/lib/rbkb/plug/feed_import.rb +74 -0
  57. data/lib/rbkb/plug/peer.rb +67 -0
  58. data/lib/rbkb/plug/plug.rb +215 -0
  59. data/lib/rbkb/plug/proxy.rb +26 -0
  60. data/lib/rbkb/plug/unix_domain.rb +75 -0
  61. data/lib_usage.rdoc +176 -0
  62. data/rbkb.gemspec +38 -0
  63. data/spec/rbkb_spec.rb +7 -0
  64. data/spec/spec_helper.rb +16 -0
  65. data/tasks/ann.rake +80 -0
  66. data/tasks/bones.rake +20 -0
  67. data/tasks/gem.rake +201 -0
  68. data/tasks/git.rake +40 -0
  69. data/tasks/notes.rake +27 -0
  70. data/tasks/post_load.rake +34 -0
  71. data/tasks/rdoc.rake +51 -0
  72. data/tasks/rubyforge.rake +55 -0
  73. data/tasks/setup.rb +292 -0
  74. data/tasks/spec.rake +54 -0
  75. data/tasks/svn.rake +47 -0
  76. data/tasks/test.rake +40 -0
  77. data/test/test_cli_b64.rb +35 -0
  78. data/test/test_cli_bgrep.rb +137 -0
  79. data/test/test_cli_blit.rb +11 -0
  80. data/test/test_cli_chars.rb +21 -0
  81. data/test/test_cli_crc32.rb +108 -0
  82. data/test/test_cli_d64.rb +22 -0
  83. data/test/test_cli_dedump.rb +118 -0
  84. data/test/test_cli_feed.rb +11 -0
  85. data/test/test_cli_helper.rb +96 -0
  86. data/test/test_cli_hexify.rb +63 -0
  87. data/test/test_cli_len.rb +96 -0
  88. data/test/test_cli_rstrings.rb +15 -0
  89. data/test/test_cli_slice.rb +73 -0
  90. data/test/test_cli_telson.rb +11 -0
  91. data/test/test_cli_unhexify.rb +43 -0
  92. data/test/test_cli_urldec.rb +50 -0
  93. data/test/test_cli_urlenc.rb +44 -0
  94. data/test/test_cli_xor.rb +71 -0
  95. data/test/test_helper.rb +5 -0
  96. data/test/test_http.rb +27 -0
  97. data/test/test_http_helper.rb +60 -0
  98. data/test/test_http_request.rb +136 -0
  99. data/test/test_http_response.rb +222 -0
  100. data/test/test_rbkb.rb +19 -0
  101. metadata +238 -0
@@ -0,0 +1,58 @@
1
+ module Rbkb::Http
2
+
3
+ # A Request encapsulates all the entities in a HTTP request message
4
+ # including the action header, general headers, and body.
5
+ class Request < Base
6
+ attr_accessor :action
7
+
8
+ alias first_entity action
9
+ alias first_entity= action=
10
+
11
+ def request_parameters
12
+ @action.parameters
13
+ end
14
+
15
+ # Returns a new Headers object extended as RequestHeaders. This is the
16
+ # default object which will be used when composing fresh Request header
17
+ # entities.
18
+ def default_headers_obj(*args)
19
+ Headers.new(*args).extend(RequestHeaders)
20
+ end
21
+
22
+ # Returns a new BoundBody object. This is the default object which will
23
+ # be used when composing fresh Request body entities.
24
+ def default_body_obj(*args)
25
+ Body.new(*args)
26
+ end
27
+
28
+ # Returns a raw HTTP request for this instance. The instance must have
29
+ # an action element defined at the bare minimum.
30
+ def to_raw(tmp_body=@body)
31
+ raise "this request has no action entity" unless first_entity()
32
+ self.headers ||= default_headers_obj()
33
+ self.body ||= default_body_obj()
34
+
35
+ if len=@opts[:static_length]
36
+ @body = Body.new(@body, @body.opts) {|x| x.base = self}
37
+ @headers.set_header("Content-Length", len.to_i)
38
+ elsif @opts[:ignore_content_length]
39
+ @headers.delete_header("Content-Length")
40
+ end
41
+
42
+ bstr = tmp_body.to_raw
43
+ hdrs = (@headers).to_raw_array.unshift(first_entity.to_raw)
44
+ return "#{hdrs.join("\r\n")}\r\n\r\n#{bstr}"
45
+ end
46
+
47
+
48
+ # Parses a raw HTTP request and captures data into the current instance.
49
+ def capture(str)
50
+ raise "arg 0 must be a string" unless String === str
51
+ hstr, bstr = str.split(/\s*\r?\n\r?\n/, 2)
52
+ capture_headers(hstr)
53
+ self.body = content_length ? BoundBody.new : Body.new
54
+ capture_body(bstr)
55
+ return self
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,86 @@
1
+
2
+ module Rbkb::Http
3
+ # A Response encapsulates all the entities in a HTTP response,
4
+ # including the status header, general headers, and body.
5
+ class Response < Base
6
+ attr_accessor :status
7
+
8
+ alias first_entity status
9
+ alias first_entity= status=
10
+
11
+ # Returns a raw HTTP response for this instance. Must have a status
12
+ # element defined at a bare minimum.
13
+ def to_raw(raw_body=nil)
14
+ raise "this response has no status" unless first_entity()
15
+ self.headers ||= default_headers_obj()
16
+ self.body = raw_body if raw_body
17
+
18
+ if do_chunked_encoding?(@headers)
19
+ unless @body.is_a? ChunkedBody
20
+ @body = ChunkedBody.new(@body, @body.opts)
21
+ end
22
+ @headers.delete_header("Content-Length")
23
+ elsif not opts[:ignore_content_length]
24
+ unless @body.is_a? BoundBody
25
+ @body = BoundBody.new(@body, @body.opts)
26
+ end
27
+ @headers.delete_header("Transfer-Encoding")
28
+ else
29
+ @body = Body.new(@body, @body.opts)
30
+ end
31
+ @body.base = self
32
+
33
+ yield(self) if block_given?
34
+
35
+ bstr = @body.to_raw
36
+ hdrs = @headers.to_raw_array.unshift(self.first_entity.to_raw)
37
+ return "#{hdrs.join("\r\n")}\r\n\r\n#{bstr}"
38
+ end
39
+
40
+ # Parses a raw HTTP response and captures data into the current instance.
41
+ def capture(str)
42
+ raise "arg 0 must be a string" unless String === str
43
+ hstr, bstr = str.split(/\s*\r?\n\r?\n/, 2)
44
+
45
+ capture_headers(hstr)
46
+
47
+ yield(self, bstr) if block_given?
48
+
49
+ unless @body and @body.capture_complete?
50
+ @body =
51
+ if do_chunked_encoding?
52
+ ChunkedBody.new {|b| b.base = self }
53
+ elsif content_length()
54
+ BoundBody.new {|b| b.base = self }
55
+ else
56
+ Body.new {|b| b.base = self }
57
+ end
58
+ end
59
+
60
+ capture_body(bstr)
61
+
62
+ return self
63
+ end
64
+
65
+ # Indicates whether to use chunked encoding based on presence of
66
+ # the "Transfer-Encoding: chunked" header or the :ignore_chunked_encoding
67
+ # opts parameter.
68
+ def do_chunked_encoding?(hdrs=@headers)
69
+ ( (not @opts[:ignore_chunked_encoding]) and
70
+ (hdrs.get_header_value("Transfer-Encoding").to_s =~ /(?:^|\W)chunked(?:\W|$)/) )
71
+ end
72
+
73
+ # Returns a new Headers object extended as ResponseHeaders. This is the
74
+ # default object which will be used when composing fresh Response header
75
+ # entities.
76
+ def default_headers_obj(*args)
77
+ Headers.new(*args).extend(ResponseHeaders)
78
+ end
79
+
80
+ # Returns a new BoundBody object. This is the default object which will
81
+ # be used when composing fresh Response body entities.
82
+ def default_body_obj(*args)
83
+ BoundBody.new(*args)
84
+ end
85
+ end
86
+ end
data/lib/rbkb/plug.rb ADDED
@@ -0,0 +1,9 @@
1
+ # Copyright 2009 emonti at matasano.com
2
+ # See README.rdoc for license information
3
+ #
4
+
5
+ require "rbkb"
6
+
7
+ require "rbkb/plug/plug"
8
+ require "rbkb/plug/blit"
9
+
@@ -0,0 +1,222 @@
1
+ # Copyright 2009 emonti at matasano.com
2
+ # See README.rdoc for license information
3
+ #
4
+ module Plug
5
+ module Blit
6
+ include Base
7
+
8
+ DEFAULT_IPADDR = "127.0.0.1"
9
+ DEFAULT_PORT = 25195
10
+ DEFAULT_PROTOCOL = :TCP
11
+
12
+ OPCODES = {
13
+ 0 => :squelch,
14
+ 1 => :unsquelch,
15
+ 2 => :delete,
16
+ 5 => :sendmsg,
17
+ 6 => :list_peers,
18
+
19
+ 0xfe => :clear,
20
+ 0xff => :kill,
21
+ }
22
+
23
+ attr_accessor :kind
24
+
25
+ def initialize(transport, slave)
26
+ super(transport)
27
+
28
+ @kind = :blitsrv
29
+ @slave = slave
30
+ @peers = slave.peers
31
+ initbuf
32
+ end
33
+
34
+ def post_init
35
+ # override so we don't get unneccessary "Start" message from Base
36
+ end
37
+
38
+ def unbind
39
+ # override so we don't get unneccessary "closed" message from Base
40
+ end
41
+
42
+
43
+ ### Blit protocol stuff
44
+ SIG = "BLT"
45
+
46
+ # (re)initializes the blit buffer
47
+ def initbuf
48
+ @buf = StringIO.new
49
+ end
50
+
51
+ def receive_data dat
52
+ return unless (@buf.write(dat) > SIG.size) or (@buf.pos > (SIG.size + 1))
53
+
54
+ @buf.rewind
55
+
56
+ return unless @buf.read(SIG.size) == SIG and
57
+ op = OPCODES[ @buf.read(1)[0] ]
58
+
59
+ initbuf if self.send(op)
60
+ end
61
+
62
+
63
+ def self.blit_header(op)
64
+ return nil unless opno = OPCODES.invert[op]
65
+ SIG + opno.chr
66
+ end
67
+
68
+ def mute
69
+ unless ( peerno=@buf.read(2) and peerno.size == 2 and
70
+ peer=@peers[peerno.dat_to_num(:big)] )
71
+
72
+ UI.log "** BLIT-ERROR(Malformed or missing peer for mute)"
73
+ return true
74
+ end
75
+ end
76
+
77
+ def self.make_mute(peerno)
78
+ self.blit_header(:squelch) +
79
+ peerno.to_bytes(:big, 2)
80
+ end
81
+
82
+ def unmute
83
+ unless ( peerno=@buf.read(2) and peerno.size == 2 and
84
+ peer=@peers[peerno.dat_to_num(:big)] )
85
+ UI.log "** BLIT-ERROR(Malformed or missing peer for unmute)"
86
+ return true
87
+ end
88
+ end
89
+
90
+ def self.make_squelch(peerno)
91
+ self.blit_header(:squelch) +
92
+ peerno.to_bytes(:big, 2)
93
+ end
94
+
95
+ def sendmsg
96
+ unless peerno=@buf.read(2) and peerno.size == 2 and
97
+ bufsiz=@buf.read(4) and bufsiz.size == 4
98
+ UI.log "** BLIT-ERROR(Malformed sendmsg)"
99
+ return true
100
+ end
101
+
102
+ peerno = peerno.dat_to_num(:big)
103
+ bufsiz = bufsiz.dat_to_num(:big)
104
+
105
+ if (rdat=@buf.read(bufsiz)).size == bufsiz
106
+ if peer=@peers[peerno]
107
+ peer.say(rdat, self)
108
+ return true
109
+ else
110
+ UI.log "** BLIT-ERROR(Invalid peer index #{peerno})"
111
+ return true
112
+ end
113
+ else
114
+ return nil
115
+ end
116
+ end
117
+
118
+ # Blit packed message format is (SUBJECT TO CHANGE):
119
+ # "BLT"
120
+ # char opcode
121
+ # uint16be idx = index of slave peer to send to
122
+ # uint32le size = length of data
123
+ # str data
124
+ def self.make_sendmsg(idx, dat)
125
+ self.blit_header(:sendmsg) +
126
+ idx.to_bytes(:big, 2) +
127
+ dat.size.to_bytes(:big, 4) +
128
+ dat
129
+ end
130
+
131
+ def kill
132
+ UI.log("** BLIT-KILL - Received shutdown command")
133
+ EM.stop
134
+ end
135
+
136
+ def self.make_kill(idx=nil)
137
+ self.blit_header(:kill)
138
+ end
139
+
140
+ def clear
141
+ @peers.each { |p| p.close }
142
+ @peers.replace []
143
+ end
144
+
145
+ def self.make_clear
146
+ self.blit_header(:clear)
147
+ end
148
+
149
+ def delete(peerno)
150
+ @peers.delete(peerno)
151
+ end
152
+
153
+ def self.make_delete(idx=0)
154
+ self.blit_header(:delete) +
155
+ idx.to_bytes(:big, 2)
156
+ end
157
+
158
+ def list_peers
159
+ UI.log("** BLIT-LISTPEERS - Received list peers command")
160
+
161
+ @peers.each_index {|i| UI.log "** #{i} - #{@peers[i].name}"}
162
+ UI.log("** BLIT-LISTPEERS-END - End of peer list")
163
+ end
164
+
165
+ def self.make_list_peers
166
+ self.blit_header(:list_peers)
167
+ end
168
+
169
+ #----------------------------------------------------------------------
170
+ # Convenience methods for blit clients
171
+ #----------------------------------------------------------------------
172
+
173
+ BLIT_HANDLERS = {
174
+ :TCP => lambda {|msg|
175
+ s=TCPSocket.new(@blit_addr, @blit_port)
176
+ wl=s.write(msg)
177
+ s.close
178
+ return wl
179
+ },
180
+ :UDP => lambda {|msg|
181
+ s=UDPSocket.new
182
+ wl=s.send( msg, 0, @blit_addr, @blit_port)
183
+ s.close
184
+ return wl
185
+ }
186
+ }
187
+
188
+ def self.blit_init(opts={})
189
+ @blit_addr = (opts[:addr] || DEFAULT_IPADDR)
190
+ @blit_port = (opts[:port] || DEFAULT_PORT)
191
+ proto = (opts[:protocol] || DEFAULT_PROTOCOL)
192
+ @blit_handler = BLIT_HANDLERS[ proto ]
193
+ raise "invalid blit transport protocol" unless @blit_handler
194
+ end
195
+
196
+ def self.initialized?
197
+ @blit_addr and @blit_port and @blit_handler
198
+ end
199
+
200
+ def self.blit_send(data, idx=0)
201
+ msg = make_sendmsg(idx, data)
202
+ blit_raw(msg)
203
+ end
204
+
205
+ def self.blit_raw(buf)
206
+ raise "use blit_init first!" unless self.initialized?
207
+ @blit_handler.call buf
208
+ end
209
+
210
+ end # of module Blit
211
+
212
+
213
+ end # of module Plug
214
+
215
+ class String
216
+ #----------------------------------------------------------------------
217
+ # A Blit sender convenience method for strings
218
+ def blit(idx=0)
219
+ raise "blit must be initialized with blit_init" unless Plug::Blit.initialized?
220
+ Plug::Blit.blit_send(self, idx)
221
+ end
222
+ end
@@ -0,0 +1,83 @@
1
+ require 'rbkb/cli'
2
+ require 'rbkb/plug'
3
+ require 'eventmachine'
4
+
5
+
6
+ # Copyright 2009 emonti at matasano.com
7
+ # See README.rdoc for license information
8
+ #
9
+ module Rbkb::Cli
10
+
11
+ # Rbkb::Cli::Executable is an abstract class for creating command line
12
+ # executables using the Ruby Black Bag framework.
13
+ class PlugCli < Executable
14
+ RX_HOST_AND_PORT = /^([\w\._-]+):(\d+)$/
15
+ RX_PORT_OPT_ADDR = /^(?:([\w\._-]+):)?(\d+)$/
16
+
17
+ attr_accessor :blit_addr, :blit_port, :blit_proto,
18
+ :local_addr, :local_port, :transport,
19
+ :target_addr, :target_port, :plug_opts
20
+
21
+ def initialize(*args)
22
+ super(*args) do |this|
23
+ this.blit_addr ||= Plug::Blit::DEFAULT_IPADDR
24
+ this.blit_port ||= Plug::Blit::DEFAULT_PORT
25
+ this.transport ||= :TCP
26
+ this.plug_opts ||= {}
27
+ yield this if block_given?
28
+ end
29
+
30
+ # TODO Plug::UI obviously need fixing.
31
+ # TODO It shouldn't be driven by constants for configuration
32
+ Plug::UI::LOGCFG[:verbose] = true
33
+ Plug::UI::LOGCFG[:dump] = :hex
34
+ Plug::UI::LOGCFG[:out] = @stderr
35
+ end
36
+
37
+ def make_parser()
38
+ arg = super()
39
+ arg.banner << " host:port"
40
+
41
+ arg.on("-o", "--output=FILE", "Output to file") do |o|
42
+ Plug::UI::LOGCFG[:out] = File.open(o, "w") # XXX
43
+ end
44
+
45
+ arg.on("-q", "--quiet", "Turn off verbose logging") do
46
+ Plug::UI::LOGCFG[:verbose] = false # XXX
47
+ end
48
+
49
+ arg.on("-d", "--dump-format=hex/raw",
50
+ "Output conversations in hexdump or raw") do |d|
51
+ if m=/^(hex|raw)$/i.match(d)
52
+ Plug::UI::LOGCFG[:dump] = m[1].downcase.to_sym # XXX
53
+ else
54
+ bail "Invalid dump format: #{d.inspect}"
55
+ end
56
+ end
57
+
58
+ arg.on("-b", "--blit=ADDR:PORT", "Where to listen for blit") do |b|
59
+ unless m=RX_PORT_OPT_ADDR.match(b)
60
+ bail("Invalid blit address/port")
61
+ end
62
+ @blit_port = m[2].to_i
63
+ @blit_addr = m[1] if m[1]
64
+ end
65
+
66
+ arg.on("-u", "--udp", "UDP mode") { @transport=:UDP }
67
+
68
+ arg.on("-S", "--start-tls", "Initiate TLS") {|s| @plug_opts[:tls]=true }
69
+
70
+ return arg
71
+ end
72
+
73
+ def parse_target_argument()
74
+ unless (m = RX_HOST_AND_PORT.match(tgt=@argv.shift))
75
+ bail "Invalid target: #{tgt}\n Hint: use -h"
76
+ end
77
+ @target_addr = m[1]
78
+ @target_port = m[2].to_i
79
+ return m
80
+ end
81
+ end
82
+ end
83
+