packetgen 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +5 -1
- data/lib/packetgen/header.rb +4 -0
- data/lib/packetgen/header/icmpv6.rb +0 -1
- data/lib/packetgen/header/igmp.rb +126 -0
- data/lib/packetgen/header/igmpv3.rb +150 -0
- data/lib/packetgen/header/igmpv3/group_record.rb +98 -0
- data/lib/packetgen/header/igmpv3/mq.rb +96 -0
- data/lib/packetgen/header/igmpv3/mr.rb +65 -0
- data/lib/packetgen/header/ip.rb +40 -70
- data/lib/packetgen/header/ip/addr.rb +58 -0
- data/lib/packetgen/header/ip/option.rb +194 -0
- data/lib/packetgen/header/ip/options.rb +53 -0
- data/lib/packetgen/header/ipv6.rb +24 -69
- data/lib/packetgen/header/ipv6/addr.rb +96 -0
- data/lib/packetgen/header/ipv6/extension.rb +65 -0
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +132 -0
- data/lib/packetgen/header/mld.rb +100 -0
- data/lib/packetgen/header/mldv2.rb +50 -0
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +103 -0
- data/lib/packetgen/header/mldv2/mlq.rb +144 -0
- data/lib/packetgen/header/mldv2/mlr.rb +65 -0
- data/lib/packetgen/packet.rb +18 -0
- data/lib/packetgen/types/array.rb +1 -0
- data/lib/packetgen/types/string.rb +14 -13
- data/lib/packetgen/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d08bf3611fcb1af6c5e794d4582fe373b4887c02
|
4
|
+
data.tar.gz: 7149de75ef5a5ebaca9d9b90239ffce8619c38c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82804e0c46bc17d30c6bc151a24b3fc415c476aa1159239330611d2b8ef3ef7d2013dc7078bb40e298d29c0e81f3e758f53e82ff280acc0548b37dc78ff7d8be
|
7
|
+
data.tar.gz: 6f4c84f64e8728af30a61d56b22dce9eb34fa574984eafe427d48cebdac1446344f1f5dd37370604d58b9df4bb1af587135348ad682e15d3ce97d45cfd769ed1
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -7,7 +7,11 @@
|
|
7
7
|
PacketGen provides simple ways to generate, send and capture network packets.
|
8
8
|
|
9
9
|
## Installation
|
10
|
-
|
10
|
+
PacketGen depends on PcapRub, which needs pcap development files to install. On Debian, you have to do:
|
11
|
+
|
12
|
+
$ sudo apt install libpcap-dev
|
13
|
+
|
14
|
+
Installation using RubyGems is then easy:
|
11
15
|
|
12
16
|
$ gem install packetgen
|
13
17
|
|
data/lib/packetgen/header.rb
CHANGED
@@ -103,3 +103,7 @@ require_relative 'header/bootp'
|
|
103
103
|
require_relative 'header/dhcp'
|
104
104
|
require_relative 'header/http'
|
105
105
|
require_relative 'header/tftp'
|
106
|
+
require_relative 'header/igmp'
|
107
|
+
require_relative 'header/igmpv3'
|
108
|
+
require_relative 'header/mld'
|
109
|
+
require_relative 'header/mldv2'
|
@@ -0,0 +1,126 @@
|
|
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
|
+
module PacketGen
|
7
|
+
module Header
|
8
|
+
|
9
|
+
# This class supports IGMPv2 (RFC 2236).
|
10
|
+
#
|
11
|
+
# From RFC 2236, a IGMP header has the following format:
|
12
|
+
# 0 1 2 3
|
13
|
+
# 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
|
14
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
15
|
+
# | Type | Max Resp Time | Checksum |
|
16
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
|
+
# | Group Address |
|
18
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
|
+
#
|
20
|
+
# A IGMP header consists of:
|
21
|
+
# * a {#type} field ({Types::Int8Enum} type),
|
22
|
+
# * a {#max_resp_time} field ({Types::Int8} type),
|
23
|
+
# * a {#checksum} field ({Types::Int16} type),
|
24
|
+
# * a {#group_addr} field ({Header::IP::Addr} type),
|
25
|
+
# * and a {#body} (unused for IGMPv2).
|
26
|
+
#
|
27
|
+
# == Create a IGMP header
|
28
|
+
# # standalone
|
29
|
+
# igmp = PacketGen::Header::IGMP.new
|
30
|
+
# # in a packet
|
31
|
+
# pkt = PacketGen.gen('IP').add('IGMP')
|
32
|
+
# # access to IGMP header
|
33
|
+
# pkt.igmp # => PacketGen::Header::IGMP
|
34
|
+
#
|
35
|
+
# == IGMP attributes
|
36
|
+
# icmp.type = 'MembershipQuery' # or 0x11
|
37
|
+
# icmp.max_resp_time = 20
|
38
|
+
# icmp.checksum = 0x248a
|
39
|
+
# icmp.group_addr = '224.0.0.1'
|
40
|
+
# @author Sylvain Daubert
|
41
|
+
class IGMP < Base
|
42
|
+
|
43
|
+
# IGMP internet protocol number
|
44
|
+
IP_PROTOCOL = 2
|
45
|
+
|
46
|
+
# Known types
|
47
|
+
TYPES = {
|
48
|
+
'MembershipQuery' => 0x11,
|
49
|
+
'MembershipReportv1' => 0x12,
|
50
|
+
'MembershipReportv2' => 0x16,
|
51
|
+
'LeaveGroup' => 0x17,
|
52
|
+
}
|
53
|
+
|
54
|
+
# @!attribute type
|
55
|
+
# 8-bit IGMP Type
|
56
|
+
# @return [Integer]
|
57
|
+
define_field :type, Types::Int8Enum, enum: TYPES
|
58
|
+
# @!attribute max_resp_time
|
59
|
+
# 8-bit IGMP Max Response Time
|
60
|
+
# @return [Integer]
|
61
|
+
define_field :max_resp_time, Types::Int8
|
62
|
+
# @!attribute checksum
|
63
|
+
# 16-bit IGMP Checksum
|
64
|
+
# @return [Integer]
|
65
|
+
define_field :checksum, Types::Int16
|
66
|
+
# @!attribute group_addr
|
67
|
+
# IP Group address
|
68
|
+
# @return [IP::Addr]
|
69
|
+
define_field :group_addr, IP::Addr, default: '0.0.0.0'
|
70
|
+
# @!attribute body
|
71
|
+
# @return [String,Base]
|
72
|
+
define_field :body, Types::String
|
73
|
+
|
74
|
+
# @api private
|
75
|
+
# @note This method is used internally by PacketGen and should not be
|
76
|
+
# directly called
|
77
|
+
def added_to_packet(packet)
|
78
|
+
igmp_idx = packet.headers.size
|
79
|
+
packet.instance_eval "def igmpize() @headers[#{igmp_idx}].igmpize; end"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get human readbale type
|
83
|
+
# @return [String]
|
84
|
+
def human_type
|
85
|
+
self[:type].to_human
|
86
|
+
end
|
87
|
+
|
88
|
+
# Compute checksum and set +checksum+ field
|
89
|
+
# @return [Integer]
|
90
|
+
def calc_checksum
|
91
|
+
sum = (type << 8) | max_resp_time
|
92
|
+
|
93
|
+
payload = self[:group_addr].to_s + body.to_s
|
94
|
+
payload << "\x00" unless payload.size % 2 == 0
|
95
|
+
payload.unpack('n*').each { |x| sum += x; }
|
96
|
+
|
97
|
+
while sum > 0xffff do
|
98
|
+
sum = (sum & 0xffff) + (sum >> 16)
|
99
|
+
end
|
100
|
+
sum = ~sum & 0xffff
|
101
|
+
self[:checksum].value = (sum == 0) ? 0xffff : sum
|
102
|
+
end
|
103
|
+
|
104
|
+
# Fixup IP header according to RFC 2236:
|
105
|
+
# * set TTL to 1,
|
106
|
+
# * add Router Alert option,
|
107
|
+
# * recalculate checksum and length.
|
108
|
+
# This method may be called as:
|
109
|
+
# # first method
|
110
|
+
# pkt.igmp.igmpize
|
111
|
+
# # second method
|
112
|
+
# pkt.igmpize
|
113
|
+
# @return [void]
|
114
|
+
def igmpize
|
115
|
+
iph = ip_header(self)
|
116
|
+
iph.ttl = 1
|
117
|
+
iph.options << IP::RA.new
|
118
|
+
packet.calc
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
self.add_class IGMP
|
123
|
+
IP.bind_header IGMP, op: :and, protocol: IGMP::IP_PROTOCOL, frag: 0, ttl: 1,
|
124
|
+
tos: ->(v) { v.nil? ? 0 : v != 0xc0 }
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,150 @@
|
|
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
|
+
module PacketGen
|
7
|
+
module Header
|
8
|
+
|
9
|
+
# This class supports IGMPv3 (RFC3376).
|
10
|
+
#
|
11
|
+
# From RFC 3376, a IGMP header has the following format:
|
12
|
+
# 0 1 2 3
|
13
|
+
# 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
|
14
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
15
|
+
# | Type | Max Resp Code | Checksum |
|
16
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
|
+
#
|
18
|
+
# A IGMP header consists of:
|
19
|
+
# * a {#type} field ({Types::Int8Enum} type),
|
20
|
+
# * a {#max_resp_time} field ({Types::Int8} type),
|
21
|
+
# * a {#checksum} field ({Types::Int16} type),
|
22
|
+
# * and a {#body}, containing more fields (see below).
|
23
|
+
#
|
24
|
+
# A IGMPv3 header may have additionnal fields. These fields are handled by
|
25
|
+
# additional headers (see {IGMPv3::MQ}).
|
26
|
+
#
|
27
|
+
# == Create a IGMPv3 header
|
28
|
+
# # standalone
|
29
|
+
# igmp = PacketGen::Header::IGMPv3.new
|
30
|
+
# # in a packet
|
31
|
+
# pkt = PacketGen.gen('IP').add('IGMPv3')
|
32
|
+
# # access to IGMPv3 header
|
33
|
+
# pkt.igmp # => PacketGen::Header::IGMPv3
|
34
|
+
#
|
35
|
+
# == IGMPv3 attributes
|
36
|
+
# igmp.type = 'MembershipQuery' # or 0x11
|
37
|
+
# igmp.max_resp_time = 20
|
38
|
+
# igmp.checksum = 0x248a
|
39
|
+
#
|
40
|
+
# == IGMPv3 specifics
|
41
|
+
# === Max Resp Code
|
42
|
+
# {#max_resp_code} field of IGMPv3 packets is encoded differently than
|
43
|
+
# previous versions. This encoding permits to set value up to 31743 (instead
|
44
|
+
# of 255 for IGMPv2).
|
45
|
+
#
|
46
|
+
# This encoding is handled by {#max_resp_code} accessors:
|
47
|
+
# igmp.max_resp_code = 10000
|
48
|
+
# igmp.max_resp_code #=> 9728 error due to encoding as a floating point value
|
49
|
+
#
|
50
|
+
# === IGMPv3 Membership Query
|
51
|
+
# With IGMPv3, a Membership Query packet has more fields than with IGMPv2. To
|
52
|
+
# handle those fields, an additional header should be used:
|
53
|
+
# pkt = PacketGen.gen('IP').add('IGMPv3', type: 'MembershipQuery').add('IGMPv3::MQ')
|
54
|
+
# pkt.igmpv3 #=> PacketGen::Header::IGMPv3
|
55
|
+
# pkt.igmpv3_mq #=> PacketGen::Header::IGMPv3::MQ
|
56
|
+
#
|
57
|
+
# === IGMPv3 Membership Report
|
58
|
+
# With IGMPv3, a Membership Report packet has more fields than with IGMPv2. To
|
59
|
+
# handle those fields, an additional header should be used:
|
60
|
+
# pkt = PacketGen.gen('IP').add('IGMPv3', type: 'MembershipQuery').add('IGMPv3::MR')
|
61
|
+
# pkt.igmpv3 #=> PacketGen::Header::IGMPv3
|
62
|
+
# pkt.igmpv3_mr #=> PacketGen::Header::IGMPv3::MR
|
63
|
+
# @author Sylvain Daubert
|
64
|
+
class IGMPv3 < IGMP
|
65
|
+
|
66
|
+
# Known types
|
67
|
+
TYPES = {
|
68
|
+
'MembershipQuery' => 0x11,
|
69
|
+
'MembershipReport' => 0x22,
|
70
|
+
}
|
71
|
+
|
72
|
+
delete_field :group_addr
|
73
|
+
#undef group_addr
|
74
|
+
#undef group_addr=
|
75
|
+
|
76
|
+
# Encode value for IGMPv3 Max Resp Code and QQIC.
|
77
|
+
# Value may be encoded as a float, so some error may occur.
|
78
|
+
# See RFC 3376 §4.1.1 and §4.1.7.
|
79
|
+
# @param [Integer] value
|
80
|
+
# @return [Integer]
|
81
|
+
def self.encode(value)
|
82
|
+
if value < 128
|
83
|
+
value
|
84
|
+
elsif value > 31743
|
85
|
+
255
|
86
|
+
else
|
87
|
+
exp = 0
|
88
|
+
value >>= 3
|
89
|
+
while value > 31 do
|
90
|
+
exp += 1
|
91
|
+
value >>= 1
|
92
|
+
end
|
93
|
+
0x80 | (exp << 4) | (value & 0xf)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Decode value for IGMPv3 Max Resp Code and QQIC.
|
98
|
+
# See RFC 3376 §4.1.1 and §4.1.7.
|
99
|
+
# @param [Integer] value
|
100
|
+
# @return [Integer]
|
101
|
+
def self.decode(value)
|
102
|
+
if value < 128
|
103
|
+
value
|
104
|
+
else
|
105
|
+
mant = value & 0xf
|
106
|
+
exp = (value >> 4) & 0x7
|
107
|
+
(0x10 | mant) << (exp + 3)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Getter for +max_resp_time+ for IGMPv3 packets. Use {.decode}.
|
112
|
+
# @return [Integer]
|
113
|
+
def max_resp_time
|
114
|
+
IGMPv3.decode(self[:max_resp_time].value || self[:max_resp_time].default)
|
115
|
+
end
|
116
|
+
alias max_resp_code max_resp_time
|
117
|
+
|
118
|
+
# Setter for +max_resp_time+ for IGMPv3 packets. Use {.encode}.
|
119
|
+
# @param [Integer] value
|
120
|
+
# @return [Integer]
|
121
|
+
def max_resp_time=(value)
|
122
|
+
self[:max_resp_time].value = IGMPv3.encode(value)
|
123
|
+
end
|
124
|
+
alias max_resp_code= max_resp_time=
|
125
|
+
|
126
|
+
# Compute checksum and set +checksum+ field
|
127
|
+
# @return [Integer]
|
128
|
+
def calc_checksum
|
129
|
+
sum = (type << 8) | max_resp_code
|
130
|
+
|
131
|
+
payload = body.to_s
|
132
|
+
payload << "\x00" unless payload.size % 2 == 0
|
133
|
+
payload.unpack('n*').each { |x| sum += x; }
|
134
|
+
|
135
|
+
while sum > 0xffff do
|
136
|
+
sum = (sum & 0xffff) + (sum >> 16)
|
137
|
+
end
|
138
|
+
sum = ~sum & 0xffff
|
139
|
+
self[:checksum].value = (sum == 0) ? 0xffff : sum
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
self.add_class IGMPv3
|
144
|
+
IP.bind_header IGMPv3, op: :and, protocol: IGMPv3::IP_PROTOCOL, frag: 0, ttl: 1,
|
145
|
+
tos: 0xc0
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
require_relative 'igmpv3/mq'
|
150
|
+
require_relative 'igmpv3/mr'
|
@@ -0,0 +1,98 @@
|
|
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
|
+
module PacketGen
|
7
|
+
module Header
|
8
|
+
class IGMPv3
|
9
|
+
# Class to handle IGMPv3 Group Records.
|
10
|
+
#
|
11
|
+
# A Group Record is a block of fields containing information
|
12
|
+
# pertaining to the sender's membership in a single multicast group on
|
13
|
+
# the interface from which the Report is sent.
|
14
|
+
#
|
15
|
+
# A Group Record has the following format:
|
16
|
+
# 0 1 2 3
|
17
|
+
# 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
|
18
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
|
+
# | Record Type | Aux Data Len | Number of Sources (N) |
|
20
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
21
|
+
# | Multicast Address |
|
22
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
23
|
+
# | Source Address [1] |
|
24
|
+
# +- -+
|
25
|
+
# | Source Address [2] |
|
26
|
+
# +- -+
|
27
|
+
# . . .
|
28
|
+
# . . .
|
29
|
+
# . . .
|
30
|
+
# +- -+
|
31
|
+
# | Source Address [N] |
|
32
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
33
|
+
# | |
|
34
|
+
# . .
|
35
|
+
# . Auxiliary Data .
|
36
|
+
# . .
|
37
|
+
# | |
|
38
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
39
|
+
# @author Sylvain Daubert
|
40
|
+
class GroupRecord < Types::Fields
|
41
|
+
|
42
|
+
# Known record types
|
43
|
+
RECORD_TYPES = {
|
44
|
+
'MODE_IS_INCLUDE' => 1,
|
45
|
+
'MODE_IS_EXCLUDE' => 2,
|
46
|
+
'CHANGE_TO_INCLUDE_MODE' => 3,
|
47
|
+
'CHANGE_TO_EXCLUDE_MODE' => 4,
|
48
|
+
'ALLOW_NEW_SOURCES' => 5,
|
49
|
+
'BLOCK_OLD_SOURCES' => 6
|
50
|
+
}
|
51
|
+
|
52
|
+
# @!attribute type
|
53
|
+
# 8-bit record type
|
54
|
+
# @return [Integer]
|
55
|
+
define_field :type, Types::Int8Enum, enum: RECORD_TYPES
|
56
|
+
# @!attribute aux_data_len
|
57
|
+
# 8-bit length of of the Auxiliary Data field ({#aux_data}), in unit of
|
58
|
+
# 32-bit words
|
59
|
+
# @return [Integer]
|
60
|
+
define_field :aux_data_len, Types::Int8, default: 0
|
61
|
+
# @!attribute number_of_sources
|
62
|
+
# 16-bit Number of source addresses in {#source_addr}
|
63
|
+
# @return [Integer]
|
64
|
+
define_field :number_of_sources, Types::Int16, default: 0
|
65
|
+
# @!attribute multicast_addr
|
66
|
+
# IP multicast address to which this Group Record pertains
|
67
|
+
# @return [IP::Addr]
|
68
|
+
define_field :multicast_addr, IP::Addr, default: '0.0.0.0'
|
69
|
+
# @!attribute source_addr
|
70
|
+
# Array of source addresses
|
71
|
+
# @return [IP::ArrayOfAddr]
|
72
|
+
define_field :source_addr, IP::ArrayOfAddr,
|
73
|
+
builder: ->(h, t) { t.new(counter: h[:number_of_sources]) }
|
74
|
+
# @!attribute aux_data
|
75
|
+
# @return [String]
|
76
|
+
define_field :aux_data, Types::String,
|
77
|
+
builder: ->(h, t) { t.new(length_from: ->() { h[:aux_data_len].to_i * 4 }) }
|
78
|
+
|
79
|
+
def human_type
|
80
|
+
self[:type].to_human
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_human
|
84
|
+
"#{human_type}(ma:#{multicast_addr}|src:#{source_addr.to_human})"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Class to handle series of {GroupRecord}.
|
89
|
+
# @author Sylvain Daubert
|
90
|
+
class GroupRecords < Types::Array
|
91
|
+
set_of GroupRecord
|
92
|
+
|
93
|
+
# Separator used in {#to_human}.
|
94
|
+
HUMAN_SEPARATOR = ';'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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
|
+
module PacketGen
|
7
|
+
module Header
|
8
|
+
class IGMPv3
|
9
|
+
# IGMPv3 Membership Query.
|
10
|
+
#
|
11
|
+
# This is a subpayload for IGMPv3 packets only. This kind of payload is
|
12
|
+
# sent by IP multicast routers to query the multicast reception state of
|
13
|
+
# neighboring interfaces. Queries has 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
|
+
# | Group Address |
|
18
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
|
+
# | Resv |S| QRV | QQIC | Number of Sources (N) |
|
20
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
21
|
+
# | Source Address [1] |
|
22
|
+
# +- -+
|
23
|
+
# | Source Address [2] |
|
24
|
+
# +- . -+
|
25
|
+
# . . .
|
26
|
+
# . . .
|
27
|
+
# +- -+
|
28
|
+
# | Source Address [N] |
|
29
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
30
|
+
#
|
31
|
+
# Fields are:
|
32
|
+
# * 32-bit {#group_addr} field ({Header::IP::Addr} type),
|
33
|
+
# * 4-bit {#resv}, a reserved field,
|
34
|
+
# * 1-bit {#flag_s} (Suppress Router-Side Processing),
|
35
|
+
# * 3-bit {#qrv} (Querier's Robustness Variable),
|
36
|
+
# * 8-bit {#qqic} (Querier's Query Interval Code),
|
37
|
+
# * 16-bit {#number_of_sources},
|
38
|
+
# * {#source_addr} field, a {IP::ArrayOfAddr} to handle sources addresses.
|
39
|
+
# @author Sylvain Daubert
|
40
|
+
class MQ < Base
|
41
|
+
# @!attribute group_addr
|
42
|
+
# IP Group address
|
43
|
+
# @return [IP::Addr]
|
44
|
+
define_field :group_addr, IP::Addr, default: '0.0.0.0'
|
45
|
+
# @!attribute u8
|
46
|
+
# First 8-bit field, composed of {#resv}, {#flag_s} and {#qrv}
|
47
|
+
# @return [Integer]
|
48
|
+
define_field :u8, Types::Int8
|
49
|
+
# @!attribute qqic
|
50
|
+
# 8-bit QQIC
|
51
|
+
# @return [Integer,Float]
|
52
|
+
define_field :qqic, Types::Int8
|
53
|
+
# @!attribute number_of_sources
|
54
|
+
# 16-bit Number of Sources in {#source_addr}
|
55
|
+
# @return [Integer]
|
56
|
+
define_field :number_of_sources, Types::Int16
|
57
|
+
|
58
|
+
# @!attribute source_addr
|
59
|
+
# Array of IP source addresses
|
60
|
+
# @return [IP::ArrayOfAddr]
|
61
|
+
define_field :source_addr, IP::ArrayOfAddr,
|
62
|
+
builder: ->(h,t) { t.new(counter: h[:number_of_sources]) }
|
63
|
+
|
64
|
+
# @!attribute resv
|
65
|
+
# 4-bit reserved field in
|
66
|
+
# @return [Integer]
|
67
|
+
# @!attribute flag_s
|
68
|
+
# 1-bit S flag (Suppress Router-Side Processing)
|
69
|
+
# @return [Boolean]
|
70
|
+
# @!attribute qrv
|
71
|
+
# 3-bit Querier's Robustness Variable
|
72
|
+
# @return [Integer]
|
73
|
+
define_bit_fields_on :u8, :resv, 4, :flag_s, :qrv, 3
|
74
|
+
|
75
|
+
# Get QQIC value
|
76
|
+
# @note May return a different value from value previously set, as a
|
77
|
+
# float encoding is used to encode big values. See {IGMPv3.decode}.
|
78
|
+
# @return [Integer]
|
79
|
+
def qqic
|
80
|
+
IGMPv3.decode self[:qqic].to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
# Set QQIC value
|
84
|
+
# @note See {IGMPv3.encode}.
|
85
|
+
# @param [Integer] value
|
86
|
+
# @return [Integer]
|
87
|
+
def qqic=(value)
|
88
|
+
self[:qqic].value = IGMPv3.encode(value)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
self.add_class IGMPv3::MQ
|
94
|
+
IGMPv3.bind_header IGMPv3::MQ, type: 0x11
|
95
|
+
end
|
96
|
+
end
|