packetfu 1.1.11 → 1.1.12.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.rspec +2 -0
- data/.travis.yml +2 -3
- data/README.md +127 -0
- data/examples/100kpackets.rb +11 -10
- data/examples/ackscan.rb +4 -1
- data/examples/arp.rb +4 -5
- data/examples/arphood.rb +5 -4
- data/examples/dissect_thinger.rb +10 -7
- data/examples/ethernet.rb +8 -3
- data/examples/ids.rb +22 -4
- data/examples/idsv2.rb +25 -6
- data/examples/ifconfig.rb +6 -3
- data/examples/new-simple-stats.rb +5 -6
- data/examples/packetfu-shell.rb +11 -48
- data/examples/pcap2pcapng.rb +32 -0
- data/examples/simple-sniffer.rb +9 -4
- data/examples/simple-stats.rb +7 -8
- data/examples/slammer.rb +2 -2
- data/examples/uniqpcap.rb +17 -7
- data/lib/packetfu.rb +10 -175
- data/lib/packetfu/capture.rb +2 -2
- data/lib/packetfu/common.rb +142 -0
- data/lib/packetfu/config.rb +8 -8
- data/lib/packetfu/inject.rb +3 -3
- data/lib/packetfu/packet.rb +22 -18
- data/lib/packetfu/pcap.rb +2 -1
- data/lib/packetfu/pcapng.rb +37 -0
- data/lib/packetfu/pcapng/block.rb +25 -0
- data/lib/packetfu/pcapng/epb.rb +112 -0
- data/lib/packetfu/pcapng/file.rb +316 -0
- data/lib/packetfu/pcapng/idb.rb +125 -0
- data/lib/packetfu/pcapng/shb.rb +146 -0
- data/lib/packetfu/pcapng/spb.rb +83 -0
- data/lib/packetfu/pcapng/unknown_block.rb +60 -0
- data/lib/packetfu/protos.rb +3 -0
- data/lib/packetfu/protos/arp.rb +10 -10
- data/lib/packetfu/protos/icmpv6.rb +131 -0
- data/lib/packetfu/protos/icmpv6/header.rb +69 -0
- data/lib/packetfu/protos/icmpv6/mixin.rb +14 -0
- data/lib/packetfu/protos/ip.rb +4 -5
- data/lib/packetfu/protos/ipv6/header.rb +2 -0
- data/lib/packetfu/protos/udp.rb +24 -12
- data/lib/packetfu/structfu.rb +27 -0
- data/lib/packetfu/utils.rb +55 -9
- data/lib/packetfu/version.rb +1 -1
- data/packetfu.gemspec +13 -7
- data/spec/arp_spec.rb +11 -5
- data/spec/eth_spec.rb +20 -11
- data/spec/fake_packets.rb +28 -0
- data/spec/hsrp_spec.rb +15 -0
- data/spec/icmp_spec.rb +12 -5
- data/spec/icmpv6_spec.rb +98 -0
- data/spec/invalid_spec.rb +28 -0
- data/spec/ip_spec.rb +10 -5
- data/spec/ipv4_icmp.pcap +0 -0
- data/spec/ipv4_udp.pcap +0 -0
- data/spec/ipv6_icmp.pcap +0 -0
- data/spec/ipv6_spec.rb +4 -0
- data/spec/ipv6_udp.pcap +0 -0
- data/spec/lldp_spec.rb +36 -0
- data/spec/octets_spec.rb +43 -0
- data/spec/packet_spec.rb +24 -0
- data/spec/packetfu_spec.rb +6 -1
- data/spec/pcap_spec.rb +286 -0
- data/spec/pcapng/epb_spec.rb +81 -0
- data/spec/pcapng/file_spec.rb +295 -0
- data/spec/pcapng/file_spec_helper.rb +45 -0
- data/spec/pcapng/idb_spec.rb +53 -0
- data/spec/pcapng/shb_spec.rb +42 -0
- data/spec/pcapng/spb_spec.rb +43 -0
- data/spec/pcapng/unknown_block_spec.rb +36 -0
- data/spec/spec_helper.rb +3 -31
- data/spec/tcp_spec.rb +4 -1
- data/spec/udp_spec.rb +149 -1
- data/spec/utils_spec.rb +98 -15
- data/test/pcapng-test/output_be/advanced/test100.pcapng +0 -0
- data/test/pcapng-test/output_be/advanced/test100.txt +11 -0
- data/test/pcapng-test/output_be/advanced/test101.pcapng +0 -0
- data/test/pcapng-test/output_be/advanced/test101.txt +11 -0
- data/test/pcapng-test/output_be/advanced/test102.pcapng +0 -0
- data/test/pcapng-test/output_be/advanced/test102.txt +14 -0
- data/test/pcapng-test/output_be/basic/test001.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test001.txt +9 -0
- data/test/pcapng-test/output_be/basic/test002.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test002.txt +7 -0
- data/test/pcapng-test/output_be/basic/test003.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test003.txt +8 -0
- data/test/pcapng-test/output_be/basic/test004.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test004.txt +9 -0
- data/test/pcapng-test/output_be/basic/test005.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test005.txt +9 -0
- data/test/pcapng-test/output_be/basic/test006.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test006.txt +9 -0
- data/test/pcapng-test/output_be/basic/test007.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test007.txt +9 -0
- data/test/pcapng-test/output_be/basic/test008.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test008.txt +9 -0
- data/test/pcapng-test/output_be/basic/test009.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test009.txt +9 -0
- data/test/pcapng-test/output_be/basic/test010.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test010.txt +9 -0
- data/test/pcapng-test/output_be/basic/test011.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test011.txt +10 -0
- data/test/pcapng-test/output_be/basic/test012.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test012.txt +10 -0
- data/test/pcapng-test/output_be/basic/test013.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test013.txt +9 -0
- data/test/pcapng-test/output_be/basic/test014.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test014.txt +9 -0
- data/test/pcapng-test/output_be/basic/test015.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test015.txt +9 -0
- data/test/pcapng-test/output_be/basic/test016.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test016.txt +11 -0
- data/test/pcapng-test/output_be/basic/test017.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test017.txt +9 -0
- data/test/pcapng-test/output_be/basic/test018.pcapng +0 -0
- data/test/pcapng-test/output_be/basic/test018.txt +12 -0
- data/test/pcapng-test/output_be/difficult/test200.pcapng +0 -0
- data/test/pcapng-test/output_be/difficult/test200.txt +8 -0
- data/test/pcapng-test/output_be/difficult/test201.pcapng +0 -0
- data/test/pcapng-test/output_be/difficult/test201.txt +11 -0
- data/test/pcapng-test/output_be/difficult/test202.pcapng +0 -0
- data/test/pcapng-test/output_be/difficult/test202.txt +14 -0
- data/test/pcapng-test/output_le/advanced/test100.pcapng +0 -0
- data/test/pcapng-test/output_le/advanced/test100.txt +11 -0
- data/test/pcapng-test/output_le/advanced/test101.pcapng +0 -0
- data/test/pcapng-test/output_le/advanced/test101.txt +11 -0
- data/test/pcapng-test/output_le/advanced/test102.pcapng +0 -0
- data/test/pcapng-test/output_le/advanced/test102.txt +14 -0
- data/test/pcapng-test/output_le/basic/test001.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test001.txt +9 -0
- data/test/pcapng-test/output_le/basic/test002.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test002.txt +7 -0
- data/test/pcapng-test/output_le/basic/test003.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test003.txt +8 -0
- data/test/pcapng-test/output_le/basic/test004.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test004.txt +9 -0
- data/test/pcapng-test/output_le/basic/test005.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test005.txt +9 -0
- data/test/pcapng-test/output_le/basic/test006.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test006.txt +9 -0
- data/test/pcapng-test/output_le/basic/test007.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test007.txt +9 -0
- data/test/pcapng-test/output_le/basic/test008.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test008.txt +9 -0
- data/test/pcapng-test/output_le/basic/test009.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test009.txt +9 -0
- data/test/pcapng-test/output_le/basic/test010.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test010.txt +9 -0
- data/test/pcapng-test/output_le/basic/test011.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test011.txt +10 -0
- data/test/pcapng-test/output_le/basic/test012.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test012.txt +10 -0
- data/test/pcapng-test/output_le/basic/test013.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test013.txt +9 -0
- data/test/pcapng-test/output_le/basic/test014.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test014.txt +9 -0
- data/test/pcapng-test/output_le/basic/test015.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test015.txt +9 -0
- data/test/pcapng-test/output_le/basic/test016.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test016.txt +11 -0
- data/test/pcapng-test/output_le/basic/test017.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test017.txt +9 -0
- data/test/pcapng-test/output_le/basic/test018.pcapng +0 -0
- data/test/pcapng-test/output_le/basic/test018.txt +12 -0
- data/test/pcapng-test/output_le/difficult/test200.pcapng +0 -0
- data/test/pcapng-test/output_le/difficult/test200.txt +8 -0
- data/test/pcapng-test/output_le/difficult/test201.pcapng +0 -0
- data/test/pcapng-test/output_le/difficult/test201.txt +11 -0
- data/test/pcapng-test/output_le/difficult/test202.pcapng +0 -0
- data/test/pcapng-test/output_le/difficult/test202.txt +14 -0
- data/test/sample-ipv6.pcapng +0 -0
- data/test/sample-spb.pcapng +0 -0
- data/test/sample.pcapng +0 -0
- data/test/sample2.pcapng +0 -0
- metadata +190 -68
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -2
- data/INSTALL.rdoc +0 -40
- data/README.rdoc +0 -64
- data/examples/examples.rb +0 -4
- data/setup.rb +0 -1586
- data/test/func_lldp.rb +0 -25
- data/test/ptest.rb +0 -16
- data/test/test_eth.rb +0 -93
- data/test/test_hsrp.rb +0 -20
- data/test/test_invalid.rb +0 -28
- data/test/test_octets.rb +0 -36
- data/test/test_pcap.rb +0 -211
- data/test/test_udp.rb +0 -100
- metadata.gz.sig +0 -2
@@ -0,0 +1,131 @@
|
|
1
|
+
# coding: binary
|
2
|
+
require 'packetfu/protos/eth/header'
|
3
|
+
require 'packetfu/protos/eth/mixin'
|
4
|
+
|
5
|
+
require 'packetfu/protos/ipv6/header'
|
6
|
+
require 'packetfu/protos/ipv6/mixin'
|
7
|
+
|
8
|
+
require 'packetfu/protos/icmpv6/header'
|
9
|
+
require 'packetfu/protos/icmpv6/mixin'
|
10
|
+
|
11
|
+
module PacketFu
|
12
|
+
|
13
|
+
# ICMPv6Packet is used to construct ICMPv6 Packets. They contain an EthHeader,
|
14
|
+
# an IPv6Header, and a ICMPv6Header.
|
15
|
+
#
|
16
|
+
# == Example
|
17
|
+
#
|
18
|
+
# icmpv6_pkt.new
|
19
|
+
# icmpv6_pkt.icmpv6_type = 8
|
20
|
+
# icmpv6_pkt.icmpv6_code = 0
|
21
|
+
# icmpv6_pkt.payload = "ABC, easy as 123. As simple as do-re-mi. ABC, 123, baby, you and me!"
|
22
|
+
#
|
23
|
+
# icmpv6_pkt.ipv6_saddr="2000::1234"
|
24
|
+
# icmpv6_pkt.ipv6_daddr="2000::5678"
|
25
|
+
#
|
26
|
+
# icmpv6_pkt.recalc
|
27
|
+
# icmpv6_pkt.to_f('/tmp/icmpv6.pcap')
|
28
|
+
#
|
29
|
+
# == Parameters
|
30
|
+
#
|
31
|
+
# :eth
|
32
|
+
# A pre-generated EthHeader object.
|
33
|
+
# :ipv6
|
34
|
+
# A pre-generated IPv6Header object.
|
35
|
+
# :icmpv6
|
36
|
+
# A pre-generated ICMPv6Header object.
|
37
|
+
class ICMPv6Packet < Packet
|
38
|
+
include ::PacketFu::EthHeaderMixin
|
39
|
+
include ::PacketFu::IPv6HeaderMixin
|
40
|
+
include ::PacketFu::ICMPv6HeaderMixin
|
41
|
+
|
42
|
+
attr_accessor :eth_header, :ipv6_header, :icmpv6_header
|
43
|
+
|
44
|
+
def self.can_parse?(str)
|
45
|
+
return false unless str.size >= 58
|
46
|
+
return false unless EthPacket.can_parse? str
|
47
|
+
return false unless IPv6Packet.can_parse? str
|
48
|
+
return false unless str[20,1] == [PacketFu::ICMPv6Header::PROTOCOL_NUMBER].pack('C')
|
49
|
+
return true
|
50
|
+
end
|
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
|
+
def initialize(args={})
|
60
|
+
@eth_header = EthHeader.new(args).read(args[:eth])
|
61
|
+
@ipv6_header = IPv6Header.new(args).read(args[:ipv6])
|
62
|
+
@ipv6_header.ipv6_next = PacketFu::ICMPv6Header::PROTOCOL_NUMBER
|
63
|
+
@icmpv6_header = ICMPv6Header.new(args).read(args[:icmpv6])
|
64
|
+
|
65
|
+
@ipv6_header.body = @icmpv6_header
|
66
|
+
@eth_header.body = @ipv6_header
|
67
|
+
|
68
|
+
@headers = [@eth_header, @ipv6_header, @icmpv6_header]
|
69
|
+
super
|
70
|
+
icmpv6_calc_sum
|
71
|
+
end
|
72
|
+
|
73
|
+
# Calculates the checksum for the object.
|
74
|
+
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
|
81
|
+
checksum += PacketFu::ICMPv6Header::PROTOCOL_NUMBER
|
82
|
+
checksum += ipv6_len
|
83
|
+
# Then compute it on ICMPv6 header + payload
|
84
|
+
checksum += (icmpv6_type.to_i << 8) + icmpv6_code.to_i
|
85
|
+
chk_body = (payload.to_s.size % 2 == 0 ? payload.to_s : payload.to_s + "\x00")
|
86
|
+
if 1.respond_to? :ord
|
87
|
+
chk_body.split("").each_slice(2).map { |x| (x[0].ord << 8) + x[1].ord }.
|
88
|
+
each { |y| checksum += y }
|
89
|
+
else
|
90
|
+
chk_body.split("").each_slice(2).map { |x| (x[0] << 8) + x[1] }.
|
91
|
+
each { |y| checksum += y }
|
92
|
+
end
|
93
|
+
checksum = checksum % 0xffff
|
94
|
+
checksum = 0xffff - checksum
|
95
|
+
checksum == 0 ? 0xffff : checksum
|
96
|
+
end
|
97
|
+
|
98
|
+
# Recalculates the calculatable fields for ICMPv6.
|
99
|
+
def icmpv6_recalc(arg=:all)
|
100
|
+
arg = arg.intern if arg.respond_to? :intern
|
101
|
+
case arg
|
102
|
+
when :icmpv6_sum
|
103
|
+
self.icmpv6_sum = icmpv6_calc_sum
|
104
|
+
when :all
|
105
|
+
self.icmpv6_sum = icmpv6_calc_sum
|
106
|
+
else
|
107
|
+
raise ArgumentError, "No such field `#{arg}'"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Peek provides summary data on packet contents.
|
112
|
+
def peek_format
|
113
|
+
peek_data = ["6C "]
|
114
|
+
peek_data << "%-5d" % self.to_s.size
|
115
|
+
type = case self.icmpv6_type.to_i
|
116
|
+
when 128
|
117
|
+
"ping"
|
118
|
+
when 129
|
119
|
+
"pong"
|
120
|
+
else
|
121
|
+
"%02x-%02x" % [self.icmpv6_type, self.icmpv6_code]
|
122
|
+
end
|
123
|
+
peek_data << "%-21s" % "#{self.ipv6_saddr}:#{type}"
|
124
|
+
peek_data << "->"
|
125
|
+
peek_data << "%21s" % "#{self.ipv6_daddr}"
|
126
|
+
peek_data.join
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'packetfu/protos/ipv6/header'
|
2
|
+
require 'packetfu/protos/ipv6/mixin'
|
3
|
+
|
4
|
+
module PacketFu
|
5
|
+
|
6
|
+
# ICMPv6Header is a complete ICMPv6 struct, used in ICMPv6Packet.
|
7
|
+
# ICMPv6 is typically used for network administration and connectivity
|
8
|
+
# testing.
|
9
|
+
#
|
10
|
+
# For more on ICMP packets, see
|
11
|
+
# http://www.networksorcery.com/enp/protocol/icmpv6.htm
|
12
|
+
#
|
13
|
+
# ==== Header Definition
|
14
|
+
#
|
15
|
+
# Int8 :icmp_type # Type
|
16
|
+
# Int8 :icmp_code # Code
|
17
|
+
# Int16 :icmp_sum Default: calculated # Checksum
|
18
|
+
# String :body
|
19
|
+
class ICMPv6Header < Struct.new(:icmpv6_type, :icmpv6_code, :icmpv6_sum, :body)
|
20
|
+
include StructFu
|
21
|
+
|
22
|
+
PROTOCOL_NUMBER = 58
|
23
|
+
|
24
|
+
def initialize(args={})
|
25
|
+
super(
|
26
|
+
Int8.new(args[:icmpv6_type]),
|
27
|
+
Int8.new(args[:icmpv6_code]),
|
28
|
+
Int16.new(args[:icmpv6_sum]),
|
29
|
+
StructFu::String.new.read(args[:body])
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the object in string form.
|
34
|
+
def to_s
|
35
|
+
self.to_a.map {|x| x.to_s}.join
|
36
|
+
end
|
37
|
+
|
38
|
+
# Reads a string to populate the object.
|
39
|
+
def read(str)
|
40
|
+
force_binary(str)
|
41
|
+
return self if str.nil?
|
42
|
+
self[:icmpv6_type].read(str[0,1])
|
43
|
+
self[:icmpv6_code].read(str[1,1])
|
44
|
+
self[:icmpv6_sum].read(str[2,2])
|
45
|
+
self[:body].read(str[4,str.size])
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Setter for the type.
|
50
|
+
def icmpv6_type=(i); typecast i; end
|
51
|
+
# Getter for the type.
|
52
|
+
def icmpv6_type; self[:icmpv6_type].to_i; end
|
53
|
+
# Setter for the code.
|
54
|
+
def icmpv6_code=(i); typecast i; end
|
55
|
+
# Getter for the code.
|
56
|
+
def icmpv6_code; self[:icmpv6_code].to_i; end
|
57
|
+
# Setter for the checksum. Note, this is calculated automatically with
|
58
|
+
# icmpv6_calc_sum.
|
59
|
+
def icmpv6_sum=(i); typecast i; end
|
60
|
+
# Getter for the checksum.
|
61
|
+
def icmpv6_sum; self[:icmpv6_sum].to_i; end
|
62
|
+
|
63
|
+
def icmpv6_sum_readable
|
64
|
+
"0x%04x" % icmpv6_sum
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PacketFu
|
2
|
+
# This Mixin simplifies access to the ICMPv6Headers. Mix this in with your
|
3
|
+
# packet interface, and it will add methods that essentially delegate to
|
4
|
+
# the 'icmpv6_header' method (assuming that it is a ICMPv6Header object)
|
5
|
+
module ICMPv6HeaderMixin
|
6
|
+
def icmpv6_type=(v); self.icmpv6_header.icmpv6_type= v; end
|
7
|
+
def icmpv6_type; self.icmpv6_header.icmpv6_type; end
|
8
|
+
def icmpv6_code=(v); self.icmpv6_header.icmpv6_code= v; end
|
9
|
+
def icmpv6_code; self.icmpv6_header.icmpv6_code; end
|
10
|
+
def icmpv6_sum=(v); self.icmpv6_header.icmpv6_sum= v; end
|
11
|
+
def icmpv6_sum; self.icmpv6_header.icmpv6_sum; end
|
12
|
+
def icmpv6_sum_readable; self.icmpv6_header.icmpv6_sum_readable; end
|
13
|
+
end
|
14
|
+
end
|
data/lib/packetfu/protos/ip.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# -*- coding: binary -*-
|
2
2
|
require 'packetfu/protos/eth/header'
|
3
3
|
require 'packetfu/protos/eth/mixin'
|
4
|
-
|
5
4
|
require 'packetfu/protos/ip/header'
|
6
5
|
require 'packetfu/protos/ip/mixin'
|
7
6
|
|
@@ -20,7 +19,7 @@ module PacketFu
|
|
20
19
|
# ip_pkt.ip_ttl=64
|
21
20
|
# ip_pkt.ip_payload="\x00\x00\x12\x34\x00\x01\x00\x01"+
|
22
21
|
# "Lovingly hand-crafted echo responses delivered directly to your door."
|
23
|
-
# ip_pkt.recalc
|
22
|
+
# ip_pkt.recalc
|
24
23
|
# ip_pkt.to_f('/tmp/ip.pcap')
|
25
24
|
#
|
26
25
|
# == Parameters
|
@@ -49,7 +48,7 @@ module PacketFu
|
|
49
48
|
else
|
50
49
|
ipv = str[14,1][0] >> 4
|
51
50
|
end
|
52
|
-
return true if ipv == 4
|
51
|
+
return true if ipv == 4
|
53
52
|
else
|
54
53
|
return false
|
55
54
|
end
|
@@ -58,11 +57,11 @@ module PacketFu
|
|
58
57
|
def read(str=nil, args={})
|
59
58
|
raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
|
60
59
|
@eth_header.read(str)
|
61
|
-
super(args)
|
60
|
+
super(args)
|
62
61
|
self
|
63
62
|
end
|
64
63
|
|
65
|
-
# Creates a new IPPacket object.
|
64
|
+
# Creates a new IPPacket object.
|
66
65
|
def initialize(args={})
|
67
66
|
@eth_header = EthHeader.new(args).read(args[:eth])
|
68
67
|
@ip_header = IPHeader.new(args).read(args[:ip])
|
data/lib/packetfu/protos/udp.rb
CHANGED
@@ -55,9 +55,12 @@ module PacketFu
|
|
55
55
|
def self.can_parse?(str)
|
56
56
|
return false unless str.size >= 28
|
57
57
|
return false unless EthPacket.can_parse? str
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
if IPPacket.can_parse? str
|
59
|
+
return true if str[23,1] == "\x11"
|
60
|
+
elsif IPv6Packet.can_parse? str
|
61
|
+
return true if str[20,1] == "\x11"
|
62
|
+
end
|
63
|
+
false
|
61
64
|
end
|
62
65
|
|
63
66
|
def read(str=nil, args={})
|
@@ -157,19 +160,28 @@ module PacketFu
|
|
157
160
|
|
158
161
|
# Peek provides summary data on packet contents.
|
159
162
|
def peek_format
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
163
|
+
if self.ipv6?
|
164
|
+
peek_data = ["6U "]
|
165
|
+
peek_data << "%-5d" % self.to_s.size
|
166
|
+
peek_data << "%-31s" % "#{self.ipv6_saddr}:#{self.udp_sport}"
|
167
|
+
peek_data << "->"
|
168
|
+
peek_data << "%31s" % "#{self.ipv6_daddr}:#{self.udp_dport}"
|
169
|
+
peek_data.join
|
170
|
+
else
|
171
|
+
peek_data = ["U "]
|
172
|
+
peek_data << "%-5d" % self.to_s.size
|
173
|
+
peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
|
174
|
+
peek_data << "->"
|
175
|
+
peek_data << "%21s" % "#{self.ip_daddr}:#{self.udp_dport}"
|
176
|
+
peek_data << "%23s" % "I:"
|
177
|
+
peek_data << "%04x" % self.ip_id
|
178
|
+
peek_data.join
|
179
|
+
end
|
168
180
|
end
|
169
181
|
|
170
182
|
# Is that packet an UDP on IPv6 packet ?
|
171
183
|
def ipv6?
|
172
|
-
@ipv6_header
|
184
|
+
not @ipv6_header.nil?
|
173
185
|
end
|
174
186
|
|
175
187
|
end
|
data/lib/packetfu/structfu.rb
CHANGED
@@ -165,6 +165,33 @@ module StructFu
|
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
+
# Int64 is a eight byte value.
|
169
|
+
class Int64 < Int
|
170
|
+
def initialize(v=nil, e=:big)
|
171
|
+
super(v, e, w=4)
|
172
|
+
@packstr = (self.e == :big) ? 'Q>' : 'Q<'
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns a eight byte value as a packed string.
|
176
|
+
def to_s
|
177
|
+
@packstr = (self.e == :big) ? 'Q>' : 'Q<'
|
178
|
+
[(self.v || self.d)].pack(@packstr)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Int64be is a eight byte value in big-endian format. The endianness cannot be altered.
|
183
|
+
class Int64be < Int64
|
184
|
+
undef :endian=
|
185
|
+
end
|
186
|
+
|
187
|
+
# Int64le is a eight byte value in little-endian format. The endianness cannot be altered.
|
188
|
+
class Int64le < Int64
|
189
|
+
undef :endian=
|
190
|
+
def initialize(v=nil, e=:little)
|
191
|
+
super(v,e)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
168
195
|
# Strings are just like regular strings, except it comes with a read() function
|
169
196
|
# so that it behaves like other StructFu elements.
|
170
197
|
class String < ::String
|
data/lib/packetfu/utils.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# -*- coding: binary -*-
|
2
2
|
require 'singleton'
|
3
3
|
require 'timeout'
|
4
|
-
require 'network_interface'
|
5
4
|
|
6
5
|
module PacketFu
|
7
6
|
|
@@ -23,6 +22,9 @@ module PacketFu
|
|
23
22
|
# The flavor of the ARP request. Defaults to :none.
|
24
23
|
# :timeout
|
25
24
|
# Timeout in seconds. Defaults to 3.
|
25
|
+
# :no_cache
|
26
|
+
# Do not query ARP cache and always send an ARP request. Defaults to
|
27
|
+
# false.
|
26
28
|
#
|
27
29
|
# === Example
|
28
30
|
# PacketFu::Utils::arp("192.168.1.1") #=> "00:18:39:01:33:70"
|
@@ -33,6 +35,11 @@ module PacketFu
|
|
33
35
|
# It goes without saying, spewing forged ARP packets on your network is a great way to really
|
34
36
|
# irritate your co-workers.
|
35
37
|
def self.arp(target_ip,args={})
|
38
|
+
unless args[:no_cache]
|
39
|
+
cache = self.arp_cache
|
40
|
+
return cache[target_ip].first if cache[target_ip]
|
41
|
+
end
|
42
|
+
|
36
43
|
iface = args[:iface] || :eth0
|
37
44
|
args[:config] ||= whoami?(:iface => iface)
|
38
45
|
arp_pkt = PacketFu::ARPPacket.new(:flavor => (args[:flavor] || :none), :config => args[:config])
|
@@ -59,6 +66,25 @@ module PacketFu
|
|
59
66
|
cap_thread.value
|
60
67
|
end
|
61
68
|
|
69
|
+
# Determine ARP cache data string
|
70
|
+
def self.arp_cache_raw
|
71
|
+
%x(/usr/sbin/arp -na)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get ARP cache.
|
75
|
+
# More rubyish than PAcketFu::Utils.arp_cache_data_string
|
76
|
+
def self.arp_cache
|
77
|
+
arp_cache = {}
|
78
|
+
arp_table = arp_cache_raw
|
79
|
+
arp_table.split(/\n/).each do |line|
|
80
|
+
match = line.match(/\? \((?<ip>\d+\.\d+\.\d+\.\d+)\) at (?<mac>([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2})(?: \[ether\])? on (?<int>[a-zA-Z0-9]+)/)
|
81
|
+
if match
|
82
|
+
arp_cache[match[:ip]] = [match[:mac], match[:int]]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
arp_cache
|
86
|
+
end
|
87
|
+
|
62
88
|
# Since 177/8 is IANA reserved (for now), this network should
|
63
89
|
# be handled by your default gateway and default interface.
|
64
90
|
def self.rand_routable_daddr
|
@@ -166,13 +192,10 @@ module PacketFu
|
|
166
192
|
def self.default_int
|
167
193
|
ip = default_ip
|
168
194
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
return interface if address["addr"] == ip
|
174
|
-
end
|
175
|
-
end
|
195
|
+
Socket.getifaddrs.each do |ifaddr|
|
196
|
+
next unless ifaddr.addr.ip?
|
197
|
+
|
198
|
+
return ifaddr.name if ifaddr.addr.ip_address == ip
|
176
199
|
end
|
177
200
|
|
178
201
|
# Fall back to libpcap as last resort
|
@@ -182,7 +205,7 @@ module PacketFu
|
|
182
205
|
# Determine the ifconfig data string for a given interface
|
183
206
|
def self.ifconfig_data_string(iface=default_int)
|
184
207
|
# Make sure to only get interface data for a real interface
|
185
|
-
unless
|
208
|
+
unless Socket.getifaddrs.any? {|ifaddr| ifaddr.name == iface}
|
186
209
|
raise ArgumentError, "#{iface} interface does not exist"
|
187
210
|
end
|
188
211
|
return %x[ifconfig #{iface}]
|
@@ -290,6 +313,29 @@ module PacketFu
|
|
290
313
|
ret[:ip6_obj] = IPAddr.new($1)
|
291
314
|
end
|
292
315
|
end # freebsd
|
316
|
+
when /openbsd/i
|
317
|
+
ifconfig_data = ifconfig_data_string(iface)
|
318
|
+
if ifconfig_data =~ /#{iface}/
|
319
|
+
ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
|
320
|
+
else
|
321
|
+
raise ArgumentError, "Cannot ifconfig #{iface}"
|
322
|
+
end
|
323
|
+
ret[:iface] = iface
|
324
|
+
ifconfig_data.each do |s|
|
325
|
+
case s
|
326
|
+
when /lladdr[\s]*([0-9a-fA-F:]{17})/
|
327
|
+
ret[:eth_saddr] = $1.downcase
|
328
|
+
ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
|
329
|
+
when /inet[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*netmask[\s]*(0x[0-9a-fA-F]{8}))?/
|
330
|
+
ret[:ip_saddr] = $1
|
331
|
+
ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
|
332
|
+
ret[:ip4_obj] = IPAddr.new($1)
|
333
|
+
ret[:ip4_obj] = ret[:ip4_obj].mask(($3.hex.to_s(2) =~ /0*$/)) if $3
|
334
|
+
when /inet6[\s]*([0-9a-fA-F:\x2f]+)/
|
335
|
+
ret[:ip6_saddr] = $1
|
336
|
+
ret[:ip6_obj] = IPAddr.new($1)
|
337
|
+
end
|
338
|
+
end # openbsd
|
293
339
|
end # RUBY_PLATFORM
|
294
340
|
ret
|
295
341
|
end
|