Ben N. wrote:
I don’t know what arguments it needs.
Has anyone done this before, for any protocol? Oh, and to save time, I
don’t want to use libnet or rubyforger or *random-lib-someone-wrote.
Hi, Ben,
Just use #send. It’s documented in the BasicSocket part of the appendix
in the PickAxe.
I think it’s platform dependent how much of the IP header gets filled in
for you (for example, the checksum is calculated by linux, but not IIRC
by QNX). On linux, man 7 raw will tell you:
+---------------------------------------------------+
|IP Header fields modified on sending by IP_HDRINCL |
+----------------------+----------------------------+
|IP Checksum |Always filled in. |
+----------------------+----------------------------+
|Source Address |Filled in when zero. |
+----------------------+----------------------------+
|Packet Id |Filled in when zero. |
+----------------------+----------------------------+
|Total Length |Always filled in. |
+----------------------+----------------------------+
Here’s an example from the bit-struct examples dir, but BitStruct is
only used to construct the packet, not open the socket or send the
packet. The example has two threads, a sender and a receiver.
$ cat raw.rb
require “socket”
require “./ip”
A more substantial example of sending and receiving RAW packets.
begin
rsock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW,
Socket::IPPROTO_RAW)
rescue Errno::EPERM
$stderr.puts “Must run #{$0} as root.”
exit!
end
begin
ssock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW,
Socket::IPPROTO_RAW)
unless ssock.getsockopt(Socket::SOL_IP, Socket::IP_HDRINCL)
puts “IP_HDRINCL is supposed to be the default for IPPROTO_RAW!”
puts “setting IP_HDRINCL anyway”
ssock.setsockopt(Socket::SOL_IP, Socket::IP_HDRINCL, true)
end
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)
out = “-”*80,
“packet received from #{host}:#{port}:”,
IP.new(data).inspect_detailed,
“-”*80
puts out
$stdout.flush
end
end
addr = Socket.pack_sockaddr_in(1024, “localhost”)
3.times do |i|
ip = IP.new do |b|
# ip_v and ip_hl are set for us by IP class
b.ip_tos = 0
b.ip_id = i+1
b.ip_off = 0
b.ip_ttl = 64
b.ip_p = Socket::IPPROTO_RAW
b.ip_src = “127.0.0.1”
b.ip_dst = “127.0.0.1”
b.body = “just another IP hacker”
b.ip_len = b.length
b.ip_sum = 0 # linux will calculate this for us (QNX won’t?)
end
out = “-”*80,
“packet sent:”,
ip.inspect_detailed,
“-”*80
puts out
$stdout.flush
ssock.send(ip, 0, addr)
sleep 1
end
$ su
Password:
ruby raw.rb
packet sent:
IP:
Version = 4
Header length = 5
TOS = 0
Length = 42
ID = 1
Frag offset = 0
TTL = 64
Protocol = 255
Checksum = 0
Source addr = “127.0.0.1”
Dest addr = “127.0.0.1”
Body of message = “just another IP hacker”
packet received from 127.0.0.1:0:
IP:
Version = 4
Header length = 5
TOS = 0
Length = 42
ID = 1
Frag offset = 0
TTL = 64
Protocol = 255
Checksum = 31698
Source addr = “127.0.0.1”
Dest addr = “127.0.0.1”
Body of message = “just another IP hacker”