Created
February 18, 2013 17:02
-
-
Save clicube/4978853 to your computer and use it in GitHub Desktop.
Read TCP, UDP, IP header by Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
require_relative 'protocol' | |
# TODO: チェックサムを確認する | |
class IPv4Header | |
attr_reader :version,:header_length,:packet_length,:identification,:frag_dont,:frag_more,:frag_offset,:ttl,:protocol,:checksum,:sndr_addr,:dest_addr, | |
:data_length | |
def initialize(packet,offset=0) | |
@packet = packet.force_encoding("ASCII-8BIT") | |
@offset = offset | |
header = packet.unpack("x#{offset}n10") | |
@version = header[0] >> 12 | |
@header_length = ((header[0] >> 8) & 0x0f)*4 | |
@packet_length = header[1] | |
@identification = header[2] | |
@frag_dont = (header[3] >> 14) & 0x01 != 0 | |
@frag_more = (header[3] >> 13) & 0x01 != 0 | |
@frag_offset = header[3] & 0x1fff | |
@ttl = header[4] >> 8 | |
@protocol = header[4] & 0x00ff | |
@checksum = header[5] | |
@sndr_addr = ip_to_s(packet[12..15]) | |
@dest_addr = ip_to_s(packet[16..19]) | |
@data_length = @packet_length - @header_length | |
@virtual_header = packet[12..19] + [0,6,@data_length].pack("CCn") | |
end | |
def upper | |
upper_header = Protocol.to_class(@protocol) | |
offset = @offset+@header_length | |
upper_header.new(@packet,offset,@data_length,self) | |
end | |
def data | |
start = @offset+@header_length | |
@packet[start..start+@data_length] | |
end | |
def get_virtual_header | |
@virtual_header | |
end | |
def ip_to_s(ip) | |
ip = ip.unpack("n2") | |
sprintf("%d.%d.%d.%d",ip[0]>>8,ip[0]&0x00ff,ip[1]>>8,ip[1]&0x00ff) | |
end | |
def to_s | |
"IPv4 Header\n" << | |
" Version : #{@version}\n" << | |
" Header Length : #{@header_length}\n" << | |
" Packet Length : #{@packet_length}\n" << | |
" Identification : #{@identification}\n" << | |
" Don't fragment : #{@frag_dont}\n" << | |
" More fragments : #{@frag_more}\n" << | |
" Fragment Offset : #{@frag_offset}\n" << | |
" TTL : #{@ttl}\n" << | |
" Protocol : #{Protocol.to_s(@protocol)}\n" << | |
" Header Checksum : #{@checksum}\n" << | |
" Sender Address : #{@sndr_addr}\n" << | |
" Destination Address: #{@dest_addr}\n" << | |
" (Data Length) : #{@data_length}" | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative 'ipv4header' | |
require_relative 'udpheader' | |
require_relative 'tcpheader' | |
class Protocol | |
ICMP = 0x01 | |
IGMP = 0x02 | |
TCP = 0x06 | |
UDP = 0x11 | |
IPv6 = 0x29 | |
def self.to_class protocol | |
case protocol | |
when Protocol::ICMP | |
raise "ICMP is not supported" | |
when Protocol::IGMP | |
raise "IGMP is not supported" | |
when Protocol::TCP | |
TCPHeader | |
when Protocol::UDP | |
UDPHeader | |
when Protocol::IPv6 | |
raise "IPv6 is not supported" | |
else | |
raise "Protocol:"+sprintf("0x%2X",protocol)+" is not supported" | |
end | |
end | |
def self.to_s protocol | |
case protocol | |
when Protocol::ICMP | |
"ICMP" | |
when Protocol::IGMP | |
"IGMP" | |
when Protocol::TCP | |
"TCP" | |
when Protocol::UDP | |
"UDP" | |
when Protocol::IPv6 | |
"IPv6" | |
else | |
sprintf("0x%2X",protocol) | |
end | |
end | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TCPHeader | |
attr_reader :sndr_port,:dest_port,:seq_num,:ack_num,:header_length, | |
:urg,:ack,:psh,:rst,:syn,:fin,:win_size,:checksum,:emgcy_ptr, | |
:packet_length,:data_length,:lower | |
def initialize(packet,offset=0,length=nil,lower=nil) | |
@packet = packet.force_encoding("ASCII-8BIT") | |
@offset = offset | |
@length = length || packet.bytesize-offset | |
header = packet.unpack("x#{offset}n2N2n4") | |
@sndr_port = header[0] | |
@dest_port = header[1] | |
@seq_num = header[2] | |
@ack_num = header[3] | |
@header_length = (header[4]>>12)*4 | |
@urg = (header[4] & 0b100000) != 0 | |
@ack = (header[4] & 0b010000) != 0 | |
@psh = (header[4] & 0b001000) != 0 | |
@rst = (header[4] & 0b000100) != 0 | |
@syn = (header[4] & 0b000010) != 0 | |
@fin = (header[4] & 0b000001) != 0 | |
@win_size = header[5] | |
@checksum = header[6] | |
@emgcy_ptr = header[7] | |
@packet_length = @length | |
@data_length = @packet_length-@header_length | |
@lower = lower | |
# check checksum | |
calc_cs = false | |
if calc_cs | |
tmp = @packet[@offset..@offset+@length] | |
if (tmp.length % 2) != 0 | |
tmp += "\0" | |
end | |
data = @lower.get_virtual_header + tmp | |
sum = 0 | |
list = data.unpack("n*") | |
list.each do |d| | |
sum += d | |
end | |
sum = (sum & 0xffff) + (sum >> 16) | |
sum = (sum & 0xffff) + (sum >> 16) | |
raise if sum != 65535 | |
end | |
end | |
def data | |
if(@data_length>0) | |
@packet[@offset+@header_length..@offset+@length] | |
else | |
"" | |
end | |
end | |
def to_s | |
"TCP Header\n" << | |
" Sender Port : #{@sndr_port}\n" << | |
" Destination Port: #{@dest_port}\n" << | |
" Sequence Number : #{@seq_num}\n" << | |
" ACK Number : #{@ack_num}\n" << | |
" Header Length : #{@header_length}\n" << | |
" URG : #{@urg}\n" << | |
" ACK : #{@ack}\n" << | |
" PSH : #{@psh}\n" << | |
" RST : #{@rst}\n" << | |
" SYN : #{@syn}\n" << | |
" FIN : #{@fin}\n" << | |
" Window Size : #{@win_size}\n" << | |
" Checksum : #{@checksum}\n" << | |
" Emergency Ptr : #{@emgcy_ptr}\n" << | |
" (Packet Length) : #{@packet_length}\n" << | |
" (Data Length) : #{@data_length}" | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UDPHeader | |
attr_reader :sndr_port,:dist_port,:packet_length,:checksum, | |
:data_length,:lower | |
def initialize(packet,offset=0,length=nil,lower=nil) | |
@packet = packet | |
@offset = offset | |
header = packet.unpack("x#{offset}n4") | |
@sndr_port = header[0] | |
@dist_port = header[1] | |
@packet_length = header[2] | |
@checksum = header[3] | |
@data_length = @packet_length - 8 | |
@lower = lower | |
end | |
def data | |
if(@packet_length>8) | |
@packet[@offset+8..@offset+@packet_length] | |
else | |
"" | |
end | |
end | |
def to_s | |
"" << | |
"UDP Header\n" << | |
" Sender Port : #{@sndr_port}\n" << | |
" Distication Port: #{@dist_port}\n" << | |
" Packet Length : #{@packet_length}\n" << | |
" Checksum : #{@checksum}\n" << | |
" (Data Length) : #{@data_length}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment