emonti-rbkb 0.6.2.1 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +10 -7
  3. data/Rakefile +47 -0
  4. data/bin/feed +5 -0
  5. data/bin/plugsrv +3 -3
  6. data/cli_usage.rdoc +44 -9
  7. data/doctor-bag.jpg +0 -0
  8. data/lib/rbkb.rb +47 -2
  9. data/lib/rbkb/cli.rb +8 -6
  10. data/lib/rbkb/cli/b64.rb +5 -0
  11. data/lib/rbkb/cli/bgrep.rb +14 -9
  12. data/lib/rbkb/cli/chars.rb +2 -1
  13. data/lib/rbkb/cli/crc32.rb +4 -1
  14. data/lib/rbkb/cli/d64.rb +3 -0
  15. data/lib/rbkb/cli/dedump.rb +5 -3
  16. data/lib/rbkb/cli/feed.rb +223 -0
  17. data/lib/rbkb/cli/hexify.rb +3 -3
  18. data/lib/rbkb/cli/len.rb +12 -9
  19. data/lib/rbkb/cli/rstrings.rb +13 -10
  20. data/lib/rbkb/cli/slice.rb +1 -0
  21. data/lib/rbkb/cli/telson.rb +21 -57
  22. data/lib/rbkb/cli/unhexify.rb +2 -6
  23. data/lib/rbkb/cli/urldec.rb +1 -0
  24. data/lib/rbkb/cli/urlenc.rb +1 -0
  25. data/lib/rbkb/extends.rb +41 -6
  26. data/lib/rbkb/http.rb +20 -0
  27. data/lib/rbkb/http/base.rb +172 -0
  28. data/lib/rbkb/http/body.rb +214 -0
  29. data/lib/rbkb/http/common.rb +74 -0
  30. data/lib/rbkb/http/headers.rb +356 -0
  31. data/lib/rbkb/http/parameters.rb +101 -0
  32. data/lib/rbkb/http/request.rb +58 -0
  33. data/lib/rbkb/http/response.rb +86 -0
  34. data/lib/rbkb/plug.rb +3 -3
  35. data/lib/rbkb/plug/cli.rb +83 -0
  36. data/lib/rbkb/plug/feed_import.rb +74 -0
  37. data/lib/rbkb/plug/plug.rb +36 -19
  38. data/lib/rbkb/plug/unix_domain.rb +75 -0
  39. data/rbkb.gemspec +38 -0
  40. data/spec/rbkb_spec.rb +7 -0
  41. data/spec/spec_helper.rb +16 -0
  42. data/tasks/ann.rake +80 -0
  43. data/tasks/bones.rake +20 -0
  44. data/tasks/gem.rake +201 -0
  45. data/tasks/git.rake +40 -0
  46. data/tasks/notes.rake +27 -0
  47. data/tasks/post_load.rake +34 -0
  48. data/tasks/rdoc.rake +51 -0
  49. data/tasks/rubyforge.rake +55 -0
  50. data/tasks/setup.rb +292 -0
  51. data/tasks/spec.rake +54 -0
  52. data/tasks/svn.rake +47 -0
  53. data/tasks/test.rake +40 -0
  54. data/test/test_cli_b64.rb +35 -0
  55. data/test/test_cli_bgrep.rb +137 -0
  56. data/test/test_cli_blit.rb +11 -0
  57. data/test/test_cli_chars.rb +21 -0
  58. data/test/test_cli_crc32.rb +108 -0
  59. data/test/test_cli_d64.rb +22 -0
  60. data/test/test_cli_dedump.rb +118 -0
  61. data/test/test_cli_feed.rb +11 -0
  62. data/test/test_cli_helper.rb +96 -0
  63. data/test/test_cli_hexify.rb +63 -0
  64. data/test/test_cli_len.rb +96 -0
  65. data/test/test_cli_rstrings.rb +15 -0
  66. data/test/test_cli_slice.rb +73 -0
  67. data/test/test_cli_telson.rb +11 -0
  68. data/test/test_cli_unhexify.rb +43 -0
  69. data/test/test_cli_urldec.rb +50 -0
  70. data/test/test_cli_urlenc.rb +44 -0
  71. data/test/test_cli_xor.rb +71 -0
  72. data/test/test_helper.rb +5 -0
  73. data/test/test_http.rb +27 -0
  74. data/test/test_http_helper.rb +60 -0
  75. data/test/test_http_request.rb +136 -0
  76. data/test/test_http_response.rb +222 -0
  77. data/test/test_rbkb.rb +19 -0
  78. metadata +127 -21
