emonti-rbkb 0.6.2.1 → 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
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