マイペースなプログラミング日記

x86エミュレータやFPGA、WebGLにお熱なd-kamiがマイペースに書くブログ

Raw Socketを使ってみる その3

Raw Socketを使ってみる その2ではSocketの1回ぶんの読み込みしか表示できなかったけど、今回のはIPパケットなら何回でも表示できるようにした。ARPとかがくると止まる。あと、UDPヘッダの一部の表示を追加したのとファイルをヘッダ毎に分割した。これで次回からは同じヘッダを省略できる。次回があるのかはわからんけど、そのうち送信もやってみたいな

socket.rb

require 'socket'
require './ether'
require './ip'
require './tcp'
require './udp'

ETH_P_ALL    = 0x300
ETHERTYPE_IP = 0x800

socket = Socket.open(Socket::PF_INET, Socket::SOCK_PACKET, ETH_P_ALL)

buff = ''

loop do
    if(buff.size < 1600)
        buff << socket.read(8192)
    end

    ether_header = EtherHeader.new(buff)

    puts 'Ethernetフレーム'
    puts "送信元MACアドレス #{ether_header.ether_shost}"
    puts "送信先MACアドレス #{ether_header.ether_dhost}"
    puts sprintf("EtherType = 0x%X", ether_header.ether_type)

    buff.slice!(0..13)

    if(ether_header.ether_type == ETHERTYPE_IP)
        puts 'IPパケット'
        ip_header = IPHeader.new(buff)
        puts "送信元IPアドレス #{ip_header.ip_src}"
        puts "送信先IPアドレス #{ip_header.ip_dst}"
        puts "プロトコル番号 #{ip_header.ip_p}"
        puts "サイズ #{ip_header.ip_len}"
        buff.slice!(0..(ip_header.ip_hl << 2) - 1)

        transport_size = 0

        if(ip_header.ip_p == Socket::IPPROTO_TCP)
            puts 'TCPパケット'
            tcp_header = TCPHeader.new(buff)
            puts "送信元ポート番号 #{tcp_header.th_sport}"
            puts "送信先ポート番号 #{tcp_header.th_dport}"
            transport_size = tcp_header.th_off << 2
            buff.slice!(0..transport_size - 1)

            size = ip_header.ip_len - (ip_header.ip_hl << 2) - transport_size - 1
            if(tcp_header.th_dport == 80 && size > 0)
                contents = buff.slice(0..size)
                puts contents
            end
        elsif(ip_header.ip_p == Socket::IPPROTO_UDP)
            puts 'UDPパケット'
            udp_header = UDPHeader.new(buff)
            puts "送信元ポート番号 #{udp_header.uh_sport}"
            puts "送信先ポート番号 #{udp_header.uh_dport}"
            transport_size = udp_header.uh_ulen
            buff.slice!(0..transport_size - 1)
        end

       size = (ip_header.ip_len - (ip_header.ip_hl << 2) - transport_size - 1)
       if(size > 0)
           buff.slice!(0..size)
       end
    else
        break
    end

    puts
end

ether.rb

class EtherHeader
    attr_reader :ether_dhost
    attr_reader :ether_shost
    attr_reader :ether_type

    def initialize(frame)
        @ether_dhost = mac_tos(frame, 0)
        @ether_shost = mac_tos(frame, 6)
        @ether_type = (frame[12] << 8) + frame[13]
    end

    def mac_tos(frame, index)
        return sprintf('%02X:%02X:%02X:%02X:%02X:%02X',
            frame[index], frame[index + 1], frame[index + 2], frame[index + 3], frame[index + 4], frame[index + 5])
    end
end

ip.rb

class IPHeader
    attr_reader :version
    attr_reader :ip_hl
    attr_reader :ip_tos
    attr_reader :ip_len
    attr_reader :ip_id
    attr_reader :ip_off 
    attr_reader :ip_ttl
    attr_reader :ip_p
    attr_reader :ip_sum
    attr_reader :ip_src
    attr_reader :ip_dst

    def initialize(packet)
        @version = (packet[0] >> 4) & 0x0F
        @ip_hl = packet[0] & 0x0F
        @ip_tos = packet[1]
        @ip_len = (packet[2] << 8) + packet[3]
        @ip_id = (packet[4] << 8) + packet[5]
        @ip_off = (packet[6] << 8) + packet[7]
        @ip_ttl = packet[8]
        @ip_p = packet[9]
        @ip_sum = (packet[10] << 8) + packet[11]
        @ip_src = ip_tos(packet, 12)
        @ip_dst = ip_tos(packet, 16)
    end

    def ip_tos(packet, index)
        return sprintf("%d.%d.%d.%d", packet[index], packet[index + 1], packet[index + 2], packet[index + 3])
    end
end

tcp.rb

class TCPHeader
    attr_reader :th_sport
    attr_reader :th_dport
    attr_reader :th_seq
    attr_reader :th_ack
    attr_reader :th_off
    attr_reader :th_x2
    attr_reader :th_falgs
    attr_reader :th_win
    attr_reader :th_sum
    attr_reader :th_urp

    def initialize(packet)
        @th_sport = (packet[0] << 8) + packet[1]
        @th_dport = (packet[2] << 8) + packet[3]
        @th_seq = (packet[4] << 24) + (packet[5] << 16) + (packet[6] << 8) + packet[7]
        @th_ack = (packet[8] << 24) + (packet[9] << 16) + (packet[10] << 8) + packet[11]
        @th_off = (packet[12] >> 4) & 0x0F
        @th_x2 = packet[12] & 0x0F
        @th_flags = packet[13]
        @th_win = (packet[14] << 8) + packet[15]
        @th_sum = (packet[16] << 8) + packet[17]
        @th_urp = (packet[18] << 8) + packet[19]
    end
end

udp.rb

class UDPHeader
    attr_reader :uh_sport
    attr_reader :uh_dport
    attr_reader :uh_ulen
    attr_reader :us_sum

    def initialize(packet)
        @uh_sport = (packet[0] << 8) + packet[1]
        @uh_dport = (packet[2] << 8) + packet[3]
        @uh_ulen = (packet[4] << 8) + packet[5]
        @uh_sum = (packet[6] << 8) + packet[7]
    end
end