class Rbkb::Cli::Feed
Copyright 2009 emonti at moatasano dot com See README.rdoc for license information
This is a plug-board message feeder from static data sources. The “feed” handles messages opaquely and just plays them in the given sequence.
Feed
can do the following things with minimum fuss:
- Import messages from files, yaml, or pcap - Inject custom/modified messages with "blit" - Run as a server or client using UDP or TCP - Bootstrap protocols without a lot of work up front - Skip uninteresting messages and focus attention on the fun ones. - Replay conversations for relatively unfamiliar protocols. - Observe client/server behaviors using different messages at various phases of a conversation.
To-dos / Ideas:
- Unix Domain Socket support? - more import options? - dynamic feed elements? - add/control feed elements while 'stepping'?
Public Class Methods
new(*args)
click to toggle source
Calls superclass method
Rbkb::Cli::Executable::new
# File lib/rbkb/cli/feed.rb, line 31 def initialize(*args) @local_addr = "0.0.0.0" @local_port = nil @listen = false @persist = false @transport = :TCP @svr_method = :start_server @cli_method = :bind_connect @blit_addr = Plug::Blit::DEFAULT_IPADDR @blit_port = Plug::Blit::DEFAULT_PORT ## Default options sent to the Feed handler @feed_opts = { :close_at_end => false, :step => false, :go_first => false } super(*args) # TODO Plug::UI obviously need fixing. # TODO It shouldn't be driven by constants for configuration Plug::UI::LOGCFG[:verbose] = true Plug::UI::LOGCFG[:dump] = :hex Plug::UI::LOGCFG[:out] = @stderr end
Public Instance Methods
go(*args)
click to toggle source
Calls superclass method
Rbkb::Cli::Executable#go
# File lib/rbkb/cli/feed.rb, line 202 def go(*args) super(*args) Plug::UI.verbose "** FEED CONTAINS #{@feed_opts[:feed].size} MESSAGES" ## Start the eventmachine loop do EventMachine::run do EventMachine.send(*@em_args) do |c| EventMachine.start_server(@blit_addr, @blit_port, Plug::Blit, :TCP, c) Plug::UI::verbose("** BLITSRV-#{@blit_addr}:#{@blit_port}(TCP) Started") # if this is a UDP client, we will always send the first message if [:UDP, :client] == [@transport, c.kind] peer = c.peers.add_peer_manually(@target_addr, @target_port) c.feed_data(peer) c.go_first = false end end end break unless @persist Plug::UI::verbose("** RECONNECTING") end end
make_parser()
click to toggle source
Calls superclass method
Rbkb::Cli::Executable#make_parser
# File lib/rbkb/cli/feed.rb, line 59 def make_parser() arg = super() arg.banner += " host:port" arg.on("-o", "--output=FILE", "Output to file") do |o| Plug::UI::LOGCFG[:out] = File.open(o, "w") end arg.on("-l", "--listen=(ADDR:?)PORT", "Server - on port (and addr?)") do |p| if m=/^(?:([\w\._-]+):)?(\d+)$/.match(p) @local_addr = $1 if $1 @local_port = $2.to_i @listen = true else raise "Invalid listen argument: #{p.inspect}" end end arg.on("-s", "--source=(ADDR:?)PORT", "Bind client on port and addr") do |p| if m=/^(?:([\w\.]+):)?(\d+)$/.match(p) @local_addr = $1 if $1 @local_port = $2.to_i else bail("Invalid source argument: #{p.inspect}") end end arg.on("-b", "--blit=(ADDR:)?PORT", "Where to listen for blit") do |b| puts b unless(m=/^(?:([\w\._-]+):)?(\d+)$/.match(b)) raise "Invalid blit argument: #{b.inspect}" end @blit_port = m[2].to_i @blit_addr = m[1] if m[1] end arg.on("-i", "--[no-]initiate", "Send the first message on connect") do |i| @feed_opts[:go_first] = i end arg.on("-e", "--[no-]end", "End connection when feed is exhausted") do |c| @feed_opts[:close_at_end] = c end arg.on("--[no-]step", "'Continue' prompt between messages") do |s| @feed_opts[:step] = s end arg.on("-u", "--udp", "Use UDP instead of TCP" ) do @transport = :UDP end arg.on("-r", "--reconnect", "Attempt to reconnect endlessly.") do @persist=true end arg.on("-q", "--quiet", "Suppress verbose messages/dumps") do Plug::UI::LOGCFG[:verbose] = false end arg.on("-Q", "--squelch-exhausted", "Squelch 'FEED EXHAUSTED' messages") do |s| @feed_opts[:squelch_exhausted] = true end arg.separator " Sources: (can be combined)" arg.on("-f", "--from-files=GLOB", "Import messages from raw files") do |f| @feed_opts[:feed] ||= [] @feed_opts[:feed] += FeedImport.import_rawfiles(f) end arg.on("-x", "--from-hex=FILE", "Import messages from hexdumps") do |x| @feed_opts[:feed] ||= [] @feed_opts[:feed] += FeedImport.import_dump(x) end arg.on("-y", "--from-yaml=FILE", "Import messages from yaml") do |y| @feed_opts[:feed] ||= [] @feed_opts[:feed] += FeedImport.import_yaml(y) end arg.on("-p", "--from-pcap=FILE[:FILTER]", "Import messages from pcap") do |p| if /^([^:]+):(.+)$/.match(p) file = $1 filter = $2 else file = p filter = nil end @feed_opts[:feed] ||= [] @feed_opts[:feed] += FeedImport.import_pcap(file, filter) end end
parse(*args)
click to toggle source
Calls superclass method
Rbkb::Cli::Executable#parse
# File lib/rbkb/cli/feed.rb, line 154 def parse(*args) super(*args) if @transport == :UDP @svr_method = @cli_method = :open_datagram_socket end @local_port ||= 0 # Prepare EventMachine arguments based on whether we are a client or server if @listen # server @meth = @svr_method addr_args = [@local_addr, @local_port] @feed_opts[:kind] = :server @feed_opts[:no_stop_on_unbind] = true else # client ## Get target/listen argument for client mode unless (m = /^([\w\.]+):(\d+)$/.match(tgt=@argv.shift)) bail_args tgt end @target_addr = m[1] @target_port = m[2].to_i if @transport == :UDP addr_args = [@local_addr, @local_port] else addr_args = [@local_addr, @local_port, @target_addr, @target_port] end @meth = @cli_method @feed_opts[:kind] = :client end @feed_opts[:feed] ||= [] @em_args=[ @meth, addr_args, Plug::ArrayFeeder, @transport, @feed_opts ].flatten parse_catchall() end