Forum: Ruby Re: libnet binding for ruby

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-02-04 23:35
(Received via mailing list)
Dave King 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] http://redshift.sourceforge.net/bit-struct
    http://redshift.sourceforge.net/bit-struct/doc/index.html
This topic is locked and can not be replied to.