class PacketGen::Header::IP
IP
protocol ({tools.ietf.org/html/rfc791 RFC 791})
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
A IP
header consists of:
-
a first byte ({#u8} of {Types::Int8} type) composed of:
-
a 4-bit {#version} field,
-
a 4-bit
IP
header length ({#ihl}) field,
-
-
a Type of Service field ({#tos}, {Types::Int8} type),
-
a total length ({#length}, {Types::Int16} type),
-
a ID ({#id},
Int16
type), -
a {#frag} worg (
Int16
) composed of:-
3 1-bit flags ({#flag_rsv}, {#flag_df} and {#flag_mf}),
-
a 13-bit {#fragment_offset} field,
-
-
a Time-to-Live ({#ttl}) field (
Int8
), -
a {#protocol} field (
Int8
), -
a {#checksum} field (
Int16
), -
a source
IP
address ({#src}, {Addr} type), -
a destination
IP
address ({#dst},Addr
type), -
an optional {#options} field ({Options} type),
-
and a {#body} ({Types::String} type).
Create a IP
header¶ ↑
# standalone ip = PacketGen::Header::IP.new # in a packet pkt = PacketGen.gen('IP') # access to IP header pkt.ip # => PacketGen::Header::IP
IP
attributes¶ ↑
ip.u8 = 0x45 # the same as ip.version = 4 ip.ihl = 5 ip.length = 0x43 ip.id = 0x1234 ip.frag = 0x2031 # the same as: ip.flag_mf = true ip.fragment_offset = 0x31 ip.flag_rsv? # => Boolean ip.flag_df? # => Boolean ip.flag_mf? # => Boolean ip.ttl = 0x40 ip.protocol = 6 ip.checksum = 0xffff ip.src = '127.0.0.1' ip.src # => "127.0.0.1" ip[:src] # => PacketGen::Header::IP::Addr ip.dst = '127.0.0.2' ip.body.read 'this is a body'
Add IP
options¶ ↑
IP
has an {#options} attribute used to store datagram options.
pkt = PacketGen.gen('IP') # add option from class pkt.ip.options << PacketGen::Header::IP::RA.new # or use a hash pkt.ip.options << { type: 'RR', data: ['192.168.16.4']}
@author Sylvain Daubert
Constants
- ETHERTYPE
IP
Ether type
Public Class Methods
Helper method to reduce an IP
checksum. This method:
-
checks a checksum is not greater than 0xffff. If it is, reduces it.
-
inverts reduced self.
@param [Integer] checksum checksum to reduce @return [Integer] reduced checksum
# File lib/packetgen/header/ip.rb, line 184 def self.reduce_checksum(checksum) checksum = (checksum & 0xffff) + (checksum >> 16) while checksum > 0xffff checksum = ~checksum & 0xffff checksum.zero? ? 0xffff : checksum end
Helper method to compute sum of 16-bit words. Used to compute IP-style checksums. @param [#to_s] hdr header or other object on which calculates a sum
of 16-bit words.
@return [Integer]
# File lib/packetgen/header/ip.rb, line 160 def self.sum16(hdr) old_checksum = nil if hdr.respond_to? :checksum= old_checksum = hdr.checksum hdr.checksum = 0 end data = hdr.to_s data << "\x00" if data.size.odd? sum = data.unpack('n*').sum hdr.checksum = old_checksum if old_checksum sum end
Public Instance Methods
Compute checksum and set checksum
field @return [Integer]
# File lib/packetgen/header/ip.rb, line 192 def calc_checksum # Checksum is only on header, so cannot use IP.sum16, # which also calculates checksum on #body. nb_words = ihl * 2 self.checksum = 0 checksum = to_s.unpack("n#{nb_words}").sum self[:checksum].value = IP.reduce_checksum(checksum) end
Compute and set length
and ihl
field @return [Integer] @since 3.0.0 add ihl
calculation
# File lib/packetgen/header/ip.rb, line 204 def calc_length Base.calculate_and_set_length self self.ihl = 5 + self[:options].sz / 4 end
@return [String]
# File lib/packetgen/header/ip.rb, line 230 def inspect super do |attr| case attr when :u8 inspect_u8 when :frag inspect_frag end end end
Check version field @see [Base#parse?]
# File lib/packetgen/header/ip.rb, line 243 def parse? (version == 4) && (ihl >= 5) end
Get IP
part of pseudo header checksum. @return [Integer]
# File lib/packetgen/header/ip.rb, line 211 def pseudo_header_checksum checksum = self[:src].to_i + self[:dst].to_i (checksum >> 16) + (checksum & 0xffff) end
Invert source and destination addresses @return [self] @since 2.7.0
# File lib/packetgen/header/ip.rb, line 257 def reply! self[:src], self[:dst] = self[:dst], self[:src] self end
Get binary string. Fixup IHL if needed (IP
header has options, and IHL was not set by user).
# File lib/packetgen/header/ip.rb, line 249 def to_s self.ihl = 5 + self[:options].sz / 4 if self.ihl == 5 super end
Send IP
packet on wire.
When sending packet at IP
level, checksum
and length
fields are set by kernel, so bad IP
packets cannot be sent this way. To do so, use {Eth#to_w}. @param [String,nil] _iface interface name. Not used @return [void]
# File lib/packetgen/header/ip.rb, line 222 def to_w(_iface=nil) sock = Socket.new(Socket::AF_INET, Socket::SOCK_RAW, Socket::IPPROTO_RAW) sockaddrin = Socket.sockaddr_in(0, dst) sock.send to_s, 0, sockaddrin sock.close end
Private Instance Methods
# File lib/packetgen/header/ip.rb, line 271 def inspect_frag shift = Inspect.shift_level str = Inspect.inspect_attribute(:frag, self[:frag]) flags = %i[rsv df mf].select { |flag| send("flag_#{flag}?") }.map(&:upcase) flags_str = flags.empty? ? 'none' : flags.join(',') str << shift << Inspect::FMT_ATTR % ['', 'flags', flags_str] foff = Inspect.int_dec_hex(fragment_offset, 4) str << shift << Inspect::FMT_ATTR % ['', 'frag_offset', foff] end
# File lib/packetgen/header/ip.rb, line 264 def inspect_u8 shift = Inspect.shift_level str = Inspect.inspect_attribute(:u8, self[:u8]) str << shift << Inspect::FMT_ATTR % ['', 'version', version] str << shift << Inspect::FMT_ATTR % ['', 'ihl', ihl] end