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
>