Exploring Network with Ruby : PCap/WinPCap, FFI pcap, ffi, packets, winpcap, hexdump, ethernet
- Purpose
- Installing libraries
- Listing network devices
- Listening raw packet
- Filtering
- Hexdump
- Ethernet frame structure
- Analyzing Ethernet Frame
Purpose
Since I got some times some overload in my lan wireless network, I want to see who and what traffic is in it, and take this task for exploring the OSI model …
Installing libraries
For Windows, install the winpcap library : this dll is use by common network tools like wireshark for listening packet over networks.
And get a Ruby binding : FFI-PCap installed with gem i ffi-pcap
. FFI is a nice library for use other language library.
Listing network devices
There are several methods for listing active network device : check methods in pry by :
cd FFI::PCap
ls
device_names
and dump_devices
just list actives devices use later for listening (FFI::PCap.device_names
in full).
Other methods like pcap_lookupnet
, pcap_findalldevs
take some unusual arguments in Ruby but common in C : pointers … (look at source pcap.rb in the gem for full description of parameters of each methods). The FFI library provide all the help.
Example for pcap_lookupnet
for the first device :
require 'ffi/pcap'
dev = FFI::PCap.device_names.first
netp = FFI::MemoryPointer.new(find_type(:bpf_uint32))
maskp = FFI::MemoryPointer.new(find_type(:bpf_uint32))
errbuf = FFI::PCap::ErrorBuffer.new
FFI::PCap.pcap_lookupnet dev, netp, maskp, errbuf
puts netp.get_array_of_uchar(0,4).join('.')
puts maskp.get_array_of_uchar(0,4).join('.')
Example for pcap_findalldevs
:
require 'ffi/pcap'
devices = FFI::MemoryPointer.new(:pointer)
errbuf = FFI::PCap::ErrorBuffer.new
FFI::PCap.pcap_findalldevs(devices, errbuf)
node = devices.get_pointer(0)
dev = FFI::PCap::Interface(node) # return a structure object for exploring :
dev.name
dev.description
dev.addresses
dev.addresses.addr
FFI::PCap.pcap_freealldevs(node)
Listening raw packet
We’ve got our active device, so let listen to packets :
require 'ffi/cap'
dev = FFI::PCap.device_names[1] # or another for you
pcap = FFI::PCap::Live.new(:dev => dev) # for this time, listening is active, as show with stats
pcap.stats
pcap.stats.ps_recv
pcap.datalink.describe
pakt = []
pcap.loop(:count => 1) do |this,pkt| # :count => -1 for infinite loop, break with .breakloop method
pakt << pkt
puts "#{pkt.time} :: #{pkt.len}"
pkt.body.each_byte {|x| print "%0.2x " % x }
putc "\n"
end
The first packet ! :)
Filtering
The filter is set before the loop. Start by the man page with lot of examples : http://www.manpagez.com/man/7/pcap-filter/
set_filter = "port 80" # simple filter
Now let’s look into this packet …
Hexdump
Start first with a better hexdump look with … Hexdump gem :) (gem i hexdump
) :
pcap.loop(count: 2){|t,p| Hexdump.dump(p.body);puts "\n";};
render :
00000000 33 33 00 00 00 0c 74 e5 43 82 96 a2 86 dd 60 00 |33....t.C.....`.|
00000010 00 00 00 9a 11 01 fe 80 00 00 00 00 00 00 1c 3e |...............>|
00000020 c1 df 18 3d 8d ea ff 02 00 00 00 00 00 00 00 00 |...=............|
...
Ethernet frame structure
We are on OSI level 2, so our ‘packet’ are in reality some ‘frame’ (packet denomination is for level 3 OSI) :check http://en.wikipedia.org/wiki/OSI_model#Examples.
| Destination MAC address | Source MAC address | Type/Length | User Data |
| :---------------------: | :----------------: | :---------: | :-------: |
| vendor / id | vendor / id | | |
| 3 / 3 | 3 / 3 | 2 | 46 - 1500 |
The list of vendor / organization can be found here http://anonsvn.wireshark.org/wireshark/trunk/manuf or here http://standards.ieee.org/develop/regauth/oui/oui.txt.
A short script to transform the wireshark database (saved as ./manuf) into a local YAML hash :
def create_manuf
ctr = {}
File.readlines("./manuf").each do |line|
line =~ /^([^\s]+)\s+([^#]+)(\s+#(.*))?$/
ctr[$1] = {:sh => ($2 ? $2.strip : $2), :lg => ($4 ? $4.strip : $4)}
end
File.open("./manuf.yaml", "w+"){|f| f.write(ctr.to_yaml)}
return ctr
end
ie ctr["00:00:0C"]
give a short and a long name of the constructor.
Nota: A destination MAC address of ff:ff:ff:ff:ff:ff
indicate a broadcast message from the source.
Analyzing Ethernet Frame
First get a full frame :
frame = ''
pcap.loop(count: 1){|t,p| frame = p.body}
And then initialize FFI::Packets::Eth :
eth = FFI::Packets::Eth.new raw: frame
and get the MAC source and destination adresse and the type :
puts eth.dump
eth.src
eth.lookup_etype
Nota : the ffi-packets gem need some adjustments (the gemspec isn’t complete), you can use my fork for the moment.
TweetNota 2 : read the source of ffi/dry, ffi/pcap and ffi/packets for better understanding the usage.
comments powered by Disqus