このプログラムはルータに必要な機能を使えるようにします。
今回はこのプログラムに定義されているクラスとメソッドについて簡単に説明します。
(router-utils.rb)
1 require 'ipaddr' 2 3 def get_checksum csum, val 4 sum = ( ~csum & 0xffff ) + val 5 while sum > 0xffff 6 sum = ( sum & 0xffff ) + ( sum >> 16 ) 7 end 8 ~sum & 0xffff 9 end 10 11 class IPAddr 12 def to_a 13 self.to_s.split( "." ).collect do | each | 14 each.to_i 15 end 16 end 17 end 18 19 class EthernetHeader 20 attr_accessor :macda, :macsa, :eth_type 21 22 def initialize macda, macsa, eth_type 23 @macda = macda 24 @macsa = macsa 25 @eth_type = eth_type 26 end 27 28 def pack 29 ( @macda.to_a + @macsa.to_a + [ eth_type ] ).pack( "C12n" ) 30 end 31 end 32 33 class ARPPacket 34 attr_accessor :type, :tha, :sha, :tpa, :spa 35 36 def initialize type, tha, sha, tpa, spa 37 @type = type 38 @tha = tha 39 @sha = sha 40 @tpa = tpa 41 @spa = spa 42 end 43 44 def pack 45 eth_header = EthernetHeader.new( @tha, @sha, 0x0806 ) 46 47 # arp 48 arp = [ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, @type ] 49 arp += @sha.to_a + @spa.to_a + @tha.to_a + @tpa.to_a 50 51 while arp.length < 46 do 52 arp += [ 0x00 ] 53 end 54 55 eth_header.pack + arp.pack( "C*" ) 56 end 57 end 58 59 class ARPRequest < ARPPacket 60 def initialize sha, tpa, spa 61 tha = [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ] 62 super( 1, tha, sha, tpa, spa ) 63 end 64 end 65 66 class ARPReply < ARPPacket 67 def initialize tha, sha, tpa, spa 68 super( 2, tha, sha, tpa, spa ) 69 end 70 end 71 72 class IPPacket 73 attr_accessor :id, :protocol, :daddr, :saddr, :payload 74 75 def initialize options 76 @id = options[ :id ] 77 @protocol = options[ :protocol ] 78 @daddr = options[ :daddr ] 79 @saddr = options[ :saddr ] 80 @payload = options[ :payload ] 81 @tot_len = 20 + payload.length 82 end 83 84 def pack 85 csum = get_checksum( 0, 0x4500 ) 86 header = [ 0x45, 0x00 ] # Version, IHL, ToS 87 88 csum = get_checksum( csum, @tot_len ) 89 header += [ @tot_len >> 8, @tot_len & 0xff ] # len 90 91 csum = get_checksum( csum, @id ) 92 header += [ @id >> 8, @id & 0xff ] # ID 93 94 csum = get_checksum( csum, 0x4000 ) 95 header += [ 0x40, 0x00 ] # Flags, Frag offset 96 97 csum = get_checksum( csum, 0x40 * 0x100 + @protocol ) 98 header += [ 0x40, @protocol ] # ttl, protocol 99 100 csum = get_checksum( csum, @saddr.to_i >> 16 ) 101 csum = get_checksum( csum, @saddr.to_i & 0xffff ) 102 csum = get_checksum( csum, @daddr.to_i >> 16 ) 103 csum = get_checksum( csum, @daddr.to_i & 0xffff ) 104 header += [ csum >> 8, csum & 0xff ] # checksum 105 header += @saddr.to_a + @daddr.to_a 106 107 header.pack( "C*" ) + @payload.pack 108 end 109 end 110 111 class ICMPPacket 112 attr_reader :payload, :length 113 114 def initialize type, code, payload 115 @type = type 116 @code = code 117 @payload = payload 118 @length = 4 + payload.length 119 end 120 121 def pack 122 @checksum = get_checksum( 0, @type * 0x100 + @code ) 123 124 words = @payload.pack( "C*" ).unpack( "n*" ) 125 words.each do | each | 126 @checksum = get_checksum( @checksum, each ) 127 end 128 129 [ @type, @code, @checksum ].pack( "C2n" ) + @payload.pack( "C*" ) 130 end 131 end 132 133 class ICMPEchoReply < ICMPPacket 134 def initialize payload 135 super( 0x00, 0x00, payload ) 136 end 137 end 138 139 module RouterUtils 140 def create_arp_request_from interface, addr 141 arp = ARPRequest.new( interface.hwaddr, addr, interface.ipaddr ) 142 arp.pack 143 end 144 145 def create_arp_reply_from message, replyaddr 146 arp = ARPReply.new( message.macsa, replyaddr, message.arp_spa, message.arp_tpa ) 147 arp.pack 148 end 149 150 def create_icmpv4_reply entry, interface, message 151 offset = 14 + 20 + 4 152 payload = message.data.unpack( "C*" )[ offset .. message.data.length - 1 ] 153 icmp = ICMPEchoReply.new( payload ) 154 ip_packet = IPPacket.new( :id => message.ipv4_id, 155 :protocol => message.ipv4_protocol, 156 :ttl => message.ipv4_ttl, 157 :daddr => message.ipv4_saddr, 158 :saddr => message.ipv4_daddr, 159 :payload => icmp ) 160 eth_header = EthernetHeader.new( entry.hwaddr, interface.hwaddr, 0x0800 ) 161 162 eth_header.pack + ip_packet.pack 163 end 164 end
get_checksumメソッド
IPv4パケットのチェックサムを計算する時に使用するメソッドです。
IPAddrクラス
1行目のrequireでipaddrを読み込む事で、標準ライブラリIPAddrクラス使えるようになっていますが、そのIPAddrクラスに定義を追加しています。
EthernetHeaderクラス
イーサネットヘッダーを構成するためのクラスです。
ARPPacketクラス
ARPパケットを構成するためのクラスです。
ARPRequestクラス
ARPリクエストのパケットを作るクラスです。
ARPPacketクラスを継承しています。
ARPPacketクラスを継承しています。
ARPReplyクラス
ARPリプライのパケットを作るクラスです。
ARPPacketクラスを継承しています。
ARPPacketクラスを継承しています。
IPPacketクラス
IPパケットを作るクラスです
ここではICMPのリプライパケットを送るのに使われています。
ここではICMPのリプライパケットを送るのに使われています。
ICMPPacketクラス
ICMPパケットを構成するためのクラスです。
ICMPEchoReplyクラス
ICMPのリプライパケットを作るクラスです。
ICMPPacketクラスを継承しています。
ICMPPacketクラスを継承しています。
RouterUtilsモジュール
create_arp_request_fromメソッドとcreate_arp_reply_fromメソッドとcreate_icmpv4_replyメソッドを定義しています。
今回は大まかな説明だけになります。
個人的にはsimple-router全体でこのソースが一番難しかったです。
次回以降、何度かに分けてこのソースを読んでいきます。
0 件のコメント:
コメントを投稿