前回のはIPヘッダ(の一部)までしか表示してなかったけど、今回はTCPヘッダ(の一部)まで表示するようにした。まぁ、TCPパケットが来てくれないと意味がないんだけど、ブラウザとか立ち上げれば普通にヘッダの内容が見れる。readはどうやら、指定したサイズまで読み込まないと処理を返してくれないみたいなので、ブラウザのようなアプリケーションじゃないと、表示まで時間がかかるかもしれない。また、今回は1回で読み込んだ複数のEthernetフレームを処理してるけど、IPパケットでない場合はループを抜けるようにしている。ARPやUDPも対応させようと思ったが長くなるのとやる気がなくなったため、対応させなかった。あとループを抜ける条件式は適当
require 'socket' class EtherHeader attr_reader :ether_dhost attr_reader :ether_shost attr_reader :ether_type def initialize(frame, index) @ether_dhost = mac_tos(frame, index) @ether_shost = mac_tos(frame, index + 6) @ether_type = (frame[index + 12] << 8) + frame[index + 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 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, index) @version = (packet[index] >> 4) & 0x0F @ip_hl = packet[index] & 0x0F @ip_tos = packet[index + 1] @ip_len = (packet[index + 2] << 8) + packet[index + 3] @ip_id = (packet[index + 4] << 8) + packet[index + 5] @ip_off = (packet[index + 6] << 8) + packet[index + 7] @ip_ttl = packet[index + 8] @ip_p = packet[index + 9] @ip_sum = (packet[index + 10] << 8) + packet[index + 11] @ip_src = ip_tos(packet, index + 12) @ip_dst = ip_tos(packet, index + 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 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, index) @th_sport = (packet[index] << 8) + packet[index + 1] @th_dport = (packet[index + 2] << 8) + packet[index + 3] @th_seq = (packet[index + 4] << 24) + (packet[index + 5] << 16) + (packet[index + 6] << 8) + packet[index + 7] @th_ack = (packet[index + 8] << 24) + (packet[index + 9] << 16) + (packet[index + 10] << 8) + packet[index + 11] @th_off = (packet[index + 12] >> 4) & 0x0F @th_x2 = packet[index + 12] &0x0F @th_flags = packet[index + 13] @th_win = (packet[index + 14] << 8) + packet[index + 15] @th_sum = (packet[index + 16] << 8) + packet[index + 17] @th_urp = (packet[index + 18] << 8) + packet[index + 19] end end ETH_P_ALL = 0x0300 ETHERTYPE_IP = 0x800 socket = Socket.open(Socket::PF_INET, Socket::SOCK_PACKET, ETH_P_ALL) index = 0 buff = socket.read(8192) loop do if((8192 - index) < 40) break end ether_header = EtherHeader.new(buff, index) puts 'Ethernetフレーム' puts "送信元MACアドレス #{ether_header.ether_shost}" puts "送信先MACアドレス #{ether_header.ether_dhost}" puts sprintf("EtherType = 0x%X", ether_header.ether_type) index += 14 if(ether_header.ether_type == ETHERTYPE_IP) puts 'IPパケット' ip_header = IPHeader.new(buff, index) puts "送信元IPアドレス #{ip_header.ip_src}" puts "送信先IPアドレス #{ip_header.ip_dst}" puts "プロトコル番号 #{ip_header.ip_p}" puts "サイズ #{ip_header.ip_len}" if(ip_header.ip_p == Socket::IPPROTO_TCP) tcp_header = TCPHeader.new(buff, index + (ip_header.ip_hl << 2)) puts "送信元ポート番号 #{tcp_header.th_sport}" puts "送信先ポート番号 #{tcp_header.th_dport}" end index += ip_header.ip_len else break end puts end