data/lib/rbkb/cli/d64.rb CHANGED
@@ -8,12 +8,15 @@ class Rbkb::Cli::D64 < Rbkb::Cli::Executable
8
8
  def make_parser
9
9
  super()
10
10
  @oparse.banner += " <data | blank for stdin>"
11
+ add_std_file_opt(:indat)
11
12
  end
12
13
 
13
14
  def parse(*args)
14
15
  super(*args)
15
16
  parse_string_argument(:indat)
17
+ parse_file_argument(:indat)
16
18
  parse_catchall()
19
+ @opts[:indat] ||= @stdin.read
17
20
  end
18
21
 
19
22
  def go(*args)
@@ -7,8 +7,10 @@ require 'rbkb/cli'
7
7
  # by Unix utilities like 'xxd' as well as 'hexdump -C'.
8
8
  class Rbkb::Cli::Dedump < Rbkb::Cli::Executable
9
9
  def initialize(*args)
10
- super(*args)
11
- @opts[:len] ||= 16
10
+ super(*args) {|this|
11
+ this.opts[:len] ||= 16
12
+ yield this if block_given?
13
+ }
12
14
  end
13
15
 
14
16
  def make_parser()
@@ -16,7 +18,7 @@ class Rbkb::Cli::Dedump < Rbkb::Cli::Executable
16
18
  arg.banner += " <input-file | blank for stdin>"
17
19
 
18
20
  arg.on("-l", "--length LEN", Numeric,
19
- "Bytes per line in hexdump (default: #{@opts[:len]})") do |l|
21
+ "Bytes per line in hexdump (Default: #{@opts[:len]})") do |l|
20
22
  bail("Length must be greater than zero") unless (@opts[:len] = l) > 0
21
23
  end
22
24
  return arg
