Process server, port, error and warning records

This commit is contained in:
Mike Cifelli 2024-03-17 09:49:03 -04:00
parent ec308c1fd4
commit 28f1a91ebf
Signed by: mike
GPG Key ID: 6B08C6BE47D08E4C
3 changed files with 53 additions and 5 deletions

View File

@ -11,6 +11,7 @@ defmodule Chronoscope.NTS do
case :ssl.connect(host, port, tls_options, @timeout_in_milliseconds) do case :ssl.connect(host, port, tls_options, @timeout_in_milliseconds) do
{:ok, socket} -> perform_key_establishment(socket) {:ok, socket} -> perform_key_establishment(socket)
{:error, {:tls_alert, {:handshake_failure, error}}} -> {:error, to_string(error)} {:error, {:tls_alert, {:handshake_failure, error}}} -> {:error, to_string(error)}
{:error, :timeout} -> {:error, :timeout}
{:error, error} -> {:error, inspect(error)} {:error, error} -> {:error, inspect(error)}
error -> {:error, inspect(error)} error -> {:error, inspect(error)}
end end

View File

@ -10,24 +10,37 @@ defmodule Chronoscope.NTS.KeyEstablishment do
30 => "AEAD_AES_128_GCM_SIV" 30 => "AEAD_AES_128_GCM_SIV"
} }
@next_protocols %{0 => "NTPv4"} @next_protocols %{
0 => "NTPv4"
}
@errors %{
0 => "Unrecognized Critical Record",
1 => "Bad Request",
2 => "Internal Server Error"
}
def request() do def request() do
@next_protocol_negotiation <> @aead_algorithm_negotiation <> @end_of_message @next_protocol_negotiation <> @aead_algorithm_negotiation <> @end_of_message
end end
def parse_response(response) do def parse_response(response) do
{:ok, Map.update(do_parse_response(response, %{}), :cookies, 0, &length/1)} response
|> do_parse_response(%{})
|> Map.update(:cookies, 0, &length/1)
|> then(&{:ok, &1})
end end
defp do_parse_response([], acc) do defp do_parse_response([], acc) do
acc acc
end end
# End of Message
defp do_parse_response([0x80, 0x00, 0x00, 0x00], acc) do defp do_parse_response([0x80, 0x00, 0x00, 0x00], acc) do
acc acc
end end
# NTS Next Protocol Negotiation
defp do_parse_response([0x80, 0x01, length_high, length_low | rest], acc) do defp do_parse_response([0x80, 0x01, length_high, length_low | rest], acc) do
length = combine_octets(length_high, length_low) length = combine_octets(length_high, length_low)
{next_protocols, remaining} = Enum.split(rest, length) {next_protocols, remaining} = Enum.split(rest, length)
@ -38,6 +51,24 @@ defmodule Chronoscope.NTS.KeyEstablishment do
) )
end end
# Error
defp do_parse_response([0x80, 0x02, 0x00, 0x02, error_high, error_low | rest], acc) do
error = combine_octets(error_high, error_low)
do_parse_response(
rest,
Map.put(acc, :error, Map.get(@errors, error, error))
)
end
# Warning
defp do_parse_response([0x80, 0x03, 0x00, 0x02, warning_high, warning_low | rest], acc) do
warning = combine_octets(warning_high, warning_low)
do_parse_response(rest, Map.put(acc, :warning, warning))
end
# AEAD Algorithm Negotiation
defp do_parse_response([first, 0x04, length_high, length_low | rest], acc) defp do_parse_response([first, 0x04, length_high, length_low | rest], acc)
when first == 0x00 or first == 0x80 do when first == 0x00 or first == 0x80 do
length = combine_octets(length_high, length_low) length = combine_octets(length_high, length_low)
@ -49,6 +80,7 @@ defmodule Chronoscope.NTS.KeyEstablishment do
) )
end end
# New Cookie for NTPv4
defp do_parse_response([first, 0x05, length_high, length_low | rest], acc) defp do_parse_response([first, 0x05, length_high, length_low | rest], acc)
when first == 0x00 or first == 0x80 do when first == 0x00 or first == 0x80 do
length = combine_octets(length_high, length_low) length = combine_octets(length_high, length_low)
@ -62,6 +94,23 @@ defmodule Chronoscope.NTS.KeyEstablishment do
) )
end end
# NTPv4 Server Negotiation
defp do_parse_response([first, 0x06, length_high, length_low | rest], acc)
when first == 0x00 or first == 0x80 do
length = combine_octets(length_high, length_low)
{server, remaining} = Enum.split(rest, length)
do_parse_response(remaining, Map.put(acc, :server, to_string(server)))
end
# NTPv4 Port Negotiation
defp do_parse_response([first, 0x07, 0x00, 0x02, port_high, port_low | rest], acc)
when first == 0x00 or first == 0x80 do
port = combine_octets(port_high, port_low)
do_parse_response(rest, Map.put(acc, :port, port))
end
defp do_parse_response([_, _, length_high, length_low | rest], acc) do defp do_parse_response([_, _, length_high, length_low | rest], acc) do
length = combine_octets(length_high, length_low) length = combine_octets(length_high, length_low)
{_, remaining} = Enum.split(rest, length) {_, remaining} = Enum.split(rest, length)
@ -97,8 +146,6 @@ defmodule Chronoscope.NTS.KeyEstablishment do
|> then(&do_parse_aead_algorithm_list(rest, [&1 | acc])) |> then(&do_parse_aead_algorithm_list(rest, [&1 | acc]))
end end
# todo parse server/port information
defp combine_octets(high, low) do defp combine_octets(high, low) do
high <<< 8 ||| low high <<< 8 ||| low
end end

View File

@ -16,7 +16,7 @@ defmodule ChronoscopeWeb.API.V1.NTS.KeyEstablishmentController do
ok_response(conn, %{status: :ok, configuration: configuration}) ok_response(conn, %{status: :ok, configuration: configuration})
{:error, error} -> {:error, error} ->
ok_response(conn, %{status: :error, reason: inspect(error)}) ok_response(conn, %{status: :error, reason: to_string(error)})
end end
end end