packetfu 1.1.13 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/ISSUE_TEMPLATE.md +29 -0
  4. data/.github/workflows/verify.yml +72 -0
  5. data/.travis.yml +10 -6
  6. data/LICENSE.txt +1 -1
  7. data/README.md +8 -8
  8. data/certs/todb.pem +25 -0
  9. data/examples/100kpackets.rb +2 -2
  10. data/examples/ackscan.rb +7 -6
  11. data/examples/pcap2pcapng.rb +2 -2
  12. data/examples/readpcap.rb +28 -0
  13. data/lib/packetfu/capture.rb +1 -1
  14. data/lib/packetfu/config.rb +2 -2
  15. data/lib/packetfu/inject.rb +1 -1
  16. data/lib/packetfu/packet.rb +6 -3
  17. data/lib/packetfu/pcap.rb +25 -25
  18. data/lib/packetfu/pcapng/file.rb +1 -1
  19. data/lib/packetfu/protos/arp.rb +1 -8
  20. data/lib/packetfu/protos/eth.rb +0 -7
  21. data/lib/packetfu/protos/hsrp.rb +0 -7
  22. data/lib/packetfu/protos/icmp/header.rb +7 -10
  23. data/lib/packetfu/protos/icmp.rb +0 -7
  24. data/lib/packetfu/protos/icmpv6.rb +4 -17
  25. data/lib/packetfu/protos/ip/header.rb +2 -2
  26. data/lib/packetfu/protos/ip/mixin.rb +9 -0
  27. data/lib/packetfu/protos/ip.rb +0 -8
  28. data/lib/packetfu/protos/ipv6/mixin.rb +12 -0
  29. data/lib/packetfu/protos/ipv6.rb +0 -7
  30. data/lib/packetfu/protos/lldp.rb +1 -8
  31. data/lib/packetfu/protos/tcp.rb +73 -30
  32. data/lib/packetfu/protos/udp/header.rb +4 -5
  33. data/lib/packetfu/protos/udp.rb +6 -18
  34. data/lib/packetfu/structfu.rb +1 -1
  35. data/lib/packetfu/version.rb +1 -1
  36. data/packetfu.gemspec +10 -18
  37. data/spec/arp_spec.rb +1 -1
  38. data/spec/capture_spec.rb +137 -0
  39. data/spec/eth_spec.rb +1 -1
  40. data/spec/icmp_spec.rb +1 -1
  41. data/spec/icmpv6_spec.rb +1 -1
  42. data/spec/inject_spec.rb +95 -0
  43. data/spec/ip_spec.rb +23 -1
  44. data/spec/packetfu_spec.rb +1 -1
  45. data/spec/pcap_spec.rb +3 -3
  46. data/spec/pcapng/file_spec.rb +1 -1
  47. data/spec/spec_helper.rb +4 -2
  48. data/spec/structfu_spec.rb +86 -82
  49. data/spec/tcp_spec.rb +155 -53
  50. data/test/sample-ipv6.pcap +0 -0
  51. data.tar.gz.sig +0 -0
  52. metadata +64 -37
  53. metadata.gz.sig +0 -0
  54. data/test/test_capture.rb +0 -58
  55. data/test/test_inject.rb +0 -31
  56. data/test/test_structfu.rb +0 -114
@@ -23,7 +23,7 @@ module PacketFu
23
23
  # icmpv6_pkt.ipv6_saddr="2000::1234"
24
24
  # icmpv6_pkt.ipv6_daddr="2000::5678"
25
25
  #
26
- # icmpv6_pkt.recalc
26
+ # icmpv6_pkt.recalc
27
27
  # icmpv6_pkt.to_f('/tmp/icmpv6.pcap')
28
28
  #
29
29
  # == Parameters
@@ -49,13 +49,6 @@ module PacketFu
49
49
  return true
50
50
  end
51
51
 
52
- def read(str=nil, args={})
53
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
54
- @eth_header.read(str)
55
- super(args)
56
- self
57
- end
58
-
59
52
  def initialize(args={})
