From: Joel VanderWerf Date: 2005-03-28T06:00:41+09:00 Subject: Re: Any Tools/Libraries for Replaying IP Packets? --------------080709010801000306020303 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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. --------------080709010801000306020303 Content-Type: text/plain; name="ip.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ip.rb" require 'scanf' # based on icmp.rb Copyright (C) 2000 GOTOU YUUZOU 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; ""; 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 --------------080709010801000306020303 Content-Type: text/plain; name="send-recv.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="send-recv.rb" 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 --------------080709010801000306020303 Content-Type: text/plain; name="send.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="send.rb" 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 --------------080709010801000306020303--