今回はからrouter-utilsを見ていきいます。
このプログラムはルータに必要な機能を使えるようにします。
今回はこのプログラムに定義されているクラスとメソッドについて簡単に説明します。
(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クラスを継承しています。
ARPReplyクラス
ARPリプライのパケットを作るクラスです。
ARPPacketクラスを継承しています。
IPPacketクラス
IPパケットを作るクラスです
ここではICMPのリプライパケットを送るのに使われています。
ICMPPacketクラス
ICMPパケットを構成するためのクラスです。
ICMPEchoReplyクラス
ICMPのリプライパケットを作るクラスです。
ICMPPacketクラスを継承しています。
RouterUtilsモジュール
create_arp_request_fromメソッドとcreate_arp_reply_fromメソッドとcreate_icmpv4_replyメソッドを定義しています。
今回は大まかな説明だけになります。
個人的にはsimple-router全体でこのソースが一番難しかったです。
次回以降、何度かに分けてこのソースを読んでいきます。