60
53
  @eth_header = EthHeader.new(args).read(args[:eth])
61
54
  @ipv6_header = IPv6Header.new(args).read(args[:ipv6])
@@ -72,12 +65,7 @@ module PacketFu
72
65
 
73
66
  # Calculates the checksum for the object.
74
67
  def icmpv6_calc_sum
75
- checksum = 0
76
-
77
- # Compute sum on pseudo-header
78
- [ipv6_src, ipv6_dst].each do |iaddr|
79
- 8.times { |i| checksum += (iaddr >> (i*16)) & 0xffff }
80
- end
68
+ checksum = ipv6_calc_sum_on_addr
81
69
  checksum += PacketFu::ICMPv6Header::PROTOCOL_NUMBER
82
70
  checksum += ipv6_len
83
71
  # Then compute it on ICMPv6 header + payload
@@ -96,9 +84,8 @@ module PacketFu
96
84
  end
97
85
 
98
86
  # Recalculates the calculatable fields for ICMPv6.
99
- def icmpv6_recalc(arg=:all)
100
- arg = arg.intern if arg.respond_to? :intern
101
- case arg
87
+ def icmpv6_recalc(arg = :all)
88
+ case arg.to_sym
102
89
  when :icmpv6_sum
103
90
  self.icmpv6_sum = icmpv6_calc_sum
104
91
  when :all
@@ -107,7 +107,7 @@ module PacketFu
107
107
  # Int16 :ip_len, Default: calculated
108
108
  # Int16 :ip_id, Default: calculated # IRL, hardly random.
109
109
  # Int16 :ip_frag, Default: 0 # TODO: Break out the bits
110
- # Int8 :ip_ttl, Default: 0xff # Changes per flavor
110
+ # Int8 :ip_ttl, Default: 64 # https://www.iana.org/assignments/ip-parameters/ip-parameters.xml
111
111
  # Int8 :ip_proto, Default: 0x01 # TCP: 0x06, UDP 0x11, ICMP 0x01
112
112
  # Int16 :ip_sum, Default: calculated
113
113
  # Octets :ip_src
@@ -131,7 +131,7 @@ module PacketFu
131
131
  Int16.new(args[:ip_len] || 20),
132
132
  Int16.new(args[:ip_id] || ip_calc_id),
133
133
  Int16.new(args[:ip_frag]),
134
- Int8.new(args[:ip_ttl] || 32),
134
+ Int8.new(args[:ip_ttl] || 64),
135
135
  Int8.new(args[:ip_proto]),
136
136
  Int16.new(args[:ip_sum] || ip_calc_sum),
137
137
  Octets.new.read(args[:ip_src] || "\x00\x00\x00\x00"),
@@ -40,5 +40,14 @@ module PacketFu
40
40
  def ip_ttl=(v); self.ip_header.ip_ttl= v; end
41
41
  def ip_v; self.ip_header.ip_v ; end
42
42
  def ip_v=(v); self.ip_header.ip_v= v; end
43
+
44
+ # Add method to each packet class on IP to ease checksum computation
45
+ def ip_calc_sum_on_addr(cksum=0)
46
+ checksum = cksum
47
+ checksum += (ip_src.to_i >> 16)
48
+ checksum += (ip_src.to_i & 0xffff)
49
+ checksum += (ip_dst.to_i >> 16)
50
+ checksum += (ip_dst.to_i & 0xffff)
51
+ end
43
52
  end
44
53
  end
@@ -16,7 +16,6 @@ module PacketFu
16
16
  # ip_pkt.ip_saddr="10.20.30.40"
17
17
  # ip_pkt.ip_daddr="192.168.1.1"
18
18
  # ip_pkt.ip_proto=1
19
- # ip_pkt.ip_ttl=64
20
19
  # ip_pkt.ip_payload="\x00\x00\x12\x34\x00\x01\x00\x01"+
21
20
  # "Lovingly hand-crafted echo responses delivered directly to your door."
22
21
  # ip_pkt.recalc
@@ -54,13 +53,6 @@ module PacketFu
54
53
  end
55
54
  end
56
55
 