@@ -0,0 +1,223 @@
1
+ require 'rbkb/cli'
2
+ require 'rbkb/plug'
3
+ require 'rbkb/plug/feed_import'
4
+ require 'eventmachine'
5
+
6
+ # Copyright 2009 emonti at moatasano dot com
7
+ # See README.rdoc for license information
8
+ #
9
+ # This is a plug-board message feeder from static data sources.
10
+ # The "feed" handles messages opaquely and just plays them in the given
11
+ # sequence.
12
+ #
13
+ # Feed can do the following things with minimum fuss:
14
+ # - Import messages from files, yaml, or pcap
15
+ # - Inject custom/modified messages with "blit"
16
+ # - Run as a server or client using UDP or TCP
17
+ # - Bootstrap protocols without a lot of work up front
18
+ # - Skip uninteresting messages and focus attention on the fun ones.
19
+ # - Replay conversations for relatively unfamiliar protocols.
20
+ # - Observe client/server behaviors using different messages at
21
+ # various phases of a conversation.
22
+ #
23
+ # To-dos / Ideas:
24
+ # - Unix Domain Socket support?
25
+ # - more import options?
26
+ # - dynamic feed elements?
27
+ # - add/control feed elements while 'stepping'?
28
+ #
29
+
30
+ class Rbkb::Cli::Feed < Rbkb::Cli::Executable
31
+ def initialize(*args)
32
+ @local_addr = "0.0.0.0"
33
+ @local_port = nil
34
+ @listen = false
35
+ @persist = false
36
+ @transport = :TCP
37
+ @svr_method = :start_server
38
+ @cli_method = :connect
39
+ @blit_addr = Plug::Blit::DEFAULT_IPADDR
40
+ @blit_port = Plug::Blit::DEFAULT_PORT
41
+
42
+
43
+ ## Default options sent to the Feed handler
44
+ @feed_opts = {
45
+ :close_at_end => false,
46
+ :step => false,
47
+ :go_first => false
48
+ }
49
+
50
+ super(*args)
51
+
52
+ # TODO Plug::UI obviously need fixing.
53
+ # TODO It shouldn't be driven by constants for configuration
54
+ Plug::UI::LOGCFG[:verbose] = true
55
+ Plug::UI::LOGCFG[:dump] = :hex
56
+ Plug::UI::LOGCFG[:out] = @stderr
57
+ end
58
+
59
+ def make_parser()
60
+ arg = super()
61
+ arg.banner += " host:port"
62
+
63
+ arg.on("-o", "--output=FILE", "Output to file") do |o|
64
+ Plug::UI::LOGCFG[:out] = File.open(o, "w")
65
+ end
66
+
67
+ arg.on("-l", "--listen=(ADDR:?)PORT", "Server - on port (and addr?)") do |p|
68
+ if m=/^(?:([\w\._-]+):)?(\d+)$/.match(p)
69
+ @local_addr = $1 if $1
70
+ @local_port = $2.to_i
71
+ @listen = true
72
+ else
73
+ raise "Invalid listen argument: #{p.inspect}"
74
+ end
75
+ end
76
+
77
+ arg.on("-b", "--blit=(ADDR:)?PORT", "Where to listen for blit") do |b|
78
+ puts b
79
+ unless(m=/^(?:([\w\._-]+):)?(\d+)$/.match(b))
80
+ raise "Invalid blit argument: #{b.inspect}"
81
+ end
82
+ @blit_port = m[2].to_i
83
+ @blit_addr = m[1] if m[1]
84
+ end
85
+
86
+ arg.on("-i", "--[no-]initiate", "Send the first message on connect") do |i|
87
+ @feed_opts[:go_first] = i
88
+ end
89
+
90
+ arg.on("-e", "--[no-]end", "End connection when feed is exhausted") do |c|
91
+ @feed_opts[:close_at_end] = c
92
+ end
93
+
94
+ arg.on("-s", "--[no-]step", "'Continue' prompt between messages") do |s|
95
+ @feed_opts[:step] = s
96
+ end
97
+
98
+ arg.on("-u", "--udp", "Use UDP instead of TCP" ) do
99
+ @transport = :UDP
100
+ end
101
+
102
+ arg.on("-r", "--reconnect", "Attempt to reconnect endlessly.") do
103
+ @persist=true
104
+ end
105
+
106
+ arg.on("-q", "--quiet", "Suppress verbose messages/dumps") do
107
+ Plug::UI::LOGCFG[:verbose] = false
108
+ end
109
+
110
+ arg.on("-Q", "--squelch-exhausted", "Squelch 'FEED EXHAUSTED' messages") do |s|
111
+ @feed_opts[:squelch_exhausted] = true
112
+ end
113
+
114
+ arg.separator " Sources: (can be combined)"
115
+
116
+ arg.on("-f", "--from-files=GLOB", "Import messages from raw files") do |f|
117
+ @feed_opts[:feed] ||= []
118
+ @feed_opts[:feed] += FeedImport.import_rawfiles(f)
119
+ end
120
+
121
+ arg.on("-x", "--from-hex=FILE", "Import messages from hexdumps") do |x|
122
+ @feed_opts[:feed] ||= []
123
+ @feed_opts[:feed] += FeedImport.import_dump(x)
124
+ end
125
+
126
+ arg.on("-y", "--from-yaml=FILE", "Import messages from yaml") do |y|
127
+ @feed_opts[:feed] ||= []
128
+ @feed_opts[:feed] += FeedImport.import_yaml(y)
129
+ end
130
+
131
+ arg.on("-p", "--from-pcap=FILE[:FILTER]", "Import messages from pcap") do |p|
132
+ if /^([^:]+):(.+)$/.match(p)
133
+ file = $1
134
+ filter = $2
135
+ else
136
+ file = p
137
+ filter = nil
138
+ end
139
+
140
+ @feed_opts[:feed] ||= []
141
+ @feed_opts[:feed] += FeedImport.import_pcap(file, filter)
142
+ end
143
+ end
144
+
145
+ def parse(*args)
146
+ super(*args)
147
+
148
+ if @transport == :UDP
149
+ @svr_method = @cli_method = :open_datagram_socket
150
+ end
151
+
152
+ # Prepare EventMachine arguments based on whether we are a client or server
153
+ if @listen
154
+ @evma_addr = @local_addr
155
+ @evma_port = @local_port
156
+ @meth = @svr_method
157
+ @feed_opts[:kind] = :server
158
+ @feed_opts[:no_stop_on_unbind] = true
159
+ else
160
+
161
+ ## Get target/listen argument for client mode
162
+ unless (m = /^([\w\.]+):(\d+)$/.match(tgt=@argv.shift))
163
+ bail_args tgt
164
+ end
165
+
166
+ @target_addr = m[1]
167
+ @target_port = m[2].to_i
168
+
169
+ if @transport == :UDP
170
+ @evma_addr = @local_addr
171
+ @evma_port = @local_port || 0
172
+ else
173
+ @evma_addr = @target_addr
174
+ @evma_port = @target_port
175
+ end
176
+
177
+ @meth = @cli_method
178
+ @feed_opts[:kind] = :client
179
+ end
180
+
181
+ @feed_opts[:feed] ||= []
182
+
183
+ @em_args=[
184
+ @meth,
185
+ @evma_addr,
186
+ @evma_port,
187
+ Plug::ArrayFeeder,
188
+ @transport,
189
+ @feed_opts
190
+ ].flatten
191
+
192
+ parse_catchall()
193
+ end
194
+
195
+
196
+ def go(*args)
197
+ super(*args)
198
+
199
+ Plug::UI.verbose "** FEED CONTAINS #{@feed_opts[:feed].size} MESSAGES"
200
+
201
+ ## Start the eventmachine
202
+ loop do
203
+ EventMachine::run do
204
+ EventMachine.send(*@em_args) do |c|
205
+ EventMachine.start_server(@blit_addr, @blit_port, Plug::Blit, :TCP, c)
206
+ Plug::UI::verbose("** BLITSRV-#{@blit_addr}:#{@blit_port}(TCP) Started")
207
+
208
+ # if this is a UDP client, we will always send the first message
209
+ if [:UDP, :client] == [@transport, c.kind]
210
+ peer = c.peers.add_peer_manually(@target_addr, @target_port)
211
+ c.feed_data(peer)
212
+ c.go_first = false
213
+ end
214
+ end
215
+ end
216
+
217
+ break unless @persist
218
+ Plug::UI::verbose("** RECONNECTING")
219
+ end
220
+
221
+ end
222
+ end
223
+
@@ -15,7 +15,7 @@ class Rbkb::Cli::Hexify < Rbkb::Cli::Executable
15
15
  arg.banner += " <data | blank for stdin>"
