--- /dev/null
+defmodule DnsPhrases.Message do
+ defstruct [:op, tid: 0]
+
+ @typedoc """
+ A message received from a client.
+ """
+ @type t :: %DnsPhrases.Message{op: integer, tid: integer}
+end
--- /dev/null
+defmodule DnsPhrases.Message.Parser do
+ alias DnsPhrases.Message
+
+ @spec parse(bitstring) :: DnsPhrases.Message.t()
+
+ def parse(<<
+ tid::16,
+ 0::1,
+ _flags::15,
+ 1::integer-size(16),
+ _number_of_answers::16,
+ _authority_rrs::16,
+ _additional_rrs::16,
+ data::bitstring
+ >>) do
+ op = parse_question(data)
+ %Message{tid: tid, op: op}
+ end
+
+ @spec parse_question(bitstring) :: list
+ def parse_question(data), do: parse_question(data, []) |> Enum.reverse()
+
+ @spec parse_question(bitstring, list) :: list
+ defp parse_question(
+ <<n::integer-size(8), data::bitstring-size(n * 8), 0::8, _rest::bitstring>>,
+ parts
+ ) do
+ [data | parts]
+ end
+
+ defp parse_question(
+ <<n::integer-size(8), data::bitstring-size(n * 8), rest::bitstring>>,
+ parts
+ ) do
+ parse_question(rest, [data | parts])
+ end
+end
defmodule DnsPhrases.Server do
use GenServer
+ alias DnsPhrases.Message.Parser
+
defmodule State do
defstruct([:socket])
end
{:udp, socket, _ip, _port, data},
%State{socket: socket} = state
) do
- # TODO 1: Fetch random phrase
+ # TODO 1: Parse DNS message
+ Parser.parse(data)
+
# TODO 2: Assemble DNS response as a TXT record containing the frame
# TODO 3: Reply to our client
{:noreply, state}