57
- def read(str=nil, args={})
58
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
59
- @eth_header.read(str)
60
- super(args)
61
- self
62
- end
63
-
64
56
  # Creates a new IPPacket object.
65
57
  def initialize(args={})
66
58
  @eth_header = EthHeader.new(args).read(args[:eth])
@@ -28,5 +28,17 @@ module PacketFu
28
28
  def ipv6_daddr=(v); self.ipv6_header.ipv6_daddr= v; end
29
29
  def ipv6_src_readable; self.ipv6_header.ipv6_src_readable; end
30
30
  def ipv6_dst_readable; self.ipv6_header.ipv6_dst_readable; end
31
+ def ipv6?; not self.ipv6_header.nil?; end
32
+
33
+ # Add method to each packet class on IPv6 to ease checksum computation
34
+ def ipv6_calc_sum_on_addr(cksum=0)
35
+ checksum = cksum
36
+ [ipv6_src, ipv6_dst].each do |iaddr|
37
+ 8.times do |i|
38
+ checksum += (iaddr >> (i * 16)) & 0xffff
39
+ end
40
+ end
41
+ checksum
42
+ end
31
43
  end
32
44
  end
@@ -34,13 +34,6 @@ module PacketFu
34
34
  true
35
35
  end
36
36
 
37
- def read(str=nil,args={})
38
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
39
- @eth_header.read(str)
40
- super(args)
41
- self
42
- end
43
-
44
37
  def initialize(args={})
45
38
  @eth_header = (args[:eth] || EthHeader.new)
46
39
  @ipv6_header = (args[:ipv6] || IPv6Header.new)
@@ -8,7 +8,7 @@ require 'packetfu/protos/lldp/mixin'
8
8
  module PacketFu
9
9
 
10
10
  class LLDPPacket < Packet
11
- MAGIC = Regexp.new("^\x01\x80\xc2\x00\x00[\x0e\x03\x00]", nil, "n")
11
+ MAGIC = Regexp.new("^\x01\x80\xc2\x00\x00[\x0e\x03\x00]".force_encoding('ASCII-8BIT'), Regexp::NOENCODING)
12
12
  include ::PacketFu::EthHeaderMixin
13
13
  include ::PacketFu::LLDPHeaderMixin
14
14
 
@@ -22,13 +22,6 @@ module PacketFu
22
22
  true
23
23
  end
24
24
 
25
- def read(str=nil,args={})
26
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
27
- @eth_header.read(str)
28
- super(args)
29
- self
30
- end
31
-
32
25
  def initialize(args={})
33
26
  @eth_header = EthHeader.new(args).read(args[:eth])
34
27
  @lldp_header = LLDPHeader.new(args).read(args[:lldp])
@@ -8,6 +8,9 @@ require 'packetfu/protos/tcp/mixin'
8
8
  require 'packetfu/protos/ip/header'
9
9
  require 'packetfu/protos/ip/mixin'
10
10
 
11
+ require 'packetfu/protos/ipv6/header'
12
+ require 'packetfu/protos/ipv6/mixin'
13
+
11
14
  module PacketFu
12
15
  # TCPPacket is used to construct TCP packets. They contain an EthHeader, an IPHeader, and a TCPHeader.
13
16
  #
@@ -25,6 +28,16 @@ module PacketFu
25
28
  # tcp_pkt.recalc
26
29
  # tcp_pkt.to_f('/tmp/tcp.pcap')
27
30
  #
31
+ # tcp6_pkt = PacketFu::TCPPacket.new(:on_ipv6 => true)
32
+ # tcp6_pkt.tcp_flags.syn=1
33
+ # tcp6_pkt.tcp_dst=80
34
+ # tcp6_pkt.tcp_win=5840
35
+ # tcp6_pkt.tcp_options="mss:1460,sack.ok,ts:#{rand(0xffffffff)};0,nop,ws:7"
36
+ # tcp6_pkt.ipv6_saddr="4::1"
37
+ # tcp6_pkt.ipv6_daddr="12:3::4567"
38
+ # tcp6_pkt.recalc
39
+ # tcp6_pkt.to_f('/tmp/udp.pcap')
40
+ #
28
41
  # == Parameters
