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.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rspec +2 -0
  4. data/.travis.yml +2 -3
  5. data/README.md +127 -0
  6. data/examples/100kpackets.rb +11 -10
  7. data/examples/ackscan.rb +4 -1
  8. data/examples/arp.rb +4 -5
  9. data/examples/arphood.rb +5 -4
  10. data/examples/dissect_thinger.rb +10 -7
  11. data/examples/ethernet.rb +8 -3
  12. data/examples/ids.rb +22 -4
  13. data/examples/idsv2.rb +25 -6
  14. data/examples/ifconfig.rb +6 -3
  15. data/examples/new-simple-stats.rb +5 -6
  16. data/examples/packetfu-shell.rb +11 -48
  17. data/examples/pcap2pcapng.rb +32 -0
  18. data/examples/simple-sniffer.rb +9 -4
  19. data/examples/simple-stats.rb +7 -8
  20. data/examples/slammer.rb +2 -2
  21. data/examples/uniqpcap.rb +17 -7
  22. data/lib/packetfu.rb +10 -175
  23. data/lib/packetfu/capture.rb +2 -2
  24. data/lib/packetfu/common.rb +142 -0
  25. data/lib/packetfu/config.rb +8 -8
  26. data/lib/packetfu/inject.rb +3 -3
  27. data/lib/packetfu/packet.rb +22 -18
  28. data/lib/packetfu/pcap.rb +2 -1
  29. data/lib/packetfu/pcapng.rb +37 -0
  30. data/lib/packetfu/pcapng/block.rb +25 -0
  31. data/lib/packetfu/pcapng/epb.rb +112 -0
  32. data/lib/packetfu/pcapng/file.rb +316 -0
  33. data/lib/packetfu/pcapng/idb.rb +125 -0
  34. data/lib/packetfu/pcapng/shb.rb +146 -0
  35. data/lib/packetfu/pcapng/spb.rb +83 -0
  36. data/lib/packetfu/pcapng/unknown_block.rb +60 -0
  37. data/lib/packetfu/protos.rb +3 -0
  38. data/lib/packetfu/protos/arp.rb +10 -10
  39. data/lib/packetfu/protos/icmpv6.rb +131 -0
  40. data/lib/packetfu/protos/icmpv6/header.rb +69 -0
  41. data/lib/packetfu/protos/icmpv6/mixin.rb +14 -0
  42. data/lib/packetfu/protos/ip.rb +4 -5
  43. data/lib/packetfu/protos/ipv6/header.rb +2 -0
  44. data/lib/packetfu/protos/udp.rb +24 -12
  45. data/lib/packetfu/structfu.rb +27 -0
  46. data/lib/packetfu/utils.rb +55 -9
  47. data/lib/packetfu/version.rb +1 -1
  48. data/packetfu.gemspec +13 -7
  49. data/spec/arp_spec.rb +11 -5
  50. data/spec/eth_spec.rb +20 -11
  51. data/spec/fake_packets.rb +28 -0
  52. data/spec/hsrp_spec.rb +15 -0
  53. data/spec/icmp_spec.rb +12 -5
  54. data/spec/icmpv6_spec.rb +98 -0
  55. data/spec/invalid_spec.rb +28 -0
  56. data/spec/ip_spec.rb +10 -5
  57. data/spec/ipv4_icmp.pcap +0 -0
  58. data/spec/ipv4_udp.pcap +0 -0
  59. data/spec/ipv6_icmp.pcap +0 -0
  60. data/spec/ipv6_spec.rb +4 -0
  61. data/spec/ipv6_udp.pcap +0 -0
  62. data/spec/lldp_spec.rb +36 -0
  63. data/spec/octets_spec.rb +43 -0
  64. data/spec/packet_spec.rb +24 -0
  65. data/spec/packetfu_spec.rb +6 -1
  66. data/spec/pcap_spec.rb +286 -0
  67. data/spec/pcapng/epb_spec.rb +81 -0
  68. data/spec/pcapng/file_spec.rb +295 -0
  69. data/spec/pcapng/file_spec_helper.rb +45 -0
  70. data/spec/pcapng/idb_spec.rb +53 -0
  71. data/spec/pcapng/shb_spec.rb +42 -0
  72. data/spec/pcapng/spb_spec.rb +43 -0
  73. data/spec/pcapng/unknown_block_spec.rb +36 -0
  74. data/spec/spec_helper.rb +3 -31
  75. data/spec/tcp_spec.rb +4 -1
  76. data/spec/udp_spec.rb +149 -1
  77. data/spec/utils_spec.rb +98 -15
  78. data/test/pcapng-test/output_be/advanced/test100.pcapng +0 -0
  79. data/test/pcapng-test/output_be/advanced/test100.txt +11 -0
  80. data/test/pcapng-test/output_be/advanced/test101.pcapng +0 -0
  81. data/test/pcapng-test/output_be/advanced/test101.txt +11 -0
  82. data/test/pcapng-test/output_be/advanced/test102.pcapng +0 -0
  83. data/test/pcapng-test/output_be/advanced/test102.txt +14 -0
  84. data/test/pcapng-test/output_be/basic/test001.pcapng +0 -0
  85. data/test/pcapng-test/output_be/basic/test001.txt +9 -0
  86. data/test/pcapng-test/output_be/basic/test002.pcapng +0 -0
  87. data/test/pcapng-test/output_be/basic/test002.txt +7 -0
  88. data/test/pcapng-test/output_be/basic/test003.pcapng +0 -0
  89. data/test/pcapng-test/output_be/basic/test003.txt +8 -0
  90. data/test/pcapng-test/output_be/basic/test004.pcapng +0 -0
  91. data/test/pcapng-test/output_be/basic/test004.txt +9 -0
  92. data/test/pcapng-test/output_be/basic/test005.pcapng +0 -0
  93. data/test/pcapng-test/output_be/basic/test005.txt +9 -0
  94. data/test/pcapng-test/output_be/basic/test006.pcapng +0 -0
  95. data/test/pcapng-test/output_be/basic/test006.txt +9 -0
  96. data/test/pcapng-test/output_be/basic/test007.pcapng +0 -0
  97. data/test/pcapng-test/output_be/basic/test007.txt +9 -0
  98. data/test/pcapng-test/output_be/basic/test008.pcapng +0 -0
  99. data/test/pcapng-test/output_be/basic/test008.txt +9 -0
  100. data/test/pcapng-test/output_be/basic/test009.pcapng +0 -0
  101. data/test/pcapng-test/output_be/basic/test009.txt +9 -0
  102. data/test/pcapng-test/output_be/basic/test010.pcapng +0 -0
  103. data/test/pcapng-test/output_be/basic/test010.txt +9 -0
  104. data/test/pcapng-test/output_be/basic/test011.pcapng +0 -0
  105. data/test/pcapng-test/output_be/basic/test011.txt +10 -0
  106. data/test/pcapng-test/output_be/basic/test012.pcapng +0 -0
  107. data/test/pcapng-test/output_be/basic/test012.txt +10 -0
  108. data/test/pcapng-test/output_be/basic/test013.pcapng +0 -0
  109. data/test/pcapng-test/output_be/basic/test013.txt +9 -0
  110. data/test/pcapng-test/output_be/basic/test014.pcapng +0 -0
  111. data/test/pcapng-test/output_be/basic/test014.txt +9 -0
  112. data/test/pcapng-test/output_be/basic/test015.pcapng +0 -0
  113. data/test/pcapng-test/output_be/basic/test015.txt +9 -0
  114. data/test/pcapng-test/output_be/basic/test016.pcapng +0 -0
  115. data/test/pcapng-test/output_be/basic/test016.txt +11 -0
  116. data/test/pcapng-test/output_be/basic/test017.pcapng +0 -0
  117. data/test/pcapng-test/output_be/basic/test017.txt +9 -0
  118. data/test/pcapng-test/output_be/basic/test018.pcapng +0 -0
  119. data/test/pcapng-test/output_be/basic/test018.txt +12 -0
  120. data/test/pcapng-test/output_be/difficult/test200.pcapng +0 -0
  121. data/test/pcapng-test/output_be/difficult/test200.txt +8 -0
  122. data/test/pcapng-test/output_be/difficult/test201.pcapng +0 -0
  123. data/test/pcapng-test/output_be/difficult/test201.txt +11 -0
  124. data/test/pcapng-test/output_be/difficult/test202.pcapng +0 -0
  125. data/test/pcapng-test/output_be/difficult/test202.txt +14 -0
  126. data/test/pcapng-test/output_le/advanced/test100.pcapng +0 -0
  127. data/test/pcapng-test/output_le/advanced/test100.txt +11 -0
  128. data/test/pcapng-test/output_le/advanced/test101.pcapng +0 -0
  129. data/test/pcapng-test/output_le/advanced/test101.txt +11 -0
  130. data/test/pcapng-test/output_le/advanced/test102.pcapng +0 -0
  131. data/test/pcapng-test/output_le/advanced/test102.txt +14 -0
  132. data/test/pcapng-test/output_le/basic/test001.pcapng +0 -0
  133. data/test/pcapng-test/output_le/basic/test001.txt +9 -0
  134. data/test/pcapng-test/output_le/basic/test002.pcapng +0 -0
  135. data/test/pcapng-test/output_le/basic/test002.txt +7 -0
  136. data/test/pcapng-test/output_le/basic/test003.pcapng +0 -0
  137. data/test/pcapng-test/output_le/basic/test003.txt +8 -0
  138. data/test/pcapng-test/output_le/basic/test004.pcapng +0 -0
  139. data/test/pcapng-test/output_le/basic/test004.txt +9 -0
  140. data/test/pcapng-test/output_le/basic/test005.pcapng +0 -0
  141. data/test/pcapng-test/output_le/basic/test005.txt +9 -0
  142. data/test/pcapng-test/output_le/basic/test006.pcapng +0 -0
  143. data/test/pcapng-test/output_le/basic/test006.txt +9 -0
  144. data/test/pcapng-test/output_le/basic/test007.pcapng +0 -0
  145. data/test/pcapng-test/output_le/basic/test007.txt +9 -0
  146. data/test/pcapng-test/output_le/basic/test008.pcapng +0 -0
  147. data/test/pcapng-test/output_le/basic/test008.txt +9 -0
  148. data/test/pcapng-test/output_le/basic/test009.pcapng +0 -0
  149. data/test/pcapng-test/output_le/basic/test009.txt +9 -0
  150. data/test/pcapng-test/output_le/basic/test010.pcapng +0 -0
  151. data/test/pcapng-test/output_le/basic/test010.txt +9 -0
  152. data/test/pcapng-test/output_le/basic/test011.pcapng +0 -0
  153. data/test/pcapng-test/output_le/basic/test011.txt +10 -0
  154. data/test/pcapng-test/output_le/basic/test012.pcapng +0 -0
  155. data/test/pcapng-test/output_le/basic/test012.txt +10 -0
  156. data/test/pcapng-test/output_le/basic/test013.pcapng +0 -0
  157. data/test/pcapng-test/output_le/basic/test013.txt +9 -0
  158. data/test/pcapng-test/output_le/basic/test014.pcapng +0 -0
  159. data/test/pcapng-test/output_le/basic/test014.txt +9 -0
  160. data/test/pcapng-test/output_le/basic/test015.pcapng +0 -0
  161. data/test/pcapng-test/output_le/basic/test015.txt +9 -0
  162. data/test/pcapng-test/output_le/basic/test016.pcapng +0 -0
  163. data/test/pcapng-test/output_le/basic/test016.txt +11 -0
  164. data/test/pcapng-test/output_le/basic/test017.pcapng +0 -0
  165. data/test/pcapng-test/output_le/basic/test017.txt +9 -0
  166. data/test/pcapng-test/output_le/basic/test018.pcapng +0 -0
  167. data/test/pcapng-test/output_le/basic/test018.txt +12 -0
  168. data/test/pcapng-test/output_le/difficult/test200.pcapng +0 -0
  169. data/test/pcapng-test/output_le/difficult/test200.txt +8 -0
  170. data/test/pcapng-test/output_le/difficult/test201.pcapng +0 -0
  171. data/test/pcapng-test/output_le/difficult/test201.txt +11 -0
  172. data/test/pcapng-test/output_le/difficult/test202.pcapng +0 -0
  173. data/test/pcapng-test/output_le/difficult/test202.txt +14 -0
  174. data/test/sample-ipv6.pcapng +0 -0
  175. data/test/sample-spb.pcapng +0 -0
  176. data/test/sample.pcapng +0 -0
  177. data/test/sample2.pcapng +0 -0
  178. metadata +190 -68
  179. checksums.yaml.gz.sig +0 -0
  180. data.tar.gz.sig +0 -2
  181. data/INSTALL.rdoc +0 -40
  182. data/README.rdoc +0 -64
  183. data/examples/examples.rb +0 -4
  184. data/setup.rb +0 -1586
  185. data/test/func_lldp.rb +0 -25
  186. data/test/ptest.rb +0 -16
  187. data/test/test_eth.rb +0 -93
  188. data/test/test_hsrp.rb +0 -20
  189. data/test/test_invalid.rb +0 -28
  190. data/test/test_octets.rb +0 -36
  191. data/test/test_pcap.rb +0 -211
  192. data/test/test_udp.rb +0 -100
  193. 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
@@ -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])
@@ -1,4 +1,6 @@
1
1
  # -*- coding: binary -*-
2
+ require 'ipaddr'
3
+
2
4
  module PacketFu
3
5
  # AddrIpv6 handles addressing for IPv6Header
4
6
  #
@@ -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
- return false unless IPPacket.can_parse? str
59
- return false unless str[23,1] == "\x11"
60
- return true
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
- peek_data = ["U "]
161
- peek_data << "%-5d" % self.to_s.size
162
- peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
163
- peek_data << "->"
164
- peek_data << "%21s" % "#{self.ip_daddr}:#{self.udp_dport}"
165
- peek_data << "%23s" % "I:"
166
- peek_data << "%04x" % self.ip_id
167
- peek_data.join
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
@@ -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
@@ -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
- NetworkInterface.interfaces.each do |interface|
170
- NetworkInterface.addresses(interface).values.each do |addresses|
171
- addresses.each do |address|
172
- next if address["addr"].nil?
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 NetworkInterface.interfaces.include?(iface)
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