packetfu 1.1.6 → 1.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/.mailmap ADDED
@@ -0,0 +1,5 @@
1
+ Tod Beardsley <todb@packetfu.com> Tod Beardsley <tod_beardsley@rapid7.com>
2
+ Tod Beardsley <todb@packetfu.com> Tod Beardsley <todb@metasploit.com>
3
+ Tod Beardsley <todb@packetfu.com> Tod Beardsley <todb@planb-security.net>
4
+ Tod Beardsley <todb@packetfu.com> todb <todb@planb-security.net>
5
+
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = PacketFu
2
2
 
3
- A library for reading a writing packets to an interface or to a libpcap-formatted file.
3
+ A library for reading and writing packets to an interface or to a libpcap-formatted file.
4
4
 
5
5
  It is maintained at http://code.google.com/p/packetfu and https://github.com/todb/packetfu (which repository will win?)
6
6
 
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+
2
+ begin
3
+ require 'rspec/core/rake_task'
4
+ rescue LoadError
5
+ $stderr.puts "rspec not available, so can't set up spec tasks."
6
+ else
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default => :spec
10
+ end
11
+
data/examples/arp.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # (and a wee bit cleaner) is already available as Packet::Utils::arp, since knowing the
5
5
  # MAC address of a target IP turns out to be pretty useful day-to-day.
6
6
 
7
- require 'examples' # For path setting slight-of-hand
7
+ require './examples' # For path setting slight-of-hand
8
8
  require 'packetfu'
9
9
 
10
10
  def usage
data/examples/arphood.rb CHANGED
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  # A simple local network fingerprinter. Uses the OUI list.
4
+ # Usage: rvmsudo ./arphood.rb [iface] [network] <oui.txt>
4
5
 
5
- require 'examples'
6
+ require './examples'
6
7
  require 'packetfu'
7
8
  require 'open-uri'
8
9
 
9
10
  $oui_prefixes = {}
10
11
  $arp_results = []
11
12
  def build_oui_list
12
- if ARGV[0].nil?
13
- puts "Fetching the oui.txt from IEEE, it'll be a second. Avoid this with #{$0} <filename>."
13
+ if ARGV[2].nil?
14
+ puts "Fetching the oui.txt from IEEE, it'll be a second. Avoid this with #{$0} [iface] [network] <filename>."
14
15
  oui_file = open("http://standards.ieee.org/regauth/oui/oui.txt")
15
16
  else
16
- oui_file = File.open(ARGV[0], "rb")
17
+ oui_file = File.open(ARGV[2], "rb")
17
18
  end
18
19
  oui_file.each do |oui_line|
19
20
  maybe_oui = oui_line.scan(/^[0-9a-f]{2}\-[0-9a-f]{2}\-[0-9a-f]{2}/i)[0]
@@ -30,9 +31,9 @@ build_oui_list
30
31
  $root_ok = true if Process.euid.zero?
31
32
 
32
33
  def arp_everyone
33
- my_net = PacketFu::Config.new(PacketFu::Utils.whoami?(:iface => 'wlan0'))
34
+ my_net = PacketFu::Config.new(PacketFu::Utils.whoami?(:iface =>(ARGV[0] || 'wlan0')))
34
35
  threads = []
35
- network = "192.168.2"
36
+ network = ARGV[1] || "192.168.2"
36
37
  print "Arping around..."
37
38
  253.times do |i|
38
39
  threads[i] = Thread.new do
@@ -47,7 +48,7 @@ def arp_everyone
47
48
  $arp_results << "%s : %s / %s" % [this_host,colon_mac,$oui_prefixes[hyphen_mac]]
48
49
  end
49
50
  end
50
- threads.join
51
+ threads.each {|thr| thr.join}
51
52
  end
52
53
 
53
54
  if $root_ok
data/examples/ethernet.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- require 'examples' # For path setting slight-of-hand
2
+ require './examples' # For path setting slight-of-hand
3
3
  require 'packetfu'
4
4
 
5
5
  eth_pkt = PacketFu::EthPacket.new
@@ -8,7 +8,7 @@
8
8
  # every 11 seconds (my own benchmark) for this script, at least
9
9
  # it doesn't hog up all your memory.
10
10
 
11
- require 'examples' # For path setting slight-of-hand
11
+ require './examples' # For path setting slight-of-hand
12
12
  require 'packetfu'
13
13
 
14
14
  def print_results(stats)
@@ -44,7 +44,7 @@
44
44
  # => nil
45
45
 
46
46
  $: << File.expand_path(File.dirname(__FILE__) + "/../lib/")
47
- require 'examples'
47
+ require './examples'
48
48
  require 'packetfu'
49
49
 
50
50
  module PacketFu
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require 'examples'
2
+ require './examples'
3
3
  require 'packetfu'
4
4
 
5
5
  puts "Simple sniffer for PacketFu #{PacketFu.version}"
@@ -11,7 +11,7 @@ def sniff(iface)
11
11
  cap.stream.each do |p|
12
12
  pkt = Packet.parse p
13
13
  if pkt.is_ip?
14
- next if pkt.ip_saddr == Utils.ifconfig[:ip_saddr]
14
+ next if pkt.ip_saddr == Utils.ifconfig(iface)[:ip_saddr]
15
15
  packet_info = [pkt.ip_saddr, pkt.ip_daddr, pkt.size, pkt.proto.last]
16
16
  puts "%-15s -> %-15s %-4d %s" % packet_info
17
17
  end