29
42
  # :eth
30
43
  # A pre-generated EthHeader object.
@@ -41,42 +54,58 @@ module PacketFu
41
54
  class TCPPacket < Packet
42
55
  include ::PacketFu::EthHeaderMixin
43
56
  include ::PacketFu::IPHeaderMixin
57
+ include ::PacketFu::IPv6HeaderMixin
44
58
  include ::PacketFu::TCPHeaderMixin
45
59
 
46
- attr_accessor :eth_header, :ip_header, :tcp_header
60
+ attr_accessor :eth_header, :ip_header, :ipv6_header, :tcp_header
47
61
 
48
62
  def self.can_parse?(str)
49
63
  return false unless str.size >= 54
50
64
  return false unless EthPacket.can_parse? str
51
- return false unless IPPacket.can_parse? str
52
- return false unless str[23,1] == "\x06"
53
- return true
65
+ if IPPacket.can_parse? str
66
+ return true if str[23,1] == "\x06"
67
+ elsif IPv6Packet.can_parse? str
68
+ return true if str[20,1] == "\x06"
69
+ end
70
+ return false
54
71
  end
55
72
 
56
73
  def read(str=nil, args={})
57
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
58
- @eth_header.read(str)
59
-
74
+ super
60
75
  # Strip off any extra data, if we are asked to do so.
61
76
  if args[:strip]
62
77
  tcp_body_len = self.ip_len - self.ip_hlen - (self.tcp_hlen * 4)
63
78
  @tcp_header.body.read(@tcp_header.body.to_s[0,tcp_body_len])
79
+ tcp_calc_sum
80
+ @ip_header.ip_recalc
64
81
  end
65
- super(args)
66
82
  self
67
83
  end
68
84
 
69
85
  def initialize(args={})
70
- @eth_header = (args[:eth] || EthHeader.new)
71
- @ip_header = (args[:ip] || IPHeader.new)
72
- @tcp_header = (args[:tcp] || TCPHeader.new)
73
- @tcp_header.flavor = args[:flavor].to_s.downcase
86
+ if args[:on_ipv6] or args[:ipv6]
87
+ @eth_header = EthHeader.new(args.merge(:eth_proto => 0x86dd)).read(args[:eth])
88
+ @ipv6_header = IPv6Header.new(args).read(args[:ipv6])
89
+ @tcp_header = TCPHeader.new(args).read(args[:tcp])
90
+
91
+ @ipv6_header.body = @tcp_header
92
+ @eth_header.body = @ipv6_header
93
+ @headers = [@eth_header, @ipv6_header, @tcp_header]
94
+
95
+ @ipv6_header.ipv6_next = 0x06
96
+ else
97
+ @eth_header = EthHeader.new(args.merge(:eth_proto => 0x0800)).read(args[:eth])
98
+ @ip_header = IPHeader.new(args).read(args[:ip])
99
+ @tcp_header = TCPHeader.new(args).read(args[:tcp])
74
100
 
75
- @ip_header.body = @tcp_header
76
- @eth_header.body = @ip_header
77
- @headers = [@eth_header, @ip_header, @tcp_header]
101
+ @ip_header.body = @tcp_header
102
+ @eth_header.body = @ip_header
103
+ @headers = [@eth_header, @ip_header, @tcp_header]
104
+
105
+ @ip_header.ip_proto = 0x06
106
+ end
107
+ @tcp_header.flavor = args[:flavor].to_s.downcase
78
108
 
79
- @ip_header.ip_proto=0x06
80
109
  super
81
110
  if args[:flavor]
82
111
  tcp_calc_flavor(@tcp_header.flavor)
@@ -118,12 +147,16 @@ module PacketFu
118
147
  # from the IP header, too.
119
148
  #++
120
149
  def tcp_calc_sum