16
16
 
17
17
  arg.on("-l", "--length LEN", Numeric, "Output lines of LEN bytes") do |l|
18
- bail("Length must be greater than zero") unless (@opts[:len] = l) > 0
18
+ @opts[:len] = l
19
19
  end
20
20
 
21
21
  arg.on("-d", "--delim=DELIMITER", "DELIMITER between each byte") do |d|
@@ -51,9 +51,9 @@ class Rbkb::Cli::Hexify < Rbkb::Cli::Executable
51
51
  @opts[:indat] ||= @stdin.read()
52
52
 
53
53
  indat = @opts.delete(:indat)
54
- len = @opts.delete(:len)
54
+ len = (@opts.delete(:len) || indat.length)
55
55
 
56
- self.exit(1) unless((len ||= indat.length) > 0)
56
+ bail("Length must be greater than zero") unless(len > 0)
57
57
 
58
58
  until (m = indat.slice!(0..len-1)).empty?
59
59
  @stdout << m.hexify(@opts)
data/lib/rbkb/cli/len.rb CHANGED
@@ -2,23 +2,25 @@ require 'rbkb/cli'
2
2
 
3
3
  # Copyright 2009 emonti at matasano.com
4
4
  # See README.rdoc for license information
5
- #
5
+
6
6
  # len prepends a binary length number in front of its input and outputs
7
7
  # raw on STDOUT