@@ -9,7 +9,7 @@
9
9
  # See new-simple-stats.rb for an example of the streaming
10
10
  # parsing method.
11
11
 
12
- require 'examples' # For path setting slight-of-hand
12
+ require './examples' # For path setting slight-of-hand
13
13
  require 'packetfu'
14
14
 
15
15
  # Takes a file name, parses the packets, and records the packet
data/examples/uniqpcap.rb CHANGED
@@ -7,7 +7,7 @@
7
7
  # Currently, the timestamp information is lost due to PcapRub's
8
8
  # file read. For me, this isn't a big deal. Future versions
9
9
  # will deal with timestamps correctly.
10
- require 'examples' # For path setting slight-of-hand
10
+ require './examples' # For path setting slight-of-hand
11
11
  require 'packetfu'
12
12
 
13
13
  in_array = PacketFu::Read.f2a(:file => ARGV[0])
@@ -26,7 +26,7 @@ module PacketFu
26
26
  # Read, Write
27
27
  class Capture
28
28
  attr_accessor :array, :stream # Leave these public and open.
29
- attr_reader :iface, :snaplen, :promisc, :timeout # Cant change after the init.
29
+ attr_reader :iface, :snaplen, :promisc, :timeout, :filter
30
30
 
31
31
  def initialize(args={})
32
32
  @array = [] # Where the packet array goes.
@@ -35,13 +35,13 @@ module PacketFu
35
35
  @snaplen = args[:snaplen] || 0xffff
36
36
  @promisc = args[:promisc] || false # Sensible for some Intel wifi cards
37
37
  @timeout = args[:timeout] || 1
38
-
38
+ @filter = args[:filter] || args[:bpf]
39
39
  setup_params(args)
40
40
  end
41
41
 
42
42
  # Used by new().
43
43
  def setup_params(args={})
44
- filter = args[:filter] # Not global; filter criteria can change.
44
+ filter = args[:filter] || args[:bpf] || @filter
45
45
  start = args[:start] || false
46
46
  capture if start
47
47
  bpf(:filter=>filter) if filter
@@ -55,7 +55,7 @@ module PacketFu
55
55
  # When true, start capturing packets to the @stream variable. Defaults to true
56
56
  def capture(args={})
57
57
  if Process.euid.zero?
58
- filter = args[:filter]
58
+ filter = args[:filter] || args[:bpf] || @filter
59
59
  start = args[:start] || true
60
60
  if start
61
61
  begin
@@ -98,11 +98,14 @@ module PacketFu
98
98
  # :filter
99
99
  # Provide a bpf filter to enable for the capture. For example, 'ip and not tcp'
100
100
  def bpf(args={})
101
- filter = args[:filter]
101
+ filter = args[:filter] || args[:bpf] || @filter
102
102
  capture if @stream.class == Array
103
- @stream.setfilter(filter)
103
+ @stream.setfilter(filter) if filter
104
+ @filter = filter
104
105
  end
105
106
 
107
+ alias :filter :bpf
108
+
106
109
  # wire_to_array() saves a packet stream as an array of binary strings. From here,
107
110
  # packets may accessed by other functions. Note that the wire_to_array empties
108
111
  # the stream, so multiple calls will append new packets to @array.
@@ -111,7 +114,7 @@ module PacketFu
111
114
  # :filter
112
115
  # Provide a bpf filter to apply to packets moving from @stream to @array.
113
116
  def wire_to_array(args={})
114
- filter = args[:filter]
117
+ filter = args[:filter] || args[:bpf] || @filter
115
118
  bpf(:filter=>filter) if filter
116
119
 
117
120
  while this_pkt = @stream.next
@@ -146,7 +149,7 @@ module PacketFu
146
149
  # :quiet
147
150
  # TODO: Not implemented yet; do less than peek() at the packets.
148
151
  def show_live(args={})
149
- filter = args[:filter]
152
+ filter = args[:filter] || args[:bpf] || @filter
150
153
  save = args[:save]
151
154
  verbose = args[:verbose] || args[:v] || false
152
155
  quiet = args[:quiet] || args[:q] || false # Setting q and v doesn't make a lot of sense but hey.
@@ -251,7 +251,7 @@ module PacketFu
251
251
  case self.name # Lol ran into case's fancy treatment of classes
252
252
  when /InvalidPacket$/; 0
253
253
  when /EthPacket$/; 1
254
- when /IPPacket$/, /ARPPacket$/, /IPv6Packet$/; 2
254
+ when /IPPacket$/, /ARPPacket$/, /LLDPPacket$/, /IPv6Packet$/; 2
255
255
  when /TCPPacket$/, /UDPPacket$/, /ICMPPacket$/; 3
256
256
  when /HSRPPacket$/; 4
257
257
  else; self.new.headers.size
@@ -21,7 +21,7 @@ module PacketFu
21
21
 
22
22
  def self.can_parse?(str)
23
23
  # XXX Temporary fix. Need to extend the EthHeader class to handle more.
24
- valid_eth_types = [0x0800, 0x0806, 0x86dd]
24
+ valid_eth_types = [0x0800, 0x0806, 0x86dd, 0x88cc]
25
25
  return false unless str.size >= 14
26
26
  type = str[12,2].unpack("n").first rescue nil
27
27
  return false unless valid_eth_types.include? type
@@ -42,7 +42,7 @@ module PacketFu
42
42
  attr_accessor :eth_header, :ip_header, :icmp_header
43
43
 
