1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
require 'socket'
require 'ipaddr'
class RawSocket # :nodoc:
@@id_arr = []
def initialize(src_addr, dest_addr)
# Define socket
begin
@socket = Socket.new PF_INET, SOCK_RAW, IPPROTO_RAW
rescue SystemCallError => e
raise SystemCallError, "You must be root to use raw sockets! #{e}"
end
@socket.setsockopt IPPROTO_IP, IP_HDRINCL, 1
# Checks addresses
@src_addr = check_addr src_addr
@dest_addr = check_addr dest_addr
# Source and destination port are zero
@src_port = 0
@dest_port = 0
# Set correct protocol version in the header
@version = @dest_addr.ipv4? ? "0100" : "0110"
# Total lenght: must be overridden by subclasses
@tot_lenght = 20
# Protocol: must be overridden by subclasses
@protocol = 1 # ICMP by default
# Generate a new id
# @id = genID
@id = 1234
# Generate peer sockaddr
@to = Socket.pack_sockaddr_in @dest_port, @dest_addr.to_s
end
def send(payload = '')
packet = make_ip_header([
[@version + '0101', 'B8'], # version, hlen
[0, 'C'], # tos
[@tot_lenght + payload.size, 'n'], # total len
[@id, 'n'], # id
[0, 'n'], # flags, offset
[64, 'C'], # ttl
[@protocol, 'C'], # protocol
[0, 'n'], # checksum
[@src_addr.to_i, 'N'], # source
[@dest_addr.to_i, 'N'], # destination
])
packet << make_transport_header(payload.size)
packet << [payload].pack("a*")
@socket.send(packet, 0, @to)
end
private
def check_addr(addr)
case addr
when String
IPAddr.new(addr)
when IPAddr
addr
else
raise ArgumentError, "Wrong address format: #{addr}"
end
end
def check_port(port)
if (1..65_535).cover?(port) && port.is_a?(Integer)
port
else
raise ArgumentError, "Port #{port} not valid"
end
end
def genID
while @@id_arr.include?(q = rand(65_535))
end
@@id_arr.push(q)
q
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_transport_header
""
end
end
class UdpRawSocket < RawSocket # :nodoc:
def initialize(src_addr, src_port, dest_addr, dest_port)
super(src_addr, dest_addr)
# Check ports
@src_port = check_port src_port
@dest_port = check_port dest_port
# Total lenght: must be overridden by subclasses
@tot_lenght = 20 + 8 # 8 bytes => UDP Header
# Protocol: must be overridden by subclasses
@protocol = 17 # UDP protocol
@to = Socket.pack_sockaddr_in @dest_port, @dest_addr.to_s
end
private
def make_udp_header(parts)
template = ''
data = []
parts.each do |part|
data += part[0..-2]
template << part[-1]
end
data.pack(template)
end
def make_transport_header(pay_size)
make_udp_header([
[@src_port, 'n'], # source port
[@dest_port, 'n'], # destination port
[8 + pay_size, 'n'], # len
[0, 'n'] # checksum (mandatory)
])
end
end
|