121
- checksum = (ip_src.to_i >> 16)
122
- checksum += (ip_src.to_i & 0xffff)
123
- checksum += (ip_dst.to_i >> 16)
124
- checksum += (ip_dst.to_i & 0xffff)
150
+ if @ipv6_header
151
+ checksum = ipv6_calc_sum_on_addr
152
+ tcp_len = ipv6_len
153
+ else
154
+ checksum = ip_calc_sum_on_addr
155
+ tcp_len = ip_len.to_i - ((ip_hl.to_i) * 4)
156
+ end
157
+
125
158
  checksum += 0x06 # TCP Protocol.
126
- checksum += (ip_len.to_i - ((ip_hl.to_i) * 4))
159
+ checksum += tcp_len
127
160
  checksum += tcp_src
128
161
  checksum += tcp_dst
129
162
  checksum += (tcp_seq.to_i >> 16)
@@ -140,8 +173,8 @@ module PacketFu
140
173
 
141
174
  chk_tcp_opts = (tcp_opts.to_s.size % 2 == 0 ? tcp_opts.to_s : tcp_opts.to_s + "\x00")
142
175
  chk_tcp_opts.unpack("n*").each {|x| checksum = checksum + x }
143
- if (ip_len - ((ip_hl + tcp_hlen) * 4)) >= 0
144
- real_tcp_payload = payload[0,( ip_len - ((ip_hl + tcp_hlen) * 4) )] # Can't forget those pesky FCSes!
176
+ if (tcp_len - (tcp_hlen * 4)) >= 0
177
+ real_tcp_payload = payload[0, (tcp_len - (tcp_hlen * 4))] # Can't forget those pesky FCSes!
145
178
  else
146
179
  real_tcp_payload = payload # Something's amiss here so don't bother figuring out where the real payload is.
147
180
  end
@@ -181,19 +214,29 @@ module PacketFu
181
214
  # source and dest information, packet flags, sequence
182
215
  # number, and IPID.
183
216
  def peek_format
184
- peek_data = ["T "]
185
- peek_data << "%-5d" % self.to_s.size
186
- peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
187
- peek_data << "->"
188
- peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
217
+ if ipv6?
218
+ peek_data = ["6T "]
219
+ peek_data << "%-5d" % self.to_s.size
220
+ peek_data << "%-31s" % "#{self.ipv6_saddr}:#{self.tcp_src}"
221
+ peek_data << "->"
222
+ peek_data << "%31s" % "#{self.ipv6_daddr}:#{self.tcp_dst}"
223
+ else
224
+ peek_data = ["T "]
225
+ peek_data << "%-5d" % self.to_s.size
226
+ peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
227
+ peek_data << "->"
228
+ peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
229
+ end
189
230
  flags = ' ['
190
231
  flags << self.tcp_flags_dotmap
191
232
  flags << '] '
192
233
  peek_data << flags
193
234
  peek_data << "S:"
194
235
  peek_data << "%08x" % self.tcp_seq
195
- peek_data << "|I:"
196
- peek_data << "%04x" % self.ip_id
236
+ unless ipv6?
237
+ peek_data << "|I:"
238
+ peek_data << "%04x" % self.ip_id
239
+ end
197
240
  peek_data.join
198
241
  end
199
242
 
@@ -10,7 +10,7 @@ module PacketFu
10
10
  # Int16 :udp_src
11
11
  # Int16 :udp_dst
12
12
  # Int16 :udp_len Default: calculated
13
- # Int16 :udp_sum Default: 0. Often calculated.
13
+ # Int16 :udp_sum Default: 0. Often calculated.
14
14
  # String :body
15
15
  class UDPHeader < Struct.new(:udp_src, :udp_dst, :udp_len, :udp_sum, :body)
16
16
 
@@ -66,9 +66,8 @@ module PacketFu
66
66
  end
67
67
 
68
68
  # Recalculates calculated fields for UDP.
69
- def udp_recalc(args=:all)
70
- arg = arg.intern if arg.respond_to? :intern
71
- case args
69
+ def udp_recalc(arg = :all)
70
+ case arg.to_sym
72
71
  when :udp_len
73
72
  self.udp_len = udp_calc_len