44
44
  def self.can_parse?(str)
45
- return false unless str.size >= 54
45
+ return false unless str.size >= 38
46
46
  return false unless EthPacket.can_parse? str
47
47
  return false unless IPPacket.can_parse? str
48
48
  return false unless str[23,1] == "\x01"
@@ -0,0 +1,59 @@
1
+ require 'packetfu/protos/eth/header'
2
+ require 'packetfu/protos/eth/mixin'
3
+
4
+ require 'packetfu/protos/lldp/header'
5
+ require 'packetfu/protos/lldp/mixin'
6
+
7
+ module PacketFu
8
+
9
+ class LLDPPacket < Packet
10
+ include ::PacketFu::EthHeaderMixin
11
+ include ::PacketFu::LLDPHeaderMixin
12
+
13
+ attr_accessor :eth_header, :lldp_header
14
+
15
+ def self.can_parse?(str)
16
+ return false unless EthPacket.can_parse? str
17
+ return false unless str.size >= 6
18
+ return false unless str[12,2] == "\x88\xcc"
19
+ return false unless str =~ /^\x01\x80\xc2\x00\x00[\x0e\x03\x00]/
20
+ true
21
+ end
22
+
23
+ def read(str=nil,args={})
24
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
25
+ @eth_header.read(str)
26
+ super(args)
27
+ self
28
+ end
29
+
30
+ def initialize(args={})
31
+ @eth_header = EthHeader.new(args).read(args[:eth])
32
+ @lldp_header = LLDPHeader.new(args).read(args[:lldp])
33
+ @eth_header.eth_proto = "\x88\xCC"
34
+ @eth_header.body=@lldp_header
35
+
36
+ @headers = [@eth_header, @lldp_header]
37
+ super
38
+ end
39
+
40
+ # Generates summary data for LLDP packets.
41
+ def peek_format
42
+ peek_data = ["A "]
43
+ peek_data << "%-5d" % self.to_s.size
44
+ peek_data << lldp_saddr_mac
45
+ peek_data << "(#{lldp_saddr_mac})"
46
+ peek_data << "->"
47
+ peek_data << "01:80:c2:00:00:0e"
48
+ peek_data.join
49
+ end
50
+
51
+ # While there are lengths in LLDPPackets, there's not
52
+ # much to do with them.
53
+ def recalc(args={})
54
+ @headers[0].inspect
55
+ end
56
+ end
57
+ end
58
+
59
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -0,0 +1,250 @@
1
+ module PacketFu
2
+ # LLDPHeader is a complete LLDP struct, used in LLDPPacket.
3
+
4
+ class LLDPHeader < Struct.new(:lldp_chassis_id_type, :lldp_chassis_id, :lldp_port_id_type, :lldp_port_id, :lldp_ttl, :lldp_port_description, :lldp_system_name, :lldp_system_description, :lldp_capabilty, :lldp_enabled_capability, :lldp_address_type, :lldp_address, :lldp_interface_type, :lldp_interface, :lldp_oid)
5
+ include StructFu
6
+
7
+ def initialize(args={})
8
+ src_mac = (args[:lldp_port_id] if :lldp_port_id_type == 3) || (args[:config][:eth_src] if args[:config])
9
+ src_ip_bin = (args[:lldp_address] if :lldp_address_type == 1) || (args[:config][:ip_src_bin] if args[:config])
10
+
11
+ super(Int8.new(args[:lldp_chassis_id_type] || 4),
12
+ StructFu::String.new.read(:lldp_chassis_id),
13
+ Int8.new(args[:lldp_port_id_type] || 3),
14
+ EthMac.new.read(src_mac),
15
+ Int16.new(args[:lldp_ttl] || 120),
16
+ StructFu::String.new.read(:lldp_port_description) || "",
17
+ StructFu::String.new.read(:lldp_system_name) || "",
18
+ StructFu::String.new.read(:lldp_system_description) || "",
19
+ Int16.new(args[:lldp_capabilty] || 0x0080),
20
+ Int16.new(args[:lldp_enabled_capability] || 0x0080),
21
+ Int8.new(args[:lldp_address_type] || 1),
22
+ StructFu::String.new.read(:lldp_address) || src_ip_bin,
23
+ Int8.new(args[:lldp_interface_type] || 2),
24
+ Int32.new(args[:lldp_interface]),
25
+ StructFu::String.new.read(:lldp_oid) || ""
26
+ )
27
+ end
28
+
29
+ # Returns the object in string form.
30
+ def to_s
31
+ self.to_a.map {|x| x.to_s}.join
32
+ end
33
+
34
+ # Reads a string to populate the object.
35
+ def read(str)
36
+ force_binary(str)
37
+ return self if str.nil?
38
+ index = 0
39
+ #check for lldp pdu end
40
+ while (str[index,2] != "\x00\x00") && (index+2 < str.size)
41
+ tlv_known = false
42
+ #chassis subtype
43
+ if str[index,1] == "\x02"
44
+ tlv_known = true
45
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
46
+ self[:lldp_chassis_id_type].read(str[index+2,1])
47
+ self[:lldp_chassis_id].read(str[index+3, tlv_length - 1])
48
+ index += tlv_length + 2
49
+ end
50
+ #port subtype
51
+ if str[index,1] == "\x04"
52
+ tlv_known = true
53
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
54
+ self[:lldp_port_id_type].read(str[index+2,1])
55
+ self[:lldp_port_id].read(str[index+3, tlv_length - 1])
56
+ index += tlv_length + 2
57
+ end
58
+ #ttl subtype
59
+ if str[index,1] == "\x06"
60
+ tlv_known = true
61
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
62
+ self[:lldp_ttl].read(str[index+2, tlv_length])
63
+ index += tlv_length + 2
64
+ end
65
+ #port description
66
+ if str[index,1] == "\x08"
67
+ tlv_known = true
68
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
69
+ self[:lldp_port_description].read(str[index+2, tlv_length])
70
+ index += tlv_length + 2
71
+ end
72
+ #system name
73
+ if str[index,1] == "\x0a"
74
+ tlv_known = true
75
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
76
+ self[:lldp_system_name].read(str[index+2, tlv_length])
77
+ index += tlv_length + 2
78
+ end
79
+ #system description
80
+ if str[index,1] == "\x0c"
81
+ tlv_known = true
82
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
83
+ self[:lldp_system_description].read(str[index+2, tlv_length])
84
+ index += tlv_length + 2
85
+ end
86
+ #system capabilities
87
+ if str[index,1] == "\x0e"
88
+ tlv_known = true
89
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
90
+ self[:lldp_capabilty].read(str[index+2, 2])
91
+ self[:lldp_enabled_capability].read(str[index+4, 2])
92
+ index += tlv_length + 2
93
+ end
94
+ #management address
95
+ if str[index,1] == "\x10"
96
+ tlv_known = true
97
+ tlv_length = str[index + 1,1].unpack("U*").join.to_i
98
+ addr_length = str[index + 2, 1].unpack("U*").join.to_i
99
+ self[:lldp_address_type].read(str[index + 3, 1])
100
+ self[:lldp_address].read(str[index + 4,addr_length - 1])
101
+ self[:lldp_interface_type].read(str[index + addr_length + 3, 1].unpack("U*").join.to_i)
102
+ self[:lldp_interface].read(str[index + addr_length + 4, 4])
103
+ oid_string_length = str[index + addr_length + 8, 1].unpack("U*").join.to_i
104
+ if oid_string_length > 0
105
+ self[:lldp_oid].read(str[index + addr_length + 9, oid_string_length])
106
+ end
107
+ index += tlv_length + 2
108
+ end
109
+
110
+ #if tlv type is unknown jump over it
111
+ unless tlv_known
112
+ tlv_length = str[index+1,1].unpack("U*").join.to_i
113
+ index += tlv_length + 2
114
+ end
115
+ end
116
+ self
117
+ end
118
+
119
+ # Setter for the LLDP chassis id type.
120
+ def lldp_chassis_id_type=(i); typecast i; end
121
+ # Getter for the LLDP chassis id type.
122
+ def lldp_chassis_id_type; self[:lldp_chassis_id_type].to_i; end
123
+ # Setter for the LLDP chassis id.
124
+ def lldp_chassis_id=(i); typecast i; end
125
+ # Getter for the LLDP chassis id .
126
+ def lldp_chassis_id_readable()
127
+ if self[:lldp_chassis_id_type].to_i == 4
128
+ return EthHeader.str2mac(self[:lldp_chassis_id].to_s)
129
+ else
130
+ return self[:lldp_chassis_id].to_s
131
+ end
132
+ end
133
+ # Setter for the LLDP port id type.
134
+ def lldp_port_id_type=(i); typecast i; end
135
+ # Getter for the LLDP port id type.
136
+ def lldp_port_id_type; self[:lldp_port_id_type].to_i; end
137
+ # Setter for the LLDP port id .
138
+ def lldp_port_id=(i); typecast i; end
139
+ # Getter for the LLDP port id.
140
+ def lldp_port_id_readable()
141
+ #if mac addr
142
+ if self[:lldp_port_id_type].to_i == 3
143
+ return EthHeader.str2mac(self[:lldp_port_id].to_s)
144
+ else
145
+ return self[:lldp_port_id].to_s
146
+ end
147
+ end
148
+
149
+ # Set the source MAC address in a more readable way.
150
+ def lldp_saddr_mac=(mac)
151
+ mac = EthHeader.mac2str(mac)
152
+ self[:lldp_port_id_type] = 3
153
+ self[:lldp_port_id].read(mac)
154
+ self.lldp_port_id
155
+ end
156
+
157
+ # Setter for the LLDP ttl.
158
+ def lldp_ttl=(i); typecast i; end
159
+ # Getter for the LLDP ttl.
160
+ def lldp_ttl; self[:lldp_ttl].to_i; end
161
+ # Setter for the LLDP port description.
162
+ def lldp_port_description=(i); typecast i; end
163
+ # Getter for the LLDP port description.
164
+ def lldp_port_description; self[:lldp_port_description].to_s; end
165
+ # Setter for the LLDP system name.
166
+ def lldp_system_name=(i); typecast i; end
167
+ # Getter for the LLDP system name.
168
+ def lldp_system_name; self[:lldp_system_name].to_s; end
169
+ # Setter for the LLDP system description.
170
+ def lldp_system_description=(i); typecast i; end
171
+ # Getter for the LLDP system description.
172
+ def lldp_system_description; self[:lldp_system_description].to_s; end
173
+ # Setter for the LLDP capability.
174
+ def lldp_capabilty=(i); typecast i; end
175
+ # Setter for the LLDP enabled capability.
176
+ def lldp_enabled_capability=(i); typecast i; end
177
+
178
+ # Setter for the LLDP address type.
179
+ def lldp_address_type=(i); typecast i; end
180
+ # Getter for the LLDP address type.
181
+ def lldp_address_type; self[:lldp_address_type].to_i; end
182
+ # Setter for the LLDP interface type.
183
+ def lldp_interface_type=(i); typecast i; end
184
+ # Getter for the LLDP interface type.
185
+ def lldp_interface_type; self[:lldp_interface_type].to_i; end
186
+ # Setter for the LLDP interface.
187
+ def lldp_interface=(i); typecast i; end
188
+ # Getter for the LLDP interface type.
189
+ def lldp_interface; self[:lldp_interface].to_i; end
190
+ # Setter for the LLDP oid.
191
+ def lldp_oid=(i); typecast i; end
192
+ # Getter for the LLDP oid type.
193
+ def lldp_oid; self[:lldp_oid].to_i; end
194
+
195
+
196
+ # Get a more readable source MAC address.
197
+ def lldp_saddr_mac
198
+ EthHeader.str2mac(self[:lldp_port_id].to_s)
199
+ end
200
+
201
+ # Set a more readable source IP address.
202
+ def lldp_saddr_ip=(addr)
203
+ self[:lldp_address_type] = 1
204
+ self[:lldp_address].read_quad(addr)
205
+ end
206
+
207
+ # Get a more readable source IP address.
208
+ def lldp_saddr_ip
209
+ #ipv4 or ipv6
210
+ if (self[:lldp_address_type].to_i == 1) or (self[:lldp_address_type].to_i == 2)
211
+ begin
212
+ IPAddr::ntop(self[:lldp_address])
213
+ rescue
214
+ self[:lldp_address]
215
+ end
216
+ elsif self[:lldp_address_type].to_i == 6
217
+ #mac
218
+ EthHeader.str2mac(self[:lldp_address].to_s)
219
+ end
220
+ end
221
+
222
+ def lldp_address_type_readable
223
+ case lldp_address_type
224
+ when 1
225
+ "IPv4"
226
+ when 2
227
+ "IPv6"
228
+ when 6
229
+ "MAC"
230
+ else
231
+ lldp_address_type
232
+ end
233
+ end
234
+
235
+ def lldp_capabilty_readable
236
+ "0x%04x" % lldp_capabilty
237
+ end
238
+
239
+ def lldp_enabled_capability_readable
240
+ "0x%04x" % lldp_enabled_capability
241
+ end
242
+
243
+
244
+ # Readability aliases
245
+
246
+ alias :lldp_chassis_id :lldp_saddr_mac
247
+ alias :lldp_address :lldp_saddr_ip
248
+
249
+ end # class LLDPHeader
250
+ end
@@ -0,0 +1,55 @@
1
+ module PacketFu
2
+ # This Mixin simplifies access to the LLDPHeaders. Mix this in with your
3
+ # packet interface, and it will add methods that essentially delegate to
4
+ # the 'lldp_header' method (assuming that it is a LLDPHeader object)
5
+ module LLDPHeaderMixin
6
+ def lldp_chassis_id_type=(v); self.lldp_header.lldp_chassis_id_type= v; end
7
+ def lldp_chassis_id_type; self.lldp_header.lldp_chassis_id_type; end
8
+ def lldp_chassis_id=(v); self.lldp_header.lldp_chassis_id= v; end
9
+ def lldp_chassis_id; self.lldp_header.lldp_chassis_id_readable(); end
10
+
11
+ def lldp_port_id_type=(v); self.lldp_header.lldp_port_id_type= v; end
12
+ def lldp_port_id_type; self.lldp_header.lldp_port_id_type; end
13
+ def lldp_port_id=(v); self.lldp_header.lldp_port_id= v; end
14
+ def lldp_port_id; self.lldp_header.lldp_port_id_readable(); end
15
+
16
+ def lldp_ttl=(v); self.lldp_header.lldp_ttl= v; end
17
+ def lldp_ttl; self.lldp_header.lldp_ttl; end
18
+
19
+ def lldp_port_description=(v); self.lldp_header.lldp_port_description= v; end
20
+ def lldp_port_description; self.lldp_header.lldp_port_description; end
21
+
22
+ def lldp_system_name=(v); self.lldp_header.lldp_system_name= v; end
23
+ def lldp_system_name; self.lldp_header.lldp_system_name; end
24
+
25
+ def lldp_system_description=(v); self.lldp_header.lldp_system_description= v; end
26
+ def lldp_system_description; self.lldp_header.lldp_system_description; end
27
+
28
+ def lldp_capabilty=(v); self.lldp_header.lldp_capabilty= v; end
29
+ def lldp_capabilty; self.lldp_header.lldp_capabilty_readable(); end
30
+
31
+ def lldp_enabled_capability=(v); self.lldp_header.lldp_enabled_capability= v; end
32
+ def lldp_enabled_capability; self.lldp_header.lldp_enabled_capability_readable(); end
33
+
34
+ def lldp_address_type=(v); self.lldp_header.lldp_address_type= v; end
35
+ def lldp_address_type; self.lldp_header.lldp_address_type; end
36
+
37
+ def lldp_address=(v); self.lldp_header.lldp_saddr_ip= v; end
38
+ def lldp_address; self.lldp_header.lldp_saddr_ip(); end
39
+
40
+ def lldp_interface_type=(v); self.lldp_header.lldp_interface_type= v; end
41
+ def lldp_interface_type; self.lldp_header.lldp_interface_type; end
42
+
43
+ def lldp_interface=(v); self.lldp_header.lldp_interface= v; end
44
+ def lldp_interface; self.lldp_header.lldp_interface; end
45
+
46
+ def lldp_oid=(v); self.lldp_header.lldp_oid= v; end
47
+ def lldp_oid; self.lldp_header.lldp_oid; end
48
+
49
+ def lldp_saddr_mac=(v); self.lldp_header.lldp_saddr_mac= v; end
50
+ def lldp_saddr_mac; self.lldp_header.lldp_saddr_mac; end
51
+ def lldp_saddr_ip=(v); self.lldp_header.lldp_saddr_ip= v; end
52
+ def lldp_saddr_ip; self.lldp_header.lldp_saddr_ip(); end
53
+
54
+ end
55
+ end
@@ -53,6 +53,12 @@ module PacketFu
53
53
  cap_thread.value