8
8
  class Rbkb::Cli::Len < Rbkb::Cli::Executable
9
9
 
10
10
  def initialize(*args)
11
- super(*args)
12
-
13
11
  # endianness pair. index 0 is always the default
14
12
  @endpair = [:big, :little]
15
- {
16
- :nudge => 0,
17
- :size => 4,
18
- :endian => @endpair[0],
19
- }.each {|k,v| @opts[k] ||= v}
20
- end
21
13
 
14
+ super(*args) do |this|
15
+ {
16
+ :nudge => 0,
17
+ :size => 4,
18
+ :endian => @endpair[0],
19
+ }.each {|k,v| this.opts[k] ||= v}
20
+
21
+ yield this if block_given?
22
+ end
23
+ end
22
24
 
23
25
  def make_parser()
24
26
  super()
@@ -67,6 +69,7 @@ class Rbkb::Cli::Len < Rbkb::Cli::Executable
67
69
  len += @opts[:nudge]
68
70
  end
69
71
  @stdout << len.to_bytes(@opts[:endian], @opts[:size]) << @opts[:indat]
72
+ self.exit(0)
70
73
  end
71
74
 
72
75
  end
@@ -6,16 +6,19 @@ require 'rbkb/cli'
6
6
  # rstrings is Unix "strings" in ruby... with some extra stuff
7
7
  class Rbkb::Cli::Rstrings < Rbkb::Cli::Executable
8
8
  def initialize(*args)
9
- super(*args)
10
- {
11
- :start_off => 0,
12
- :end_off => -1,
13
- :encoding => :both,
14
- :minimum => 6,
15
- :align => nil,
16
- :indat => Array.new,
17
- :fnames => Array.new,
18
- }.each {|k,v| @opts[k] ||= v }
9
+ super(*args) do |this|
10
+ {
11
+ :start_off => 0,
12
+ :end_off => -1,
13
+ :encoding => :both,
14
+ :minimum => 6,
15
+ :align => nil,
16
+ :indat => Array.new,
17
+ :fnames => Array.new,
18
+ }.each {|k,v| this.opts[k] ||= v }
19
+
20
+ yield this if block_given?
21
+ end
19
22
  end
20
23
 
21
24
  def make_parser()
@@ -40,6 +40,7 @@ class Rbkb::Cli::Slice < Rbkb::Cli::Executable
40
40
  def go(*args)
41
41
  super(*args)
42
42
  @stdout << @opts[:indat][ @opts[:first] .. @opts[:last] ]
43
+ self.exit(0)
43
44
  end
44
45
 
45
46
  end
@@ -1,6 +1,4 @@
1
- require 'rbkb/cli'
2
- require 'rbkb/plug'
3
- require 'eventmachine'
1
+ require 'rbkb/plug/cli'
4
2
 
5
3
  # Copyright 2009 emonti at matasano.com
6
4
  # See README.rdoc for license information
@@ -14,48 +12,21 @@ require 'eventmachine'
14
12
  # - Observe client/server behaviors using different messages at
15
13
  # various phases of a conversation.
16
14
  #
17
- class Rbkb::Cli::Telson < Rbkb::Cli::Executable
15
+ class Rbkb::Cli::Telson < Rbkb::Cli::PlugCli
18
16
 
19
17
  def initialize(*args)
20
- super(*args)
21
- @b_addr = Plug::Blit::DEFAULT_IPADDR
22
- @b_port = Plug::Blit::DEFAULT_PORT
23
- @srced = @persist = false
24
- @s_addr = "0.0.0.0"
25
- @s_port = 0
26
- @proto = :TCP
27
-
28
- # XXX TODO Plug::UI obviously need fixing. It shouldn't be a module
29
- # with constants for configuration
30
- Plug::UI::LOGCFG[:verbose] = true
31
- Plug::UI::LOGCFG[:dump] = :hex
32
- Plug::UI::LOGCFG[:out] = @stderr
18
+ super(*args) do |this|
19
+ this.local_addr = "0.0.0.0"
20
+ this.local_port = 0
21
+ end
22
+
23
+ @srced = false
24
+ @persist = false
33
25
  end
