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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed1c35530cd3ce2e62507e1a78c92fb5f764a49b
4
- data.tar.gz: 77d4baf7bc094aa0b04d7e6035e9420233135008
3
+ metadata.gz: d08bf3611fcb1af6c5e794d4582fe373b4887c02
4
+ data.tar.gz: 7149de75ef5a5ebaca9d9b90239ffce8619c38c4
5
5
  SHA512:
6
- metadata.gz: dbe78e47c236179d9d866ce997778c1b2b65633b751d47d72948bcb0f7f56ccb8bf52fbdd1dd1292844d064493502a11392a7c4c9582552b452522d235bf22b7
7
- data.tar.gz: 8c972a697a5bbd5c4654c973b1da378c8e733fb8c1887310b281acd0e36ef5de2e83259da0dfdca75a6da54f3c5af510d7cdc943af338aea839f661663ada014
6
+ metadata.gz: 82804e0c46bc17d30c6bc151a24b3fc415c476aa1159239330611d2b8ef3ef7d2013dc7078bb40e298d29c0e81f3e758f53e82ff280acc0548b37dc78ff7d8be
7
+ data.tar.gz: 6f4c84f64e8728af30a61d56b22dce9eb34fa574984eafe427d48cebdac1446344f1f5dd37370604d58b9df4bb1af587135348ad682e15d3ce97d45cfd769ed1
@@ -4,6 +4,7 @@ rvm:
4
4
  - 2.2.7
5
5
  - 2.3.5
6
6
  - 2.4.2
7
+ - 2.5.0
7
8
 
8
9
  install:
9
10
  - sudo apt-get update -qq
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
- Via RubyGems:
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
 
@@ -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'
@@ -52,7 +52,6 @@ module PacketGen
52
52
  end
53
53
 
54
54
  self.add_class ICMPv6
55
-
56
55
  IPv6.bind_header ICMPv6, next: ICMPv6::IP_PROTOCOL
57
56
  end
58
57
  end
@@ -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