54
54
  end
55
55
 
56
+ # Since 177/8 is IANA reserved (for now), this network should
57
+ # be handled by your default gateway and default interface.
58
+ def self.rand_routable_daddr
59
+ IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET)
60
+ end
61
+
56
62
  # Discovers the local IP and Ethernet address, which is useful for writing
57
63
  # packets you expect to get a response to. Note, this is a noisy
58
64
  # operation; a UDP packet is generated and dropped on to the default (or named)
@@ -74,8 +80,6 @@ module PacketFu
74
80
  # you will need to specify a target which will use this interface.
75
81
  # :target => "1.2.3.4"
76
82
  # A target IP address. By default, a packet will be sent to a random address in the 177/8 network.
77
- # Since this network is IANA reserved (for now), this network should be handled by your default gateway
78
- # and default interface.
79
83
  def self.whoami?(args={})
80
84
  unless args.kind_of? Hash
81
85
  raise ArgumentError, "Argument to `whoami?' must be a Hash"
@@ -83,7 +87,7 @@ module PacketFu
83
87
  if args[:iface].to_s =~ /^lo/ # Linux loopback more or less. Need a switch for windows loopback, too.
84
88
  dst_host = "127.0.0.1"
85
89
  else
86
- dst_host = (args[:target] || IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET).to_s)
90
+ dst_host = (args[:target] || rand_routable_daddr.to_s)
87
91
  end