34
26
 
35
27
 
36
28
  def make_parser()
37
29
  arg = super()
38
- arg.banner += " host:port"
39
-
40
- arg.on("-u", "--udp", "UDP mode") do
41
- @proto=:UDP
42
- end
43
-
44
- arg.on("-b", "--blit=ADDR:PORT", "Where to listen for blit") do |b|
45
- unless m=/^(?:([\w\.]+):)?(\d+)$/.match(b)
46
- bail("Invalid blit address/port")
47
- end
48
- @b_port = m[2].to_i
49
- @b_addr = m[1] if m[1]
50
- end
51
-
52
- arg.on("-o", "--output=FILE", "Output to file instead of screen") do |f|
53
- Plug::UI::LOGCFG[:out] = File.open(f, "w") # XXX
54
- end
55
-
56
- arg.on("-q", "--quiet", "Turn off verbose logging") do
57
- Plug::UI::LOGCFG[:verbose] = false # XXX
58
- end
59
30
 
60
31
  arg.on("-r", "--reconnect", "Attempt to reconnect endlessly.") do
61
32
  @persist=true
@@ -63,8 +34,8 @@ class Rbkb::Cli::Telson < Rbkb::Cli::Executable
63
34
 
64
35
  arg.on("-s", "--source=(ADDR:?)PORT", "Bind on port (and addr?)") do |p|
65
36
  if m=/^(?:([\w\.]+):)?(\d+)$/.match(p)
66
- @s_addr = $1 if $1
67
- @s_port = $2.to_i
37
+ @local_addr = $1 if $1
38
+ @local_port = $2.to_i
68
39
  @srced = true
69
40
  else
70
41
  bail("Invalid listen argument: #{p.inspect}")
@@ -76,13 +47,8 @@ class Rbkb::Cli::Telson < Rbkb::Cli::Executable
76
47
  def parse(*args)
77
48
  super(*args)
78
49
 
79
- # Get target argument
80
- unless (m = /^([\w\.]+):(\d+)$/.match(@argv.shift)) and @argv.shift.nil?
81
- bail "Invalid target #{arg}"
82
- end
83
-
84
- @t_addr = m[1]
85
- @t_port = m[2].to_i
50
+ parse_target_argument()
51
+ parse_catchall()
86
52
  end
87
53
 
88
54
 
@@ -91,24 +57,22 @@ class Rbkb::Cli::Telson < Rbkb::Cli::Executable
91
57
 
92
58
  loop do
93
59
  EventMachine.run {
94
- if @proto == :TCP
60
+ if @transport == :TCP
95
61
  bail("Sorry: --source only works with UDP.") if @srced
96
62
 
97
- c=EventMachine.connect(@t_addr, @t_port, Plug::Telson, @proto)
63
+ c=EventMachine.connect(@target_addr, @target_port, Plug::Telson, @transport, @plug_opts)
98
64
 
99
- elsif @proto == :UDP
100
- c=EventMachine.open_datagram_socket(
101
- @s_addr, @s_port, Plug::Telson, @proto
102
- )
103
- c.peers.add_peer_manually(@t_addr, @t_port)
65
+ elsif @transport == :UDP
66
+ c=EventMachine.open_datagram_socket( @local_addr, @local_port, Plug::Telson, @transport, @plug_opts)
67
+ c.peers.add_peer_manually(@target_addr, @target_port)
104
68
 
105
69
  ### someday maybe raw or others?
106
70
  else
107
- raise "bad protocol"
71
+ raise "bad transport protocol"
108
72
  end
109
73
 
110
- EventMachine.start_server(@b_addr, @b_port, Plug::Blit, :TCP, c)
111
- Plug::UI::verbose("** BLITSRV-#{@b_addr}:#{@b_port}(TCP) Started") # XXX
74
+ EventMachine.start_server(@blit_addr, @blit_port, Plug::Blit, @blit_proto, c)
75
+ Plug::UI::verbose("** BLITSRV-#{@blit_addr}:#{@blit_port}(TCP) Started") # XXX
112
76
  }
113
77
  break unless @persist
114
78
  Plug::UI::verbose("** RECONNECTING") # XXX