packetgen 3.3.3 → 4.1.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 +4 -4
- data/README.md +38 -22
- data/lib/packetgen/capture.rb +2 -2
- data/lib/packetgen/config.rb +0 -1
- data/lib/packetgen/deprecation.rb +14 -8
- data/lib/packetgen/header/arp.rb +17 -18
- data/lib/packetgen/header/asn1_base.rb +2 -1
- data/lib/packetgen/header/base.rb +42 -40
- data/lib/packetgen/header/bootp.rb +35 -37
- data/lib/packetgen/header/dhcp/option.rb +21 -21
- data/lib/packetgen/header/dhcp/options.rb +3 -3
- data/lib/packetgen/header/dhcp.rb +8 -9
- data/lib/packetgen/header/dhcpv6/duid.rb +16 -16
- data/lib/packetgen/header/dhcpv6/option.rb +83 -61
- data/lib/packetgen/header/dhcpv6/options.rb +4 -4
- data/lib/packetgen/header/dhcpv6/relay.rb +6 -5
- data/lib/packetgen/header/dhcpv6.rb +17 -18
- data/lib/packetgen/header/dns/name.rb +21 -16
- data/lib/packetgen/header/dns/opt.rb +5 -2
- data/lib/packetgen/header/dns/option.rb +14 -14
- data/lib/packetgen/header/dns/qdsection.rb +3 -3
- data/lib/packetgen/header/dns/question.rb +7 -8
- data/lib/packetgen/header/dns/rr.rb +56 -43
- data/lib/packetgen/header/dns/rrsection.rb +6 -6
- data/lib/packetgen/header/dns.rb +103 -90
- data/lib/packetgen/header/dot11/control.rb +12 -12
- data/lib/packetgen/header/dot11/data.rb +25 -24
- data/lib/packetgen/header/dot11/element.rb +4 -4
- data/lib/packetgen/header/dot11/management.rb +21 -18
- data/lib/packetgen/header/dot11/sub_mngt.rb +40 -53
- data/lib/packetgen/header/dot11.rb +117 -122
- data/lib/packetgen/header/dot1q.rb +12 -13
- data/lib/packetgen/header/dot1x.rb +13 -13
- data/lib/packetgen/header/eap/fast.rb +4 -4
- data/lib/packetgen/header/eap/md5.rb +16 -8
- data/lib/packetgen/header/eap/tls.rb +18 -19
- data/lib/packetgen/header/eap/ttls.rb +22 -21
- data/lib/packetgen/header/eap.rb +73 -48
- data/lib/packetgen/header/eth.rb +41 -27
- data/lib/packetgen/header/gre.rb +33 -11
- data/lib/packetgen/header/http/headers.rb +7 -6
- data/lib/packetgen/header/http/request.rb +38 -29
- data/lib/packetgen/header/http/response.rb +35 -27
- data/lib/packetgen/header/http/verbs.rb +1 -3
- data/lib/packetgen/header/icmp.rb +14 -14
- data/lib/packetgen/header/icmpv6.rb +10 -9
- data/lib/packetgen/header/igmp.rb +26 -15
- data/lib/packetgen/header/igmpv3/group_record.rb +18 -13
- data/lib/packetgen/header/igmpv3/mq.rb +16 -18
- data/lib/packetgen/header/igmpv3/mr.rb +5 -5
- data/lib/packetgen/header/igmpv3.rb +12 -11
- data/lib/packetgen/header/ip/addr.rb +19 -15
- data/lib/packetgen/header/ip/option.rb +47 -36
- data/lib/packetgen/header/ip/options.rb +1 -1
- data/lib/packetgen/header/ip.rb +77 -95
- data/lib/packetgen/header/ipv6/addr.rb +28 -27
- data/lib/packetgen/header/ipv6/extension.rb +13 -11
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +32 -13
- data/lib/packetgen/header/ipv6.rb +42 -35
- data/lib/packetgen/header/llc.rb +28 -21
- data/lib/packetgen/header/mdns.rb +10 -3
- data/lib/packetgen/header/mld.rb +15 -13
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +17 -12
- data/lib/packetgen/header/mldv2/mlq.rb +22 -24
- data/lib/packetgen/header/mldv2/mlr.rb +8 -8
- data/lib/packetgen/header/mldv2.rb +1 -1
- data/lib/packetgen/header/ospfv2/db_description.rb +17 -18
- data/lib/packetgen/header/ospfv2/hello.rb +18 -17
- data/lib/packetgen/header/ospfv2/ls_ack.rb +6 -7
- data/lib/packetgen/header/ospfv2/ls_request.rb +14 -13
- data/lib/packetgen/header/ospfv2/ls_update.rb +9 -9
- data/lib/packetgen/header/ospfv2/lsa.rb +79 -60
- data/lib/packetgen/header/ospfv2/lsa_header.rb +12 -11
- data/lib/packetgen/header/ospfv2.rb +49 -46
- data/lib/packetgen/header/ospfv3/db_description.rb +20 -22
- data/lib/packetgen/header/ospfv3/hello.rb +17 -16
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +22 -20
- data/lib/packetgen/header/ospfv3/ls_ack.rb +7 -8
- data/lib/packetgen/header/ospfv3/ls_request.rb +18 -18
- data/lib/packetgen/header/ospfv3/ls_update.rb +10 -10
- data/lib/packetgen/header/ospfv3/lsa.rb +62 -51
- data/lib/packetgen/header/ospfv3/lsa_header.rb +12 -11
- data/lib/packetgen/header/ospfv3.rb +54 -52
- data/lib/packetgen/header/sctp/chunk.rb +80 -56
- data/lib/packetgen/header/sctp/error.rb +174 -202
- data/lib/packetgen/header/sctp/padded32.rb +3 -3
- data/lib/packetgen/header/sctp/parameter.rb +89 -136
- data/lib/packetgen/header/sctp.rb +19 -8
- data/lib/packetgen/header/snmp.rb +108 -7
- data/lib/packetgen/header/tcp/option.rb +52 -39
- data/lib/packetgen/header/tcp/options.rb +13 -5
- data/lib/packetgen/header/tcp.rb +83 -65
- data/lib/packetgen/header/tftp.rb +31 -25
- data/lib/packetgen/header/udp.rb +21 -19
- data/lib/packetgen/header.rb +23 -18
- data/lib/packetgen/headerable.rb +21 -5
- data/lib/packetgen/inspect.rb +3 -8
- data/lib/packetgen/packet.rb +146 -71
- data/lib/packetgen/pcap.rb +15 -4
- data/lib/packetgen/pcapng/block.rb +20 -18
- data/lib/packetgen/pcapng/epb.rb +13 -15
- data/lib/packetgen/pcapng/file.rb +44 -111
- data/lib/packetgen/pcapng/idb.rb +11 -12
- data/lib/packetgen/pcapng/shb.rb +15 -16
- data/lib/packetgen/pcapng/spb.rb +9 -11
- data/lib/packetgen/pcapng/unknown_block.rb +6 -17
- data/lib/packetgen/pcapng.rb +6 -4
- data/lib/packetgen/pcaprub_wrapper.rb +17 -1
- data/lib/packetgen/proto.rb +5 -1
- data/lib/packetgen/unknown_packet.rb +5 -5
- data/lib/packetgen/utils/arp_spoofer.rb +18 -19
- data/lib/packetgen/utils.rb +4 -3
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +12 -5
- metadata +29 -38
- data/lib/packetgen/types/abstract_tlv.rb +0 -278
- data/lib/packetgen/types/array.rb +0 -287
- data/lib/packetgen/types/cstring.rb +0 -109
- data/lib/packetgen/types/enum.rb +0 -171
- data/lib/packetgen/types/fieldable.rb +0 -66
- data/lib/packetgen/types/fields.rb +0 -622
- data/lib/packetgen/types/int.rb +0 -473
- data/lib/packetgen/types/int_string.rb +0 -102
- data/lib/packetgen/types/length_from.rb +0 -54
- data/lib/packetgen/types/oui.rb +0 -52
- data/lib/packetgen/types/string.rb +0 -97
- data/lib/packetgen/types/tlv.rb +0 -161
- data/lib/packetgen/types.rb +0 -26
@@ -10,25 +10,26 @@ module PacketGen
|
|
10
10
|
module Header
|
11
11
|
module HTTP
|
12
12
|
# An HTTP/1.1 Response packet consists of:
|
13
|
-
# * the version (
|
14
|
-
# * the status code (
|
15
|
-
# * the status message (
|
16
|
-
# * associated
|
17
|
-
# * the actual
|
13
|
+
# * the version (+BinStruct::String+).
|
14
|
+
# * the status code (+BinStruct::String+).
|
15
|
+
# * the status message (+BinStruct::String+).
|
16
|
+
# * associated HTTP headers ({HTTP::Headers}).
|
17
|
+
# * the actual HTTP payload body (+BinStruct::String+).
|
18
18
|
#
|
19
|
-
#
|
19
|
+
# Note: When creating a HTTP Response packet, +sport+ and +dport+
|
20
|
+
# attributes of TCP header are not set.
|
21
|
+
#
|
22
|
+
# @example Create a HTTP Response header
|
20
23
|
# # standalone
|
21
24
|
# http_resp = PacketGen::Header::HTTP::Response.new
|
22
25
|
# # in a packet
|
23
26
|
# pkt = PacketGen.gen("IP").add("TCP").add("HTTP::Response")
|
24
27
|
# # access to HTTP Response header
|
25
|
-
# pkt.http_response # => PacketGen::Header::HTTP::Response
|
28
|
+
# pkt.http_response.class # => PacketGen::Header::HTTP::Response
|
26
29
|
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# == HTTP Response attributes
|
31
|
-
# http_resp.version = "HTTP/1.1"
|
30
|
+
# @example HTTP Response attributes
|
31
|
+
# http_resp = PacketGen::Header::HTTP::Response.new
|
32
|
+
# http_resp.version #=> "HTTP/1.1"
|
32
33
|
# http_resp.status_code = "200"
|
33
34
|
# http_resp.status_mesg = "OK"
|
34
35
|
# http_resp.body = "this is a body"
|
@@ -36,23 +37,28 @@ module PacketGen
|
|
36
37
|
# http_resp.headers = { "Host": "tcpdump.org" } # even a hash
|
37
38
|
#
|
38
39
|
# @author Kent 'picat' Gruber
|
40
|
+
# @author LemonTree55
|
39
41
|
class Response < Base
|
40
42
|
# @!attribute version
|
41
|
-
#
|
42
|
-
|
43
|
+
# HTTP version
|
44
|
+
# @return [BinStruct::String]
|
45
|
+
define_attr :version, BinStruct::String, default: 'HTTP/1.1'
|
43
46
|
# @!attribute status_code
|
44
|
-
#
|
45
|
-
|
47
|
+
# Response status code
|
48
|
+
# @return [BinStruct::String]
|
49
|
+
define_attr :status_code, BinStruct::String
|
46
50
|
# @!attribute status_mesg
|
47
|
-
#
|
48
|
-
|
51
|
+
# Response status message
|
52
|
+
# @return [BinStruct::String]
|
53
|
+
define_attr :status_mesg, BinStruct::String
|
49
54
|
# @!attribute headers
|
50
55
|
# associated http/1.1 headers
|
51
|
-
# @return [
|
52
|
-
|
56
|
+
# @return [HTTP::Headers]
|
57
|
+
define_attr :headers, HTTP::Headers
|
53
58
|
# @!attribute body
|
54
|
-
#
|
55
|
-
|
59
|
+
# Response body
|
60
|
+
# @return [BinStruct::String]
|
61
|
+
define_attr :body, BinStruct::String
|
56
62
|
|
57
63
|
# @param [Hash] options
|
58
64
|
# @option options [String] :version
|
@@ -61,12 +67,12 @@ module PacketGen
|
|
61
67
|
# @option options [String] :body
|
62
68
|
# @option options [Hash] :headers
|
63
69
|
def initialize(options={})
|
64
|
-
super
|
70
|
+
super
|
65
71
|
self.headers ||= options[:headers]
|
66
72
|
end
|
67
73
|
|
68
74
|
# Read in the HTTP portion of the packet, and parse it.
|
69
|
-
# @return [
|
75
|
+
# @return [self]
|
70
76
|
def read(str)
|
71
77
|
headers, data = collect_headers_and_data(str)
|
72
78
|
|
@@ -79,6 +85,8 @@ module PacketGen
|
|
79
85
|
self
|
80
86
|
end
|
81
87
|
|
88
|
+
# May be parsed as a HTTP response if version is +HTTP/1.x+.
|
89
|
+
# @return [Boolean]
|
82
90
|
def parse?
|
83
91
|
version.start_with?('HTTP/1.')
|
84
92
|
end
|
@@ -125,9 +133,9 @@ module PacketGen
|
|
125
133
|
first_line = headers.shift.split
|
126
134
|
return if first_line.size < 3
|
127
135
|
|
128
|
-
self[:version].read
|
129
|
-
self[:status_code].read
|
130
|
-
self[:status_mesg].read
|
136
|
+
self[:version].read(first_line[0])
|
137
|
+
self[:status_code].read(first_line[1])
|
138
|
+
self[:status_mesg].read(first_line[2..].join(' '))
|
131
139
|
end
|
132
140
|
|
133
141
|
def raise_on_bad_version_status
|
@@ -9,10 +9,8 @@
|
|
9
9
|
module PacketGen
|
10
10
|
module Header
|
11
11
|
# @since 2.2.0
|
12
|
+
# @author Kent 'picat' Gruber
|
12
13
|
module HTTP
|
13
|
-
# @abstract Collection of useful HTTP verbs.
|
14
|
-
# @author Kent 'picat' Gruber
|
15
|
-
|
16
14
|
# Valid HTTP Verbs
|
17
15
|
VERBS = %w[GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATCH].freeze
|
18
16
|
|
@@ -15,24 +15,25 @@ module PacketGen
|
|
15
15
|
# | Type | Code | Checksum |
|
16
16
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
17
|
# A ICMP header consists of:
|
18
|
-
# * a {#type} field (
|
19
|
-
# * a {#code} field (
|
20
|
-
# * a {#checksum} field (
|
18
|
+
# * a {#type} field (+BinStruct::Int8+ type),
|
19
|
+
# * a {#code} field (+BinStruct::Int8+ type),
|
20
|
+
# * a {#checksum} field (+BinStruct::Int16+ type),
|
21
21
|
# * and a {#body}.
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# @example Create a ICMP header
|
24
24
|
# # standalone
|
25
25
|
# icmp = PacketGen::Header::ICMP.new
|
26
26
|
# # in a packet
|
27
27
|
# pkt = PacketGen.gen('IP').add('ICMP')
|
28
28
|
# # access to ICMP header
|
29
|
-
# pkt.icmp
|
29
|
+
# pkt.icmp.class # => PacketGen::Header::ICMP
|
30
30
|
#
|
31
|
-
#
|
31
|
+
# @example ICMP attributes
|
32
|
+
# icmp = PacketGen::Header::ICMP.new
|
32
33
|
# icmp.code = 0
|
33
34
|
# icmp.type = 200
|
34
35
|
# icmp.checksum = 0x248a
|
35
|
-
# icmp.body
|
36
|
+
# icmp.body = 'this is a body'
|
36
37
|
# @author Sylvain Daubert
|
37
38
|
class ICMP < Base
|
38
39
|
# ICMP internet protocol number
|
@@ -41,18 +42,19 @@ module PacketGen
|
|
41
42
|
# @!attribute type
|
42
43
|
# 8-bit ICMP type
|
43
44
|
# @return [Integer]
|
44
|
-
|
45
|
+
define_attr :type, BinStruct::Int8
|
45
46
|
# @!attribute code
|
46
47
|
# 8-bit ICMP code
|
47
48
|
# @return [Integer]
|
48
|
-
|
49
|
+
define_attr :code, BinStruct::Int8
|
49
50
|
# @!attribute checksum
|
50
51
|
# 16-bit ICMP checksum
|
51
52
|
# @return [Integer]
|
52
|
-
|
53
|
+
define_attr :checksum, BinStruct::Int16
|
53
54
|
# @!attribute body
|
54
|
-
#
|
55
|
-
|
55
|
+
# ICMP body
|
56
|
+
# @return [BinStruct::String,Headerable]
|
57
|
+
define_attr :body, BinStruct::String
|
56
58
|
|
57
59
|
# Compute checksum and set +checksum+ field
|
58
60
|
# @return [Integer]
|
@@ -61,9 +63,7 @@ module PacketGen
|
|
61
63
|
self.checksum = IP.reduce_checksum(sum)
|
62
64
|
end
|
63
65
|
end
|
64
|
-
|
65
66
|
self.add_class ICMP
|
66
|
-
|
67
67
|
IP.bind ICMP, protocol: ICMP::IP_PROTOCOL
|
68
68
|
end
|
69
69
|
end
|
@@ -15,30 +15,31 @@ module PacketGen
|
|
15
15
|
# | Type | Code | Checksum |
|
16
16
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
17
17
|
# A ICMPv6 header consists of:
|
18
|
-
# * a
|
19
|
-
# * a
|
20
|
-
# * a
|
21
|
-
# * and a
|
18
|
+
# * a {#type #type} field (+BinStruct::Int8+ type),
|
19
|
+
# * a {#code #code} field (+BinStruct::Int8+ type),
|
20
|
+
# * a {#checksum #checksum} field (+BinStruct::Int16+ type),
|
21
|
+
# * and a {#body #body}.
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# @example Create a ICMPv6 header
|
24
24
|
# # standalone
|
25
25
|
# icmpv6 = PacketGen::Header::ICMPv6.new
|
26
26
|
# # in a packet
|
27
27
|
# pkt = PacketGen.gen('IPv6').add('ICMPv6')
|
28
28
|
# # access to ICMPv6 header
|
29
|
-
# pkt.icmpv6
|
29
|
+
# pkt.icmpv6.class # => PacketGen::Header::ICMPv6
|
30
30
|
#
|
31
|
-
#
|
31
|
+
# @example ICMPv6 attributes
|
32
|
+
# icmpv6 = PacketGen::Header::ICMPv6.new
|
32
33
|
# icmpv6.code = 0
|
33
34
|
# icmpv6.type = 200
|
34
35
|
# icmpv6.checksum = 0x248a
|
35
|
-
# icmpv6.body
|
36
|
+
# icmpv6.body = 'this is a body'
|
36
37
|
# @author Sylvain Daubert
|
37
38
|
class ICMPv6 < ICMP
|
38
39
|
# ICMPv6 internet protocol number
|
39
40
|
IP_PROTOCOL = 58
|
40
41
|
|
41
|
-
# Compute checksum and set +checksum+ field
|
42
|
+
# Compute IPV6-style checksum and set +checksum+ field
|
42
43
|
# @return [Integer]
|
43
44
|
def calc_checksum
|
44
45
|
sum = ip_header(self).pseudo_header_checksum
|
@@ -20,25 +20,29 @@ module PacketGen
|
|
20
20
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
21
21
|
#
|
22
22
|
# A IGMP header consists of:
|
23
|
-
# * a {#type} field (
|
24
|
-
# * a {#max_resp_time} field (
|
25
|
-
# * a {#checksum} field (
|
23
|
+
# * a {#type} field (+BinStruct::Int8Enum+ type),
|
24
|
+
# * a {#max_resp_time} field (+BinStruct::Int8+ type),
|
25
|
+
# * a {#checksum} field (+BinStruct::Int16+ type),
|
26
26
|
# * a {#group_addr} field ({Header::IP::Addr} type),
|
27
27
|
# * and a {#body} (unused for IGMPv2).
|
28
28
|
#
|
29
|
-
#
|
29
|
+
# After adding a IGMP header to a packet, you have to call {#igmpize} to ensure
|
30
|
+
# resulting packet conforms to RFC 2236.
|
31
|
+
#
|
32
|
+
# @example Create a IGMP header
|
30
33
|
# # standalone
|
31
34
|
# igmp = PacketGen::Header::IGMP.new
|
32
35
|
# # in a packet
|
33
36
|
# pkt = PacketGen.gen('IP').add('IGMP')
|
34
37
|
# # access to IGMP header
|
35
|
-
# pkt.igmp
|
38
|
+
# pkt.igmp.class # => PacketGen::Header::IGMP
|
36
39
|
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
40
|
+
# @example IGMP attributes
|
41
|
+
# igmp = PacketGen::Header::IGMP.new
|
42
|
+
# igmp.type = 'MembershipQuery' # or 0x11
|
43
|
+
# igmp.max_resp_time = 20
|
44
|
+
# igmp.checksum = 0x248a
|
45
|
+
# igmp.group_addr = '224.0.0.1'
|
42
46
|
# @author Sylvain Daubert
|
43
47
|
# @since 2.4.0
|
44
48
|
class IGMP < Base
|
@@ -56,26 +60,28 @@ module PacketGen
|
|
56
60
|
# @!attribute type
|
57
61
|
# 8-bit IGMP Type
|
58
62
|
# @return [Integer]
|
59
|
-
|
63
|
+
define_attr :type, BinStruct::Int8Enum, enum: TYPES
|
60
64
|
# @!attribute max_resp_time
|
61
65
|
# 8-bit IGMP Max Response Time
|
62
66
|
# @return [Integer]
|
63
|
-
|
67
|
+
define_attr :max_resp_time, BinStruct::Int8
|
64
68
|
# @!attribute checksum
|
65
69
|
# 16-bit IGMP Checksum
|
66
70
|
# @return [Integer]
|
67
|
-
|
71
|
+
define_attr :checksum, BinStruct::Int16
|
68
72
|
# @!attribute group_addr
|
69
73
|
# IP Group address
|
70
74
|
# @return [IP::Addr]
|
71
|
-
|
75
|
+
define_attr :group_addr, IP::Addr, default: '0.0.0.0'
|
72
76
|
# @!attribute body
|
77
|
+
# IGMP body (not used in IGMPv2)
|
73
78
|
# @return [String,Base]
|
74
|
-
|
79
|
+
define_attr :body, BinStruct::String
|
75
80
|
|
76
81
|
# @api private
|
77
82
|
# @note This method is used internally by PacketGen and should not be
|
78
83
|
# directly called
|
84
|
+
# Define +#igmpize+ method onto +packet+. This method calls {#igmpize}.
|
79
85
|
def added_to_packet(packet)
|
80
86
|
igmp_idx = packet.headers.size
|
81
87
|
packet.instance_eval "def igmpize() @headers[#{igmp_idx}].igmpize; end" # def igmpize() @headers[2].igmpize; end
|
@@ -103,6 +109,11 @@ module PacketGen
|
|
103
109
|
# pkt.igmp.igmpize
|
104
110
|
# # second method
|
105
111
|
# pkt.igmpize
|
112
|
+
# @example
|
113
|
+
# pkt = PacketGen.gen('IP').add('IGMP', type: 'MembershipQuery', max_resp_time: 20, group_addr: '1.2.3.4')
|
114
|
+
# pkt.igmpize
|
115
|
+
# pkt.ip.ttl #=> 1
|
116
|
+
# pkt.ip.options.map(&:class) #=> [PacketGen::Header::IP::RA]
|
106
117
|
# @return [void]
|
107
118
|
def igmpize
|
108
119
|
iph = ip_header(self)
|
@@ -11,7 +11,7 @@ module PacketGen
|
|
11
11
|
class IGMPv3
|
12
12
|
# Class to handle IGMPv3 Group Records.
|
13
13
|
#
|
14
|
-
# A Group Record is a block of
|
14
|
+
# A Group Record is a block of attributes containing information
|
15
15
|
# pertaining to the sender's membership in a single multicast group on
|
16
16
|
# the interface from which the Report is sent.
|
17
17
|
#
|
@@ -40,8 +40,8 @@ module PacketGen
|
|
40
40
|
# | |
|
41
41
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
42
42
|
# @author Sylvain Daubert
|
43
|
-
class GroupRecord <
|
44
|
-
include
|
43
|
+
class GroupRecord < BinStruct::Struct
|
44
|
+
include BinStruct::Structable
|
45
45
|
|
46
46
|
# Known record types
|
47
47
|
RECORD_TYPES = {
|
@@ -56,34 +56,39 @@ module PacketGen
|
|
56
56
|
# @!attribute type
|
57
57
|
# 8-bit record type
|
58
58
|
# @return [Integer]
|
59
|
-
|
59
|
+
define_attr :type, BinStruct::Int8Enum, enum: RECORD_TYPES
|
60
60
|
# @!attribute aux_data_len
|
61
61
|
# 8-bit length of of the Auxiliary Data field ({#aux_data}), in unit of
|
62
62
|
# 32-bit words
|
63
63
|
# @return [Integer]
|
64
|
-
|
64
|
+
define_attr :aux_data_len, BinStruct::Int8, default: 0
|
65
65
|
# @!attribute number_of_sources
|
66
66
|
# 16-bit Number of source addresses in {#source_addr}
|
67
67
|
# @return [Integer]
|
68
|
-
|
68
|
+
define_attr :number_of_sources, BinStruct::Int16, default: 0
|
69
69
|
# @!attribute multicast_addr
|
70
70
|
# IP multicast address to which this Group Record pertains
|
71
71
|
# @return [IP::Addr]
|
72
|
-
|
72
|
+
define_attr :multicast_addr, IP::Addr, default: '0.0.0.0'
|
73
73
|
# @!attribute source_addr
|
74
74
|
# Array of source addresses
|
75
75
|
# @return [IP::ArrayOfAddr]
|
76
|
-
|
77
|
-
|
76
|
+
define_attr :source_addr, IP::ArrayOfAddr,
|
77
|
+
builder: ->(h, t) { t.new(counter: h[:number_of_sources]) }
|
78
78
|
# @!attribute aux_data
|
79
|
+
# Not used in IGMPv3
|
79
80
|
# @return [String]
|
80
|
-
|
81
|
-
|
81
|
+
define_attr :aux_data, BinStruct::String,
|
82
|
+
builder: ->(h, t) { t.new(length_from: -> { h[:aux_data_len].to_i * 4 }) }
|
82
83
|
|
84
|
+
# Human-readable type
|
85
|
+
# @return [String]
|
83
86
|
def human_type
|
84
87
|
self[:type].to_human
|
85
88
|
end
|
86
89
|
|
90
|
+
# Human-readable description of a group record
|
91
|
+
# @return [String]
|
87
92
|
def to_human
|
88
93
|
"#{human_type}(ma:#{multicast_addr}|src:#{source_addr.to_human})"
|
89
94
|
end
|
@@ -91,10 +96,10 @@ module PacketGen
|
|
91
96
|
|
92
97
|
# Class to handle series of {GroupRecord}.
|
93
98
|
# @author Sylvain Daubert
|
94
|
-
class GroupRecords <
|
99
|
+
class GroupRecords < BinStruct::Array
|
95
100
|
set_of GroupRecord
|
96
101
|
|
97
|
-
# Separator used in
|
102
|
+
# Separator used in +#to_human+.
|
98
103
|
HUMAN_SEPARATOR = ';'
|
99
104
|
end
|
100
105
|
end
|
@@ -31,7 +31,7 @@ module PacketGen
|
|
31
31
|
# | Source Address [N] |
|
32
32
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
33
33
|
#
|
34
|
-
#
|
34
|
+
# Struct are:
|
35
35
|
# * 32-bit {#group_addr} field ({Header::IP::Addr} type),
|
36
36
|
# * 4-bit {#resv}, a reserved field,
|
37
37
|
# * 1-bit {#flag_s} (Suppress Router-Side Processing),
|
@@ -44,36 +44,34 @@ module PacketGen
|
|
44
44
|
# @!attribute group_addr
|
45
45
|
# IP Group address
|
46
46
|
# @return [IP::Addr]
|
47
|
-
|
47
|
+
define_attr :group_addr, IP::Addr, default: '0.0.0.0'
|
48
48
|
# @!attribute u8
|
49
49
|
# First 8-bit field, composed of {#resv}, {#flag_s} and {#qrv}
|
50
50
|
# @return [Integer]
|
51
|
-
|
51
|
+
# @!attribute resv
|
52
|
+
# 4-bit reserved field
|
53
|
+
# @return [Integer]
|
54
|
+
# @!attribute flag_s
|
55
|
+
# 1-bit S flag (Suppress Router-Side Processing)
|
56
|
+
# @return [Integer]
|
57
|
+
# @!attribute qrv
|
58
|
+
# 3-bit Querier's Robustness Variable
|
59
|
+
# @return [Integer]
|
60
|
+
define_bit_attr :u8, resv: 4, flag_s: 1, qrv: 3
|
52
61
|
# @!attribute qqic
|
53
62
|
# 8-bit QQIC
|
54
63
|
# @return [Integer,Float]
|
55
|
-
|
64
|
+
define_attr :qqic, BinStruct::Int8
|
56
65
|
# @!attribute number_of_sources
|
57
66
|
# 16-bit Number of Sources in {#source_addr}
|
58
67
|
# @return [Integer]
|
59
|
-
|
68
|
+
define_attr :number_of_sources, BinStruct::Int16
|
60
69
|
|
61
70
|
# @!attribute source_addr
|
62
71
|
# Array of IP source addresses
|
63
72
|
# @return [IP::ArrayOfAddr]
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# @!attribute resv
|
68
|
-
# 4-bit reserved field in
|
69
|
-
# @return [Integer]
|
70
|
-
# @!attribute flag_s
|
71
|
-
# 1-bit S flag (Suppress Router-Side Processing)
|
72
|
-
# @return [Boolean]
|
73
|
-
# @!attribute qrv
|
74
|
-
# 3-bit Querier's Robustness Variable
|
75
|
-
# @return [Integer]
|
76
|
-
define_bit_fields_on :u8, :resv, 4, :flag_s, :qrv, 3
|
73
|
+
define_attr :source_addr, IP::ArrayOfAddr,
|
74
|
+
builder: ->(h, t) { t.new(counter: h[:number_of_sources]) }
|
77
75
|
|
78
76
|
undef qqic, qqic=
|
79
77
|
|
@@ -48,18 +48,18 @@ module PacketGen
|
|
48
48
|
class MR < Base
|
49
49
|
# @!attribute reserved
|
50
50
|
# 16-bit reserved field
|
51
|
-
#
|
52
|
-
|
51
|
+
# @return [Integer]
|
52
|
+
define_attr :reserved, BinStruct::Int16, default: 0
|
53
53
|
# @!attribute number_of_gr
|
54
54
|
# 16-bit Number of group records in {#group_records}
|
55
55
|
# @return [Integer]
|
56
|
-
|
56
|
+
define_attr :number_of_gr, BinStruct::Int16, default: 0
|
57
57
|
|
58
58
|
# @!attribute group_records
|
59
59
|
# Array of group records
|
60
60
|
# @return [GroupRecords]
|
61
|
-
|
62
|
-
|
61
|
+
define_attr :group_records, GroupRecords,
|
62
|
+
builder: ->(h, t) { t.new(counter: h[:number_of_gr]) }
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -18,23 +18,24 @@ module PacketGen
|
|
18
18
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
19
|
#
|
20
20
|
# A IGMP header consists of:
|
21
|
-
# * a {#type} field (
|
22
|
-
# * a {#max_resp_time} field (
|
23
|
-
# * a {#checksum} field (
|
24
|
-
# * and a {#body}, containing more fields (see below).
|
21
|
+
# * a {#type #type} field (+BinStruct::Int8Enum+ type),
|
22
|
+
# * a {#max_resp_time #max_resp_time} field (+BinStruct::Int8+ type),
|
23
|
+
# * a {#checksum #checksum} field (+BinStruct::Int16+ type),
|
24
|
+
# * and a {#body #body}, containing more fields (see below).
|
25
25
|
#
|
26
|
-
# A IGMPv3 header may have additionnal fields. These
|
26
|
+
# A IGMPv3 header may have additionnal fields. These attributes are handled by
|
27
27
|
# additional headers (see {IGMPv3::MQ}).
|
28
28
|
#
|
29
|
-
#
|
29
|
+
# @example Create a IGMPv3 header
|
30
30
|
# # standalone
|
31
31
|
# igmp = PacketGen::Header::IGMPv3.new
|
32
32
|
# # in a packet
|
33
33
|
# pkt = PacketGen.gen('IP').add('IGMPv3')
|
34
34
|
# # access to IGMPv3 header
|
35
|
-
# pkt.
|
35
|
+
# pkt.igmpv3.class # => PacketGen::Header::IGMPv3
|
36
36
|
#
|
37
|
-
#
|
37
|
+
# @example IGMPv3 attributes
|
38
|
+
# igmp = PacketGen::Header::IGMPv3.new
|
38
39
|
# igmp.type = 'MembershipQuery' # or 0x11
|
39
40
|
# igmp.max_resp_time = 20
|
40
41
|
# igmp.checksum = 0x248a
|
@@ -50,14 +51,14 @@ module PacketGen
|
|
50
51
|
# igmp.max_resp_code #=> 9728 error due to encoding as a floating point value
|
51
52
|
#
|
52
53
|
# === IGMPv3 Membership Query
|
53
|
-
# With IGMPv3, a Membership Query packet has more
|
54
|
+
# With IGMPv3, a Membership Query packet has more attributes than with IGMPv2. To
|
54
55
|
# handle those fields, an additional header should be used:
|
55
56
|
# pkt = PacketGen.gen('IP').add('IGMPv3', type: 'MembershipQuery').add('IGMPv3::MQ')
|
56
57
|
# pkt.igmpv3 #=> PacketGen::Header::IGMPv3
|
57
58
|
# pkt.igmpv3_mq #=> PacketGen::Header::IGMPv3::MQ
|
58
59
|
#
|
59
60
|
# === IGMPv3 Membership Report
|
60
|
-
# With IGMPv3, a Membership Report packet has more
|
61
|
+
# With IGMPv3, a Membership Report packet has more attributes than with IGMPv2. To
|
61
62
|
# handle those fields, an additional header should be used:
|
62
63
|
# pkt = PacketGen.gen('IP').add('IGMPv3', type: 'MembershipQuery').add('IGMPv3::MR')
|
63
64
|
# pkt.igmpv3 #=> PacketGen::Header::IGMPv3
|
@@ -71,7 +72,7 @@ module PacketGen
|
|
71
72
|
'MembershipReport' => 0x22,
|
72
73
|
}.freeze
|
73
74
|
|
74
|
-
|
75
|
+
remove_attr :group_addr
|
75
76
|
|
76
77
|
# Encode value for IGMPv3 Max Resp Code and QQIC.
|
77
78
|
# Value may be encoded as a float, so some error may occur.
|
@@ -11,23 +11,24 @@ module PacketGen
|
|
11
11
|
class IP
|
12
12
|
# IP address, as a group of 4 bytes
|
13
13
|
# @author Sylvain Daubert
|
14
|
-
class Addr <
|
15
|
-
include
|
14
|
+
class Addr < BinStruct::Struct
|
15
|
+
include BinStruct::Structable
|
16
16
|
|
17
17
|
# @!attribute a1
|
18
18
|
# @return [Integer] IP address first byte
|
19
|
-
|
19
|
+
define_attr :a1, BinStruct::Int8
|
20
20
|
# @!attribute a2
|
21
|
-
# @return [Integer] IP address
|
22
|
-
|
21
|
+
# @return [Integer] IP address second byte
|
22
|
+
define_attr :a2, BinStruct::Int8
|
23
23
|
# @!attribute a3
|
24
24
|
# @return [Integer] IP address third byte
|
25
|
-
|
25
|
+
define_attr :a3, BinStruct::Int8
|
26
26
|
# @!attribute a4
|
27
27
|
# @return [Integer] IP address fourth byte
|
28
|
-
|
28
|
+
define_attr :a4, BinStruct::Int8
|
29
29
|
|
30
|
-
|
30
|
+
## Regex to match IPv4 addresses
|
31
|
+
IPV4_ADDR_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
|
31
32
|
|
32
33
|
# Read a dotted address
|
33
34
|
# @param [String] str
|
@@ -37,10 +38,10 @@ module PacketGen
|
|
37
38
|
|
38
39
|
m = str.match(IPV4_ADDR_REGEX)
|
39
40
|
if m
|
40
|
-
self[:a1].
|
41
|
-
self[:a2].
|
42
|
-
self[:a3].
|
43
|
-
self[:a4].
|
41
|
+
self[:a1].from_human(m[1].to_i)
|
42
|
+
self[:a2].from_human(m[2].to_i)
|
43
|
+
self[:a3].from_human(m[3].to_i)
|
44
|
+
self[:a4].from_human(m[4].to_i)
|
44
45
|
end
|
45
46
|
self
|
46
47
|
end
|
@@ -48,10 +49,10 @@ module PacketGen
|
|
48
49
|
# Addr in human readable form (dotted format)
|
49
50
|
# @return [String]
|
50
51
|
def to_human
|
51
|
-
|
52
|
+
attributes.map { |f| self[f].to_i.to_s }.join('.')
|
52
53
|
end
|
53
54
|
|
54
|
-
# Addr as
|
55
|
+
# Addr as a 32-bit integer
|
55
56
|
# @return [Integer]
|
56
57
|
def to_i
|
57
58
|
(self.a1 << 24) | (self.a2 << 16) | (self.a3 << 8) |
|
@@ -64,9 +65,12 @@ module PacketGen
|
|
64
65
|
self.a1 >= 224 && self.a1 <= 239
|
65
66
|
end
|
66
67
|
|
68
|
+
# Check equality.
|
69
|
+
# Equal is other has same class and all attributes are equal.
|
70
|
+
# @return [Boolean]
|
67
71
|
def ==(other)
|
68
72
|
other.is_a?(self.class) &&
|
69
|
-
|
73
|
+
attributes.all? { |attr| self[attr].value == other[attr].value }
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|