88
92
 
89
93
  dst_port = rand(0xffff-1024)+1024
@@ -1,7 +1,7 @@
1
1
  module PacketFu
2
2
 
3
3
  # Check the repo's for version release histories
4
- VERSION = "1.1.6"
4
+ VERSION = "1.1.8"
5
5
 
6
6
  # Returns PacketFu::VERSION
7
7
  def self.version
data/packetfu.gemspec CHANGED
@@ -2,20 +2,20 @@ require 'rake'
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'packetfu'
5
- s.version = '1.1.6'
5
+ s.version = '1.1.8'
6
6
  s.authors = ['Tod Beardsley']
7
7
  s.email = 'todb@packetfu.com'
8
8
  s.summary = 'PacketFu is a mid-level packet manipulation library.'
9
9
  s.homepage = 'https://github.com/todb/packetfu'
10
10
  s.description = %q{PacketFu is a mid-level packet manipulation library for Ruby. With it, users can read, parse, and write network packets with the level of ease and fun they expect from Ruby. Note that this gem does not automatically require pcaprub, since users may install pcaprub through non-gem means.}
11
11
  s.files = `git ls-files`.split($/)
12
- s.license = 'BSD'
12
+ s.license = 'BSD'
13
13
 
14
14
  s.add_development_dependency('pcaprub', '>= 0.9.2')
