From: Alexander Goussas Date: Sat, 31 Jan 2026 20:48:18 +0000 (-0500) Subject: feat: parse incoming dns question X-Git-Url: http://git.frustrated-labs.net/?a=commitdiff_plain;h=268f3d0ba158b62d8ef9e80dbb047916d7f77f10;p=dns-phrasex.git feat: parse incoming dns question --- diff --git a/lib/dns_phrases/message.ex b/lib/dns_phrases/message.ex new file mode 100644 index 0000000..e0ac29c --- /dev/null +++ b/lib/dns_phrases/message.ex @@ -0,0 +1,8 @@ +defmodule DnsPhrases.Message do + defstruct [:op, tid: 0] + + @typedoc """ + A message received from a client. + """ + @type t :: %DnsPhrases.Message{op: integer, tid: integer} +end diff --git a/lib/dns_phrases/message/parser.ex b/lib/dns_phrases/message/parser.ex new file mode 100644 index 0000000..835ab73 --- /dev/null +++ b/lib/dns_phrases/message/parser.ex @@ -0,0 +1,37 @@ +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( + <>, + parts + ) do + [data | parts] + end + + defp parse_question( + <>, + parts + ) do + parse_question(rest, [data | parts]) + end +end diff --git a/lib/dns_phrases/server.ex b/lib/dns_phrases/server.ex index d022ca0..fcb5d4a 100644 --- a/lib/dns_phrases/server.ex +++ b/lib/dns_phrases/server.ex @@ -1,6 +1,8 @@ defmodule DnsPhrases.Server do use GenServer + alias DnsPhrases.Message.Parser + defmodule State do defstruct([:socket]) end @@ -21,7 +23,9 @@ defmodule DnsPhrases.Server do {: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}