--sm4nu43k4a2Rpi4c
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Dec 01, 2006 at 04:47:05AM +0900, Daniel Berger wrote:
> Well, you could start by porting the ping_icmp() function from Ping.pm 
> to Ruby.  I started working on it but I got stuck and I need to work on 
> other things.  Below is what I've got so far:

I've made some progress; see attached. Let me know what you think.

-- 
Jos Backus
jos at catnook.com

--sm4nu43k4a2Rpi4c
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ping_icmp.rb"

#!/usr/bin/env ruby

require 'rubygems'
require 'net/ping'

module Net
  class Ping::ICMP < Ping   

    ICMP_ECHOREPLY  
    ICMP_ECHO       
    ICMP_STRUCT     C2 n3 A'
    ICMP_SUBCODE    
    ICMP_FLAGS      
    ICMP_PORT       

    def initialize(*args)
      super(args)
      raise 'requires root privileges' if Process.euid > 0 # unsure
      @seq  
      @data_size  
      @data  '
      @pid  rocess.pid & 0xffff
    end

    def checksum(msg)
      length     sg.length
      num_short  ength / 2
      check      

      msg.unpack("n#{num_short}").each do |short|
        check + hort
      end

      if length % 2 > 0
        check + sg[length-1, 1].unpack('C') << 8
      end

      check  check >> 16) + (check & 0xffff)
      return (~((check >> 16) + check) & 0xffff)
    end

    def ping(ip, timeout)
      ret  il
      socket  ocket.new(
        Socket::PF_INET,
        Socket::SOCK_RAW,
        Socket::IPPROTO_ICMP
      )

      @seq  @seq + 1) % 65536
      pstring  C2 n3 A' << @data_size.to_s

      checksum  
      msg  ICMP_ECHO, ICMP_SUBCODE, checksum, @pid, @seq, @data].pack(pstring)
      checksum  hecksum(msg)
      msg  ICMP_ECHO, ICMP_SUBCODE, checksum, @pid, @seq, @data].pack(pstring)

      begin
      saddr  ocket.pack_sockaddr_in(ICMP_PORT, ip)
      rescue exc
	return nil
      end

      @from_ip  from_type  from_subcode  il
      socket.send(msg, ICMP_FLAGS, saddr) # Send the message

      done  alse
      finish_time  ime.now + timeout
      while !done and timeout > 0
        nfound  elect([socket], nil, nil, timeout)
	timeout  inish_time - Time.now
        if nfound.nil? # timed out
          ret  il
          done  rue
        elsif !nfound[0].empty?
          recv_msg  '
          from_pid  1
          from_seq  1
          recv_msg, from_saddr  ocket.recvfrom(1500, ICMP_FLAGS)
          from_port, from_ip  ocket.unpack_sockaddr_in(from_saddr)
          from_type, from_subcode  ecv_msg[20, 2].unpack('C2')
          case from_type
          when ICMP_ECHOREPLY
            if recv_msg.length > 8
              from_pid, from_seq  ecv_msg[24, 4].unpack('n3')
            end
          else
            if recv_msg.length > 6
              from_pid, from_seq  ecv_msg[52, 4].unpack('n3')
            end
          end
          @from_ip  rom_ip
          @from_type  rom_type
          @from_subcode  rom_subcode
          if from_pid @pid and from_seq @seq
            if from_type ICMP_ECHOREPLY
              ret  
            end
            done  rue
          end
        else
	  # Shouldn't happen
          done  rue
        end
      end
      return ret
    end

  end

end

p  et::Ping::ICMP.new
p p.ping(ARGV.shift, 5)

--sm4nu43k4a2Rpi4c--