PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/packetfu/packet.rb

https://bitbucket.org/jrossi/metasploit
Ruby | 500 lines | 317 code | 30 blank | 153 comment | 49 complexity | 9b6d15f25a6f6843c680ecdf89aa2d35 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. module PacketFu
  2. # Packet is the parent class of EthPacket, IPPacket, UDPPacket, TCPPacket, and all
  3. # other packets.
  4. class Packet
  5. attr_reader :flavor # Packet Headers are responsible for their own specific flavor methods.
  6. attr_accessor :headers # All packets have a header collection, useful for determining protocol trees.
  7. attr_accessor :iface # Default inferface to send packets to
  8. # Force strings into binary.
  9. def self.force_binary(str)
  10. str.force_encoding "binary" if str.respond_to? :force_encoding
  11. end
  12. # Parse() creates the correct packet type based on the data, and returns the apporpiate
  13. # Packet subclass.
  14. #
  15. # There is an assumption here that all incoming packets are either EthPacket
  16. # or InvalidPacket types.
  17. #
  18. # New packet types should get an entry here.
  19. def self.parse(packet,args={})
  20. force_binary(packet)
  21. if packet.size >= 14 # Min size for Ethernet. No check for max size, yet.
  22. case packet[12,2] # Check the Eth protocol field.
  23. when "\x08\x00" # It's IP.
  24. if 1.respond_to? :ord
  25. ipv = packet[14,1][0].ord >> 4
  26. else
  27. ipv = packet[14,1][0] >> 4
  28. end
  29. case ipv # Check the IP version field.
  30. when 4; # It's IPv4.
  31. case packet[23,1] # Check the IP protocol field.
  32. when "\x06"; p = TCPPacket.new # Returns a TCPPacket.
  33. when "\x11"; p = UDPPacket.new # Returns a UDPPacket.
  34. when "\x01"; p = ICMPPacket.new # Returns an ICMPPacket.
  35. else; p = IPPacket.new # Returns an IPPacket since we can't tell the transport layer.
  36. end
  37. else; p = IPPacket.new # Returns an EthPacket since we don't know any other IP version.
  38. end
  39. when "\x08\x06" # It's arp
  40. if packet.size >= 28 # Min size for complete arp
  41. p = ARPPacket.new
  42. else; p = EthPacket.new # Returns an EthPacket since we can't deal with tiny arps.
  43. end
  44. when "\x86\xdd" # It's IPv6
  45. if packet.size >= 54 # Min size for a complete IPv6 packet.
  46. p = IPv6Packet.new
  47. else; p = EthPacket.new # Returns an EthPacket since we can't deal with tiny Ipv6.
  48. end
  49. else; p = EthPacket.new # Returns an EthPacket since we can't tell the network layer.
  50. end
  51. else
  52. p = InvalidPacket.new # Not the right size for Ethernet (jumbo frames are okay)
  53. end
  54. parsed_packet = p.read(packet,args)
  55. return parsed_packet
  56. end
  57. #method_missing() delegates protocol-specific field actions to the apporpraite
  58. #class variable (which contains the associated packet type)
  59. #This register-of-protocols style switch will work for the
  60. #forseeable future (there aren't /that/ many packet types), and it's a handy
  61. #way to know at a glance what packet types are supported.
  62. def method_missing(sym, *args, &block)
  63. case sym.to_s
  64. when /^invalid_/
  65. @invalid_header.send(sym,*args)
  66. when /^eth_/
  67. @eth_header.send(sym,*args)
  68. when /^arp_/
  69. @arp_header.send(sym,*args)
  70. when /^ip_/
  71. @ip_header.send(sym,*args)
  72. when /^icmp_/
  73. @icmp_header.send(sym,*args)
  74. when /^udp_/
  75. @udp_header.send(sym,*args)
  76. when /^tcp_/
  77. @tcp_header.send(sym,*args)
  78. when /^ipv6_/
  79. @ipv6_header.send(sym,*args)
  80. else
  81. raise NoMethodError, "Unknown method `#{sym}' for this packet object."
  82. end
  83. end
  84. def respond_to?(sym, include_private = false)
  85. if sym.to_s =~ /^(invalid|eth|arp|ip|icmp|udp|tcp|ipv6)_/
  86. self.instance_variable_get("@#{$1}_header").respond_to? sym
  87. else
  88. super
  89. end
  90. end
  91. # Get the binary string of the entire packet.
  92. def to_s
  93. @headers[0].to_s
  94. end
  95. # In the event of no proper decoding, at least send it to the inner-most header.
  96. def write(io)
  97. @headers[0].write(io)
  98. end
  99. # Get the outermost payload (body) of the packet; this is why all packet headers
  100. # should have a body type.
  101. def payload
  102. @headers.last.body
  103. end
  104. # Set the outermost payload (body) of the packet.
  105. def payload=(args)
  106. @headers.last.body=(args)
  107. end
  108. # Converts a packet to libpcap format. Bit of a hack?
  109. def to_pcap(args={})
  110. p = PcapPacket.new(:endian => args[:endian],
  111. :timestamp => Timestamp.new.to_s,
  112. :incl_len => self.to_s.size,
  113. :orig_len => self.to_s.size,
  114. :data => self)
  115. end
  116. # Put the entire packet into a libpcap file. XXX: this is a
  117. # hack for now just to confirm that packets are getting created
  118. # correctly. Now with append! XXX: Document this!
  119. def to_f(filename=nil,mode='w')
  120. filename ||= 'out.pcap'
  121. mode = mode.to_s[0,1] + "b"
  122. raise ArgumentError, "Unknown mode: #{mode.to_s}" unless mode =~ /^[wa]/
  123. if(mode == 'w' || !(File.exists?(filename)))
  124. data = [PcapHeader.new, self.to_pcap].map {|x| x.to_s}.join
  125. else
  126. data = self.to_pcap
  127. end
  128. File.open(filename, mode) {|f| f.write data}
  129. return [filename, 1, data.size]
  130. end
  131. # Put the entire packet on the wire by creating a temporary PacketFu::Inject object.
  132. # TODO: Do something with auto-checksumming?
  133. def to_w(iface=nil)
  134. iface = iface || self.iface || PacketFu::Config.new.config[:iface]
  135. inj = PacketFu::Inject.new(:iface => iface)
  136. inj.array = [@headers[0].to_s]
  137. inj.inject
  138. end
  139. # Recalculates all the calcuated fields for all headers in the packet.
  140. # This is important since read() wipes out all the calculated fields
  141. # such as length and checksum and what all.
  142. def recalc(arg=:all)
  143. case arg
  144. when :ip
  145. ip_recalc(:all)
  146. when :icmp
  147. icmp_recalc(:all)
  148. when :udp
  149. udp_recalc(:all)
  150. when :tcp
  151. tcp_recalc(:all)
  152. when :all
  153. ip_recalc(:all) if @ip_header
  154. icmp_recalc(:all) if @icmp_header
  155. udp_recalc(:all) if @udp_header
  156. tcp_recalc(:all) if @tcp_header
  157. else
  158. raise ArgumentError, "Recalculating `#{arg}' unsupported. Try :all"
  159. end
  160. @headers[0]
  161. end
  162. # Read() takes (and trusts) the io input and shoves it all into a well-formed Packet.
  163. # Note that read is a destructive process, so any existing data will be lost.
  164. #
  165. # TODO: This giant if tree is a mess, and worse, is decieving. You need to define
  166. # actions both here and in parse(). All read() does is make a (good) guess as to
  167. # what @headers to expect, and reads data to them.
  168. #
  169. # To take strings and turn them into packets without knowing ahead of time what kind of
  170. # packet it is, use Packet.parse instead; parse() handles the figuring-out part.
  171. #
  172. # A note on the :strip => true argument: If :strip is set, defined lengths of data will
  173. # be believed, and any trailers (such as frame check sequences) will be chopped off. This
  174. # helps to ensure well-formed packets, at the cost of losing perhaps important FCS data.
  175. #
  176. # If :strip is false, header lengths are /not/ believed, and all data will be piped in.
  177. # When capturing from the wire, this is usually fine, but recalculating the length before
  178. # saving or re-transmitting will absolutely change the data payload; FCS data will become
  179. # part of the TCP data as far as tcp_len is concerned. Some effort has been made to preserve
  180. # the "real" payload for the purposes of checksums, but currently, it's impossible to seperate
  181. # new payload data from old trailers, so things like pkt.payload += "some data" will not work
  182. # correctly.
  183. #
  184. # So, to summarize; if you intend to alter the data, use :strip. If you don't, don't. Also,
  185. # this is a horrid XXX hack. Stripping is useful (and fun!), but the default behavior really
  186. # should be to create payloads correctly, and /not/ treat extra FCS data as a payload.
  187. #
  188. # Update: This scheme is so lame. Need to fix. Seriously.
  189. # Update: still sucks. Really.
  190. def read(io,args={})
  191. begin
  192. if io.size >= 14
  193. @eth_header.read(io)
  194. eth_proto_num = io[12,2].unpack("n")[0]
  195. if eth_proto_num == 0x0800 # It's IP.
  196. if 1.respond_to? :ord
  197. ipv = io[14].ord
  198. else
  199. ipv = io[14]
  200. end
  201. ip_hlen=(ipv & 0x0f) * 4
  202. ip_ver=(ipv >> 4) # It's IPv4. Other versions, all bets are off!
  203. if ip_ver == 4
  204. ip_proto_num = io[23,1].unpack("C")[0]
  205. @ip_header.read(io[14,ip_hlen])
  206. if ip_proto_num == 0x06 # It's TCP.
  207. tcp_len = io[16,2].unpack("n")[0] - 20
  208. if args[:strip] # Drops trailers like frame check sequence (FCS). Often desired for cleaner packets.
  209. tcp_all = io[ip_hlen+14,tcp_len] # Believe the tcp_len value; chop off anything that's not in range.
  210. else
  211. tcp_all = io[ip_hlen+14,0xffff] # Don't believe the tcp_len value; suck everything up.
  212. end
  213. tcp_hlen = ((tcp_all[12,1].unpack("C")[0]) >> 4) * 4
  214. if tcp_hlen.to_i >= 20
  215. @tcp_header.read(tcp_all)
  216. @ip_header.body = @tcp_header
  217. else # It's a TCP packet with an impossibly small hlen, so it can't be real TCP. Abort! Abort!
  218. @ip_header.body = io[16,io.size-16]
  219. end
  220. elsif ip_proto_num == 0x11 # It's UDP.
  221. udp_len = io[16,2].unpack("n")[0] - 20
  222. if args[:strip] # Same deal as with TCP. We might have stuff at the end of the packet that's not part of the payload.
  223. @udp_header.read(io[ip_hlen+14,udp_len])
  224. else # ... Suck it all up. BTW, this will change the lengths if they are ever recalc'ed. Bummer.
  225. @udp_header.read(io[ip_hlen+14,0xffff])
  226. end
  227. @ip_header.body = @udp_header
  228. elsif ip_proto_num == 1 # It's ICMP
  229. @icmp_header.read(io[ip_hlen+14,0xffff])
  230. @ip_header.body = @icmp_header
  231. else # It's an IP packet for a protocol we don't have a decoder for.
  232. @ip_header.body = io[16,io.size-16]
  233. end
  234. else # It's not IPv4, so no idea what should come next. Just dump it all into an ip_header and ip payload.
  235. @ip_header.read(io[14,ip_hlen])
  236. @ip_header.body = io[16,io.size-16]
  237. end
  238. @eth_header.body = @ip_header
  239. elsif eth_proto_num == 0x0806 # It's ARP
  240. @arp_header.read(io[14,0xffff]) # You'll nearly have a trailer and you'll never know what size.
  241. @eth_header.body=@arp_header
  242. @eth_header.body
  243. elsif eth_proto_num == 0x86dd # It's IPv6
  244. @ipv6_header.read(io[14,0xffff])
  245. @eth_header.body=@ipv6_header
  246. else # It's an Ethernet packet for a protocol we don't have a decoder for
  247. @eth_header.body = io[14,io.size-14]
  248. end
  249. if (args[:fix] || args[:recalc])
  250. # Unfortunately, we cannot simply recalc with abandon, since
  251. # we may have unaccounted trailers that will sneak into the checksum.
  252. # The better way to handle this is to put trailers in their own
  253. # StructFu field, but I'm not a-gonna right now. :/
  254. ip_recalc(:ip_sum) if respond_to? :ip_header
  255. recalc(:tcp) if respond_to? :tcp_header
  256. recalc(:udp) if respond_to? :udp_header
  257. end
  258. else # You're not big enough for Ethernet.
  259. @invalid_header.read(io)
  260. end
  261. # @headers[0]
  262. self
  263. rescue ::Exception => e
  264. # remove last header
  265. # nested_types = self.headers.collect {|header| header.class}
  266. # nested_types.pop # whatever this packet type is, we weren't able to parse it
  267. self.headers.pop
  268. return_header_type = self.headers[self.headers.length-1].class.to_s
  269. retklass = PacketFu::InvalidPacket
  270. seekpos = 0
  271. target_header = @invalid_header
  272. case return_header_type.to_s
  273. when "PacketFu::EthHeader"
  274. retklass = PacketFu::EthPacket
  275. seekpos = 0x0e
  276. target_header = @eth_header
  277. when "PacketFu::IPHeader"
  278. retklass = PacketFu::IPPacket
  279. seekpos = 0x0e + @ip_header.ip_hl * 4
  280. target_header = @ip_header
  281. when "PacketFu::TCPHeader"
  282. retklass = PacketFu::TCPPacket
  283. seekpos = 0x0e + @ip_header.ip_hl * 4 + @tcpheader.tcp_hlen
  284. target_header = @tcp_header
  285. when "PacketFu::UDPHeader"
  286. retklass = PacketFu::UDPPacket
  287. when "PacketFu::ARPHeader"
  288. retklass = PacketFu::ARPPacket
  289. when "PacketFu::ICMPHeader"
  290. retklass = PacketFu::ICMPPacket
  291. when "PacketFu::IPv6Header"
  292. retklass = PacketFu::IPv6Packet
  293. else
  294. end
  295. io = io[seekpos,io.length - seekpos]
  296. target_header.body = io
  297. p = retklass.new
  298. p.headers = self.headers
  299. p
  300. raise e if $debug
  301. end
  302. end
  303. # Peek provides summary data on packet contents.
  304. # Each packet type should provide its own peek method, and shouldn't exceed 80 characters wide (for
  305. # easy reading in normal irb shells). If they don't, this default summary will step in.
  306. def peek(args={})
  307. peek_data = ["? "]
  308. peek_data << "%-5d" % self.to_s.size
  309. peek_data << "%68s" % self.to_s[0,34].unpack("H*")[0]
  310. peek_data.join
  311. end
  312. # Hexify provides a neatly-formatted dump of binary data, familar to hex readers.
  313. def hexify(str)
  314. hexascii_lines = str.to_s.unpack("H*")[0].scan(/.{1,32}/)
  315. chars = str.to_s.gsub(/[\x00-\x1f\x7f-\xff]/,'.')
  316. chars_lines = chars.scan(/.{1,16}/)
  317. ret = []
  318. hexascii_lines.size.times {|i| ret << "%-48s %s" % [hexascii_lines[i].gsub(/(.{2})/,"\\1 "),chars_lines[i]]}
  319. ret.join("\n")
  320. end
  321. # Returns a hex-formatted representation of the packet.
  322. #
  323. # ==== Arguments
  324. #
  325. # 0..9 : If a number is given only the layer in @header[arg] will be displayed. Note that this will include all @headers included in that header.
  326. # :layers : If :layers is specified, the dump will return an array of headers by layer level.
  327. # :all : An alias for arg=0.
  328. #
  329. # ==== Examples
  330. #
  331. # irb(main):003:0> pkt = TCPPacket.new
  332. # irb(main):003:0> puts pkt.inspect_hex(:layers)
  333. # 00 1a c5 00 00 00 00 1a c5 00 00 00 08 00 45 00 ..............E.
  334. # 00 28 83 ce 00 00 ff 06 38 02 00 00 00 00 00 00 .(......8.......
  335. # 00 00 a6 0f 00 00 ac 89 7b 26 00 00 00 00 50 00 ........{&....P.
  336. # 40 00 a2 25 00 00 @..%..
  337. # 45 00 00 28 83 ce 00 00 ff 06 38 02 00 00 00 00 E..(......8.....
  338. # 00 00 00 00 a6 0f 00 00 ac 89 7b 26 00 00 00 00 ..........{&....
  339. # 50 00 40 00 a2 25 00 00 P.@..%..
  340. # a6 0f 00 00 ac 89 7b 26 00 00 00 00 50 00 40 00 ......{&....P.@.
  341. # a2 25 00 00 .%..
  342. # => nil
  343. # irb(main):004:0> puts pkt.inspect_hex(:layers)[2]
  344. # a6 0f 00 00 ac 89 7b 26 00 00 00 00 50 00 40 00 ......{&....P.@.
  345. # a2 25 00 00 .%..
  346. # => nil
  347. #
  348. # TODO: Colorize this! Everyone loves colorized irb output.
  349. def inspect_hex(arg=0)
  350. case arg
  351. when :layers
  352. ret = []
  353. @headers.size.times do |i|
  354. ret << hexify(@headers[i])
  355. end
  356. ret
  357. when (0..9)
  358. if @headers[arg]
  359. hexify(@headers[arg])
  360. else
  361. nil
  362. end
  363. when :all
  364. inspect_hex(0)
  365. end
  366. end
  367. # For packets, inspect is overloaded as inspect_hex(0).
  368. # Not sure if this is a great idea yet, but it sure makes
  369. # the irb output more sane.
  370. #
  371. # If you hate this, you can run PacketFu.toggle_inspect to return
  372. # to the typical (and often unreadable) Object#inspect format.
  373. def inspect
  374. self.proto.join("|") + "\n" + self.inspect_hex
  375. end
  376. # Returns the size of the packet (as a binary string)
  377. def size
  378. self.to_s.size
  379. end
  380. # Returns an array of protocols contained in this packet. For example:
  381. #
  382. # t = PacketFu::TCPPacket.new
  383. # => 00 1a c5 00 00 00 00 1a c5 00 00 00 08 00 45 00 ..............E.
  384. # 00 28 3c ab 00 00 ff 06 7f 25 00 00 00 00 00 00 .(<......%......
  385. # 00 00 93 5e 00 00 ad 4f e4 a4 00 00 00 00 50 00 ...^...O......P.
  386. # 40 00 4a 92 00 00 @.J...
  387. # t.proto
  388. # => ["Eth", "IP", "TCP"]
  389. #
  390. def proto
  391. type_array = []
  392. self.headers.each {|header| type_array << header.class.to_s.split('::').last.gsub(/Header$/,'')}
  393. type_array
  394. end
  395. alias_method :protocol, :proto
  396. # Returns true if this is an Invalid packet. Else, false.
  397. def is_invalid? ; self.proto.include? "Invalid"; end
  398. # Returns true if this is an Ethernet packet. Else, false.
  399. def is_ethernet? ; self.proto.include? "Eth"; end
  400. alias_method :is_eth?, :is_ethernet?
  401. # Returns true if this is an IP packet. Else, false.
  402. def is_ip? ; self.proto.include? "IP"; end
  403. # Returns true if this is an TCP packet. Else, false.
  404. def is_tcp? ; self.proto.include? "TCP"; end
  405. # Returns true if this is an UDP packet. Else, false.
  406. def is_udp? ; self.proto.include? "UDP"; end
  407. # Returns true if this is an ARP packet. Else, false.
  408. def is_arp? ; self.proto.include? "ARP"; end
  409. # Returns true if this is an IPv6 packet. Else, false.
  410. def is_ipv6? ; self.proto.include? "IPv6" ; end
  411. # Returns true if this is an ICMP packet. Else, false.
  412. def is_icmp? ; self.proto.include? "ICMP" ; end
  413. # Returns true if this is an IPv6 packet. Else, false.
  414. def is_ipv6? ; self.proto.include? "IPv6" ; end
  415. # Returns true if the outermost layer has data. Else, false.
  416. def has_data? ; self.payload.size.zero? ? false : true ; end
  417. alias_method :length, :size
  418. def initialize(args={})
  419. if args[:config]
  420. args[:config].each_pair do |k,v|
  421. case k
  422. when :eth_daddr; @eth_header.eth_daddr=v if @eth_header
  423. when :eth_saddr; @eth_header.eth_saddr=v if @eth_header
  424. when :ip_saddr; @ip_header.ip_saddr=v if @ip_header
  425. when :iface; @iface = v
  426. end
  427. end
  428. end
  429. end
  430. end # class Packet
  431. @@inspect_style = :pretty
  432. # If @@inspect_style is :ugly, set the inspect method to the usual inspect.
  433. # By default, @@inspect_style is :pretty. This default may change if people
  434. # hate it.
  435. # Since PacketFu is designed with irb in mind, the normal inspect is way too
  436. # verbose when new packets are created, and it ruins the aesthetics of the
  437. # PacketFu console or quick hping-like exercises in irb.
  438. #
  439. # However, there are cases where knowing things like object id numbers, the complete
  440. # @header array, etc. is useful (especially in debugging). So, toggle_inspect
  441. # provides a means for a script to declar which style of inspect to use.
  442. #
  443. # This method may be an even worse idea than the original monkeypatch to Packet.inspect,
  444. # since it would almost certainly be better to redefine inspect just in the PacketFu console.
  445. # We'll see what happens.
  446. #
  447. # == Example
  448. #
  449. # irb(main):001:0> p = PacketFu::TCPPacket.new
  450. # => Eth|IP|TCP
  451. # 00 1a c5 00 00 00 00 1a c5 00 00 00 08 00 45 00 ..............E.
  452. # 00 28 ea d7 00 00 ff 06 d0 f8 00 00 00 00 00 00 .(..............
  453. # 00 00 a9 76 00 00 f9 28 7e 95 00 00 00 00 50 00 ...v...(~.....P.
  454. # 40 00 4e b0 00 00 @.N...
  455. # irb(main):002:0> PacketFu.toggle_inspect
  456. # => :ugly
  457. # irb(main):003:0> p = PacketFu::TCPPacket.new
  458. # => #<PacketFu::TCPPacket:0xb7aaf96c @ip_header=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>, @tcp_header=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">, @eth_header=#<struct PacketFu::EthHeader eth_dst=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_src=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_proto=#<struct StructFu::Int16 value=2048, endian=:big, width=2, default=0>, body=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>>, @headers=[#<struct PacketFu::EthHeader eth_dst=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_src=#<struct PacketFu::EthMac oui=#<struct PacketFu::EthOui b0=nil, b1=nil, b2=nil, b3=nil, b4=nil, b5=nil, local=0, multicast=nil, oui=428>, nic=#<struct PacketFu::EthNic n0=nil, n1=nil, n2=nil>>, eth_proto=#<struct StructFu::Int16 value=2048, endian=:big, width=2, default=0>, body=#<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>>, #<struct PacketFu::IPHeader ip_v=4, ip_hl=5, ip_tos=#<struct StructFu::Int8 value=nil, endian=nil, width=1, default=0>, ip_len=#<struct StructFu::Int16 value=20, endian=:big, width=2, default=0>, ip_id=#<struct StructFu::Int16 value=58458, endian=:big, width=2, default=0>, ip_frag=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, ip_ttl=#<struct StructFu::Int8 value=32, endian=nil, width=1, default=0>, ip_proto=#<struct StructFu::Int8 value=6, endian=nil, width=1, default=0>, ip_sum=#<struct StructFu::Int16 value=65535, endian=:big, width=2, default=0>, ip_src=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, ip_dst=#<struct PacketFu::Octets o1=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o2=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o3=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>, o4=#<struct StructFu::Int8 value=0, endian=nil, width=1, default=0>>, body=#<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">>, #<struct PacketFu::TCPHeader tcp_src=#<struct StructFu::Int16 value=17222, endian=:big, width=2, default=0>, tcp_dst=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_seq=#<struct StructFu::Int32 value=1528113240, endian=:big, width=4, default=0>, tcp_ack=#<struct StructFu::Int32 value=nil, endian=:big, width=4, default=0>, tcp_hlen=#<struct PacketFu::TcpHlen hlen=5>, tcp_reserved=#<struct PacketFu::TcpReserved r1=0, r2=0, r3=0>, tcp_ecn=#<struct PacketFu::TcpEcn n=nil, c=nil, e=nil>, tcp_flags=#<struct PacketFu::TcpFlags urg=0, ack=0, psh=0, rst=0, syn=0, fin=0>, tcp_win=#<struct StructFu::Int16 value=16384, endian=:big, width=2, default=0>, tcp_sum=#<struct StructFu::Int16 value=43333, endian=:big, width=2, default=0>, tcp_urg=#<struct StructFu::Int16 value=nil, endian=:big, width=2, default=0>, tcp_opts=[], body="">]>
  459. # irb(main):004:0>
  460. def toggle_inspect
  461. if @@inspect_style == :pretty
  462. eval("class Packet; def inspect; super; end; end")
  463. @@inspect_style = :ugly
  464. else
  465. eval("class Packet; def inspect; self.proto.join('|') + \"\n\" + self.inspect_hex; end; end")
  466. @@inspect_style = :pretty
  467. end
  468. end
  469. end
  470. # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby