lib/inet.ex

defmodule Inet do
  @moduledoc """
  Documentation for `Inet`.
  """

  @doc """
  A function that takes a hostname and returns a list of IP addresses.
  The IP address in the result may vary as it depends on the network and DNS resolution.

  ## Examples

      iex> Inet.get_ip_address_list("google.com")

  """
  def get_ip_address_list(hostname) do
    case get_host_by_name(hostname) do
      {:ok, {_, _, [], _, _, ip_address_tuple_list}} ->
        ip_address_list = _get_ip_address_list(ip_address_tuple_list)
        {:ok, ip_address_list}

      {:ok, {_, _, [_], _, _, ip_address_tuple_list}} ->
        ip_address_list = _get_ip_address_list(ip_address_tuple_list)
        {:ok, ip_address_list}

      {:error, reason} ->
        {:error, reason}
    end
  end

  @doc """
  A function that takes a ip address and returns a list of dns.

  ## Examples

      iex> Inet.get_dns_list("172.217.27.46")

  """
  def get_dns_list(ip_address) do
    case get_host_by_addr(ip_address) do
      {:ok, {_, host, host_list, _, _, []}} ->
        only_host_list = _only_dns_address_list(host_list)
        {:ok, [host] ++ only_host_list}

      {:ok, {_, host, host_list, _, _, [_]}} ->
        only_host_list = _only_dns_address_list(host_list)
        {:ok, [host] ++ only_host_list}

      {:error, reason} ->
        {:error, reason}
    end
  end

  @doc """
  A convenience function that calls `:inet.gethostbyname`.

  ## Examples

      iex> Inet.get_host_by_name("google.com")

  """
  def get_host_by_name(hostname) do
    Kernel.to_charlist(hostname)
    |> :inet.gethostbyname()
  end

  @doc """
  A convenience function that calls `:inet.gethostbyaddr`.

  ## Examples

      iex> Inet.get_host_by_addr("172.217.27.46")

  """
  def get_host_by_addr(ip_address) do
    Kernel.to_charlist(ip_address)
    |> :inet.gethostbyaddr()
  end

  defp _get_ip_address_list(ip_address_tuple_list) do
    ip_address_tuple_list
    |> Enum.map(fn tuple -> Tuple.to_list(tuple) end)
    |> Enum.map(fn address -> Enum.join(address, ".") end)
  end

  defp _only_dns_address_list(host_list) do
    host_list
    |> Enum.reject(fn addr -> String.contains?(to_string(addr), "in-addr.arpa") end)
  end
end