Joel VanderWerf
3/27/2005 9:01:00 PM
Sven C. Koehler wrote:
> Hello!
>
> I have captured the TCP/IP traffic of an application with tcpdump -w, and
> now I would like to read in the file to replay the traffic, can you
> advise any tools/libraries to do this? (preferably Ruby ones.) I work on
> a Linux box, the dump contains both TCP and UDP packets. I want to use
> Ruby here because I need to adjust some data of the dump when replaying.
I guess tcpdump -w writes raw packets, so you will need to send out the
same data as raw packets.
Here are some files to do that. Start with send.rb. Take out the
readline code. Add code to read each packet data as a string, and call
IP.new on it to get a packet, and then call send with the packet. The IP
methods will help with manipulating the packet data (in particular, you
can treat the whole packet as a string). The send-recv.rb file is nice
for debugging. Of course, all have to be run as root.
BTW, these three files are ruby prototypes for a library I am working on
to generate C code (and ruby wrappers) for doing similar things with raw
IP packets and packet options, esp. DSRC wireless options. I'll make it
available in a few weeks, probably.
require 'scanf'
# based on icmp.rb Copyright (C) 2000 GOTOU YUUZOU <gotoyuzo@notwork.org>
class IP < String
def self.new(s=nil); s ? super(s) : super("\0" * 20); end
def ip_v; (self[0] >> 4) & 0x0f; end
def ip_v=(v); self[0] = (v << 4) | (self[0] & 0x0f); end
def ip_hl; self[0] & 0xf end
def ip_hl=(v); self[0] = (self[0] & 0xf0) | (v & 0x0f); end
def ip_tos; self[1]; end
def ip_tos=(v); self[1] = v; end
def ip_len; self[2..3].unpack("n")[0]; end
def ip_len=(v); self[2..3]=[v].pack("n"); end
def ip_id; self[4..5].unpack("n")[0]; end
def ip_id=(v); self[4..5]=[v].pack("n"); end
def ip_off; self[6..7].unpack("n")[0]; end
def ip_off=(v); self[6..7]=[v].pack("n"); end
def ip_ttl; self[8]; end
def ip_ttl=(v); self[8]=v; end
def ip_p; self[9]; end
def ip_p=(v); self[9]=v; end
def ip_sum; self[10..11].unpack("n")[0]; end
def ip_sum=(v); self[10..11]=[v].pack("n"); end
def ip_src; "%d.%d.%d.%d" % [self[12], self[13], self[14], self[15]]; end
def ip_src=(s); self[12..15] = s.scanf("%d.%d.%d.%d").pack("c*"); end
def ip_dst; "%d.%d.%d.%d" % [self[16], self[17], self[18], self[19]]; end
def ip_dst=(s); self[16..19] = s.scanf("%d.%d.%d.%d").pack("c*"); end
def body; self[(ip_hl*4)..-1]; end
def body=(s); self[(ip_hl*4)..-1] = s; end
# def inspect; "<IP: size=#{size} src=#{ip_src} dst=#{ip_dst}>"; end
IP_FIELDS = [
["Version", :ip_v ],
["Header length", :ip_hl ],
["TOS", :ip_tos ],
["Length", :ip_len ],
["ID", :ip_id ],
["Frag offset", :ip_off ],
["TTL", :ip_ttl ],
["Protocol", :ip_p ],
["Checksum", :ip_sum ],
["Source addr", :ip_src ],
["Dest addr", :ip_dst ]
]
def details
IP_FIELDS.map do |name, meth|
sprintf("%20s = %s\n", name, send(meth))
end <<
sprintf("%20s = %s\n", "Body", body.inspect)
end
end
if __FILE__ == $0
ip = IP.new
ip.ip_v = 4
ip.ip_hl = 5 ## ?
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"
print ip.details
end
require "socket"
require "ip"
require "readline"
begin
rsock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
rescue Errno::EPERM => e
raise e, "You must be root to run this program."
end
rsock.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
listener = Thread.new do
loop do
data, sender = rsock.recvfrom(8192)
port, host = Socket.unpack_sockaddr_in(sender)
puts
puts "-"*80
puts "packet received from #{host}:#{port}:"
puts IP.new(data).details
$stdout.flush
end
end
sockaddr = Socket.pack_sockaddr_in(1024, "127.0.0.1")
#dst_port, dst_host = Socket.unpack_sockaddr_in(sockaddr)
#src_port, src_host = Socket.unpack_sockaddr_in(rsock.getsockname)
ip = IP.new
ip.ip_v = 4
ip.ip_hl = 5
ip.ip_tos = 0
ip.ip_len = 0
ip.ip_id = 0
ip.ip_off = 0
ip.ip_ttl = 255
ip.ip_p = Socket::IPPROTO_RAW
ip.ip_sum = 0
# ip.ip_src = src_host <-- filled in by socket
# ip.ip_dst = dst_host
loop do
line = Readline.readline("input> ", true)
break unless line
ip.body = line
rsock.send(ip, 0, sockaddr)
end
listener.kill
rsock.close
require "socket"
require "ip"
require "readline"
rsock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
sockaddr = Socket.pack_sockaddr_in(1024, "localhost")
ip = IP.new
ip.ip_v = 4
ip.ip_hl = 5
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"
loop do
line = Readline.readline("input> ", true)
break unless line
ip.body = line
rsock.send(ip, 0, sockaddr)
end
rsock.close