15
15
  s.add_development_dependency('rspec', '>= 2.6.2')
16
16
  s.add_development_dependency('sdoc', '>= 0.2.0')
17
17
 
18
18
  s.extra_rdoc_files = %w[.document README.rdoc]
19
- s.test_files = (s.files & Dir['test/test_*.rb'])
19
+ s.test_files = (s.files & (Dir['spec/**/*_spec.rb'] + Dir['test/test_*.rb']) )
20
20
  s.rubyforge_project = 'packetfu'
21
21
  end
@@ -6,7 +6,7 @@ include PacketFu
6
6
  describe EthPacket, "when read from a pcap file" do
7
7
 
8
8
  before :all do
9
- parsed_packets = PcapFile.read_packets(File.join(".","sample.pcap"))
9
+ parsed_packets = PcapFile.read_packets(File.join(File.dirname(__FILE__),"sample.pcap"))
10
10
  @eth_packet = parsed_packets.first
11
11
  end
12
12
 
@@ -61,7 +61,7 @@ describe EthPacket, "when read from a pcap file" do
61
61
  context "isn't a regular Ethernet packet" do
62
62
 
63
63
  subject {
64
- parsed_packets = PcapFile.read_packets(File.join(".","vlan-pcapr.cap"))
64
+ parsed_packets = PcapFile.read_packets(File.join(File.dirname(__FILE__),"vlan-pcapr.cap"))
65
65
  parsed_packets.first
66
66
  }
67
67
 
File without changes
File without changes
@@ -1,16 +1,11 @@
1
1
  $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
2
  require 'packetfu'
3
3
 
