ospfv2 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/ospfv2 +136 -0
- data/lib/ie/au_type.rb +79 -0
- data/lib/ie/external_route.rb +181 -0
- data/lib/ie/id.rb +97 -0
- data/lib/ie/interface_mtu.rb +64 -0
- data/lib/ie/ls_age.rb +89 -0
- data/lib/ie/ls_type.rb +148 -0
- data/lib/ie/metric.rb +63 -0
- data/lib/ie/mt_metric.rb +119 -0
- data/lib/ie/options.rb +356 -0
- data/lib/ie/ospf_version.rb +67 -0
- data/lib/ie/packet_type.rb +65 -0
- data/lib/ie/router_link.rb +167 -0
- data/lib/ie/router_link_factory.rb +53 -0
- data/lib/ie/router_link_type.rb +86 -0
- data/lib/ie/sequence_number.rb +144 -0
- data/lib/ie/tos_metric.rb +102 -0
- data/lib/infra/ospf_common.rb +291 -0
- data/lib/infra/ospf_constants.rb +73 -0
- data/lib/infra/ospf_io.rb +133 -0
- data/lib/infra/ospf_socket.rb +126 -0
- data/lib/infra/parse_options.rb +135 -0
- data/lib/infra/timer.rb +104 -0
- data/lib/infra/to_s.rb +38 -0
- data/lib/ls_db/advertised_routers.rb +78 -0
- data/lib/ls_db/common.rb +31 -0
- data/lib/ls_db/link_state_database.rb +376 -0
- data/lib/ls_db/link_state_database_build.rb +181 -0
- data/lib/ls_db/link_state_database_links.rb +178 -0
- data/lib/ls_db/links.rb +160 -0
- data/lib/lsa/external.rb +347 -0
- data/lib/lsa/lsa.rb +438 -0
- data/lib/lsa/lsa_factory.rb +59 -0
- data/lib/lsa/network.rb +166 -0
- data/lib/lsa/router.rb +336 -0
- data/lib/lsa/summary.rb +393 -0
- data/lib/neighbor/neighbor.rb +298 -0
- data/lib/neighbor/neighbor_event_handler.rb +61 -0
- data/lib/neighbor/recv_database_description.rb +153 -0
- data/lib/neighbor/recv_hello.rb +53 -0
- data/lib/neighbor/recv_ospf_packet.rb +68 -0
- data/lib/neighbor_sm/attempt_state.rb +44 -0
- data/lib/neighbor_sm/down_state.rb +46 -0
- data/lib/neighbor_sm/exchange_state.rb +32 -0
- data/lib/neighbor_sm/exstart_state.rb +69 -0
- data/lib/neighbor_sm/full_state.rb +36 -0
- data/lib/neighbor_sm/init_state.rb +43 -0
- data/lib/neighbor_sm/loading_state.rb +33 -0
- data/lib/neighbor_sm/neighbor_state.rb +87 -0
- data/lib/packet/database_description.rb +300 -0
- data/lib/packet/hello.rb +327 -0
- data/lib/packet/link_state_ack.rb +144 -0
- data/lib/packet/link_state_request.rb +153 -0
- data/lib/packet/link_state_update.rb +189 -0
- data/lib/packet/ospf_packet.rb +306 -0
- metadata +116 -0
@@ -0,0 +1,291 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of OSPFv2.
|
8
|
+
#
|
9
|
+
# OSPFv2 is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# OSPFv2 is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'ipaddr'
|
25
|
+
|
26
|
+
class Class
|
27
|
+
def attr_checked(attribute, &validation)
|
28
|
+
define_method "#{attribute}=" do |val|
|
29
|
+
raise "Invalid attribute #{val.inspect}" unless validation.call(val)
|
30
|
+
instance_variable_set("@#{attribute}", val)
|
31
|
+
end
|
32
|
+
define_method attribute do
|
33
|
+
instance_variable_get "@#{attribute}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
def attr_writer_delegate(*args)
|
37
|
+
# p self
|
38
|
+
args.each do |name|
|
39
|
+
define_method "#{name}=" do |value|
|
40
|
+
# p "in method..", self.class
|
41
|
+
instance_variable_set("@#{name}",
|
42
|
+
self.class.const_get(name.to_s.to_camel.to_sym).new(value))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class String
|
49
|
+
|
50
|
+
def to_underscore
|
51
|
+
gsub(/([A-Z]+|[A-Z][a-z])/) {|x| ' ' + x }.gsub(/[A-Z][a-z]+/) {|x| ' ' + x }.split.collect{|x| x.downcase}.join('_')
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_camel
|
55
|
+
split('_').collect {|x| x.capitalize}.join
|
56
|
+
end
|
57
|
+
|
58
|
+
def hexlify
|
59
|
+
l,n,ls,s=0,0,[''],self.dup
|
60
|
+
while s.size>0
|
61
|
+
l = s.slice!(0,16)
|
62
|
+
ls << format("0x%4.4x: %s", n, l.unpack("n#{l.size/2}").collect { |x| format("%4.4x",x) }.join(' '))
|
63
|
+
n+=1
|
64
|
+
end
|
65
|
+
if l.size%2 >0
|
66
|
+
ns = if l.size>1 then 1 else 0 end
|
67
|
+
ls.last << format("%s%2.2x",' '*ns,l[-1])
|
68
|
+
end
|
69
|
+
ls
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
class Symbol
|
75
|
+
def to_klass
|
76
|
+
to_s.to_camel.to_sym
|
77
|
+
end
|
78
|
+
def to_setter
|
79
|
+
(to_s + "=").to_sym
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
class Object
|
85
|
+
def to_shex(*args)
|
86
|
+
self.respond_to?(:encode) ? self.encode(*args).unpack('H*')[0] : ""
|
87
|
+
end
|
88
|
+
def to_shex_len(len, *args)
|
89
|
+
s = to_shex(*args)
|
90
|
+
"#{s[0..len]}#{s.size>len ? '...' : ''}"
|
91
|
+
end
|
92
|
+
def to_shex4_len(len, *args)
|
93
|
+
s = to_shex4(*args)
|
94
|
+
"#{s[0..len]}#{s.size>len ? '...' : ''}"
|
95
|
+
end
|
96
|
+
def to_bitstring
|
97
|
+
if self.respond_to?(:encode)
|
98
|
+
self.enc.unpack('B*')[0]
|
99
|
+
else
|
100
|
+
""
|
101
|
+
end
|
102
|
+
end
|
103
|
+
def method_missing(method, *args, &block)
|
104
|
+
# puts "COMMON method_missing: #{method}"
|
105
|
+
|
106
|
+
if method.to_s =~ /^to_s(\d+)/
|
107
|
+
to_s($1.to_i)
|
108
|
+
else
|
109
|
+
# p caller
|
110
|
+
super
|
111
|
+
end
|
112
|
+
end
|
113
|
+
def define_to_s
|
114
|
+
if defined?($style)
|
115
|
+
self.class.class_eval { eval("alias :to_s :to_s_#{$style}") }
|
116
|
+
elsif respond_to?(:to_s_default)
|
117
|
+
self.class.class_eval { alias :to_s :to_s_default }
|
118
|
+
else
|
119
|
+
puts "You're screwed!"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Time
|
125
|
+
class << self
|
126
|
+
def to_ts
|
127
|
+
Time.now.strftime("%M:%S")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class IPAddr
|
133
|
+
alias encode hton
|
134
|
+
|
135
|
+
def self.create(arg)
|
136
|
+
if arg.is_a?(String) and arg.is_packed?
|
137
|
+
IPAddr.new_ntoh(arg)
|
138
|
+
elsif arg.is_a?(Integer)
|
139
|
+
IPAddr.new_ntoh([arg].pack('N'))
|
140
|
+
elsif arg.is_a?(Array) and arg[0].is_a?(Fixnum)
|
141
|
+
IPAddr.new_ntoh([arg].pack('C*'))
|
142
|
+
elsif arg.is_a?(self)
|
143
|
+
IPAddr.new
|
144
|
+
else
|
145
|
+
IPAddr.new(arg)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def mlen
|
150
|
+
@_jme_mlen_ ||= _mlen_
|
151
|
+
end
|
152
|
+
|
153
|
+
def +(i)
|
154
|
+
[IPAddr.create(to_i + i).to_s, mlen].join("/")
|
155
|
+
end
|
156
|
+
def ^(i)
|
157
|
+
@increment ||= _generate_network_inc_
|
158
|
+
[IPAddr.create(to_i + @increment.call(i)).to_s, mlen].join("/")
|
159
|
+
end
|
160
|
+
|
161
|
+
def netmask
|
162
|
+
if ipv4?
|
163
|
+
[@mask_addr].pack('N').unpack('C4').collect { |x| x.to_s}.join('.')
|
164
|
+
else
|
165
|
+
i = @mask_addr
|
166
|
+
arr=[]
|
167
|
+
while i>0
|
168
|
+
arr << (i & 0xffff) and i >>= 16
|
169
|
+
end
|
170
|
+
arr.reverse.collect { |x| x.to_s(16) }.join(':')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def to_s_net
|
175
|
+
[to_s,mlen].join('/')
|
176
|
+
end
|
177
|
+
|
178
|
+
def IPAddr.to_ary(prefix)
|
179
|
+
source_address,mlen = prefix.split('/')
|
180
|
+
ip = IPAddr.new(prefix)
|
181
|
+
network = ip.to_s
|
182
|
+
[ip, source_address, mlen.to_i, network, ip.netmask]
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def _mlen_
|
188
|
+
m = @mask_addr
|
189
|
+
len = ipv6? ? 128 : 32
|
190
|
+
loop do
|
191
|
+
break if m & 1 > 0
|
192
|
+
m = m >> 1
|
193
|
+
len += -1
|
194
|
+
end
|
195
|
+
len
|
196
|
+
end
|
197
|
+
|
198
|
+
def _generate_network_inc_
|
199
|
+
max_len = ipv4? ? 32 : 128
|
200
|
+
Proc.new { |n| n*(2**(max_len - mlen)) }
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
module OSPFv2
|
209
|
+
module Common
|
210
|
+
|
211
|
+
def ivar_to_klassname(ivar)
|
212
|
+
ivar.to_s.to_camel.to_sym
|
213
|
+
end
|
214
|
+
|
215
|
+
def set(h)
|
216
|
+
# p "\n\n\n#{self.class}: IN SET(): ivars; #{ivars.inspect} - h: #{h.inspect}:"
|
217
|
+
for key in [ivars].flatten
|
218
|
+
# p key
|
219
|
+
if h.has_key?(key) and ! h[key].nil?
|
220
|
+
# puts " h has key #{key}"
|
221
|
+
begin
|
222
|
+
klassname = key.to_klass
|
223
|
+
if self.class.const_defined?(klassname)
|
224
|
+
# puts " class #{klassname} exists! => set @#{key.to_s} = #{klassname}.new(#{h[key]})"
|
225
|
+
instance_variable_set("@#{key.to_s}", self.class.const_get(klassname).new(h[key]))
|
226
|
+
elsif OSPFv2.const_defined?(klassname)
|
227
|
+
# puts " class OSPFv2::#{klassname} exists! => set @#{key.to_s} = #{klassname}.new(#{h[key]})"
|
228
|
+
instance_variable_set("@#{key.to_s}", OSPFv2.const_get(klassname).new(h[key]))
|
229
|
+
# elsif OSPFv2::LSDB::const_defined?(klassname)
|
230
|
+
# # puts " class OSPFv2::LSDB::#{klassname} exists! => set @#{key.to_s} = #{klassname}.new(#{h[key]})"
|
231
|
+
# instance_variable_set("@#{key.to_s}", OSPFv2::LSDB::const_get(klassname).new(h[key]))
|
232
|
+
elsif self.respond_to?(key.to_setter)
|
233
|
+
# puts " self respond to #{key.to_setter} => self.__send__ #{key.to_setter}, #{h[key]}"
|
234
|
+
self.send key.to_setter, h[key]
|
235
|
+
#elsif has an instance variable of that name ?
|
236
|
+
#or create ivar on the fly ?
|
237
|
+
else
|
238
|
+
# puts " just set ivar: @#{key} = #{h[key]}"
|
239
|
+
instance_variable_set("@#{key.to_s}", h[key])
|
240
|
+
end
|
241
|
+
rescue ArgumentError => e
|
242
|
+
raise
|
243
|
+
#
|
244
|
+
# #FIXME: attr_writer_delegate generate a NameError (in link_state_database)
|
245
|
+
# p "WE HAVE A NAME ERROR: #{e.inspect}"
|
246
|
+
# # instance_variable_set("@#{key.to_s}", h[key])
|
247
|
+
ensure
|
248
|
+
h.delete(key)
|
249
|
+
end
|
250
|
+
else
|
251
|
+
# puts "did not find #{key} in #{h.inspect}"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def to_hash
|
257
|
+
h = {}
|
258
|
+
for key in [ivars].flatten
|
259
|
+
ivar = instance_variable_get("@#{key.to_s}")
|
260
|
+
if ivar.respond_to?(:to_hash)
|
261
|
+
# p "#{key} respond to hash"
|
262
|
+
# p ivar
|
263
|
+
# p "#{key} --"
|
264
|
+
# p ivar
|
265
|
+
h.store(key,ivar.to_hash)
|
266
|
+
elsif ivar.is_a?(Array)
|
267
|
+
h.store(key, ivar.collect { |x| x.to_hash })
|
268
|
+
else
|
269
|
+
# p "#{key} don't respond to hast"
|
270
|
+
# p ivar
|
271
|
+
# p ivar.class
|
272
|
+
# p "#{key} --"
|
273
|
+
#FIXME: ivar.to_s ? ivar.value ? ivar.hash_value ?
|
274
|
+
h.store(key,ivar) unless ivar.nil?
|
275
|
+
end
|
276
|
+
end
|
277
|
+
h
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
module Common
|
282
|
+
|
283
|
+
def ivars
|
284
|
+
instance_variables.reject { |x| x =~ /^@_/ }.collect { |x| x[1..-1].to_sym }
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
load "../../../test/ospfv2/infra/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of OSPFv2.
|
8
|
+
#
|
9
|
+
# OSPFv2 is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# OSPFv2 is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
module OSPFv2
|
24
|
+
|
25
|
+
module Constant
|
26
|
+
V2=2
|
27
|
+
V3=3
|
28
|
+
HELLO = 1
|
29
|
+
DATABASE_DESCRIPTION = 2
|
30
|
+
LINK_STATE_REQUEST = 3
|
31
|
+
LINK_STATE_UPDATE = 4
|
32
|
+
LINK_STATE_ACKNOWLEDGEMENT = 5
|
33
|
+
end
|
34
|
+
|
35
|
+
VERSION=2
|
36
|
+
LSRefreshTime = 30*60
|
37
|
+
MinLSInterval = 5
|
38
|
+
MinLSArrival = 1
|
39
|
+
MaxAge = 3600
|
40
|
+
CheckAge = 5*60
|
41
|
+
MaxAgeDiff = 15*60
|
42
|
+
LSInfinity = 0xffffffff
|
43
|
+
DefaultDestination = "0.0.0.0"
|
44
|
+
N = 0x80000000
|
45
|
+
InitialSequenceNumber = N + 1
|
46
|
+
MaxSequenceNumber = N - 1
|
47
|
+
|
48
|
+
ROUTER_LINK_P2P = 1
|
49
|
+
ROUTER_LINK_TRANSIT = 2
|
50
|
+
ROUTER_LINK_STUB = 3
|
51
|
+
ROUTER_LINK_VL = 4
|
52
|
+
|
53
|
+
ROUTER_LSA = 1
|
54
|
+
NETWORK_LSA = 2
|
55
|
+
SUMMARY_LSA = 3
|
56
|
+
ASBR_SUMMMARY_LSA = 4
|
57
|
+
EXTERNAL_LSA = 5
|
58
|
+
NSSA_LSA = 7
|
59
|
+
|
60
|
+
IPPROTO_OSPF = 89
|
61
|
+
AllSPFRouters = "224.0.0.5"
|
62
|
+
AllDRouters = "224.0.0.6"
|
63
|
+
|
64
|
+
EXTERNAL_BASE_ADDRESS='50.0.0.0/24'
|
65
|
+
SUMMARY_BASE_ADDRESS='30.0.0.0/24'
|
66
|
+
NETWORK_BASE_ADDRESS='20.0.0.0/24'
|
67
|
+
LINK_BASE_ADDRESS='13.0.0.0/30'
|
68
|
+
|
69
|
+
PACKET_HEADER_LEN = 24
|
70
|
+
LSA_HEADER_LEN = 20
|
71
|
+
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of OSPFv2.
|
8
|
+
#
|
9
|
+
# OSPFv2 is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# OSPFv2 is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'observer'
|
25
|
+
require 'thread'
|
26
|
+
|
27
|
+
module OSPFv2
|
28
|
+
|
29
|
+
class Input
|
30
|
+
include Observable
|
31
|
+
|
32
|
+
attr_reader :sock
|
33
|
+
|
34
|
+
def initialize(sock, neighbor, ev_handler)
|
35
|
+
super()
|
36
|
+
@sock=sock
|
37
|
+
@neighbor=neighbor
|
38
|
+
add_observer(ev_handler)
|
39
|
+
@continue=true
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :thread
|
43
|
+
|
44
|
+
def our_address
|
45
|
+
@neighbor.address
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop
|
49
|
+
@thread.exit
|
50
|
+
@thread.join
|
51
|
+
rescue
|
52
|
+
end
|
53
|
+
|
54
|
+
def start
|
55
|
+
@thread = Thread.new(@sock) do |s|
|
56
|
+
Thread.current['name'] = self.class.to_s
|
57
|
+
begin
|
58
|
+
while @continue
|
59
|
+
from, port, data = s.recv
|
60
|
+
hdr = header(data)
|
61
|
+
if hdr[:ip_proto] == 89 and data[20] == 2
|
62
|
+
if from != our_address
|
63
|
+
changed and notify_observers(:ev_recv, data, from, port) # * @sock.recv ....
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue Exception => e
|
68
|
+
p e
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
|
76
|
+
def long2ip(ip)
|
77
|
+
return ip if ip.is_a?(String)
|
78
|
+
[ip].pack('N').unpack('CCCC').collect {|c| c}.join('.')
|
79
|
+
end
|
80
|
+
def header(_h)
|
81
|
+
h = _h.unpack('CCnnnCCnNN')
|
82
|
+
{
|
83
|
+
:ip_ver => h[0] >> 4,
|
84
|
+
:ip_hlen => (h[0] & 0xf) <<2,
|
85
|
+
:ip_tos => h[1],
|
86
|
+
:ip_length => h[2],
|
87
|
+
:ip_id => h[3],
|
88
|
+
:ip_offset => h[4],
|
89
|
+
:ip_ttl => h[5],
|
90
|
+
:ip_proto => h[6],
|
91
|
+
:ip_csum => h[7],
|
92
|
+
:ip_src => long2ip(h[8]),
|
93
|
+
:ip_dst => long2ip(h[9]),
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
class OutputQ < Queue
|
100
|
+
include Observable
|
101
|
+
|
102
|
+
def initialize(sock, *obs)
|
103
|
+
super()
|
104
|
+
@sock= sock
|
105
|
+
obs.each { |o| self.add_observer(o) }
|
106
|
+
@continue = true
|
107
|
+
end
|
108
|
+
|
109
|
+
attr_reader :thread
|
110
|
+
|
111
|
+
def stop
|
112
|
+
@thread.exit
|
113
|
+
@thread.join
|
114
|
+
rescue
|
115
|
+
end
|
116
|
+
|
117
|
+
def start
|
118
|
+
@thread = Thread.new(@sock) do |s|
|
119
|
+
Thread.current['name'] = self.class.to_s
|
120
|
+
begin
|
121
|
+
while @continue
|
122
|
+
el = deq
|
123
|
+
@sock.send *el
|
124
|
+
end
|
125
|
+
rescue => e
|
126
|
+
p e
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2010 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of OSPFv2.
|
8
|
+
#
|
9
|
+
# OSPFv2 is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# OSPFv2 is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'socket'
|
25
|
+
require 'ipaddr'
|
26
|
+
require 'infra/ospf_constants'
|
27
|
+
|
28
|
+
module OSPFv2
|
29
|
+
|
30
|
+
class SendSocket
|
31
|
+
|
32
|
+
attr_reader :sock
|
33
|
+
|
34
|
+
def initialize(src, options={})
|
35
|
+
@src = src
|
36
|
+
@sock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, IPPROTO_OSPF)
|
37
|
+
add_membership OSPFv2::AllSPFRouters
|
38
|
+
add_membership OSPFv2::AllDRouters
|
39
|
+
rescue Errno::EPERM
|
40
|
+
$stderr.puts "#{e}: You are not root, cannot run: #{$0}!"
|
41
|
+
exit(1)
|
42
|
+
rescue Errno::EADDRNOTAVAIL
|
43
|
+
STDERR.puts "TODO: check if 127/8 and exit if not."
|
44
|
+
# for testing with 127/8
|
45
|
+
rescue Exception => e
|
46
|
+
STDERR.puts "#{e} Cannot Open Socket!"
|
47
|
+
exit(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
#TODO: use all_spf_routers, all_dr_routers, ...
|
51
|
+
# 8.1 Sending protocol packets .............................. 58
|
52
|
+
|
53
|
+
def send(packet, location={:to=> :all_spf_routers})
|
54
|
+
case location
|
55
|
+
when :all_spf_routers ; send_all_spf_routers(packet)
|
56
|
+
when :all_dr_routers ; send_all_dr_routers(packet)
|
57
|
+
else
|
58
|
+
send_to(packet, location[:to])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def send_all_spf_routers
|
63
|
+
_send_ (packet.respond_to?(:encode) ? packet.encode : packet), 0, @sock_addr_all_spf_routers
|
64
|
+
end
|
65
|
+
|
66
|
+
def send_all_dr_routers
|
67
|
+
_send_ (packet.respond_to?(:encode) ? packet.encode : packet), 0, @send_all_dr_routers
|
68
|
+
end
|
69
|
+
|
70
|
+
def send_to(packet, dest)
|
71
|
+
_send_ (packet.respond_to?(:encode) ? packet.encode : packet), 0, Socket.pack_sockaddr_in(0, dest)
|
72
|
+
end
|
73
|
+
|
74
|
+
def send(packet, dest)
|
75
|
+
addr = Socket.pack_sockaddr_in(0, dest)
|
76
|
+
@sock.send((packet.respond_to?(:encode) ? packet.encode : packet),0,addr)
|
77
|
+
end
|
78
|
+
|
79
|
+
def close
|
80
|
+
@sock.close unless @sock.closed?
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def add_membership(group)
|
86
|
+
@sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, (IPAddr.new(group).hton + IPAddr.new(@src).hton))
|
87
|
+
puts "*** ADDED #{group} membership to Send Socket ***"
|
88
|
+
rescue Errno::EADDRNOTAVAIL
|
89
|
+
end
|
90
|
+
|
91
|
+
def _send_(bits, sock_addr)
|
92
|
+
@sock.send(bits,0,addr)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class RecvSocket
|
97
|
+
require 'socket'
|
98
|
+
require 'ipaddr'
|
99
|
+
attr_reader :sock
|
100
|
+
def initialize(src, options={})
|
101
|
+
@src=src
|
102
|
+
@sock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW,89)
|
103
|
+
add_membership OSPFv2::AllSPFRouters
|
104
|
+
add_membership OSPFv2::AllDRouters
|
105
|
+
end
|
106
|
+
def recv(size=8192)
|
107
|
+
begin
|
108
|
+
data, sender = @sock.recvfrom(size)
|
109
|
+
port, host = Socket.unpack_sockaddr_in(sender)
|
110
|
+
[host,port,data]
|
111
|
+
rescue => e
|
112
|
+
STDERR.puts "RSocket recv() error: #{e}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
def close
|
116
|
+
begin ; @sock.close ; rescue ; end
|
117
|
+
@sock=nil
|
118
|
+
end
|
119
|
+
def add_membership(group)
|
120
|
+
@sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, (IPAddr.new(group).hton + IPAddr.new(@src).hton))
|
121
|
+
puts "*** ADDED #{group} membership to Recv Socket ***"
|
122
|
+
rescue Errno::EADDRNOTAVAIL
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|