Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(elixir): add example of secure channel over udp, tweak udp parsing/serializing #7914

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
["setup.exs"] |> Enum.map(&Code.require_file/1)

# Register this process as worker address "app".
Ockam.Node.register_address("app")

Ockam.Transport.UDP.start()

# Create an identity and a purpose key
{:ok, identity} = Ockam.Identity.create()
{:ok, keypair} = Ockam.SecureChannel.Crypto.generate_dh_keypair()
{:ok, attestation} = Ockam.Identity.attest_purpose_key(identity, keypair)

# Connect to a secure channel listener and perform a handshake.
alias Ockam.Transport.UDPAddress
r = [UDPAddress.new("127.0.0.1", 4000), "secure_channel_listener"]
{:ok, c} = Ockam.SecureChannel.create_channel(route: r,
identity: identity,
encryption_options: [static_keypair: keypair, static_key_attestation: attestation])

# Prepare the message.
message = %{onward_route: [c, "echoer"], return_route: ["app"], payload: "Hello Ockam!"}

# Route the message.
Ockam.Router.route(message)

# Wait to receive a reply.
receive do
message -> IO.puts("!! Address: app\t Received: #{inspect(message)}")
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
["setup.exs", "echoer.exs"] |> Enum.map(&Code.require_file/1)

Logger.configure(level: :debug)
# Create a Echoer type worker at address "echoer".
{:ok, _echoer} = Echoer.create(address: "echoer")



# Create an identity and a purpose key
{:ok, identity} = Ockam.Identity.create()
{:ok, keypair} = Ockam.SecureChannel.Crypto.generate_dh_keypair()
{:ok, attestation} = Ockam.Identity.attest_purpose_key(identity, keypair)

# Create a secure channel listener that will wait for requests to initiate an Authenticated Key Exchange.
Ockam.SecureChannel.create_listener(identity: identity,
address: "secure_channel_listener",
encryption_options: [static_keypair: keypair, static_key_attestation: attestation])

# Start the UDP Transport Add-on for Ockam Routing and a UDP listener on port 4000.
{:ok, _} = Ockam.Transport.UDP.start(port: 4000)

Process.sleep(:infinity)
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ defmodule Ockam.Transport.UDP.Listener do

@doc false
@impl true
def handle_info({:udp, _socket, _from_ip, _from_port, _packet} = udp_message, state) do
## TODO: use from_ip and from_port to route messages back
case decode_and_send_to_router(udp_message, state) do
# The 2 bytes heading indicating the size is necessary on TCP streams,
# but is not neccesary on UDP where we map 1 ockam msg per udp datagram
# However, rust implementation is adding and expecting it to be there, it's done here as well.
def handle_info({:udp, socket, from_ip, from_port, <<length::size(16), packet::binary>>}, state)
when byte_size(packet) == length do
case decode_and_send_to_router({:udp, socket, from_ip, from_port, packet}, state) do
{:ok, state} ->
{:noreply, state}

Expand Down Expand Up @@ -103,6 +106,7 @@ defmodule Ockam.Transport.UDP.Listener do
end

{:error, reason} ->
Logger.error("Error processing udp packet: #{inspect(reason)}")
{:error, Telemetry.emit_event(function_name, metadata: %{name: reason})}
end
end
Expand All @@ -112,7 +116,13 @@ defmodule Ockam.Transport.UDP.Listener do

with {:ok, destination, message} <- pick_destination_and_set_onward_route(message),
{:ok, encoded_message} <- Wire.encode(message),
:ok <- :gen_udp.send(socket, destination.ip, destination.port, encoded_message) do
:ok <-
:gen_udp.send(
socket,
destination.ip,
destination.port,
<<byte_size(encoded_message)::size(16), encoded_message::binary>>
) do
Telemetry.emit_event(function_name, metadata: %{name: "successfully_encoded_and_sent"})
{:ok, state}
else
Expand Down
Loading