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