Skip to content

Instantly share code, notes, and snippets.

@th1agoalmeida
Created March 11, 2023 04:21
Show Gist options
  • Save th1agoalmeida/8a1ca4bf460a2ed7ac184716e18ca9dc to your computer and use it in GitHub Desktop.
Save th1agoalmeida/8a1ca4bf460a2ed7ac184716e18ca9dc to your computer and use it in GitHub Desktop.
require 'socket'
class MyIcmpSocket
ICMP_ECHO_REQUEST_TYPE = 8
ICMP_ECHO_REQUEST_CODE = 0
ICMP_HEADER_SIZE = 8
def initialize
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_RAW, Socket::IPPROTO_ICMP)
end
def ping(host)
icmp_id = Process.pid & 0xffff
icmp_seq = 0
icmp_data = "ping #{host} packet"
# Construct ICMP echo request packet
icmp_header = [ICMP_ECHO_REQUEST_TYPE, ICMP_ECHO_REQUEST_CODE, 0, icmp_id, icmp_seq].pack('CCnS>S>')
icmp_checksum = calc_checksum(icmp_header + icmp_data)
icmp_packet = [ICMP_ECHO_REQUEST_TYPE, ICMP_ECHO_REQUEST_CODE, icmp_checksum, icmp_id, icmp_seq, icmp_data].pack('CCnS>S>a*')
# Send ICMP echo request packet and receive response
sockaddr = Socket.sockaddr_in(0, host)
start_time = Time.now
@socket.send(icmp_packet, 0, sockaddr)
response_packet, sockaddr = @socket.recvfrom(1024)
end_time = Time.now
# Parse ICMP echo response packet
response_header = response_packet[0, ICMP_HEADER_SIZE]
response_type, response_code, response_checksum, response_id, response_seq = response_header.unpack('CCnS>S>')
raise "Invalid ICMP echo response packet" unless response_type == 0 && response_code == 0 && response_id == icmp_id && response_seq == icmp_seq
round_trip_time = (end_time - start_time) * 1000
# Return round-trip time
round_trip_time
end
private
def calc_checksum(data)
sum = 0
data.scan(/.{2}/m).map { |word| sum += word.unpack('n')[0] }
sum = (sum >> 16) + (sum & 0xffff)
sum += sum >> 16
~sum & 0xffff
end
end
# This code creates a raw socket using Socket, which allows it to send and
# receive ICMP packets directly. The ping method constructs an ICMP echo
# request packet, sends it to the specified host, and receives the response.
# The round-trip time is then calculated and returned. The calc_checksum
# method is used to calculate the checksum for the ICMP packet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment