Разница в работе с сокетами на разных ОС в Ruby?

Доброго времени суток. Написал небольшой скрипт на Ruby, подобие traceroute. Писал под Mac OS, все работало. Проверил в виртуальной машине на Win XP — все ок. Когда пришло время показать это добро, попытался запустить на Windows 7 — облом. После недолгой отладки стало понятно, что проблема в месте вызова recvfrom, функция вылетает по тайм-ауту, пакеты не принимаются. Причем только в Windows 7 x64, на OS X Lion и Windows XP все работает прекрасно. Фаерволл отключил, не помогло. В чем может быть проблема?



#!/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!'
  • Вопрос задан
  • 3414 просмотров
Пригласить эксперта
Ответы на вопрос 2
crackedmind
@crackedmind
web-developer
А вы под администратором запускали?

У меня под Windows 7 X64, на ruby 1.8.7 & 1.9.3 показывает следующее:
> Checking hosts between ya.ru and ya.ru
* Checking ya.ru
|\
|* Host is unreacheble. Starting trace...
|* Timeout TTL=1
|* Timeout TTL=2
|/
> Finished!
Ответ написан
Skyggedans
@Skyggedans
А ведь PING на точно таких же RAW-сокетах в семерке работает нормально. Проблемы с блокированием recvfrom() начинаются только когда TTL меньше необходимого для достижения целевого узла, и в ответ приходит ICMP-пакет с типом 11 (TTL Exceeded). Вот этот пакет сокет уже почему-то не принимает и блокируется (или выходит по таймауту).
Проверялось в нескольких версиях Python.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы