packetgen 2.4.0 → 2.5.0
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.
- checksums.yaml +5 -5
- data/.travis.yml +13 -4
- data/lib/packetgen.rb +3 -1
- data/lib/packetgen/capture.rb +2 -0
- data/lib/packetgen/config.rb +1 -0
- data/lib/packetgen/header.rb +5 -0
- data/lib/packetgen/header/arp.rb +2 -0
- data/lib/packetgen/header/asn1_base.rb +2 -0
- data/lib/packetgen/header/base.rb +16 -0
- data/lib/packetgen/header/bootp.rb +2 -0
- data/lib/packetgen/header/crypto.rb +2 -0
- data/lib/packetgen/header/dhcp.rb +2 -0
- data/lib/packetgen/header/dhcp/option.rb +3 -0
- data/lib/packetgen/header/dhcp/options.rb +2 -0
- data/lib/packetgen/header/dhcpv6.rb +109 -0
- data/lib/packetgen/header/dhcpv6/duid.rb +147 -0
- data/lib/packetgen/header/dhcpv6/option.rb +391 -0
- data/lib/packetgen/header/dhcpv6/options.rb +29 -0
- data/lib/packetgen/header/dhcpv6/relay.rb +48 -0
- data/lib/packetgen/header/dns.rb +10 -2
- data/lib/packetgen/header/dns/name.rb +7 -0
- data/lib/packetgen/header/dns/opt.rb +6 -0
- data/lib/packetgen/header/dns/option.rb +7 -0
- data/lib/packetgen/header/dns/qdsection.rb +7 -1
- data/lib/packetgen/header/dns/question.rb +7 -0
- data/lib/packetgen/header/dns/rr.rb +7 -0
- data/lib/packetgen/header/dns/rrsection.rb +7 -0
- data/lib/packetgen/header/dot11.rb +4 -2
- data/lib/packetgen/header/dot11/control.rb +2 -0
- data/lib/packetgen/header/dot11/data.rb +2 -0
- data/lib/packetgen/header/dot11/element.rb +2 -0
- data/lib/packetgen/header/dot11/management.rb +2 -0
- data/lib/packetgen/header/dot11/sub_mngt.rb +2 -0
- data/lib/packetgen/header/dot1q.rb +2 -0
- data/lib/packetgen/header/dot1x.rb +3 -1
- data/lib/packetgen/header/eap.rb +3 -1
- data/lib/packetgen/header/eap/fast.rb +2 -0
- data/lib/packetgen/header/eap/md5.rb +2 -0
- data/lib/packetgen/header/eap/tls.rb +2 -0
- data/lib/packetgen/header/eap/ttls.rb +2 -0
- data/lib/packetgen/header/esp.rb +7 -0
- data/lib/packetgen/header/eth.rb +2 -0
- data/lib/packetgen/header/gre.rb +4 -9
- data/lib/packetgen/header/http/headers.rb +2 -0
- data/lib/packetgen/header/http/request.rb +3 -1
- data/lib/packetgen/header/http/response.rb +3 -1
- data/lib/packetgen/header/icmp.rb +4 -11
- data/lib/packetgen/header/icmpv6.rb +4 -11
- data/lib/packetgen/header/igmp.rb +4 -11
- data/lib/packetgen/header/igmpv3.rb +4 -11
- data/lib/packetgen/header/igmpv3/group_record.rb +2 -0
- data/lib/packetgen/header/igmpv3/mq.rb +2 -0
- data/lib/packetgen/header/igmpv3/mr.rb +2 -0
- data/lib/packetgen/header/ike.rb +13 -6
- data/lib/packetgen/header/ike/auth.rb +2 -0
- data/lib/packetgen/header/ike/cert.rb +2 -0
- data/lib/packetgen/header/ike/certreq.rb +2 -0
- data/lib/packetgen/header/ike/id.rb +2 -0
- data/lib/packetgen/header/ike/ke.rb +2 -0
- data/lib/packetgen/header/ike/nonce.rb +2 -0
- data/lib/packetgen/header/ike/notify.rb +7 -0
- data/lib/packetgen/header/ike/payload.rb +9 -0
- data/lib/packetgen/header/ike/sa.rb +11 -4
- data/lib/packetgen/header/ike/sk.rb +7 -0
- data/lib/packetgen/header/ike/ts.rb +2 -0
- data/lib/packetgen/header/ike/vendor_id.rb +2 -0
- data/lib/packetgen/header/ip.rb +48 -11
- data/lib/packetgen/header/ip/addr.rb +8 -0
- data/lib/packetgen/header/ip/option.rb +2 -0
- data/lib/packetgen/header/ip/options.rb +2 -0
- data/lib/packetgen/header/ipv6.rb +5 -3
- data/lib/packetgen/header/ipv6/addr.rb +8 -0
- data/lib/packetgen/header/ipv6/extension.rb +2 -0
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +2 -0
- data/lib/packetgen/header/llc.rb +2 -0
- data/lib/packetgen/header/mld.rb +2 -0
- data/lib/packetgen/header/mldv2.rb +4 -2
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +3 -1
- data/lib/packetgen/header/mldv2/mlq.rb +2 -0
- data/lib/packetgen/header/mldv2/mlr.rb +4 -2
- data/lib/packetgen/header/ospfv2.rb +249 -0
- data/lib/packetgen/header/ospfv2/db_description.rb +105 -0
- data/lib/packetgen/header/ospfv2/hello.rb +104 -0
- data/lib/packetgen/header/ospfv2/ls_ack.rb +55 -0
- data/lib/packetgen/header/ospfv2/ls_request.rb +90 -0
- data/lib/packetgen/header/ospfv2/ls_update.rb +72 -0
- data/lib/packetgen/header/ospfv2/lsa.rb +252 -0
- data/lib/packetgen/header/ospfv2/lsa_header.rb +122 -0
- data/lib/packetgen/header/ospfv3.rb +216 -0
- data/lib/packetgen/header/ospfv3/db_description.rb +114 -0
- data/lib/packetgen/header/ospfv3/hello.rb +104 -0
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +103 -0
- data/lib/packetgen/header/ospfv3/ls_ack.rb +51 -0
- data/lib/packetgen/header/ospfv3/ls_request.rb +108 -0
- data/lib/packetgen/header/ospfv3/ls_update.rb +74 -0
- data/lib/packetgen/header/ospfv3/lsa.rb +252 -0
- data/lib/packetgen/header/ospfv3/lsa_header.rb +123 -0
- data/lib/packetgen/header/snmp.rb +2 -0
- data/lib/packetgen/header/tcp.rb +14 -14
- data/lib/packetgen/header/tcp/option.rb +7 -1
- data/lib/packetgen/header/tcp/options.rb +7 -0
- data/lib/packetgen/header/tftp.rb +2 -0
- data/lib/packetgen/header/udp.rb +6 -14
- data/lib/packetgen/inspect.rb +5 -1
- data/lib/packetgen/packet.rb +3 -1
- data/lib/packetgen/pcapng.rb +2 -0
- data/lib/packetgen/pcapng/block.rb +2 -0
- data/lib/packetgen/pcapng/epb.rb +2 -0
- data/lib/packetgen/pcapng/file.rb +2 -0
- data/lib/packetgen/pcapng/idb.rb +2 -0
- data/lib/packetgen/pcapng/shb.rb +2 -0
- data/lib/packetgen/pcapng/spb.rb +2 -0
- data/lib/packetgen/pcapng/unknown_block.rb +2 -0
- data/lib/packetgen/proto.rb +2 -0
- data/lib/packetgen/types/array.rb +3 -0
- data/lib/packetgen/types/cstring.rb +3 -1
- data/lib/packetgen/types/enum.rb +2 -0
- data/lib/packetgen/types/fields.rb +8 -4
- data/lib/packetgen/types/int.rb +3 -1
- data/lib/packetgen/types/int_string.rb +2 -0
- data/lib/packetgen/types/oui.rb +2 -0
- data/lib/packetgen/types/string.rb +3 -0
- data/lib/packetgen/types/tlv.rb +8 -0
- data/lib/packetgen/utils.rb +6 -4
- data/lib/packetgen/utils/arp_spoofer.rb +2 -0
- data/lib/packetgen/version.rb +3 -1
- metadata +25 -3
@@ -0,0 +1,104 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
module Header
|
10
|
+
class OSPFv3
|
11
|
+
|
12
|
+
# This class handles {OSPFv3 OSPFv3} HELLO packets payload. The HELLO
|
13
|
+
# payload has the following format:
|
14
|
+
# 0 1 2 3
|
15
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
16
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
|
+
# | Interface ID |
|
18
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
|
+
# | Rtr Priority | Options |
|
20
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
21
|
+
# | HelloInterval | RouterDeadInterval |
|
22
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
23
|
+
# | Designated Router ID |
|
24
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
25
|
+
# | Backup Designated Router ID |
|
26
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
27
|
+
# | Neighbor ID |
|
28
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
29
|
+
# | ... |
|
30
|
+
# A HELLO payload consists of:
|
31
|
+
# * a {#interface_id} field ({Types::Int32}),
|
32
|
+
# * a {#priority} field ({Types::Int8}),
|
33
|
+
# * an {#options} field ({Types::Int24}),
|
34
|
+
# * a {#hello_interval} field ({Types::Int16}),
|
35
|
+
# * a {#dead_interval} field ({Types::Int16}),
|
36
|
+
# * a {#designated_router} field ({IP::Addr}),
|
37
|
+
# * a {#backup_designated_router} field ({IP::Addr}),
|
38
|
+
# * a {#neighbors} array containing neighbors as {IP::Addr}.
|
39
|
+
#
|
40
|
+
# == Create a HELLO payload
|
41
|
+
# # standalone
|
42
|
+
# hello = PacketGen::Header::OSPFv3::Hello.new
|
43
|
+
# # in a packet
|
44
|
+
# pkt = PacketGen.gen('IPv6', src: source_ip).add('OSPFv3').add('OSPFv3::Hello')
|
45
|
+
# # make IPv6 header correct for OSPF
|
46
|
+
# pkt.ospfize
|
47
|
+
# # access to Hello payload
|
48
|
+
# pkt.ospfv3_hello # => PacketGen::Header::OSPFv3::Hello
|
49
|
+
#
|
50
|
+
# == HELLO attributes
|
51
|
+
# hello.interface_id = 1
|
52
|
+
# hello.priority = 1
|
53
|
+
# # set options. Options may also be set one by one with #v6_opt, #e_opt,
|
54
|
+
# # #n_opt, #r_opt and #dc_opt
|
55
|
+
# hello.options = 0x33
|
56
|
+
# hello.hello_interval = 10
|
57
|
+
# hello.dead_interval = 300
|
58
|
+
# hello.designated_router = '0.0.0.1'
|
59
|
+
# hello.backup_designated_router = '0.0.0.2'
|
60
|
+
# # set neighbors identifiers
|
61
|
+
# hello.neighbors << '1.1.1.1'
|
62
|
+
# hello.neighbors << '2.2.2.2'
|
63
|
+
# @author Sylvain Daubert
|
64
|
+
class Hello < Base
|
65
|
+
# @!attribute interface_id
|
66
|
+
# The network mask associated with this interface.
|
67
|
+
# @return [String]
|
68
|
+
define_field :interface_id, Types::Int32
|
69
|
+
# @!attribute priority
|
70
|
+
# This router's Router Priority. Used in (Backup) Designated
|
71
|
+
# Router election.
|
72
|
+
# @return [Integer]
|
73
|
+
define_field :priority, Types::Int8
|
74
|
+
# @!macro define_ospfv3_options
|
75
|
+
OSPFv3.define_options(self)
|
76
|
+
# @!attribute hello_interval
|
77
|
+
# The number of seconds between this router's Hello packets.
|
78
|
+
# @return [Integer]
|
79
|
+
define_field :hello_interval, Types::Int16
|
80
|
+
# @!attribute dead_interval
|
81
|
+
# The number of seconds before declaring a silent router down.
|
82
|
+
# @return [Integer]
|
83
|
+
define_field :dead_interval, Types::Int16
|
84
|
+
# @!attribute designated_router
|
85
|
+
# The identity of the Designated Router for this network, in the
|
86
|
+
# view of the sending router.
|
87
|
+
# @return [String]
|
88
|
+
define_field :designated_router, IP::Addr
|
89
|
+
# @!attribute backup_designated_router
|
90
|
+
# The identity of the Backup Designated Router for this network,
|
91
|
+
# in the view of the sending router.
|
92
|
+
# @return [String]
|
93
|
+
define_field :backup_designated_router, IP::Addr
|
94
|
+
# @!attribute neighbors
|
95
|
+
# Array of neighbors
|
96
|
+
# @return [IP::ArrayOfAddr]
|
97
|
+
define_field :neighbors, IP::ArrayOfAddr
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
self.add_class OSPFv3::Hello
|
102
|
+
OSPFv3.bind_header OSPFv3::Hello, type: OSPFv3::TYPES['HELLO']
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
module Header
|
10
|
+
class OSPFv3
|
11
|
+
|
12
|
+
# Array of 32-bit words.
|
13
|
+
# @author Sylvain Daubert
|
14
|
+
class ArrayOfInt32 < Types::Array
|
15
|
+
set_of Types::Int32
|
16
|
+
end
|
17
|
+
|
18
|
+
# This class handles IPv6 prefixes, as defined in RFC 5340 §A.4.1.
|
19
|
+
# A IPv6 prefix consists of:
|
20
|
+
# * a 8-bit {#length} field (length of the prefix, in bits),
|
21
|
+
# * a 8-bit {#options} field, giving prefix capabilities,
|
22
|
+
# * a 16-bit {#reserved} field (but it may be used in some LSA),
|
23
|
+
# * and an array of 32-bit words to encode prefix itself ({#prefix}). This
|
24
|
+
# array consumes ((PrefixLength + 31) / 32) 32-bit words.
|
25
|
+
# @author Sylvain Daubert
|
26
|
+
class IPv6Prefix < Types::Fields
|
27
|
+
# @!attribute length
|
28
|
+
# Prefix length, in bits
|
29
|
+
# @return [Integer]
|
30
|
+
define_field :length, Types::Int8
|
31
|
+
# @!attribute options
|
32
|
+
# Prefix capabilities. See also capability bits: {#dn_opt}, {#p_opt},
|
33
|
+
# {#la_opt} and {#nu_opt}.
|
34
|
+
# @return [Options]
|
35
|
+
define_field :options, Types::Int8
|
36
|
+
# @!attribute reserved
|
37
|
+
# Reserved field in most of LSA types.
|
38
|
+
# @return [Integer]
|
39
|
+
define_field :reserved, Types::Int16
|
40
|
+
# @!attribute prefix
|
41
|
+
# IPv6 Prefix as an array of 32-bit words
|
42
|
+
# @return [Prefix]
|
43
|
+
define_field :prefix, ArrayOfInt32
|
44
|
+
|
45
|
+
# @!attribute dn_opt
|
46
|
+
# This bit controls an inter-area-prefix-LSAs or AS-external-LSAs
|
47
|
+
# re-advertisement in a VPN environment.
|
48
|
+
# @return [Boolean]
|
49
|
+
# @!attribute p_opt
|
50
|
+
# The "propagate" bit. Set on NSSA area prefixes that should be
|
51
|
+
# readvertised by the translating NSSA area border.
|
52
|
+
# @return [Boolean]
|
53
|
+
# @!attribute la_opt
|
54
|
+
# The "local address" capability bit. If set, the prefix is
|
55
|
+
# actually an IPv6 interface address of the Advertising Router.
|
56
|
+
# @return [Boolean]
|
57
|
+
# @!attribute nu_opt
|
58
|
+
# The "no unicast" capability bit. If set, the prefix should be
|
59
|
+
# excluded from IPv6 unicast calculations.
|
60
|
+
# @return [Boolean]
|
61
|
+
define_bit_fields_on :options, :zz, 3, :dn_opt, :p_opt, :z, :la_opt, :nu_opt
|
62
|
+
|
63
|
+
# Get human-readable prefix
|
64
|
+
# @return [String]
|
65
|
+
def to_human
|
66
|
+
ary = prefix.map(&:to_i).map do |v|
|
67
|
+
"#{((v>>16) & 0xffff).to_s(16)}:#{(v & 0xffff).to_s(16)}"
|
68
|
+
end
|
69
|
+
pfx = ary.join(':')
|
70
|
+
pfx += '::' if prefix.size < (128/32)
|
71
|
+
"#{IPAddr.new(pfx).to_s}/#{length}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set prefix from a human-readable string. This method cannot set
|
75
|
+
# {#options} field.
|
76
|
+
# @param [String] str
|
77
|
+
# @return [void]
|
78
|
+
def from_human(str)
|
79
|
+
pfx, len = str.split('/')
|
80
|
+
len = (len || 128).to_i
|
81
|
+
addr = IPv6::Addr.new.from_human(pfx)
|
82
|
+
ary_size = (len + 31) / 32
|
83
|
+
ary = addr.to_a[0...ary_size*2]
|
84
|
+
self.prefix.clear
|
85
|
+
ary.each_with_index do |v, i|
|
86
|
+
if i % 2 == 0
|
87
|
+
self.prefix << v
|
88
|
+
else
|
89
|
+
self.prefix.last.value = (self.prefix.last.to_i << 16) | v.to_i
|
90
|
+
end
|
91
|
+
end
|
92
|
+
self.length = len
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Array of {IPv6Prefix}
|
97
|
+
# @author Sylvain Daubert
|
98
|
+
class ArrayOfIPv6Prefix < Types::Array
|
99
|
+
set_of IPv6Prefix
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
module Header
|
10
|
+
class OSPFv3
|
11
|
+
|
12
|
+
# This class handles {OSPFv3 OSPFv3} Link State Acknownledgment packets
|
13
|
+
# payload. The LSAck payload has the following format:
|
14
|
+
# 0 1 2 3
|
15
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
16
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
|
+
# | |
|
18
|
+
# +- +-+
|
19
|
+
# | LSAs |
|
20
|
+
# +- +-+
|
21
|
+
# | ... |
|
22
|
+
#
|
23
|
+
# This paylod is implemented with only one field:
|
24
|
+
# * {#lsas}, an {ArrayOfLSA} object.
|
25
|
+
#
|
26
|
+
# == Create a LSAck payload
|
27
|
+
# # standalone
|
28
|
+
# lsack = PacketGen::Header::OSPFv3::LSAck.new
|
29
|
+
# # in a packet
|
30
|
+
# pkt = PacketGen.gen('IPv6', src: source_ip).add('OSPFv3').add('OSPFv3::LSAck')
|
31
|
+
# # access to LSAck payload
|
32
|
+
# lasck = pkt.ospfv3_lsack # => PacketGen::Header::OSPFv3::LSAck
|
33
|
+
#
|
34
|
+
# == Adding LSA headers to a LSAck payload
|
35
|
+
# lsack.lsas << { type: 'Router', age: 40, link_state_id: '0.0.0.1', advertising_router: '1.1.1.1', sequence_number: 42, checksum: 0x1234, length: 56 }
|
36
|
+
# # a header may also be set from an existing lsa
|
37
|
+
# lasck.lsas << existing_lsa.to_lsa_header
|
38
|
+
# @author Sylvain Daubert
|
39
|
+
class LSAck < Base
|
40
|
+
# @!attribute lsas
|
41
|
+
# Array of {LSA LSAs}
|
42
|
+
# @return [ArrayOfLSA]
|
43
|
+
define_field :lsas, ArrayOfLSA,
|
44
|
+
builder: ->(h, t) { t.new(only_headers: true) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
self.add_class OSPFv3::LSAck
|
49
|
+
OSPFv3.bind_header OSPFv3::LSAck, type: OSPFv3::TYPES['LS_ACK']
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
module Header
|
10
|
+
class OSPFv3
|
11
|
+
|
12
|
+
# This class handle LSA requests, as used in {LSRequest} payloads.
|
13
|
+
# The LSA request payload has the following format:
|
14
|
+
# 0 1 2 3
|
15
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
16
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
|
+
# | 0 | LS Type |
|
18
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
|
+
# | Link State ID |
|
20
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
21
|
+
# | Advertising Router |
|
22
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
23
|
+
#
|
24
|
+
# It is composed of:
|
25
|
+
# * a 16-bit {#reserved} field,
|
26
|
+
# * a 16-bit {#type} field,
|
27
|
+
# * a 32-bit {#link_state_id} field,
|
28
|
+
# * and a 32-bit {#advertising_router} field.
|
29
|
+
# @author Sylvain Daubert
|
30
|
+
class LSR < Types::Fields
|
31
|
+
# @!attribute reserved
|
32
|
+
# reserved field.
|
33
|
+
# @return [Integer]
|
34
|
+
define_field :reserved, Types::Int16, default: 0
|
35
|
+
# @!attribute type
|
36
|
+
# The type of the LSA to request.
|
37
|
+
# @return [Integer]
|
38
|
+
define_field :type, Types::Int16Enum, enum: LSAHeader::TYPES
|
39
|
+
# @!attribute link_state_id
|
40
|
+
# This field identifies the portion of the internet environment
|
41
|
+
# that is being described by the LSA to request.
|
42
|
+
# @return [String]
|
43
|
+
define_field :link_state_id, IP::Addr
|
44
|
+
# @!attribute advertising_router
|
45
|
+
# The Router ID of the requested LSA.
|
46
|
+
# @return [String]
|
47
|
+
define_field :advertising_router, IP::Addr
|
48
|
+
|
49
|
+
# Get human-readable type
|
50
|
+
# @return [String]
|
51
|
+
def human_type
|
52
|
+
self[:type].to_human
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String]
|
56
|
+
def to_human
|
57
|
+
"LSR<#{human_type},#{link_state_id},#{advertising_router}>"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# This class defines a specialized {Types::Array array} to handle series
|
62
|
+
# of {LSR LSRs}.
|
63
|
+
# @author Sylvain Daubert
|
64
|
+
class ArrayOfLSR < Types::Array
|
65
|
+
set_of LSR
|
66
|
+
end
|
67
|
+
|
68
|
+
# This class handles {OSPFv3 OSPFv3} Link State Request packets
|
69
|
+
# payload. The LSR payload has the following format:
|
70
|
+
# 0 1 2 3
|
71
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
72
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
73
|
+
# | 0 | LS Type |
|
74
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
75
|
+
# | Link State ID |
|
76
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
77
|
+
# | Advertising Router |
|
78
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
79
|
+
# | ... |
|
80
|
+
#
|
81
|
+
# This paylod is implemented as a unique field: {#lsrs}, which is an
|
82
|
+
# {ArrayOfLSR} object.
|
83
|
+
#
|
84
|
+
# == Create a LSRequest payload
|
85
|
+
# # standalone
|
86
|
+
# lsr = PacketGen::Header::OSPFv3::LSRequest.new
|
87
|
+
# # in a packet
|
88
|
+
# pkt = PacketGen.gen('IPv6', src: source_ip).add('OSPFv3').add('OSPFv3::LSRequest')
|
89
|
+
# # make IPv6 header correct for OSPF
|
90
|
+
# pkt.ospfize
|
91
|
+
# # access to LSRequest payload
|
92
|
+
# pkt.ospfv3_lsrequest # => PacketGen::Header::OSPFv3::LSRequest
|
93
|
+
#
|
94
|
+
# == Add LSA requests to a LSRequest
|
95
|
+
# lsr.lsrs << { type: 'Router', link_state_id: '0.0.0.1', advertising_router: '1.1.1.1'}
|
96
|
+
# @author Sylvain Daubert
|
97
|
+
class LSRequest < Base
|
98
|
+
# @!attribute lsrs
|
99
|
+
# Array of {LSR}
|
100
|
+
# @return [ArrayOfLSR]
|
101
|
+
define_field :lsrs, ArrayOfLSR
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
self.add_class OSPFv3::LSRequest
|
106
|
+
OSPFv3.bind_header OSPFv3::LSRequest, type: OSPFv3::TYPES['LS_REQUEST']
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
module Header
|
10
|
+
class OSPFv3
|
11
|
+
|
12
|
+
# This class handles {OSPFv3 OSPFv3} Link State Update packets
|
13
|
+
# payload. The LSU payload has the following format:
|
14
|
+
# 0 1 2 3
|
15
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
16
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
|
+
# | # LSAs |
|
18
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
|
+
# | |
|
20
|
+
# +- +-+
|
21
|
+
# | LSAs |
|
22
|
+
# +- +-+
|
23
|
+
# | ... |
|
24
|
+
#
|
25
|
+
# This paylod is implemented with two fields:
|
26
|
+
# * {#lsas_count}, a {Types::Int32} field,
|
27
|
+
# * and {#lsas}, an {ArrayOfLSA} object.
|
28
|
+
#
|
29
|
+
# == Create a LSUpdate payload
|
30
|
+
# # standalone
|
31
|
+
# lsu = PacketGen::Header::OSPFv3::LSUpdate.new
|
32
|
+
# # in a packet
|
33
|
+
# pkt = PacketGen.gen('IPv6', src: source_ip).add('OSPFv3').add('OSPFv3::LSUpdate')
|
34
|
+
# # make IPv6 header correct for OSPF
|
35
|
+
# pkt.ospfize
|
36
|
+
# # access to LSUpdate payload
|
37
|
+
# lsu = pkt.ospfv3_lsupdate # => PacketGen::Header::OSPFv3::LSUpdate
|
38
|
+
#
|
39
|
+
# == Add LSAs to a LSUpdate payload
|
40
|
+
# Adding LSAs with {ArrayOfLSA#<< ArrayOfLSA#<<} automagically update
|
41
|
+
# {#lsas_count}. To not update it, use {ArrayOfLSA#push ArrayOfLSA#push}.
|
42
|
+
# lsu.lsas << { type: 'Router', age: 40, link_state_id: '0.0.0.1', advertising_router: '1.1.1.1', sequence_number: 42 }
|
43
|
+
# lsu.lsas_count #=> 1
|
44
|
+
# # add a link to Router LSA
|
45
|
+
# lsu.lsas.first.links << { type: 1, metric: 10, interface_id: 1, neighbor_interface_id: 2, neighbor_router_id: '2.2.2.2'}
|
46
|
+
# @author Sylvain Daubert
|
47
|
+
class LSUpdate < Base
|
48
|
+
# @!attribute lsas_count
|
49
|
+
# Count of LSAs included in this update
|
50
|
+
# @return [Integer]
|
51
|
+
define_field :lsas_count, Types::Int32
|
52
|
+
# @!attribute lsas
|
53
|
+
# Array of {LSA LSAs}
|
54
|
+
# @return [ArrayOfLSA]
|
55
|
+
define_field :lsas, ArrayOfLSA,
|
56
|
+
builder: ->(h, t) { t.new(counter: h[:lsas_count]) }
|
57
|
+
|
58
|
+
# Calculate checksums of all LSAs
|
59
|
+
# @return [void]
|
60
|
+
def calc_checksum
|
61
|
+
lsas.each { |lsa| lsa.calc_checksum }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Calculate length of all LSAs
|
65
|
+
def calc_length
|
66
|
+
lsas.each { |lsa| lsa.calc_length }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
self.add_class OSPFv3::LSUpdate
|
72
|
+
OSPFv3.bind_header OSPFv3::LSUpdate, type: OSPFv3::TYPES['LS_UPDATE']
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
module Header
|
10
|
+
class OSPFv3
|
11
|
+
|
12
|
+
# This class handles links in a {LSARouter OSPFv3 LSA router payload}.
|
13
|
+
# @author Sylvain Daubert
|
14
|
+
class Link < Types::Fields
|
15
|
+
# @!attribute type
|
16
|
+
# @return [Integer]
|
17
|
+
define_field :type, Types::Int8
|
18
|
+
# @!attribute reserved
|
19
|
+
# @return [Integer]
|
20
|
+
define_field :reserved, Types::Int8, default: 0
|
21
|
+
# @!attribute metric
|
22
|
+
# @return [Integer]
|
23
|
+
define_field :metric, Types::Int16
|
24
|
+
# @!attribute interface_id
|
25
|
+
# @return [Integer]
|
26
|
+
define_field :interface_id, Types::Int32
|
27
|
+
# @!attribute neighbor_interface_id
|
28
|
+
# @return [Integer]
|
29
|
+
define_field :neighbor_interface_id, Types::Int32
|
30
|
+
# @!attribute neighbor_router_id
|
31
|
+
# @return [String]
|
32
|
+
define_field :neighbor_router_id, IP::Addr
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
def to_human
|
36
|
+
"Link<type:#{type},metric:#{metric},id:#{interface_id}," \
|
37
|
+
"neighbor_id:#{neighbor_interface_id},neighbor_router:#{neighbor_router_id}>"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# This class defines a specialized {Types::Array array} to handle series
|
42
|
+
# of {Link Links}.
|
43
|
+
# @author Sylvain Daubert
|
44
|
+
class ArrayOfLink < Types::Array
|
45
|
+
set_of Link
|
46
|
+
end
|
47
|
+
|
48
|
+
# This class handles unsupported {OSPFv3 OSPFv3} LSA payloads.
|
49
|
+
# A LSA payload is a {LSAHeader} with a {#body} field.
|
50
|
+
# @author Sylvain Daubert
|
51
|
+
class LSA < LSAHeader
|
52
|
+
# @!attribute body
|
53
|
+
# LSA body
|
54
|
+
# @return [String]
|
55
|
+
define_field :body, Types::String,
|
56
|
+
builder: ->(h,t) { t.new(length_from: ->() { h.length - 20 }) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# This class handles OSPFv3 LSA Router payloads.
|
60
|
+
#
|
61
|
+
# A LSA router payload is composed of:
|
62
|
+
# * a header (see methods inherited from {LSAHeader}),
|
63
|
+
# * a 8-bit flag word {#flags} ({Types::Int8}),
|
64
|
+
# * a 24-bit {#options} field ({Types::Int24}),
|
65
|
+
# * and an array of {#links} ({ArrayOfLink}).
|
66
|
+
# @author Sylvain Daubert
|
67
|
+
class LSARouter < LSAHeader
|
68
|
+
# @attribute flags
|
69
|
+
# 8-bit flag word
|
70
|
+
# @return [Integer]
|
71
|
+
define_field :flags, Types::Int8
|
72
|
+
# @!macro define_ospfv3_options
|
73
|
+
OSPFv3.define_options(self)
|
74
|
+
# @attribute links
|
75
|
+
# @return [ArrayOfLink]
|
76
|
+
define_field :links, ArrayOfLink
|
77
|
+
|
78
|
+
# @!attribute nt_flag
|
79
|
+
# @return [Boolean]
|
80
|
+
# @!attribute v_flag
|
81
|
+
# @return [Boolean]
|
82
|
+
# @!attribute e_flag
|
83
|
+
# @return [Boolean]
|
84
|
+
# @!attribute b_flag
|
85
|
+
# @return [Boolean]
|
86
|
+
define_bit_fields_on :flags, :zz, 3, :nt_flag, :x_flag, :v_flag, :e_flag,
|
87
|
+
:b_flag
|
88
|
+
end
|
89
|
+
|
90
|
+
# This class handles OSPFv3 LSA Network payloads.
|
91
|
+
#
|
92
|
+
# A LSA network payload is composed of:
|
93
|
+
# * a header (see methods inherited from {LSAHeader}),
|
94
|
+
# * a 8-bit {#reserved} field,
|
95
|
+
# * a 24-bit {#options} field,
|
96
|
+
# * and an array of router IDs ({#routers}, {IP::ArrayOfAddr}).
|
97
|
+
# @author Sylvain Daubert
|
98
|
+
class LSANetwork < LSAHeader
|
99
|
+
# @!attribute reserved
|
100
|
+
# @return [Integer]
|
101
|
+
define_field :reserved, Types::Int8
|
102
|
+
# @!macro define_ospfv3_options
|
103
|
+
OSPFv3.define_options(self)
|
104
|
+
# @!attribute routers
|
105
|
+
# List of routers attached to the link.
|
106
|
+
# @return [IP::ArrayOfAddr]
|
107
|
+
define_field :routers, IP::ArrayOfAddr
|
108
|
+
end
|
109
|
+
|
110
|
+
# This class handles OSPFv3 LSA Intra-Area-Prefix payloads.
|
111
|
+
#
|
112
|
+
# An Intra-Area-Prefix payloads is composed of:
|
113
|
+
# * a 16-bit {#prefix_count} field ({Types::Int16}),
|
114
|
+
# * a 16-bit {#ref_ls_type} field ({Types::Int16Enum}),
|
115
|
+
# * a 32-bit {#ref_link_state_id} ({IP::Addr}),
|
116
|
+
# * a 32-bit {#ref_advertising_router} ({IP::Addr}),
|
117
|
+
# * and an array of {IPv6Prefix} ({#prefixes}, {ArrayOfIPv6Prefix}). In
|
118
|
+
# this array, {IPv6Prefix#reserved} is used as +metric+ value.
|
119
|
+
# @author Sylvain Daubert
|
120
|
+
class LSAIntraAreaPrefix < LSAHeader
|
121
|
+
# @!attribute prefix_count
|
122
|
+
# The number of IPv6 address prefixes contained in the LSA.
|
123
|
+
# @return [Integer]
|
124
|
+
define_field :prefix_count, Types::Int16
|
125
|
+
# @!attribute ref_ls_type
|
126
|
+
# Used to identify the router-LSA or network-LSA with which the IPv6
|
127
|
+
# address prefixes should be associated, in association with
|
128
|
+
# {#ref_link_state_id} and {#ref_advertising_router}.
|
129
|
+
# @return [Integer]
|
130
|
+
define_field :ref_ls_type, Types::Int16Enum, enum: TYPES
|
131
|
+
# @!attribute ref_link_state_id
|
132
|
+
# Used to identify the router-LSA or network-LSA with which the IPv6
|
133
|
+
# address prefixes should be associated, in association with
|
134
|
+
# {#ref_ls_type} and {#ref_advertising_router}.
|
135
|
+
# @return [String]
|
136
|
+
define_field :ref_link_state_id, IP::Addr
|
137
|
+
# @!attribute ref_advertising_router
|
138
|
+
# Used to identify the router-LSA or network-LSA with which the IPv6
|
139
|
+
# address prefixes should be associated, in association with
|
140
|
+
# {#ref_link_state_id} and {#ref_ls_type}.
|
141
|
+
# @return [String]
|
142
|
+
define_field :ref_advertising_router, IP::Addr
|
143
|
+
# @!attribute prefixes
|
144
|
+
# Array of {IPv6Prefix}. Note for this LSA, {IPv6Prefix#reserved} is
|
145
|
+
# used as +metric+ value.
|
146
|
+
# @return [ArrayOfIPv6Prefix]
|
147
|
+
define_field :prefixes, ArrayOfIPv6Prefix,
|
148
|
+
builder: ->(h, t) { t.new(counter: h[:prefix_count]) }
|
149
|
+
end
|
150
|
+
|
151
|
+
# This class handles OSPFv3 LSA Link payloads.
|
152
|
+
#
|
153
|
+
# A Link payloads is composed of:
|
154
|
+
# * a 8-bit {#router_priority} field ({Types::Int8}),
|
155
|
+
# * a 24-bit {#options} field ({Types::Int24}),
|
156
|
+
# * a 128-bit IPv6 {#interface_addr} ({IPv6::Addr}),
|
157
|
+
# * a 32-bit {#prefix_count} field ({Types::Int32}),
|
158
|
+
# * and an array of {IPv6Prefix} ({#prefixes}, {ArrayOfIPv6Prefix}).
|
159
|
+
# @author Sylvain Daubert
|
160
|
+
class LSALink < LSAHeader
|
161
|
+
# @!attribute router_priority
|
162
|
+
# The Router Priority of the interface attaching the originating
|
163
|
+
# router to the link.
|
164
|
+
# @return [Integer]
|
165
|
+
define_field :router_priority, Types::Int8
|
166
|
+
# @!macro define_ospfv3_options
|
167
|
+
OSPFv3.define_options(self)
|
168
|
+
# @!attribute interface_addr
|
169
|
+
# The originating router's link-local interface address on the link.
|
170
|
+
# @return [String]
|
171
|
+
define_field :interface_addr, IPv6::Addr
|
172
|
+
# @!attribute prefix_count
|
173
|
+
# The number of IPv6 address prefixes contained in the LSA.
|
174
|
+
# @return [Integer]
|
175
|
+
define_field :prefix_count, Types::Int32
|
176
|
+
# @!attribute prefixes
|
177
|
+
# List of IPv6 prefixes to be associated with the link.
|
178
|
+
# @return [ArrayOfIPv6Prefix]
|
179
|
+
define_field :prefixes, ArrayOfIPv6Prefix
|
180
|
+
end
|
181
|
+
|
182
|
+
# This class defines a specialized {Types::Array array} to handle series
|
183
|
+
# of {LSA LSAs} or {LSAHeader LSAHeaders}. It recognizes known LSA types
|
184
|
+
# and infers correct type.
|
185
|
+
# @author Sylvain Daubert
|
186
|
+
class ArrayOfLSA < Types::Array
|
187
|
+
set_of LSA
|
188
|
+
|
189
|
+
# @param [Hash] options
|
190
|
+
# @option options [Types::Int] counter Int object used as a counter for this set
|
191
|
+
# @option options [Boolean] only_headers if +true+, only {LSAHeader LSAHeaders}
|
192
|
+
# will be added to this array.
|
193
|
+
def initialize(options={})
|
194
|
+
super
|
195
|
+
@only_headers = options[:only_headers] || false
|
196
|
+
end
|
197
|
+
|
198
|
+
# Populate object from a string
|
199
|
+
# @param [String] str
|
200
|
+
# @return [self]
|
201
|
+
def read(str)
|
202
|
+
clear
|
203
|
+
return self if str.nil?
|
204
|
+
return self if @counter and @counter.to_i == 0
|
205
|
+
force_binary str
|
206
|
+
while str.length > 0
|
207
|
+
lsa = LSAHeader.new.read(str)
|
208
|
+
if !@only_headers
|
209
|
+
klass = get_lsa_class_by_human_type(lsa.human_type)
|
210
|
+
lsa = klass.new.read(str[0...lsa.length])
|
211
|
+
end
|
212
|
+
self.push lsa
|
213
|
+
str.slice!(0, lsa.sz)
|
214
|
+
break if @counter and self.size == @counter.to_i
|
215
|
+
end
|
216
|
+
self
|
217
|
+
end
|
218
|
+
|
219
|
+
private
|
220
|
+
|
221
|
+
def record_from_hash(hsh)
|
222
|
+
unless hsh.has_key? :type
|
223
|
+
raise ArgumentError, "hash should have :type key"
|
224
|
+
end
|
225
|
+
|
226
|
+
klass = if @only_headers
|
227
|
+
LSAHeader
|
228
|
+
else
|
229
|
+
case hsh[:type]
|
230
|
+
when String
|
231
|
+
get_lsa_class_by_human_type(hsh[:type])
|
232
|
+
when Integer
|
233
|
+
get_lsa_class_by_human_type(LSAHeader::TYPES.key(hsh[:type]))
|
234
|
+
else
|
235
|
+
LSA
|
236
|
+
end
|
237
|
+
end
|
238
|
+
klass.new(hsh)
|
239
|
+
end
|
240
|
+
|
241
|
+
def get_lsa_class_by_human_type(htype)
|
242
|
+
klassname = "LSA#{htype.to_s.gsub(/-/, '')}"
|
243
|
+
if OSPFv3.const_defined? klassname
|
244
|
+
OSPFv3.const_get klassname
|
245
|
+
else
|
246
|
+
LSA
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|