packetgen 1.4.3 → 2.0.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: 4b5b7c4c6b94e7e5e2323d99a06f687109495539
4
- data.tar.gz: 363abe5a21f82d8f0fe8f791912109c55d795218
3
+ metadata.gz: 77561a943f0b532168700f1752631dd1f8080ebf
4
+ data.tar.gz: 36a505013a6ff0e37a35e64d62ec627dcba5dc22
5
5
  SHA512:
6
- metadata.gz: 7782f886a780d71bd9e976bb9185742979f8a5d0a4818a07a9b8c249d4628616db690a4620e80a346ec19357df288c4d2b598804095b648e1373cf9f99c15a73
7
- data.tar.gz: e8838e0e6ba458472090661066cdd90ac4358f02e4eea53adf4c2c09867ee83c0e4c318241a30f0cb255d91cf393319002b378c174161744596b2bd2f84e2e2d
6
+ metadata.gz: f72762403800113f9816892b1d7d0df0e5fa417a28afbbc7cf56a5b15d340100721ce46bdc2fcb003a2818dec57780bdb8d3172cbe4bdcad2ba8a2dc4ed8ab16
7
+ data.tar.gz: cae3e091c5423afd66ab45a2ebea34a265e9b5a751b14bfb42e9a04bb92deb6945af0c5a85ed9520d96e721f33c815817b9898aca74bb6e51277eb3855809ed5
data/.travis.yml CHANGED
@@ -1,10 +1,9 @@
1
1
  language: ruby
2
2
  sudo: required
3
3
  rvm:
4
- - 2.1
5
- - 2.2
6
- - 2.3.3
7
- - 2.4.0
4
+ - 2.2.7
5
+ - 2.3.4
6
+ - 2.4.1
8
7
 
9
8
  install:
10
9
  - sudo apt-get update -qq
data/README.md CHANGED
@@ -36,11 +36,11 @@ PacketGen.gen('IP').to_s
36
36
  ### Send packets on wire
37
37
  ```ruby
38
38
  # send Ethernet packet
39
- PacketGen.gen('Eth', src: '00:00:00:00:01', dst: '00:00:00:00:02').to_w
39
+ PacketGen.gen('Eth', src: '00:00:00:00:00:01', dst: '00:00:00:00:00:02').to_w
40
40
  # send IP packet
41
41
  PacketGen.gen('IP', src: '192.168.1.1', dst: '192.168.1.2').to_w
42
42
  # send forged IP packet over Ethernet
43
- PacketGen.gen('Eth', src: '00:00:00:00:01', dst: '00:00:00:00:02').add('IP').to_w('eth1')
43
+ PacketGen.gen('Eth', src: '00:00:00:00:00:01', dst: '00:00:00:00:00:02').add('IP').to_w('eth1')
44
44
  ```
45
45
 
46
46
  ### Parse packets from binary data
@@ -50,16 +50,16 @@ packet = PacketGen.parse(binary_data)
50
50
 
51
51
  ### Capture packets from wire
52
52
  ```ruby
53
- # Capture packets, action from a block
54
- PacketGen.capture('eth0') do |packet|
53
+ # Capture packets from first network interface, action from a block
54
+ PacketGen.capture do |packet|
55
55
  do_stuffs_with_packet
56
56
  end
57
57
 
58
58
  # Capture some packets, and act on them afterward
59
- packets = PacketGen.capture('eth0', max: 10) # return when 10 packets were captured
59
+ packets = PacketGen.capture(iface: 'eth0', max: 10) # return when 10 packets were captured
60
60
 
61
61
  # Use filters
62
- packets = PacketGen.capture('eth0', filter: 'ip src 1.1.1.2', max: 1)
62
+ packets = PacketGen.capture(iface: 'eth0', filter: 'ip src 1.1.1.2', max: 1)
63
63
  ```
64
64
 
65
65
  ### Easily manipulate packets
data/lib/packetgen.rb CHANGED
@@ -38,7 +38,6 @@ module PacketGen
38
38
  end
39
39
 
40
40
  # Shortcut for {Packet.capture}
41
- # @param [String] iface interface name
42
41
  # @param [Hash] options capture options. See {Packet.capture}.
43
42
  # @yieldparam [Packet] packet
44
43
  # @return [Array<Packet>]
@@ -25,49 +25,27 @@ module PacketGen
25
25
  # @return [String]
26
26
  attr_reader :iface
27
27
 
