Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/proto/dns/packet.rb
Views: 11704
# -*- coding: binary -*-12require 'net/dns'3require 'resolv'4require 'dnsruby'56module Rex7module Proto8module DNS910module Packet1112#13# Checks string to ensure it can be used as a valid hostname14#15# @param subject [String] Subject name to check16#17# @return [TrueClass,FalseClass] Disposition on name match18def self.valid_hostname?(subject = '')19!subject.match(Rex::Proto::DNS::Constants::MATCH_HOSTNAME).nil?20end2122#23# Reconstructs a packet with both standard DNS libraries24# Ensures that headers match the payload25#26# @param packet [String, Net::DNS::Packet, Dnsruby::Message] Data to be validated27#28# @return [Dnsruby::Message]29def self.validate(packet)30self.encode_drb(self.encode_net(self.encode_res(packet)))31end3233#34# Sets header values to match packet content35#36# @param packet [String] Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message]37#38# @return [Dnsruby::Message]39def self.recalc_headers(packet)40packet = self.encode_drb(packet)41{42:qdcount= => :question,43:ancount= => :answer,44:nscount= => :authority,45:arcount= => :additional46}.each do |header,body|47packet.header.send(header,packet.send(body).count)48end4950return packet51end5253#54# Reads a packet into the Net::DNS::Packet format55#56# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data57#58# @return [Net::DNS::Packet]59def self.encode_net(packet)60return packet if packet.is_a?(Net::DNS::Packet)61Net::DNS::Packet.parse(62self.encode_raw(packet)63)64end6566# Reads a packet into the Resolv::DNS::Message format67#68# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data69#70# @return [Resolv::DNS::Message]71def self.encode_res(packet)72return packet if packet.is_a?(Resolv::DNS::Message)73Resolv::DNS::Message.decode(74self.encode_raw(packet)75)76end7778# Reads a packet into the Dnsruby::Message format79#80# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data81#82# @return [Dnsruby::Message]83def self.encode_drb(packet)84return packet if packet.is_a?(Dnsruby::Message)85Dnsruby::Message.decode(86self.encode_raw(packet)87)88end8990# Reads a packet into the raw String format91#92# @param data [String, Net::DNS::Packet, Resolv::DNS::Message, Dnsruby::Message] Input data93#94# @return [String]95def self.encode_raw(packet)96return packet unless packet.respond_to?(:encode) or packet.respond_to?(:data)97(packet.respond_to?(:data) ? packet.data : packet.encode).force_encoding('binary')98end99100#101# Generates a request packet, taken from Net::DNS::Resolver102#103# @param subject [String] Subject name of question section104# @param type [Fixnum] Type of DNS record to query105# @param cls [Fixnum] Class of dns record to query106# @param recurse [Fixnum] Recursive query or not107#108# @return [Dnsruby::Message] request packet109def self.generate_request(subject, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN, recurse = 1)110case subject111when IPAddr112name = subject.reverse113type = Dnsruby::Types::PTR114when /\d/ # Contains a number, try to see if it's an IP or IPv6 address115begin116name = IPAddr.new(subject).reverse117type = Dnsruby::Types::PTR118rescue ArgumentError119name = subject if self.valid_hostname?(subject)120end121else122name = subject if self.valid_hostname?(subject)123end124125# Create the packet126packet = Dnsruby::Message.new(name, type, cls)127128if packet.header.opcode == Dnsruby::OpCode::Query129packet.header.recursive = recurse130end131132# DNSSEC and TSIG stuff to be inserted here133134return packet135end136137#138# Generates a response packet for an existing request139#140# @param request [String] Net::DNS::Packet, Resolv::DNS::Message] Original request141# @param answer [Array] Set of answers to provide in the response142# @param authority [Array] Set of authority records to provide in the response143# @param additional [Array] Set of additional records to provide in the response144#145# @return [Dnsruby::Message] Response packet146def self.generate_response(request, answer = nil, authority = nil, additional = nil)147packet = self.encode_drb(request)148packet.answer = answer if answer149packet.authority = authority if authority150packet.additional = additional if additional151packet = self.recalc_headers(packet)152153# Set error code for NXDomain or unset it if reprocessing a response154if packet.header.ancount < 1155packet.header.rcode = Dnsruby::RCode::NXDOMAIN156else157if packet.header.qr and packet.header.get_header_rcode.to_i == 3158packet.header.rcode = Dnsruby::RCode::NOERROR159end160end161# Set response bit last to allow reprocessing of responses162packet.header.qr = true163# Set recursion available bit if recursion desired164packet.header.ra = true if packet.header.rd165return packet166end167168module Raw169170#171# Convert data to little endian unsigned short172#173# @param data [Fixnum, Float, Array] Input for conversion174#175# @return [String] Raw output176def self.to_short_le(data)177[data].flatten.pack('S*')178end179180#181# Convert data from little endian unsigned short182#183# @param data [String] Input for conversion184#185# @return [Array] Integer array output186def self.from_short_le(data)187data.unpack('S*')188end189190#191# Convert data to little endian unsigned int192#193# @param data [Fixnum, Float, Array] Input for conversion194#195# @return [String] Raw output196def self.to_int_le(data)197[data].flatten.pack('I*')198end199200#201# Convert data from little endian unsigned int202#203# @param data [String] Input for conversion204#205# @return [Array] Integer array output206def self.from_int_le(data)207data.unpack('I*')208end209210#211# Convert data to little endian unsigned long212#213# @param data [Fixnum, Float, Array] Input for conversion214#215# @return [String] Raw output216def self.to_long_le(data)217[data].flatten.pack('L*')218end219220#221# Convert data from little endian unsigned long222#223# @param data [String] Input for conversion224#225# @return [Array] Integer array output226def self.from_long_le(data)227data.unpack('L*')228end229230#231# Convert data to big endian unsigned short232#233# @param data [Fixnum, Float, Array] Input for conversion234#235# @return [String] Raw output236def self.to_short_be(data)237[data].flatten.pack('S>*')238end239240#241# Convert data from big endian unsigned short242#243# @param data [String] Input for conversion244#245# @return [Array] Integer array output246def self.from_short_be(data)247data.unpack('S>*')248end249250#251# Convert data to big endian unsigned int252#253# @param data [Fixnum, Float, Array] Input for conversion254#255# @return [String] Raw output256def self.to_int_be(data)257[data].flatten.pack('I>*')258end259260#261# Convert data from big endian unsigned int262#263# @param data [String] Input for conversion264#265# @return [Array] Integer array output266def self.from_int_be(data)267data.unpack('I>*')268end269270#271# Convert data to big endian unsigned long272#273# @param data [Fixnum, Float, Array] Input for conversion274#275# @return [String] Raw output276def self.to_long_be(data)277[data].flatten.pack('L>*')278end279280#281# Convert data from big endian unsigned long282#283# @param data [String] Input for conversion284#285# @return [Array] Integer array output286def self.from_long_be(data)287data.unpack('L>*')288end289290#291# Returns request ID from raw packet skipping parsing292#293# @param data [String] Request data294#295# @return [Fixnum] Request ID296def self.request_id(data)297self.from_short_be(data[0..1])[0]298end299300#301# Returns request length from raw packet skipping parsing302#303# @param data [String] Request data304#305# @return [Fixnum] Request Length306def self.request_length(data)307self.from_short_le(data[0..2])[0]308end309end310end311312end313end314end315316317