4
- unless %x{#{$0} --version} =~ /^2\.6/
5
- puts "PacketFu needs rspec 2.6 or so."
6
- exit 1
7
- end
8
-
9
4
  describe PacketFu, "version information" do
10
5
  it "reports a version number" do
11
6
  PacketFu::VERSION.should match /^1\.[0-9]\.[0-9]$/
12
7
  end
13
- its(:version) {should eq PacketFu::VERSION}
8
+ its(:version) {should eq PacketFu::VERSION}
14
9
 
15
10
  it "can compare version strings" do
16
11
  PacketFu.binarize_version("1.2.3").should == 0x010203
data/spec/sample.pcap ADDED
Binary file
data/spec/sample2.pcap ADDED
Binary file
File without changes
@@ -27,7 +27,7 @@ end
27
27
  describe TCPPacket do
28
28
 
29
29
  subject do
30
- bytes = PcapFile.file_to_array("sample2.pcap")[2]
30
+ bytes = PcapFile.file_to_array(File.join(File.dirname(__FILE__), "sample2.pcap"))[2]
31
31
  packet = Packet.parse(bytes)
32
32
  end
33
33
 
Binary file
data/test/func_lldp.rb ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Functional test script contributed by @dmaciejak
4
+ # Still need a real test set.
5
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
6
+ require 'packetfu'
7
+
8
+ def lldp_pcap
9
+ fname = "./sample_lldp.pcap"
10
+ fname if File.readable? fname
11
+ end
12
+
13
+ def lldp_test()
14
+ raise RuntimeError, "Need a sample_lldp.pcap to check!" unless lldp_pcap
15
+ cap = PacketFu::PcapFile.new.file_to_array(:filename => lldp_pcap)
16
+ cap.each do |p|
17
+ pkt = PacketFu::Packet.parse p
18
+ if pkt.is_lldp?
19
+ packet_info = [pkt.proto.last, pkt.lldp_capabilty, pkt.lldp_address_type_readable, pkt.lldp_address, pkt.lldp_interface_type, pkt.lldp_interface]
20
+ puts "%s | %15s | %15s | %15s | %15s | %15s |" % packet_info
21
+ end
22
+ end
23
+ end
24
+
25
+ lldp_test()
Binary file
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+
6
+
7
+ class CaptureTest < Test::Unit::TestCase
8
+
9
+ def test_cap
10
+ assert_nothing_raised { PacketFu::Capture }
11
+ end
12
+
13
+ def test_whoami
14
+ assert_nothing_raised { PacketFu::Utils.whoami?(:iface => (ENV['IFACE'] || 'lo')) }
15
+ end
16
+
17
+ def test_new
18
+ cap = PacketFu::Capture.new
19
+ assert_kind_of PacketFu::Capture, cap
20
+ cap = PacketFu::Capture.new(
21
+ :filter => 'tcp and dst host 1.2.3.4'
22
+ )
23
+ end
24
+
25
+ def test_filter
26
+ daddr = PacketFu::Utils.rand_routable_daddr.to_s
27
+ cap = PacketFu::Capture.new( :filter => "icmp and dst host #{daddr}")
28
+ cap.start
29
+ %x{ping -c 1 #{daddr}}
30
+ sleep 1
31
+ cap.save
32
+ assert cap.array.size == 1
33
+ pkt = PacketFu::Packet.parse(cap.array.first)
34
+ assert pkt.ip_daddr == daddr
35
+ end
36
+
37
+ def test_no_filter
38
+ daddr = PacketFu::Utils.rand_routable_daddr.to_s
39
+ daddr2 = PacketFu::Utils.rand_routable_daddr.to_s
40
+ cap = PacketFu::Capture.new
41
+ cap.start
42
+ %x{ping -c 1 #{daddr}}
43
+ %x{ping -c 1 #{daddr2}}
44
+ sleep 1
45
+ cap.save
46
+ assert cap.array.size > 1
47
+ end
48
+
49
+ def test_bpf_alias
50
+ daddr = PacketFu::Utils.rand_routable_daddr.to_s
51
+ cap = PacketFu::Capture.new( :filter => "icmp and dst host #{daddr}")
52
+ assert cap.filter.object_id == cap.bpf.object_id
53
+ end
54
+
55
+ end
56
+
57
+
58
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
data/test/test_icmp.rb CHANGED
@@ -44,11 +44,19 @@ class ICMPTest < Test::Unit::TestCase
44
44
  def test_icmp_read
45
45
  sample_packet = PcapFile.new.file_to_array(:f => 'sample.pcap')[2]
46
46
  pkt = Packet.parse(sample_packet)
47
+ assert pkt.is_icmp?
47
48
  assert_kind_of ICMPPacket, pkt
48
49
  assert_equal(0x4d58, pkt.icmp_sum.to_i)
49
50
  assert_equal(8, pkt.icmp_type.to_i)
50
51
  end
51
52
 
53
+ def test_icmp_reread
54
+ sample_packet = PacketFu::ICMPPacket.new
55
+ pkt = Packet.parse(sample_packet.to_s)
56
+ assert sample_packet.is_icmp?
57
+ assert pkt.is_icmp?
58
+ end
59
+
52
60
  end
53
61
 
54
62
  # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
data/test/test_tcp.rb CHANGED
@@ -85,6 +85,18 @@ class TcpFlagsTest < Test::Unit::TestCase
85
85
  assert_equal(0x12, t.to_i)
86
86
  end
87
87
 
88
+ def test_tcp_flags_unset
89
+ t = TcpFlags.new
90
+ assert_kind_of TcpFlags, t
91
+ t.syn = 1
92
+ assert_equal(0x02, t.to_i)
93
+ t.syn = 0
94
+ assert_equal(0x00, t.to_i)
95
+ t.syn = 1
96
+ t.syn = false
97
+ assert_equal(0x00, t.to_i)
98
+ end
99
+
88
100
  def test_tcp_flags_read
89
101
  t = TcpFlags.new
90
102
  t.read("\x11")
@@ -312,6 +324,14 @@ class TCPPacketTest < Test::Unit::TestCase
312
324
  stripped.read(str, :strip => true)
313
325
  assert_equal 16, stripped.tcp_header.body.length
314
326
  end
327
+
328
+ def test_tcp_reread
329
+ sample_packet = PacketFu::TCPPacket.new
330
+ pkt = Packet.parse(sample_packet.to_s)
331
+ assert sample_packet.is_tcp?
332
+ assert pkt.is_tcp?
333
+ end
334
+
315
335
  end
316
336
 
317
337
  class TCPPacketTest < Test::Unit::TestCase
data/test/test_udp.rb CHANGED
@@ -85,6 +85,14 @@ class UDPTest < Test::Unit::TestCase
85
85
  pkt.to_f('udp_test.pcap','a')
86
86
  end
87
87
 
88
+ def test_udp_reread
89
+ sample_packet = PacketFu::UDPPacket.new
90
+ pkt = Packet.parse(sample_packet.to_s)
91
+ assert sample_packet.is_udp?
92
+ assert pkt.is_udp?
93
+ end
94
+
95
+
88
96
  end
89
97
 
90
98
  # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packetfu
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.6
4
+ version: 1.1.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-27 00:00:00.000000000 Z
12
+ date: 2013-06-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pcaprub
16
- requirement: &12628060 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 0.9.2
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *12628060
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.2
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rspec
27
- requirement: &12627260 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: 2.6.2
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *12627260
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 2.6.2
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: sdoc
38
- requirement: &12626240 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,7 +53,12 @@ dependencies:
43
53
  version: 0.2.0
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *12626240
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.0
47
62
  description: PacketFu is a mid-level packet manipulation library for Ruby. With it,
48
63
  users can read, parse, and write network packets with the level of ease and fun
49
64
  they expect from Ruby. Note that this gem does not automatically require pcaprub,
@@ -57,9 +72,11 @@ extra_rdoc_files:
57
72
  files:
58
73
  - .document
59
74
  - .gitignore
75
+ - .mailmap
60
76
  - INSTALL.rdoc
61
77
  - LICENSE.txt
62
78
  - README.rdoc
79
+ - Rakefile
63
80
  - bench/after-2012-07-28.txt
64
81
  - bench/before-2012-07-28.txt
65
82
  - bench/benchit.rb
@@ -110,6 +127,9 @@ files:
110
127
  - lib/packetfu/protos/ipv6.rb
111
128
  - lib/packetfu/protos/ipv6/header.rb
112
129
  - lib/packetfu/protos/ipv6/mixin.rb
130
+ - lib/packetfu/protos/lldp.rb
131
+ - lib/packetfu/protos/lldp/header.rb
132
+ - lib/packetfu/protos/lldp/mixin.rb
113
133
  - lib/packetfu/protos/tcp.rb
114
134
  - lib/packetfu/protos/tcp/ecn.rb
115
135
  - lib/packetfu/protos/tcp/flags.rb
@@ -127,19 +147,25 @@ files:
127
147
  - lib/packetfu/version.rb
128
148
  - packetfu.gemspec
129
149
  - setup.rb
150
+ - spec/ethpacket_spec.rb
151
+ - spec/packet_spec.rb
152
+ - spec/packet_subclasses_spec.rb
153
+ - spec/packetfu_spec.rb
154
+ - spec/sample.pcap
155
+ - spec/sample2.pcap
156
+ - spec/structfu_spec.rb
157
+ - spec/tcp_spec.rb
158
+ - spec/vlan-pcapr.cap
130
159
  - test/all_tests.rb
131
- - test/ethpacket_spec.rb
132
- - test/packet_spec.rb
133
- - test/packet_subclasses_spec.rb
134
- - test/packetfu_spec.rb
160
+ - test/func_lldp.rb
135
161
  - test/ptest.rb
136
162
  - test/sample-ipv6.pcap
137
163
  - test/sample.pcap
138
164
  - test/sample2.pcap
139
165
  - test/sample_hsrp_pcapr.cap
140
- - test/structfu_spec.rb
141
- - test/tcp_spec.rb
166
+ - test/sample_lldp.pcap
142
167
  - test/test_arp.rb
168
+ - test/test_capture.rb
143
169
  - test/test_eth.rb
144
170
  - test/test_hsrp.rb
145
171
  - test/test_icmp.rb
@@ -175,12 +201,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
201
  version: '0'
176
202
  requirements: []
177
203
  rubyforge_project: packetfu
178
- rubygems_version: 1.8.15
204
+ rubygems_version: 1.8.25
179
205
  signing_key:
180
206
  specification_version: 3
181
207
  summary: PacketFu is a mid-level packet manipulation library.
182
208
  test_files:
209
+ - spec/ethpacket_spec.rb
210
+ - spec/packet_spec.rb
211
+ - spec/packet_subclasses_spec.rb
212
+ - spec/packetfu_spec.rb
213
+ - spec/structfu_spec.rb
214
+ - spec/tcp_spec.rb
183
215
  - test/test_arp.rb
216
+ - test/test_capture.rb
184
217
  - test/test_eth.rb
185
218
  - test/test_hsrp.rb
186
219
  - test/test_icmp.rb