# coding: utf-8
# 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
    # Multicast DNS.
    #
    # See {DNS} for header format.
    # @since 2.6.0
    # @author Sylvain Daubert
    class MDNS < DNS
      # Port number for mDNS over UDP
      UDP_PORT = 5353

      # Fixup IP header according to RFC 6762:
      # * set ethernet multicast address to +01:00:5E:00:00:FB+ (for IPv4)
      #   or +33:33:00:00:00:FB+ (for IPv6),
      # * set IPv4 address to +224.0.0.251+ or IPv6 address to +ff02::fb+.
      # This method may be called as:
      #    # first way
      #    pkt.mdns.mdnsize
      #    # second way
      #    pkt.
      # @example
      #   pkt = PacketGen.gen('Eth').add('IP').add('UDP').add('MDNS')
      #   pkt.mdnsize
      #   pkt.eth.dst   #=> "01:00:5e:00:00:fb"
      #   pkt.ip.dst    #=> "224.0.0.251"
      # @return [void]
      def mdnsize
        iph = ip_header(self)
        case iph
        when IP
          iph.dst = '224.0.0.251'
          dst_mac.from_human('01:00:5E:00:00:FB')
        when IPv6
          iph.dst = 'ff02::fb'
          dst_mac.from_human('33:33:00:00:00:FB')
        end
      end

      # @api private
      # @note This method is used internally by PacketGen and should not be
      #       directly called
      # Add +#mdnsize+ method to +packet+. This method calls {#mdnsize}.
      # @since 2.7.0 Set UDP sport according to bindings, only if sport is 0.
      #  Needed by new bind API.
      def added_to_packet(packet)
        mdns_idx = packet.headers.size
        packet.instance_eval "def mdnsize() @headers[#{mdns_idx}].mdnsize; end" # def mdnsize() @headers[4].mdnsize; end
        return unless packet.is?('UDP')
        return unless packet.udp.sport.zero?

        packet.udp.sport = UDP_PORT
      end

      private

      def dst_mac
        llh = ll_header(self)
        case llh
        when Eth
          llh[:dst]
        when Dot11
          if llh.to_ds?
            llh[:mac3]
          else
            llh[:mac1]
          end
        end
      end
    end

    self.add_class MDNS
    UDP.bind MDNS, dport: MDNS::UDP_PORT
    UDP.bind MDNS, sport: MDNS::UDP_PORT
  end
end