28
- # @overload initialize(iface=Pcap.lookupdev, options={})
29
- # @param [String] iface interface on which capture packets
30
- # @param [Hash] options
31
- # @option options [Integer] :max maximum number of packets to capture.
32
- # @option options [Integer] :timeout maximum number of seconds before end
33
- # of capture. Default: +nil+ (no timeout)
34
- # @option options [String] :filter bpf filter
35
- # @option options [Boolean] :promiscuous (default: +false+)
36
- # @option options [Boolean] :parse parse raw data to generate packets before
37
- # yielding. Default: +true+
38
- # @option options [Integer] :snaplen maximum number of bytes to capture for
39
- # each packet.
40
- # @overload initialize(options={})
41
- # @param [Hash] options
42
- # @option options [String] :iface interface on which capture
43
- # packets on. Default: Use default interface lookup. If no interface found,
44
- # use loopback one.
45
- # @option options [Integer] :max maximum number of packets to capture.
46
- # @option options [Integer] :timeout maximum number of seconds before end
47
- # of capture. Default: +nil+ (no timeout)
48
- # @option options [String] :filter bpf filter
49
- # @option options [Boolean] :promiscuous (default: +false+)
50
- # @option options [Boolean] :parse parse raw data to generate packets before
51
- # yielding. Default: +true+
52
- # @option options [Integer] :snaplen maximum number of bytes to capture for
53
- # each packet.
54
- def initialize(iface_or_options={}, options={})
28
+ # @param [Hash] options
29
+ # @option options [String] :iface interface on which capture
30
+ # packets on. Default: Use default interface lookup. If no interface found,
31
+ # use loopback one.
32
+ # @option options [Integer] :max maximum number of packets to capture.
33
+ # @option options [Integer] :timeout maximum number of seconds before end
34
+ # of capture. Default: +nil+ (no timeout)
35
+ # @option options [String] :filter bpf filter
36
+ # @option options [Boolean] :promiscuous (default: +false+)
37
+ # @option options [Boolean] :parse parse raw data to generate packets before
38
+ # yielding. Default: +true+
39
+ # @option options [Integer] :snaplen maximum number of bytes to capture for
40
+ # each packet.
41
+ # @since 2.0.0 remove old 1.x API
42
+ def initialize(options={})
55
43
  begin
56
44
  @iface = Pcap.lookupdev
57
45
  rescue PCAPRUB::BindingError
58
46
  @iface = 'lo'
59
47
  end
60
48
 
61
- case iface_or_options
62
- when Hash
63
- options = iface_or_options
64
- else
65
- warn "[deprecation] use of PacketGen::Capture#initialize with iface name as\n" \
66
- " first argument is deprecated. Instead, use:\n" \
67
- ' PacketGen::Capture.new(iface: \'name\').'
68
- @iface = iface_or_options.to_s
69
- end
70
-
71
49
  @packets = []
72
50
  @raw_packets = []
73
51
  @promisc = false
@@ -48,7 +48,7 @@ module PacketGen
48
48
  # @return [void]
49
49
  # @since 1.1.0
50
50
  def self.add_class(klass)
51
- protocol_name = klass.to_s.sub(/.*::/, '')
51
+ protocol_name = klass.new.protocol_name
52
52
  @added_header_classes[protocol_name] = klass
53
53
  @header_classes = nil
54
54
  end
@@ -59,7 +59,7 @@ module PacketGen
59
59
  # @return [void]
60
60
  # @since 1.1.0
61
61
  def self.remove_class(klass)
62
- protocol_name = klass.to_s.sub(/.*::/, '')
62
+ protocol_name = klass.new.protocol_name
63
63
  @added_header_classes.delete protocol_name
64
64
  @header_classes = nil
65
65
  end
@@ -78,6 +78,7 @@ module PacketGen
78
78
  end
79
79
  end
80
80
 
81
+ require_relative 'header/crypto'
81
82
  require_relative 'header/base'
82
83
  require_relative 'header/eth'
83
84
  require_relative 'header/dot11'
@@ -92,4 +93,7 @@ require_relative 'header/icmpv6'
92
93
  require_relative 'header/udp'
93
94
  require_relative 'header/tcp'
94
95
  require_relative 'header/esp'
96
+ require_relative 'header/ike'
95
97
  require_relative 'header/dns'
