Hi, Florian Thank you so very much!!! I expected only some tips, but got a complete working solution. It is amazing, I am impressed. It works like a charm. I am so sorry I could not thank you immediately, I was out for several days. Thanks a lot once again, Gennady. P.S. BTW, in your post's UDPSpoofer there're 2 identical sets of methods ip2long, ipchecksum, make_ip_header, make_udp_header ;-) Florian Frank wrote: > 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). > > > 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 >