packetfu 1.1.11 → 1.1.12.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|