PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/packetfu/protos/ipv6.rb

http://packetfu.googlecode.com/
Ruby | 250 lines | 152 code | 31 blank | 67 comment | 12 complexity | 321c165fd0473e58f5fed959252b01bc MD5 | raw file
  1. module PacketFu
  2. # AddrIpv6 handles addressing for IPv6Header
  3. #
  4. # ==== Header Definition
  5. #
  6. # Int32 :a1
  7. # Int32 :a2
  8. # Int32 :a3
  9. # Int32 :a4
  10. class AddrIpv6 < Struct.new(:a1, :a2, :a3, :a4)
  11. include StructFu
  12. def initialize(args={})
  13. super(
  14. Int32.new(args[:a1]),
  15. Int32.new(args[:a2]),
  16. Int32.new(args[:a3]),
  17. Int32.new(args[:a4]))
  18. end
  19. # Returns the address in string format.
  20. def to_s
  21. self.to_a.map {|x| x.to_s}.join
  22. end
  23. # Returns the address as a fairly ginormous integer.
  24. def to_i
  25. (a1.to_i << 96) + (a2.to_i << 64) + (a3.to_i << 32) + a4.to_i
  26. end
  27. # Returns the address as a colon-delimited hex string.
  28. def to_x
  29. IPAddr.new(self.to_i, Socket::AF_INET6).to_s
  30. end
  31. # Reads in a string and casts it as an IPv6 address
  32. def read(str)
  33. force_binary(str)
  34. return self if str.nil?
  35. self[:a1].read str[0,4]
  36. self[:a2].read str[4,4]
  37. self[:a3].read str[8,4]
  38. self[:a4].read str[12,4]
  39. self
  40. end
  41. # Reads in a colon-delimited hex string and casts it as an IPv6 address.
  42. def read_x(str)
  43. addr = IPAddr.new(str).to_i
  44. self[:a1]=Int32.new(addr >> 96)
  45. self[:a2]=Int32.new((addr & 0x00000000ffffffff0000000000000000) >> 64)
  46. self[:a3]=Int32.new((addr & 0x0000000000000000ffffffff00000000) >> 32)
  47. self[:a4]=Int32.new(addr & 0x000000000000000000000000ffffffff)
  48. self
  49. end
  50. end
  51. # IPv6Header is complete IPv6 struct, used in IPv6Packet.
  52. #
  53. # ==== Header Definition
  54. #
  55. # Fixnum (4 bits) :ipv6_v Default: 6 # Versiom
  56. # Fixnum (8 bits) :ipv6_class Defualt: 0 # Class
  57. # Fixnum (20 bits) :ipv6_label Defualt: 0 # Label
  58. # Int16 :ipv6_len Default: calc # Payload length
  59. # Int8 :ipv6_next # Next Header
  60. # Int8 :ipv6_hop Default: 0xff # Hop limit
  61. # AddrIpv6 :ipv6_src
  62. # AddrIpv6 :ipv6_dst
  63. # String :body
  64. class IPv6Header < Struct.new(:ipv6_v, :ipv6_class, :ipv6_label,
  65. :ipv6_len, :ipv6_next, :ipv6_hop,
  66. :ipv6_src, :ipv6_dst, :body)
  67. include StructFu
  68. def initialize(args={})
  69. super(
  70. (args[:ipv6_v] || 6),
  71. (args[:ipv6_class] || 0),
  72. (args[:ipv6_label] || 0),
  73. Int16.new(args[:ipv6_len]),
  74. Int8.new(args[:ipv6_next]),
  75. Int8.new(args[:ipv6_hop] || 0xff),
  76. AddrIpv6.new.read(args[:ipv6_src] || ("\x00" * 16)),
  77. AddrIpv6.new.read(args[:ipv6_dst] || ("\x00" * 16)),
  78. StructFu::String.new.read(args[:body])
  79. )
  80. end
  81. # Returns the object in string form.
  82. def to_s
  83. bytes_v_class_label = [(self.ipv6_v << 28) +
  84. (self.ipv6_class << 20) +
  85. self.ipv6_label].pack("N")
  86. bytes_v_class_label + (self.to_a[3,6].map {|x| x.to_s}.join)
  87. end
  88. # Reads a string to populate the object.
  89. def read(str)
  90. force_binary(str)
  91. return self if str.nil?
  92. self[:ipv6_v] = str[0,1].unpack("C").first >> 4
  93. self[:ipv6_class] = (str[0,2].unpack("n").first & 0x0ff0) >> 4
  94. self[:ipv6_label] = str[0,4].unpack("N").first & 0x000fffff
  95. self[:ipv6_len].read(str[4,2])
  96. self[:ipv6_next].read(str[6,1])
  97. self[:ipv6_hop].read(str[7,1])
  98. self[:ipv6_src].read(str[8,16])
  99. self[:ipv6_dst].read(str[24,16])
  100. self[:body].read(str[40,str.size]) if str.size > 40
  101. self
  102. end
  103. # Setter for the version (usually, 6).
  104. def ipv6_v=(i); self[:ip_v] = i.to_i; end
  105. # Getter for the version (usually, 6).
  106. def ipv6_v; self[:ipv6_v].to_i; end
  107. # Setter for the traffic class.
  108. def ipv6_class=(i); self[:ip_class] = i.to_i; end
  109. # Getter for the traffic class.
  110. def ipv6_class; self[:ipv6_class].to_i; end
  111. # Setter for the flow label.
  112. def ipv6_label=(i); self[:ip_label] = i.to_i; end
  113. # Getter for the flow label.
  114. def ipv6_label; self[:ipv6_label].to_i; end
  115. # Setter for the payload length.
  116. def ipv6_len=(i); typecast i; end
  117. # Getter for the payload length.
  118. def ipv6_len; self[:ipv6_len].to_i; end
  119. # Setter for the next protocol header.
  120. def ipv6_next=(i); typecast i; end
  121. # Getter for the next protocol header.
  122. def ipv6_next; self[:ipv6_next].to_i; end
  123. # Setter for the hop limit.
  124. def ipv6_hop=(i); typecast i; end
  125. # Getter for the hop limit.
  126. def ipv6_hop; self[:ipv6_hop].to_i; end
  127. # Setter for the source address.
  128. def ipv6_src=(i); typecast i; end
  129. # Getter for the source address.
  130. def ipv6_src; self[:ipv6_src].to_i; end
  131. # Setter for the destination address.
  132. def ipv6_dst=(i); typecast i; end
  133. # Getter for the destination address.
  134. def ipv6_dst; self[:ipv6_dst].to_i; end
  135. # Calculates the payload length.
  136. def ipv6_calc_len
  137. self[:ipv6_len] = body.to_s.length
  138. end
  139. # Recalculates the calculatable fields for this object.
  140. def ipv6_recalc(arg=:all)
  141. case arg
  142. when :ipv6_len
  143. ipv6_calc_len
  144. when :all
  145. ipv6_recalc(:len)
  146. end
  147. end
  148. # Get the source address in a more readable form.
  149. def ipv6_saddr
  150. self[:ipv6_src].to_x
  151. end
  152. # Set the source address in a more readable form.
  153. def ipv6_saddr=(str)
  154. self[:ipv6_src].read_x(str)
  155. end
  156. # Get the destination address in a more readable form.
  157. def ipv6_daddr
  158. self[:ipv6_dst].to_x
  159. end
  160. # Set the destination address in a more readable form.
  161. def ipv6_daddr=(str)
  162. self[:ipv6_dst].read_x(str)
  163. end
  164. # Readability aliases
  165. alias :ipv6_src_readable :ipv6_saddr
  166. alias :ipv6_dst_readable :ipv6_daddr
  167. end # class IPv6Header
  168. # IPv6Packet is used to construct IPv6 Packets. They contain an EthHeader and an IPv6Header, and in
  169. # the distant, unknowable future, will take interesting IPv6ish payloads.
  170. #
  171. # This mostly complete, but not very useful. It's intended primarily as an example protocol.
  172. #
  173. # == Parameters
  174. #
  175. # :eth
  176. # A pre-generated EthHeader object.
  177. # :ip
  178. # A pre-generated IPHeader object.
  179. # :flavor
  180. # TODO: Sets the "flavor" of the IPv6 packet. No idea what this will look like, haven't done much IPv6 fingerprinting.
  181. # :config
  182. # A hash of return address details, often the output of Utils.whoami?
  183. class IPv6Packet < Packet
  184. attr_accessor :eth_header, :ipv6_header
  185. def self.can_parse?(str)
  186. return false unless EthPacket.can_parse? str
  187. return false unless str.size >= 54
  188. return false unless str[12,2] == "\x86\xdd"
  189. true
  190. end
  191. def read(str=nil,args={})
  192. raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
  193. @eth_header.read(str)
  194. @ipv6_header.read(str[14,str.size])
  195. @eth_header.body = @ipv6_header
  196. super(args)
  197. self
  198. end
  199. def initialize(args={})
  200. @eth_header = (args[:eth] || EthHeader.new)
  201. @ipv6_header = (args[:ipv6] || IPv6Header.new)
  202. @eth_header.eth_proto = 0x86dd
  203. @eth_header.body=@ipv6_header
  204. @headers = [@eth_header, @ipv6_header]
  205. super
  206. end
  207. # Peek provides summary data on packet contents.
  208. def peek(args={})
  209. peek_data = ["6 "]
  210. peek_data << "%-5d" % self.to_s.size
  211. peek_data << "%-31s" % self.ipv6_saddr
  212. peek_data << "-> "
  213. peek_data << "%-31s" % self.ipv6_daddr
  214. peek_data << " N:"
  215. peek_data << self.ipv6_next.to_s(16)
  216. peek_data.join
  217. end
  218. end
  219. end