74
73
  when :all
@@ -92,7 +91,7 @@ module PacketFu
92
91
  def udp_dport
93
92
  self.udp_dst
94
93
  end
95
-
94
+
96
95
  # Equivalent to udp_dst=
97
96
  def udp_dport=(arg)
98
97
  self.udp_dst=(arg)
@@ -64,13 +64,13 @@ module PacketFu
64
64
  end
65
65
 
66
66
  def read(str=nil, args={})
67
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
68
- @eth_header.read(str)
67
+ super
69
68
  if args[:strip]
70
69
  udp_body_len = self.ip_len - self.ip_hlen - 8
71
70
  @udp_header.body.read(@udp_header.body.to_s[0,udp_body_len])
71
+ udp_calc_sum
72
+ @ip_header.ip_recalc unless ipv6?
72
73
  end
73
- super(args)
74
74
  self
75
75
  end
76
76
 
@@ -103,19 +103,12 @@ module PacketFu
103
103
  def udp_calc_sum
104
104
  # This is /not/ delegated down to @udp_header since we need info
105
105
  # from the IP header, too.
106
- checksum = 0
107
106
  if @ipv6_header
108
- [ipv6_src, ipv6_dst].each do |iaddr|
109
- 8.times do |i|
110
- checksum += (iaddr >> (i * 16)) & 0xffff
111
- end
112
- end
107
+ checksum = ipv6_calc_sum_on_addr
113
108
  else
114
- checksum += (ip_src.to_i >> 16)
115
- checksum += (ip_src.to_i & 0xffff)
116
- checksum += (ip_dst.to_i >> 16)
117
- checksum += (ip_dst.to_i & 0xffff)
109
+ checksum = ip_calc_sum_on_addr
118
110
  end
111
+
119
112
  checksum += 0x11
120
113
  checksum += udp_len.to_i
121
114
  checksum += udp_src.to_i
@@ -179,11 +172,6 @@ module PacketFu
179
172
  end
180
173
  end
181
174
 
182
- # Is that packet an UDP on IPv6 packet ?
183
- def ipv6?
184
- not @ipv6_header.nil?
185
- end
186
-
187
175
  end
188
176
 
189
177
  end
@@ -18,7 +18,7 @@ module StructFu
18
18
  # expected type for that element.
19
19
  def typecast(i)