98
+ require_relative 'header/asn1_base'
99
+ require_relative 'header/snmp'
@@ -0,0 +1,86 @@
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
+ require 'rasn1'
6
+
7
+ module PacketGen
8
+ module Header
9
+
10
+ # @abstract Base class for ASN.1 header types.
11
+ # Subclasses may define magic methods:
12
+ # * {#parse?}.
13
+ # @author Sylvain Daubert
14
+ class ASN1Base < RASN1::Model
15
+
16
+ # @api private
17
+ # Reference on packet which owns this header
18
+ attr_accessor :packet
19
+
20
+ # Give protocol name for this class
21
+ # @return [String]
22
+ # @since 2.0.0
23
+ def self.protocol_name
24
+ self.new.protocol_name
25
+ end
26
+
27
+ # Define some methods from given ASN.1 fields to mimic {Base} attributes
28
+ # @param [Array<Symbol>] attributes
29
+ # @return [void]
30
+ def self.define_attributes(*attributes)
31
+ @attributes = attributes
32
+ attributes.each do |attr|
33
+ class_eval "def #{attr}; @elements[:#{attr}].value; end\n" \
34
+ "def #{attr}=(v); @elements[:#{attr}].value = v; end"
35
+ end
36
+ end
37
+
38
+ # Return header protocol name
39
+ # @return [String]
40
+ def protocol_name
41
+ return @protocol_name if @protocol_name
42
+
43
+ classname = self.class.to_s
44
+ @protocol_name = if classname.start_with?('PacketGen::Header')
45
+ classname.sub(/.*Header::/, '')
46
+ else
47
+ classname.sub(/.*::/, '')
48
+ end
49
+ end
50
+ # return header method name
51
+ # @return [String]
52
+ # @since 2.0.0
53
+ def method_name
54
+ return @method_name if @method_name
55
+
56
+ @method_name = protocol_name.downcase.sub(/::/, '_')
57
+ end
58
+
59
+ # @return [true]
60
+ def parse?
61
+ true
62
+ end
63
+
64
+ alias :parse :parse!
65
+ alias :to_s :to_der
66
+
67
+ # Read a BER string
68
+ # @param [String] str
69
+ # @return [ASN1Base] self
70
+ def read(str)
71
+ parse(str, ber: true)
72
+ self
73
+ end
74
+
75
+ # Common inspect method for ASN.1 headers
76
+ # @return [String]
77
+ def inspect
78
+ str = Inspect.dashed_line(self.class, 2)
79
+ self.class.class_eval { @attributes }.each do |attr|
80
+ str << Inspect.inspect_asn1_attribute(attr, self[attr], 2)
81
+ end
82
+ str
83
+ end
84
+ end
85
+ end
86
+ end
@@ -6,8 +6,9 @@
6
6
  module PacketGen
7
7
  module Header
8
8
 
9
- # @abstract
10
- # Base class for all header types
9
+ # @abstract Base class for all header types.
10
+ # Subclasses may define magic methods:
11
+ # * {#parse?}.
11
12
  # @author Sylvain Daubert
12
13
  class Base < Types::Fields
13
14
 
@@ -39,6 +40,32 @@ module PacketGen
39
40
  end
40
41
  end
41
42
 
43
+ # @api private
44
+ # Class to handle a header association from procs
45
+ class ProcBinding
46
+
47
+ # @param [Array<Proc>] procs first proc is used to set fields, second proc is
48
+ # used to check binding
49
+ def initialize(procs)
50
+ @set = procs.shift
51
+ @check = procs.shift
52
+ end
53
+
54
+ # Check +fields+ responds to binding
55
+ # @param [Types::Fields] fields
56
+ # @return [Boolean]
57
+ def check?(fields)
58
+ @check.call(fields)
59
+ end
60
+
61
+ # Set +fields+ field to binding value
62
+ # @param [Types::Fields] fields
63
+ # @return [void]
64
+ def set(fields)
65
+ @set.call(fields)
66
+ end
67
+ end
68
+
42
69
  # @api private
43
70
  # Class to handle header associations
44
71
  class Bindings
@@ -100,41 +127,6 @@ module PacketGen
100
127
  end
101
128
  end
102
129
 
103
- # @api private
104
- # Class to handle header associations
105
- class Bindings
106
- include Enumerable
107
-
108
- # op type
109
- # @return [:or,:and]
110
- attr_accessor :op
111
- # @return [Array<Binding>]
112
- attr_accessor :bindings
113
-
114
- # @param [:or, :and] op
115
- def initialize(op)
116
- @op = op
117
- @bindings = []
118
- end
119
-
120
- # @param [Object] arg
121
- # @return [Bindings] self
122
- def <<(arg)
123
- @bindings << arg
124
- end
125
-
126
- # each iterator
127
- # @return [void]
128
- def each
129
- @bindings.each { |b| yield b }
130
- end
131
-
132
- # @return [Boolean]
133
- def empty?
134
- @bindings.empty?
135
- end
136
- end
137
-
138
130
  # @api private
139
131
  # Reference on packet which owns this header
140
132
  attr_accessor :packet
@@ -149,9 +141,10 @@ module PacketGen
149
141
 
150
142
  # Bind a upper header to current class
151
143
  # Header1.bind_header Header2, field1: 43
