# frozen_string_literal: true # This file is part of PacketGen # See https://github.com/lemontree55/packetgen for more informations # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net> # Copyright (C) 2024 LemonTree55 <lenontree@proton.me> # This program is published under MIT license. module PacketGen module Header # An ARP header consists of: # * a hardware type ({#hrd} or {#htype}) field ({BinStruct::Int16}), # * a protocol type ({#pro} or {#ptype}) field (+Int16+), # * a hardware address length ({#hln} or {#hlen}) field ({BinStruct::Int8}), # * a protocol address length ({#pln} or {#plen}) field (+Int8+), # * a {#opcode} (or {#op}) field (+Int16+), # * a source hardware address ({#sha} or {#src_mac}) field ({Eth::MacAddr}), # * a source protocol address ({#spa} or {#src_ip}) field ({IP::Addr}), # * a target hardware address ({#tha} or {#dst_mac}) field (+Eth::MacAddr+), # * a target protocol address ({#tpa} or {#dst_ip}) field (+IP::Addr+), # * and a {#body}. # # == Create a ARP header # # standalone # arp = PacketGen::Header::ARP.new # # in a packet # pkt = PacketGen.gen('Eth').add('ARP') # # access to ARP header # pkt.arp # => PacketGen::Header::ARP # # @author Sylvain Daubert class ARP < Base # @!attribute hrd # 16-bit hardware protocol type # # @return [Integer] define_attr :hrd, BinStruct::Int16, default: 1 # @!attribute pro # 16-bit internet protocol type # # @return [Integer] define_attr :pro, BinStruct::Int16, default: 0x800 # @!attribute hln # 8-bit hardware address length # # @return [Integer] define_attr :hln, BinStruct::Int8, default: 6 # @!attribute pln # 8-bit internet address length # # @return [Integer] define_attr :pln, BinStruct::Int8, default: 4 # @!attribute op # 16-bit operation code # # @return [Integer] define_attr :op, BinStruct::Int16Enum, enum: { 'request' => 1, 'reply' => 2 } # @!attribute sha # source hardware address # @return [Eth::MacAddr] define_attr :sha, Eth::MacAddr # @!attribute spa # source protocol address # @return [IP::Addr] define_attr :spa, IP::Addr # @!attribute tha # target hardware address # @return [Eth::MacAddr] define_attr :tha, Eth::MacAddr # @!attribute tpa # target protocol address # @return [IP::Addr] define_attr :tpa, IP::Addr # @!attribute body # @return [BinStruct::String,Header::Base] define_attr :body, BinStruct::String # @param [Hash] options # @option options [Integer] :hrd network protocol type (default: 1) # @option options [Integer] :pro internet protocol type (default: 0x800) # @option options [Integer] :hln length of hardware addresses (default: 6) # @option options [Integer] :pln length of internet addresses (default: 4) # @option options [Integer] :op operation performing by sender (default: 1). # known values are +request+ (1) and +reply+ (2) # @option options [String] :sha sender hardware address # @option options [String] :spa sender internet address # @option options [String] :tha target hardware address # @option options [String] :tpa targetr internet address def initialize(options={}) handle_options(options) super end alias htype hrd alias htype= hrd= alias ptype pro alias ptype= pro= alias hlen hln alias hlen= hln= alias plen pln alias plen= pln= alias opcode op alias opcode= op= alias src_mac sha alias src_mac= sha= alias src_ip spa alias src_ip= spa= alias dst_mac tha alias dst_mac= tha= alias dst_ip tpa alias dst_ip= tpa= # Invert data to create a reply. # @return [self] def reply! case opcode.to_i when 1 self.opcode = 2 invert_addresses when 2 self.opcode = 1 invert_addresses self[:tha].from_human('00:00:00:00:00:00') end self end private # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def handle_options(options) options[:hrd] ||= options[:htype] options[:pro] ||= options[:ptype] options[:hln] ||= options[:hlen] options[:pln] ||= options[:plen] options[:op] ||= options[:opcode] options[:sha] ||= options[:src_mac] options[:spa] ||= options[:src_ip] options[:tha] ||= options[:dst_mac] options[:tpa] ||= options[:dst_ip] end # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def invert_addresses self.spa, self.tpa = self.tpa, self.spa self.sha, self.tha = self.tha, self.sha end end self.add_class ARP Eth.bind ARP, ethertype: 0x806 Dot1q.bind ARP, ethertype: 0x806 end end