20
20
  c = caller[0].match(/.*`([^']+)='/)[1]
21
- self[c.intern].read i
21
+ self[c.to_sym].read i
22
22
  end
23
23
 
24
24
  # Used like typecast(), but specifically for casting Strings to StructFu::Strings.
@@ -2,7 +2,7 @@
2
2
  module PacketFu
3
3
 
4
4
  # Check the repo's for version release histories
5
- VERSION = "1.1.13"
5
+ VERSION = "2.0.0"
6
6
 
7
7
  # Returns PacketFu::VERSION
8
8
  def self.version
data/packetfu.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- require 'rake'
2
1
  require './lib/packetfu/version'
3
2
 
4
3
  Gem::Specification.new do |s|
@@ -14,26 +13,19 @@ Gem::Specification.new do |s|
14
13
  ease and fun they expect from Ruby.
15
14
  }
16
15
  s.files = `git ls-files`.split($/)
17
- s.license = 'BSD'
18
- s.required_ruby_version = '>= 2.1.0'
19
- s.add_dependency('pcaprub')
16
+ s.license = 'BSD-3-Clause'
17
+ s.required_ruby_version = '>= 2.7.0'
18
+ s.add_dependency('pcaprub', '~> 0.13.1')
20
19
  s.add_development_dependency('rake')
21
- s.add_development_dependency('rspec')
22
- s.add_development_dependency('rspec-its')
23
- s.add_development_dependency('sdoc')
24
- s.add_development_dependency('pry')
25
- s.add_development_dependency('coveralls')
26
-
20
+ s.add_development_dependency('rspec', '~> 3.0')
21
+ s.add_development_dependency('rspec-its', '~> 1.2')
22
+ s.add_development_dependency('sdoc', '~> 0.4')
23
+ s.add_development_dependency('pry-byebug')
24
+ s.add_development_dependency('coveralls', '~> 0.8')
27
25
 
28
26
  s.extra_rdoc_files = %w[.document README.md]
29
27
  s.test_files = (s.files & (Dir['spec/**/*_spec.rb'] + Dir['test/test_*.rb']) )
30
- s.rubyforge_project = 'packetfu'
31
-
32
- cert = File.expand_path("~/.ssh/gem-private_key_todb.pem")
33
-
34
- if File.exist?(cert) and File.readable?(cert)
35
- s.signing_key = cert
36
- s.cert_chain = ['gem-public_cert.pem']
37
- end
38
28
 
29
+ s.cert_chain = ['certs/todb.pem']
30
+ s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
39
31
  end
data/spec/arp_spec.rb CHANGED
@@ -190,7 +190,7 @@ describe ARPPacket do
190
190
  expect(@temp_file.read).to eql("")
191
191
 
192
192
  @arp_packet.to_f(@temp_file.path, 'a')
193
- expect(File.exists?(@temp_file.path)).to be(true)
193
+ expect(File.exist?(@temp_file.path)).to be(true)
194
194
  expect(@temp_file.read.size).to be >= 76
195
195
  end
196
196
  end
@@ -0,0 +1,137 @@
1
+ # -*- coding: binary -*-
2
+ require 'spec_helper'
3
+ require 'packetfu/protos/eth'
4
+ require 'packetfu/protos/ip'
5
+ require 'packetfu/protos/ipv6'
6
+ require 'packetfu/protos/tcp'
7
+ require 'packetfu/protos/icmp'
8
+ require 'packetfu/config'
9
+ require 'packetfu/pcap'
10
+ require 'packetfu/utils'
11
+ require 'tempfile'
12
+
13
+ include PacketFu
14
+
15
+ describe Capture do
16
+
17
+ if Process.uid != 0
18
+ warn "Not running as root, PacketFu::Capture capabilities that require root will be skipped"
19
+ end
20
+
21
+ context "when creating an object from scratch" do
22
+ before :each do
23
+ @capture = PacketFu::Capture.new
24
+ end
25
+
26
+ it "should have sane defaults" do
27
+ expect(@capture.array).to be_kind_of(Array)
28
+ expect(@capture.stream).to be_kind_of(Array)
29
+ expect(@capture.iface).to be_kind_of(String)
30
+ expect(@capture.snaplen).to eql(65535)
31
+ expect(@capture.promisc).to eql(false)
32
+ expect(@capture.timeout).to eql(1)
33
+
34
+ # Requires root/sudo to get this...
35
+ if Process.uid == 0
36
+ expect(@capture.filter).to eql(nil)
37
+ else
38
+ expect{@capture.filter}.to raise_error(RuntimeError)
39
+ end
40
+ end
41
+
42
+ it "should allow creating a capture object with non-std attributes" do
43
+ # Can only run this if we're root
44
+ if Process.uid == 0
45
+ options = {
46
+ :iface => PacketFu::Utils::default_int,
47
+ :snaplen => 0xfffe,
48
+ :promisc => true,
49
+ :timeout => 5,
50
+ :filter => "not port 22",
51
+ }
52
+ @capture = PacketFu::Capture.new(options)
53
+
54
+ expect(@capture.array).to be_kind_of(Array)
55
+ expect(@capture.stream).to be_kind_of(PCAPRUB::Pcap)
56
+ expect(@capture.iface).to eql(options[:iface])
57
+ expect(@capture.snaplen).to eql(options[:snaplen])
58
+ expect(@capture.promisc).to eql(options[:promisc])
59
+ expect(@capture.timeout).to eql(options[:timeout])
60
+ expect(@capture.filter).to eql(options[:filter])
61
+ expect(@capture.bpf).to eql(options[:filter])
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when capturing traffic on the wire" do
67
+ # Can only run this if we're root
68
+ if Process.uid == 0
69
+ it "should capture an ICMP echo request from the wire" do
70
+ daddr = PacketFu::Utils.rand_routable_daddr.to_s
71
+
72
+ def do_capture_test(daddr)
73
+ begin
74
+ Timeout::timeout(3) {
75
+ cap = PacketFu::Capture.new(:iface => PacketFu::Utils::default_int, :start => true)
76
+ cap.stream.each do |p|
77
+ pkt = PacketFu::Packet.parse p
78
+ next unless pkt.is_icmp?
79
+
80
+ if pkt.ip_daddr == daddr and pkt.icmp_type == 8
81
+ return true
82
+ end
83
+ end
84
+ }
85
+ rescue Timeout::Error
86
+ return false
87
+ end
88
+ end
89
+
90
+ capture_thread = Thread.new { expect(do_capture_test(daddr)).to eql(true) }
91
+ %x{ping -c 1 #{daddr}}
92
+ capture_thread.join
93
+ end
94
+
95
+ it "should capture only capture ICMP echo requests we ask for from the wire" do
96
+ daddr = PacketFu::Utils.rand_routable_daddr.to_s
97
+ daddr2 = PacketFu::Utils.rand_routable_daddr.to_s
98
+
99
+ def do_bpf_capture_test(daddr, daddr2)
100
+ count = 0
101
+ valid_icmp = false
102
+ invalid_icmp = false
103
+
104
+ begin
105
+ Timeout::timeout(3) {
106
+ cap = PacketFu::Capture.new(:iface => PacketFu::Utils::default_int, :start => true, :filter => "icmp and dst host #{daddr}")
107
+ cap.stream.each do |p|
108
+ pkt = PacketFu::Packet.parse p
109
+ next unless pkt.is_icmp?
110
+ count += 1
111
+
112
+ if pkt.ip_daddr == daddr and pkt.icmp_type == 8
113
+ valid_icmp = true
114
+ elsif pkt.ip_daddr == daddr2 and pkt.icmp_type == 8
115
+ invalid_icmp = true
116
+ end
117
+ end
118
+ }
119
+ rescue Timeout::Error
120
+ ### do nothing, we need to wait for the timeout anyways
121
+ end
122
+
123
+ if count == 1 && valid_icmp == true && invalid_icmp == false
124
+ return true
125
+ else
126
+ return false
127
+ end
128
+ end
129
+
130
+ capture_thread = Thread.new { expect(do_bpf_capture_test(daddr,daddr2)).to eql(true) }
131
+ %x{ping -c 1 #{daddr}}
132
+ %x{ping -c 1 #{daddr2}}
133
+ capture_thread.join
134
+ end
135
+ end
136
+ end
137
+ end
data/spec/eth_spec.rb CHANGED
@@ -130,7 +130,7 @@ describe EthPacket do
130
130
  expect(@temp_file.read).to eql("")
131
131
 
132
132
  @eth_packet.to_f(@temp_file.path, 'a')
133
- expect(File.exists?(@temp_file.path))
133
+ expect(File.exist?(@temp_file.path))
134
134
  expect(@temp_file.read.size).to be >= 30
135
135
  end
136
136
 
data/spec/icmp_spec.rb CHANGED
@@ -87,7 +87,7 @@ describe ICMPPacket, "when read from a pcap file" do
87
87
  expect(@temp_file.read).to eql("")
88
88
 
89
89
  @icmp_packet.to_f(@temp_file.path, 'a')
90
- expect(File.exists?(@temp_file.path))
90
+ expect(File.exist?(@temp_file.path))
91
91
  expect(@temp_file.read.size).to be >= 79
92
92
  end
93
93
 
data/spec/icmpv6_spec.rb CHANGED
@@ -80,7 +80,7 @@ describe ICMPv6Packet, "when read from a pcap file" do
80
80
  expect(@temp_file.read).to eql("")
81
81
 
82
82
  @icmpv6_packet.to_f(@temp_file.path, 'a')
83
- expect(File.exists?(@temp_file.path))
83
+ expect(File.exist?(@temp_file.path))
84
84
  expect(@temp_file.read.size).to be >= 79
85
85
  end
86
86