Wednesday, June 25, 2008

BitStruct is great

If you code in Ruby and do any binary parsing then you need to be using BitStruct. It makes C style structs in Ruby very easy. Sometimes you have to sniff a custom binary protocol the quick and dirty way, these are times I turn to Ruby instead of C. The Bitstruct release has some good examples of parsing network protocols but using raw sockets in Ruby is ugly. I prefer to use the LibPcap wrappers instead for the awesomeness of pcap filters.
require 'pcaplet'
require 'bit-struct'

# Fake protocol I made up for this example
class CustomProtocol < BitStruct
char :header, 64, :endian => :native
unsigned :length, 8, :endian => :native
unsigned :next_hdr, 16, :endian => :little
unsigned :next_tag, 16, :endian => :network
unsigned :type, 32, :endian => :native
rest :data
end

# Capture up to 1533 bytes
sniff = Pcaplet.new('-s 1533')

# Specific pcap filter so we only grab the protocol we are dissecting
pcap_filter = Pcap::Filter.new('tcp && port 34504 && src 192.168.1.10', sniff.capture)

sniff.add_filter(pcap_filter)

for pkt in sniff
if pcap_filter =~ pkt
puts pkt
struct = CustomProtocol.new(pkt.tcp_data)
puts sprintf("ASCII Header: %s\tLength: %x\tNext Hdr: %x\tNext Tag: %x\tType: %x\tData: %s",
struct.header, struct.length, struct.next_hdr, struct.next_tag, struct.type, struct.data)
end
end

3 comments:

Anonymous said...

Neat! Looks similar in construct to its Python equivalent, dpkt:

http://code.google.com/p/dpkt/

Example of ARP module:

http://code.google.com/p/dpkt/source/browse/trunk/dpkt/arp.py

Anonymous said...

I used a lot of bit-struct early. But I kept bumping my head against variable length fields.

I ended up moving to BinData for lots of things. It's much further along in this regard.

http://bindata.rubyforge.org/

Anonymous said...

http://kenai.com/projects/ruby-ffi is usefull too