152
- # Header1.bind_header Header2, field1: 43, field2: 43
153
- # Header1.bind_header Header2, op: :and, field1: 43, field2: 43
154
- # Header1.bind_header Header2, field1: ->(v) { v.nil? ? 128 : v > 127 }
144
+ # Header1.bind_header Header3, field1: 43, field2: 43
145
+ # Header1.bind_header Header4, op: :and, field1: 43, field2: 43
146
+ # Header1.bind_header Header5, field1: ->(v) { v.nil? ? 128 : v > 127 }
147
+ # Header1.bind_header Header6, proc: ->(pkt) { pkt.header1.field1 == 1 && pkt.header1.body[0..1] == "\x00\x00" }
155
148
  # @param [Class] header_klass header class to bind to current class
156
149
  # @param [Hash] args current class fields and their value when +header_klass+
157
150
  # is embedded in current class. Given value may be a lambda, whose alone argument
@@ -165,13 +158,28 @@ module PacketGen
165
158
  # @return [void]
166
159
  def self.bind_header(header_klass, args={})
167
160
  op = args.delete(:op) || :or
168
- bindings = Bindings.new(op)
169
- @known_headers[header_klass] = bindings
161
+ if @known_headers[header_klass].nil? || @known_headers[header_klass].op != op
162
+ bindings = Bindings.new(op)
163
+ @known_headers[header_klass] = bindings
164
+ else
165
+ bindings = @known_headers[header_klass]
166
+ end
170
167
  args.each do |key, value|
171
- bindings << Binding.new(key, value)
168
+ if key == :procs
169
+ bindings << ProcBinding.new(value)
170
+ else
171
+ bindings << Binding.new(key, value)
172
+ end
172
173
  end
173
174
  end
174
175
 
176
+ # Give protocol name for this class
177
+ # @return [String]
178
+ # @since 2.0.0
179
+ def self.protocol_name
180
+ self.new.protocol_name
181
+ end
182
+
175
183
  # @api private
176
184
  # Get knwon headers
177
185
  # @return [Hash] keys: header classes, values: hashes
@@ -182,7 +190,23 @@ module PacketGen
182
190
  # Return header protocol name
183
191
  # @return [String]
184
192
  def protocol_name
185
- self.class.to_s.sub(/.*::/, '')
193
+ return @protocol_name if @protocol_name
194
+
195
+ classname = self.class.to_s
196
+ @protocol_name = if classname.start_with?('PacketGen::Header')
197
+ classname.sub(/.*Header::/, '')
198
+ else
199
+ classname.sub(/.*::/, '')
200
+ end
201
+ end
202
+
203
+ # return header method name
204
+ # @return [String]
205
+ # @since 2.0.0
206
+ def method_name
207
+ return @method_name if @method_name
208
+
209
+ @method_name = protocol_name.downcase.sub(/::/, '_')
186
210
  end
187
211
 
188
212
  # @abstract Should be redefined by subclasses. This method should check invariant
@@ -0,0 +1,62 @@
1
+ module PacketGen
2
+ module Header
3
+
4
+ # Mixin for cryptographic classes
5
+ # @api private
6
+ # @author Sylvain Daubert
7
+ module Crypto
8
+
9
+ # Cryptographic error
10
+ class Error < PacketGen::Error; end
11
+
12
+ # Register cryptographic modes
13
+ # @param [OpenSSL::Cipher] conf
14
+ # @param [OpenSSL::HMAC] intg
15
+ # @return [void]
16
+ def set_crypto(conf, intg)
17
+ @conf, @intg = conf, intg
18
+ if conf.authenticated?
19
+ # #auth_tag_len only supported from ruby 2.4.0
20
+ @conf.auth_tag_len = @trunc if @conf.respond_to? :auth_tag_len
21
+ end
22
+ end
23
+
24
+ # Get confidentiality mode name
25
+ # @return [String]
26
+ def confidentiality_mode
27
+ mode = @conf.name.match(/-([^-]*)$/)[1]
28
+ raise Error, 'unknown cipher mode' if mode.nil?
29
+ mode.downcase
30
+ end
31
+
32
+ # Say if crypto modes permit authentication
33
+ # @return [Boolean]
34
+ def authenticated?
35
+ @conf.authenticated? or !!@intg
36
+ end
37
+
38
+ def authenticate!
39
+ @conf.final
40
+ if @intg
41
+ @intg.update @esn.to_s if @esn
42
+ @intg.digest[0, @icv_length] == @icv
43
+ else
44
+ true
45
+ end
46
+ rescue OpenSSL::Cipher::CipherError
47
+ false
48
+ end
49
+
50
+ def encipher(data)
51
+ enciphered_data = @conf.update(data)
52
+ @intg.update(enciphered_data) if @intg
53
+ enciphered_data
54
+ end
55
+
56
+ def decipher(data)
57
+ @intg.update(data) if @intg
58
+ @conf.update(data)
59
+ end
60
+ end
61
+ end
62
+ end