Re: libnet binding for ruby

Dave K. wrote:

I was hoping to be able to build raw packets in ruby. I’ve found and
have a working pcap binding. Is there a working libnet binding out there?

I don’t know libnet (except what I just read on the website) but if you
just want to fill in raw IP packets and send them, you can do that in
ruby with the socket lib and with Array#pack.

I wrote an object-oriented wrapper around #pack and #unpack called
bit-struct[1]. It lets you define packet structure and construct packets
like so:

=== ip.rb ===
require ‘bit-struct’

class IP < BitStruct
unsigned :ip_v, 4, “Version”
unsigned :ip_hl, 4, “Header length”
unsigned :ip_tos, 8, “TOS”
unsigned :ip_len, 16, “Length”
unsigned :ip_id, 16, “ID”
unsigned :ip_off, 16, “Frag offset”
unsigned :ip_ttl, 8, “TTL”
unsigned :ip_p, 8, “Protocol”
unsigned :ip_sum, 16, “Checksum”
octets :ip_src, 32, “Source addr”
octets :ip_dst, 32, “Dest addr”
rest :body, “Body of message”

note " rest is application defined message body"

initial_value.ip_v = 4
initial_value.ip_hl = 5
end

ip = IP.new
ip.ip_tos = 0
ip.ip_len = 0
ip.ip_id = 0
ip.ip_off = 0
ip.ip_ttl = 255
ip.ip_p = 255
ip.ip_sum = 0
ip.ip_src = “192.168.1.4”
ip.ip_dst = “192.168.1.255”
ip.body = “This is the payload text.”
ip.ip_len = ip.length

And here is some code to receive ping (ICMP) packets using a raw IP
socket. Sending would be similar.

=== ping-recv.rb ===
require “socket”
require “./ip” # the file above

Example of using the IP class to receive ping (ICMP) messages.

begin
rsock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW,
Socket::IPPROTO_ICMP)
rescue Errno::EPERM
$stderr.puts “Must run #{$0} as root.”
exit!
end

Thread.new do
loop do
data, sender = rsock.recvfrom(8192)
port, host = Socket.unpack_sockaddr_in(sender)
puts “-”*80,
“packet received from #{host}:#{port}:”,
IP.new(data).inspect_detailed,
“-”*80
$stdout.flush
end
end

system “ping 127.0.0.1”

Sample output:

64 bytes from 127.0.0.1: icmp_seq=8 ttl=64 time=0.045 ms

packet received from 127.0.0.1:62400:
IP:
Version = 4
Header length = 5
TOS = 0
Length = 84
ID = 41868
Frag offset = 0
TTL = 64
Protocol = 1
Checksum = 55578
Source addr = “127.0.0.1”
Dest addr = “127.0.0.1”
Body of message =
“\000\000n\030/<\000\010\365*\345C\2301\005\000\010\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\e\034\035\036\037
!"#$%&'()*+,-./01234567”
.
.
.

(One could of course define more fields, based on ICMP, to make this
body data more intelligible.)


[1] BitStruct
bit-struct