E
E
etc2012-06-02 08:50:34
ruby
etc, 2012-06-02 08:50:34

Difference in working with sockets on different OS in Ruby?

Good day. Wrote a small Ruby script similar to traceroute. I wrote under Mac OS, everything worked. I checked it in a virtual machine on Win XP - everything is ok. When it came time to show this kindness, I tried to run it on Windows 7 - a bummer. After a short debugging, it became clear that the problem is in the place of the recvfrom call, the function crashes on a timeout, packets are not received. And only in Windows 7 x64, on OS X Lion and Windows XP everything works fine. Disabled firewall, didn't help. What could be the problem?

#!/usr/bin/env ruby<br>
<br>
require 'timeout'<br>
require 'socket'<br>
<br>
def trace host<br>
    port = 33434<br>
    ttl = 58<br>
    check = 1<br>
    errn = 0<br>
    errr = 0<br>
    reached = 0<br>
    puts '* Checking ' + host<br>
    puts '|\\'<br>
    while ttl <= 255 and reached == 0 do<br>
        # recv sock init<br>
        recv_sock = Socket.new( Socket::PF_INET, <br>
                                Socket::SOCK_RAW, <br>
                                Socket::IPPROTO_ICMP )<br>
        recv_sockaddr = Socket.pack_sockaddr_in( port, '' )<br>
        recv_sock.bind( recv_sockaddr )<br>
        # send sock init<br>
        send_sock = UDPSocket.new<br>
        send_sock.setsockopt( Socket::IPPROTO_IP, Socket::IP_TTL, ttl )<br>
        # sending<br>
        send_time = Time.now<br>
        send_sock.send( '', 0, host, port )<br>
        begin<br>
            Timeout::timeout( 1 ) {<br>
                # receiving<br>
                data, sender = recv_sock.recvfrom( 8192 )<br>
                recv_time = Time.now<br>
                icmp_type = data.unpack( '<hh user=20C>' )[0]<br>
                icmp_code = data.unpack( '<hh user=21C>' )[0]<br>
                # show result<br>
                rtt = ( recv_time.to_f - send_time.to_f ) * 1000<br>
                addr = Socket.unpack_sockaddr_in( sender )[1].to_s<br>
                begin<br>
                    paddr = addr.split('.').collect { |a| a.to_i() }<br>
                    name = Socket.gethostbyaddr( paddr.pack('CCCC') )[0]<br>
                rescue<br>
                    name = addr<br>
                end  <br>
                puts '|* ' + name + ' ( ' + addr + ' ) '  \<br>
                   + 'TIME=' + rtt.round.to_s + ' TTL=' + ttl.to_s<br>
                if ( icmp_type ==3 and icmp_code == 13 )<br>
                    puts '|* Prohibited'<br>
                elsif ( icmp_type == 3 and icmp_code == 3 )<br>
                    puts '|* Destination reached'<br>
                    reached = 1<br>
                end<br>
                errr = 0<br>
            }<br>
        rescue Timeout::Error<br>
            if check == 1<br>
                check = 0<br>
                ttl = 0<br>
                puts '|* Host is unreacheble. Starting trace...'<br>
            else<br>
                puts '|* Timeout TTL=' + ttl.to_s<br>
                errn += 1 if errr == 1<br>
                break if errn > 1<br>
            end<br>
            errr = 1<br>
        end<br>
        ttl += 1<br>
    end<br>
    puts '|/'<br>
end<br>
<br>
first = ARGV.shift || 'localhost'<br>
last = ARGV.shift || first<br>
<br>
puts '> Checking hosts between ' + first + ' and ' + last<br>
<br>
i = first.split('.')<br>
j = last.split('.')<br>
<br>
while i[3].to_i <= j[3].to_i do<br>
    trace i.join('.')<br>
    i[3] = i[3].to_i + 1<br>
end<br>
<br>
puts '> Finished!'

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Stanislav, 2012-06-02
@crackedmind

Did you run it as administrator?
I have under Windows 7 X64, on ruby ​​1.8.7 & 1.9.3 it shows the following:
> Checking hosts between ya.ru and ya.ru
* Checking ya.ru
|\
|* Host is unreacheble. Starting trace...
|* Timeout TTL=1
|* Timeout TTL=2
|/
> Finished!

S
Skyggedans, 2012-09-18
@Skyggedans

But PING on exactly the same RAW sockets in the seven works fine. Problems with blocking recvfrom() only start when the TTL is less than what is needed to reach the target node, and an ICMP packet with type 11 (TTL Exceeded) comes in response. For some reason, the socket does not accept this packet and is blocked (or exits by timeout).
Tested in several versions of Python.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question