Spoofing seems to work pretty good in Ruby (see below). You would have
to recalculate the ip header checksum (and probably also the udp
checksum), if you want to change the source address of a given packet .
BTW, the ipchecksum algorithm is really beautiful in Ruby:
def ipchecksum(data)
checksum = data.unpack(“n*”).inject(0) { |s, x| s + x }
((checksum >> 16) + (checksum & 0xffff)) ^ 0xffff
end
Here comes my little hack:
require ‘socket’
class UDPSpoofer
@@id = 1234 - 1
def initialize
@s = Socket.new(Socket::PF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW)
@s.setsockopt(Socket::IPPROTO_IP, Socket::IP_HDRINCL, 1)
end
def send(src, sport, dst, dport, payload = '')
dst_numeric = dst.split(/\./).map { |x| x.to_i }
to = [ Socket::AF_INET,
dport, dst_numeric, '' ].flatten.pack('snCCCCa8')
packet = make_ip_header([
[ '01000101', 'B8' ], # version, hlen
[ 0, 'C' ], # tos
[ 28 + payload.size, 'n' ], # total len
[ @@id += 1, 'n' ], # id
[ 0, 'n' ], # flags, offset
[ 64, 'C' ], # ttl
[ 17, 'C' ], # protocol
[ 0, 'n' ], # checksum
[ ip2long(src), 'N' ], # source
[ ip2long(dst), 'N' ], # destination
])
packet << make_udp_header([
[ sport, 'n'], # source port
[ dport, 'n' ], # destination port
[ 8 + payload.size, 'n' ], # len
[ 0, 'n' ] # checksum (mandatory)
])
packet << payload
@s.send(packet, 0, to)
end
private
def ip2long(ip)
long = 0
ip.split(/\./).reverse.each_with_index do |x, i|
long += x.to_i << (i * 8)
end
long
end
def ipchecksum(data)
checksum = data.unpack("n*").inject(0) { |s, x| s + x }
((checksum >> 16) + (checksum & 0xffff)) ^ 0xffff
end
def make_ip_header(parts)
template = ''
data = []
parts.each do |part|
data += part[0..-2]
template << part[-1]
end
data_str = data.pack(template)
checksum = ipchecksum(data_str)
data[-3] = checksum
data.pack(template)
end
def make_udp_header(parts)
template = ''
data = []
parts.each do |part|
data += part[0..-2]
template << part[-1]
end
data.pack(template)
end
def ip2long(ip)
long = 0
ip.split(/\./).reverse.each_with_index do |x, i|
long += x.to_i << (i * 8)
end
long
end
def ipchecksum(data)
checksum = data.unpack("n*").inject(0) { |s, x| s + x }
((checksum >> 16) + (checksum & 0xffff)) ^ 0xffff
end
def make_ip_header(parts)
template = ''
data = []
parts.each do |part|
data += part[0..-2]
template << part[-1]
end
data_str = data.pack(template)
checksum = ipchecksum(data_str)
data[-3] = checksum
data.pack(template)
end
def make_udp_header(parts)
template = ''
data = []
parts.each do |part|
data += part[0..-2]
template << part[-1]
end
data.pack(template)
end
end
us = UDPSpoofer.new
loop do # fire!
us.send(‘192.168.1.66’, 666, ‘192.168.1.1’, 42, ‘i am on the ether’)
end
···
On 2004-03-17 04:14:18 +0900, Gennady wrote:
Is there a way, in general, to “fake” a sender’s IP address when
sending a UDP packet? I need to receive a UDP packet on one port and
redirect it to another “pretending” that it is from the original
sender.
Even if it is not possible from Ruby now, I would appreciate any
pointers so that I can make an extension to do it (if at all possible).
–
lambda { |c| lambda { |f| f[f] } [ lambda { |f| c[lambda { |x| f[f] } ] }] }